diff --git a/Cargo.lock b/Cargo.lock index c368b4a79d3fd..e69b36cb98346 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4739,6 +4739,15 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "sysroot" +version = "0.0.0" +dependencies = [ + "proc_macro", + "std", + "test", +] + [[package]] name = "tar" version = "0.4.38" @@ -4823,7 +4832,6 @@ dependencies = [ "getopts", "panic_abort", "panic_unwind", - "proc_macro", "std", ] diff --git a/Cargo.toml b/Cargo.toml index a497d7321e02c..7aaa34a68e66f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ members = [ "compiler/rustc", "library/std", - "library/test", + "library/sysroot", "src/rustdoc-json-types", "src/tools/build_helper", "src/tools/cargotest", diff --git a/compiler/rustc_borrowck/src/def_use.rs b/compiler/rustc_borrowck/src/def_use.rs index 6259722b6940f..74e6ce37e971a 100644 --- a/compiler/rustc_borrowck/src/def_use.rs +++ b/compiler/rustc_borrowck/src/def_use.rs @@ -54,7 +54,7 @@ pub fn categorize(context: PlaceContext) -> Option { // `PlaceMention` and `AscribeUserType` both evaluate the place, which must not // contain dangling references. - PlaceContext::NonUse(NonUseContext::PlaceMention) | + PlaceContext::NonMutatingUse(NonMutatingUseContext::PlaceMention) | PlaceContext::NonUse(NonUseContext::AscribeUserTy) | PlaceContext::MutatingUse(MutatingUseContext::AddressOf) | diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs index 22de7549e9409..4389d2b60bc55 100644 --- a/compiler/rustc_borrowck/src/renumber.rs +++ b/compiler/rustc_borrowck/src/renumber.rs @@ -108,6 +108,14 @@ impl<'a, 'tcx> MutVisitor<'tcx> for RegionRenumberer<'a, 'tcx> { debug!(?region); } + #[instrument(skip(self), level = "debug")] + fn visit_ty_const(&mut self, ct: &mut ty::Const<'tcx>, location: Location) { + let old_ct = *ct; + *ct = self.renumber_regions(old_ct, || RegionCtxt::Location(location)); + + debug!(?ct); + } + #[instrument(skip(self), level = "debug")] fn visit_constant(&mut self, constant: &mut Constant<'tcx>, location: Location) { let literal = constant.literal; diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 601589480d1d5..dcabeb792be3e 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -772,12 +772,10 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { match context { PlaceContext::MutatingUse(_) => ty::Invariant, - PlaceContext::NonUse(StorageDead | StorageLive | PlaceMention | VarDebugInfo) => { - ty::Invariant - } + PlaceContext::NonUse(StorageDead | StorageLive | VarDebugInfo) => ty::Invariant, PlaceContext::NonMutatingUse( - Inspect | Copy | Move | SharedBorrow | ShallowBorrow | UniqueBorrow | AddressOf - | Projection, + Inspect | Copy | Move | PlaceMention | SharedBorrow | ShallowBorrow | UniqueBorrow + | AddressOf | Projection, ) => ty::Covariant, PlaceContext::NonUse(AscribeUserTy) => ty::Covariant, } @@ -1803,6 +1801,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Rvalue::Repeat(operand, len) => { self.check_operand(operand, location); + let array_ty = rvalue.ty(body.local_decls(), tcx); + self.prove_predicate( + ty::PredicateKind::WellFormed(array_ty.into()), + Locations::Single(location), + ConstraintCategory::Boring, + ); + // If the length cannot be evaluated we must assume that the length can be larger // than 1. // If the length is larger than 1, the repeat expression will need to copy the diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index 0334c7ff13264..569599faa362b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -203,7 +203,9 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> self.assign(local, DefLocation::Body(location)); } - PlaceContext::NonUse(_) | PlaceContext::MutatingUse(MutatingUseContext::Retag) => {} + PlaceContext::NonUse(_) + | PlaceContext::NonMutatingUse(NonMutatingUseContext::PlaceMention) + | PlaceContext::MutatingUse(MutatingUseContext::Retag) => {} PlaceContext::NonMutatingUse( NonMutatingUseContext::Copy | NonMutatingUseContext::Move, diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 047d8a82bfc3f..bba049c381934 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1426,6 +1426,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_repeat_element_needs_copy_bound(element, count, element_ty); + self.register_wf_obligation( + tcx.mk_array_with_const_len(t, count).into(), + expr.span, + traits::WellFormed(None), + ); + tcx.mk_array_with_const_len(t, count) } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 0a9fcd898b93e..6718605ed0bc4 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -192,6 +192,14 @@ macro_rules! make_mir_visitor { self.super_constant(constant, location); } + fn visit_ty_const( + &mut self, + ct: $( & $mutability)? ty::Const<'tcx>, + location: Location, + ) { + self.super_ty_const(ct, location); + } + fn visit_span( &mut self, span: $(& $mutability)? Span, @@ -410,7 +418,7 @@ macro_rules! make_mir_visitor { StatementKind::PlaceMention(place) => { self.visit_place( place, - PlaceContext::NonUse(NonUseContext::PlaceMention), + PlaceContext::NonMutatingUse(NonMutatingUseContext::PlaceMention), location ); } @@ -625,8 +633,9 @@ macro_rules! make_mir_visitor { self.visit_operand(operand, location); } - Rvalue::Repeat(value, _) => { + Rvalue::Repeat(value, ct) => { self.visit_operand(value, location); + self.visit_ty_const($(&$mutability)? *ct, location); } Rvalue::ThreadLocalRef(_) => {} @@ -878,12 +887,20 @@ macro_rules! make_mir_visitor { self.visit_span($(& $mutability)? *span); drop(user_ty); // no visit method for this match literal { - ConstantKind::Ty(_) => {} + ConstantKind::Ty(ct) => self.visit_ty_const($(&$mutability)? *ct, location), ConstantKind::Val(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)), ConstantKind::Unevaluated(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)), } } + fn super_ty_const( + &mut self, + _ct: $(& $mutability)? ty::Const<'tcx>, + _location: Location, + ) { + + } + fn super_span(&mut self, _span: $(& $mutability)? Span) { } @@ -1251,6 +1268,11 @@ pub enum NonMutatingUseContext { UniqueBorrow, /// AddressOf for *const pointer. AddressOf, + /// PlaceMention statement. + /// + /// This statement is executed as a check that the `Place` is live without reading from it, + /// so it must be considered as a non-mutating use. + PlaceMention, /// Used as base for another place, e.g., `x` in `x.y`. Will not mutate the place. /// For example, the projection `x.y` is not marked as a mutation in these cases: /// ```ignore (illustrative) @@ -1301,8 +1323,6 @@ pub enum NonUseContext { AscribeUserTy, /// The data of a user variable, for debug info. VarDebugInfo, - /// PlaceMention statement. - PlaceMention, } #[derive(Copy, Clone, Debug, PartialEq, Eq)] diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index bc67aa476f1af..aeca0073304ea 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -197,6 +197,7 @@ impl DefUse { | NonMutatingUseContext::Copy | NonMutatingUseContext::Inspect | NonMutatingUseContext::Move + | NonMutatingUseContext::PlaceMention | NonMutatingUseContext::ShallowBorrow | NonMutatingUseContext::SharedBorrow | NonMutatingUseContext::UniqueBorrow, diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index deec66bbaf356..b3a3a25ebe863 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -752,6 +752,7 @@ impl Visitor<'_> for CanConstProp { | NonMutatingUse(NonMutatingUseContext::Move) | NonMutatingUse(NonMutatingUseContext::Inspect) | NonMutatingUse(NonMutatingUseContext::Projection) + | NonMutatingUse(NonMutatingUseContext::PlaceMention) | NonUse(_) => {} // These could be propagated with a smarter analysis or just some careful thinking about diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index f876b8c7ae0de..6f5d54bcf87e4 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2070,6 +2070,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } visit::walk_ty(self, ty) } + + // A type may have an expression as a const generic argument. + // We do not want to recurse into those. + fn visit_expr(&mut self, _: &'a Expr) {} } let impl_self = self diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index a002421aeef3a..18f25aec5feee 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -101,6 +101,7 @@ #![feature(array_into_iter_constructors)] #![feature(array_methods)] #![feature(array_windows)] +#![feature(ascii_char)] #![feature(assert_matches)] #![feature(async_iterator)] #![feature(coerce_unsized)] diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index cf16a3424a092..b9ef76c109abf 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -2526,6 +2526,15 @@ impl ToString for T { } } +#[cfg(not(no_global_oom_handling))] +#[unstable(feature = "ascii_char", issue = "110998")] +impl ToString for core::ascii::Char { + #[inline] + fn to_string(&self) -> String { + self.as_str().to_owned() + } +} + #[cfg(not(no_global_oom_handling))] #[stable(feature = "char_to_string_specialization", since = "1.46.0")] impl ToString for char { diff --git a/library/core/src/array/ascii.rs b/library/core/src/array/ascii.rs new file mode 100644 index 0000000000000..6750d7c071144 --- /dev/null +++ b/library/core/src/array/ascii.rs @@ -0,0 +1,34 @@ +use crate::ascii; + +#[cfg(not(test))] +impl [u8; N] { + /// Converts this array of bytes into a array of ASCII characters, + /// or returns `None` if any of the characters is non-ASCII. + #[unstable(feature = "ascii_char", issue = "110998")] + #[must_use] + #[inline] + pub fn as_ascii(&self) -> Option<&[ascii::Char; N]> { + if self.is_ascii() { + // SAFETY: Just checked that it's ASCII + Some(unsafe { self.as_ascii_unchecked() }) + } else { + None + } + } + + /// Converts this array of bytes into a array of ASCII characters, + /// without checking whether they're valid. + /// + /// # Safety + /// + /// Every byte in the array must be in `0..=127`, or else this is UB. + #[unstable(feature = "ascii_char", issue = "110998")] + #[must_use] + #[inline] + pub const unsafe fn as_ascii_unchecked(&self) -> &[ascii::Char; N] { + let byte_ptr: *const [u8; N] = self; + let ascii_ptr = byte_ptr as *const [ascii::Char; N]; + // SAFETY: The caller promised all the bytes are ASCII + unsafe { &*ascii_ptr } + } +} diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 940558974e69b..bdb4c975909e0 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -17,6 +17,7 @@ use crate::ops::{ }; use crate::slice::{Iter, IterMut}; +mod ascii; mod drain; mod equality; mod iter; diff --git a/library/core/src/ascii.rs b/library/core/src/ascii.rs index 065f1b3e70e68..7fd14a7e1eae8 100644 --- a/library/core/src/ascii.rs +++ b/library/core/src/ascii.rs @@ -14,6 +14,10 @@ use crate::fmt; use crate::iter::FusedIterator; use crate::num::NonZeroUsize; +mod ascii_char; +#[unstable(feature = "ascii_char", issue = "110998")] +pub use ascii_char::AsciiChar as Char; + /// An iterator over the escaped version of a byte. /// /// This `struct` is created by the [`escape_default`] function. See its diff --git a/library/core/src/ascii/ascii_char.rs b/library/core/src/ascii/ascii_char.rs new file mode 100644 index 0000000000000..f093a0990d1a9 --- /dev/null +++ b/library/core/src/ascii/ascii_char.rs @@ -0,0 +1,565 @@ +//! This uses the name `AsciiChar`, even though it's not exposed that way right now, +//! because it avoids a whole bunch of "are you sure you didn't mean `char`?" +//! suggestions from rustc if you get anything slightly wrong in here, and overall +//! helps with clarity as we're also referring to `char` intentionally in here. + +use crate::fmt; +use crate::mem::transmute; + +/// One of the 128 Unicode characters from U+0000 through U+007F, +/// often known as the [ASCII] subset. +/// +/// Officially, this is the first [block] in Unicode, _Basic Latin_. +/// For details, see the [*C0 Controls and Basic Latin*][chart] code chart. +/// +/// This block was based on older 7-bit character code standards such as +/// ANSI X3.4-1977, ISO 646-1973, and [NIST FIPS 1-2]. +/// +/// # When to use this +/// +/// The main advantage of this subset is that it's always valid UTF-8. As such, +/// the `&[ascii::Char]` -> `&str` conversion function (as well as other related +/// ones) are O(1): *no* runtime checks are needed. +/// +/// If you're consuming strings, you should usually handle Unicode and thus +/// accept `str`s, not limit yourself to `ascii::Char`s. +/// +/// However, certain formats are intentionally designed to produce ASCII-only +/// output in order to be 8-bit-clean. In those cases, it can be simpler and +/// faster to generate `ascii::Char`s instead of dealing with the variable width +/// properties of general UTF-8 encoded strings, while still allowing the result +/// to be used freely with other Rust things that deal in general `str`s. +/// +/// For example, a UUID library might offer a way to produce the string +/// representation of a UUID as an `[ascii::Char; 36]` to avoid memory +/// allocation yet still allow it to be used as UTF-8 via `as_str` without +/// paying for validation (or needing `unsafe` code) the way it would if it +/// were provided as a `[u8; 36]`. +/// +/// # Layout +/// +/// This type is guaranteed to have a size and alignment of 1 byte. +/// +/// # Names +/// +/// The variants on this type are [Unicode names][NamesList] of the characters +/// in upper camel case, with a few tweaks: +/// - For `` characters, the primary alias name is used. +/// - `LATIN` is dropped, as this block has no non-latin letters. +/// - `LETTER` is dropped, as `CAPITAL`/`SMALL` suffices in this block. +/// - `DIGIT`s use a single digit rather than writing out `ZERO`, `ONE`, etc. +/// +/// [ASCII]: https://www.unicode.org/glossary/index.html#ASCII +/// [block]: https://www.unicode.org/glossary/index.html#block +/// [chart]: https://www.unicode.org/charts/PDF/U0000.pdf +/// [NIST FIPS 1-2]: https://nvlpubs.nist.gov/nistpubs/Legacy/FIPS/fipspub1-2-1977.pdf +/// [NamesList]: https://www.unicode.org/Public/15.0.0/ucd/NamesList.txt +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[unstable(feature = "ascii_char", issue = "110998")] +#[repr(u8)] +pub enum AsciiChar { + /// U+0000 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + Null = 0, + /// U+0001 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + StartOfHeading = 1, + /// U+0002 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + StartOfText = 2, + /// U+0003 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + EndOfText = 3, + /// U+0004 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + EndOfTransmission = 4, + /// U+0005 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + Enquiry = 5, + /// U+0006 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + Acknowledge = 6, + /// U+0007 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + Bell = 7, + /// U+0008 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + Backspace = 8, + /// U+0009 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + CharacterTabulation = 9, + /// U+000A + #[unstable(feature = "ascii_char_variants", issue = "110998")] + LineFeed = 10, + /// U+000B + #[unstable(feature = "ascii_char_variants", issue = "110998")] + LineTabulation = 11, + /// U+000C + #[unstable(feature = "ascii_char_variants", issue = "110998")] + FormFeed = 12, + /// U+000D + #[unstable(feature = "ascii_char_variants", issue = "110998")] + CarriageReturn = 13, + /// U+000E + #[unstable(feature = "ascii_char_variants", issue = "110998")] + ShiftOut = 14, + /// U+000F + #[unstable(feature = "ascii_char_variants", issue = "110998")] + ShiftIn = 15, + /// U+0010 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + DataLinkEscape = 16, + /// U+0011 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + DeviceControlOne = 17, + /// U+0012 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + DeviceControlTwo = 18, + /// U+0013 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + DeviceControlThree = 19, + /// U+0014 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + DeviceControlFour = 20, + /// U+0015 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + NegativeAcknowledge = 21, + /// U+0016 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + SynchronousIdle = 22, + /// U+0017 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + EndOfTransmissionBlock = 23, + /// U+0018 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + Cancel = 24, + /// U+0019 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + EndOfMedium = 25, + /// U+001A + #[unstable(feature = "ascii_char_variants", issue = "110998")] + Substitute = 26, + /// U+001B + #[unstable(feature = "ascii_char_variants", issue = "110998")] + Escape = 27, + /// U+001C + #[unstable(feature = "ascii_char_variants", issue = "110998")] + InformationSeparatorFour = 28, + /// U+001D + #[unstable(feature = "ascii_char_variants", issue = "110998")] + InformationSeparatorThree = 29, + /// U+001E + #[unstable(feature = "ascii_char_variants", issue = "110998")] + InformationSeparatorTwo = 30, + /// U+001F + #[unstable(feature = "ascii_char_variants", issue = "110998")] + InformationSeparatorOne = 31, + /// U+0020 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + Space = 32, + /// U+0021 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + ExclamationMark = 33, + /// U+0022 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + QuotationMark = 34, + /// U+0023 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + NumberSign = 35, + /// U+0024 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + DollarSign = 36, + /// U+0025 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + PercentSign = 37, + /// U+0026 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + Ampersand = 38, + /// U+0027 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + Apostrophe = 39, + /// U+0028 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + LeftParenthesis = 40, + /// U+0029 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + RightParenthesis = 41, + /// U+002A + #[unstable(feature = "ascii_char_variants", issue = "110998")] + Asterisk = 42, + /// U+002B + #[unstable(feature = "ascii_char_variants", issue = "110998")] + PlusSign = 43, + /// U+002C + #[unstable(feature = "ascii_char_variants", issue = "110998")] + Comma = 44, + /// U+002D + #[unstable(feature = "ascii_char_variants", issue = "110998")] + HyphenMinus = 45, + /// U+002E + #[unstable(feature = "ascii_char_variants", issue = "110998")] + FullStop = 46, + /// U+002F + #[unstable(feature = "ascii_char_variants", issue = "110998")] + Solidus = 47, + /// U+0030 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + Digit0 = 48, + /// U+0031 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + Digit1 = 49, + /// U+0032 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + Digit2 = 50, + /// U+0033 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + Digit3 = 51, + /// U+0034 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + Digit4 = 52, + /// U+0035 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + Digit5 = 53, + /// U+0036 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + Digit6 = 54, + /// U+0037 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + Digit7 = 55, + /// U+0038 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + Digit8 = 56, + /// U+0039 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + Digit9 = 57, + /// U+003A + #[unstable(feature = "ascii_char_variants", issue = "110998")] + Colon = 58, + /// U+003B + #[unstable(feature = "ascii_char_variants", issue = "110998")] + Semicolon = 59, + /// U+003C + #[unstable(feature = "ascii_char_variants", issue = "110998")] + LessThanSign = 60, + /// U+003D + #[unstable(feature = "ascii_char_variants", issue = "110998")] + EqualsSign = 61, + /// U+003E + #[unstable(feature = "ascii_char_variants", issue = "110998")] + GreaterThanSign = 62, + /// U+003F + #[unstable(feature = "ascii_char_variants", issue = "110998")] + QuestionMark = 63, + /// U+0040 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + CommercialAt = 64, + /// U+0041 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + CapitalA = 65, + /// U+0042 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + CapitalB = 66, + /// U+0043 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + CapitalC = 67, + /// U+0044 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + CapitalD = 68, + /// U+0045 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + CapitalE = 69, + /// U+0046 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + CapitalF = 70, + /// U+0047 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + CapitalG = 71, + /// U+0048 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + CapitalH = 72, + /// U+0049 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + CapitalI = 73, + /// U+004A + #[unstable(feature = "ascii_char_variants", issue = "110998")] + CapitalJ = 74, + /// U+004B + #[unstable(feature = "ascii_char_variants", issue = "110998")] + CapitalK = 75, + /// U+004C + #[unstable(feature = "ascii_char_variants", issue = "110998")] + CapitalL = 76, + /// U+004D + #[unstable(feature = "ascii_char_variants", issue = "110998")] + CapitalM = 77, + /// U+004E + #[unstable(feature = "ascii_char_variants", issue = "110998")] + CapitalN = 78, + /// U+004F + #[unstable(feature = "ascii_char_variants", issue = "110998")] + CapitalO = 79, + /// U+0050 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + CapitalP = 80, + /// U+0051 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + CapitalQ = 81, + /// U+0052 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + CapitalR = 82, + /// U+0053 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + CapitalS = 83, + /// U+0054 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + CapitalT = 84, + /// U+0055 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + CapitalU = 85, + /// U+0056 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + CapitalV = 86, + /// U+0057 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + CapitalW = 87, + /// U+0058 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + CapitalX = 88, + /// U+0059 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + CapitalY = 89, + /// U+005A + #[unstable(feature = "ascii_char_variants", issue = "110998")] + CapitalZ = 90, + /// U+005B + #[unstable(feature = "ascii_char_variants", issue = "110998")] + LeftSquareBracket = 91, + /// U+005C + #[unstable(feature = "ascii_char_variants", issue = "110998")] + ReverseSolidus = 92, + /// U+005D + #[unstable(feature = "ascii_char_variants", issue = "110998")] + RightSquareBracket = 93, + /// U+005E + #[unstable(feature = "ascii_char_variants", issue = "110998")] + CircumflexAccent = 94, + /// U+005F + #[unstable(feature = "ascii_char_variants", issue = "110998")] + LowLine = 95, + /// U+0060 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + GraveAccent = 96, + /// U+0061 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + SmallA = 97, + /// U+0062 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + SmallB = 98, + /// U+0063 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + SmallC = 99, + /// U+0064 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + SmallD = 100, + /// U+0065 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + SmallE = 101, + /// U+0066 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + SmallF = 102, + /// U+0067 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + SmallG = 103, + /// U+0068 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + SmallH = 104, + /// U+0069 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + SmallI = 105, + /// U+006A + #[unstable(feature = "ascii_char_variants", issue = "110998")] + SmallJ = 106, + /// U+006B + #[unstable(feature = "ascii_char_variants", issue = "110998")] + SmallK = 107, + /// U+006C + #[unstable(feature = "ascii_char_variants", issue = "110998")] + SmallL = 108, + /// U+006D + #[unstable(feature = "ascii_char_variants", issue = "110998")] + SmallM = 109, + /// U+006E + #[unstable(feature = "ascii_char_variants", issue = "110998")] + SmallN = 110, + /// U+006F + #[unstable(feature = "ascii_char_variants", issue = "110998")] + SmallO = 111, + /// U+0070 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + SmallP = 112, + /// U+0071 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + SmallQ = 113, + /// U+0072 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + SmallR = 114, + /// U+0073 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + SmallS = 115, + /// U+0074 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + SmallT = 116, + /// U+0075 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + SmallU = 117, + /// U+0076 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + SmallV = 118, + /// U+0077 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + SmallW = 119, + /// U+0078 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + SmallX = 120, + /// U+0079 + #[unstable(feature = "ascii_char_variants", issue = "110998")] + SmallY = 121, + /// U+007A + #[unstable(feature = "ascii_char_variants", issue = "110998")] + SmallZ = 122, + /// U+007B + #[unstable(feature = "ascii_char_variants", issue = "110998")] + LeftCurlyBracket = 123, + /// U+007C + #[unstable(feature = "ascii_char_variants", issue = "110998")] + VerticalLine = 124, + /// U+007D + #[unstable(feature = "ascii_char_variants", issue = "110998")] + RightCurlyBracket = 125, + /// U+007E + #[unstable(feature = "ascii_char_variants", issue = "110998")] + Tilde = 126, + /// U+007F + #[unstable(feature = "ascii_char_variants", issue = "110998")] + Delete = 127, +} + +impl AsciiChar { + /// Creates an ascii character from the byte `b`, + /// or returns `None` if it's too large. + #[unstable(feature = "ascii_char", issue = "110998")] + #[inline] + pub const fn from_u8(b: u8) -> Option { + if b <= 127 { + // SAFETY: Just checked that `b` is in-range + Some(unsafe { Self::from_u8_unchecked(b) }) + } else { + None + } + } + + /// Creates an ASCII character from the byte `b`, + /// without checking whether it's valid. + /// + /// # Safety + /// + /// `b` must be in `0..=127`, or else this is UB. + #[unstable(feature = "ascii_char", issue = "110998")] + #[inline] + pub const unsafe fn from_u8_unchecked(b: u8) -> Self { + // SAFETY: Our safety precondition is that `b` is in-range. + unsafe { transmute(b) } + } + + /// When passed the *number* `0`, `1`, …, `9`, returns the *character* + /// `'0'`, `'1'`, …, `'9'` respectively. + /// + /// If `d >= 10`, returns `None`. + #[unstable(feature = "ascii_char", issue = "110998")] + #[inline] + pub const fn digit(d: u8) -> Option { + if d < 10 { + // SAFETY: Just checked it's in-range. + Some(unsafe { Self::digit_unchecked(d) }) + } else { + None + } + } + + /// When passed the *number* `0`, `1`, …, `9`, returns the *character* + /// `'0'`, `'1'`, …, `'9'` respectively, without checking that it's in-range. + /// + /// # Safety + /// + /// This is immediate UB if called with `d > 64`. + /// + /// If `d >= 10` and `d <= 64`, this is allowed to return any value or panic. + /// Notably, it should not be expected to return hex digits, or any other + /// reasonable extension of the decimal digits. + /// + /// (This lose safety condition is intended to simplify soundness proofs + /// when writing code using this method, since the implementation doesn't + /// need something really specific, not to make those other arguments do + /// something useful. It might be tightened before stabilization.) + #[unstable(feature = "ascii_char", issue = "110998")] + #[inline] + pub const unsafe fn digit_unchecked(d: u8) -> Self { + debug_assert!(d < 10); + + // SAFETY: `'0'` through `'9'` are U+00030 through U+0039, + // so because `d` must be 64 or less the addition can return at most + // 112 (0x70), which doesn't overflow and is within the ASCII range. + unsafe { + let byte = b'0'.unchecked_add(d); + Self::from_u8_unchecked(byte) + } + } + + /// Gets this ASCII character as a byte. + #[unstable(feature = "ascii_char", issue = "110998")] + #[inline] + pub const fn as_u8(self) -> u8 { + self as u8 + } + + /// Gets this ASCII character as a `char` Unicode Scalar Value. + #[unstable(feature = "ascii_char", issue = "110998")] + #[inline] + pub const fn as_char(self) -> char { + self as u8 as char + } + + /// Views this ASCII character as a one-code-unit UTF-8 `str`. + #[unstable(feature = "ascii_char", issue = "110998")] + #[inline] + pub const fn as_str(&self) -> &str { + crate::slice::from_ref(self).as_str() + } +} + +impl [AsciiChar] { + /// Views this slice of ASCII characters as a UTF-8 `str`. + #[unstable(feature = "ascii_char", issue = "110998")] + #[inline] + pub const fn as_str(&self) -> &str { + let ascii_ptr: *const Self = self; + let str_ptr = ascii_ptr as *const str; + // SAFETY: Each ASCII codepoint in UTF-8 is encoded as one single-byte + // code unit having the same value as the ASCII byte. + unsafe { &*str_ptr } + } + + /// Views this slice of ASCII characters as a slice of `u8` bytes. + #[unstable(feature = "ascii_char", issue = "110998")] + #[inline] + pub const fn as_bytes(&self) -> &[u8] { + self.as_str().as_bytes() + } +} + +#[unstable(feature = "ascii_char", issue = "110998")] +impl fmt::Display for AsciiChar { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ::fmt(self.as_str(), f) + } +} diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 2408f17807554..1dfa9c34db14c 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -1,5 +1,6 @@ //! impl char {} +use crate::ascii; use crate::slice; use crate::str::from_utf8_unchecked_mut; use crate::unicode::printable::is_printable; @@ -1101,6 +1102,24 @@ impl char { *self as u32 <= 0x7F } + /// Returns `Some` if the value is within the ASCII range, + /// or `None` if it's not. + /// + /// This is preferred to [`Self::is_ascii`] when you're passing the value + /// along to something else that can take [`ascii::Char`] rather than + /// needing to check again for itself whether the value is in ASCII. + #[must_use] + #[unstable(feature = "ascii_char", issue = "110998")] + #[inline] + pub const fn as_ascii(&self) -> Option { + if self.is_ascii() { + // SAFETY: Just checked that this is ASCII. + Some(unsafe { ascii::Char::from_u8_unchecked(*self as u8) }) + } else { + None + } + } + /// Makes a copy of the value in its ASCII upper case equivalent. /// /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index fdd7be625ed93..08444421dca08 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -472,7 +472,16 @@ impl u8 { #[rustc_const_stable(feature = "const_u8_is_ascii", since = "1.43.0")] #[inline] pub const fn is_ascii(&self) -> bool { - *self & 128 == 0 + *self <= 127 + } + + /// If the value of this byte is within the ASCII range, returns it as an + /// [ASCII character](ascii::Char). Otherwise, returns `None`. + #[must_use] + #[unstable(feature = "ascii_char", issue = "110998")] + #[inline] + pub const fn as_ascii(&self) -> Option { + ascii::Char::from_u8(*self) } /// Makes a copy of the value in its ASCII upper case equivalent. diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index b80bfe1c92df1..74a325b89d442 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -713,6 +713,32 @@ macro_rules! nonzero_signed_operations { unsafe { $Uty::new_unchecked(self.get().unsigned_abs()) } } + /// Returns `true` if `self` is positive and `false` if the + /// number is negative. + /// + /// # Example + /// + /// ``` + /// #![feature(nonzero_negation_ops)] + /// + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")] + #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")] + /// + /// assert!(pos_five.is_positive()); + /// assert!(!neg_five.is_positive()); + /// # Some(()) + /// # } + /// ``` + #[must_use] + #[inline] + #[unstable(feature = "nonzero_negation_ops", issue = "102443")] + pub const fn is_positive(self) -> bool { + self.get().is_positive() + } + /// Returns `true` if `self` is negative and `false` if the /// number is positive. /// diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index 5e5399acc1b0f..7bae6692ad4ed 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs @@ -16,6 +16,36 @@ impl [u8] { is_ascii(self) } + /// If this slice [`is_ascii`](Self::is_ascii), returns it as a slice of + /// [ASCII characters](`ascii::Char`), otherwise returns `None`. + #[unstable(feature = "ascii_char", issue = "110998")] + #[must_use] + #[inline] + pub fn as_ascii(&self) -> Option<&[ascii::Char]> { + if self.is_ascii() { + // SAFETY: Just checked that it's ASCII + Some(unsafe { self.as_ascii_unchecked() }) + } else { + None + } + } + + /// Converts this slice of bytes into a slice of ASCII characters, + /// without checking whether they're valid. + /// + /// # Safety + /// + /// Every byte in the slice must be in `0..=127`, or else this is UB. + #[unstable(feature = "ascii_char", issue = "110998")] + #[must_use] + #[inline] + pub const unsafe fn as_ascii_unchecked(&self) -> &[ascii::Char] { + let byte_ptr: *const [u8] = self; + let ascii_ptr = byte_ptr as *const [ascii::Char]; + // SAFETY: The caller promised all the bytes are ASCII + unsafe { &*ascii_ptr } + } + /// Checks that two slices are an ASCII case-insensitive match. /// /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index a13107fd0de09..66fa9cf6f64c0 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -16,6 +16,7 @@ mod validations; use self::pattern::Pattern; use self::pattern::{DoubleEndedSearcher, ReverseSearcher, Searcher}; +use crate::ascii; use crate::char::{self, EscapeDebugExtArgs}; use crate::mem; use crate::slice::{self, SliceIndex}; @@ -2366,6 +2367,16 @@ impl str { self.as_bytes().is_ascii() } + /// If this string slice [`is_ascii`](Self::is_ascii), returns it as a slice + /// of [ASCII characters](`ascii::Char`), otherwise returns `None`. + #[unstable(feature = "ascii_char", issue = "110998")] + #[must_use] + #[inline] + pub fn as_ascii(&self) -> Option<&[ascii::Char]> { + // Like in `is_ascii`, we can work on the bytes directly. + self.as_bytes().as_ascii() + } + /// Checks that two strings are an ASCII case-insensitive match. /// /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, diff --git a/library/std/src/ascii.rs b/library/std/src/ascii.rs index c29f015777f1a..b18ab50de123e 100644 --- a/library/std/src/ascii.rs +++ b/library/std/src/ascii.rs @@ -16,6 +16,9 @@ #[stable(feature = "rust1", since = "1.0.0")] pub use core::ascii::{escape_default, EscapeDefault}; +#[unstable(feature = "ascii_char", issue = "110998")] +pub use core::ascii::Char; + /// Extension methods for ASCII-subset only operations. /// /// Be aware that operations on seemingly non-ASCII characters can sometimes diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml new file mode 100644 index 0000000000000..5356ee277cc2c --- /dev/null +++ b/library/sysroot/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "sysroot" +version = "0.0.0" +edition = "2021" + +# this is a dummy crate to ensure that all required crates appear in the sysroot +[dependencies] +proc_macro = { path = "../proc_macro" } +std = { path = "../std" } +test = { path = "../test" } + +# Forward features to the `std` crate as necessary +[features] +default = ["std_detect_file_io", "std_detect_dlsym_getauxval", "panic-unwind"] +backtrace = ["std/backtrace"] +compiler-builtins-c = ["std/compiler-builtins-c"] +compiler-builtins-mem = ["std/compiler-builtins-mem"] +compiler-builtins-no-asm = ["std/compiler-builtins-no-asm"] +compiler-builtins-mangled-names = ["std/compiler-builtins-mangled-names"] +llvm-libunwind = ["std/llvm-libunwind"] +system-llvm-libunwind = ["std/system-llvm-libunwind"] +panic-unwind = ["std/panic_unwind"] +panic_immediate_abort = ["std/panic_immediate_abort"] +profiler = ["std/profiler"] +std_detect_file_io = ["std/std_detect_file_io"] +std_detect_dlsym_getauxval = ["std/std_detect_dlsym_getauxval"] +std_detect_env_override = ["std/std_detect_env_override"] diff --git a/library/sysroot/src/lib.rs b/library/sysroot/src/lib.rs new file mode 100644 index 0000000000000..71ceb580a40c3 --- /dev/null +++ b/library/sysroot/src/lib.rs @@ -0,0 +1 @@ +// This is intentionally empty since this crate is only used to depend on other library crates. diff --git a/library/test/Cargo.toml b/library/test/Cargo.toml index 18cb023d274a4..91a1abde059f6 100644 --- a/library/test/Cargo.toml +++ b/library/test/Cargo.toml @@ -12,23 +12,3 @@ std = { path = "../std" } core = { path = "../core" } panic_unwind = { path = "../panic_unwind" } panic_abort = { path = "../panic_abort" } - -# not actually used but needed to always have proc_macro in the sysroot -proc_macro = { path = "../proc_macro" } - -# Forward features to the `std` crate as necessary -[features] -default = ["std_detect_file_io", "std_detect_dlsym_getauxval", "panic-unwind"] -backtrace = ["std/backtrace"] -compiler-builtins-c = ["std/compiler-builtins-c"] -compiler-builtins-mem = ["std/compiler-builtins-mem"] -compiler-builtins-no-asm = ["std/compiler-builtins-no-asm"] -compiler-builtins-mangled-names = ["std/compiler-builtins-mangled-names"] -llvm-libunwind = ["std/llvm-libunwind"] -system-llvm-libunwind = ["std/system-llvm-libunwind"] -panic-unwind = ["std/panic_unwind"] -panic_immediate_abort = ["std/panic_immediate_abort"] -profiler = ["std/profiler"] -std_detect_file_io = ["std/std_detect_file_io"] -std_detect_dlsym_getauxval = ["std/std_detect_dlsym_getauxval"] -std_detect_env_override = ["std/std_detect_env_override"] diff --git a/library/test/src/formatters/junit.rs b/library/test/src/formatters/junit.rs index 2e07ce3c09923..9f5bf24367eaa 100644 --- a/library/test/src/formatters/junit.rs +++ b/library/test/src/formatters/junit.rs @@ -11,7 +11,7 @@ use crate::{ pub struct JunitFormatter { out: OutputLocation, - results: Vec<(TestDesc, TestResult, Duration)>, + results: Vec<(TestDesc, TestResult, Duration, Vec)>, } impl JunitFormatter { @@ -26,6 +26,18 @@ impl JunitFormatter { } } +fn str_to_cdata(s: &str) -> String { + // Drop the stdout in a cdata. Unfortunately, you can't put either of `]]>` or + // `", "]]]]>"); + let escaped_output = escaped_output.replace(" ", ""); + format!("", escaped_output) +} + impl OutputFormatter for JunitFormatter { fn write_discovery_start(&mut self) -> io::Result<()> { Err(io::Error::new(io::ErrorKind::NotFound, "Not yet implemented!")) @@ -63,14 +75,14 @@ impl OutputFormatter for JunitFormatter { desc: &TestDesc, result: &TestResult, exec_time: Option<&time::TestExecTime>, - _stdout: &[u8], + stdout: &[u8], _state: &ConsoleTestState, ) -> io::Result<()> { // Because the testsuite node holds some of the information as attributes, we can't write it // until all of the tests have finished. Instead of writing every result as they come in, we add // them to a Vec and write them all at once when run is complete. let duration = exec_time.map(|t| t.0).unwrap_or_default(); - self.results.push((desc.clone(), result.clone(), duration)); + self.results.push((desc.clone(), result.clone(), duration, stdout.to_vec())); Ok(()) } fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result { @@ -85,7 +97,7 @@ impl OutputFormatter for JunitFormatter { >", state.failed, state.total, state.ignored ))?; - for (desc, result, duration) in std::mem::take(&mut self.results) { + for (desc, result, duration, stdout) in std::mem::take(&mut self.results) { let (class_name, test_name) = parse_class_name(&desc); match result { TestResult::TrIgnored => { /* no-op */ } @@ -98,6 +110,11 @@ impl OutputFormatter for JunitFormatter { duration.as_secs_f64() ))?; self.write_message("")?; + if !stdout.is_empty() { + self.write_message("")?; + self.write_message(&str_to_cdata(&String::from_utf8_lossy(&stdout)))?; + self.write_message("")?; + } self.write_message("")?; } @@ -110,6 +127,11 @@ impl OutputFormatter for JunitFormatter { duration.as_secs_f64() ))?; self.write_message(&format!(""))?; + if !stdout.is_empty() { + self.write_message("")?; + self.write_message(&str_to_cdata(&String::from_utf8_lossy(&stdout)))?; + self.write_message("")?; + } self.write_message("")?; } @@ -136,11 +158,19 @@ impl OutputFormatter for JunitFormatter { TestResult::TrOk => { self.write_message(&format!( "", + name=\"{}\" time=\"{}\"", class_name, test_name, duration.as_secs_f64() ))?; + if stdout.is_empty() || !state.options.display_output { + self.write_message("/>")?; + } else { + self.write_message(">")?; + self.write_message(&str_to_cdata(&String::from_utf8_lossy(&stdout)))?; + self.write_message("")?; + self.write_message("")?; + } } } } diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 60de46ce64c15..956b82385f6f5 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -79,7 +79,7 @@ impl Step for Std { const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.all_krates("test").path("library") + run.all_krates("sysroot").path("library") } fn make_run(run: RunConfig<'_>) { diff --git a/src/bootstrap/clean.rs b/src/bootstrap/clean.rs index 7ebd0a8f27069..0d9fd56b03814 100644 --- a/src/bootstrap/clean.rs +++ b/src/bootstrap/clean.rs @@ -81,7 +81,7 @@ macro_rules! clean_crate_tree { clean_crate_tree! { Rustc, Mode::Rustc, "rustc-main"; - Std, Mode::Std, "test"; + Std, Mode::Std, "sysroot"; } fn clean_default(build: &Build, all: bool) { diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 7d2a6862500a3..966ae00fa1d86 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -56,7 +56,7 @@ impl Step for Std { // When downloading stage1, the standard library has already been copied to the sysroot, so // there's no need to rebuild it. let builder = run.builder; - run.crate_or_deps("test") + run.crate_or_deps("sysroot") .path("library") .lazy_default_condition(Box::new(|| !builder.download_rustc())) } @@ -364,7 +364,7 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car .arg("--features") .arg(features) .arg("--manifest-path") - .arg(builder.src.join("library/test/Cargo.toml")); + .arg(builder.src.join("library/sysroot/Cargo.toml")); // Help the libc crate compile by assisting it in finding various // sysroot native libraries. diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 3b35ca1d15dc8..ab7f7350d5f4d 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -976,6 +976,7 @@ impl Step for PlainSourceTarball { "config.example.toml", "Cargo.toml", "Cargo.lock", + ".gitmodules", ]; let src_dirs = ["src", "compiler", "library", "tests"]; diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 9ad98eb57022c..8f5d9bb66e103 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -438,7 +438,7 @@ impl Step for Std { fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; - run.all_krates("test").path("library").default_condition(builder.config.docs) + run.all_krates("sysroot").path("library").default_condition(builder.config.docs) } fn make_run(run: RunConfig<'_>) { diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index aee84e9c9beb9..cfccb51662785 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -2145,7 +2145,7 @@ impl Step for Crate { const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.crate_or_deps("test") + run.crate_or_deps("sysroot") } fn make_run(run: RunConfig<'_>) { diff --git a/tests/codegen/ascii-char.rs b/tests/codegen/ascii-char.rs new file mode 100644 index 0000000000000..4167becf5e9a9 --- /dev/null +++ b/tests/codegen/ascii-char.rs @@ -0,0 +1,37 @@ +// compile-flags: -C opt-level=1 +// ignore-debug (the extra assertions get in the way) + +#![crate_type = "lib"] +#![feature(ascii_char)] + +use std::ascii::Char as AsciiChar; + +// CHECK-LABEL: i8 @unwrap_digit_from_remainder(i32 +#[no_mangle] +pub fn unwrap_digit_from_remainder(v: u32) -> AsciiChar { + // CHECK-NOT: icmp + // CHECK-NOT: panic + + // CHECK: %[[R:.+]] = urem i32 %v, 10 + // CHECK-NEXT: %[[T:.+]] = trunc i32 %[[R]] to i8 + // CHECK-NEXT: %[[D:.+]] = or i8 %[[T]], 48 + // CHECK-NEXT: ret i8 %[[D]] + + // CHECK-NOT: icmp + // CHECK-NOT: panic + AsciiChar::digit((v % 10) as u8).unwrap() +} + +// CHECK-LABEL: i8 @unwrap_from_masked(i8 +#[no_mangle] +pub fn unwrap_from_masked(b: u8) -> AsciiChar { + // CHECK-NOT: icmp + // CHECK-NOT: panic + + // CHECK: %[[M:.+]] = and i8 %b, 127 + // CHECK-NEXT: ret i8 %[[M]] + + // CHECK-NOT: icmp + // CHECK-NOT: panic + AsciiChar::from_u8(b & 0x7f).unwrap() +} diff --git a/tests/mir-opt/dead-store-elimination/place_mention.main.DeadStoreElimination.diff b/tests/mir-opt/dead-store-elimination/place_mention.main.DeadStoreElimination.diff new file mode 100644 index 0000000000000..761c074ed9450 --- /dev/null +++ b/tests/mir-opt/dead-store-elimination/place_mention.main.DeadStoreElimination.diff @@ -0,0 +1,25 @@ +- // MIR for `main` before DeadStoreElimination ++ // MIR for `main` after DeadStoreElimination + + fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/place_mention.rs:+0:11: +0:11 + let mut _1: (&str, &str); // in scope 0 at $DIR/place_mention.rs:+3:18: +3:36 + scope 1 { + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/place_mention.rs:+3:18: +3:36 + _1 = (const "Hello", const "World"); // scope 0 at $DIR/place_mention.rs:+3:18: +3:36 + // mir::Constant + // + span: $DIR/place_mention.rs:8:19: 8:26 + // + literal: Const { ty: &str, val: Value(Slice(..)) } + // mir::Constant + // + span: $DIR/place_mention.rs:8:28: 8:35 + // + literal: Const { ty: &str, val: Value(Slice(..)) } + PlaceMention(_1); // scope 0 at $DIR/place_mention.rs:+3:18: +3:36 + StorageDead(_1); // scope 0 at $DIR/place_mention.rs:+3:36: +3:37 + _0 = const (); // scope 0 at $DIR/place_mention.rs:+0:11: +4:2 + return; // scope 0 at $DIR/place_mention.rs:+4:2: +4:2 + } + } + diff --git a/tests/mir-opt/dead-store-elimination/place_mention.rs b/tests/mir-opt/dead-store-elimination/place_mention.rs new file mode 100644 index 0000000000000..59dc74454a402 --- /dev/null +++ b/tests/mir-opt/dead-store-elimination/place_mention.rs @@ -0,0 +1,9 @@ +// unit-test: DeadStoreElimination +// compile-flags: -Zmir-keep-place-mention + +// EMIT_MIR place_mention.main.DeadStoreElimination.diff +fn main() { + // Verify that we account for the `PlaceMention` statement as a use of the tuple, + // and don't remove it as a dead store. + let (_, _) = ("Hello", "World"); +} diff --git a/tests/run-make/libtest-junit/Makefile b/tests/run-make/libtest-junit/Makefile new file mode 100644 index 0000000000000..d97cafccf1fd4 --- /dev/null +++ b/tests/run-make/libtest-junit/Makefile @@ -0,0 +1,19 @@ +# ignore-cross-compile +include ../tools.mk + +# Test expected libtest's junit output + +OUTPUT_FILE_DEFAULT := $(TMPDIR)/libtest-junit-output-default.xml +OUTPUT_FILE_STDOUT_SUCCESS := $(TMPDIR)/libtest-junit-output-stdout-success.xml + +all: f.rs validate_junit.py output-default.xml output-stdout-success.xml + $(RUSTC) --test f.rs + RUST_BACKTRACE=0 $(call RUN,f) -Z unstable-options --test-threads=1 --format=junit > $(OUTPUT_FILE_DEFAULT) || true + RUST_BACKTRACE=0 $(call RUN,f) -Z unstable-options --test-threads=1 --format=junit --show-output > $(OUTPUT_FILE_STDOUT_SUCCESS) || true + + cat $(OUTPUT_FILE_DEFAULT) | "$(PYTHON)" validate_junit.py + cat $(OUTPUT_FILE_STDOUT_SUCCESS) | "$(PYTHON)" validate_junit.py + + # Normalize the actual output and compare to expected output file + cat $(OUTPUT_FILE_DEFAULT) | sed 's/time="[0-9.]*"/time="$$TIME"/g' | diff output-default.xml - + cat $(OUTPUT_FILE_STDOUT_SUCCESS) | sed 's/time="[0-9.]*"/time="$$TIME"/g' | diff output-stdout-success.xml - diff --git a/tests/run-make/libtest-junit/f.rs b/tests/run-make/libtest-junit/f.rs new file mode 100644 index 0000000000000..d360d77317d78 --- /dev/null +++ b/tests/run-make/libtest-junit/f.rs @@ -0,0 +1,23 @@ +#[test] +fn a() { + println!("print from successful test"); + // Should pass +} + +#[test] +fn b() { + println!("print from failing test"); + assert!(false); +} + +#[test] +#[should_panic] +fn c() { + assert!(false); +} + +#[test] +#[ignore = "msg"] +fn d() { + assert!(false); +} diff --git a/tests/run-make/libtest-junit/output-default.xml b/tests/run-make/libtest-junit/output-default.xml new file mode 100644 index 0000000000000..d59e07b8ad89d --- /dev/null +++ b/tests/run-make/libtest-junit/output-default.xml @@ -0,0 +1 @@ + diff --git a/tests/run-make/libtest-junit/output-stdout-success.xml b/tests/run-make/libtest-junit/output-stdout-success.xml new file mode 100644 index 0000000000000..0c300611e1f76 --- /dev/null +++ b/tests/run-make/libtest-junit/output-stdout-success.xml @@ -0,0 +1 @@ + diff --git a/tests/run-make/libtest-junit/validate_junit.py b/tests/run-make/libtest-junit/validate_junit.py new file mode 100755 index 0000000000000..47a8e70ccc38c --- /dev/null +++ b/tests/run-make/libtest-junit/validate_junit.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python + +import sys +import xml.etree.ElementTree as ET + +# Try to decode line in order to ensure it is a valid XML document +for line in sys.stdin: + try: + ET.fromstring(line) + except ET.ParseError as pe: + print("Invalid xml: %r" % line) + raise diff --git a/tests/ui/const-generics/sneaky-array-repeat-expr.rs b/tests/ui/const-generics/sneaky-array-repeat-expr.rs index b147c246bdac8..cd1607608a6e9 100644 --- a/tests/ui/const-generics/sneaky-array-repeat-expr.rs +++ b/tests/ui/const-generics/sneaky-array-repeat-expr.rs @@ -10,6 +10,7 @@ impl Trait for () { pub const fn foo() where (): Trait { let bar = [(); <()>::Assoc]; //~^ error: constant expression depends on a generic parameter + //~| error: constant expression depends on a generic parameter } trait Trait2 { @@ -24,6 +25,7 @@ impl Trait2 for () { pub const fn foo2() where (): Trait2 { let bar2 = [(); <()>::Assoc2]; //~^ error: constant expression depends on a generic parameter + //~| error: constant expression depends on a generic parameter } fn main() { diff --git a/tests/ui/const-generics/sneaky-array-repeat-expr.stderr b/tests/ui/const-generics/sneaky-array-repeat-expr.stderr index 5c77375d39934..e532f27a10da9 100644 --- a/tests/ui/const-generics/sneaky-array-repeat-expr.stderr +++ b/tests/ui/const-generics/sneaky-array-repeat-expr.stderr @@ -7,12 +7,28 @@ LL | let bar = [(); <()>::Assoc]; = note: this may fail depending on what value the parameter takes error: constant expression depends on a generic parameter - --> $DIR/sneaky-array-repeat-expr.rs:25:21 + --> $DIR/sneaky-array-repeat-expr.rs:11:15 + | +LL | let bar = [(); <()>::Assoc]; + | ^^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: constant expression depends on a generic parameter + --> $DIR/sneaky-array-repeat-expr.rs:26:21 | LL | let bar2 = [(); <()>::Assoc2]; | ^^^^^^^^^^^^ | = note: this may fail depending on what value the parameter takes -error: aborting due to 2 previous errors +error: constant expression depends on a generic parameter + --> $DIR/sneaky-array-repeat-expr.rs:26:16 + | +LL | let bar2 = [(); <()>::Assoc2]; + | ^^^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to 4 previous errors diff --git a/tests/ui/consts/issue-50439.rs b/tests/ui/consts/issue-50439.rs index 0be7c405473ca..d42347e136e1c 100644 --- a/tests/ui/consts/issue-50439.rs +++ b/tests/ui/consts/issue-50439.rs @@ -22,7 +22,9 @@ impl PinDropInternal for Bears { where Self: ReflectDrop, { - let _ = [(); 0 - !!( as ReflectDrop>::REFLECT_DROP) as usize]; //~ ERROR constant expression depends on a generic parameter + let _ = [(); 0 - !!( as ReflectDrop>::REFLECT_DROP) as usize]; + //~^ ERROR constant expression depends on a generic parameter + //~| ERROR constant expression depends on a generic parameter } } diff --git a/tests/ui/consts/issue-50439.stderr b/tests/ui/consts/issue-50439.stderr index 3fbdf33b2d881..7a8cd45ecc7d1 100644 --- a/tests/ui/consts/issue-50439.stderr +++ b/tests/ui/consts/issue-50439.stderr @@ -6,5 +6,13 @@ LL | let _ = [(); 0 - !!( as ReflectDrop>::REFLECT_DROP) as usi | = note: this may fail depending on what value the parameter takes -error: aborting due to previous error +error: constant expression depends on a generic parameter + --> $DIR/issue-50439.rs:25:17 + | +LL | let _ = [(); 0 - !!( as ReflectDrop>::REFLECT_DROP) as usize]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to 2 previous errors diff --git a/tests/ui/self/elision/nested-item.rs b/tests/ui/self/elision/nested-item.rs new file mode 100644 index 0000000000000..4bcb645c60eef --- /dev/null +++ b/tests/ui/self/elision/nested-item.rs @@ -0,0 +1,13 @@ +// Regression test for #110899. +// When looking for the elided lifetime for `wrap`, +// we must not consider the lifetimes in `bar` as candidates. + +fn wrap(self: Wrap<{ fn bar(&self) {} }>) -> &() { + //~^ ERROR `self` parameter is only allowed in associated functions + //~| ERROR `self` parameter is only allowed in associated functions + //~| ERROR missing lifetime specifier + //~| ERROR cannot find type `Wrap` in this scope + &() +} + +fn main() {} diff --git a/tests/ui/self/elision/nested-item.stderr b/tests/ui/self/elision/nested-item.stderr new file mode 100644 index 0000000000000..752fd82332c38 --- /dev/null +++ b/tests/ui/self/elision/nested-item.stderr @@ -0,0 +1,38 @@ +error: `self` parameter is only allowed in associated functions + --> $DIR/nested-item.rs:5:9 + | +LL | fn wrap(self: Wrap<{ fn bar(&self) {} }>) -> &() { + | ^^^^ not semantically valid as function parameter + | + = note: associated functions are those in `impl` or `trait` definitions + +error: `self` parameter is only allowed in associated functions + --> $DIR/nested-item.rs:5:29 + | +LL | fn wrap(self: Wrap<{ fn bar(&self) {} }>) -> &() { + | ^^^^^ not semantically valid as function parameter + | + = note: associated functions are those in `impl` or `trait` definitions + +error[E0106]: missing lifetime specifier + --> $DIR/nested-item.rs:5:46 + | +LL | fn wrap(self: Wrap<{ fn bar(&self) {} }>) -> &() { + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime + | +LL | fn wrap(self: Wrap<{ fn bar(&self) {} }>) -> &'static () { + | +++++++ + +error[E0412]: cannot find type `Wrap` in this scope + --> $DIR/nested-item.rs:5:15 + | +LL | fn wrap(self: Wrap<{ fn bar(&self) {} }>) -> &() { + | ^^^^ not found in this scope + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0106, E0412. +For more information about an error, try `rustc --explain E0106`. diff --git a/tests/ui/typeck/repeat-expr-checks-wf.rs b/tests/ui/typeck/repeat-expr-checks-wf.rs new file mode 100644 index 0000000000000..b8a2a0ceb5880 --- /dev/null +++ b/tests/ui/typeck/repeat-expr-checks-wf.rs @@ -0,0 +1,10 @@ +trait Foo { + const ASSOC: [u8]; +} + +fn bar() { + let a = [T::ASSOC; 2]; + //~^ ERROR: the size for values of type `[u8]` cannot be known at compilation time +} + +fn main() {} diff --git a/tests/ui/typeck/repeat-expr-checks-wf.stderr b/tests/ui/typeck/repeat-expr-checks-wf.stderr new file mode 100644 index 0000000000000..a821088a4b30e --- /dev/null +++ b/tests/ui/typeck/repeat-expr-checks-wf.stderr @@ -0,0 +1,12 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/repeat-expr-checks-wf.rs:6:13 + | +LL | let a = [T::ASSOC; 2]; + | ^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: slice and array elements must have `Sized` type + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`.