Skip to content

Commit 8bf93e9

Browse files
committedApr 9, 2022
Auto merge of rust-lang#95855 - Dylan-DPC:rollup-h45xmpw, r=Dylan-DPC
Rollup of 7 pull requests Successful merges: - rust-lang#94794 (Clarify indexing into Strings) - rust-lang#95361 (Make non-power-of-two alignments a validity error in `Layout`) - rust-lang#95369 (Fix `x test src/librustdoc` with `download-rustc` enabled ) - rust-lang#95805 (Left overs of rust-lang#95761) - rust-lang#95808 (expand: Remove `ParseSess::missing_fragment_specifiers`) - rust-lang#95817 (hide another #[allow] directive from a docs example) - rust-lang#95831 (Use bitwise XOR in to_ascii_uppercase) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
2 parents 8c1fb2e + 7726265 commit 8bf93e9

26 files changed

+569
-95
lines changed
 

‎compiler/rustc_expand/src/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
#![feature(associated_type_bounds)]
33
#![feature(associated_type_defaults)]
44
#![feature(crate_visibility_modifier)]
5-
#![feature(decl_macro)]
65
#![feature(if_let_guard)]
76
#![feature(let_chains)]
87
#![feature(let_else)]

‎compiler/rustc_expand/src/mbe/macro_check.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ use rustc_ast::token::{DelimToken, Token, TokenKind};
110110
use rustc_ast::{NodeId, DUMMY_NODE_ID};
111111
use rustc_data_structures::fx::FxHashMap;
112112
use rustc_errors::MultiSpan;
113-
use rustc_session::lint::builtin::META_VARIABLE_MISUSE;
113+
use rustc_session::lint::builtin::{META_VARIABLE_MISUSE, MISSING_FRAGMENT_SPECIFIER};
114114
use rustc_session::parse::ParseSess;
115115
use rustc_span::symbol::kw;
116116
use rustc_span::{symbol::MacroRulesNormalizedIdent, Span};
@@ -261,7 +261,18 @@ fn check_binders(
261261
}
262262
}
263263
// Similarly, this can only happen when checking a toplevel macro.
264-
TokenTree::MetaVarDecl(span, name, _kind) => {
264+
TokenTree::MetaVarDecl(span, name, kind) => {
265+
if kind.is_none() && node_id != DUMMY_NODE_ID {
266+
// FIXME: Report this as a hard error eventually and remove equivalent errors from
267+
// `parse_tt_inner` and `nameize`. Until then the error may be reported twice, once
268+
// as a hard error and then once as a buffered lint.
269+
sess.buffer_lint(
270+
MISSING_FRAGMENT_SPECIFIER,
271+
span,
272+
node_id,
273+
&format!("missing fragment specifier"),
274+
);
275+
}
265276
if !macros.is_empty() {
266277
sess.span_diagnostic.span_bug(span, "unexpected MetaVarDecl in nested lhs");
267278
}

‎compiler/rustc_expand/src/mbe/macro_parser.rs

+6-12
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,6 @@ impl TtParser {
411411
/// track of through the mps generated.
412412
fn parse_tt_inner(
413413
&mut self,
414-
sess: &ParseSess,
415414
matcher: &[MatcherLoc],
416415
token: &Token,
417416
) -> Option<NamedParseResult> {
@@ -519,11 +518,9 @@ impl TtParser {
519518
self.bb_mps.push(mp);
520519
}
521520
} else {
521+
// E.g. `$e` instead of `$e:expr`, reported as a hard error if actually used.
522522
// Both this check and the one in `nameize` are necessary, surprisingly.
523-
if sess.missing_fragment_specifiers.borrow_mut().remove(&span).is_some() {
524-
// E.g. `$e` instead of `$e:expr`.
525-
return Some(Error(span, "missing fragment specifier".to_string()));
526-
}
523+
return Some(Error(span, "missing fragment specifier".to_string()));
527524
}
528525
}
529526
MatcherLoc::Eof => {
@@ -549,7 +546,7 @@ impl TtParser {
549546
// Need to take ownership of the matches from within the `Lrc`.
550547
Lrc::make_mut(&mut eof_mp.matches);
551548
let matches = Lrc::try_unwrap(eof_mp.matches).unwrap().into_iter();
552-
self.nameize(sess, matcher, matches)
549+
self.nameize(matcher, matches)
553550
}
554551
EofMatcherPositions::Multiple => {
555552
Error(token.span, "ambiguity: multiple successful parses".to_string())
@@ -587,7 +584,7 @@ impl TtParser {
587584

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

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

695692
fn nameize<I: Iterator<Item = NamedMatch>>(
696693
&self,
697-
sess: &ParseSess,
698694
matcher: &[MatcherLoc],
699695
mut res: I,
700696
) -> NamedParseResult {
@@ -711,11 +707,9 @@ impl TtParser {
711707
}
712708
};
713709
} else {
710+
// E.g. `$e` instead of `$e:expr`, reported as a hard error if actually used.
714711
// Both this check and the one in `parse_tt_inner` are necessary, surprisingly.
715-
if sess.missing_fragment_specifiers.borrow_mut().remove(&span).is_some() {
716-
// E.g. `$e` instead of `$e:expr`.
717-
return Error(span, "missing fragment specifier".to_string());
718-
}
712+
return Error(span, "missing fragment specifier".to_string());
719713
}
720714
}
721715
}

‎compiler/rustc_expand/src/mbe/quoted.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ use crate::mbe::macro_parser::count_metavar_decls;
22
use crate::mbe::{Delimited, KleeneOp, KleeneToken, MetaVarExpr, SequenceRepetition, TokenTree};
33

44
use rustc_ast::token::{self, Token};
5-
use rustc_ast::tokenstream;
6-
use rustc_ast::{NodeId, DUMMY_NODE_ID};
5+
use rustc_ast::{tokenstream, NodeId};
76
use rustc_ast_pretty::pprust;
87
use rustc_feature::Features;
98
use rustc_session::parse::{feature_err, ParseSess};
@@ -104,10 +103,7 @@ pub(super) fn parse(
104103
}
105104
tree => tree.as_ref().map_or(start_sp, tokenstream::TokenTree::span),
106105
};
107-
if node_id != DUMMY_NODE_ID {
108-
// Macros loaded from other crates have dummy node ids.
109-
sess.missing_fragment_specifiers.borrow_mut().insert(span, node_id);
110-
}
106+
111107
result.push(TokenTree::MetaVarDecl(span, ident, None));
112108
}
113109

‎compiler/rustc_interface/src/passes.rs

-16
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ use rustc_resolve::{Resolver, ResolverArenas};
3030
use rustc_serialize::json;
3131
use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType};
3232
use rustc_session::cstore::{MetadataLoader, MetadataLoaderDyn};
33-
use rustc_session::lint;
3433
use rustc_session::output::{filename_for_input, filename_for_metadata};
3534
use rustc_session::search_paths::PathKind;
3635
use rustc_session::{Limit, Session};
@@ -349,23 +348,8 @@ pub fn configure_and_expand(
349348
ecx.check_unused_macros();
350349
});
351350

352-
let mut missing_fragment_specifiers: Vec<_> = ecx
353-
.sess
354-
.parse_sess
355-
.missing_fragment_specifiers
356-
.borrow()
357-
.iter()
358-
.map(|(span, node_id)| (*span, *node_id))
359-
.collect();
360-
missing_fragment_specifiers.sort_unstable_by_key(|(span, _)| *span);
361-
362351
let recursion_limit_hit = ecx.reduced_recursion_limit.is_some();
363352

364-
for (span, node_id) in missing_fragment_specifiers {
365-
let lint = lint::builtin::MISSING_FRAGMENT_SPECIFIER;
366-
let msg = "missing fragment specifier";
367-
resolver.lint_buffer().buffer_lint(lint, node_id, span, msg);
368-
}
369353
if cfg!(windows) {
370354
env::set_var("PATH", &old_path);
371355
}

‎compiler/rustc_session/src/parse.rs

-2
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,6 @@ pub struct ParseSess {
140140
pub config: CrateConfig,
141141
pub check_config: CrateCheckConfig,
142142
pub edition: Edition,
143-
pub missing_fragment_specifiers: Lock<FxHashMap<Span, NodeId>>,
144143
/// Places where raw identifiers were used. This is used to avoid complaining about idents
145144
/// clashing with keywords in new editions.
146145
pub raw_identifier_spans: Lock<Vec<Span>>,
@@ -195,7 +194,6 @@ impl ParseSess {
195194
config: FxHashSet::default(),
196195
check_config: CrateCheckConfig::default(),
197196
edition: ExpnId::root().expn_data().edition,
198-
missing_fragment_specifiers: Default::default(),
199197
raw_identifier_spans: Lock::new(Vec::new()),
200198
bad_unicode_identifiers: Lock::new(Default::default()),
201199
source_map,

‎library/alloc/src/rc.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ impl<T> Rc<T> {
393393
/// # Examples
394394
///
395395
/// ```
396-
/// #![allow(dead_code)]
396+
/// # #![allow(dead_code)]
397397
/// use std::rc::{Rc, Weak};
398398
///
399399
/// struct Gadget {

‎library/alloc/src/string.rs

+82-10
Original file line numberDiff line numberDiff line change
@@ -117,27 +117,99 @@ use crate::vec::Vec;
117117
///
118118
/// # UTF-8
119119
///
120-
/// `String`s are always valid UTF-8. This has a few implications, the first of
121-
/// which is that if you need a non-UTF-8 string, consider [`OsString`]. It is
122-
/// similar, but without the UTF-8 constraint. The second implication is that
123-
/// you cannot index into a `String`:
120+
/// `String`s are always valid UTF-8. If you need a non-UTF-8 string, consider
121+
/// [`OsString`]. It is similar, but without the UTF-8 constraint. Because UTF-8
122+
/// is a variable width encoding, `String`s are typically smaller than an array of
123+
/// the same `chars`:
124+
///
125+
/// ```
126+
/// use std::mem;
127+
///
128+
/// // `s` is ASCII which represents each `char` as one byte
129+
/// let s = "hello";
130+
/// assert_eq!(s.len(), 5);
131+
///
132+
/// // A `char` array with the same contents would be longer because
133+
/// // every `char` is four bytes
134+
/// let s = ['h', 'e', 'l', 'l', 'o'];
135+
/// let size: usize = s.into_iter().map(|c| mem::size_of_val(&c)).sum();
136+
/// assert_eq!(size, 20);
137+
///
138+
/// // However, for non-ASCII strings, the difference will be smaller
139+
/// // and sometimes they are the same
140+
/// let s = "💖💖💖💖💖";
141+
/// assert_eq!(s.len(), 20);
142+
///
143+
/// let s = ['💖', '💖', '💖', '💖', '💖'];
144+
/// let size: usize = s.into_iter().map(|c| mem::size_of_val(&c)).sum();
145+
/// assert_eq!(size, 20);
146+
/// ```
147+
///
148+
/// This raises interesting questions as to how `s[i]` should work.
149+
/// What should `i` be here? Several options include byte indices and
150+
/// `char` indices but, because of UTF-8 encoding, only byte indices
151+
/// would provide constant time indexing. Getting the `i`th `char`, for
152+
/// example, is available using [`chars`]:
153+
///
154+
/// ```
155+
/// let s = "hello";
156+
/// let third_character = s.chars().nth(2);
157+
/// assert_eq!(third_character, Some('l'));
158+
///
159+
/// let s = "💖💖💖💖💖";
160+
/// let third_character = s.chars().nth(2);
161+
/// assert_eq!(third_character, Some('💖'));
162+
/// ```
163+
///
164+
/// Next, what should `s[i]` return? Because indexing returns a reference
165+
/// to underlying data it could be `&u8`, `&[u8]`, or something else similar.
166+
/// Since we're only providing one index, `&u8` makes the most sense but that
167+
/// might not be what the user expects and can be explicitly achieved with
168+
/// [`as_bytes()`]:
169+
///
170+
/// ```
171+
/// // The first byte is 104 - the byte value of `'h'`
172+
/// let s = "hello";
173+
/// assert_eq!(s.as_bytes()[0], 104);
174+
/// // or
175+
/// assert_eq!(s.as_bytes()[0], b'h');
176+
///
177+
/// // The first byte is 240 which isn't obviously useful
178+
/// let s = "💖💖💖💖💖";
179+
/// assert_eq!(s.as_bytes()[0], 240);
180+
/// ```
181+
///
182+
/// Due to these ambiguities/restrictions, indexing with a `usize` is simply
183+
/// forbidden:
124184
///
125185
/// ```compile_fail,E0277
126186
/// let s = "hello";
127187
///
128-
/// println!("The first letter of s is {}", s[0]); // ERROR!!!
188+
/// // The following will not compile!
189+
/// println!("The first letter of s is {}", s[0]);
129190
/// ```
130191
///
192+
/// It is more clear, however, how `&s[i..j]` should work (that is,
193+
/// indexing with a range). It should accept byte indices (to be constant-time)
194+
/// and return a `&str` which is UTF-8 encoded. This is also called "string slicing".
195+
/// Note this will panic if the byte indices provided are not character
196+
/// boundaries - see [`is_char_boundary`] for more details. See the implementations
197+
/// for [`SliceIndex<str>`] for more details on string slicing. For a non-panicking
198+
/// version of string slicing, see [`get`].
199+
///
131200
/// [`OsString`]: ../../std/ffi/struct.OsString.html "ffi::OsString"
201+
/// [`SliceIndex<str>`]: core::slice::SliceIndex
202+
/// [`as_bytes()`]: str::as_bytes
203+
/// [`get`]: str::get
204+
/// [`is_char_boundary`]: str::is_char_boundary
132205
///
133-
/// Indexing is intended to be a constant-time operation, but UTF-8 encoding
134-
/// does not allow us to do this. Furthermore, it's not clear what sort of
135-
/// thing the index should return: a byte, a codepoint, or a grapheme cluster.
136-
/// The [`bytes`] and [`chars`] methods return iterators over the first
137-
/// two, respectively.
206+
/// The [`bytes`] and [`chars`] methods return iterators over the bytes and
207+
/// codepoints of the string, respectively. To iterate over codepoints along
208+
/// with byte indices, use [`char_indices`].
138209
///
139210
/// [`bytes`]: str::bytes
140211
/// [`chars`]: str::chars
212+
/// [`char_indices`]: str::char_indices
141213
///
142214
/// # Deref
143215
///

‎library/core/src/alloc/layout.rs

+5-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use crate::cmp;
22
use crate::fmt;
3-
use crate::mem;
4-
use crate::num::NonZeroUsize;
3+
use crate::mem::{self, ValidAlign};
54
use crate::ptr::NonNull;
65

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

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

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

123122
/// Constructs a `Layout` suitable for holding a value of type `T`.

‎library/core/src/mem/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ mod maybe_uninit;
2121
#[stable(feature = "maybe_uninit", since = "1.36.0")]
2222
pub use maybe_uninit::MaybeUninit;
2323

24+
mod valid_align;
25+
// For now this type is left crate-local. It could potentially make sense to expose
26+
// it publicly, as it would be a nice parameter type for methods which need to take
27+
// alignment as a parameter, such as `Layout::padding_needed_for`.
28+
pub(crate) use valid_align::ValidAlign;
29+
2430
#[stable(feature = "rust1", since = "1.0.0")]
2531
#[doc(inline)]
2632
pub use crate::intrinsics::transmute;

‎library/core/src/mem/valid_align.rs

+240
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
use crate::convert::TryFrom;
2+
use crate::num::NonZeroUsize;
3+
use crate::{cmp, fmt, mem, num};
4+
5+
/// A type storing a `usize` which is a power of two, and thus
6+
/// represents a possible alignment in the rust abstract machine.
7+
///
8+
/// Note that particularly large alignments, while representable in this type,
9+
/// are likely not to be supported by actual allocators and linkers.
10+
#[derive(Copy, Clone)]
11+
#[repr(transparent)]
12+
pub(crate) struct ValidAlign(ValidAlignEnum);
13+
14+
// ValidAlign is `repr(usize)`, but via extra steps.
15+
const _: () = assert!(mem::size_of::<ValidAlign>() == mem::size_of::<usize>());
16+
const _: () = assert!(mem::align_of::<ValidAlign>() == mem::align_of::<usize>());
17+
18+
impl ValidAlign {
19+
/// Creates a `ValidAlign` from a power-of-two `usize`.
20+
///
21+
/// # Safety
22+
///
23+
/// `align` must be a power of two.
24+
///
25+
/// Equivalently, it must be `1 << exp` for some `exp` in `0..usize::BITS`.
26+
/// It must *not* be zero.
27+
#[inline]
28+
pub(crate) const unsafe fn new_unchecked(align: usize) -> Self {
29+
debug_assert!(align.is_power_of_two());
30+
31+
// SAFETY: By precondition, this must be a power of two, and
32+
// our variants encompass all possible powers of two.
33+
unsafe { mem::transmute::<usize, ValidAlign>(align) }
34+
}
35+
36+
#[inline]
37+
pub(crate) const fn as_nonzero(self) -> NonZeroUsize {
38+
// SAFETY: All the discriminants are non-zero.
39+
unsafe { NonZeroUsize::new_unchecked(self.0 as usize) }
40+
}
41+
42+
/// Returns the base 2 logarithm of the alignment.
43+
///
44+
/// This is always exact, as `self` represents a power of two.
45+
#[inline]
46+
pub(crate) fn log2(self) -> u32 {
47+
self.as_nonzero().trailing_zeros()
48+
}
49+
}
50+
51+
impl fmt::Debug for ValidAlign {
52+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53+
write!(f, "{:?} (1 << {:?})", self.as_nonzero(), self.log2())
54+
}
55+
}
56+
57+
impl TryFrom<NonZeroUsize> for ValidAlign {
58+
type Error = num::TryFromIntError;
59+
60+
#[inline]
61+
fn try_from(align: NonZeroUsize) -> Result<ValidAlign, Self::Error> {
62+
if align.is_power_of_two() {
63+
// SAFETY: Just checked for power-of-two
64+
unsafe { Ok(ValidAlign::new_unchecked(align.get())) }
65+
} else {
66+
Err(num::TryFromIntError(()))
67+
}
68+
}
69+
}
70+
71+
impl TryFrom<usize> for ValidAlign {
72+
type Error = num::TryFromIntError;
73+
74+
#[inline]
75+
fn try_from(align: usize) -> Result<ValidAlign, Self::Error> {
76+
if align.is_power_of_two() {
77+
// SAFETY: Just checked for power-of-two
78+
unsafe { Ok(ValidAlign::new_unchecked(align)) }
79+
} else {
80+
Err(num::TryFromIntError(()))
81+
}
82+
}
83+
}
84+
85+
impl cmp::Eq for ValidAlign {}
86+
87+
impl cmp::PartialEq for ValidAlign {
88+
#[inline]
89+
fn eq(&self, other: &Self) -> bool {
90+
self.as_nonzero() == other.as_nonzero()
91+
}
92+
}
93+
94+
impl cmp::Ord for ValidAlign {
95+
#[inline]
96+
fn cmp(&self, other: &Self) -> cmp::Ordering {
97+
self.as_nonzero().cmp(&other.as_nonzero())
98+
}
99+
}
100+
101+
impl cmp::PartialOrd for ValidAlign {
102+
#[inline]
103+
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
104+
Some(self.cmp(other))
105+
}
106+
}
107+
108+
#[cfg(target_pointer_width = "16")]
109+
type ValidAlignEnum = ValidAlignEnum16;
110+
#[cfg(target_pointer_width = "32")]
111+
type ValidAlignEnum = ValidAlignEnum32;
112+
#[cfg(target_pointer_width = "64")]
113+
type ValidAlignEnum = ValidAlignEnum64;
114+
115+
#[derive(Copy, Clone)]
116+
#[repr(u16)]
117+
enum ValidAlignEnum16 {
118+
_Align1Shl0 = 1 << 0,
119+
_Align1Shl1 = 1 << 1,
120+
_Align1Shl2 = 1 << 2,
121+
_Align1Shl3 = 1 << 3,
122+
_Align1Shl4 = 1 << 4,
123+
_Align1Shl5 = 1 << 5,
124+
_Align1Shl6 = 1 << 6,
125+
_Align1Shl7 = 1 << 7,
126+
_Align1Shl8 = 1 << 8,
127+
_Align1Shl9 = 1 << 9,
128+
_Align1Shl10 = 1 << 10,
129+
_Align1Shl11 = 1 << 11,
130+
_Align1Shl12 = 1 << 12,
131+
_Align1Shl13 = 1 << 13,
132+
_Align1Shl14 = 1 << 14,
133+
_Align1Shl15 = 1 << 15,
134+
}
135+
136+
#[derive(Copy, Clone)]
137+
#[repr(u32)]
138+
enum ValidAlignEnum32 {
139+
_Align1Shl0 = 1 << 0,
140+
_Align1Shl1 = 1 << 1,
141+
_Align1Shl2 = 1 << 2,
142+
_Align1Shl3 = 1 << 3,
143+
_Align1Shl4 = 1 << 4,
144+
_Align1Shl5 = 1 << 5,
145+
_Align1Shl6 = 1 << 6,
146+
_Align1Shl7 = 1 << 7,
147+
_Align1Shl8 = 1 << 8,
148+
_Align1Shl9 = 1 << 9,
149+
_Align1Shl10 = 1 << 10,
150+
_Align1Shl11 = 1 << 11,
151+
_Align1Shl12 = 1 << 12,
152+
_Align1Shl13 = 1 << 13,
153+
_Align1Shl14 = 1 << 14,
154+
_Align1Shl15 = 1 << 15,
155+
_Align1Shl16 = 1 << 16,
156+
_Align1Shl17 = 1 << 17,
157+
_Align1Shl18 = 1 << 18,
158+
_Align1Shl19 = 1 << 19,
159+
_Align1Shl20 = 1 << 20,
160+
_Align1Shl21 = 1 << 21,
161+
_Align1Shl22 = 1 << 22,
162+
_Align1Shl23 = 1 << 23,
163+
_Align1Shl24 = 1 << 24,
164+
_Align1Shl25 = 1 << 25,
165+
_Align1Shl26 = 1 << 26,
166+
_Align1Shl27 = 1 << 27,
167+
_Align1Shl28 = 1 << 28,
168+
_Align1Shl29 = 1 << 29,
169+
_Align1Shl30 = 1 << 30,
170+
_Align1Shl31 = 1 << 31,
171+
}
172+
173+
#[derive(Copy, Clone)]
174+
#[repr(u64)]
175+
enum ValidAlignEnum64 {
176+
_Align1Shl0 = 1 << 0,
177+
_Align1Shl1 = 1 << 1,
178+
_Align1Shl2 = 1 << 2,
179+
_Align1Shl3 = 1 << 3,
180+
_Align1Shl4 = 1 << 4,
181+
_Align1Shl5 = 1 << 5,
182+
_Align1Shl6 = 1 << 6,
183+
_Align1Shl7 = 1 << 7,
184+
_Align1Shl8 = 1 << 8,
185+
_Align1Shl9 = 1 << 9,
186+
_Align1Shl10 = 1 << 10,
187+
_Align1Shl11 = 1 << 11,
188+
_Align1Shl12 = 1 << 12,
189+
_Align1Shl13 = 1 << 13,
190+
_Align1Shl14 = 1 << 14,
191+
_Align1Shl15 = 1 << 15,
192+
_Align1Shl16 = 1 << 16,
193+
_Align1Shl17 = 1 << 17,
194+
_Align1Shl18 = 1 << 18,
195+
_Align1Shl19 = 1 << 19,
196+
_Align1Shl20 = 1 << 20,
197+
_Align1Shl21 = 1 << 21,
198+
_Align1Shl22 = 1 << 22,
199+
_Align1Shl23 = 1 << 23,
200+
_Align1Shl24 = 1 << 24,
201+
_Align1Shl25 = 1 << 25,
202+
_Align1Shl26 = 1 << 26,
203+
_Align1Shl27 = 1 << 27,
204+
_Align1Shl28 = 1 << 28,
205+
_Align1Shl29 = 1 << 29,
206+
_Align1Shl30 = 1 << 30,
207+
_Align1Shl31 = 1 << 31,
208+
_Align1Shl32 = 1 << 32,
209+
_Align1Shl33 = 1 << 33,
210+
_Align1Shl34 = 1 << 34,
211+
_Align1Shl35 = 1 << 35,
212+
_Align1Shl36 = 1 << 36,
213+
_Align1Shl37 = 1 << 37,
214+
_Align1Shl38 = 1 << 38,
215+
_Align1Shl39 = 1 << 39,
216+
_Align1Shl40 = 1 << 40,
217+
_Align1Shl41 = 1 << 41,
218+
_Align1Shl42 = 1 << 42,
219+
_Align1Shl43 = 1 << 43,
220+
_Align1Shl44 = 1 << 44,
221+
_Align1Shl45 = 1 << 45,
222+
_Align1Shl46 = 1 << 46,
223+
_Align1Shl47 = 1 << 47,
224+
_Align1Shl48 = 1 << 48,
225+
_Align1Shl49 = 1 << 49,
226+
_Align1Shl50 = 1 << 50,
227+
_Align1Shl51 = 1 << 51,
228+
_Align1Shl52 = 1 << 52,
229+
_Align1Shl53 = 1 << 53,
230+
_Align1Shl54 = 1 << 54,
231+
_Align1Shl55 = 1 << 55,
232+
_Align1Shl56 = 1 << 56,
233+
_Align1Shl57 = 1 << 57,
234+
_Align1Shl58 = 1 << 58,
235+
_Align1Shl59 = 1 << 59,
236+
_Align1Shl60 = 1 << 60,
237+
_Align1Shl61 = 1 << 61,
238+
_Align1Shl62 = 1 << 62,
239+
_Align1Shl63 = 1 << 63,
240+
}

‎library/core/src/num/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -299,8 +299,8 @@ impl u8 {
299299
#[rustc_const_stable(feature = "const_ascii_methods_on_intrinsics", since = "1.52.0")]
300300
#[inline]
301301
pub const fn to_ascii_uppercase(&self) -> u8 {
302-
// Unset the fifth bit if this is a lowercase letter
303-
*self & !((self.is_ascii_lowercase() as u8) * ASCII_CASE_MASK)
302+
// Toggle the fifth bit if this is a lowercase letter
303+
*self ^ ((self.is_ascii_lowercase() as u8) * ASCII_CASE_MASK)
304304
}
305305

306306
/// Makes a copy of the value in its ASCII lower case equivalent.

‎library/core/src/tuple.rs

+13-13
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::cmp::*;
55

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

108108
tuple_impls! {
109-
Tuple1(A)
110-
Tuple2(A B)
111-
Tuple3(A B C)
112-
Tuple4(A B C D)
113-
Tuple5(A B C D E)
114-
Tuple6(A B C D E F)
115-
Tuple7(A B C D E F G)
116-
Tuple8(A B C D E F G H)
117-
Tuple9(A B C D E F G H I)
118-
Tuple10(A B C D E F G H I J)
119-
Tuple11(A B C D E F G H I J K)
120-
Tuple12(A B C D E F G H I J K L)
109+
(A)
110+
(A B)
111+
(A B C)
112+
(A B C D)
113+
(A B C D E)
114+
(A B C D E F)
115+
(A B C D E F G)
116+
(A B C D E F G H)
117+
(A B C D E F G H I)
118+
(A B C D E F G H I J)
119+
(A B C D E F G H I J K)
120+
(A B C D E F G H I J K L)
121121
}

‎library/core/tests/alloc.rs

+18
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,21 @@ fn const_unchecked_layout() {
1111
assert_eq!(LAYOUT.align(), ALIGN);
1212
assert_eq!(Some(DANGLING), NonNull::new(ALIGN as *mut u8));
1313
}
14+
15+
#[test]
16+
fn layout_debug_shows_log2_of_alignment() {
17+
// `Debug` is not stable, but here's what it does right now
18+
let layout = Layout::from_size_align(24576, 8192).unwrap();
19+
let s = format!("{:?}", layout);
20+
assert_eq!(s, "Layout { size_: 24576, align_: 8192 (1 << 13) }");
21+
}
22+
23+
// Running this normally doesn't do much, but it's also run in Miri, which
24+
// will double-check that these are allowed by the validity invariants.
25+
#[test]
26+
fn layout_accepts_all_valid_alignments() {
27+
for align in 0..usize::BITS {
28+
let layout = Layout::from_size_align(0, 1_usize << align).unwrap();
29+
assert_eq!(layout.align(), 1_usize << align);
30+
}
31+
}

‎src/bootstrap/test.rs

+29-6
Original file line numberDiff line numberDiff line change
@@ -2065,6 +2065,7 @@ impl Step for Crate {
20652065
}
20662066
}
20672067

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

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

21022107
let mut cargo = tool::prepare_tool_cargo(
@@ -2112,6 +2117,15 @@ impl Step for CrateRustdoc {
21122117
if test_kind.subcommand() == "test" && !builder.fail_fast {
21132118
cargo.arg("--no-fail-fast");
21142119
}
2120+
match builder.doc_tests {
2121+
DocTests::Only => {
2122+
cargo.arg("--doc");
2123+
}
2124+
DocTests::No => {
2125+
cargo.args(&["--lib", "--bins", "--examples", "--tests", "--benches"]);
2126+
}
2127+
DocTests::Yes => {}
2128+
}
21152129

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

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

21512174
if !builder.config.verbose_tests {
+15-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,25 @@
11
error[E0080]: it is undefined behavior to use this value
2-
--> $DIR/alloc.rs:8:1
2+
--> $DIR/alloc.rs:9:1
33
|
4-
LL | const LAYOUT_INVALID: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) };
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align_: encountered 0, but expected something greater or equal to 1
4+
LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) };
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align_.0.<enum-tag>: encountered 0x00000000, but expected a valid enum tag
66
|
77
= 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.
88
= note: the raw bytes of the constant (size: 8, align: 4) {
99
00 10 00 00 00 00 00 00 │ ........
1010
}
1111

12-
error: aborting due to previous error
12+
error[E0080]: it is undefined behavior to use this value
13+
--> $DIR/alloc.rs:13:1
14+
|
15+
LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) };
16+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align_.0.<enum-tag>: encountered 0x00000003, but expected a valid enum tag
17+
|
18+
= 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.
19+
= note: the raw bytes of the constant (size: 8, align: 4) {
20+
09 00 00 00 03 00 00 00 │ ........
21+
}
22+
23+
error: aborting due to 2 previous errors
1324

1425
For more information about this error, try `rustc --explain E0080`.
+15-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,25 @@
11
error[E0080]: it is undefined behavior to use this value
2-
--> $DIR/alloc.rs:8:1
2+
--> $DIR/alloc.rs:9:1
33
|
4-
LL | const LAYOUT_INVALID: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) };
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align_: encountered 0, but expected something greater or equal to 1
4+
LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) };
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align_.0.<enum-tag>: encountered 0x0000000000000000, but expected a valid enum tag
66
|
77
= 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.
88
= note: the raw bytes of the constant (size: 16, align: 8) {
99
00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
1010
}
1111

12-
error: aborting due to previous error
12+
error[E0080]: it is undefined behavior to use this value
13+
--> $DIR/alloc.rs:13:1
14+
|
15+
LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) };
16+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align_.0.<enum-tag>: encountered 0x0000000000000003, but expected a valid enum tag
17+
|
18+
= 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.
19+
= note: the raw bytes of the constant (size: 16, align: 8) {
20+
09 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 │ ................
21+
}
22+
23+
error: aborting due to 2 previous errors
1324

1425
For more information about this error, try `rustc --explain E0080`.

‎src/test/ui/consts/std/alloc.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
// stderr-per-bitwidth
2+
// ignore-debug (the debug assertions change the error)
23
use std::alloc::Layout;
34

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

78
// not ok, since alignment needs to be non-zero.
8-
const LAYOUT_INVALID: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) };
9+
const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) };
10+
//~^ ERROR it is undefined behavior to use this value
11+
12+
// not ok, since alignment needs to be a power of two.
13+
const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) };
914
//~^ ERROR it is undefined behavior to use this value
1015

1116
fn main() {}

‎src/test/ui/macros/macro-match-nonterminal.rs

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ macro_rules! test {
22
($a, $b) => {
33
//~^ ERROR missing fragment
44
//~| ERROR missing fragment
5+
//~| ERROR missing fragment
6+
//~| WARN this was previously accepted
57
//~| WARN this was previously accepted
68
()
79
};

‎src/test/ui/macros/macro-match-nonterminal.stderr

+11-2
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,24 @@ error: missing fragment specifier
44
LL | ($a, $b) => {
55
| ^
66

7+
error: missing fragment specifier
8+
--> $DIR/macro-match-nonterminal.rs:2:8
9+
|
10+
LL | ($a, $b) => {
11+
| ^
12+
|
13+
= note: `#[deny(missing_fragment_specifier)]` on by default
14+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
15+
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
16+
717
error: missing fragment specifier
818
--> $DIR/macro-match-nonterminal.rs:2:10
919
|
1020
LL | ($a, $b) => {
1121
| ^^
1222
|
13-
= note: `#[deny(missing_fragment_specifier)]` on by default
1423
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
1524
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
1625

17-
error: aborting due to 2 previous errors
26+
error: aborting due to 3 previous errors
1827

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// compile-flags: -Zdeduplicate-diagnostics=yes
2+
3+
macro_rules! m {
4+
($name) => {}
5+
//~^ ERROR missing fragment
6+
//~| ERROR missing fragment
7+
//~| WARN this was previously accepted
8+
}
9+
10+
fn main() {
11+
m!();
12+
m!();
13+
m!();
14+
m!();
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error: missing fragment specifier
2+
--> $DIR/macro-missing-fragment-deduplication.rs:4:6
3+
|
4+
LL | ($name) => {}
5+
| ^^^^^
6+
7+
error: missing fragment specifier
8+
--> $DIR/macro-missing-fragment-deduplication.rs:4:6
9+
|
10+
LL | ($name) => {}
11+
| ^^^^^
12+
|
13+
= note: `#[deny(missing_fragment_specifier)]` on by default
14+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
15+
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
16+
17+
error: aborting due to 2 previous errors
18+
+22-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,26 @@
1-
macro_rules! m {
2-
( $( any_token $field_rust_type )* ) => {}; //~ ERROR missing fragment
1+
#![warn(missing_fragment_specifier)]
2+
3+
macro_rules! used_arm {
4+
( $( any_token $field_rust_type )* ) => {};
5+
//~^ ERROR missing fragment
6+
//~| WARN missing fragment
7+
//~| WARN this was previously accepted
8+
}
9+
10+
macro_rules! used_macro_unused_arm {
11+
() => {};
12+
( $name ) => {};
13+
//~^ WARN missing fragment
14+
//~| WARN this was previously accepted
15+
}
16+
17+
macro_rules! unused_macro {
18+
( $name ) => {};
19+
//~^ WARN missing fragment
20+
//~| WARN this was previously accepted
321
}
422

523
fn main() {
6-
m!();
24+
used_arm!();
25+
used_macro_unused_arm!();
726
}
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,40 @@
11
error: missing fragment specifier
2-
--> $DIR/macro-missing-fragment.rs:2:20
2+
--> $DIR/macro-missing-fragment.rs:4:20
33
|
44
LL | ( $( any_token $field_rust_type )* ) => {};
55
| ^^^^^^^^^^^^^^^^
66

7-
error: aborting due to previous error
7+
warning: missing fragment specifier
8+
--> $DIR/macro-missing-fragment.rs:4:20
9+
|
10+
LL | ( $( any_token $field_rust_type )* ) => {};
11+
| ^^^^^^^^^^^^^^^^
12+
|
13+
note: the lint level is defined here
14+
--> $DIR/macro-missing-fragment.rs:1:9
15+
|
16+
LL | #![warn(missing_fragment_specifier)]
17+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
18+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
19+
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
20+
21+
warning: missing fragment specifier
22+
--> $DIR/macro-missing-fragment.rs:12:7
23+
|
24+
LL | ( $name ) => {};
25+
| ^^^^^
26+
|
27+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
28+
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
29+
30+
warning: missing fragment specifier
31+
--> $DIR/macro-missing-fragment.rs:18:7
32+
|
33+
LL | ( $name ) => {};
34+
| ^^^^^
35+
|
36+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
37+
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
38+
39+
error: aborting due to previous error; 3 warnings emitted
840

‎src/test/ui/parser/macro/issue-33569.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
macro_rules! foo {
22
{ $+ } => { //~ ERROR expected identifier, found `+`
33
//~^ ERROR missing fragment specifier
4+
//~| ERROR missing fragment specifier
5+
//~| WARN this was previously accepted
46
$(x)(y) //~ ERROR expected one of: `*`, `+`, or `?`
57
}
68
}

‎src/test/ui/parser/macro/issue-33569.stderr

+12-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | { $+ } => {
55
| ^
66

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

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

0 commit comments

Comments
 (0)
Please sign in to comment.