mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-21 14:23:45 +00:00
Auto merge of #133219 - matthiaskrgr:rollup-hnuq0zf, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - #123947 (Add vec_deque::Iter::as_slices and friends) - #125405 (Add std:🧵:add_spawn_hook.) - #133175 (ci: use free runner in dist-i686-msvc) - #133183 (Mention std::fs::remove_dir_all in std::fs::remove_dir) - #133188 (Add `visit` methods to ast nodes that already have `walk`s on ast visitors) - #133201 (Remove `TokenKind::InvalidPrefix`) - #133207 (Default-enable `llvm_tools_enabled` when no `config.toml` is present) - #133213 (Correct the tier listing of `wasm32-wasip2`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
875df370be
@ -330,6 +330,10 @@ pub trait MutVisitor: Sized {
|
|||||||
fn visit_capture_by(&mut self, capture_by: &mut CaptureBy) {
|
fn visit_capture_by(&mut self, capture_by: &mut CaptureBy) {
|
||||||
walk_capture_by(self, capture_by)
|
walk_capture_by(self, capture_by)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_fn_ret_ty(&mut self, fn_ret_ty: &mut FnRetTy) {
|
||||||
|
walk_fn_ret_ty(self, fn_ret_ty)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful
|
/// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful
|
||||||
@ -609,7 +613,7 @@ fn walk_angle_bracketed_parameter_data<T: MutVisitor>(vis: &mut T, data: &mut An
|
|||||||
fn walk_parenthesized_parameter_data<T: MutVisitor>(vis: &mut T, args: &mut ParenthesizedArgs) {
|
fn walk_parenthesized_parameter_data<T: MutVisitor>(vis: &mut T, args: &mut ParenthesizedArgs) {
|
||||||
let ParenthesizedArgs { inputs, output, span, inputs_span } = args;
|
let ParenthesizedArgs { inputs, output, span, inputs_span } = args;
|
||||||
visit_thin_vec(inputs, |input| vis.visit_ty(input));
|
visit_thin_vec(inputs, |input| vis.visit_ty(input));
|
||||||
walk_fn_ret_ty(vis, output);
|
vis.visit_fn_ret_ty(output);
|
||||||
vis.visit_span(span);
|
vis.visit_span(span);
|
||||||
vis.visit_span(inputs_span);
|
vis.visit_span(inputs_span);
|
||||||
}
|
}
|
||||||
@ -911,7 +915,7 @@ fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) {
|
|||||||
fn walk_fn_decl<T: MutVisitor>(vis: &mut T, decl: &mut P<FnDecl>) {
|
fn walk_fn_decl<T: MutVisitor>(vis: &mut T, decl: &mut P<FnDecl>) {
|
||||||
let FnDecl { inputs, output } = decl.deref_mut();
|
let FnDecl { inputs, output } = decl.deref_mut();
|
||||||
inputs.flat_map_in_place(|param| vis.flat_map_param(param));
|
inputs.flat_map_in_place(|param| vis.flat_map_param(param));
|
||||||
walk_fn_ret_ty(vis, output);
|
vis.visit_fn_ret_ty(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn walk_fn_ret_ty<T: MutVisitor>(vis: &mut T, fn_ret_ty: &mut FnRetTy) {
|
fn walk_fn_ret_ty<T: MutVisitor>(vis: &mut T, fn_ret_ty: &mut FnRetTy) {
|
||||||
|
@ -299,6 +299,12 @@ pub trait Visitor<'ast>: Sized {
|
|||||||
fn visit_coroutine_kind(&mut self, _coroutine_kind: &'ast CoroutineKind) -> Self::Result {
|
fn visit_coroutine_kind(&mut self, _coroutine_kind: &'ast CoroutineKind) -> Self::Result {
|
||||||
Self::Result::output()
|
Self::Result::output()
|
||||||
}
|
}
|
||||||
|
fn visit_fn_decl(&mut self, fn_decl: &'ast FnDecl) -> Self::Result {
|
||||||
|
walk_fn_decl(self, fn_decl)
|
||||||
|
}
|
||||||
|
fn visit_qself(&mut self, qs: &'ast Option<P<QSelf>>) -> Self::Result {
|
||||||
|
walk_qself(self, qs)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) -> V::Result {
|
pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) -> V::Result {
|
||||||
@ -434,13 +440,13 @@ impl WalkItemKind for ItemKind {
|
|||||||
body,
|
body,
|
||||||
from_glob: _,
|
from_glob: _,
|
||||||
}) => {
|
}) => {
|
||||||
try_visit!(walk_qself(visitor, qself));
|
try_visit!(visitor.visit_qself(qself));
|
||||||
try_visit!(visitor.visit_path(path, *id));
|
try_visit!(visitor.visit_path(path, *id));
|
||||||
visit_opt!(visitor, visit_ident, rename);
|
visit_opt!(visitor, visit_ident, rename);
|
||||||
visit_opt!(visitor, visit_block, body);
|
visit_opt!(visitor, visit_block, body);
|
||||||
}
|
}
|
||||||
ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
|
ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
|
||||||
try_visit!(walk_qself(visitor, qself));
|
try_visit!(visitor.visit_qself(qself));
|
||||||
try_visit!(visitor.visit_path(prefix, id));
|
try_visit!(visitor.visit_path(prefix, id));
|
||||||
if let Some(suffixes) = suffixes {
|
if let Some(suffixes) = suffixes {
|
||||||
for (ident, rename) in suffixes {
|
for (ident, rename) in suffixes {
|
||||||
@ -518,10 +524,10 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result {
|
|||||||
let BareFnTy { safety: _, ext: _, generic_params, decl, decl_span: _ } =
|
let BareFnTy { safety: _, ext: _, generic_params, decl, decl_span: _ } =
|
||||||
&**function_declaration;
|
&**function_declaration;
|
||||||
walk_list!(visitor, visit_generic_param, generic_params);
|
walk_list!(visitor, visit_generic_param, generic_params);
|
||||||
try_visit!(walk_fn_decl(visitor, decl));
|
try_visit!(visitor.visit_fn_decl(decl));
|
||||||
}
|
}
|
||||||
TyKind::Path(maybe_qself, path) => {
|
TyKind::Path(maybe_qself, path) => {
|
||||||
try_visit!(walk_qself(visitor, maybe_qself));
|
try_visit!(visitor.visit_qself(maybe_qself));
|
||||||
try_visit!(visitor.visit_path(path, *id));
|
try_visit!(visitor.visit_path(path, *id));
|
||||||
}
|
}
|
||||||
TyKind::Pat(ty, pat) => {
|
TyKind::Pat(ty, pat) => {
|
||||||
@ -652,16 +658,16 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res
|
|||||||
let Pat { id, kind, span: _, tokens: _ } = pattern;
|
let Pat { id, kind, span: _, tokens: _ } = pattern;
|
||||||
match kind {
|
match kind {
|
||||||
PatKind::TupleStruct(opt_qself, path, elems) => {
|
PatKind::TupleStruct(opt_qself, path, elems) => {
|
||||||
try_visit!(walk_qself(visitor, opt_qself));
|
try_visit!(visitor.visit_qself(opt_qself));
|
||||||
try_visit!(visitor.visit_path(path, *id));
|
try_visit!(visitor.visit_path(path, *id));
|
||||||
walk_list!(visitor, visit_pat, elems);
|
walk_list!(visitor, visit_pat, elems);
|
||||||
}
|
}
|
||||||
PatKind::Path(opt_qself, path) => {
|
PatKind::Path(opt_qself, path) => {
|
||||||
try_visit!(walk_qself(visitor, opt_qself));
|
try_visit!(visitor.visit_qself(opt_qself));
|
||||||
try_visit!(visitor.visit_path(path, *id))
|
try_visit!(visitor.visit_path(path, *id))
|
||||||
}
|
}
|
||||||
PatKind::Struct(opt_qself, path, fields, _rest) => {
|
PatKind::Struct(opt_qself, path, fields, _rest) => {
|
||||||
try_visit!(walk_qself(visitor, opt_qself));
|
try_visit!(visitor.visit_qself(opt_qself));
|
||||||
try_visit!(visitor.visit_path(path, *id));
|
try_visit!(visitor.visit_path(path, *id));
|
||||||
walk_list!(visitor, visit_pat_field, fields);
|
walk_list!(visitor, visit_pat_field, fields);
|
||||||
}
|
}
|
||||||
@ -846,13 +852,13 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Resu
|
|||||||
// Identifier and visibility are visited as a part of the item.
|
// Identifier and visibility are visited as a part of the item.
|
||||||
try_visit!(visitor.visit_fn_header(header));
|
try_visit!(visitor.visit_fn_header(header));
|
||||||
try_visit!(visitor.visit_generics(generics));
|
try_visit!(visitor.visit_generics(generics));
|
||||||
try_visit!(walk_fn_decl(visitor, decl));
|
try_visit!(visitor.visit_fn_decl(decl));
|
||||||
visit_opt!(visitor, visit_block, body);
|
visit_opt!(visitor, visit_block, body);
|
||||||
}
|
}
|
||||||
FnKind::Closure(binder, coroutine_kind, decl, body) => {
|
FnKind::Closure(binder, coroutine_kind, decl, body) => {
|
||||||
try_visit!(visitor.visit_closure_binder(binder));
|
try_visit!(visitor.visit_closure_binder(binder));
|
||||||
visit_opt!(visitor, visit_coroutine_kind, coroutine_kind.as_ref());
|
visit_opt!(visitor, visit_coroutine_kind, coroutine_kind.as_ref());
|
||||||
try_visit!(walk_fn_decl(visitor, decl));
|
try_visit!(visitor.visit_fn_decl(decl));
|
||||||
try_visit!(visitor.visit_expr(body));
|
try_visit!(visitor.visit_expr(body));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -902,13 +908,13 @@ impl WalkItemKind for AssocItemKind {
|
|||||||
body,
|
body,
|
||||||
from_glob: _,
|
from_glob: _,
|
||||||
}) => {
|
}) => {
|
||||||
try_visit!(walk_qself(visitor, qself));
|
try_visit!(visitor.visit_qself(qself));
|
||||||
try_visit!(visitor.visit_path(path, *id));
|
try_visit!(visitor.visit_path(path, *id));
|
||||||
visit_opt!(visitor, visit_ident, rename);
|
visit_opt!(visitor, visit_ident, rename);
|
||||||
visit_opt!(visitor, visit_block, body);
|
visit_opt!(visitor, visit_block, body);
|
||||||
}
|
}
|
||||||
AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
|
AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
|
||||||
try_visit!(walk_qself(visitor, qself));
|
try_visit!(visitor.visit_qself(qself));
|
||||||
try_visit!(visitor.visit_path(prefix, id));
|
try_visit!(visitor.visit_path(prefix, id));
|
||||||
if let Some(suffixes) = suffixes {
|
if let Some(suffixes) = suffixes {
|
||||||
for (ident, rename) in suffixes {
|
for (ident, rename) in suffixes {
|
||||||
@ -1023,7 +1029,7 @@ pub fn walk_inline_asm_sym<'a, V: Visitor<'a>>(
|
|||||||
visitor: &mut V,
|
visitor: &mut V,
|
||||||
InlineAsmSym { id, qself, path }: &'a InlineAsmSym,
|
InlineAsmSym { id, qself, path }: &'a InlineAsmSym,
|
||||||
) -> V::Result {
|
) -> V::Result {
|
||||||
try_visit!(walk_qself(visitor, qself));
|
try_visit!(visitor.visit_qself(qself));
|
||||||
visitor.visit_path(path, *id)
|
visitor.visit_path(path, *id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1055,7 +1061,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
|
|||||||
}
|
}
|
||||||
ExprKind::Struct(se) => {
|
ExprKind::Struct(se) => {
|
||||||
let StructExpr { qself, path, fields, rest } = &**se;
|
let StructExpr { qself, path, fields, rest } = &**se;
|
||||||
try_visit!(walk_qself(visitor, qself));
|
try_visit!(visitor.visit_qself(qself));
|
||||||
try_visit!(visitor.visit_path(path, *id));
|
try_visit!(visitor.visit_path(path, *id));
|
||||||
walk_list!(visitor, visit_expr_field, fields);
|
walk_list!(visitor, visit_expr_field, fields);
|
||||||
match rest {
|
match rest {
|
||||||
@ -1164,7 +1170,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
|
|||||||
}
|
}
|
||||||
ExprKind::Underscore => {}
|
ExprKind::Underscore => {}
|
||||||
ExprKind::Path(maybe_qself, path) => {
|
ExprKind::Path(maybe_qself, path) => {
|
||||||
try_visit!(walk_qself(visitor, maybe_qself));
|
try_visit!(visitor.visit_qself(maybe_qself));
|
||||||
try_visit!(visitor.visit_path(path, *id));
|
try_visit!(visitor.visit_path(path, *id));
|
||||||
}
|
}
|
||||||
ExprKind::Break(opt_label, opt_expr) => {
|
ExprKind::Break(opt_label, opt_expr) => {
|
||||||
|
@ -38,6 +38,11 @@ local-rebuild = true
|
|||||||
codegen-backends = ["cranelift"]
|
codegen-backends = ["cranelift"]
|
||||||
deny-warnings = false
|
deny-warnings = false
|
||||||
verbose-tests = false
|
verbose-tests = false
|
||||||
|
# The cg_clif sysroot doesn't contain llvm tools and unless llvm_tools is
|
||||||
|
# disabled bootstrap will crash trying to copy llvm tools for the bootstrap
|
||||||
|
# compiler.
|
||||||
|
llvm_tools = false
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
popd
|
popd
|
||||||
|
|
||||||
|
@ -57,11 +57,10 @@ impl Token {
|
|||||||
/// Enum representing common lexeme types.
|
/// Enum representing common lexeme types.
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub enum TokenKind {
|
pub enum TokenKind {
|
||||||
// Multi-char tokens:
|
/// A line comment, e.g. `// comment`.
|
||||||
/// "// comment"
|
|
||||||
LineComment { doc_style: Option<DocStyle> },
|
LineComment { doc_style: Option<DocStyle> },
|
||||||
|
|
||||||
/// `/* block comment */`
|
/// A block comment, e.g. `/* block comment */`.
|
||||||
///
|
///
|
||||||
/// Block comments can be recursive, so a sequence like `/* /* */`
|
/// Block comments can be recursive, so a sequence like `/* /* */`
|
||||||
/// will not be considered terminated and will result in a parsing error.
|
/// will not be considered terminated and will result in a parsing error.
|
||||||
@ -70,18 +69,17 @@ pub enum TokenKind {
|
|||||||
/// Any whitespace character sequence.
|
/// Any whitespace character sequence.
|
||||||
Whitespace,
|
Whitespace,
|
||||||
|
|
||||||
/// "ident" or "continue"
|
/// An identifier or keyword, e.g. `ident` or `continue`.
|
||||||
///
|
|
||||||
/// At this step, keywords are also considered identifiers.
|
|
||||||
Ident,
|
Ident,
|
||||||
|
|
||||||
/// Like the above, but containing invalid unicode codepoints.
|
/// An identifier that is invalid because it contains emoji.
|
||||||
InvalidIdent,
|
InvalidIdent,
|
||||||
|
|
||||||
/// "r#ident"
|
/// A raw identifier, e.g. "r#ident".
|
||||||
RawIdent,
|
RawIdent,
|
||||||
|
|
||||||
/// An unknown prefix, like `foo#`, `foo'`, `foo"`.
|
/// An unknown literal prefix, like `foo#`, `foo'`, `foo"`. Excludes
|
||||||
|
/// literal prefixes that contain emoji, which are considered "invalid".
|
||||||
///
|
///
|
||||||
/// Note that only the
|
/// Note that only the
|
||||||
/// prefix (`foo`) is included in the token, not the separator (which is
|
/// prefix (`foo`) is included in the token, not the separator (which is
|
||||||
@ -93,87 +91,83 @@ pub enum TokenKind {
|
|||||||
|
|
||||||
/// An unknown prefix in a lifetime, like `'foo#`.
|
/// An unknown prefix in a lifetime, like `'foo#`.
|
||||||
///
|
///
|
||||||
/// Note that like above, only the `'` and prefix are included in the token
|
/// Like `UnknownPrefix`, only the `'` and prefix are included in the token
|
||||||
/// and not the separator.
|
/// and not the separator.
|
||||||
UnknownPrefixLifetime,
|
UnknownPrefixLifetime,
|
||||||
|
|
||||||
/// `'r#lt`, which in edition < 2021 is split into several tokens: `'r # lt`.
|
/// A raw lifetime, e.g. `'r#foo`. In edition < 2021 it will be split into
|
||||||
|
/// several tokens: `'r` and `#` and `foo`.
|
||||||
RawLifetime,
|
RawLifetime,
|
||||||
|
|
||||||
/// Similar to the above, but *always* an error on every edition. This is used
|
|
||||||
/// for emoji identifier recovery, as those are not meant to be ever accepted.
|
|
||||||
InvalidPrefix,
|
|
||||||
|
|
||||||
/// Guarded string literal prefix: `#"` or `##`.
|
/// Guarded string literal prefix: `#"` or `##`.
|
||||||
///
|
///
|
||||||
/// Used for reserving "guarded strings" (RFC 3598) in edition 2024.
|
/// Used for reserving "guarded strings" (RFC 3598) in edition 2024.
|
||||||
/// Split into the component tokens on older editions.
|
/// Split into the component tokens on older editions.
|
||||||
GuardedStrPrefix,
|
GuardedStrPrefix,
|
||||||
|
|
||||||
/// Examples: `12u8`, `1.0e-40`, `b"123"`. Note that `_` is an invalid
|
/// Literals, e.g. `12u8`, `1.0e-40`, `b"123"`. Note that `_` is an invalid
|
||||||
/// suffix, but may be present here on string and float literals. Users of
|
/// suffix, but may be present here on string and float literals. Users of
|
||||||
/// this type will need to check for and reject that case.
|
/// this type will need to check for and reject that case.
|
||||||
///
|
///
|
||||||
/// See [LiteralKind] for more details.
|
/// See [LiteralKind] for more details.
|
||||||
Literal { kind: LiteralKind, suffix_start: u32 },
|
Literal { kind: LiteralKind, suffix_start: u32 },
|
||||||
|
|
||||||
/// "'a"
|
/// A lifetime, e.g. `'a`.
|
||||||
Lifetime { starts_with_number: bool },
|
Lifetime { starts_with_number: bool },
|
||||||
|
|
||||||
// One-char tokens:
|
/// `;`
|
||||||
/// ";"
|
|
||||||
Semi,
|
Semi,
|
||||||
/// ","
|
/// `,`
|
||||||
Comma,
|
Comma,
|
||||||
/// "."
|
/// `.`
|
||||||
Dot,
|
Dot,
|
||||||
/// "("
|
/// `(`
|
||||||
OpenParen,
|
OpenParen,
|
||||||
/// ")"
|
/// `)`
|
||||||
CloseParen,
|
CloseParen,
|
||||||
/// "{"
|
/// `{`
|
||||||
OpenBrace,
|
OpenBrace,
|
||||||
/// "}"
|
/// `}`
|
||||||
CloseBrace,
|
CloseBrace,
|
||||||
/// "["
|
/// `[`
|
||||||
OpenBracket,
|
OpenBracket,
|
||||||
/// "]"
|
/// `]`
|
||||||
CloseBracket,
|
CloseBracket,
|
||||||
/// "@"
|
/// `@`
|
||||||
At,
|
At,
|
||||||
/// "#"
|
/// `#`
|
||||||
Pound,
|
Pound,
|
||||||
/// "~"
|
/// `~`
|
||||||
Tilde,
|
Tilde,
|
||||||
/// "?"
|
/// `?`
|
||||||
Question,
|
Question,
|
||||||
/// ":"
|
/// `:`
|
||||||
Colon,
|
Colon,
|
||||||
/// "$"
|
/// `$`
|
||||||
Dollar,
|
Dollar,
|
||||||
/// "="
|
/// `=`
|
||||||
Eq,
|
Eq,
|
||||||
/// "!"
|
/// `!`
|
||||||
Bang,
|
Bang,
|
||||||
/// "<"
|
/// `<`
|
||||||
Lt,
|
Lt,
|
||||||
/// ">"
|
/// `>`
|
||||||
Gt,
|
Gt,
|
||||||
/// "-"
|
/// `-`
|
||||||
Minus,
|
Minus,
|
||||||
/// "&"
|
/// `&`
|
||||||
And,
|
And,
|
||||||
/// "|"
|
/// `|`
|
||||||
Or,
|
Or,
|
||||||
/// "+"
|
/// `+`
|
||||||
Plus,
|
Plus,
|
||||||
/// "*"
|
/// `*`
|
||||||
Star,
|
Star,
|
||||||
/// "/"
|
/// `/`
|
||||||
Slash,
|
Slash,
|
||||||
/// "^"
|
/// `^`
|
||||||
Caret,
|
Caret,
|
||||||
/// "%"
|
/// `%`
|
||||||
Percent,
|
Percent,
|
||||||
|
|
||||||
/// Unknown token, not expected by the lexer, e.g. "№"
|
/// Unknown token, not expected by the lexer, e.g. "№"
|
||||||
@ -468,7 +462,7 @@ impl Cursor<'_> {
|
|||||||
Literal { kind, suffix_start }
|
Literal { kind, suffix_start }
|
||||||
}
|
}
|
||||||
// Identifier starting with an emoji. Only lexed for graceful error recovery.
|
// Identifier starting with an emoji. Only lexed for graceful error recovery.
|
||||||
c if !c.is_ascii() && c.is_emoji_char() => self.fake_ident_or_unknown_prefix(),
|
c if !c.is_ascii() && c.is_emoji_char() => self.invalid_ident(),
|
||||||
_ => Unknown,
|
_ => Unknown,
|
||||||
};
|
};
|
||||||
let res = Token::new(token_kind, self.pos_within_token());
|
let res = Token::new(token_kind, self.pos_within_token());
|
||||||
@ -552,24 +546,22 @@ impl Cursor<'_> {
|
|||||||
// we see a prefix here, it is definitely an unknown prefix.
|
// we see a prefix here, it is definitely an unknown prefix.
|
||||||
match self.first() {
|
match self.first() {
|
||||||
'#' | '"' | '\'' => UnknownPrefix,
|
'#' | '"' | '\'' => UnknownPrefix,
|
||||||
c if !c.is_ascii() && c.is_emoji_char() => self.fake_ident_or_unknown_prefix(),
|
c if !c.is_ascii() && c.is_emoji_char() => self.invalid_ident(),
|
||||||
_ => Ident,
|
_ => Ident,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fake_ident_or_unknown_prefix(&mut self) -> TokenKind {
|
fn invalid_ident(&mut self) -> TokenKind {
|
||||||
// Start is already eaten, eat the rest of identifier.
|
// Start is already eaten, eat the rest of identifier.
|
||||||
self.eat_while(|c| {
|
self.eat_while(|c| {
|
||||||
unicode_xid::UnicodeXID::is_xid_continue(c)
|
const ZERO_WIDTH_JOINER: char = '\u{200d}';
|
||||||
|| (!c.is_ascii() && c.is_emoji_char())
|
is_id_continue(c) || (!c.is_ascii() && c.is_emoji_char()) || c == ZERO_WIDTH_JOINER
|
||||||
|| c == '\u{200d}'
|
|
||||||
});
|
});
|
||||||
// Known prefixes must have been handled earlier. So if
|
// An invalid identifier followed by '#' or '"' or '\'' could be
|
||||||
// we see a prefix here, it is definitely an unknown prefix.
|
// interpreted as an invalid literal prefix. We don't bother doing that
|
||||||
match self.first() {
|
// because the treatment of invalid identifiers and invalid prefixes
|
||||||
'#' | '"' | '\'' => InvalidPrefix,
|
// would be the same.
|
||||||
_ => InvalidIdent,
|
InvalidIdent
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn c_or_byte_string(
|
fn c_or_byte_string(
|
||||||
|
@ -213,7 +213,7 @@ impl<'psess, 'src> StringReader<'psess, 'src> {
|
|||||||
let ident = Symbol::intern(lifetime_name);
|
let ident = Symbol::intern(lifetime_name);
|
||||||
token::Lifetime(ident, IdentIsRaw::No)
|
token::Lifetime(ident, IdentIsRaw::No)
|
||||||
}
|
}
|
||||||
rustc_lexer::TokenKind::InvalidIdent | rustc_lexer::TokenKind::InvalidPrefix
|
rustc_lexer::TokenKind::InvalidIdent
|
||||||
// Do not recover an identifier with emoji if the codepoint is a confusable
|
// Do not recover an identifier with emoji if the codepoint is a confusable
|
||||||
// with a recoverable substitution token, like `➖`.
|
// with a recoverable substitution token, like `➖`.
|
||||||
if !UNICODE_ARRAY.iter().any(|&(c, _, _)| {
|
if !UNICODE_ARRAY.iter().any(|&(c, _, _)| {
|
||||||
@ -359,8 +359,7 @@ impl<'psess, 'src> StringReader<'psess, 'src> {
|
|||||||
rustc_lexer::TokenKind::Percent => token::BinOp(token::Percent),
|
rustc_lexer::TokenKind::Percent => token::BinOp(token::Percent),
|
||||||
|
|
||||||
rustc_lexer::TokenKind::Unknown
|
rustc_lexer::TokenKind::Unknown
|
||||||
| rustc_lexer::TokenKind::InvalidIdent
|
| rustc_lexer::TokenKind::InvalidIdent => {
|
||||||
| rustc_lexer::TokenKind::InvalidPrefix => {
|
|
||||||
// Don't emit diagnostics for sequences of the same invalid token
|
// Don't emit diagnostics for sequences of the same invalid token
|
||||||
if swallow_next_invalid > 0 {
|
if swallow_next_invalid > 0 {
|
||||||
swallow_next_invalid -= 1;
|
swallow_next_invalid -= 1;
|
||||||
|
@ -19,6 +19,40 @@ impl<'a, T> Iter<'a, T> {
|
|||||||
pub(super) fn new(i1: slice::Iter<'a, T>, i2: slice::Iter<'a, T>) -> Self {
|
pub(super) fn new(i1: slice::Iter<'a, T>, i2: slice::Iter<'a, T>) -> Self {
|
||||||
Self { i1, i2 }
|
Self { i1, i2 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Views the underlying data as a pair of subslices of the original data.
|
||||||
|
///
|
||||||
|
/// The slices contain, in order, the contents of the deque not yet yielded
|
||||||
|
/// by the iterator.
|
||||||
|
///
|
||||||
|
/// This has the same lifetime as the original `VecDeque`, and so the
|
||||||
|
/// iterator can continue to be used while this exists.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(vec_deque_iter_as_slices)]
|
||||||
|
///
|
||||||
|
/// use std::collections::VecDeque;
|
||||||
|
///
|
||||||
|
/// let mut deque = VecDeque::new();
|
||||||
|
/// deque.push_back(0);
|
||||||
|
/// deque.push_back(1);
|
||||||
|
/// deque.push_back(2);
|
||||||
|
/// deque.push_front(10);
|
||||||
|
/// deque.push_front(9);
|
||||||
|
/// deque.push_front(8);
|
||||||
|
///
|
||||||
|
/// let mut iter = deque.iter();
|
||||||
|
/// iter.next();
|
||||||
|
/// iter.next_back();
|
||||||
|
///
|
||||||
|
/// assert_eq!(iter.as_slices(), (&[9, 10][..], &[0, 1][..]));
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "vec_deque_iter_as_slices", issue = "123947")]
|
||||||
|
pub fn as_slices(&self) -> (&'a [T], &'a [T]) {
|
||||||
|
(self.i1.as_slice(), self.i2.as_slice())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "collection_debug", since = "1.17.0")]
|
#[stable(feature = "collection_debug", since = "1.17.0")]
|
||||||
|
@ -19,6 +19,113 @@ impl<'a, T> IterMut<'a, T> {
|
|||||||
pub(super) fn new(i1: slice::IterMut<'a, T>, i2: slice::IterMut<'a, T>) -> Self {
|
pub(super) fn new(i1: slice::IterMut<'a, T>, i2: slice::IterMut<'a, T>) -> Self {
|
||||||
Self { i1, i2 }
|
Self { i1, i2 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Views the underlying data as a pair of subslices of the original data.
|
||||||
|
///
|
||||||
|
/// The slices contain, in order, the contents of the deque not yet yielded
|
||||||
|
/// by the iterator.
|
||||||
|
///
|
||||||
|
/// To avoid creating `&mut` references that alias, this is forced to
|
||||||
|
/// consume the iterator.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(vec_deque_iter_as_slices)]
|
||||||
|
///
|
||||||
|
/// use std::collections::VecDeque;
|
||||||
|
///
|
||||||
|
/// let mut deque = VecDeque::new();
|
||||||
|
/// deque.push_back(0);
|
||||||
|
/// deque.push_back(1);
|
||||||
|
/// deque.push_back(2);
|
||||||
|
/// deque.push_front(10);
|
||||||
|
/// deque.push_front(9);
|
||||||
|
/// deque.push_front(8);
|
||||||
|
///
|
||||||
|
/// let mut iter = deque.iter_mut();
|
||||||
|
/// iter.next();
|
||||||
|
/// iter.next_back();
|
||||||
|
///
|
||||||
|
/// let slices = iter.into_slices();
|
||||||
|
/// slices.0[0] = 42;
|
||||||
|
/// slices.1[0] = 24;
|
||||||
|
/// assert_eq!(deque.as_slices(), (&[8, 42, 10][..], &[24, 1, 2][..]));
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "vec_deque_iter_as_slices", issue = "123947")]
|
||||||
|
pub fn into_slices(self) -> (&'a mut [T], &'a mut [T]) {
|
||||||
|
(self.i1.into_slice(), self.i2.into_slice())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Views the underlying data as a pair of subslices of the original data.
|
||||||
|
///
|
||||||
|
/// The slices contain, in order, the contents of the deque not yet yielded
|
||||||
|
/// by the iterator.
|
||||||
|
///
|
||||||
|
/// To avoid creating `&mut [T]` references that alias, the returned slices
|
||||||
|
/// borrow their lifetimes from the iterator the method is applied on.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(vec_deque_iter_as_slices)]
|
||||||
|
///
|
||||||
|
/// use std::collections::VecDeque;
|
||||||
|
///
|
||||||
|
/// let mut deque = VecDeque::new();
|
||||||
|
/// deque.push_back(0);
|
||||||
|
/// deque.push_back(1);
|
||||||
|
/// deque.push_back(2);
|
||||||
|
/// deque.push_front(10);
|
||||||
|
/// deque.push_front(9);
|
||||||
|
/// deque.push_front(8);
|
||||||
|
///
|
||||||
|
/// let mut iter = deque.iter_mut();
|
||||||
|
/// iter.next();
|
||||||
|
/// iter.next_back();
|
||||||
|
///
|
||||||
|
/// assert_eq!(iter.as_slices(), (&[9, 10][..], &[0, 1][..]));
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "vec_deque_iter_as_slices", issue = "123947")]
|
||||||
|
pub fn as_slices(&self) -> (&[T], &[T]) {
|
||||||
|
(self.i1.as_slice(), self.i2.as_slice())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Views the underlying data as a pair of subslices of the original data.
|
||||||
|
///
|
||||||
|
/// The slices contain, in order, the contents of the deque not yet yielded
|
||||||
|
/// by the iterator.
|
||||||
|
///
|
||||||
|
/// To avoid creating `&mut [T]` references that alias, the returned slices
|
||||||
|
/// borrow their lifetimes from the iterator the method is applied on.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(vec_deque_iter_as_slices)]
|
||||||
|
///
|
||||||
|
/// use std::collections::VecDeque;
|
||||||
|
///
|
||||||
|
/// let mut deque = VecDeque::new();
|
||||||
|
/// deque.push_back(0);
|
||||||
|
/// deque.push_back(1);
|
||||||
|
/// deque.push_back(2);
|
||||||
|
/// deque.push_front(10);
|
||||||
|
/// deque.push_front(9);
|
||||||
|
/// deque.push_front(8);
|
||||||
|
///
|
||||||
|
/// let mut iter = deque.iter_mut();
|
||||||
|
/// iter.next();
|
||||||
|
/// iter.next_back();
|
||||||
|
///
|
||||||
|
/// iter.as_mut_slices().0[0] = 42;
|
||||||
|
/// iter.as_mut_slices().1[0] = 24;
|
||||||
|
/// assert_eq!(deque.as_slices(), (&[8, 42, 10][..], &[24, 1, 2][..]));
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "vec_deque_iter_as_slices", issue = "123947")]
|
||||||
|
pub fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]) {
|
||||||
|
(self.i1.as_mut_slice(), self.i2.as_mut_slice())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "collection_debug", since = "1.17.0")]
|
#[stable(feature = "collection_debug", since = "1.17.0")]
|
||||||
|
@ -143,6 +143,7 @@
|
|||||||
#![feature(sized_type_properties)]
|
#![feature(sized_type_properties)]
|
||||||
#![feature(slice_from_ptr_range)]
|
#![feature(slice_from_ptr_range)]
|
||||||
#![feature(slice_index_methods)]
|
#![feature(slice_index_methods)]
|
||||||
|
#![feature(slice_iter_mut_as_mut_slice)]
|
||||||
#![feature(slice_ptr_get)]
|
#![feature(slice_ptr_get)]
|
||||||
#![feature(slice_range)]
|
#![feature(slice_range)]
|
||||||
#![feature(std_internals)]
|
#![feature(std_internals)]
|
||||||
|
@ -2738,6 +2738,10 @@ pub fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
|
|||||||
|
|
||||||
/// Removes an empty directory.
|
/// Removes an empty directory.
|
||||||
///
|
///
|
||||||
|
/// If you want to remove a directory that is not empty, as well as all
|
||||||
|
/// of its contents recursively, consider using [`remove_dir_all`]
|
||||||
|
/// instead.
|
||||||
|
///
|
||||||
/// # Platform-specific behavior
|
/// # Platform-specific behavior
|
||||||
///
|
///
|
||||||
/// This function currently corresponds to the `rmdir` function on Unix
|
/// This function currently corresponds to the `rmdir` function on Unix
|
||||||
|
@ -188,6 +188,11 @@ mod current;
|
|||||||
pub use current::current;
|
pub use current::current;
|
||||||
pub(crate) use current::{current_id, drop_current, set_current, try_current};
|
pub(crate) use current::{current_id, drop_current, set_current, try_current};
|
||||||
|
|
||||||
|
mod spawnhook;
|
||||||
|
|
||||||
|
#[unstable(feature = "thread_spawn_hook", issue = "132951")]
|
||||||
|
pub use spawnhook::add_spawn_hook;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Thread-local storage
|
// Thread-local storage
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -259,6 +264,8 @@ pub struct Builder {
|
|||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
// The size of the stack for the spawned thread in bytes
|
// The size of the stack for the spawned thread in bytes
|
||||||
stack_size: Option<usize>,
|
stack_size: Option<usize>,
|
||||||
|
// Skip running and inheriting the thread spawn hooks
|
||||||
|
no_hooks: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Builder {
|
impl Builder {
|
||||||
@ -282,7 +289,7 @@ impl Builder {
|
|||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub fn new() -> Builder {
|
pub fn new() -> Builder {
|
||||||
Builder { name: None, stack_size: None }
|
Builder { name: None, stack_size: None, no_hooks: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Names the thread-to-be. Currently the name is used for identification
|
/// Names the thread-to-be. Currently the name is used for identification
|
||||||
@ -338,6 +345,16 @@ impl Builder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Disables running and inheriting [spawn hooks](add_spawn_hook).
|
||||||
|
///
|
||||||
|
/// Use this if the parent thread is in no way relevant for the child thread.
|
||||||
|
/// For example, when lazily spawning threads for a thread pool.
|
||||||
|
#[unstable(feature = "thread_spawn_hook", issue = "132951")]
|
||||||
|
pub fn no_hooks(mut self) -> Builder {
|
||||||
|
self.no_hooks = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Spawns a new thread by taking ownership of the `Builder`, and returns an
|
/// Spawns a new thread by taking ownership of the `Builder`, and returns an
|
||||||
/// [`io::Result`] to its [`JoinHandle`].
|
/// [`io::Result`] to its [`JoinHandle`].
|
||||||
///
|
///
|
||||||
@ -460,7 +477,7 @@ impl Builder {
|
|||||||
F: Send,
|
F: Send,
|
||||||
T: Send,
|
T: Send,
|
||||||
{
|
{
|
||||||
let Builder { name, stack_size } = self;
|
let Builder { name, stack_size, no_hooks } = self;
|
||||||
|
|
||||||
let stack_size = stack_size.unwrap_or_else(|| {
|
let stack_size = stack_size.unwrap_or_else(|| {
|
||||||
static MIN: AtomicUsize = AtomicUsize::new(0);
|
static MIN: AtomicUsize = AtomicUsize::new(0);
|
||||||
@ -485,6 +502,13 @@ impl Builder {
|
|||||||
Some(name) => Thread::new(id, name.into()),
|
Some(name) => Thread::new(id, name.into()),
|
||||||
None => Thread::new_unnamed(id),
|
None => Thread::new_unnamed(id),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let hooks = if no_hooks {
|
||||||
|
spawnhook::ChildSpawnHooks::default()
|
||||||
|
} else {
|
||||||
|
spawnhook::run_spawn_hooks(&my_thread)
|
||||||
|
};
|
||||||
|
|
||||||
let their_thread = my_thread.clone();
|
let their_thread = my_thread.clone();
|
||||||
|
|
||||||
let my_packet: Arc<Packet<'scope, T>> = Arc::new(Packet {
|
let my_packet: Arc<Packet<'scope, T>> = Arc::new(Packet {
|
||||||
@ -494,9 +518,6 @@ impl Builder {
|
|||||||
});
|
});
|
||||||
let their_packet = my_packet.clone();
|
let their_packet = my_packet.clone();
|
||||||
|
|
||||||
let output_capture = crate::io::set_output_capture(None);
|
|
||||||
crate::io::set_output_capture(output_capture.clone());
|
|
||||||
|
|
||||||
// Pass `f` in `MaybeUninit` because actually that closure might *run longer than the lifetime of `F`*.
|
// Pass `f` in `MaybeUninit` because actually that closure might *run longer than the lifetime of `F`*.
|
||||||
// See <https://github.com/rust-lang/rust/issues/101983> for more details.
|
// See <https://github.com/rust-lang/rust/issues/101983> for more details.
|
||||||
// To prevent leaks we use a wrapper that drops its contents.
|
// To prevent leaks we use a wrapper that drops its contents.
|
||||||
@ -534,10 +555,9 @@ impl Builder {
|
|||||||
imp::Thread::set_name(name);
|
imp::Thread::set_name(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::io::set_output_capture(output_capture);
|
|
||||||
|
|
||||||
let f = f.into_inner();
|
let f = f.into_inner();
|
||||||
let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
|
let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
|
||||||
|
crate::sys::backtrace::__rust_begin_short_backtrace(|| hooks.run());
|
||||||
crate::sys::backtrace::__rust_begin_short_backtrace(f)
|
crate::sys::backtrace::__rust_begin_short_backtrace(f)
|
||||||
}));
|
}));
|
||||||
// SAFETY: `their_packet` as been built just above and moved by the
|
// SAFETY: `their_packet` as been built just above and moved by the
|
||||||
|
148
library/std/src/thread/spawnhook.rs
Normal file
148
library/std/src/thread/spawnhook.rs
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
use crate::cell::Cell;
|
||||||
|
use crate::iter;
|
||||||
|
use crate::sync::Arc;
|
||||||
|
use crate::thread::Thread;
|
||||||
|
|
||||||
|
crate::thread_local! {
|
||||||
|
/// A thread local linked list of spawn hooks.
|
||||||
|
///
|
||||||
|
/// It is a linked list of Arcs, such that it can very cheaply be inhereted by spawned threads.
|
||||||
|
///
|
||||||
|
/// (That technically makes it a set of linked lists with shared tails, so a linked tree.)
|
||||||
|
static SPAWN_HOOKS: Cell<SpawnHooks> = const { Cell::new(SpawnHooks { first: None }) };
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Clone)]
|
||||||
|
struct SpawnHooks {
|
||||||
|
first: Option<Arc<SpawnHook>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manually implement drop to prevent deep recursion when dropping linked Arc list.
|
||||||
|
impl Drop for SpawnHooks {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let mut next = self.first.take();
|
||||||
|
while let Some(SpawnHook { hook, next: n }) = next.and_then(|n| Arc::into_inner(n)) {
|
||||||
|
drop(hook);
|
||||||
|
next = n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SpawnHook {
|
||||||
|
hook: Box<dyn Send + Sync + Fn(&Thread) -> Box<dyn Send + FnOnce()>>,
|
||||||
|
next: Option<Arc<SpawnHook>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Registers a function to run for every newly thread spawned.
|
||||||
|
///
|
||||||
|
/// The hook is executed in the parent thread, and returns a function
|
||||||
|
/// that will be executed in the new thread.
|
||||||
|
///
|
||||||
|
/// The hook is called with the `Thread` handle for the new thread.
|
||||||
|
///
|
||||||
|
/// The hook will only be added for the current thread and is inherited by the threads it spawns.
|
||||||
|
/// In other words, adding a hook has no effect on already running threads (other than the current
|
||||||
|
/// thread) and the threads they might spawn in the future.
|
||||||
|
///
|
||||||
|
/// Hooks can only be added, not removed.
|
||||||
|
///
|
||||||
|
/// The hooks will run in reverse order, starting with the most recently added.
|
||||||
|
///
|
||||||
|
/// # Usage
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(thread_spawn_hook)]
|
||||||
|
///
|
||||||
|
/// std::thread::add_spawn_hook(|_| {
|
||||||
|
/// ..; // This will run in the parent (spawning) thread.
|
||||||
|
/// move || {
|
||||||
|
/// ..; // This will run it the child (spawned) thread.
|
||||||
|
/// }
|
||||||
|
/// });
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// A spawn hook can be used to "inherit" a thread local from the parent thread:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(thread_spawn_hook)]
|
||||||
|
///
|
||||||
|
/// use std::cell::Cell;
|
||||||
|
///
|
||||||
|
/// thread_local! {
|
||||||
|
/// static X: Cell<u32> = Cell::new(0);
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // This needs to be done once in the main thread before spawning any threads.
|
||||||
|
/// std::thread::add_spawn_hook(|_| {
|
||||||
|
/// // Get the value of X in the spawning thread.
|
||||||
|
/// let value = X.get();
|
||||||
|
/// // Set the value of X in the newly spawned thread.
|
||||||
|
/// move || X.set(value)
|
||||||
|
/// });
|
||||||
|
///
|
||||||
|
/// X.set(123);
|
||||||
|
///
|
||||||
|
/// std::thread::spawn(|| {
|
||||||
|
/// assert_eq!(X.get(), 123);
|
||||||
|
/// }).join().unwrap();
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "thread_spawn_hook", issue = "132951")]
|
||||||
|
pub fn add_spawn_hook<F, G>(hook: F)
|
||||||
|
where
|
||||||
|
F: 'static + Send + Sync + Fn(&Thread) -> G,
|
||||||
|
G: 'static + Send + FnOnce(),
|
||||||
|
{
|
||||||
|
SPAWN_HOOKS.with(|h| {
|
||||||
|
let mut hooks = h.take();
|
||||||
|
let next = hooks.first.take();
|
||||||
|
hooks.first = Some(Arc::new(SpawnHook {
|
||||||
|
hook: Box::new(move |thread| Box::new(hook(thread))),
|
||||||
|
next,
|
||||||
|
}));
|
||||||
|
h.set(hooks);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Runs all the spawn hooks.
|
||||||
|
///
|
||||||
|
/// Called on the parent thread.
|
||||||
|
///
|
||||||
|
/// Returns the functions to be called on the newly spawned thread.
|
||||||
|
pub(super) fn run_spawn_hooks(thread: &Thread) -> ChildSpawnHooks {
|
||||||
|
// Get a snapshot of the spawn hooks.
|
||||||
|
// (Increments the refcount to the first node.)
|
||||||
|
let hooks = SPAWN_HOOKS.with(|hooks| {
|
||||||
|
let snapshot = hooks.take();
|
||||||
|
hooks.set(snapshot.clone());
|
||||||
|
snapshot
|
||||||
|
});
|
||||||
|
// Iterate over the hooks, run them, and collect the results in a vector.
|
||||||
|
let to_run: Vec<_> = iter::successors(hooks.first.as_deref(), |hook| hook.next.as_deref())
|
||||||
|
.map(|hook| (hook.hook)(thread))
|
||||||
|
.collect();
|
||||||
|
// Pass on the snapshot of the hooks and the results to the new thread,
|
||||||
|
// which will then run SpawnHookResults::run().
|
||||||
|
ChildSpawnHooks { hooks, to_run }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The results of running the spawn hooks.
|
||||||
|
///
|
||||||
|
/// This struct is sent to the new thread.
|
||||||
|
/// It contains the inherited hooks and the closures to be run.
|
||||||
|
#[derive(Default)]
|
||||||
|
pub(super) struct ChildSpawnHooks {
|
||||||
|
hooks: SpawnHooks,
|
||||||
|
to_run: Vec<Box<dyn FnOnce() + Send>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChildSpawnHooks {
|
||||||
|
// This is run on the newly spawned thread, directly at the start.
|
||||||
|
pub(super) fn run(self) {
|
||||||
|
SPAWN_HOOKS.set(self.hooks);
|
||||||
|
for run in self.to_run {
|
||||||
|
run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -24,6 +24,7 @@
|
|||||||
#![feature(process_exitcode_internals)]
|
#![feature(process_exitcode_internals)]
|
||||||
#![feature(panic_can_unwind)]
|
#![feature(panic_can_unwind)]
|
||||||
#![feature(test)]
|
#![feature(test)]
|
||||||
|
#![feature(thread_spawn_hook)]
|
||||||
#![allow(internal_features)]
|
#![allow(internal_features)]
|
||||||
#![warn(rustdoc::unescaped_backticks)]
|
#![warn(rustdoc::unescaped_backticks)]
|
||||||
|
|
||||||
@ -134,6 +135,16 @@ pub fn test_main(args: &[String], tests: Vec<TestDescAndFn>, options: Option<Opt
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
panic::set_hook(hook);
|
panic::set_hook(hook);
|
||||||
|
// Use a thread spawning hook to make new threads inherit output capturing.
|
||||||
|
std::thread::add_spawn_hook(|_| {
|
||||||
|
// Get and clone the output capture of the current thread.
|
||||||
|
let output_capture = io::set_output_capture(None);
|
||||||
|
io::set_output_capture(output_capture.clone());
|
||||||
|
// Set the output capture of the new thread.
|
||||||
|
|| {
|
||||||
|
io::set_output_capture(output_capture);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
let res = console::run_tests_console(&opts, tests);
|
let res = console::run_tests_console(&opts, tests);
|
||||||
// Prevent Valgrind from reporting reachable blocks in users' unit tests.
|
// Prevent Valgrind from reporting reachable blocks in users' unit tests.
|
||||||
|
@ -1255,6 +1255,10 @@ impl Config {
|
|||||||
},
|
},
|
||||||
out: PathBuf::from("build"),
|
out: PathBuf::from("build"),
|
||||||
|
|
||||||
|
// This is needed by codegen_ssa on macOS to ship `llvm-objcopy` aliased to
|
||||||
|
// `rust-objcopy` to workaround bad `strip`s on macOS.
|
||||||
|
llvm_tools_enabled: true,
|
||||||
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -300,4 +300,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
|
|||||||
severity: ChangeSeverity::Info,
|
severity: ChangeSeverity::Info,
|
||||||
summary: "`download-rustc='if-unchanged'` is now a default option for library profile.",
|
summary: "`download-rustc='if-unchanged'` is now a default option for library profile.",
|
||||||
},
|
},
|
||||||
|
ChangeInfo {
|
||||||
|
change_id: 133207,
|
||||||
|
severity: ChangeSeverity::Info,
|
||||||
|
summary: "`rust.llvm-tools` is now enabled by default when no `config.toml` is provided.",
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
@ -465,7 +465,7 @@ auto:
|
|||||||
SCRIPT: python x.py dist bootstrap --include-default-paths
|
SCRIPT: python x.py dist bootstrap --include-default-paths
|
||||||
DIST_REQUIRE_ALL_TOOLS: 1
|
DIST_REQUIRE_ALL_TOOLS: 1
|
||||||
CODEGEN_BACKENDS: llvm,cranelift
|
CODEGEN_BACKENDS: llvm,cranelift
|
||||||
<<: *job-windows-8c
|
<<: *job-windows
|
||||||
|
|
||||||
- image: dist-aarch64-msvc
|
- image: dist-aarch64-msvc
|
||||||
env:
|
env:
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# `wasm32-wasip2`
|
# `wasm32-wasip2`
|
||||||
|
|
||||||
**Tier: 3**
|
**Tier: 2**
|
||||||
|
|
||||||
The `wasm32-wasip2` target is a new and still (as of January 2024) an
|
The `wasm32-wasip2` target is a new and still (as of January 2024) an
|
||||||
experimental target. This target is an extension to `wasm32-wasip1` target,
|
experimental target. This target is an extension to `wasm32-wasip1` target,
|
||||||
|
@ -861,10 +861,9 @@ impl<'src> Classifier<'src> {
|
|||||||
},
|
},
|
||||||
Some(c) => c,
|
Some(c) => c,
|
||||||
},
|
},
|
||||||
TokenKind::RawIdent
|
TokenKind::RawIdent | TokenKind::UnknownPrefix | TokenKind::InvalidIdent => {
|
||||||
| TokenKind::UnknownPrefix
|
Class::Ident(self.new_span(before, text))
|
||||||
| TokenKind::InvalidPrefix
|
}
|
||||||
| TokenKind::InvalidIdent => Class::Ident(self.new_span(before, text)),
|
|
||||||
TokenKind::Lifetime { .. }
|
TokenKind::Lifetime { .. }
|
||||||
| TokenKind::RawLifetime
|
| TokenKind::RawLifetime
|
||||||
| TokenKind::UnknownPrefixLifetime => Class::Lifetime,
|
| TokenKind::UnknownPrefixLifetime => Class::Lifetime,
|
||||||
|
@ -183,7 +183,7 @@ impl<'a> Converter<'a> {
|
|||||||
rustc_lexer::TokenKind::Ident => {
|
rustc_lexer::TokenKind::Ident => {
|
||||||
SyntaxKind::from_keyword(token_text, self.edition).unwrap_or(IDENT)
|
SyntaxKind::from_keyword(token_text, self.edition).unwrap_or(IDENT)
|
||||||
}
|
}
|
||||||
rustc_lexer::TokenKind::InvalidPrefix | rustc_lexer::TokenKind::InvalidIdent => {
|
rustc_lexer::TokenKind::InvalidIdent => {
|
||||||
err = "Ident contains invalid characters";
|
err = "Ident contains invalid characters";
|
||||||
IDENT
|
IDENT
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user