summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-05-04 17:56:17 +0000
committerbors <bors@rust-lang.org>2023-05-04 17:56:17 +0000
commiteb7a7434215dd9d4b7cc18746ad1d0e531c25325 (patch)
tree0287e377a5dbb3e130b3eb2265703697cfd50ff0
parenteac35583d2ffb5ed9e564dee0822c9a244058ee0 (diff)
parent75e8f87673905d58618773bec92eff6446c0d579 (diff)
downloadrust-eb7a7434215dd9d4b7cc18746ad1d0e531c25325.tar.gz
Auto merge of #111210 - matthiaskrgr:rollup-doquh2n, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - #108865 (Add a `sysroot` crate to represent the standard library crates) - #110651 (libtest: include test output in junit xml reports) - #110826 (Make PlaceMention a non-mutating use.) - #110982 (Do not recurse into const generic args when resolving self lifetime elision.) - #111009 (Add `ascii::Char` (ACP#179)) - #111100 (check array type of repeat exprs is wf) - #111186 (Add `is_positive` method for signed non-zero integers.) - #111201 (bootstrap: add .gitmodules to the sources) Failed merges: - #110954 (Reject borrows of projections in ConstProp.) r? `@ghost` `@rustbot` modify labels: rollup
-rw-r--r--Cargo.lock10
-rw-r--r--Cargo.toml2
-rw-r--r--compiler/rustc_borrowck/src/def_use.rs2
-rw-r--r--compiler/rustc_borrowck/src/renumber.rs8
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs15
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/analyze.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs6
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs30
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/liveness.rs1
-rw-r--r--compiler/rustc_mir_transform/src/const_prop.rs1
-rw-r--r--compiler/rustc_resolve/src/late.rs4
-rw-r--r--library/alloc/src/lib.rs1
-rw-r--r--library/alloc/src/string.rs9
-rw-r--r--library/core/src/array/ascii.rs34
-rw-r--r--library/core/src/array/mod.rs1
-rw-r--r--library/core/src/ascii.rs4
-rw-r--r--library/core/src/ascii/ascii_char.rs565
-rw-r--r--library/core/src/char/methods.rs19
-rw-r--r--library/core/src/num/mod.rs11
-rw-r--r--library/core/src/num/nonzero.rs26
-rw-r--r--library/core/src/slice/ascii.rs30
-rw-r--r--library/core/src/str/mod.rs11
-rw-r--r--library/std/src/ascii.rs3
-rw-r--r--library/sysroot/Cargo.toml27
-rw-r--r--library/sysroot/src/lib.rs1
-rw-r--r--library/test/Cargo.toml20
-rw-r--r--library/test/src/formatters/junit.rs40
-rw-r--r--src/bootstrap/check.rs2
-rw-r--r--src/bootstrap/clean.rs2
-rw-r--r--src/bootstrap/compile.rs4
-rw-r--r--src/bootstrap/dist.rs1
-rw-r--r--src/bootstrap/doc.rs2
-rw-r--r--src/bootstrap/test.rs2
-rw-r--r--tests/codegen/ascii-char.rs37
-rw-r--r--tests/mir-opt/dead-store-elimination/place_mention.main.DeadStoreElimination.diff25
-rw-r--r--tests/mir-opt/dead-store-elimination/place_mention.rs9
-rw-r--r--tests/run-make/libtest-junit/Makefile19
-rw-r--r--tests/run-make/libtest-junit/f.rs23
-rw-r--r--tests/run-make/libtest-junit/output-default.xml1
-rw-r--r--tests/run-make/libtest-junit/output-stdout-success.xml1
-rwxr-xr-xtests/run-make/libtest-junit/validate_junit.py12
-rw-r--r--tests/ui/const-generics/sneaky-array-repeat-expr.rs2
-rw-r--r--tests/ui/const-generics/sneaky-array-repeat-expr.stderr20
-rw-r--r--tests/ui/consts/issue-50439.rs4
-rw-r--r--tests/ui/consts/issue-50439.stderr10
-rw-r--r--tests/ui/self/elision/nested-item.rs13
-rw-r--r--tests/ui/self/elision/nested-item.stderr38
-rw-r--r--tests/ui/typeck/repeat-expr-checks-wf.rs10
-rw-r--r--tests/ui/typeck/repeat-expr-checks-wf.stderr12
49 files changed, 1084 insertions, 50 deletions
diff --git a/Cargo.lock b/Cargo.lock
index c368b4a79d3..e69b36cb983 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4740,6 +4740,15 @@ dependencies = [
]
[[package]]
+name = "sysroot"
+version = "0.0.0"
+dependencies = [
+ "proc_macro",
+ "std",
+ "test",
+]
+
+[[package]]
name = "tar"
version = "0.4.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4823,7 +4832,6 @@ dependencies = [
"getopts",
"panic_abort",
"panic_unwind",
- "proc_macro",
"std",
]
diff --git a/Cargo.toml b/Cargo.toml
index a497d7321e0..7aaa34a68e6 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 6259722b694..74e6ce37e97 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<DefUse> {
// `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 22de7549e94..4389d2b60bc 100644
--- a/compiler/rustc_borrowck/src/renumber.rs
+++ b/compiler/rustc_borrowck/src/renumber.rs
@@ -109,6 +109,14 @@ impl<'a, 'tcx> MutVisitor<'tcx> for RegionRenumberer<'a, 'tcx> {
}
#[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;
constant.literal = self.renumber_regions(literal, || RegionCtxt::Location(location));
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 601589480d1..dcabeb792be 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 0334c7ff132..569599faa36 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 047d8a82bfc..bba049c3819 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 0a9fcd898b9..6718605ed0b 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 bc67aa476f1..aeca0073304 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 deec66bbaf3..b3a3a25ebe8 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 f876b8c7ae0..6f5d54bcf87 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 a002421aeef..18f25aec5fe 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 cf16a3424a0..b9ef76c109a 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -2527,6 +2527,15 @@ impl<T: fmt::Display + ?Sized> 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 {
#[inline]
diff --git a/library/core/src/array/ascii.rs b/library/core/src/array/ascii.rs
new file mode 100644
index 00000000000..6750d7c0711
--- /dev/null
+++ b/library/core/src/array/ascii.rs
@@ -0,0 +1,34 @@
+use crate::ascii;
+
+#[cfg(not(test))]
+impl<const N: usize> [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 940558974e6..bdb4c975909 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 065f1b3e70e..7fd14a7e1ea 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 00000000000..f093a0990d1
--- /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 `<control>` 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<Self> {
+ 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<Self> {
+ 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 {
+ <str as fmt::Display>::fmt(self.as_str(), f)
+ }
+}
diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs
index 2408f178075..1dfa9c34db1 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<ascii::Char> {
+ 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 fdd7be625ed..08444421dca 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> {
+ 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 b80bfe1c92d..74a325b89d4 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 5e5399acc1b..7bae6692ad4 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 a13107fd0de..66fa9cf6f64 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 c29f015777f..b18ab50de12 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 00000000000..5356ee277cc
--- /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 00000000000..71ceb580a40
--- /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 18cb023d274..91a1abde059 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 2e07ce3c099..9f5bf24367e 100644
--- a/library/test/src/formatters/junit.rs
+++ b/library/test/src/formatters/junit.rs
@@ -11,7 +11,7 @@ use crate::{
pub struct JunitFormatter<T> {
out: OutputLocation<T>,
- results: Vec<(TestDesc, TestResult, Duration)>,
+ results: Vec<(TestDesc, TestResult, Duration, Vec<u8>)>,
}
impl<T: Write> JunitFormatter<T> {
@@ -26,6 +26,18 @@ impl<T: Write> JunitFormatter<T> {
}
}
+fn str_to_cdata(s: &str) -> String {
+ // Drop the stdout in a cdata. Unfortunately, you can't put either of `]]>` or
+ // `<?'` in a CDATA block, so the escaping gets a little weird.
+ let escaped_output = s.replace("]]>", "]]]]><![CDATA[>");
+ let escaped_output = escaped_output.replace("<?", "<]]><![CDATA[?");
+ // We also smuggle newlines as &#xa so as to keep all the output on one line
+ let escaped_output = escaped_output.replace("\n", "]]>&#xA;<![CDATA[");
+ // Prune empty CDATA blocks resulting from any escaping
+ let escaped_output = escaped_output.replace("<![CDATA[]]>", "");
+ format!("<![CDATA[{}]]>", escaped_output)
+}
+
impl<T: Write> OutputFormatter for JunitFormatter<T> {
fn write_discovery_start(&mut self) -> io::Result<()> {
Err(io::Error::new(io::ErrorKind::NotFound, "Not yet implemented!"))
@@ -63,14 +75,14 @@ impl<T: Write> OutputFormatter for JunitFormatter<T> {
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<bool> {
@@ -85,7 +97,7 @@ impl<T: Write> OutputFormatter for JunitFormatter<T> {
>",
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<T: Write> OutputFormatter for JunitFormatter<T> {
duration.as_secs_f64()
))?;
self.write_message("<failure type=\"assert\"/>")?;
+ if !stdout.is_empty() {
+ self.write_message("<system-out>")?;
+ self.write_message(&str_to_cdata(&String::from_utf8_lossy(&stdout)))?;
+ self.write_message("</system-out>")?;
+ }
self.write_message("</testcase>")?;
}
@@ -110,6 +127,11 @@ impl<T: Write> OutputFormatter for JunitFormatter<T> {
duration.as_secs_f64()
))?;
self.write_message(&format!("<failure message=\"{m}\" type=\"assert\"/>"))?;
+ if !stdout.is_empty() {
+ self.write_message("<system-out>")?;
+ self.write_message(&str_to_cdata(&String::from_utf8_lossy(&stdout)))?;
+ self.write_message("</system-out>")?;
+ }
self.write_message("</testcase>")?;
}
@@ -136,11 +158,19 @@ impl<T: Write> OutputFormatter for JunitFormatter<T> {
TestResult::TrOk => {
self.write_message(&format!(
"<testcase classname=\"{}\" \
- name=\"{}\" time=\"{}\"/>",
+ 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("><system-out>")?;
+ self.write_message(&str_to_cdata(&String::from_utf8_lossy(&stdout)))?;
+ self.write_message("</system-out>")?;
+ self.write_message("</testcase>")?;
+ }
}
}
}
diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index 60de46ce64c..956b82385f6 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 7ebd0a8f270..0d9fd56b038 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 7d2a6862500..966ae00fa1d 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 3b35ca1d15d..ab7f7350d5f 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 9ad98eb5702..8f5d9bb66e1 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 aee84e9c9be..cfccb516627 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 00000000000..4167becf5e9
--- /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 00000000000..761c074ed94
--- /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 00000000000..59dc74454a4
--- /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 00000000000..d97cafccf1f
--- /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 00000000000..d360d77317d
--- /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 00000000000..d59e07b8ad8
--- /dev/null
+++ b/tests/run-make/libtest-junit/output-default.xml
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><testsuites><testsuite name="test" package="test" id="0" errors="0" failures="1" tests="4" skipped="1" ><testcase classname="unknown" name="a" time="$TIME"/><testcase classname="unknown" name="b" time="$TIME"><failure type="assert"/><system-out><![CDATA[print from failing test]]>&#xA;<![CDATA[thread 'b' panicked at 'assertion failed: false', f.rs:10:5]]>&#xA;<![CDATA[note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace]]>&#xA;<![CDATA[]]></system-out></testcase><testcase classname="unknown" name="c" time="$TIME"/><system-out/><system-err/></testsuite></testsuites>
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 00000000000..0c300611e1f
--- /dev/null
+++ b/tests/run-make/libtest-junit/output-stdout-success.xml
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><testsuites><testsuite name="test" package="test" id="0" errors="0" failures="1" tests="4" skipped="1" ><testcase classname="unknown" name="a" time="$TIME"><system-out><![CDATA[print from successful test]]>&#xA;<![CDATA[]]></system-out></testcase><testcase classname="unknown" name="b" time="$TIME"><failure type="assert"/><system-out><![CDATA[print from failing test]]>&#xA;<![CDATA[thread 'b' panicked at 'assertion failed: false', f.rs:10:5]]>&#xA;<![CDATA[note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace]]>&#xA;<![CDATA[]]></system-out></testcase><testcase classname="unknown" name="c" time="$TIME"><system-out><![CDATA[thread 'c' panicked at 'assertion failed: false', f.rs:16:5]]>&#xA;<![CDATA[]]></system-out></testcase><system-out/><system-err/></testsuite></testsuites>
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 00000000000..47a8e70ccc3
--- /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 b147c246bda..cd1607608a6 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<const N: usize> Trait<N> for () {
pub const fn foo<const N: usize>() where (): Trait<N> {
let bar = [(); <()>::Assoc];
//~^ error: constant expression depends on a generic parameter
+ //~| error: constant expression depends on a generic parameter
}
trait Trait2<const N: usize> {
@@ -24,6 +25,7 @@ impl<const N: usize> Trait2<N> for () {
pub const fn foo2<const N: usize>() where (): Trait2<N> {
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 5c77375d399..e532f27a10d 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 0be7c405473..d42347e136e 100644
--- a/tests/ui/consts/issue-50439.rs
+++ b/tests/ui/consts/issue-50439.rs
@@ -22,7 +22,9 @@ impl<T: Sized> PinDropInternal for Bears<T> {
where
Self: ReflectDrop,
{
- let _ = [(); 0 - !!(<Bears<T> as ReflectDrop>::REFLECT_DROP) as usize]; //~ ERROR constant expression depends on a generic parameter
+ let _ = [(); 0 - !!(<Bears<T> 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 3fbdf33b2d8..7a8cd45ecc7 100644
--- a/tests/ui/consts/issue-50439.stderr
+++ b/tests/ui/consts/issue-50439.stderr
@@ -6,5 +6,13 @@ LL | let _ = [(); 0 - !!(<Bears<T> 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 - !!(<Bears<T> 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 00000000000..4bcb645c60e
--- /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 00000000000..752fd82332c
--- /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 00000000000..b8a2a0ceb58
--- /dev/null
+++ b/tests/ui/typeck/repeat-expr-checks-wf.rs
@@ -0,0 +1,10 @@
+trait Foo {
+ const ASSOC: [u8];
+}
+
+fn bar<T: Foo>() {
+ 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 00000000000..a821088a4b3
--- /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`.