Skip to content

Rollup of 7 pull requests #95855

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Apr 9, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion compiler/rustc_expand/src/lib.rs
Original file line number Diff line number Diff line change
@@ -2,7 +2,6 @@
#![feature(associated_type_bounds)]
#![feature(associated_type_defaults)]
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
#![feature(if_let_guard)]
#![feature(let_chains)]
#![feature(let_else)]
15 changes: 13 additions & 2 deletions compiler/rustc_expand/src/mbe/macro_check.rs
Original file line number Diff line number Diff line change
@@ -110,7 +110,7 @@ use rustc_ast::token::{DelimToken, Token, TokenKind};
use rustc_ast::{NodeId, DUMMY_NODE_ID};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::MultiSpan;
use rustc_session::lint::builtin::META_VARIABLE_MISUSE;
use rustc_session::lint::builtin::{META_VARIABLE_MISUSE, MISSING_FRAGMENT_SPECIFIER};
use rustc_session::parse::ParseSess;
use rustc_span::symbol::kw;
use rustc_span::{symbol::MacroRulesNormalizedIdent, Span};
@@ -261,7 +261,18 @@ fn check_binders(
}
}
// Similarly, this can only happen when checking a toplevel macro.
TokenTree::MetaVarDecl(span, name, _kind) => {
TokenTree::MetaVarDecl(span, name, kind) => {
if kind.is_none() && node_id != DUMMY_NODE_ID {
// FIXME: Report this as a hard error eventually and remove equivalent errors from
// `parse_tt_inner` and `nameize`. Until then the error may be reported twice, once
// as a hard error and then once as a buffered lint.
sess.buffer_lint(
MISSING_FRAGMENT_SPECIFIER,
span,
node_id,
&format!("missing fragment specifier"),
);
}
if !macros.is_empty() {
sess.span_diagnostic.span_bug(span, "unexpected MetaVarDecl in nested lhs");
}
18 changes: 6 additions & 12 deletions compiler/rustc_expand/src/mbe/macro_parser.rs
Original file line number Diff line number Diff line change
@@ -411,7 +411,6 @@ impl TtParser {
/// track of through the mps generated.
fn parse_tt_inner(
&mut self,
sess: &ParseSess,
matcher: &[MatcherLoc],
token: &Token,
) -> Option<NamedParseResult> {
@@ -519,11 +518,9 @@ impl TtParser {
self.bb_mps.push(mp);
}
} else {
// E.g. `$e` instead of `$e:expr`, reported as a hard error if actually used.
// Both this check and the one in `nameize` are necessary, surprisingly.
if sess.missing_fragment_specifiers.borrow_mut().remove(&span).is_some() {
// E.g. `$e` instead of `$e:expr`.
return Some(Error(span, "missing fragment specifier".to_string()));
}
return Some(Error(span, "missing fragment specifier".to_string()));
}
}
MatcherLoc::Eof => {
@@ -549,7 +546,7 @@ impl TtParser {
// Need to take ownership of the matches from within the `Lrc`.
Lrc::make_mut(&mut eof_mp.matches);
let matches = Lrc::try_unwrap(eof_mp.matches).unwrap().into_iter();
self.nameize(sess, matcher, matches)
self.nameize(matcher, matches)
}
EofMatcherPositions::Multiple => {
Error(token.span, "ambiguity: multiple successful parses".to_string())
@@ -587,7 +584,7 @@ impl TtParser {

// Process `cur_mps` until either we have finished the input or we need to get some
// parsing from the black-box parser done.
if let Some(res) = self.parse_tt_inner(&parser.sess, matcher, &parser.token) {
if let Some(res) = self.parse_tt_inner(matcher, &parser.token) {
return res;
}

@@ -694,7 +691,6 @@ impl TtParser {

fn nameize<I: Iterator<Item = NamedMatch>>(
&self,
sess: &ParseSess,
matcher: &[MatcherLoc],
mut res: I,
) -> NamedParseResult {
@@ -711,11 +707,9 @@ impl TtParser {
}
};
} else {
// E.g. `$e` instead of `$e:expr`, reported as a hard error if actually used.
// Both this check and the one in `parse_tt_inner` are necessary, surprisingly.
if sess.missing_fragment_specifiers.borrow_mut().remove(&span).is_some() {
// E.g. `$e` instead of `$e:expr`.
return Error(span, "missing fragment specifier".to_string());
}
return Error(span, "missing fragment specifier".to_string());
}
}
}
8 changes: 2 additions & 6 deletions compiler/rustc_expand/src/mbe/quoted.rs
Original file line number Diff line number Diff line change
@@ -2,8 +2,7 @@ use crate::mbe::macro_parser::count_metavar_decls;
use crate::mbe::{Delimited, KleeneOp, KleeneToken, MetaVarExpr, SequenceRepetition, TokenTree};

use rustc_ast::token::{self, Token};
use rustc_ast::tokenstream;
use rustc_ast::{NodeId, DUMMY_NODE_ID};
use rustc_ast::{tokenstream, NodeId};
use rustc_ast_pretty::pprust;
use rustc_feature::Features;
use rustc_session::parse::{feature_err, ParseSess};
@@ -104,10 +103,7 @@ pub(super) fn parse(
}
tree => tree.as_ref().map_or(start_sp, tokenstream::TokenTree::span),
};
if node_id != DUMMY_NODE_ID {
// Macros loaded from other crates have dummy node ids.
sess.missing_fragment_specifiers.borrow_mut().insert(span, node_id);
}

result.push(TokenTree::MetaVarDecl(span, ident, None));
}

16 changes: 0 additions & 16 deletions compiler/rustc_interface/src/passes.rs
Original file line number Diff line number Diff line change
@@ -30,7 +30,6 @@ use rustc_resolve::{Resolver, ResolverArenas};
use rustc_serialize::json;
use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType};
use rustc_session::cstore::{MetadataLoader, MetadataLoaderDyn};
use rustc_session::lint;
use rustc_session::output::{filename_for_input, filename_for_metadata};
use rustc_session::search_paths::PathKind;
use rustc_session::{Limit, Session};
@@ -349,23 +348,8 @@ pub fn configure_and_expand(
ecx.check_unused_macros();
});

let mut missing_fragment_specifiers: Vec<_> = ecx
.sess
.parse_sess
.missing_fragment_specifiers
.borrow()
.iter()
.map(|(span, node_id)| (*span, *node_id))
.collect();
missing_fragment_specifiers.sort_unstable_by_key(|(span, _)| *span);

let recursion_limit_hit = ecx.reduced_recursion_limit.is_some();

for (span, node_id) in missing_fragment_specifiers {
let lint = lint::builtin::MISSING_FRAGMENT_SPECIFIER;
let msg = "missing fragment specifier";
resolver.lint_buffer().buffer_lint(lint, node_id, span, msg);
}
if cfg!(windows) {
env::set_var("PATH", &old_path);
}
2 changes: 0 additions & 2 deletions compiler/rustc_session/src/parse.rs
Original file line number Diff line number Diff line change
@@ -140,7 +140,6 @@ pub struct ParseSess {
pub config: CrateConfig,
pub check_config: CrateCheckConfig,
pub edition: Edition,
pub missing_fragment_specifiers: Lock<FxHashMap<Span, NodeId>>,
/// Places where raw identifiers were used. This is used to avoid complaining about idents
/// clashing with keywords in new editions.
pub raw_identifier_spans: Lock<Vec<Span>>,
@@ -195,7 +194,6 @@ impl ParseSess {
config: FxHashSet::default(),
check_config: CrateCheckConfig::default(),
edition: ExpnId::root().expn_data().edition,
missing_fragment_specifiers: Default::default(),
raw_identifier_spans: Lock::new(Vec::new()),
bad_unicode_identifiers: Lock::new(Default::default()),
source_map,
2 changes: 1 addition & 1 deletion library/alloc/src/rc.rs
Original file line number Diff line number Diff line change
@@ -393,7 +393,7 @@ impl<T> Rc<T> {
/// # Examples
///
/// ```
/// #![allow(dead_code)]
/// # #![allow(dead_code)]
/// use std::rc::{Rc, Weak};
///
/// struct Gadget {
92 changes: 82 additions & 10 deletions library/alloc/src/string.rs
Original file line number Diff line number Diff line change
@@ -117,27 +117,99 @@ use crate::vec::Vec;
///
/// # UTF-8
///
/// `String`s are always valid UTF-8. This has a few implications, the first of
/// which is that if you need a non-UTF-8 string, consider [`OsString`]. It is
/// similar, but without the UTF-8 constraint. The second implication is that
/// you cannot index into a `String`:
/// `String`s are always valid UTF-8. If you need a non-UTF-8 string, consider
/// [`OsString`]. It is similar, but without the UTF-8 constraint. Because UTF-8
/// is a variable width encoding, `String`s are typically smaller than an array of
/// the same `chars`:
///
/// ```
/// use std::mem;
///
/// // `s` is ASCII which represents each `char` as one byte
/// let s = "hello";
/// assert_eq!(s.len(), 5);
///
/// // A `char` array with the same contents would be longer because
/// // every `char` is four bytes
/// let s = ['h', 'e', 'l', 'l', 'o'];
/// let size: usize = s.into_iter().map(|c| mem::size_of_val(&c)).sum();
/// assert_eq!(size, 20);
///
/// // However, for non-ASCII strings, the difference will be smaller
/// // and sometimes they are the same
/// let s = "💖💖💖💖💖";
/// assert_eq!(s.len(), 20);
///
/// let s = ['💖', '💖', '💖', '💖', '💖'];
/// let size: usize = s.into_iter().map(|c| mem::size_of_val(&c)).sum();
/// assert_eq!(size, 20);
/// ```
///
/// This raises interesting questions as to how `s[i]` should work.
/// What should `i` be here? Several options include byte indices and
/// `char` indices but, because of UTF-8 encoding, only byte indices
/// would provide constant time indexing. Getting the `i`th `char`, for
/// example, is available using [`chars`]:
///
/// ```
/// let s = "hello";
/// let third_character = s.chars().nth(2);
/// assert_eq!(third_character, Some('l'));
///
/// let s = "💖💖💖💖💖";
/// let third_character = s.chars().nth(2);
/// assert_eq!(third_character, Some('💖'));
/// ```
///
/// Next, what should `s[i]` return? Because indexing returns a reference
/// to underlying data it could be `&u8`, `&[u8]`, or something else similar.
/// Since we're only providing one index, `&u8` makes the most sense but that
/// might not be what the user expects and can be explicitly achieved with
/// [`as_bytes()`]:
///
/// ```
/// // The first byte is 104 - the byte value of `'h'`
/// let s = "hello";
/// assert_eq!(s.as_bytes()[0], 104);
/// // or
/// assert_eq!(s.as_bytes()[0], b'h');
///
/// // The first byte is 240 which isn't obviously useful
/// let s = "💖💖💖💖💖";
/// assert_eq!(s.as_bytes()[0], 240);
/// ```
///
/// Due to these ambiguities/restrictions, indexing with a `usize` is simply
/// forbidden:
///
/// ```compile_fail,E0277
/// let s = "hello";
///
/// println!("The first letter of s is {}", s[0]); // ERROR!!!
/// // The following will not compile!
/// println!("The first letter of s is {}", s[0]);
/// ```
///
/// It is more clear, however, how `&s[i..j]` should work (that is,
/// indexing with a range). It should accept byte indices (to be constant-time)
/// and return a `&str` which is UTF-8 encoded. This is also called "string slicing".
/// Note this will panic if the byte indices provided are not character
/// boundaries - see [`is_char_boundary`] for more details. See the implementations
/// for [`SliceIndex<str>`] for more details on string slicing. For a non-panicking
/// version of string slicing, see [`get`].
///
/// [`OsString`]: ../../std/ffi/struct.OsString.html "ffi::OsString"
/// [`SliceIndex<str>`]: core::slice::SliceIndex
/// [`as_bytes()`]: str::as_bytes
/// [`get`]: str::get
/// [`is_char_boundary`]: str::is_char_boundary
///
/// Indexing is intended to be a constant-time operation, but UTF-8 encoding
/// does not allow us to do this. Furthermore, it's not clear what sort of
/// thing the index should return: a byte, a codepoint, or a grapheme cluster.
/// The [`bytes`] and [`chars`] methods return iterators over the first
/// two, respectively.
/// The [`bytes`] and [`chars`] methods return iterators over the bytes and
/// codepoints of the string, respectively. To iterate over codepoints along
/// with byte indices, use [`char_indices`].
///
/// [`bytes`]: str::bytes
/// [`chars`]: str::chars
/// [`char_indices`]: str::char_indices
///
/// # Deref
///
11 changes: 5 additions & 6 deletions library/core/src/alloc/layout.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use crate::cmp;
use crate::fmt;
use crate::mem;
use crate::num::NonZeroUsize;
use crate::mem::{self, ValidAlign};
use crate::ptr::NonNull;

// While this function is used in one place and its implementation
@@ -40,7 +39,7 @@ pub struct Layout {
//
// (However, we do not analogously require `align >= sizeof(void*)`,
// even though that is *also* a requirement of `posix_memalign`.)
align_: NonZeroUsize,
align_: ValidAlign,
}

impl Layout {
@@ -97,8 +96,8 @@ impl Layout {
#[must_use]
#[inline]
pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self {
// SAFETY: the caller must ensure that `align` is greater than zero.
Layout { size_: size, align_: unsafe { NonZeroUsize::new_unchecked(align) } }
// SAFETY: the caller must ensure that `align` is a power of two.
Layout { size_: size, align_: unsafe { ValidAlign::new_unchecked(align) } }
}

/// The minimum size in bytes for a memory block of this layout.
@@ -117,7 +116,7 @@ impl Layout {
without modifying the layout"]
#[inline]
pub const fn align(&self) -> usize {
self.align_.get()
self.align_.as_nonzero().get()
}

/// Constructs a `Layout` suitable for holding a value of type `T`.
6 changes: 6 additions & 0 deletions library/core/src/mem/mod.rs
Original file line number Diff line number Diff line change
@@ -21,6 +21,12 @@ mod maybe_uninit;
#[stable(feature = "maybe_uninit", since = "1.36.0")]
pub use maybe_uninit::MaybeUninit;

mod valid_align;
// For now this type is left crate-local. It could potentially make sense to expose
// it publicly, as it would be a nice parameter type for methods which need to take
// alignment as a parameter, such as `Layout::padding_needed_for`.
pub(crate) use valid_align::ValidAlign;

#[stable(feature = "rust1", since = "1.0.0")]
#[doc(inline)]
pub use crate::intrinsics::transmute;
240 changes: 240 additions & 0 deletions library/core/src/mem/valid_align.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
use crate::convert::TryFrom;
use crate::num::NonZeroUsize;
use crate::{cmp, fmt, mem, num};

/// A type storing a `usize` which is a power of two, and thus
/// represents a possible alignment in the rust abstract machine.
///
/// Note that particularly large alignments, while representable in this type,
/// are likely not to be supported by actual allocators and linkers.
#[derive(Copy, Clone)]
#[repr(transparent)]
pub(crate) struct ValidAlign(ValidAlignEnum);

// ValidAlign is `repr(usize)`, but via extra steps.
const _: () = assert!(mem::size_of::<ValidAlign>() == mem::size_of::<usize>());
const _: () = assert!(mem::align_of::<ValidAlign>() == mem::align_of::<usize>());

impl ValidAlign {
/// Creates a `ValidAlign` from a power-of-two `usize`.
///
/// # Safety
///
/// `align` must be a power of two.
///
/// Equivalently, it must be `1 << exp` for some `exp` in `0..usize::BITS`.
/// It must *not* be zero.
#[inline]
pub(crate) const unsafe fn new_unchecked(align: usize) -> Self {
debug_assert!(align.is_power_of_two());

// SAFETY: By precondition, this must be a power of two, and
// our variants encompass all possible powers of two.
unsafe { mem::transmute::<usize, ValidAlign>(align) }
}

#[inline]
pub(crate) const fn as_nonzero(self) -> NonZeroUsize {
// SAFETY: All the discriminants are non-zero.
unsafe { NonZeroUsize::new_unchecked(self.0 as usize) }
}

/// Returns the base 2 logarithm of the alignment.
///
/// This is always exact, as `self` represents a power of two.
#[inline]
pub(crate) fn log2(self) -> u32 {
self.as_nonzero().trailing_zeros()
}
}

impl fmt::Debug for ValidAlign {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?} (1 << {:?})", self.as_nonzero(), self.log2())
}
}

impl TryFrom<NonZeroUsize> for ValidAlign {
type Error = num::TryFromIntError;

#[inline]
fn try_from(align: NonZeroUsize) -> Result<ValidAlign, Self::Error> {
if align.is_power_of_two() {
// SAFETY: Just checked for power-of-two
unsafe { Ok(ValidAlign::new_unchecked(align.get())) }
} else {
Err(num::TryFromIntError(()))
}
}
}

impl TryFrom<usize> for ValidAlign {
type Error = num::TryFromIntError;

#[inline]
fn try_from(align: usize) -> Result<ValidAlign, Self::Error> {
if align.is_power_of_two() {
// SAFETY: Just checked for power-of-two
unsafe { Ok(ValidAlign::new_unchecked(align)) }
} else {
Err(num::TryFromIntError(()))
}
}
}

impl cmp::Eq for ValidAlign {}

impl cmp::PartialEq for ValidAlign {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.as_nonzero() == other.as_nonzero()
}
}

impl cmp::Ord for ValidAlign {
#[inline]
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.as_nonzero().cmp(&other.as_nonzero())
}
}

impl cmp::PartialOrd for ValidAlign {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}

#[cfg(target_pointer_width = "16")]
type ValidAlignEnum = ValidAlignEnum16;
#[cfg(target_pointer_width = "32")]
type ValidAlignEnum = ValidAlignEnum32;
#[cfg(target_pointer_width = "64")]
type ValidAlignEnum = ValidAlignEnum64;

#[derive(Copy, Clone)]
#[repr(u16)]
enum ValidAlignEnum16 {
_Align1Shl0 = 1 << 0,
_Align1Shl1 = 1 << 1,
_Align1Shl2 = 1 << 2,
_Align1Shl3 = 1 << 3,
_Align1Shl4 = 1 << 4,
_Align1Shl5 = 1 << 5,
_Align1Shl6 = 1 << 6,
_Align1Shl7 = 1 << 7,
_Align1Shl8 = 1 << 8,
_Align1Shl9 = 1 << 9,
_Align1Shl10 = 1 << 10,
_Align1Shl11 = 1 << 11,
_Align1Shl12 = 1 << 12,
_Align1Shl13 = 1 << 13,
_Align1Shl14 = 1 << 14,
_Align1Shl15 = 1 << 15,
}

#[derive(Copy, Clone)]
#[repr(u32)]
enum ValidAlignEnum32 {
_Align1Shl0 = 1 << 0,
_Align1Shl1 = 1 << 1,
_Align1Shl2 = 1 << 2,
_Align1Shl3 = 1 << 3,
_Align1Shl4 = 1 << 4,
_Align1Shl5 = 1 << 5,
_Align1Shl6 = 1 << 6,
_Align1Shl7 = 1 << 7,
_Align1Shl8 = 1 << 8,
_Align1Shl9 = 1 << 9,
_Align1Shl10 = 1 << 10,
_Align1Shl11 = 1 << 11,
_Align1Shl12 = 1 << 12,
_Align1Shl13 = 1 << 13,
_Align1Shl14 = 1 << 14,
_Align1Shl15 = 1 << 15,
_Align1Shl16 = 1 << 16,
_Align1Shl17 = 1 << 17,
_Align1Shl18 = 1 << 18,
_Align1Shl19 = 1 << 19,
_Align1Shl20 = 1 << 20,
_Align1Shl21 = 1 << 21,
_Align1Shl22 = 1 << 22,
_Align1Shl23 = 1 << 23,
_Align1Shl24 = 1 << 24,
_Align1Shl25 = 1 << 25,
_Align1Shl26 = 1 << 26,
_Align1Shl27 = 1 << 27,
_Align1Shl28 = 1 << 28,
_Align1Shl29 = 1 << 29,
_Align1Shl30 = 1 << 30,
_Align1Shl31 = 1 << 31,
}

#[derive(Copy, Clone)]
#[repr(u64)]
enum ValidAlignEnum64 {
_Align1Shl0 = 1 << 0,
_Align1Shl1 = 1 << 1,
_Align1Shl2 = 1 << 2,
_Align1Shl3 = 1 << 3,
_Align1Shl4 = 1 << 4,
_Align1Shl5 = 1 << 5,
_Align1Shl6 = 1 << 6,
_Align1Shl7 = 1 << 7,
_Align1Shl8 = 1 << 8,
_Align1Shl9 = 1 << 9,
_Align1Shl10 = 1 << 10,
_Align1Shl11 = 1 << 11,
_Align1Shl12 = 1 << 12,
_Align1Shl13 = 1 << 13,
_Align1Shl14 = 1 << 14,
_Align1Shl15 = 1 << 15,
_Align1Shl16 = 1 << 16,
_Align1Shl17 = 1 << 17,
_Align1Shl18 = 1 << 18,
_Align1Shl19 = 1 << 19,
_Align1Shl20 = 1 << 20,
_Align1Shl21 = 1 << 21,
_Align1Shl22 = 1 << 22,
_Align1Shl23 = 1 << 23,
_Align1Shl24 = 1 << 24,
_Align1Shl25 = 1 << 25,
_Align1Shl26 = 1 << 26,
_Align1Shl27 = 1 << 27,
_Align1Shl28 = 1 << 28,
_Align1Shl29 = 1 << 29,
_Align1Shl30 = 1 << 30,
_Align1Shl31 = 1 << 31,
_Align1Shl32 = 1 << 32,
_Align1Shl33 = 1 << 33,
_Align1Shl34 = 1 << 34,
_Align1Shl35 = 1 << 35,
_Align1Shl36 = 1 << 36,
_Align1Shl37 = 1 << 37,
_Align1Shl38 = 1 << 38,
_Align1Shl39 = 1 << 39,
_Align1Shl40 = 1 << 40,
_Align1Shl41 = 1 << 41,
_Align1Shl42 = 1 << 42,
_Align1Shl43 = 1 << 43,
_Align1Shl44 = 1 << 44,
_Align1Shl45 = 1 << 45,
_Align1Shl46 = 1 << 46,
_Align1Shl47 = 1 << 47,
_Align1Shl48 = 1 << 48,
_Align1Shl49 = 1 << 49,
_Align1Shl50 = 1 << 50,
_Align1Shl51 = 1 << 51,
_Align1Shl52 = 1 << 52,
_Align1Shl53 = 1 << 53,
_Align1Shl54 = 1 << 54,
_Align1Shl55 = 1 << 55,
_Align1Shl56 = 1 << 56,
_Align1Shl57 = 1 << 57,
_Align1Shl58 = 1 << 58,
_Align1Shl59 = 1 << 59,
_Align1Shl60 = 1 << 60,
_Align1Shl61 = 1 << 61,
_Align1Shl62 = 1 << 62,
_Align1Shl63 = 1 << 63,
}
4 changes: 2 additions & 2 deletions library/core/src/num/mod.rs
Original file line number Diff line number Diff line change
@@ -299,8 +299,8 @@ impl u8 {
#[rustc_const_stable(feature = "const_ascii_methods_on_intrinsics", since = "1.52.0")]
#[inline]
pub const fn to_ascii_uppercase(&self) -> u8 {
// Unset the fifth bit if this is a lowercase letter
*self & !((self.is_ascii_lowercase() as u8) * ASCII_CASE_MASK)
// Toggle the fifth bit if this is a lowercase letter
*self ^ ((self.is_ascii_lowercase() as u8) * ASCII_CASE_MASK)
}

/// Makes a copy of the value in its ASCII lower case equivalent.
26 changes: 13 additions & 13 deletions library/core/src/tuple.rs
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ use crate::cmp::*;

// macro for implementing n-ary tuple functions and operations
macro_rules! tuple_impls {
( $( $Tuple:ident( $( $T:ident )+ ) )+ ) => {
( $( ( $( $T:ident )+ ) )+ ) => {
$(
#[stable(feature = "rust1", since = "1.0.0")]
impl<$($T:PartialEq),+> PartialEq for ($($T,)+) where last_type!($($T,)+): ?Sized {
@@ -106,16 +106,16 @@ macro_rules! last_type {
}

tuple_impls! {
Tuple1(A)
Tuple2(A B)
Tuple3(A B C)
Tuple4(A B C D)
Tuple5(A B C D E)
Tuple6(A B C D E F)
Tuple7(A B C D E F G)
Tuple8(A B C D E F G H)
Tuple9(A B C D E F G H I)
Tuple10(A B C D E F G H I J)
Tuple11(A B C D E F G H I J K)
Tuple12(A B C D E F G H I J K L)
(A)
(A B)
(A B C)
(A B C D)
(A B C D E)
(A B C D E F)
(A B C D E F G)
(A B C D E F G H)
(A B C D E F G H I)
(A B C D E F G H I J)
(A B C D E F G H I J K)
(A B C D E F G H I J K L)
}
18 changes: 18 additions & 0 deletions library/core/tests/alloc.rs
Original file line number Diff line number Diff line change
@@ -11,3 +11,21 @@ fn const_unchecked_layout() {
assert_eq!(LAYOUT.align(), ALIGN);
assert_eq!(Some(DANGLING), NonNull::new(ALIGN as *mut u8));
}

#[test]
fn layout_debug_shows_log2_of_alignment() {
// `Debug` is not stable, but here's what it does right now
let layout = Layout::from_size_align(24576, 8192).unwrap();
let s = format!("{:?}", layout);
assert_eq!(s, "Layout { size_: 24576, align_: 8192 (1 << 13) }");
}

// Running this normally doesn't do much, but it's also run in Miri, which
// will double-check that these are allowed by the validity invariants.
#[test]
fn layout_accepts_all_valid_alignments() {
for align in 0..usize::BITS {
let layout = Layout::from_size_align(0, 1_usize << align).unwrap();
assert_eq!(layout.align(), 1_usize << align);
}
}
35 changes: 29 additions & 6 deletions src/bootstrap/test.rs
Original file line number Diff line number Diff line change
@@ -2065,6 +2065,7 @@ impl Step for Crate {
}
}

/// Rustdoc is special in various ways, which is why this step is different from `Crate`.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct CrateRustdoc {
host: TargetSelection,
@@ -2092,11 +2093,15 @@ impl Step for CrateRustdoc {
let test_kind = self.test_kind;
let target = self.host;

// Use the previous stage compiler to reuse the artifacts that are
// created when running compiletest for src/test/rustdoc. If this used
// `compiler`, then it would cause rustdoc to be built *again*, which
// isn't really necessary.
let compiler = builder.compiler_for(builder.top_stage, target, target);
let compiler = if builder.config.download_rustc {
builder.compiler(builder.top_stage, target)
} else {
// Use the previous stage compiler to reuse the artifacts that are
// created when running compiletest for src/test/rustdoc. If this used
// `compiler`, then it would cause rustdoc to be built *again*, which
// isn't really necessary.
builder.compiler_for(builder.top_stage, target, target)
};
builder.ensure(compile::Rustc { compiler, target });

let mut cargo = tool::prepare_tool_cargo(
@@ -2112,6 +2117,15 @@ impl Step for CrateRustdoc {
if test_kind.subcommand() == "test" && !builder.fail_fast {
cargo.arg("--no-fail-fast");
}
match builder.doc_tests {
DocTests::Only => {
cargo.arg("--doc");
}
DocTests::No => {
cargo.args(&["--lib", "--bins", "--examples", "--tests", "--benches"]);
}
DocTests::Yes => {}
}

cargo.arg("-p").arg("rustdoc:0.0.0");

@@ -2136,6 +2150,8 @@ impl Step for CrateRustdoc {
// sets up the dylib path for the *host* (stage1/lib), which is the
// wrong directory.
//
// Recall that we special-cased `compiler_for(top_stage)` above, so we always use stage1.
//
// It should be considered to just stop running doctests on
// librustdoc. There is only one test, and it doesn't look too
// important. There might be other ways to avoid this, but it seems
@@ -2144,8 +2160,15 @@ impl Step for CrateRustdoc {
// See also https://github.com/rust-lang/rust/issues/13983 where the
// host vs target dylibs for rustdoc are consistently tricky to deal
// with.
//
// Note that this set the host libdir for `download_rustc`, which uses a normal rust distribution.
let libdir = if builder.config.download_rustc {
builder.rustc_libdir(compiler)
} else {
builder.sysroot_libdir(compiler, target).to_path_buf()
};
let mut dylib_path = dylib_path();
dylib_path.insert(0, PathBuf::from(&*builder.sysroot_libdir(compiler, target)));
dylib_path.insert(0, PathBuf::from(&*libdir));
cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());

if !builder.config.verbose_tests {
19 changes: 15 additions & 4 deletions src/test/ui/consts/std/alloc.32bit.stderr
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
error[E0080]: it is undefined behavior to use this value
--> $DIR/alloc.rs:8:1
--> $DIR/alloc.rs:9:1
|
LL | const LAYOUT_INVALID: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align_: encountered 0, but expected something greater or equal to 1
LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align_.0.<enum-tag>: encountered 0x00000000, but expected a valid enum tag
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
00 10 00 00 00 00 00 00 │ ........
}

error: aborting due to previous error
error[E0080]: it is undefined behavior to use this value
--> $DIR/alloc.rs:13:1
|
LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align_.0.<enum-tag>: encountered 0x00000003, but expected a valid enum tag
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
09 00 00 00 03 00 00 00 │ ........
}

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0080`.
19 changes: 15 additions & 4 deletions src/test/ui/consts/std/alloc.64bit.stderr
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
error[E0080]: it is undefined behavior to use this value
--> $DIR/alloc.rs:8:1
--> $DIR/alloc.rs:9:1
|
LL | const LAYOUT_INVALID: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align_: encountered 0, but expected something greater or equal to 1
LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align_.0.<enum-tag>: encountered 0x0000000000000000, but expected a valid enum tag
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
}

error: aborting due to previous error
error[E0080]: it is undefined behavior to use this value
--> $DIR/alloc.rs:13:1
|
LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align_.0.<enum-tag>: encountered 0x0000000000000003, but expected a valid enum tag
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
09 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 │ ................
}

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0080`.
7 changes: 6 additions & 1 deletion src/test/ui/consts/std/alloc.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
// stderr-per-bitwidth
// ignore-debug (the debug assertions change the error)
use std::alloc::Layout;

// ok
const LAYOUT_VALID: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x08) };

// not ok, since alignment needs to be non-zero.
const LAYOUT_INVALID: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) };
const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) };
//~^ ERROR it is undefined behavior to use this value

// not ok, since alignment needs to be a power of two.
const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) };
//~^ ERROR it is undefined behavior to use this value

fn main() {}
2 changes: 2 additions & 0 deletions src/test/ui/macros/macro-match-nonterminal.rs
Original file line number Diff line number Diff line change
@@ -2,6 +2,8 @@ macro_rules! test {
($a, $b) => {
//~^ ERROR missing fragment
//~| ERROR missing fragment
//~| ERROR missing fragment
//~| WARN this was previously accepted
//~| WARN this was previously accepted
()
};
13 changes: 11 additions & 2 deletions src/test/ui/macros/macro-match-nonterminal.stderr
Original file line number Diff line number Diff line change
@@ -4,15 +4,24 @@ error: missing fragment specifier
LL | ($a, $b) => {
| ^

error: missing fragment specifier
--> $DIR/macro-match-nonterminal.rs:2:8
|
LL | ($a, $b) => {
| ^
|
= note: `#[deny(missing_fragment_specifier)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>

error: missing fragment specifier
--> $DIR/macro-match-nonterminal.rs:2:10
|
LL | ($a, $b) => {
| ^^
|
= note: `#[deny(missing_fragment_specifier)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>

error: aborting due to 2 previous errors
error: aborting due to 3 previous errors

15 changes: 15 additions & 0 deletions src/test/ui/macros/macro-missing-fragment-deduplication.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// compile-flags: -Zdeduplicate-diagnostics=yes

macro_rules! m {
($name) => {}
//~^ ERROR missing fragment
//~| ERROR missing fragment
//~| WARN this was previously accepted
}

fn main() {
m!();
m!();
m!();
m!();
}
18 changes: 18 additions & 0 deletions src/test/ui/macros/macro-missing-fragment-deduplication.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
error: missing fragment specifier
--> $DIR/macro-missing-fragment-deduplication.rs:4:6
|
LL | ($name) => {}
| ^^^^^

error: missing fragment specifier
--> $DIR/macro-missing-fragment-deduplication.rs:4:6
|
LL | ($name) => {}
| ^^^^^
|
= note: `#[deny(missing_fragment_specifier)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>

error: aborting due to 2 previous errors

25 changes: 22 additions & 3 deletions src/test/ui/macros/macro-missing-fragment.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,26 @@
macro_rules! m {
( $( any_token $field_rust_type )* ) => {}; //~ ERROR missing fragment
#![warn(missing_fragment_specifier)]

macro_rules! used_arm {
( $( any_token $field_rust_type )* ) => {};
//~^ ERROR missing fragment
//~| WARN missing fragment
//~| WARN this was previously accepted
}

macro_rules! used_macro_unused_arm {
() => {};
( $name ) => {};
//~^ WARN missing fragment
//~| WARN this was previously accepted
}

macro_rules! unused_macro {
( $name ) => {};
//~^ WARN missing fragment
//~| WARN this was previously accepted
}

fn main() {
m!();
used_arm!();
used_macro_unused_arm!();
}
36 changes: 34 additions & 2 deletions src/test/ui/macros/macro-missing-fragment.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,40 @@
error: missing fragment specifier
--> $DIR/macro-missing-fragment.rs:2:20
--> $DIR/macro-missing-fragment.rs:4:20
|
LL | ( $( any_token $field_rust_type )* ) => {};
| ^^^^^^^^^^^^^^^^

error: aborting due to previous error
warning: missing fragment specifier
--> $DIR/macro-missing-fragment.rs:4:20
|
LL | ( $( any_token $field_rust_type )* ) => {};
| ^^^^^^^^^^^^^^^^
|
note: the lint level is defined here
--> $DIR/macro-missing-fragment.rs:1:9
|
LL | #![warn(missing_fragment_specifier)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>

warning: missing fragment specifier
--> $DIR/macro-missing-fragment.rs:12:7
|
LL | ( $name ) => {};
| ^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>

warning: missing fragment specifier
--> $DIR/macro-missing-fragment.rs:18:7
|
LL | ( $name ) => {};
| ^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>

error: aborting due to previous error; 3 warnings emitted

2 changes: 2 additions & 0 deletions src/test/ui/parser/macro/issue-33569.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
macro_rules! foo {
{ $+ } => { //~ ERROR expected identifier, found `+`
//~^ ERROR missing fragment specifier
//~| ERROR missing fragment specifier
//~| WARN this was previously accepted
$(x)(y) //~ ERROR expected one of: `*`, `+`, or `?`
}
}
14 changes: 12 additions & 2 deletions src/test/ui/parser/macro/issue-33569.stderr
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ LL | { $+ } => {
| ^

error: expected one of: `*`, `+`, or `?`
--> $DIR/issue-33569.rs:4:13
--> $DIR/issue-33569.rs:6:13
|
LL | $(x)(y)
| ^^^
@@ -16,5 +16,15 @@ error: missing fragment specifier
LL | { $+ } => {
| ^

error: aborting due to 3 previous errors
error: missing fragment specifier
--> $DIR/issue-33569.rs:2:8
|
LL | { $+ } => {
| ^
|
= note: `#[deny(missing_fragment_specifier)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>

error: aborting due to 4 previous errors