mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 08:44:35 +00:00
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:
commit
8a63c84af5
@ -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.
|
||||
|
||||
|
@ -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,
|
||||
),
|
||||
)],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
});
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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`.
|
||||
|
@ -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() {
|
||||
|
@ -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.)
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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>,
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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>()),
|
||||
&[
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
|
@ -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))?;
|
||||
|
@ -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))?;
|
||||
|
@ -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.
|
||||
///
|
||||
|
@ -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)?;
|
||||
|
@ -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
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -1,3 +1,6 @@
|
||||
//@ check-pass
|
||||
// https://github.com/rust-lang/rust/issues/102154
|
||||
|
||||
trait A<Y, N> {
|
||||
type B;
|
||||
}
|
@ -1,3 +1,6 @@
|
||||
//@ check-pass
|
||||
// https://github.com/rust-lang/rust/issues/100620
|
||||
|
||||
pub trait Bar<S> {}
|
||||
|
||||
pub trait Qux<T> {}
|
@ -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`
|
@ -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;
|
@ -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;
|
@ -1,3 +1,4 @@
|
||||
// https://github.com/rust-lang/rust/issues/105952
|
||||
#![crate_name = "foo"]
|
||||
|
||||
#![feature(associated_const_equality)]
|
@ -2,6 +2,7 @@
|
||||
//@ build-aux-docs
|
||||
//@ ignore-cross-compile
|
||||
|
||||
// https://github.com/rust-lang/rust/issues/100204
|
||||
#![crate_name="second"]
|
||||
|
||||
extern crate first;
|
@ -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 {
|
||||
() => {};
|
||||
}
|
||||
}
|
17
tests/rustdoc/macro-rules-broken-intra-doc-106142.rs
Normal file
17
tests/rustdoc/macro-rules-broken-intra-doc-106142.rs
Normal 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 {
|
||||
() => {};
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
//@ build-aux-docs
|
||||
//@ ignore-cross-compile
|
||||
|
||||
// https://github.com/rust-lang/rust/issues/99734
|
||||
#![crate_name = "foo"]
|
||||
|
||||
#[macro_use]
|
@ -2,6 +2,7 @@
|
||||
//@ build-aux-docs
|
||||
//@ ignore-cross-compile
|
||||
|
||||
// https://github.com/rust-lang/rust/issues/99221
|
||||
#![crate_name = "foo"]
|
||||
|
||||
#[macro_use]
|
@ -2,6 +2,7 @@
|
||||
//@ build-aux-docs
|
||||
//@ ignore-cross-compile
|
||||
|
||||
// https://github.com/rust-lang/rust/issues/99734
|
||||
#![crate_name = "foo"]
|
||||
|
||||
#[macro_use]
|
@ -2,6 +2,7 @@
|
||||
//@ build-aux-docs
|
||||
//@ ignore-cross-compile
|
||||
|
||||
// https://github.com/rust-lang/rust/issues/99221
|
||||
#![crate_name = "foo"]
|
||||
|
||||
#[macro_use]
|
@ -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]
|
@ -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]
|
Loading…
Reference in New Issue
Block a user