1
Fork 0

Auto merge of #104192 - Dylan-DPC:rollup-jjo1o80, r=Dylan-DPC

Rollup of 7 pull requests

Successful merges:

 - #103570 (Stabilize integer logarithms)
 - #103694 (Add documentation examples for `pointer::mask`)
 - #103919 (Unescaping cleanups)
 - #103933 (Promote {aarch64,i686,x86_64}-unknown-uefi to Tier 2)
 - #103952 (Don't intra linkcheck reference)
 - #104111 (rustdoc: Add mutable to the description)
 - #104125 (Const Compare for Tuples)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2022-11-09 16:54:02 +00:00
commit c71658706f
36 changed files with 340 additions and 366 deletions

View file

@ -2,12 +2,9 @@
use crate::ast::{self, Lit, LitKind}; use crate::ast::{self, Lit, LitKind};
use crate::token::{self, Token}; use crate::token::{self, Token};
use rustc_lexer::unescape::{byte_from_char, unescape_byte, unescape_char, unescape_literal, Mode};
use rustc_lexer::unescape::{unescape_byte, unescape_char};
use rustc_lexer::unescape::{unescape_byte_literal, unescape_literal, Mode};
use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::Span; use rustc_span::Span;
use std::ascii; use std::ascii;
pub enum LitError { pub enum LitError {
@ -109,13 +106,11 @@ impl LitKind {
let s = symbol.as_str(); let s = symbol.as_str();
let mut buf = Vec::with_capacity(s.len()); let mut buf = Vec::with_capacity(s.len());
let mut error = Ok(()); let mut error = Ok(());
unescape_byte_literal(&s, Mode::ByteStr, &mut |_, unescaped_byte| { unescape_literal(&s, Mode::ByteStr, &mut |_, c| match c {
match unescaped_byte { Ok(c) => buf.push(byte_from_char(c)),
Ok(c) => buf.push(c), Err(err) => {
Err(err) => { if err.is_fatal() {
if err.is_fatal() { error = Err(LitError::LexerError);
error = Err(LitError::LexerError);
}
} }
} }
}); });
@ -127,13 +122,11 @@ impl LitKind {
let bytes = if s.contains('\r') { let bytes = if s.contains('\r') {
let mut buf = Vec::with_capacity(s.len()); let mut buf = Vec::with_capacity(s.len());
let mut error = Ok(()); let mut error = Ok(());
unescape_byte_literal(&s, Mode::RawByteStr, &mut |_, unescaped_byte| { unescape_literal(&s, Mode::RawByteStr, &mut |_, c| match c {
match unescaped_byte { Ok(c) => buf.push(byte_from_char(c)),
Ok(c) => buf.push(c), Err(err) => {
Err(err) => { if err.is_fatal() {
if err.is_fatal() { error = Err(LitError::LexerError);
error = Err(LitError::LexerError);
}
} }
} }
}); });

View file

@ -205,13 +205,13 @@ pub enum RawStrError {
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum Base { pub enum Base {
/// Literal starts with "0b". /// Literal starts with "0b".
Binary, Binary = 2,
/// Literal starts with "0o". /// Literal starts with "0o".
Octal, Octal = 8,
/// Literal starts with "0x".
Hexadecimal,
/// Literal doesn't contain a prefix. /// Literal doesn't contain a prefix.
Decimal, Decimal = 10,
/// Literal starts with "0x".
Hexadecimal = 16,
} }
/// `rustc` allows files to have a shebang, e.g. "#!/usr/bin/rustrun", /// `rustc` allows files to have a shebang, e.g. "#!/usr/bin/rustrun",

View file

@ -52,10 +52,8 @@ pub enum EscapeError {
/// Unicode escape code in byte literal. /// Unicode escape code in byte literal.
UnicodeEscapeInByte, UnicodeEscapeInByte,
/// Non-ascii character in byte literal. /// Non-ascii character in byte literal, byte string literal, or raw byte string literal.
NonAsciiCharInByte, NonAsciiCharInByte,
/// Non-ascii character in byte string literal.
NonAsciiCharInByteString,
/// After a line ending with '\', the next line contains whitespace /// After a line ending with '\', the next line contains whitespace
/// characters that are not skipped. /// characters that are not skipped.
@ -78,54 +76,33 @@ impl EscapeError {
/// Takes a contents of a literal (without quotes) and produces a /// Takes a contents of a literal (without quotes) and produces a
/// sequence of escaped characters or errors. /// sequence of escaped characters or errors.
/// Values are returned through invoking of the provided callback. /// Values are returned through invoking of the provided callback.
pub fn unescape_literal<F>(literal_text: &str, mode: Mode, callback: &mut F) pub fn unescape_literal<F>(src: &str, mode: Mode, callback: &mut F)
where where
F: FnMut(Range<usize>, Result<char, EscapeError>), F: FnMut(Range<usize>, Result<char, EscapeError>),
{ {
match mode { match mode {
Mode::Char | Mode::Byte => { Mode::Char | Mode::Byte => {
let mut chars = literal_text.chars(); let mut chars = src.chars();
let result = unescape_char_or_byte(&mut chars, mode); let res = unescape_char_or_byte(&mut chars, mode == Mode::Byte);
// The Chars iterator moved forward. callback(0..(src.len() - chars.as_str().len()), res);
callback(0..(literal_text.len() - chars.as_str().len()), result);
} }
Mode::Str | Mode::ByteStr => unescape_str_or_byte_str(literal_text, mode, callback), Mode::Str | Mode::ByteStr => unescape_str_or_byte_str(src, mode == Mode::ByteStr, callback),
// NOTE: Raw strings do not perform any explicit character escaping, here we
// only translate CRLF to LF and produce errors on bare CR.
Mode::RawStr | Mode::RawByteStr => { Mode::RawStr | Mode::RawByteStr => {
unescape_raw_str_or_raw_byte_str(literal_text, mode, callback) unescape_raw_str_or_raw_byte_str(src, mode == Mode::RawByteStr, callback)
} }
} }
} }
/// Takes a contents of a byte, byte string or raw byte string (without quotes)
/// and produces a sequence of bytes or errors.
/// Values are returned through invoking of the provided callback.
pub fn unescape_byte_literal<F>(literal_text: &str, mode: Mode, callback: &mut F)
where
F: FnMut(Range<usize>, Result<u8, EscapeError>),
{
debug_assert!(mode.is_bytes());
unescape_literal(literal_text, mode, &mut |range, result| {
callback(range, result.map(byte_from_char));
})
}
/// Takes a contents of a char literal (without quotes), and returns an /// Takes a contents of a char literal (without quotes), and returns an
/// unescaped char or an error /// unescaped char or an error.
pub fn unescape_char(literal_text: &str) -> Result<char, (usize, EscapeError)> { pub fn unescape_char(src: &str) -> Result<char, EscapeError> {
let mut chars = literal_text.chars(); unescape_char_or_byte(&mut src.chars(), false)
unescape_char_or_byte(&mut chars, Mode::Char)
.map_err(|err| (literal_text.len() - chars.as_str().len(), err))
} }
/// Takes a contents of a byte literal (without quotes), and returns an /// Takes a contents of a byte literal (without quotes), and returns an
/// unescaped byte or an error. /// unescaped byte or an error.
pub fn unescape_byte(literal_text: &str) -> Result<u8, (usize, EscapeError)> { pub fn unescape_byte(src: &str) -> Result<u8, EscapeError> {
let mut chars = literal_text.chars(); unescape_char_or_byte(&mut src.chars(), true).map(byte_from_char)
unescape_char_or_byte(&mut chars, Mode::Byte)
.map(byte_from_char)
.map_err(|err| (literal_text.len() - chars.as_str().len(), err))
} }
/// What kind of literal do we parse. /// What kind of literal do we parse.
@ -147,7 +124,7 @@ impl Mode {
} }
} }
pub fn is_bytes(self) -> bool { pub fn is_byte(self) -> bool {
match self { match self {
Mode::Byte | Mode::ByteStr | Mode::RawByteStr => true, Mode::Byte | Mode::ByteStr | Mode::RawByteStr => true,
Mode::Char | Mode::Str | Mode::RawStr => false, Mode::Char | Mode::Str | Mode::RawStr => false,
@ -155,12 +132,9 @@ impl Mode {
} }
} }
fn scan_escape(chars: &mut Chars<'_>, mode: Mode) -> Result<char, EscapeError> { fn scan_escape(chars: &mut Chars<'_>, is_byte: bool) -> Result<char, EscapeError> {
// Previous character was '\\', unescape what follows. // Previous character was '\\', unescape what follows.
let res = match chars.next().ok_or(EscapeError::LoneSlash)? {
let second_char = chars.next().ok_or(EscapeError::LoneSlash)?;
let res = match second_char {
'"' => '"', '"' => '"',
'n' => '\n', 'n' => '\n',
'r' => '\r', 'r' => '\r',
@ -181,7 +155,7 @@ fn scan_escape(chars: &mut Chars<'_>, mode: Mode) -> Result<char, EscapeError> {
let value = hi * 16 + lo; let value = hi * 16 + lo;
// For a non-byte literal verify that it is within ASCII range. // For a non-byte literal verify that it is within ASCII range.
if !mode.is_bytes() && !is_ascii(value) { if !is_byte && !is_ascii(value) {
return Err(EscapeError::OutOfRangeHexEscape); return Err(EscapeError::OutOfRangeHexEscape);
} }
let value = value as u8; let value = value as u8;
@ -217,7 +191,7 @@ fn scan_escape(chars: &mut Chars<'_>, mode: Mode) -> Result<char, EscapeError> {
// Incorrect syntax has higher priority for error reporting // Incorrect syntax has higher priority for error reporting
// than unallowed value for a literal. // than unallowed value for a literal.
if mode.is_bytes() { if is_byte {
return Err(EscapeError::UnicodeEscapeInByte); return Err(EscapeError::UnicodeEscapeInByte);
} }
@ -249,23 +223,22 @@ fn scan_escape(chars: &mut Chars<'_>, mode: Mode) -> Result<char, EscapeError> {
} }
#[inline] #[inline]
fn ascii_check(first_char: char, mode: Mode) -> Result<char, EscapeError> { fn ascii_check(c: char, is_byte: bool) -> Result<char, EscapeError> {
if mode.is_bytes() && !first_char.is_ascii() { if is_byte && !c.is_ascii() {
// Byte literal can't be a non-ascii character. // Byte literal can't be a non-ascii character.
Err(EscapeError::NonAsciiCharInByte) Err(EscapeError::NonAsciiCharInByte)
} else { } else {
Ok(first_char) Ok(c)
} }
} }
fn unescape_char_or_byte(chars: &mut Chars<'_>, mode: Mode) -> Result<char, EscapeError> { fn unescape_char_or_byte(chars: &mut Chars<'_>, is_byte: bool) -> Result<char, EscapeError> {
debug_assert!(mode == Mode::Char || mode == Mode::Byte); let c = chars.next().ok_or(EscapeError::ZeroChars)?;
let first_char = chars.next().ok_or(EscapeError::ZeroChars)?; let res = match c {
let res = match first_char { '\\' => scan_escape(chars, is_byte),
'\\' => scan_escape(chars, mode),
'\n' | '\t' | '\'' => Err(EscapeError::EscapeOnlyChar), '\n' | '\t' | '\'' => Err(EscapeError::EscapeOnlyChar),
'\r' => Err(EscapeError::BareCarriageReturn), '\r' => Err(EscapeError::BareCarriageReturn),
_ => ascii_check(first_char, mode), _ => ascii_check(c, is_byte),
}?; }?;
if chars.next().is_some() { if chars.next().is_some() {
return Err(EscapeError::MoreThanOneChar); return Err(EscapeError::MoreThanOneChar);
@ -275,20 +248,20 @@ fn unescape_char_or_byte(chars: &mut Chars<'_>, mode: Mode) -> Result<char, Esca
/// Takes a contents of a string literal (without quotes) and produces a /// Takes a contents of a string literal (without quotes) and produces a
/// sequence of escaped characters or errors. /// sequence of escaped characters or errors.
fn unescape_str_or_byte_str<F>(src: &str, mode: Mode, callback: &mut F) fn unescape_str_or_byte_str<F>(src: &str, is_byte: bool, callback: &mut F)
where where
F: FnMut(Range<usize>, Result<char, EscapeError>), F: FnMut(Range<usize>, Result<char, EscapeError>),
{ {
debug_assert!(mode == Mode::Str || mode == Mode::ByteStr);
let initial_len = src.len();
let mut chars = src.chars(); let mut chars = src.chars();
while let Some(first_char) = chars.next() {
let start = initial_len - chars.as_str().len() - first_char.len_utf8();
let unescaped_char = match first_char { // The `start` and `end` computation here is complicated because
// `skip_ascii_whitespace` makes us to skip over chars without counting
// them in the range computation.
while let Some(c) = chars.next() {
let start = src.len() - chars.as_str().len() - c.len_utf8();
let res = match c {
'\\' => { '\\' => {
let second_char = chars.clone().next(); match chars.clone().next() {
match second_char {
Some('\n') => { Some('\n') => {
// Rust language specification requires us to skip whitespaces // Rust language specification requires us to skip whitespaces
// if unescaped '\' character is followed by '\n'. // if unescaped '\' character is followed by '\n'.
@ -297,17 +270,17 @@ where
skip_ascii_whitespace(&mut chars, start, callback); skip_ascii_whitespace(&mut chars, start, callback);
continue; continue;
} }
_ => scan_escape(&mut chars, mode), _ => scan_escape(&mut chars, is_byte),
} }
} }
'\n' => Ok('\n'), '\n' => Ok('\n'),
'\t' => Ok('\t'), '\t' => Ok('\t'),
'"' => Err(EscapeError::EscapeOnlyChar), '"' => Err(EscapeError::EscapeOnlyChar),
'\r' => Err(EscapeError::BareCarriageReturn), '\r' => Err(EscapeError::BareCarriageReturn),
_ => ascii_check(first_char, mode), _ => ascii_check(c, is_byte),
}; };
let end = initial_len - chars.as_str().len(); let end = src.len() - chars.as_str().len();
callback(start..end, unescaped_char); callback(start..end, res);
} }
fn skip_ascii_whitespace<F>(chars: &mut Chars<'_>, start: usize, callback: &mut F) fn skip_ascii_whitespace<F>(chars: &mut Chars<'_>, start: usize, callback: &mut F)
@ -340,30 +313,29 @@ where
/// Takes a contents of a string literal (without quotes) and produces a /// Takes a contents of a string literal (without quotes) and produces a
/// sequence of characters or errors. /// sequence of characters or errors.
/// NOTE: Raw strings do not perform any explicit character escaping, here we /// NOTE: Raw strings do not perform any explicit character escaping, here we
/// only translate CRLF to LF and produce errors on bare CR. /// only produce errors on bare CR.
fn unescape_raw_str_or_raw_byte_str<F>(literal_text: &str, mode: Mode, callback: &mut F) fn unescape_raw_str_or_raw_byte_str<F>(src: &str, is_byte: bool, callback: &mut F)
where where
F: FnMut(Range<usize>, Result<char, EscapeError>), F: FnMut(Range<usize>, Result<char, EscapeError>),
{ {
debug_assert!(mode == Mode::RawStr || mode == Mode::RawByteStr); let mut chars = src.chars();
let initial_len = literal_text.len();
let mut chars = literal_text.chars(); // The `start` and `end` computation here matches the one in
while let Some(curr) = chars.next() { // `unescape_str_or_byte_str` for consistency, even though this function
let start = initial_len - chars.as_str().len() - curr.len_utf8(); // doesn't have to worry about skipping any chars.
while let Some(c) = chars.next() {
let result = match curr { let start = src.len() - chars.as_str().len() - c.len_utf8();
let res = match c {
'\r' => Err(EscapeError::BareCarriageReturnInRawString), '\r' => Err(EscapeError::BareCarriageReturnInRawString),
c if mode.is_bytes() && !c.is_ascii() => Err(EscapeError::NonAsciiCharInByteString), _ => ascii_check(c, is_byte),
c => Ok(c),
}; };
let end = initial_len - chars.as_str().len(); let end = src.len() - chars.as_str().len();
callback(start..end, res);
callback(start..end, result);
} }
} }
fn byte_from_char(c: char) -> u8 { #[inline]
pub fn byte_from_char(c: char) -> u8 {
let res = c as u32; let res = c as u32;
debug_assert!(res <= u8::MAX as u32, "guaranteed because of Mode::ByteStr"); debug_assert!(res <= u8::MAX as u32, "guaranteed because of Mode::ByteStr");
res as u8 res as u8

View file

@ -3,8 +3,7 @@ use super::*;
#[test] #[test]
fn test_unescape_char_bad() { fn test_unescape_char_bad() {
fn check(literal_text: &str, expected_error: EscapeError) { fn check(literal_text: &str, expected_error: EscapeError) {
let actual_result = unescape_char(literal_text).map_err(|(_offset, err)| err); assert_eq!(unescape_char(literal_text), Err(expected_error));
assert_eq!(actual_result, Err(expected_error));
} }
check("", EscapeError::ZeroChars); check("", EscapeError::ZeroChars);
@ -68,8 +67,7 @@ fn test_unescape_char_bad() {
#[test] #[test]
fn test_unescape_char_good() { fn test_unescape_char_good() {
fn check(literal_text: &str, expected_char: char) { fn check(literal_text: &str, expected_char: char) {
let actual_result = unescape_char(literal_text); assert_eq!(unescape_char(literal_text), Ok(expected_char));
assert_eq!(actual_result, Ok(expected_char));
} }
check("a", 'a'); check("a", 'a');
@ -149,8 +147,7 @@ fn test_unescape_str_good() {
#[test] #[test]
fn test_unescape_byte_bad() { fn test_unescape_byte_bad() {
fn check(literal_text: &str, expected_error: EscapeError) { fn check(literal_text: &str, expected_error: EscapeError) {
let actual_result = unescape_byte(literal_text).map_err(|(_offset, err)| err); assert_eq!(unescape_byte(literal_text), Err(expected_error));
assert_eq!(actual_result, Err(expected_error));
} }
check("", EscapeError::ZeroChars); check("", EscapeError::ZeroChars);
@ -219,8 +216,7 @@ fn test_unescape_byte_bad() {
#[test] #[test]
fn test_unescape_byte_good() { fn test_unescape_byte_good() {
fn check(literal_text: &str, expected_byte: u8) { fn check(literal_text: &str, expected_byte: u8) {
let actual_result = unescape_byte(literal_text); assert_eq!(unescape_byte(literal_text), Ok(expected_byte));
assert_eq!(actual_result, Ok(expected_byte));
} }
check("a", b'a'); check("a", b'a');
@ -246,10 +242,10 @@ fn test_unescape_byte_good() {
fn test_unescape_byte_str_good() { fn test_unescape_byte_str_good() {
fn check(literal_text: &str, expected: &[u8]) { fn check(literal_text: &str, expected: &[u8]) {
let mut buf = Ok(Vec::with_capacity(literal_text.len())); let mut buf = Ok(Vec::with_capacity(literal_text.len()));
unescape_byte_literal(literal_text, Mode::ByteStr, &mut |range, c| { unescape_literal(literal_text, Mode::ByteStr, &mut |range, c| {
if let Ok(b) = &mut buf { if let Ok(b) = &mut buf {
match c { match c {
Ok(c) => b.push(c), Ok(c) => b.push(byte_from_char(c)),
Err(e) => buf = Err((range, e)), Err(e) => buf = Err((range, e)),
} }
} }
@ -280,18 +276,13 @@ fn test_unescape_raw_str() {
#[test] #[test]
fn test_unescape_raw_byte_str() { fn test_unescape_raw_byte_str() {
fn check(literal: &str, expected: &[(Range<usize>, Result<u8, EscapeError>)]) { fn check(literal: &str, expected: &[(Range<usize>, Result<char, EscapeError>)]) {
let mut unescaped = Vec::with_capacity(literal.len()); let mut unescaped = Vec::with_capacity(literal.len());
unescape_byte_literal(literal, Mode::RawByteStr, &mut |range, res| { unescape_literal(literal, Mode::RawByteStr, &mut |range, res| unescaped.push((range, res)));
unescaped.push((range, res))
});
assert_eq!(unescaped, expected); assert_eq!(unescaped, expected);
} }
check("\r", &[(0..1, Err(EscapeError::BareCarriageReturnInRawString))]); check("\r", &[(0..1, Err(EscapeError::BareCarriageReturnInRawString))]);
check("🦀", &[(0..4, Err(EscapeError::NonAsciiCharInByteString))]); check("🦀", &[(0..4, Err(EscapeError::NonAsciiCharInByte))]);
check( check("🦀a", &[(0..4, Err(EscapeError::NonAsciiCharInByte)), (4..5, Ok('a'))]);
"🦀a",
&[(0..4, Err(EscapeError::NonAsciiCharInByteString)), (4..5, Ok(byte_from_char('a')))],
);
} }

View file

@ -353,55 +353,55 @@ impl<'a> StringReader<'a> {
fn cook_lexer_literal( fn cook_lexer_literal(
&self, &self,
start: BytePos, start: BytePos,
suffix_start: BytePos, end: BytePos,
kind: rustc_lexer::LiteralKind, kind: rustc_lexer::LiteralKind,
) -> (token::LitKind, Symbol) { ) -> (token::LitKind, Symbol) {
// prefix means `"` or `br"` or `r###"`, ... match kind {
let (lit_kind, mode, prefix_len, postfix_len) = match kind {
rustc_lexer::LiteralKind::Char { terminated } => { rustc_lexer::LiteralKind::Char { terminated } => {
if !terminated { if !terminated {
self.sess.span_diagnostic.span_fatal_with_code( self.sess.span_diagnostic.span_fatal_with_code(
self.mk_sp(start, suffix_start), self.mk_sp(start, end),
"unterminated character literal", "unterminated character literal",
error_code!(E0762), error_code!(E0762),
) )
} }
(token::Char, Mode::Char, 1, 1) // ' ' self.cook_quoted(token::Char, Mode::Char, start, end, 1, 1) // ' '
} }
rustc_lexer::LiteralKind::Byte { terminated } => { rustc_lexer::LiteralKind::Byte { terminated } => {
if !terminated { if !terminated {
self.sess.span_diagnostic.span_fatal_with_code( self.sess.span_diagnostic.span_fatal_with_code(
self.mk_sp(start + BytePos(1), suffix_start), self.mk_sp(start + BytePos(1), end),
"unterminated byte constant", "unterminated byte constant",
error_code!(E0763), error_code!(E0763),
) )
} }
(token::Byte, Mode::Byte, 2, 1) // b' ' self.cook_quoted(token::Byte, Mode::Byte, start, end, 2, 1) // b' '
} }
rustc_lexer::LiteralKind::Str { terminated } => { rustc_lexer::LiteralKind::Str { terminated } => {
if !terminated { if !terminated {
self.sess.span_diagnostic.span_fatal_with_code( self.sess.span_diagnostic.span_fatal_with_code(
self.mk_sp(start, suffix_start), self.mk_sp(start, end),
"unterminated double quote string", "unterminated double quote string",
error_code!(E0765), error_code!(E0765),
) )
} }
(token::Str, Mode::Str, 1, 1) // " " self.cook_quoted(token::Str, Mode::Str, start, end, 1, 1) // " "
} }
rustc_lexer::LiteralKind::ByteStr { terminated } => { rustc_lexer::LiteralKind::ByteStr { terminated } => {
if !terminated { if !terminated {
self.sess.span_diagnostic.span_fatal_with_code( self.sess.span_diagnostic.span_fatal_with_code(
self.mk_sp(start + BytePos(1), suffix_start), self.mk_sp(start + BytePos(1), end),
"unterminated double quote byte string", "unterminated double quote byte string",
error_code!(E0766), error_code!(E0766),
) )
} }
(token::ByteStr, Mode::ByteStr, 2, 1) // b" " self.cook_quoted(token::ByteStr, Mode::ByteStr, start, end, 2, 1) // b" "
} }
rustc_lexer::LiteralKind::RawStr { n_hashes } => { rustc_lexer::LiteralKind::RawStr { n_hashes } => {
if let Some(n_hashes) = n_hashes { if let Some(n_hashes) = n_hashes {
let n = u32::from(n_hashes); let n = u32::from(n_hashes);
(token::StrRaw(n_hashes), Mode::RawStr, 2 + n, 1 + n) // r##" "## let kind = token::StrRaw(n_hashes);
self.cook_quoted(kind, Mode::RawStr, start, end, 2 + n, 1 + n) // r##" "##
} else { } else {
self.report_raw_str_error(start, 1); self.report_raw_str_error(start, 1);
} }
@ -409,56 +409,59 @@ impl<'a> StringReader<'a> {
rustc_lexer::LiteralKind::RawByteStr { n_hashes } => { rustc_lexer::LiteralKind::RawByteStr { n_hashes } => {
if let Some(n_hashes) = n_hashes { if let Some(n_hashes) = n_hashes {
let n = u32::from(n_hashes); let n = u32::from(n_hashes);
(token::ByteStrRaw(n_hashes), Mode::RawByteStr, 3 + n, 1 + n) // br##" "## let kind = token::ByteStrRaw(n_hashes);
self.cook_quoted(kind, Mode::RawByteStr, start, end, 3 + n, 1 + n) // br##" "##
} else { } else {
self.report_raw_str_error(start, 2); self.report_raw_str_error(start, 2);
} }
} }
rustc_lexer::LiteralKind::Int { base, empty_int } => { rustc_lexer::LiteralKind::Int { base, empty_int } => {
return if empty_int { if empty_int {
self.sess self.sess
.span_diagnostic .span_diagnostic
.struct_span_err_with_code( .struct_span_err_with_code(
self.mk_sp(start, suffix_start), self.mk_sp(start, end),
"no valid digits found for number", "no valid digits found for number",
error_code!(E0768), error_code!(E0768),
) )
.emit(); .emit();
(token::Integer, sym::integer(0)) (token::Integer, sym::integer(0))
} else { } else {
self.validate_int_literal(base, start, suffix_start); if matches!(base, Base::Binary | Base::Octal) {
(token::Integer, self.symbol_from_to(start, suffix_start)) let base = base as u32;
}; let s = self.str_from_to(start + BytePos(2), end);
for (idx, c) in s.char_indices() {
if c != '_' && c.to_digit(base).is_none() {
self.err_span_(
start + BytePos::from_usize(2 + idx),
start + BytePos::from_usize(2 + idx + c.len_utf8()),
&format!("invalid digit for a base {} literal", base),
);
}
}
}
(token::Integer, self.symbol_from_to(start, end))
}
} }
rustc_lexer::LiteralKind::Float { base, empty_exponent } => { rustc_lexer::LiteralKind::Float { base, empty_exponent } => {
if empty_exponent { if empty_exponent {
self.err_span_(start, self.pos, "expected at least one digit in exponent"); self.err_span_(start, self.pos, "expected at least one digit in exponent");
} }
match base { match base {
Base::Hexadecimal => self.err_span_( Base::Hexadecimal => {
start, self.err_span_(start, end, "hexadecimal float literal is not supported")
suffix_start, }
"hexadecimal float literal is not supported",
),
Base::Octal => { Base::Octal => {
self.err_span_(start, suffix_start, "octal float literal is not supported") self.err_span_(start, end, "octal float literal is not supported")
} }
Base::Binary => { Base::Binary => {
self.err_span_(start, suffix_start, "binary float literal is not supported") self.err_span_(start, end, "binary float literal is not supported")
} }
_ => (), _ => {}
} }
(token::Float, self.symbol_from_to(start, end))
let id = self.symbol_from_to(start, suffix_start);
return (token::Float, id);
} }
}; }
let content_start = start + BytePos(prefix_len);
let content_end = suffix_start - BytePos(postfix_len);
let id = self.symbol_from_to(content_start, content_end);
self.validate_literal_escape(mode, content_start, content_end, prefix_len, postfix_len);
(lit_kind, id)
} }
#[inline] #[inline]
@ -649,20 +652,22 @@ impl<'a> StringReader<'a> {
) )
} }
fn validate_literal_escape( fn cook_quoted(
&self, &self,
kind: token::LitKind,
mode: Mode, mode: Mode,
content_start: BytePos, start: BytePos,
content_end: BytePos, end: BytePos,
prefix_len: u32, prefix_len: u32,
postfix_len: u32, postfix_len: u32,
) { ) -> (token::LitKind, Symbol) {
let content_start = start + BytePos(prefix_len);
let content_end = end - BytePos(postfix_len);
let lit_content = self.str_from_to(content_start, content_end); let lit_content = self.str_from_to(content_start, content_end);
unescape::unescape_literal(lit_content, mode, &mut |range, result| { unescape::unescape_literal(lit_content, mode, &mut |range, result| {
// Here we only check for errors. The actual unescaping is done later. // Here we only check for errors. The actual unescaping is done later.
if let Err(err) = result { if let Err(err) = result {
let span_with_quotes = self let span_with_quotes = self.mk_sp(start, end);
.mk_sp(content_start - BytePos(prefix_len), content_end + BytePos(postfix_len));
let (start, end) = (range.start as u32, range.end as u32); let (start, end) = (range.start as u32, range.end as u32);
let lo = content_start + BytePos(start); let lo = content_start + BytePos(start);
let hi = lo + BytePos(end - start); let hi = lo + BytePos(end - start);
@ -678,23 +683,7 @@ impl<'a> StringReader<'a> {
); );
} }
}); });
} (kind, Symbol::intern(lit_content))
fn validate_int_literal(&self, base: Base, content_start: BytePos, content_end: BytePos) {
let base = match base {
Base::Binary => 2,
Base::Octal => 8,
_ => return,
};
let s = self.str_from_to(content_start + BytePos(2), content_end);
for (idx, c) in s.char_indices() {
let idx = idx as u32;
if c != '_' && c.to_digit(base).is_none() {
let lo = content_start + BytePos(2 + idx);
let hi = content_start + BytePos(2 + idx + c.len_utf8() as u32);
self.err_span_(lo, hi, &format!("invalid digit for a base {} literal", base));
}
}
} }
} }

View file

@ -108,7 +108,7 @@ pub(crate) fn emit_unescape_error(
} }
if !has_help { if !has_help {
let (prefix, msg) = if mode.is_bytes() { let (prefix, msg) = if mode.is_byte() {
("b", "if you meant to write a byte string literal, use double quotes") ("b", "if you meant to write a byte string literal, use double quotes")
} else { } else {
("", "if you meant to write a `str` literal, use double quotes") ("", "if you meant to write a `str` literal, use double quotes")
@ -142,7 +142,7 @@ pub(crate) fn emit_unescape_error(
EscapeError::EscapeOnlyChar => { EscapeError::EscapeOnlyChar => {
let (c, char_span) = last_char(); let (c, char_span) = last_char();
let msg = if mode.is_bytes() { let msg = if mode.is_byte() {
"byte constant must be escaped" "byte constant must be escaped"
} else { } else {
"character constant must be escaped" "character constant must be escaped"
@ -182,11 +182,11 @@ pub(crate) fn emit_unescape_error(
let (c, span) = last_char(); let (c, span) = last_char();
let label = let label =
if mode.is_bytes() { "unknown byte escape" } else { "unknown character escape" }; if mode.is_byte() { "unknown byte escape" } else { "unknown character escape" };
let ec = escaped_char(c); let ec = escaped_char(c);
let mut diag = handler.struct_span_err(span, &format!("{}: `{}`", label, ec)); let mut diag = handler.struct_span_err(span, &format!("{}: `{}`", label, ec));
diag.span_label(span, label); diag.span_label(span, label);
if c == '{' || c == '}' && !mode.is_bytes() { if c == '{' || c == '}' && !mode.is_byte() {
diag.help( diag.help(
"if used in a formatting string, curly braces are escaped with `{{` and `}}`", "if used in a formatting string, curly braces are escaped with `{{` and `}}`",
); );
@ -196,7 +196,7 @@ pub(crate) fn emit_unescape_error(
version control settings", version control settings",
); );
} else { } else {
if !mode.is_bytes() { if !mode.is_byte() {
diag.span_suggestion( diag.span_suggestion(
span_with_quotes, span_with_quotes,
"if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal", "if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal",
@ -231,16 +231,23 @@ pub(crate) fn emit_unescape_error(
.emit(); .emit();
} }
EscapeError::NonAsciiCharInByte => { EscapeError::NonAsciiCharInByte => {
assert!(mode.is_bytes());
let (c, span) = last_char(); let (c, span) = last_char();
let mut err = handler.struct_span_err(span, "non-ASCII character in byte constant"); let desc = match mode {
Mode::Byte => "byte literal",
Mode::ByteStr => "byte string literal",
Mode::RawByteStr => "raw byte string literal",
_ => panic!("non-is_byte literal paired with NonAsciiCharInByte"),
};
let mut err = handler.struct_span_err(span, format!("non-ASCII character in {}", desc));
let postfix = if unicode_width::UnicodeWidthChar::width(c).unwrap_or(1) == 0 { let postfix = if unicode_width::UnicodeWidthChar::width(c).unwrap_or(1) == 0 {
format!(" but is {:?}", c) format!(" but is {:?}", c)
} else { } else {
String::new() String::new()
}; };
err.span_label(span, &format!("byte constant must be ASCII{}", postfix)); err.span_label(span, &format!("must be ASCII{}", postfix));
if (c as u32) <= 0xFF { // Note: the \\xHH suggestions are not given for raw byte string
// literals, because they are araw and so cannot use any escapes.
if (c as u32) <= 0xFF && mode != Mode::RawByteStr {
err.span_suggestion( err.span_suggestion(
span, span,
&format!( &format!(
@ -250,9 +257,9 @@ pub(crate) fn emit_unescape_error(
format!("\\x{:X}", c as u32), format!("\\x{:X}", c as u32),
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
} else if matches!(mode, Mode::Byte) { } else if mode == Mode::Byte {
err.span_label(span, "this multibyte character does not fit into a single byte"); err.span_label(span, "this multibyte character does not fit into a single byte");
} else if matches!(mode, Mode::ByteStr) { } else if mode != Mode::RawByteStr {
let mut utf8 = String::new(); let mut utf8 = String::new();
utf8.push(c); utf8.push(c);
err.span_suggestion( err.span_suggestion(
@ -270,19 +277,6 @@ pub(crate) fn emit_unescape_error(
} }
err.emit(); err.emit();
} }
EscapeError::NonAsciiCharInByteString => {
assert!(mode.is_bytes());
let (c, span) = last_char();
let postfix = if unicode_width::UnicodeWidthChar::width(c).unwrap_or(1) == 0 {
format!(" but is {:?}", c)
} else {
String::new()
};
handler
.struct_span_err(span, "raw byte string must be ASCII")
.span_label(span, &format!("must be ASCII{}", postfix))
.emit();
}
EscapeError::OutOfRangeHexEscape => { EscapeError::OutOfRangeHexEscape => {
handler handler
.struct_span_err(span, "out of range hex escape") .struct_span_err(span, "out of range hex escape")

View file

@ -1,7 +1,6 @@
// wasm32 does not support benches (no time). // wasm32 does not support benches (no time).
#![cfg(not(target_arch = "wasm32"))] #![cfg(not(target_arch = "wasm32"))]
#![feature(flt2dec)] #![feature(flt2dec)]
#![feature(int_log)]
#![feature(test)] #![feature(test)]
#![feature(trusted_random_access)] #![feature(trusted_random_access)]
#![feature(iter_array_chunks)] #![feature(iter_array_chunks)]

View file

@ -2271,15 +2271,16 @@ macro_rules! int_impl {
/// # Panics /// # Panics
/// ///
/// This function will panic if `self` is less than or equal to zero, /// This function will panic if `self` is less than or equal to zero,
/// or if `base` is less then 2. /// or if `base` is less than 2.
/// ///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// #![feature(int_log)]
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".ilog(5), 1);")] #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".ilog(5), 1);")]
/// ``` /// ```
#[unstable(feature = "int_log", issue = "70887")] #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[rustc_allow_const_fn_unstable(const_option)]
#[must_use = "this returns the result of the operation, \ #[must_use = "this returns the result of the operation, \
without modifying the original"] without modifying the original"]
#[inline] #[inline]
@ -2298,10 +2299,11 @@ macro_rules! int_impl {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// #![feature(int_log)]
#[doc = concat!("assert_eq!(2", stringify!($SelfT), ".ilog2(), 1);")] #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".ilog2(), 1);")]
/// ``` /// ```
#[unstable(feature = "int_log", issue = "70887")] #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[rustc_allow_const_fn_unstable(const_option)]
#[must_use = "this returns the result of the operation, \ #[must_use = "this returns the result of the operation, \
without modifying the original"] without modifying the original"]
#[inline] #[inline]
@ -2319,10 +2321,11 @@ macro_rules! int_impl {
/// # Example /// # Example
/// ///
/// ``` /// ```
/// #![feature(int_log)]
#[doc = concat!("assert_eq!(10", stringify!($SelfT), ".ilog10(), 1);")] #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".ilog10(), 1);")]
/// ``` /// ```
#[unstable(feature = "int_log", issue = "70887")] #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[rustc_allow_const_fn_unstable(const_option)]
#[must_use = "this returns the result of the operation, \ #[must_use = "this returns the result of the operation, \
without modifying the original"] without modifying the original"]
#[inline] #[inline]
@ -2343,10 +2346,10 @@ macro_rules! int_impl {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// #![feature(int_log)]
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_ilog(5), Some(1));")] #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_ilog(5), Some(1));")]
/// ``` /// ```
#[unstable(feature = "int_log", issue = "70887")] #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[must_use = "this returns the result of the operation, \ #[must_use = "this returns the result of the operation, \
without modifying the original"] without modifying the original"]
#[inline] #[inline]
@ -2379,10 +2382,10 @@ macro_rules! int_impl {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// #![feature(int_log)]
#[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_ilog2(), Some(1));")] #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_ilog2(), Some(1));")]
/// ``` /// ```
#[unstable(feature = "int_log", issue = "70887")] #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[must_use = "this returns the result of the operation, \ #[must_use = "this returns the result of the operation, \
without modifying the original"] without modifying the original"]
#[inline] #[inline]
@ -2403,10 +2406,10 @@ macro_rules! int_impl {
/// # Example /// # Example
/// ///
/// ``` /// ```
/// #![feature(int_log)]
#[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_ilog10(), Some(1));")] #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_ilog10(), Some(1));")]
/// ``` /// ```
#[unstable(feature = "int_log", issue = "70887")] #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[must_use = "this returns the result of the operation, \ #[must_use = "this returns the result of the operation, \
without modifying the original"] without modifying the original"]
#[inline] #[inline]

View file

@ -460,14 +460,14 @@ macro_rules! nonzero_unsigned_operations {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// #![feature(int_log)]
#[doc = concat!("# use std::num::", stringify!($Ty), ";")] #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
/// ///
#[doc = concat!("assert_eq!(", stringify!($Ty), "::new(7).unwrap().ilog2(), 2);")] #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(7).unwrap().ilog2(), 2);")]
#[doc = concat!("assert_eq!(", stringify!($Ty), "::new(8).unwrap().ilog2(), 3);")] #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(8).unwrap().ilog2(), 3);")]
#[doc = concat!("assert_eq!(", stringify!($Ty), "::new(9).unwrap().ilog2(), 3);")] #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(9).unwrap().ilog2(), 3);")]
/// ``` /// ```
#[unstable(feature = "int_log", issue = "70887")] #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[must_use = "this returns the result of the operation, \ #[must_use = "this returns the result of the operation, \
without modifying the original"] without modifying the original"]
#[inline] #[inline]
@ -485,14 +485,14 @@ macro_rules! nonzero_unsigned_operations {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// #![feature(int_log)]
#[doc = concat!("# use std::num::", stringify!($Ty), ";")] #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
/// ///
#[doc = concat!("assert_eq!(", stringify!($Ty), "::new(99).unwrap().ilog10(), 1);")] #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(99).unwrap().ilog10(), 1);")]
#[doc = concat!("assert_eq!(", stringify!($Ty), "::new(100).unwrap().ilog10(), 2);")] #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(100).unwrap().ilog10(), 2);")]
#[doc = concat!("assert_eq!(", stringify!($Ty), "::new(101).unwrap().ilog10(), 2);")] #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(101).unwrap().ilog10(), 2);")]
/// ``` /// ```
#[unstable(feature = "int_log", issue = "70887")] #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[must_use = "this returns the result of the operation, \ #[must_use = "this returns the result of the operation, \
without modifying the original"] without modifying the original"]
#[inline] #[inline]

View file

@ -692,15 +692,16 @@ macro_rules! uint_impl {
/// ///
/// # Panics /// # Panics
/// ///
/// This function will panic if `self` is zero, or if `base` is less then 2. /// This function will panic if `self` is zero, or if `base` is less than 2.
/// ///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// #![feature(int_log)]
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".ilog(5), 1);")] #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".ilog(5), 1);")]
/// ``` /// ```
#[unstable(feature = "int_log", issue = "70887")] #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[rustc_allow_const_fn_unstable(const_option)]
#[must_use = "this returns the result of the operation, \ #[must_use = "this returns the result of the operation, \
without modifying the original"] without modifying the original"]
#[inline] #[inline]
@ -719,10 +720,11 @@ macro_rules! uint_impl {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// #![feature(int_log)]
#[doc = concat!("assert_eq!(2", stringify!($SelfT), ".ilog2(), 1);")] #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".ilog2(), 1);")]
/// ``` /// ```
#[unstable(feature = "int_log", issue = "70887")] #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[rustc_allow_const_fn_unstable(const_option)]
#[must_use = "this returns the result of the operation, \ #[must_use = "this returns the result of the operation, \
without modifying the original"] without modifying the original"]
#[inline] #[inline]
@ -740,10 +742,11 @@ macro_rules! uint_impl {
/// # Example /// # Example
/// ///
/// ``` /// ```
/// #![feature(int_log)]
#[doc = concat!("assert_eq!(10", stringify!($SelfT), ".ilog10(), 1);")] #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".ilog10(), 1);")]
/// ``` /// ```
#[unstable(feature = "int_log", issue = "70887")] #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[rustc_allow_const_fn_unstable(const_option)]
#[must_use = "this returns the result of the operation, \ #[must_use = "this returns the result of the operation, \
without modifying the original"] without modifying the original"]
#[inline] #[inline]
@ -764,10 +767,10 @@ macro_rules! uint_impl {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// #![feature(int_log)]
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_ilog(5), Some(1));")] #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_ilog(5), Some(1));")]
/// ``` /// ```
#[unstable(feature = "int_log", issue = "70887")] #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[must_use = "this returns the result of the operation, \ #[must_use = "this returns the result of the operation, \
without modifying the original"] without modifying the original"]
#[inline] #[inline]
@ -800,10 +803,10 @@ macro_rules! uint_impl {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// #![feature(int_log)]
#[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_ilog2(), Some(1));")] #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_ilog2(), Some(1));")]
/// ``` /// ```
#[unstable(feature = "int_log", issue = "70887")] #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[must_use = "this returns the result of the operation, \ #[must_use = "this returns the result of the operation, \
without modifying the original"] without modifying the original"]
#[inline] #[inline]
@ -822,10 +825,10 @@ macro_rules! uint_impl {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// #![feature(int_log)]
#[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_ilog10(), Some(1));")] #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_ilog10(), Some(1));")]
/// ``` /// ```
#[unstable(feature = "int_log", issue = "70887")] #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[must_use = "this returns the result of the operation, \ #[must_use = "this returns the result of the operation, \
without modifying the original"] without modifying the original"]
#[inline] #[inline]

View file

@ -568,6 +568,31 @@ impl<T: ?Sized> *const T {
/// ///
/// For non-`Sized` pointees this operation changes only the data pointer, /// For non-`Sized` pointees this operation changes only the data pointer,
/// leaving the metadata untouched. /// leaving the metadata untouched.
///
/// ## Examples
///
/// ```
/// #![feature(ptr_mask, strict_provenance)]
/// let v = 17_u32;
/// let ptr: *const u32 = &v;
///
/// // `u32` is 4 bytes aligned,
/// // which means that lower 2 bits are always 0.
/// let tag_mask = 0b11;
/// let ptr_mask = !tag_mask;
///
/// // We can store something in these lower bits
/// let tagged_ptr = ptr.map_addr(|a| a | 0b10);
///
/// // Get the "tag" back
/// let tag = tagged_ptr.addr() & tag_mask;
/// assert_eq!(tag, 0b10);
///
/// // Note that `tagged_ptr` is unaligned, it's UB to read from it.
/// // To get original pointer `mask` can be used:
/// let masked_ptr = tagged_ptr.mask(ptr_mask);
/// assert_eq!(unsafe { *masked_ptr }, 17);
/// ```
#[unstable(feature = "ptr_mask", issue = "98290")] #[unstable(feature = "ptr_mask", issue = "98290")]
#[must_use = "returns a new pointer rather than modifying its argument"] #[must_use = "returns a new pointer rather than modifying its argument"]
#[inline(always)] #[inline(always)]

View file

@ -588,6 +588,34 @@ impl<T: ?Sized> *mut T {
/// ///
/// For non-`Sized` pointees this operation changes only the data pointer, /// For non-`Sized` pointees this operation changes only the data pointer,
/// leaving the metadata untouched. /// leaving the metadata untouched.
///
/// ## Examples
///
/// ```
/// #![feature(ptr_mask, strict_provenance)]
/// let mut v = 17_u32;
/// let ptr: *mut u32 = &mut v;
///
/// // `u32` is 4 bytes aligned,
/// // which means that lower 2 bits are always 0.
/// let tag_mask = 0b11;
/// let ptr_mask = !tag_mask;
///
/// // We can store something in these lower bits
/// let tagged_ptr = ptr.map_addr(|a| a | 0b10);
///
/// // Get the "tag" back
/// let tag = tagged_ptr.addr() & tag_mask;
/// assert_eq!(tag, 0b10);
///
/// // Note that `tagged_ptr` is unaligned, it's UB to read from/write to it.
/// // To get original pointer `mask` can be used:
/// let masked_ptr = tagged_ptr.mask(ptr_mask);
/// assert_eq!(unsafe { *masked_ptr }, 17);
///
/// unsafe { *masked_ptr = 0 };
/// assert_eq!(v, 0);
/// ```
#[unstable(feature = "ptr_mask", issue = "98290")] #[unstable(feature = "ptr_mask", issue = "98290")]
#[must_use = "returns a new pointer rather than modifying its argument"] #[must_use = "returns a new pointer rather than modifying its argument"]
#[inline(always)] #[inline(always)]

View file

@ -3667,7 +3667,8 @@ impl<T> [T] {
unsafe { self.align_to() } unsafe { self.align_to() }
} }
/// Split a slice into a prefix, a middle of aligned SIMD types, and a suffix. /// Split a mutable slice into a mutable prefix, a middle of aligned SIMD types,
/// and a mutable suffix.
/// ///
/// This is a safe wrapper around [`slice::align_to_mut`], so has the same weak /// This is a safe wrapper around [`slice::align_to_mut`], so has the same weak
/// postconditions as that method. You're only assured that /// postconditions as that method. You're only assured that

View file

@ -22,7 +22,8 @@ macro_rules! tuple_impls {
maybe_tuple_doc! { maybe_tuple_doc! {
$($T)+ @ $($T)+ @
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<$($T:PartialEq),+> PartialEq for ($($T,)+) #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
impl<$($T: ~const PartialEq),+> const PartialEq for ($($T,)+)
where where
last_type!($($T,)+): ?Sized last_type!($($T,)+): ?Sized
{ {
@ -40,7 +41,7 @@ macro_rules! tuple_impls {
maybe_tuple_doc! { maybe_tuple_doc! {
$($T)+ @ $($T)+ @
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<$($T:Eq),+> Eq for ($($T,)+) impl<$($T: Eq),+> Eq for ($($T,)+)
where where
last_type!($($T,)+): ?Sized last_type!($($T,)+): ?Sized
{} {}
@ -49,7 +50,8 @@ macro_rules! tuple_impls {
maybe_tuple_doc! { maybe_tuple_doc! {
$($T)+ @ $($T)+ @
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<$($T:PartialOrd + PartialEq),+> PartialOrd for ($($T,)+) #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
impl<$($T: ~const PartialOrd + ~const PartialEq),+> const PartialOrd for ($($T,)+)
where where
last_type!($($T,)+): ?Sized last_type!($($T,)+): ?Sized
{ {
@ -79,7 +81,8 @@ macro_rules! tuple_impls {
maybe_tuple_doc! { maybe_tuple_doc! {
$($T)+ @ $($T)+ @
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<$($T:Ord),+> Ord for ($($T,)+) #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
impl<$($T: ~const Ord),+> const Ord for ($($T,)+)
where where
last_type!($($T,)+): ?Sized last_type!($($T,)+): ?Sized
{ {

View file

@ -64,7 +64,6 @@
#![feature(try_trait_v2)] #![feature(try_trait_v2)]
#![feature(slice_internals)] #![feature(slice_internals)]
#![feature(slice_partition_dedup)] #![feature(slice_partition_dedup)]
#![feature(int_log)]
#![feature(iter_advance_by)] #![feature(iter_advance_by)]
#![feature(iter_array_chunks)] #![feature(iter_array_chunks)]
#![feature(iter_collect_into)] #![feature(iter_collect_into)]

View file

@ -118,6 +118,9 @@ ENV TARGETS=$TARGETS,armv7-unknown-linux-gnueabi
ENV TARGETS=$TARGETS,armv7-unknown-linux-musleabi ENV TARGETS=$TARGETS,armv7-unknown-linux-musleabi
ENV TARGETS=$TARGETS,i686-unknown-freebsd ENV TARGETS=$TARGETS,i686-unknown-freebsd
ENV TARGETS=$TARGETS,x86_64-unknown-none ENV TARGETS=$TARGETS,x86_64-unknown-none
ENV TARGETS=$TARGETS,aarch64-unknown-uefi
ENV TARGETS=$TARGETS,i686-unknown-uefi
ENV TARGETS=$TARGETS,x86_64-unknown-uefi
# As per https://bugs.launchpad.net/ubuntu/+source/gcc-defaults/+bug/1300211 # As per https://bugs.launchpad.net/ubuntu/+source/gcc-defaults/+bug/1300211
# we need asm in the search path for gcc-8 (for gnux32) but not in the search path of the # we need asm in the search path for gcc-8 (for gnux32) but not in the search path of the

View file

@ -128,6 +128,7 @@ target | std | notes
[`aarch64-linux-android`](platform-support/android.md) | ✓ | ARM64 Android [`aarch64-linux-android`](platform-support/android.md) | ✓ | ARM64 Android
`aarch64-unknown-none-softfloat` | * | Bare ARM64, softfloat `aarch64-unknown-none-softfloat` | * | Bare ARM64, softfloat
`aarch64-unknown-none` | * | Bare ARM64, hardfloat `aarch64-unknown-none` | * | Bare ARM64, hardfloat
[`aarch64-unknown-uefi`](platform-support/unknown-uefi.md) | * | ARM64 UEFI
[`arm-linux-androideabi`](platform-support/android.md) | ✓ | ARMv7 Android [`arm-linux-androideabi`](platform-support/android.md) | ✓ | ARMv7 Android
`arm-unknown-linux-musleabi` | ✓ | ARMv6 Linux with MUSL `arm-unknown-linux-musleabi` | ✓ | ARMv6 Linux with MUSL
`arm-unknown-linux-musleabihf` | ✓ | ARMv6 Linux with MUSL, hardfloat `arm-unknown-linux-musleabihf` | ✓ | ARMv6 Linux with MUSL, hardfloat
@ -149,6 +150,7 @@ target | std | notes
[`i686-linux-android`](platform-support/android.md) | ✓ | 32-bit x86 Android [`i686-linux-android`](platform-support/android.md) | ✓ | 32-bit x86 Android
`i686-unknown-freebsd` | ✓ | 32-bit FreeBSD `i686-unknown-freebsd` | ✓ | 32-bit FreeBSD
`i686-unknown-linux-musl` | ✓ | 32-bit Linux with MUSL `i686-unknown-linux-musl` | ✓ | 32-bit Linux with MUSL
[`i686-unknown-uefi`](platform-support/unknown-uefi.md) | * | 32-bit UEFI
`mips-unknown-linux-musl` | ✓ | MIPS Linux with MUSL `mips-unknown-linux-musl` | ✓ | MIPS Linux with MUSL
`mips64-unknown-linux-muslabi64` | ✓ | MIPS64 Linux, n64 ABI, MUSL `mips64-unknown-linux-muslabi64` | ✓ | MIPS64 Linux, n64 ABI, MUSL
`mips64el-unknown-linux-muslabi64` | ✓ | MIPS64 (LE) Linux, n64 ABI, MUSL `mips64el-unknown-linux-muslabi64` | ✓ | MIPS64 (LE) Linux, n64 ABI, MUSL
@ -181,6 +183,7 @@ target | std | notes
`x86_64-unknown-linux-gnux32` | ✓ | 64-bit Linux (x32 ABI) (kernel 4.15, glibc 2.27) `x86_64-unknown-linux-gnux32` | ✓ | 64-bit Linux (x32 ABI) (kernel 4.15, glibc 2.27)
[`x86_64-unknown-none`](platform-support/x86_64-unknown-none.md) | * | Freestanding/bare-metal x86_64, softfloat [`x86_64-unknown-none`](platform-support/x86_64-unknown-none.md) | * | Freestanding/bare-metal x86_64, softfloat
`x86_64-unknown-redox` | ✓ | Redox OS `x86_64-unknown-redox` | ✓ | Redox OS
[`x86_64-unknown-uefi`](platform-support/unknown-uefi.md) | * | 64-bit UEFI
[Fortanix ABI]: https://edp.fortanix.com/ [Fortanix ABI]: https://edp.fortanix.com/
@ -213,7 +216,6 @@ target | std | host | notes
[`aarch64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ | [`aarch64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ |
`aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD
`aarch64-unknown-hermit` | ✓ | | ARM64 HermitCore `aarch64-unknown-hermit` | ✓ | | ARM64 HermitCore
[`aarch64-unknown-uefi`](platform-support/unknown-uefi.md) | * | | ARM64 UEFI
`aarch64-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (ILP32 ABI) `aarch64-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (ILP32 ABI)
`aarch64-unknown-netbsd` | ✓ | ✓ | `aarch64-unknown-netbsd` | ✓ | ✓ |
[`aarch64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | ARM64 OpenBSD [`aarch64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | ARM64 OpenBSD
@ -252,7 +254,6 @@ target | std | host | notes
`i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku `i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku
`i686-unknown-netbsd` | ✓ | ✓ | NetBSD/i386 with SSE2 `i686-unknown-netbsd` | ✓ | ✓ | NetBSD/i386 with SSE2
[`i686-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 32-bit OpenBSD [`i686-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 32-bit OpenBSD
[`i686-unknown-uefi`](platform-support/unknown-uefi.md) | * | | 32-bit UEFI
`i686-uwp-windows-gnu` | ? | | `i686-uwp-windows-gnu` | ? | |
`i686-uwp-windows-msvc` | ? | | `i686-uwp-windows-msvc` | ? | |
`i686-wrs-vxworks` | ? | | `i686-wrs-vxworks` | ? | |
@ -311,7 +312,6 @@ target | std | host | notes
`x86_64-unknown-l4re-uclibc` | ? | | `x86_64-unknown-l4re-uclibc` | ? | |
`x86_64-unknown-none-linuxkernel` | * | | Linux kernel modules `x86_64-unknown-none-linuxkernel` | * | | Linux kernel modules
[`x86_64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 64-bit OpenBSD [`x86_64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 64-bit OpenBSD
[`x86_64-unknown-uefi`](platform-support/unknown-uefi.md) | * | | 64-bit UEFI
`x86_64-uwp-windows-gnu` | ✓ | | `x86_64-uwp-windows-gnu` | ✓ | |
`x86_64-uwp-windows-msvc` | ✓ | | `x86_64-uwp-windows-msvc` | ✓ | |
`x86_64-wrs-vxworks` | ? | | `x86_64-wrs-vxworks` | ? | |

View file

@ -1,6 +1,6 @@
# `*-unknown-uefi` # `*-unknown-uefi`
**Tier: 3** **Tier: 2**
Unified Extensible Firmware Interface (UEFI) targets for application, driver, Unified Extensible Firmware Interface (UEFI) targets for application, driver,
and core UEFI binaries. and core UEFI binaries.
@ -72,28 +72,14 @@ target = ["x86_64-unknown-uefi"]
## Building Rust programs ## Building Rust programs
Rust does not yet ship pre-compiled artifacts for this target. To compile for Starting with Rust 1.67, precompiled artifacts are provided via
this target, you will either need to build Rust with the target enabled (see `rustup`. For example, to use `x86_64-unknown-uefi`:
"Building rust for UEFI targets" above), or build your own copy of `core` by
using `build-std`, `cargo-buildx`, or similar.
A native build with the unstable `build-std`-feature can be achieved via:
```sh ```sh
cargo +nightly build \ # install cross-compile toolchain
-Zbuild-std=core,compiler_builtins \ rustup target add x86_64-unknown-uefi
-Zbuild-std-features=compiler-builtins-mem \ # target flag may be used with any cargo or rustc command
--target x86_64-unknown-uefi cargo build --target x86_64-unknown-uefi
```
Alternatively, you can install `cargo-xbuild` via
`cargo install --force cargo-xbuild` and build for the UEFI targets via:
```sh
cargo \
+nightly \
xbuild \
--target x86_64-unknown-uefi
``` ```
## Testing ## Testing
@ -167,18 +153,10 @@ The following code is a valid UEFI application returning immediately upon
execution with an exit code of 0. A panic handler is provided. This is executed execution with an exit code of 0. A panic handler is provided. This is executed
by rust on panic. For simplicity, we simply end up in an infinite loop. by rust on panic. For simplicity, we simply end up in an infinite loop.
Note that as of rust-1.31.0, all features used here are stabilized. No unstable
features are required, nor do we rely on nightly compilers. However, if you do
not compile rustc for the UEFI targets, you need a nightly compiler to support
the `-Z build-std` flag.
This example can be compiled as binary crate via `cargo`: This example can be compiled as binary crate via `cargo`:
```sh ```sh
cargo +nightly build \ cargo build --target x86_64-unknown-uefi
-Zbuild-std=core,compiler_builtins \
-Zbuild-std-features=compiler-builtins-mem \
--target x86_64-unknown-uefi
``` ```
```rust,ignore (platform-specific,eh-personality-is-unstable) ```rust,ignore (platform-specific,eh-personality-is-unstable)

View file

@ -1,4 +1,4 @@
#![feature(rustc_attrs)] #![feature(rustc_attrs)]
#[rustc_dummy = b"ffi.rs"] //~ ERROR non-ASCII character in byte constant #[rustc_dummy = b"ffi.rs"] //~ ERROR non-ASCII character in byte string literal
fn main() {} fn main() {}

View file

@ -1,8 +1,8 @@
error: non-ASCII character in byte constant error: non-ASCII character in byte string literal
--> $DIR/key-value-non-ascii.rs:3:19 --> $DIR/key-value-non-ascii.rs:3:19
| |
LL | #[rustc_dummy = b"ffi.rs"] LL | #[rustc_dummy = b"ffi.rs"]
| ^ byte constant must be ASCII | ^ must be ASCII
| |
help: if you meant to use the UTF-8 encoding of 'ffi', use \xHH escapes help: if you meant to use the UTF-8 encoding of 'ffi', use \xHH escapes
| |

View file

@ -1,4 +1,4 @@
// build-pass // check-pass
#![feature(const_fn_trait_ref_impls)] #![feature(const_fn_trait_ref_impls)]
#![feature(fn_traits)] #![feature(fn_traits)]
@ -60,21 +60,18 @@ const fn test(i: i32) -> i32 {
i + 1 i + 1
} }
const fn main() { fn main() {
const fn one() -> i32 { const fn one() -> i32 {
1 1
}; };
const fn two() -> i32 { const fn two() -> i32 {
2 2
}; };
const _: () = {
let test_one = test_fn(one);
assert!(test_one == (1, 1, 1));
// FIXME(const_cmp_tuple) let test_two = test_fn_mut(two);
let test_one = test_fn(one); assert!(test_two == (2, 2));
assert!(test_one.0 == 1); };
assert!(test_one.1 == 1);
assert!(test_one.2 == 1);
let test_two = test_fn_mut(two);
assert!(test_two.0 == 1);
assert!(test_two.1 == 1);
} }

View file

@ -7,6 +7,6 @@ pub fn main() {
b'\x0Z'; //~ ERROR invalid character in numeric character escape: `Z` b'\x0Z'; //~ ERROR invalid character in numeric character escape: `Z`
b' '; //~ ERROR byte constant must be escaped b' '; //~ ERROR byte constant must be escaped
b'''; //~ ERROR byte constant must be escaped b'''; //~ ERROR byte constant must be escaped
b'é'; //~ ERROR non-ASCII character in byte constant b'é'; //~ ERROR non-ASCII character in byte literal
b'a //~ ERROR unterminated byte constant [E0763] b'a //~ ERROR unterminated byte constant [E0763]
} }

View file

@ -32,11 +32,11 @@ error: byte constant must be escaped: `'`
LL | b'''; LL | b''';
| ^ help: escape the character: `\'` | ^ help: escape the character: `\'`
error: non-ASCII character in byte constant error: non-ASCII character in byte literal
--> $DIR/byte-literals.rs:10:7 --> $DIR/byte-literals.rs:10:7
| |
LL | b'é'; LL | b'é';
| ^ byte constant must be ASCII | ^ must be ASCII
| |
help: if you meant to use the unicode code point for 'é', use a \xHH escape help: if you meant to use the unicode code point for 'é', use a \xHH escape
| |

View file

@ -3,7 +3,7 @@ static FOO: &'static [u8] = b"\f"; //~ ERROR unknown byte escape
pub fn main() { pub fn main() {
b"\f"; //~ ERROR unknown byte escape b"\f"; //~ ERROR unknown byte escape
b"\x0Z"; //~ ERROR invalid character in numeric character escape: `Z` b"\x0Z"; //~ ERROR invalid character in numeric character escape: `Z`
b"é"; //~ ERROR non-ASCII character in byte constant b"é"; //~ ERROR non-ASCII character in byte string literal
br##"é"##; //~ ERROR raw byte string must be ASCII br##"é"##; //~ ERROR non-ASCII character in raw byte string literal
b"a //~ ERROR unterminated double quote byte string b"a //~ ERROR unterminated double quote byte string
} }

View file

@ -20,18 +20,18 @@ error: invalid character in numeric character escape: `Z`
LL | b"\x0Z"; LL | b"\x0Z";
| ^ invalid character in numeric character escape | ^ invalid character in numeric character escape
error: non-ASCII character in byte constant error: non-ASCII character in byte string literal
--> $DIR/byte-string-literals.rs:6:7 --> $DIR/byte-string-literals.rs:6:7
| |
LL | b"é"; LL | b"é";
| ^ byte constant must be ASCII | ^ must be ASCII
| |
help: if you meant to use the unicode code point for 'é', use a \xHH escape help: if you meant to use the unicode code point for 'é', use a \xHH escape
| |
LL | b"\xE9"; LL | b"\xE9";
| ~~~~ | ~~~~
error: raw byte string must be ASCII error: non-ASCII character in raw byte string literal
--> $DIR/byte-string-literals.rs:7:10 --> $DIR/byte-string-literals.rs:7:10
| |
LL | br##"é"##; LL | br##"é"##;

View file

@ -2,6 +2,6 @@
pub fn main() { pub fn main() {
br"a "; //~ ERROR bare CR not allowed in raw string br"a "; //~ ERROR bare CR not allowed in raw string
br"é"; //~ ERROR raw byte string must be ASCII br"é"; //~ ERROR non-ASCII character in raw byte string literal
br##~"a"~##; //~ ERROR only `#` is allowed in raw string delimitation br##~"a"~##; //~ ERROR only `#` is allowed in raw string delimitation
} }

View file

@ -4,7 +4,7 @@ error: bare CR not allowed in raw string
LL | br"a "; LL | br"a ";
| ^ | ^
error: raw byte string must be ASCII error: non-ASCII character in raw byte string literal
--> $DIR/raw-byte-string-literals.rs:5:8 --> $DIR/raw-byte-string-literals.rs:5:8
| |
LL | br"é"; LL | br"é";

View file

@ -14,15 +14,15 @@ fn main() {
println!("{:?}", r##"/* } if isAdmin begin admins only "##); println!("{:?}", r##"/* } if isAdmin begin admins only "##);
//~^ ERROR unicode codepoint changing visible direction of text present in literal //~^ ERROR unicode codepoint changing visible direction of text present in literal
println!("{:?}", b"/* } if isAdmin begin admins only "); println!("{:?}", b"/* } if isAdmin begin admins only ");
//~^ ERROR non-ASCII character in byte constant //~^ ERROR non-ASCII character in byte string literal
//~| ERROR non-ASCII character in byte constant //~| ERROR non-ASCII character in byte string literal
//~| ERROR non-ASCII character in byte constant //~| ERROR non-ASCII character in byte string literal
//~| ERROR non-ASCII character in byte constant //~| ERROR non-ASCII character in byte string literal
println!("{:?}", br##"/* } if isAdmin begin admins only "##); println!("{:?}", br##"/* } if isAdmin begin admins only "##);
//~^ ERROR raw byte string must be ASCII //~^ ERROR non-ASCII character in raw byte string literal
//~| ERROR raw byte string must be ASCII //~| ERROR non-ASCII character in raw byte string literal
//~| ERROR raw byte string must be ASCII //~| ERROR non-ASCII character in raw byte string literal
//~| ERROR raw byte string must be ASCII //~| ERROR non-ASCII character in raw byte string literal
println!("{:?}", ''); println!("{:?}", '');
//~^ ERROR unicode codepoint changing visible direction of text present in literal //~^ ERROR unicode codepoint changing visible direction of text present in literal
} }

View file

@ -14,69 +14,69 @@ LL | println!("{:?}", b"us\u{202B}e\u{202A}r");
| |
= help: unicode escape sequences cannot be used as a byte or in a byte string = help: unicode escape sequences cannot be used as a byte or in a byte string
error: non-ASCII character in byte constant error: non-ASCII character in byte string literal
--> $DIR/unicode-control-codepoints.rs:16:26 --> $DIR/unicode-control-codepoints.rs:16:26
| |
LL | println!("{:?}", b"/* } if isAdmin begin admins only "); LL | println!("{:?}", b"/* } if isAdmin begin admins only ");
| ^ byte constant must be ASCII but is '\u{202e}' | ^ must be ASCII but is '\u{202e}'
| |
help: if you meant to use the UTF-8 encoding of '\u{202e}', use \xHH escapes help: if you meant to use the UTF-8 encoding of '\u{202e}', use \xHH escapes
| |
LL | println!("{:?}", b"/*\xE2\x80\xAE } if isAdmin begin admins only "); LL | println!("{:?}", b"/*\xE2\x80\xAE } if isAdmin begin admins only ");
| ~~~~~~~~~~~~ | ~~~~~~~~~~~~
error: non-ASCII character in byte constant error: non-ASCII character in byte string literal
--> $DIR/unicode-control-codepoints.rs:16:30 --> $DIR/unicode-control-codepoints.rs:16:30
| |
LL | println!("{:?}", b"/* } if isAdmin begin admins only "); LL | println!("{:?}", b"/* } if isAdmin begin admins only ");
| ^ byte constant must be ASCII but is '\u{2066}' | ^ must be ASCII but is '\u{2066}'
| |
help: if you meant to use the UTF-8 encoding of '\u{2066}', use \xHH escapes help: if you meant to use the UTF-8 encoding of '\u{2066}', use \xHH escapes
| |
LL | println!("{:?}", b"/* } \xE2\x81\xA6if isAdmin begin admins only "); LL | println!("{:?}", b"/* } \xE2\x81\xA6if isAdmin begin admins only ");
| ~~~~~~~~~~~~ | ~~~~~~~~~~~~
error: non-ASCII character in byte constant error: non-ASCII character in byte string literal
--> $DIR/unicode-control-codepoints.rs:16:41 --> $DIR/unicode-control-codepoints.rs:16:41
| |
LL | println!("{:?}", b"/* } if isAdmin begin admins only "); LL | println!("{:?}", b"/* } if isAdmin begin admins only ");
| ^ byte constant must be ASCII but is '\u{2069}' | ^ must be ASCII but is '\u{2069}'
| |
help: if you meant to use the UTF-8 encoding of '\u{2069}', use \xHH escapes help: if you meant to use the UTF-8 encoding of '\u{2069}', use \xHH escapes
| |
LL | println!("{:?}", b"/* } if isAdmin\xE2\x81\xA9 begin admins only "); LL | println!("{:?}", b"/* } if isAdmin\xE2\x81\xA9 begin admins only ");
| ~~~~~~~~~~~~ | ~~~~~~~~~~~~
error: non-ASCII character in byte constant error: non-ASCII character in byte string literal
--> $DIR/unicode-control-codepoints.rs:16:43 --> $DIR/unicode-control-codepoints.rs:16:43
| |
LL | println!("{:?}", b"/* } if isAdmin begin admins only "); LL | println!("{:?}", b"/* } if isAdmin begin admins only ");
| ^ byte constant must be ASCII but is '\u{2066}' | ^ must be ASCII but is '\u{2066}'
| |
help: if you meant to use the UTF-8 encoding of '\u{2066}', use \xHH escapes help: if you meant to use the UTF-8 encoding of '\u{2066}', use \xHH escapes
| |
LL | println!("{:?}", b"/* } if isAdmin \xE2\x81\xA6 begin admins only "); LL | println!("{:?}", b"/* } if isAdmin \xE2\x81\xA6 begin admins only ");
| ~~~~~~~~~~~~ | ~~~~~~~~~~~~
error: raw byte string must be ASCII error: non-ASCII character in raw byte string literal
--> $DIR/unicode-control-codepoints.rs:21:29 --> $DIR/unicode-control-codepoints.rs:21:29
| |
LL | println!("{:?}", br##"/* } if isAdmin begin admins only "##); LL | println!("{:?}", br##"/* } if isAdmin begin admins only "##);
| ^ must be ASCII but is '\u{202e}' | ^ must be ASCII but is '\u{202e}'
error: raw byte string must be ASCII error: non-ASCII character in raw byte string literal
--> $DIR/unicode-control-codepoints.rs:21:33 --> $DIR/unicode-control-codepoints.rs:21:33
| |
LL | println!("{:?}", br##"/* } if isAdmin begin admins only "##); LL | println!("{:?}", br##"/* } if isAdmin begin admins only "##);
| ^ must be ASCII but is '\u{2066}' | ^ must be ASCII but is '\u{2066}'
error: raw byte string must be ASCII error: non-ASCII character in raw byte string literal
--> $DIR/unicode-control-codepoints.rs:21:44 --> $DIR/unicode-control-codepoints.rs:21:44
| |
LL | println!("{:?}", br##"/* } if isAdmin begin admins only "##); LL | println!("{:?}", br##"/* } if isAdmin begin admins only "##);
| ^ must be ASCII but is '\u{2069}' | ^ must be ASCII but is '\u{2069}'
error: raw byte string must be ASCII error: non-ASCII character in raw byte string literal
--> $DIR/unicode-control-codepoints.rs:21:46 --> $DIR/unicode-control-codepoints.rs:21:46
| |
LL | println!("{:?}", br##"/* } if isAdmin begin admins only "##); LL | println!("{:?}", br##"/* } if isAdmin begin admins only "##);

View file

@ -2,17 +2,17 @@
fn main() { fn main() {
b'µ'; b'µ';
//~^ ERROR: non-ASCII character in byte constant //~^ ERROR: non-ASCII character in byte literal
//~| HELP: if you meant to use the unicode code point for 'µ', use a \xHH escape //~| HELP: if you meant to use the unicode code point for 'µ', use a \xHH escape
//~| NOTE: byte constant must be ASCII //~| NOTE: must be ASCII
b'字'; b'字';
//~^ ERROR: non-ASCII character in byte constant //~^ ERROR: non-ASCII character in byte literal
//~| NOTE: this multibyte character does not fit into a single byte //~| NOTE: this multibyte character does not fit into a single byte
//~| NOTE: byte constant must be ASCII //~| NOTE: must be ASCII
b""; b"";
//~^ ERROR: non-ASCII character in byte constant //~^ ERROR: non-ASCII character in byte string literal
//~| HELP: if you meant to use the UTF-8 encoding of '字', use \xHH escapes //~| HELP: if you meant to use the UTF-8 encoding of '字', use \xHH escapes
//~| NOTE: byte constant must be ASCII //~| NOTE: must be ASCII
} }

View file

@ -1,28 +1,28 @@
error: non-ASCII character in byte constant error: non-ASCII character in byte literal
--> $DIR/multibyte-escapes.rs:4:7 --> $DIR/multibyte-escapes.rs:4:7
| |
LL | b'µ'; LL | b'µ';
| ^ byte constant must be ASCII | ^ must be ASCII
| |
help: if you meant to use the unicode code point for 'µ', use a \xHH escape help: if you meant to use the unicode code point for 'µ', use a \xHH escape
| |
LL | b'\xB5'; LL | b'\xB5';
| ~~~~ | ~~~~
error: non-ASCII character in byte constant error: non-ASCII character in byte literal
--> $DIR/multibyte-escapes.rs:9:7 --> $DIR/multibyte-escapes.rs:9:7
| |
LL | b'字'; LL | b'字';
| ^^ | ^^
| | | |
| byte constant must be ASCII | must be ASCII
| this multibyte character does not fit into a single byte | this multibyte character does not fit into a single byte
error: non-ASCII character in byte constant error: non-ASCII character in byte string literal
--> $DIR/multibyte-escapes.rs:14:7 --> $DIR/multibyte-escapes.rs:14:7
| |
LL | b"字"; LL | b"字";
| ^^ byte constant must be ASCII | ^^ must be ASCII
| |
help: if you meant to use the UTF-8 encoding of '字', use \xHH escapes help: if you meant to use the UTF-8 encoding of '字', use \xHH escapes
| |

View file

@ -60,6 +60,7 @@ static TARGETS: &[&str] = &[
"aarch64-unknown-none", "aarch64-unknown-none",
"aarch64-unknown-none-softfloat", "aarch64-unknown-none-softfloat",
"aarch64-unknown-redox", "aarch64-unknown-redox",
"aarch64-unknown-uefi",
"arm-linux-androideabi", "arm-linux-androideabi",
"arm-unknown-linux-gnueabi", "arm-unknown-linux-gnueabi",
"arm-unknown-linux-gnueabihf", "arm-unknown-linux-gnueabihf",
@ -95,6 +96,7 @@ static TARGETS: &[&str] = &[
"i686-unknown-freebsd", "i686-unknown-freebsd",
"i686-unknown-linux-gnu", "i686-unknown-linux-gnu",
"i686-unknown-linux-musl", "i686-unknown-linux-musl",
"i686-unknown-uefi",
"m68k-unknown-linux-gnu", "m68k-unknown-linux-gnu",
"mips-unknown-linux-gnu", "mips-unknown-linux-gnu",
"mips-unknown-linux-musl", "mips-unknown-linux-musl",
@ -151,6 +153,7 @@ static TARGETS: &[&str] = &[
"x86_64-unknown-none", "x86_64-unknown-none",
"x86_64-unknown-redox", "x86_64-unknown-redox",
"x86_64-unknown-hermit", "x86_64-unknown-hermit",
"x86_64-unknown-uefi",
]; ];
/// This allows the manifest to contain rust-docs for hosts that don't build /// This allows the manifest to contain rust-docs for hosts that don't build

View file

@ -55,30 +55,6 @@ const LINKCHECK_EXCEPTIONS: &[(&str, &[&str])] = &[
#[rustfmt::skip] #[rustfmt::skip]
const INTRA_DOC_LINK_EXCEPTIONS: &[(&str, &[&str])] = &[ const INTRA_DOC_LINK_EXCEPTIONS: &[(&str, &[&str])] = &[
// This will never have links that are not in other pages.
// To avoid repeating the exceptions twice, an empty list means all broken links are allowed.
("reference/print.html", &[]),
// All the reference 'links' are actually ENBF highlighted as code
("reference/comments.html", &[
"/</code> <code>!",
"*</code> <code>!",
]),
("reference/identifiers.html", &[
"a</code>-<code>z</code> <code>A</code>-<code>Z",
"a</code>-<code>z</code> <code>A</code>-<code>Z</code> <code>0</code>-<code>9</code> <code>_",
"a</code>-<code>z</code> <code>A</code>-<code>Z</code>] [<code>a</code>-<code>z</code> <code>A</code>-<code>Z</code> <code>0</code>-<code>9</code> <code>_",
]),
("reference/tokens.html", &[
"0</code>-<code>1",
"0</code>-<code>7",
"0</code>-<code>9",
"0</code>-<code>9",
"0</code>-<code>9</code> <code>a</code>-<code>f</code> <code>A</code>-<code>F",
]),
("reference/notation.html", &[
"b</code> <code>B",
"a</code>-<code>z",
]),
// This is being used in the sense of 'inclusive range', not a markdown link // This is being used in the sense of 'inclusive range', not a markdown link
("core/ops/struct.RangeInclusive.html", &["begin</code>, <code>end"]), ("core/ops/struct.RangeInclusive.html", &["begin</code>, <code>end"]),
("std/ops/struct.RangeInclusive.html", &["begin</code>, <code>end"]), ("std/ops/struct.RangeInclusive.html", &["begin</code>, <code>end"]),
@ -365,6 +341,33 @@ impl Checker {
} }
}); });
self.check_intra_doc_links(file, &pretty_path, &source, report);
// we don't need the source anymore,
// so drop to reduce memory-usage
match self.cache.get_mut(&pretty_path).unwrap() {
FileEntry::HtmlFile { source, .. } => *source = Rc::new(String::new()),
_ => unreachable!("must be html file"),
}
}
fn check_intra_doc_links(
&mut self,
file: &Path,
pretty_path: &str,
source: &str,
report: &mut Report,
) {
let relative = file.strip_prefix(&self.root).expect("should always be relative to root");
// Don't check the reference. It has several legitimate things that
// look like [<code>…</code>]. The reference has its own broken link
// checker in its CI which handles this using pulldown_cmark.
//
// This checks both the end of the root (when checking just the
// reference directory) or the beginning (when checking all docs).
if self.root.ends_with("reference") || relative.starts_with("reference") {
return;
}
// Search for intra-doc links that rustdoc didn't warn about // Search for intra-doc links that rustdoc didn't warn about
// FIXME(#77199, 77200) Rustdoc should just warn about these directly. // FIXME(#77199, 77200) Rustdoc should just warn about these directly.
// NOTE: only looks at one line at a time; in practice this should find most links // NOTE: only looks at one line at a time; in practice this should find most links
@ -379,12 +382,6 @@ impl Checker {
} }
} }
} }
// we don't need the source anymore,
// so drop to reduce memory-usage
match self.cache.get_mut(&pretty_path).unwrap() {
FileEntry::HtmlFile { source, .. } => *source = Rc::new(String::new()),
_ => unreachable!("must be html file"),
}
} }
/// Load a file from disk, or from the cache if available. /// Load a file from disk, or from the cache if available.

View file

@ -3,7 +3,6 @@
#![feature(never_type)] #![feature(never_type)]
#![feature(try_blocks)] #![feature(try_blocks)]
#![feature(io_error_more)] #![feature(io_error_more)]
#![feature(int_log)]
#![feature(variant_count)] #![feature(variant_count)]
#![feature(yeet_expr)] #![feature(yeet_expr)]
#![feature(is_some_and)] #![feature(is_some_and)]

View file

@ -1,5 +1,4 @@
//@compile-flags: -Coverflow-checks=off //@compile-flags: -Coverflow-checks=off
#![feature(int_log)]
#![allow(arithmetic_overflow)] #![allow(arithmetic_overflow)]
pub fn main() { pub fn main() {

View file

@ -5,9 +5,7 @@
mod block; mod block;
use rowan::Direction; use rowan::Direction;
use rustc_lexer::unescape::{ use rustc_lexer::unescape::{self, unescape_byte, unescape_char, unescape_literal, Mode};
self, unescape_byte, unescape_byte_literal, unescape_char, unescape_literal, Mode,
};
use crate::{ use crate::{
algo, algo,
@ -143,7 +141,7 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) {
ast::LiteralKind::ByteString(s) => { ast::LiteralKind::ByteString(s) => {
if !s.is_raw() { if !s.is_raw() {
if let Some(without_quotes) = unquote(text, 2, '"') { if let Some(without_quotes) = unquote(text, 2, '"') {
unescape_byte_literal(without_quotes, Mode::ByteStr, &mut |range, char| { unescape_literal(without_quotes, Mode::ByteStr, &mut |range, char| {
if let Err(err) = char { if let Err(err) = char {
push_err(2, (range.start, err)); push_err(2, (range.start, err));
} }