Auto merge of #127706 - workingjubilee:rollup-d07ij30, r=workingjubilee

Rollup of 6 pull requests

Successful merges:

 - #122300 (Add FileCheck annotations to mir-opt/dest-prop tests)
 - #127434 (use "bootstrap" instead of "rustbuild" in comments and docs)
 - #127477 (Clear `inner_attr_ranges` regularly.)
 - #127558 (More attribute cleanups)
 - #127659 (Use ManuallyDrop in BufWriter::into_parts)
 - #127671 (rustdoc: rename `issue-\d+.rs` tests to have meaningful names (part 8))

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-07-14 05:41:24 +00:00
commit 8a63c84af5
62 changed files with 302 additions and 240 deletions

View File

@ -215,7 +215,7 @@ python x.py build
Right now, building Rust only works with some known versions of Visual Studio.
If you have a more recent version installed and the build system doesn't
understand, you may need to force rustbuild to use an older version.
understand, you may need to force bootstrap to use an older version.
This can be done by manually calling the appropriate vcvars file before running
the bootstrap.

View File

@ -202,21 +202,18 @@ impl Attribute {
}
}
// Named `get_tokens` to distinguish it from the `<Attribute as HasTokens>::tokens` method.
pub fn get_tokens(&self) -> TokenStream {
match &self.kind {
AttrKind::Normal(normal) => TokenStream::new(
normal
.tokens
.as_ref()
.unwrap_or_else(|| panic!("attribute is missing tokens: {self:?}"))
.to_attr_token_stream()
.to_token_trees(),
),
&AttrKind::DocComment(comment_kind, data) => TokenStream::token_alone(
pub fn token_trees(&self) -> Vec<TokenTree> {
match self.kind {
AttrKind::Normal(ref normal) => normal
.tokens
.as_ref()
.unwrap_or_else(|| panic!("attribute is missing tokens: {self:?}"))
.to_attr_token_stream()
.to_token_trees(),
AttrKind::DocComment(comment_kind, data) => vec![TokenTree::token_alone(
token::DocComment(comment_kind, self.style, data),
self.span,
),
)],
}
}
}

View File

@ -16,7 +16,7 @@
use crate::ast::{AttrStyle, StmtKind};
use crate::ast_traits::{HasAttrs, HasTokens};
use crate::token::{self, Delimiter, Nonterminal, Token, TokenKind};
use crate::AttrVec;
use crate::{AttrVec, Attribute};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::{self, Lrc};
@ -179,11 +179,10 @@ impl AttrTokenStream {
AttrTokenStream(Lrc::new(tokens))
}
/// Converts this `AttrTokenStream` to a plain `Vec<TokenTree>`.
/// During conversion, `AttrTokenTree::AttrsTarget` get 'flattened'
/// back to a `TokenStream` of the form `outer_attr attr_target`.
/// If there are inner attributes, they are inserted into the proper
/// place in the attribute target tokens.
/// Converts this `AttrTokenStream` to a plain `Vec<TokenTree>`. During
/// conversion, any `AttrTokenTree::AttrsTarget` gets "flattened" back to a
/// `TokenStream`, as described in the comment on
/// `attrs_and_tokens_to_token_trees`.
pub fn to_token_trees(&self) -> Vec<TokenTree> {
let mut res = Vec::with_capacity(self.0.len());
for tree in self.0.iter() {
@ -200,51 +199,7 @@ impl AttrTokenStream {
))
}
AttrTokenTree::AttrsTarget(target) => {
let idx = target
.attrs
.partition_point(|attr| matches!(attr.style, crate::AttrStyle::Outer));
let (outer_attrs, inner_attrs) = target.attrs.split_at(idx);
let mut target_tokens = target.tokens.to_attr_token_stream().to_token_trees();
if !inner_attrs.is_empty() {
let mut found = false;
// Check the last two trees (to account for a trailing semi)
for tree in target_tokens.iter_mut().rev().take(2) {
if let TokenTree::Delimited(span, spacing, delim, delim_tokens) = tree {
// Inner attributes are only supported on extern blocks, functions,
// impls, and modules. All of these have their inner attributes
// placed at the beginning of the rightmost outermost braced group:
// e.g. fn foo() { #![my_attr] }
//
// Therefore, we can insert them back into the right location
// without needing to do any extra position tracking.
//
// Note: Outline modules are an exception - they can
// have attributes like `#![my_attr]` at the start of a file.
// Support for custom attributes in this position is not
// properly implemented - we always synthesize fake tokens,
// so we never reach this code.
let mut stream = TokenStream::default();
for inner_attr in inner_attrs {
stream.push_stream(inner_attr.get_tokens());
}
stream.push_stream(delim_tokens.clone());
*tree = TokenTree::Delimited(*span, *spacing, *delim, stream);
found = true;
break;
}
}
assert!(
found,
"Failed to find trailing delimited group in: {target_tokens:?}"
);
}
for attr in outer_attrs {
res.extend(attr.get_tokens().0.iter().cloned());
}
res.extend(target_tokens);
attrs_and_tokens_to_token_trees(&target.attrs, &target.tokens, &mut res);
}
}
}
@ -252,15 +207,76 @@ impl AttrTokenStream {
}
}
// Converts multiple attributes and the tokens for a target AST node into token trees, and appends
// them to `res`.
//
// Example: if the AST node is "fn f() { blah(); }", then:
// - Simple if no attributes are present, e.g. "fn f() { blah(); }"
// - Simple if only outer attribute are present, e.g. "#[outer1] #[outer2] fn f() { blah(); }"
// - Trickier if inner attributes are present, because they must be moved within the AST node's
// tokens, e.g. "#[outer] fn f() { #![inner] blah() }"
fn attrs_and_tokens_to_token_trees(
attrs: &[Attribute],
target_tokens: &LazyAttrTokenStream,
res: &mut Vec<TokenTree>,
) {
let idx = attrs.partition_point(|attr| matches!(attr.style, crate::AttrStyle::Outer));
let (outer_attrs, inner_attrs) = attrs.split_at(idx);
// Add outer attribute tokens.
for attr in outer_attrs {
res.extend(attr.token_trees());
}
// Add target AST node tokens.
res.extend(target_tokens.to_attr_token_stream().to_token_trees());
// Insert inner attribute tokens.
if !inner_attrs.is_empty() {
let mut found = false;
// Check the last two trees (to account for a trailing semi)
for tree in res.iter_mut().rev().take(2) {
if let TokenTree::Delimited(span, spacing, delim, delim_tokens) = tree {
// Inner attributes are only supported on extern blocks, functions,
// impls, and modules. All of these have their inner attributes
// placed at the beginning of the rightmost outermost braced group:
// e.g. fn foo() { #![my_attr] }
//
// Therefore, we can insert them back into the right location
// without needing to do any extra position tracking.
//
// Note: Outline modules are an exception - they can
// have attributes like `#![my_attr]` at the start of a file.
// Support for custom attributes in this position is not
// properly implemented - we always synthesize fake tokens,
// so we never reach this code.
let mut tts = vec![];
for inner_attr in inner_attrs {
tts.extend(inner_attr.token_trees());
}
tts.extend(delim_tokens.0.iter().cloned());
let stream = TokenStream::new(tts);
*tree = TokenTree::Delimited(*span, *spacing, *delim, stream);
found = true;
break;
}
}
assert!(found, "Failed to find trailing delimited group in: {res:?}");
}
}
/// Stores the tokens for an attribute target, along
/// with its attributes.
///
/// This is constructed during parsing when we need to capture
/// tokens.
/// tokens, for `cfg` and `cfg_attr` attributes.
///
/// For example, `#[cfg(FALSE)] struct Foo {}` would
/// have an `attrs` field containing the `#[cfg(FALSE)]` attr,
/// and a `tokens` field storing the (unparsed) tokens `struct Foo {}`
///
/// The `cfg`/`cfg_attr` processing occurs in
/// `StripUnconfigured::configure_tokens`.
#[derive(Clone, Debug, Encodable, Decodable)]
pub struct AttrsTarget {
/// Attributes, both outer and inner.
@ -437,18 +453,10 @@ impl TokenStream {
}
pub fn from_ast(node: &(impl HasAttrs + HasTokens + fmt::Debug)) -> TokenStream {
let Some(tokens) = node.tokens() else {
panic!("missing tokens for node: {:?}", node);
};
let attrs = node.attrs();
let attr_stream = if attrs.is_empty() {
tokens.to_attr_token_stream()
} else {
let target =
AttrsTarget { attrs: attrs.iter().cloned().collect(), tokens: tokens.clone() };
AttrTokenStream::new(vec![AttrTokenTree::AttrsTarget(target)])
};
TokenStream::new(attr_stream.to_token_trees())
let tokens = node.tokens().unwrap_or_else(|| panic!("missing tokens for node: {:?}", node));
let mut tts = vec![];
attrs_and_tokens_to_token_trees(node.attrs(), tokens, &mut tts);
TokenStream::new(tts)
}
pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream {

View File

@ -398,7 +398,7 @@ impl<'a> GccLinker<'a> {
self.link_arg("-dylib");
// Note that the `osx_rpath_install_name` option here is a hack
// purely to support rustbuild right now, we should get a more
// purely to support bootstrap right now, we should get a more
// principled solution at some point to force the compiler to pass
// the right `-Wl,-install_name` with an `@rpath` in it.
if self.sess.opts.cg.rpath || self.sess.opts.unstable_opts.osx_rpath_install_name {

View File

@ -187,6 +187,7 @@ impl<'a> StripUnconfigured<'a> {
.iter()
.filter_map(|tree| match tree.clone() {
AttrTokenTree::AttrsTarget(mut target) => {
// Expand any `cfg_attr` attributes.
target.attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr));
if self.in_cfg(&target.attrs) {
@ -195,6 +196,8 @@ impl<'a> StripUnconfigured<'a> {
);
Some(AttrTokenTree::AttrsTarget(target))
} else {
// Remove the target if there's a `cfg` attribute and
// the condition isn't satisfied.
None
}
}
@ -253,9 +256,9 @@ impl<'a> StripUnconfigured<'a> {
/// Gives a compiler warning when the `cfg_attr` contains no attributes and
/// is in the original source file. Gives a compiler error if the syntax of
/// the attribute is incorrect.
pub(crate) fn expand_cfg_attr(&self, attr: &Attribute, recursive: bool) -> Vec<Attribute> {
pub(crate) fn expand_cfg_attr(&self, cfg_attr: &Attribute, recursive: bool) -> Vec<Attribute> {
let Some((cfg_predicate, expanded_attrs)) =
rustc_parse::parse_cfg_attr(attr, &self.sess.psess)
rustc_parse::parse_cfg_attr(cfg_attr, &self.sess.psess)
else {
return vec![];
};
@ -264,7 +267,7 @@ impl<'a> StripUnconfigured<'a> {
if expanded_attrs.is_empty() {
self.sess.psess.buffer_lint(
rustc_lint_defs::builtin::UNUSED_ATTRIBUTES,
attr.span,
cfg_attr.span,
ast::CRATE_NODE_ID,
BuiltinLintDiag::CfgAttrNoAttributes,
);
@ -280,20 +283,21 @@ impl<'a> StripUnconfigured<'a> {
// `#[cfg_attr(false, cfg_attr(true, some_attr))]`.
expanded_attrs
.into_iter()
.flat_map(|item| self.process_cfg_attr(&self.expand_cfg_attr_item(attr, item)))
.flat_map(|item| self.process_cfg_attr(&self.expand_cfg_attr_item(cfg_attr, item)))
.collect()
} else {
expanded_attrs.into_iter().map(|item| self.expand_cfg_attr_item(attr, item)).collect()
expanded_attrs
.into_iter()
.map(|item| self.expand_cfg_attr_item(cfg_attr, item))
.collect()
}
}
fn expand_cfg_attr_item(
&self,
attr: &Attribute,
cfg_attr: &Attribute,
(item, item_span): (ast::AttrItem, Span),
) -> Attribute {
let orig_tokens = attr.get_tokens();
// We are taking an attribute of the form `#[cfg_attr(pred, attr)]`
// and producing an attribute of the form `#[attr]`. We
// have captured tokens for `attr` itself, but we need to
@ -302,11 +306,11 @@ impl<'a> StripUnconfigured<'a> {
// Use the `#` in `#[cfg_attr(pred, attr)]` as the `#` token
// for `attr` when we expand it to `#[attr]`
let mut orig_trees = orig_tokens.trees();
let mut orig_trees = cfg_attr.token_trees().into_iter();
let TokenTree::Token(pound_token @ Token { kind: TokenKind::Pound, .. }, _) =
orig_trees.next().unwrap().clone()
else {
panic!("Bad tokens for attribute {attr:?}");
panic!("Bad tokens for attribute {cfg_attr:?}");
};
// We don't really have a good span to use for the synthesized `[]`
@ -320,12 +324,12 @@ impl<'a> StripUnconfigured<'a> {
.unwrap_or_else(|| panic!("Missing tokens for {item:?}"))
.to_attr_token_stream(),
);
let trees = if attr.style == AttrStyle::Inner {
let trees = if cfg_attr.style == AttrStyle::Inner {
// For inner attributes, we do the same thing for the `!` in `#![some_attr]`
let TokenTree::Token(bang_token @ Token { kind: TokenKind::Not, .. }, _) =
orig_trees.next().unwrap().clone()
else {
panic!("Bad tokens for attribute {attr:?}");
panic!("Bad tokens for attribute {cfg_attr:?}");
};
vec![
AttrTokenTree::Token(pound_token, Spacing::Joint),
@ -340,7 +344,7 @@ impl<'a> StripUnconfigured<'a> {
&self.sess.psess.attr_id_generator,
item,
tokens,
attr.style,
cfg_attr.style,
item_span,
);
if attr.has_name(sym::crate_type) {

View File

@ -157,14 +157,14 @@ pub fn fake_token_stream_for_crate(psess: &ParseSess, krate: &ast::Crate) -> Tok
}
pub fn parse_cfg_attr(
attr: &Attribute,
cfg_attr: &Attribute,
psess: &ParseSess,
) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> {
const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]";
const CFG_ATTR_NOTE_REF: &str = "for more information, visit \
<https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>";
match attr.get_normal_item().args {
match cfg_attr.get_normal_item().args {
ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, ref tokens })
if !tokens.is_empty() =>
{
@ -180,7 +180,7 @@ pub fn parse_cfg_attr(
}
_ => {
psess.dcx().emit_err(errors::MalformedCfgAttr {
span: attr.span,
span: cfg_attr.span,
sugg: CFG_ATTR_GRAMMAR_HELP,
});
}

View File

@ -103,11 +103,8 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl {
// produce an empty `TokenStream` if no calls were made, and omit the
// final token otherwise.
let mut cursor_snapshot = self.cursor_snapshot.clone();
let tokens = iter::once((FlatToken::Token(self.start_token.0.clone()), self.start_token.1))
.chain(iter::repeat_with(|| {
let token = cursor_snapshot.next();
(FlatToken::Token(token.0), token.1)
}))
let tokens = iter::once(FlatToken::Token(self.start_token.clone()))
.chain(iter::repeat_with(|| FlatToken::Token(cursor_snapshot.next())))
.take(self.num_calls as usize);
if self.replace_ranges.is_empty() {
@ -156,11 +153,8 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl {
(range.start as usize)..(range.end as usize),
target
.into_iter()
.map(|target| (FlatToken::AttrsTarget(target), Spacing::Alone))
.chain(
iter::repeat((FlatToken::Empty, Spacing::Alone))
.take(range.len() - target_len),
),
.map(|target| FlatToken::AttrsTarget(target))
.chain(iter::repeat(FlatToken::Empty).take(range.len() - target_len)),
);
}
make_attr_token_stream(tokens.into_iter(), self.break_last_token)
@ -301,21 +295,22 @@ impl<'a> Parser<'a> {
let num_calls = end_pos - start_pos;
// If we have no attributes, then we will never need to
// use any replace ranges.
let replace_ranges: Box<[ReplaceRange]> = if ret.attrs().is_empty() && !self.capture_cfg {
Box::new([])
} else {
// Grab any replace ranges that occur *inside* the current AST node.
// We will perform the actual replacement when we convert the `LazyAttrTokenStream`
// to an `AttrTokenStream`.
self.capture_state.replace_ranges[replace_ranges_start..replace_ranges_end]
.iter()
.cloned()
.chain(inner_attr_replace_ranges.iter().cloned())
.map(|(range, data)| ((range.start - start_pos)..(range.end - start_pos), data))
.collect()
};
// This is hot enough for `deep-vector` that checking the conditions for an empty iterator
// is measurably faster than actually executing the iterator.
let replace_ranges: Box<[ReplaceRange]> =
if replace_ranges_start == replace_ranges_end && inner_attr_replace_ranges.is_empty() {
Box::new([])
} else {
// Grab any replace ranges that occur *inside* the current AST node.
// We will perform the actual replacement when we convert the `LazyAttrTokenStream`
// to an `AttrTokenStream`.
self.capture_state.replace_ranges[replace_ranges_start..replace_ranges_end]
.iter()
.cloned()
.chain(inner_attr_replace_ranges.iter().cloned())
.map(|(range, data)| ((range.start - start_pos)..(range.end - start_pos), data))
.collect()
};
let tokens = LazyAttrTokenStream::new(LazyAttrTokenStreamImpl {
start_token,
@ -325,12 +320,9 @@ impl<'a> Parser<'a> {
replace_ranges,
});
// If we support tokens at all
if let Some(target_tokens) = ret.tokens_mut() {
if target_tokens.is_none() {
// Store our newly captured tokens into the AST node.
*target_tokens = Some(tokens.clone());
}
// If we support tokens and don't already have them, store the newly captured tokens.
if let Some(target_tokens @ None) = ret.tokens_mut() {
*target_tokens = Some(tokens.clone());
}
let final_attrs = ret.attrs();
@ -352,15 +344,10 @@ impl<'a> Parser<'a> {
let target = AttrsTarget { attrs: final_attrs.iter().cloned().collect(), tokens };
self.capture_state.replace_ranges.push((start_pos..end_pos, Some(target)));
self.capture_state.replace_ranges.extend(inner_attr_replace_ranges);
}
// Only clear our `replace_ranges` when we're finished capturing entirely.
if matches!(self.capture_state.capturing, Capturing::No) {
} else if matches!(self.capture_state.capturing, Capturing::No) {
// Only clear the ranges once we've finished capturing entirely.
self.capture_state.replace_ranges.clear();
// We don't clear `inner_attr_ranges`, as doing so repeatedly
// had a measurable performance impact. Most inner attributes that
// we insert will get removed - when we drop the parser, we'll free
// up the memory used by any attributes that we didn't remove from the map.
self.capture_state.inner_attr_ranges.clear();
}
Ok(ret)
}
@ -370,7 +357,7 @@ impl<'a> Parser<'a> {
/// `AttrTokenStream`, creating an `AttrTokenTree::Delimited` for each matching pair of open and
/// close delims.
fn make_attr_token_stream(
mut iter: impl Iterator<Item = (FlatToken, Spacing)>,
iter: impl Iterator<Item = FlatToken>,
break_last_token: bool,
) -> AttrTokenStream {
#[derive(Debug)]
@ -379,19 +366,19 @@ fn make_attr_token_stream(
open_delim_sp: Option<(Delimiter, Span, Spacing)>,
inner: Vec<AttrTokenTree>,
}
let mut stack = vec![FrameData { open_delim_sp: None, inner: vec![] }];
let mut token_and_spacing = iter.next();
while let Some((token, spacing)) = token_and_spacing {
match token {
FlatToken::Token(Token { kind: TokenKind::OpenDelim(delim), span }) => {
stack
.push(FrameData { open_delim_sp: Some((delim, span, spacing)), inner: vec![] });
// The stack always has at least one element. Storing it separately makes for shorter code.
let mut stack_top = FrameData { open_delim_sp: None, inner: vec![] };
let mut stack_rest = vec![];
for flat_token in iter {
match flat_token {
FlatToken::Token((Token { kind: TokenKind::OpenDelim(delim), span }, spacing)) => {
stack_rest.push(mem::replace(
&mut stack_top,
FrameData { open_delim_sp: Some((delim, span, spacing)), inner: vec![] },
));
}
FlatToken::Token(Token { kind: TokenKind::CloseDelim(delim), span }) => {
let frame_data = stack
.pop()
.unwrap_or_else(|| panic!("Token stack was empty for token: {token:?}"));
FlatToken::Token((Token { kind: TokenKind::CloseDelim(delim), span }, spacing)) => {
let frame_data = mem::replace(&mut stack_top, stack_rest.pop().unwrap());
let (open_delim, open_sp, open_spacing) = frame_data.open_delim_sp.unwrap();
assert_eq!(
open_delim, delim,
@ -401,29 +388,20 @@ fn make_attr_token_stream(
let dspacing = DelimSpacing::new(open_spacing, spacing);
let stream = AttrTokenStream::new(frame_data.inner);
let delimited = AttrTokenTree::Delimited(dspan, dspacing, delim, stream);
stack
.last_mut()
.unwrap_or_else(|| panic!("Bottom token frame is missing for token: {token:?}"))
.inner
.push(delimited);
stack_top.inner.push(delimited);
}
FlatToken::Token((token, spacing)) => {
stack_top.inner.push(AttrTokenTree::Token(token, spacing))
}
FlatToken::AttrsTarget(target) => {
stack_top.inner.push(AttrTokenTree::AttrsTarget(target))
}
FlatToken::Token(token) => stack
.last_mut()
.expect("Bottom token frame is missing!")
.inner
.push(AttrTokenTree::Token(token, spacing)),
FlatToken::AttrsTarget(target) => stack
.last_mut()
.expect("Bottom token frame is missing!")
.inner
.push(AttrTokenTree::AttrsTarget(target)),
FlatToken::Empty => {}
}
token_and_spacing = iter.next();
}
let mut final_buf = stack.pop().expect("Missing final buf!");
if break_last_token {
let last_token = final_buf.inner.pop().unwrap();
let last_token = stack_top.inner.pop().unwrap();
if let AttrTokenTree::Token(last_token, spacing) = last_token {
let unglued_first = last_token.kind.break_two_token_op().unwrap().0;
@ -431,14 +409,14 @@ fn make_attr_token_stream(
let mut first_span = last_token.span.shrink_to_lo();
first_span = first_span.with_hi(first_span.lo() + rustc_span::BytePos(1));
final_buf
stack_top
.inner
.push(AttrTokenTree::Token(Token::new(unglued_first, first_span), spacing));
} else {
panic!("Unexpected last token {last_token:?}")
}
}
AttrTokenStream::new(final_buf.inner)
AttrTokenStream::new(stack_top.inner)
}
// Some types are used a lot. Make sure they don't unintentionally get bigger.

View File

@ -1603,7 +1603,7 @@ pub(crate) fn make_unclosed_delims_error(
enum FlatToken {
/// A token - this holds both delimiter (e.g. '{' and '}')
/// and non-delimiter tokens
Token(Token),
Token((Token, Spacing)),
/// Holds the `AttrsTarget` for an AST node. The `AttrsTarget` is inserted
/// directly into the constructed `AttrTokenStream` as an
/// `AttrTokenTree::AttrsTarget`.

View File

@ -2620,7 +2620,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
// This is the location used by the `rust-src` `rustup` component.
let mut candidate = sysroot.join("lib/rustlib/src/rust");
if let Ok(metadata) = candidate.symlink_metadata() {
// Replace the symlink rustbuild creates, with its destination.
// Replace the symlink bootstrap creates, with its destination.
// We could try to use `fs::canonicalize` instead, but that might
// produce unnecessarily verbose path.
if metadata.file_type().is_symlink() {

View File

@ -1,6 +1,6 @@
# Sample TOML configuration file for building Rust.
#
# To configure rustbuild, run `./configure` or `./x.py setup`.
# To configure bootstrap, run `./configure` or `./x.py setup`.
# See https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html#create-a-configtoml for more information.
#
# All options are commented out by default in this file, and they're commented
@ -109,7 +109,7 @@
# increases the size of binaries and consequently the memory required by
# each linker process.
# If set to 0, linker invocations are treated like any other job and
# controlled by rustbuild's -j parameter.
# controlled by bootstrap's -j parameter.
#link-jobs = 0
# Whether to build LLVM as a dynamically linked library (as opposed to statically linked).
@ -371,11 +371,11 @@
# Useful for modifying only the stage2 compiler without having to pass `--keep-stage 0` each time.
#local-rebuild = false
# Print out how long each rustbuild step took (mostly intended for CI and
# Print out how long each bootstrap step took (mostly intended for CI and
# tracking over time)
#print-step-timings = false
# Print out resource usage data for each rustbuild step, as defined by the Unix
# Print out resource usage data for each bootstrap step, as defined by the Unix
# struct rusage. (Note that this setting is completely unstable: the data it
# captures, what platforms it supports, the format of its associated output, and
# this setting's very existence, are all subject to change.)

View File

@ -3,7 +3,7 @@ use crate::fmt;
use crate::io::{
self, ErrorKind, IntoInnerError, IoSlice, Seek, SeekFrom, Write, DEFAULT_BUF_SIZE,
};
use crate::mem;
use crate::mem::{self, ManuallyDrop};
use crate::ptr;
/// Wraps a writer and buffers its output.
@ -164,13 +164,13 @@ impl<W: Write> BufWriter<W> {
/// assert_eq!(&buffered_data.unwrap(), b"ata");
/// ```
#[stable(feature = "bufwriter_into_parts", since = "1.56.0")]
pub fn into_parts(mut self) -> (W, Result<Vec<u8>, WriterPanicked>) {
let buf = mem::take(&mut self.buf);
let buf = if !self.panicked { Ok(buf) } else { Err(WriterPanicked { buf }) };
pub fn into_parts(self) -> (W, Result<Vec<u8>, WriterPanicked>) {
let mut this = ManuallyDrop::new(self);
let buf = mem::take(&mut this.buf);
let buf = if !this.panicked { Ok(buf) } else { Err(WriterPanicked { buf }) };
// SAFETY: forget(self) prevents double dropping inner
let inner = unsafe { ptr::read(&self.inner) };
mem::forget(self);
// SAFETY: double-drops are prevented by putting `this` in a ManuallyDrop that is never dropped
let inner = unsafe { ptr::read(&this.inner) };
(inner, buf)
}

View File

@ -1067,3 +1067,13 @@ fn bufreader_full_initialize() {
// But we initialized the whole buffer!
assert_eq!(reader.initialized(), reader.capacity());
}
/// This is a regression test for https://github.com/rust-lang/rust/issues/127584.
#[test]
fn bufwriter_aliasing() {
use crate::io::{BufWriter, Cursor};
let mut v = vec![0; 1024];
let c = Cursor::new(&mut v);
let w = BufWriter::new(Box::new(c));
let _ = w.into_parts();
}

View File

@ -1,7 +1,7 @@
# rustbuild - Bootstrapping Rust
# Bootstrapping Rust
This README is aimed at helping to explain how Rust is bootstrapped,
and some of the technical details of the build system.
and some of the technical details of the bootstrap build system.
Note that this README only covers internal information, not how to use the tool.
Please check [bootstrapping dev guide][bootstrapping-dev-guide] for further information.
@ -12,17 +12,17 @@ Please check [bootstrapping dev guide][bootstrapping-dev-guide] for further info
The build system defers most of the complicated logic of managing invocations
of rustc and rustdoc to Cargo itself. However, moving through various stages
and copying artifacts is still necessary for it to do. Each time rustbuild
and copying artifacts is still necessary for it to do. Each time bootstrap
is invoked, it will iterate through the list of predefined steps and execute
each serially in turn if it matches the paths passed or is a default rule.
For each step, rustbuild relies on the step internally being incremental and
parallel. Note, though, that the `-j` parameter to rustbuild gets forwarded
For each step, bootstrap relies on the step internally being incremental and
parallel. Note, though, that the `-j` parameter to bootstrap gets forwarded
to appropriate test harnesses and such.
## Build phases
The rustbuild build system goes through a few phases to actually build the
compiler. What actually happens when you invoke rustbuild is:
Bootstrap build system goes through a few phases to actually build the
compiler. What actually happens when you invoke bootstrap is:
1. The entry point script (`x` for unix like systems, `x.ps1` for windows systems,
`x.py` cross-platform) is run. This script is responsible for downloading the stage0
@ -151,9 +151,9 @@ build/
stage3/
```
## Extending rustbuild
## Extending bootstrap
When you use the bootstrap system, you'll call it through the entry point script
When you use bootstrap, you'll call it through the entry point script
(`x`, `x.ps1`, or `x.py`). However, most of the code lives in `src/bootstrap`.
`bootstrap` has a difficult problem: it is written in Rust, but yet it is run
before the Rust compiler is built! To work around this, there are two components

View File

@ -1038,7 +1038,7 @@ class RustBuild(object):
def check_vendored_status(self):
"""Check that vendoring is configured properly"""
# keep this consistent with the equivalent check in rustbuild:
# keep this consistent with the equivalent check in bootstrap:
# https://github.com/rust-lang/rust/blob/a8a33cf27166d3eabaffc58ed3799e054af3b0c6/src/bootstrap/lib.rs#L399-L405
if 'SUDO_USER' in os.environ and not self.use_vendored_sources:
if os.getuid() == 0:

View File

@ -20,7 +20,7 @@ all:
$(Q)$(BOOTSTRAP) doc --stage 2 $(BOOTSTRAP_ARGS)
help:
$(Q)echo 'Welcome to the rustbuild build system!'
$(Q)echo 'Welcome to bootstrap, the Rust build system!'
$(Q)echo
$(Q)echo This makefile is a thin veneer over the ./x.py script located
$(Q)echo in this directory. To get the full power of the build system

View File

@ -1,4 +1,4 @@
//! rustbuild, the Rust build system
//! bootstrap, the Rust build system
//!
//! This is the entry point for the build system used to compile the `rustc`
//! compiler. Lots of documentation can be found in the `README.md` file in the

View File

@ -1,7 +1,7 @@
//! Implementation of compiling various phases of the compiler and standard
//! library.
//!
//! This module contains some of the real meat in the rustbuild build system
//! This module contains some of the real meat in the bootstrap build system
//! which is where Cargo is used to compile the standard library, libtest, and
//! the compiler. This module is also responsible for assembling the sysroot as it
//! goes along from the output of the previous stage.
@ -818,8 +818,8 @@ pub struct Rustc {
pub compiler: Compiler,
/// Whether to build a subset of crates, rather than the whole compiler.
///
/// This should only be requested by the user, not used within rustbuild itself.
/// Using it within rustbuild can lead to confusing situation where lints are replayed
/// This should only be requested by the user, not used within bootstrap itself.
/// Using it within bootstrap can lead to confusing situation where lints are replayed
/// in two different steps.
crates: Vec<String>,
}

View File

@ -1,4 +1,4 @@
//! Documentation generation for rustbuilder.
//! Documentation generation for bootstrap.
//!
//! This module implements generation for all bits and pieces of documentation
//! for the Rust project. This notably includes suites like the rust book, the

View File

@ -3044,7 +3044,7 @@ impl Step for Bootstrap {
// https://github.com/rust-lang/rust/issues/49215
cmd.env("RUSTFLAGS", flags);
}
// rustbuild tests are racy on directory creation so just run them one at a time.
// bootstrap tests are racy on directory creation so just run them one at a time.
// Since there's not many this shouldn't be a problem.
run_cargo_test(cmd, &["--test-threads=1"], &[], "bootstrap", None, compiler, host, builder);
}

View File

@ -1627,11 +1627,11 @@ impl<'a> Builder<'a> {
}
// This tells Cargo (and in turn, rustc) to output more complete
// dependency information. Most importantly for rustbuild, this
// dependency information. Most importantly for bootstrap, this
// includes sysroot artifacts, like libstd, which means that we don't
// need to track those in rustbuild (an error prone process!). This
// need to track those in bootstrap (an error prone process!). This
// feature is currently unstable as there may be some bugs and such, but
// it represents a big improvement in rustbuild's reliability on
// it represents a big improvement in bootstrap's reliability on
// rebuilds, so we're using it here.
//
// For some additional context, see #63470 (the PR originally adding
@ -1643,7 +1643,7 @@ impl<'a> Builder<'a> {
// Restrict the allowed features so we don't depend on nightly
// accidentally.
//
// binary-dep-depinfo is used by rustbuild itself for all
// binary-dep-depinfo is used by bootstrap itself for all
// compilations.
//
// Lots of tools depend on proc_macro2 and proc-macro-error.

View File

@ -266,7 +266,7 @@ mod defaults {
// rustdoc/rustcc/std here (the user only requested a host=B build, so
// there's not really a need for us to build for target A in this case
// (since we're producing stage 1 libraries/binaries). But currently
// rustbuild is just a bit buggy here; this should be fixed though.
// bootstrap is just a bit buggy here; this should be fixed though.
assert_eq!(
first(cache.all::<compile::Std>()),
&[

View File

@ -658,8 +658,7 @@ impl Merge for TomlConfig {
}
}
// We are using a decl macro instead of a derive proc macro here to reduce the compile time of
// rustbuild.
// We are using a decl macro instead of a derive proc macro here to reduce the compile time of bootstrap.
macro_rules! define_config {
($(#[$attr:meta])* struct $name:ident {
$($field:ident: Option<$field_ty:ty> = $field_key:literal,)*
@ -704,7 +703,7 @@ macro_rules! define_config {
// The following is a trimmed version of what serde_derive generates. All parts not relevant
// for toml deserialization have been removed. This reduces the binary size and improves
// compile time of rustbuild.
// compile time of bootstrap.
impl<'de> Deserialize<'de> for $name {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where

View File

@ -1,4 +1,4 @@
//! Command-line interface of the rustbuild build system.
//! Command-line interface of the bootstrap build system.
//!
//! This module implements the command-line parsing of the build system which
//! has various flags to configure how it's run.

View File

@ -1,4 +1,4 @@
//! Sanity checking performed by rustbuild before actually executing anything.
//! Sanity checking performed by bootstrap before actually executing anything.
//!
//! This module contains the implementation of ensuring that the build
//! environment looks reasonable before progressing. This will verify that

View File

@ -1,9 +1,9 @@
//! Implementation of rustbuild, the Rust build system.
//! Implementation of bootstrap, the Rust build system.
//!
//! This module, and its descendants, are the implementation of the Rust build
//! system. Most of this build system is backed by Cargo but the outer layer
//! here serves as the ability to orchestrate calling Cargo, sequencing Cargo
//! builds, building artifacts like LLVM, etc. The goals of rustbuild are:
//! builds, building artifacts like LLVM, etc. The goals of bootstrap are:
//!
//! * To be an easily understandable, easily extensible, and maintainable build
//! system.

View File

@ -1,4 +1,4 @@
//! Various utility functions used throughout rustbuild.
//! Various utility functions used throughout bootstrap.
//!
//! Simple things like testing the various filesystem operations here and there,
//! not a lot of interesting happenings here unfortunately.

View File

@ -40,7 +40,7 @@ if isMacOS; then
# our own clang can figure out the correct include path on its own.
ciCommandSetEnv SDKROOT "$(xcrun --sdk macosx --show-sdk-path)"
# Configure `AR` specifically so rustbuild doesn't try to infer it as
# Configure `AR` specifically so bootstrap doesn't try to infer it as
# `clang-ar` by accident.
ciCommandSetEnv AR "ar"
elif isWindows && ! isKnownToBeMingwBuild; then

View File

@ -46,7 +46,7 @@ on how to setup a development and runtime environment.
As a tier 2 target, the target is built by the Rust project.
You can configure rustbuild like so:
You can configure bootstrap like so:
```toml
[build]

View File

@ -25,7 +25,7 @@ impl CiEnv {
/// If in a CI environment, forces the command to run with colors.
pub fn force_coloring_in_ci(self, cmd: &mut Command) {
if self != CiEnv::None {
// Due to use of stamp/docker, the output stream of rustbuild is not
// Due to use of stamp/docker, the output stream of bootstrap is not
// a TTY in CI, so coloring is by-default turned off.
// The explicit `TERM=xterm` environment is needed for
// `--color always` to actually work. This env var was lost when

View File

@ -37,7 +37,7 @@ impl<'a> LintExtractor<'a> {
.map_err(|e| format!("could not read {}: {}", groups_path.display(), e))?;
let new_contents =
contents.replace("{{groups-table}}", &self.make_groups_table(lints, &groups)?);
// Delete the output because rustbuild uses hard links in its copies.
// Delete the output because bootstrap uses hard links in its copies.
let _ = fs::remove_file(&groups_path);
fs::write(&groups_path, new_contents)
.map_err(|e| format!("could not write to {}: {}", groups_path.display(), e))?;

View File

@ -532,7 +532,7 @@ impl<'a> LintExtractor<'a> {
}
add_rename_redirect(level, &mut result);
let out_path = self.out_path.join("listing").join(level.doc_filename());
// Delete the output because rustbuild uses hard links in its copies.
// Delete the output because bootstrap uses hard links in its copies.
let _ = fs::remove_file(&out_path);
fs::write(&out_path, result)
.map_err(|e| format!("could not write to {}: {}", out_path.display(), e))?;

View File

@ -15,7 +15,7 @@ pub struct VersionInfo {
pub version: &'static str,
/// The release channel we were built for (stable/beta/nightly/dev).
///
/// `None` if not built via rustbuild.
/// `None` if not built via bootstrap.
pub release_channel: Option<&'static str>,
/// Information about the Git repository we may have been built from.
///

View File

@ -109,7 +109,7 @@ impl Combiner {
.with_context(|| format!("failed to read components in '{}'", input_tarball))?;
for component in pkg_components.split_whitespace() {
// All we need to do is copy the component directory. We could
// move it, but rustbuild wants to reuse the unpacked package
// move it, but bootstrap wants to reuse the unpacked package
// dir for OS-specific installers on macOS and Windows.
let component_dir = package_dir.join(component);
create_dir(&component_dir)?;

View File

@ -974,7 +974,7 @@ combined_remains() {
--package-name=rust \
--input-tarballs="$OUT_DIR/rustc.tar.gz,$OUT_DIR/cargo.tar.gz,$OUT_DIR/rust-docs.tar.gz"
for component in rustc cargo rust-docs; do
# rustbuild wants the original extracted package intact too
# bootstrap wants the original extracted package intact too
try test -d "$WORK_DIR/$component/$component"
try test -d "$WORK_DIR/rust/$component"
done

View File

@ -1,4 +1,3 @@
// skip-filecheck
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
//! Tests that assignment in both branches of an `if` are eliminated.
//@ test-mir-pass: DestinationPropagation
@ -12,6 +11,10 @@ fn cond() -> bool {
// EMIT_MIR branch.foo.DestinationPropagation.diff
fn foo() -> i32 {
// CHECK-LABEL: fn foo(
// CHECK: debug y => [[y:_.*]];
// CHECK: [[y]] = val()
// CHECK-NOT: [[y]] = {{_.*}};
let x = val();
let y = if cond() {

View File

@ -1,4 +1,3 @@
// skip-filecheck
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
// Check that DestinationPropagation does not propagate an assignment to a function argument
// (doing so can break usages of the original argument value)
@ -9,18 +8,29 @@ fn dummy(x: u8) -> u8 {
// EMIT_MIR copy_propagation_arg.foo.DestinationPropagation.diff
fn foo(mut x: u8) {
// CHECK-LABEL: fn foo(
// CHECK: debug x => [[x:_.*]];
// CHECK: dummy(move [[x]])
// CHECK: [[x]] = move {{_.*}};
// calling `dummy` to make a use of `x` that copyprop cannot eliminate
x = dummy(x); // this will assign a local to `x`
}
// EMIT_MIR copy_propagation_arg.bar.DestinationPropagation.diff
fn bar(mut x: u8) {
// CHECK-LABEL: fn bar(
// CHECK: debug x => [[x:_.*]];
// CHECK: dummy(move [[x]])
// CHECK: [[x]] = const 5_u8;
dummy(x);
x = 5;
}
// EMIT_MIR copy_propagation_arg.baz.DestinationPropagation.diff
fn baz(mut x: i32) -> i32 {
// CHECK-LABEL: fn baz(
// CHECK: debug x => [[x:_.*]];
// CHECK-NOT: [[x]] =
// self-assignment to a function argument should be eliminated
x = x;
x
@ -28,6 +38,12 @@ fn baz(mut x: i32) -> i32 {
// EMIT_MIR copy_propagation_arg.arg_src.DestinationPropagation.diff
fn arg_src(mut x: i32) -> i32 {
// CHECK-LABEL: fn arg_src(
// CHECK: debug x => [[x:_.*]];
// CHECK: debug y => [[y:_.*]];
// CHECK: [[y]] = [[x]]
// CHECK: [[x]] = const 123_i32;
// CHECK-NOT: {{_.*}} = [[y]];
let y = x;
x = 123; // Don't propagate this assignment to `y`
y

View File

@ -1,4 +1,3 @@
// skip-filecheck
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
//! Tests that cyclic assignments don't hang DestinationPropagation, and result in reasonable code.
//@ test-mir-pass: DestinationPropagation
@ -8,6 +7,10 @@ fn val() -> i32 {
// EMIT_MIR cycle.main.DestinationPropagation.diff
fn main() {
// CHECK-LABEL: main(
// CHECK: debug x => [[x:_.*]];
// CHECK: [[x]] = val()
// CHECK-NOT: [[x]] = {{_.*}};
let mut x = val();
let y = x;
let z = y;

View File

@ -1,4 +1,3 @@
// skip-filecheck
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
//@ test-mir-pass: DestinationPropagation
@ -8,6 +7,13 @@ fn id<T>(x: T) -> T {
// EMIT_MIR dead_stores_79191.f.DestinationPropagation.after.mir
fn f(mut a: usize) -> usize {
// CHECK-LABEL: fn f(
// CHECK: debug a => [[a:_.*]];
// CHECK: debug b => [[b:_.*]];
// CHECK: [[b]] = [[a]];
// CHECK: [[a]] = const 5_usize;
// CHECK: [[a]] = move [[b]];
// CHECK: id::<usize>(move [[a]])
let b = a;
a = 5;
a = b;

View File

@ -1,4 +1,3 @@
// skip-filecheck
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
// This is a copy of the `dead_stores_79191` test, except that we turn on DSE. This demonstrates
// that that pass enables this one to do more optimizations.
@ -12,6 +11,13 @@ fn id<T>(x: T) -> T {
// EMIT_MIR dead_stores_better.f.DestinationPropagation.after.mir
pub fn f(mut a: usize) -> usize {
// CHECK-LABEL: fn f(
// CHECK: debug a => [[a:_.*]];
// CHECK: debug b => [[b:_.*]];
// CHECK: [[b]] = [[a]];
// CHECK: [[a]] = const 5_usize;
// CHECK: [[a]] = move [[b]];
// CHECK: id::<usize>(move [[a]])
let b = a;
a = 5;
a = b;

View File

@ -1,9 +1,15 @@
// skip-filecheck
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
//! Copy of `nrvo-simple.rs`, to ensure that full dest-prop handles it too.
//@ test-mir-pass: DestinationPropagation
// EMIT_MIR simple.nrvo.DestinationPropagation.diff
fn nrvo(init: fn(&mut [u8; 1024])) -> [u8; 1024] {
// CHECK-LABEL: fn nrvo(
// CHECK: debug init => [[init:_.*]];
// CHECK: debug buf => [[buf:_.*]];
// CHECK: [[buf]] = [const 0_u8; 1024];
// CHECK-NOT: {{_.*}} = [[init]];
// CHECK: move [[init]](move {{_.*}})
// CHECK: {{_.*}} = [[buf]]
let mut buf = [0; 1024];
init(&mut buf);
buf

View File

@ -8,6 +8,8 @@ fn val() -> u32 {
// EMIT_MIR union.main.DestinationPropagation.diff
fn main() {
// CHECK-LABEL: fn args(
// CHECK: {{_.*}} = Un { us: const 1_u32 };
union Un {
us: u32,
}

View File

@ -1,3 +1,6 @@
//@ check-pass
// https://github.com/rust-lang/rust/issues/102154
trait A<Y, N> {
type B;
}

View File

@ -1,3 +1,6 @@
//@ check-pass
// https://github.com/rust-lang/rust/issues/100620
pub trait Bar<S> {}
pub trait Qux<T> {}

View File

@ -3,6 +3,8 @@
// Check that this isn't an ICE
//@ should-fail
// https://github.com/rust-lang/rust/issues/100241
mod foo {
pub use inner::S;
//~^ ERROR unresolved imports `inner`, `foo::S`

View File

@ -2,7 +2,10 @@
//@ ignore-cross-compile
// This is the version where a non-compiler-internal crate inlines a compiler-internal one.
// In this case, the item shouldn't be documented, because regular users can't get at it.
// https://github.com/rust-lang/rust/issues/106421
#![crate_name="bar"]
extern crate foo;
//@ !has issue_106421_not_internal/struct.FatalError.html '//*[@id="method.raise"]' 'fn raise'
//@ !has bar/struct.FatalError.html '//*[@id="method.raise"]' 'fn raise'
pub use foo::FatalError;

View File

@ -1,8 +1,10 @@
//@ aux-build:issue-106421-force-unstable.rs
//@ ignore-cross-compile
//@ compile-flags: -Zforce-unstable-if-unmarked
// https://github.com/rust-lang/rust/issues/106421
#![crate_name="bar"]
extern crate foo;
//@ has issue_106421/struct.FatalError.html '//*[@id="method.raise"]' 'fn raise'
//@ has bar/struct.FatalError.html '//*[@id="method.raise"]' 'fn raise'
pub use foo::FatalError;

View File

@ -1,3 +1,4 @@
// https://github.com/rust-lang/rust/issues/105952
#![crate_name = "foo"]
#![feature(associated_const_equality)]

View File

@ -2,6 +2,7 @@
//@ build-aux-docs
//@ ignore-cross-compile
// https://github.com/rust-lang/rust/issues/100204
#![crate_name="second"]
extern crate first;

View File

@ -1,14 +0,0 @@
//@ has 'issue_106142/a/index.html'
//@ count 'issue_106142/a/index.html' '//ul[@class="item-table"]//li//a' 1
#![allow(rustdoc::broken_intra_doc_links)]
pub mod a {
/// [`m`]
pub fn f() {}
#[macro_export]
macro_rules! m {
() => {};
}
}

View File

@ -0,0 +1,17 @@
// https://github.com/rust-lang/rust/issues/106142
#![crate_name="foo"]
//@ has 'foo/a/index.html'
//@ count 'foo/a/index.html' '//ul[@class="item-table"]//li//a' 1
#![allow(rustdoc::broken_intra_doc_links)]
pub mod a {
/// [`m`]
pub fn f() {}
#[macro_export]
macro_rules! m {
() => {};
}
}

View File

@ -2,6 +2,7 @@
//@ build-aux-docs
//@ ignore-cross-compile
// https://github.com/rust-lang/rust/issues/99734
#![crate_name = "foo"]
#[macro_use]

View File

@ -2,6 +2,7 @@
//@ build-aux-docs
//@ ignore-cross-compile
// https://github.com/rust-lang/rust/issues/99221
#![crate_name = "foo"]
#[macro_use]

View File

@ -2,6 +2,7 @@
//@ build-aux-docs
//@ ignore-cross-compile
// https://github.com/rust-lang/rust/issues/99734
#![crate_name = "foo"]
#[macro_use]

View File

@ -2,6 +2,7 @@
//@ build-aux-docs
//@ ignore-cross-compile
// https://github.com/rust-lang/rust/issues/99221
#![crate_name = "foo"]
#[macro_use]

View File

@ -1,4 +1,5 @@
// Regression test to ensure that both `AtomicU8` items are displayed but not the re-export.
// https://github.com/rust-lang/rust/issues/105735
#![crate_name = "foo"]
#![no_std]

View File

@ -1,4 +1,5 @@
// Regression test to ensure that both `AtomicU8` items are displayed but not the re-export.
// https://github.com/rust-lang/rust/issues/105735
#![crate_name = "foo"]
#![no_std]