Merge pull request #4284 from rust-lang/rustup-2025-04-22
Automatic Rustup
This commit is contained in:
commit
f456b40240
422 changed files with 5540 additions and 3653 deletions
44
Cargo.lock
44
Cargo.lock
|
|
@ -225,7 +225,7 @@ dependencies = [
|
|||
"memchr",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"winnow 0.7.4",
|
||||
"winnow 0.7.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -303,9 +303,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
version = "1.11.3"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0"
|
||||
checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"regex-automata 0.4.9",
|
||||
|
|
@ -496,9 +496,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.35"
|
||||
version = "4.5.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944"
|
||||
checksum = "2df961d8c8a0d08aa9945718ccf584145eee3f3aa06cddbeac12933781102e04"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
|
|
@ -516,9 +516,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.35"
|
||||
version = "4.5.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9"
|
||||
checksum = "132dbda40fb6753878316a489d5a1242a8ef2f0d9e47ba01c951ea8aa7d013a5"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
|
|
@ -798,9 +798,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.14"
|
||||
version = "0.5.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471"
|
||||
checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
|
@ -1910,9 +1910,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
|||
|
||||
[[package]]
|
||||
name = "jiff"
|
||||
version = "0.2.5"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c102670231191d07d37a35af3eb77f1f0dbf7a71be51a962dcd57ea607be7260"
|
||||
checksum = "1f33145a5cbea837164362c7bd596106eb7c5198f97d1ba6f6ebb3223952e488"
|
||||
dependencies = [
|
||||
"jiff-static",
|
||||
"log",
|
||||
|
|
@ -1923,9 +1923,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "jiff-static"
|
||||
version = "0.2.5"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4cdde31a9d349f1b1f51a0b3714a5940ac022976f4b49485fc04be052b183b4c"
|
||||
checksum = "43ce13c40ec6956157a3635d97a1ee2df323b263f09ea14165131289cb0f5c19"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -1979,9 +1979,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "jsonpath-rust"
|
||||
version = "1.0.0"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b0231bb404a6cd6c8f0ab41b907049063a089fc02aa7636cc5cd9a4d87364c9"
|
||||
checksum = "6a37c2c87b8d16e788ce359660fead0ea5f4ed29ff400d55be74a4e01d1817d9"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_derive",
|
||||
|
|
@ -2113,9 +2113,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.9.3"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413"
|
||||
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
|
||||
|
||||
[[package]]
|
||||
name = "litemap"
|
||||
|
|
@ -4807,14 +4807,14 @@ version = "0.10.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e14e4d63b804dc0c7ec4a1e52bcb63f02c7ac94476755aa579edac21e01f915d"
|
||||
dependencies = [
|
||||
"self_cell 1.1.0",
|
||||
"self_cell 1.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "self_cell"
|
||||
version = "1.1.0"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2fdfc24bc566f839a2da4c4295b82db7d25a24253867d5c64355abb5799bdbe"
|
||||
checksum = "0f7d95a54511e0c7be3f51e8867aa8cf35148d7b9445d44de2f943e2b206e749"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
|
|
@ -6415,9 +6415,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.7.4"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36"
|
||||
checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -19,6 +19,14 @@
|
|||
# Note that this has no default value (x.py uses the defaults in `bootstrap.example.toml`).
|
||||
#profile = <none>
|
||||
|
||||
# Inherits configuration values from different configuration files (a.k.a. config extensions).
|
||||
# Supports absolute paths, and uses the current directory (where the bootstrap was invoked)
|
||||
# as the base if the given path is not absolute.
|
||||
#
|
||||
# The overriding logic follows a right-to-left order. For example, in `include = ["a.toml", "b.toml"]`,
|
||||
# extension `b.toml` overrides `a.toml`. Also, parent extensions always overrides the inner ones.
|
||||
#include = []
|
||||
|
||||
# Keeps track of major changes made to this configuration.
|
||||
#
|
||||
# This value also represents ID of the PR that caused major changes. Meaning,
|
||||
|
|
|
|||
|
|
@ -416,10 +416,7 @@ impl MetaItem {
|
|||
// This path is currently unreachable in the test suite.
|
||||
unreachable!()
|
||||
}
|
||||
Some(TokenTree::Token(
|
||||
Token { kind: token::OpenDelim(_) | token::CloseDelim(_), .. },
|
||||
_,
|
||||
)) => {
|
||||
Some(TokenTree::Token(Token { kind, .. }, _)) if kind.is_delim() => {
|
||||
panic!("Should be `AttrTokenTree::Delimited`, not delim tokens: {:?}", tt);
|
||||
}
|
||||
_ => return None,
|
||||
|
|
|
|||
|
|
@ -32,6 +32,18 @@ pub enum InvisibleOrigin {
|
|||
ProcMacro,
|
||||
}
|
||||
|
||||
impl InvisibleOrigin {
|
||||
// Should the parser skip these invisible delimiters? Ideally this function
|
||||
// will eventually disappear and no invisible delimiters will be skipped.
|
||||
#[inline]
|
||||
pub fn skip(&self) -> bool {
|
||||
match self {
|
||||
InvisibleOrigin::MetaVar(_) => false,
|
||||
InvisibleOrigin::ProcMacro => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for InvisibleOrigin {
|
||||
#[inline]
|
||||
fn eq(&self, _other: &InvisibleOrigin) -> bool {
|
||||
|
|
@ -125,8 +137,7 @@ impl Delimiter {
|
|||
pub fn skip(&self) -> bool {
|
||||
match self {
|
||||
Delimiter::Parenthesis | Delimiter::Bracket | Delimiter::Brace => false,
|
||||
Delimiter::Invisible(InvisibleOrigin::MetaVar(_)) => false,
|
||||
Delimiter::Invisible(InvisibleOrigin::ProcMacro) => true,
|
||||
Delimiter::Invisible(origin) => origin.skip(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -140,6 +151,24 @@ impl Delimiter {
|
|||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_open_token_kind(&self) -> TokenKind {
|
||||
match *self {
|
||||
Delimiter::Parenthesis => OpenParen,
|
||||
Delimiter::Brace => OpenBrace,
|
||||
Delimiter::Bracket => OpenBracket,
|
||||
Delimiter::Invisible(origin) => OpenInvisible(origin),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_close_token_kind(&self) -> TokenKind {
|
||||
match *self {
|
||||
Delimiter::Parenthesis => CloseParen,
|
||||
Delimiter::Brace => CloseBrace,
|
||||
Delimiter::Bracket => CloseBracket,
|
||||
Delimiter::Invisible(origin) => CloseInvisible(origin),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Note that the suffix is *not* considered when deciding the `LitKind` in this
|
||||
|
|
@ -194,9 +223,9 @@ impl Lit {
|
|||
match token.uninterpolate().kind {
|
||||
Ident(name, IdentIsRaw::No) if name.is_bool_lit() => Some(Lit::new(Bool, name, None)),
|
||||
Literal(token_lit) => Some(token_lit),
|
||||
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
|
||||
OpenInvisible(InvisibleOrigin::MetaVar(
|
||||
MetaVarKind::Literal | MetaVarKind::Expr { .. },
|
||||
))) => {
|
||||
)) => {
|
||||
// Unreachable with the current test suite.
|
||||
panic!("from_token metavar");
|
||||
}
|
||||
|
|
@ -426,10 +455,22 @@ pub enum TokenKind {
|
|||
Question,
|
||||
/// Used by proc macros for representing lifetimes, not generated by lexer right now.
|
||||
SingleQuote,
|
||||
/// An opening delimiter (e.g., `{`).
|
||||
OpenDelim(Delimiter),
|
||||
/// A closing delimiter (e.g., `}`).
|
||||
CloseDelim(Delimiter),
|
||||
/// `(`
|
||||
OpenParen,
|
||||
/// `)`
|
||||
CloseParen,
|
||||
/// `{`
|
||||
OpenBrace,
|
||||
/// `}`
|
||||
CloseBrace,
|
||||
/// `[`
|
||||
OpenBracket,
|
||||
/// `]`
|
||||
CloseBracket,
|
||||
/// Invisible opening delimiter, produced by a macro.
|
||||
OpenInvisible(InvisibleOrigin),
|
||||
/// Invisible closing delimiter, produced by a macro.
|
||||
CloseInvisible(InvisibleOrigin),
|
||||
|
||||
/* Literals */
|
||||
Literal(Lit),
|
||||
|
|
@ -530,6 +571,37 @@ impl TokenKind {
|
|||
pub fn should_end_const_arg(&self) -> bool {
|
||||
matches!(self, Gt | Ge | Shr | ShrEq)
|
||||
}
|
||||
|
||||
pub fn is_delim(&self) -> bool {
|
||||
self.open_delim().is_some() || self.close_delim().is_some()
|
||||
}
|
||||
|
||||
pub fn open_delim(&self) -> Option<Delimiter> {
|
||||
match *self {
|
||||
OpenParen => Some(Delimiter::Parenthesis),
|
||||
OpenBrace => Some(Delimiter::Brace),
|
||||
OpenBracket => Some(Delimiter::Bracket),
|
||||
OpenInvisible(origin) => Some(Delimiter::Invisible(origin)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn close_delim(&self) -> Option<Delimiter> {
|
||||
match *self {
|
||||
CloseParen => Some(Delimiter::Parenthesis),
|
||||
CloseBrace => Some(Delimiter::Brace),
|
||||
CloseBracket => Some(Delimiter::Bracket),
|
||||
CloseInvisible(origin) => Some(Delimiter::Invisible(origin)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_close_delim_or_eof(&self) -> bool {
|
||||
match self {
|
||||
CloseParen | CloseBrace | CloseBracket | CloseInvisible(_) | Eof => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Token {
|
||||
|
|
@ -559,7 +631,8 @@ impl Token {
|
|||
| DotDotDot | DotDotEq | Comma | Semi | Colon | PathSep | RArrow | LArrow
|
||||
| FatArrow | Pound | Dollar | Question | SingleQuote => true,
|
||||
|
||||
OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..)
|
||||
OpenParen | CloseParen | OpenBrace | CloseBrace | OpenBracket | CloseBracket
|
||||
| OpenInvisible(_) | CloseInvisible(_) | Literal(..) | DocComment(..) | Ident(..)
|
||||
| NtIdent(..) | Lifetime(..) | NtLifetime(..) | Eof => false,
|
||||
}
|
||||
}
|
||||
|
|
@ -573,11 +646,12 @@ impl Token {
|
|||
/// **NB**: Take care when modifying this function, since it will change
|
||||
/// the stable set of tokens that are allowed to match an expr nonterminal.
|
||||
pub fn can_begin_expr(&self) -> bool {
|
||||
use Delimiter::*;
|
||||
match self.uninterpolate().kind {
|
||||
Ident(name, is_raw) =>
|
||||
ident_can_begin_expr(name, self.span, is_raw), // value name or keyword
|
||||
OpenDelim(Parenthesis | Brace | Bracket) | // tuple, array or block
|
||||
OpenParen | // tuple
|
||||
OpenBrace | // block
|
||||
OpenBracket | // array
|
||||
Literal(..) | // literal
|
||||
Bang | // operator not
|
||||
Minus | // unary minus
|
||||
|
|
@ -591,12 +665,12 @@ impl Token {
|
|||
PathSep | // global path
|
||||
Lifetime(..) | // labeled loop
|
||||
Pound => true, // expression attributes
|
||||
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
|
||||
OpenInvisible(InvisibleOrigin::MetaVar(
|
||||
MetaVarKind::Block |
|
||||
MetaVarKind::Expr { .. } |
|
||||
MetaVarKind::Literal |
|
||||
MetaVarKind::Path
|
||||
))) => true,
|
||||
)) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
@ -608,8 +682,8 @@ impl Token {
|
|||
match &self.uninterpolate().kind {
|
||||
// box, ref, mut, and other identifiers (can stricten)
|
||||
Ident(..) | NtIdent(..) |
|
||||
OpenDelim(Delimiter::Parenthesis) | // tuple pattern
|
||||
OpenDelim(Delimiter::Bracket) | // slice pattern
|
||||
OpenParen | // tuple pattern
|
||||
OpenBracket | // slice pattern
|
||||
And | // reference
|
||||
Minus | // negative literal
|
||||
AndAnd | // double reference
|
||||
|
|
@ -620,14 +694,14 @@ impl Token {
|
|||
Lt | // path (UFCS constant)
|
||||
Shl => true, // path (double UFCS)
|
||||
Or => matches!(pat_kind, PatWithOr), // leading vert `|` or-pattern
|
||||
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
|
||||
OpenInvisible(InvisibleOrigin::MetaVar(
|
||||
MetaVarKind::Expr { .. } |
|
||||
MetaVarKind::Literal |
|
||||
MetaVarKind::Meta { .. } |
|
||||
MetaVarKind::Pat(_) |
|
||||
MetaVarKind::Path |
|
||||
MetaVarKind::Ty { .. }
|
||||
))) => true,
|
||||
)) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
@ -637,8 +711,8 @@ impl Token {
|
|||
match self.uninterpolate().kind {
|
||||
Ident(name, is_raw) =>
|
||||
ident_can_begin_type(name, self.span, is_raw), // type name or keyword
|
||||
OpenDelim(Delimiter::Parenthesis) | // tuple
|
||||
OpenDelim(Delimiter::Bracket) | // array
|
||||
OpenParen | // tuple
|
||||
OpenBracket | // array
|
||||
Bang | // never
|
||||
Star | // raw pointer
|
||||
And | // reference
|
||||
|
|
@ -647,10 +721,10 @@ impl Token {
|
|||
Lifetime(..) | // lifetime bound in trait object
|
||||
Lt | Shl | // associated path
|
||||
PathSep => true, // global path
|
||||
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
|
||||
OpenInvisible(InvisibleOrigin::MetaVar(
|
||||
MetaVarKind::Ty { .. } |
|
||||
MetaVarKind::Path
|
||||
))) => true,
|
||||
)) => true,
|
||||
// For anonymous structs or unions, which only appear in specific positions
|
||||
// (type of struct fields or union fields), we don't consider them as regular types
|
||||
_ => false,
|
||||
|
|
@ -660,11 +734,11 @@ impl Token {
|
|||
/// Returns `true` if the token can appear at the start of a const param.
|
||||
pub fn can_begin_const_arg(&self) -> bool {
|
||||
match self.kind {
|
||||
OpenDelim(Delimiter::Brace) | Literal(..) | Minus => true,
|
||||
OpenBrace | Literal(..) | Minus => true,
|
||||
Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true,
|
||||
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
|
||||
OpenInvisible(InvisibleOrigin::MetaVar(
|
||||
MetaVarKind::Expr { .. } | MetaVarKind::Block | MetaVarKind::Literal,
|
||||
))) => true,
|
||||
)) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
@ -711,7 +785,7 @@ impl Token {
|
|||
match self.uninterpolate().kind {
|
||||
Literal(..) | Minus => true,
|
||||
Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true,
|
||||
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind))) => match mv_kind {
|
||||
OpenInvisible(InvisibleOrigin::MetaVar(mv_kind)) => match mv_kind {
|
||||
MetaVarKind::Literal => true,
|
||||
MetaVarKind::Expr { can_begin_literal_maybe_minus, .. } => {
|
||||
can_begin_literal_maybe_minus
|
||||
|
|
@ -725,7 +799,7 @@ impl Token {
|
|||
pub fn can_begin_string_literal(&self) -> bool {
|
||||
match self.uninterpolate().kind {
|
||||
Literal(..) => true,
|
||||
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind))) => match mv_kind {
|
||||
OpenInvisible(InvisibleOrigin::MetaVar(mv_kind)) => match mv_kind {
|
||||
MetaVarKind::Literal => true,
|
||||
MetaVarKind::Expr { can_begin_string_literal, .. } => can_begin_string_literal,
|
||||
_ => false,
|
||||
|
|
@ -892,7 +966,7 @@ impl Token {
|
|||
/// from an expanded metavar?
|
||||
pub fn is_metavar_seq(&self) -> Option<MetaVarKind> {
|
||||
match self.kind {
|
||||
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(kind))) => Some(kind),
|
||||
OpenInvisible(InvisibleOrigin::MetaVar(kind)) => Some(kind),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
@ -970,7 +1044,8 @@ impl Token {
|
|||
Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | PlusEq | MinusEq | StarEq | SlashEq
|
||||
| PercentEq | CaretEq | AndEq | OrEq | ShlEq | ShrEq | At | DotDotDot | DotDotEq
|
||||
| Comma | Semi | PathSep | RArrow | LArrow | FatArrow | Pound | Dollar | Question
|
||||
| OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..) | NtIdent(..)
|
||||
| OpenParen | CloseParen | OpenBrace | CloseBrace | OpenBracket | CloseBracket
|
||||
| OpenInvisible(_) | CloseInvisible(_) | Literal(..) | Ident(..) | NtIdent(..)
|
||||
| Lifetime(..) | NtLifetime(..) | DocComment(..) | Eof,
|
||||
_,
|
||||
) => {
|
||||
|
|
|
|||
|
|
@ -770,12 +770,12 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
self.bclose(span, empty);
|
||||
}
|
||||
delim => {
|
||||
let token_str = self.token_kind_to_string(&token::OpenDelim(delim));
|
||||
let token_str = self.token_kind_to_string(&delim.as_open_token_kind());
|
||||
self.word(token_str);
|
||||
self.ibox(0);
|
||||
self.print_tts(tts, convert_dollar_crate);
|
||||
self.end();
|
||||
let token_str = self.token_kind_to_string(&token::CloseDelim(delim));
|
||||
let token_str = self.token_kind_to_string(&delim.as_close_token_kind());
|
||||
self.word(token_str);
|
||||
}
|
||||
}
|
||||
|
|
@ -932,14 +932,13 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
token::RArrow => "->".into(),
|
||||
token::LArrow => "<-".into(),
|
||||
token::FatArrow => "=>".into(),
|
||||
token::OpenDelim(Delimiter::Parenthesis) => "(".into(),
|
||||
token::CloseDelim(Delimiter::Parenthesis) => ")".into(),
|
||||
token::OpenDelim(Delimiter::Bracket) => "[".into(),
|
||||
token::CloseDelim(Delimiter::Bracket) => "]".into(),
|
||||
token::OpenDelim(Delimiter::Brace) => "{".into(),
|
||||
token::CloseDelim(Delimiter::Brace) => "}".into(),
|
||||
token::OpenDelim(Delimiter::Invisible(_))
|
||||
| token::CloseDelim(Delimiter::Invisible(_)) => "".into(),
|
||||
token::OpenParen => "(".into(),
|
||||
token::CloseParen => ")".into(),
|
||||
token::OpenBracket => "[".into(),
|
||||
token::CloseBracket => "]".into(),
|
||||
token::OpenBrace => "{".into(),
|
||||
token::CloseBrace => "}".into(),
|
||||
token::OpenInvisible(_) | token::CloseInvisible(_) => "".into(),
|
||||
token::Pound => "#".into(),
|
||||
token::Dollar => "$".into(),
|
||||
token::Question => "?".into(),
|
||||
|
|
|
|||
|
|
@ -191,7 +191,6 @@ pub enum AttributeKind {
|
|||
},
|
||||
MacroTransparency(Transparency),
|
||||
Repr(ThinVec<(ReprAttr, Span)>),
|
||||
RustcMacroEdition2021,
|
||||
Stability {
|
||||
stability: Stability,
|
||||
/// Span of the `#[stable(...)]` or `#[unstable(...)]` attribute
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ pub(crate) mod cfg;
|
|||
pub(crate) mod confusables;
|
||||
pub(crate) mod deprecation;
|
||||
pub(crate) mod repr;
|
||||
pub(crate) mod rustc;
|
||||
pub(crate) mod stability;
|
||||
pub(crate) mod transparency;
|
||||
pub(crate) mod util;
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_span::sym;
|
||||
|
||||
use super::{AcceptContext, SingleAttributeParser};
|
||||
use crate::parser::ArgParser;
|
||||
|
||||
pub(crate) struct RustcMacroEdition2021Parser;
|
||||
|
||||
// FIXME(jdonszelmann): make these proper diagnostics
|
||||
impl SingleAttributeParser for RustcMacroEdition2021Parser {
|
||||
const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_macro_edition_2021];
|
||||
|
||||
fn on_duplicate(_cx: &crate::context::AcceptContext<'_>, _first_span: rustc_span::Span) {}
|
||||
|
||||
fn convert(_cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
assert!(args.no_args());
|
||||
Some(AttributeKind::RustcMacroEdition2021)
|
||||
}
|
||||
}
|
||||
|
|
@ -15,7 +15,6 @@ use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInterna
|
|||
use crate::attributes::confusables::ConfusablesParser;
|
||||
use crate::attributes::deprecation::DeprecationParser;
|
||||
use crate::attributes::repr::ReprParser;
|
||||
use crate::attributes::rustc::RustcMacroEdition2021Parser;
|
||||
use crate::attributes::stability::{
|
||||
BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser,
|
||||
};
|
||||
|
|
@ -77,7 +76,6 @@ attribute_groups!(
|
|||
// tidy-alphabetical-start
|
||||
Single<ConstStabilityIndirectParser>,
|
||||
Single<DeprecationParser>,
|
||||
Single<RustcMacroEdition2021Parser>,
|
||||
Single<TransparencyParser>,
|
||||
// tidy-alphabetical-end
|
||||
];
|
||||
|
|
|
|||
|
|
@ -430,9 +430,7 @@ impl<'a> MetaItemListParserContext<'a> {
|
|||
let span = span.with_hi(segments.last().unwrap().span.hi());
|
||||
Some(AttrPath { segments: segments.into_boxed_slice(), span })
|
||||
}
|
||||
TokenTree::Token(Token { kind: token::OpenDelim(_) | token::CloseDelim(_), .. }, _) => {
|
||||
None
|
||||
}
|
||||
TokenTree::Token(Token { kind, .. }, _) if kind.is_delim() => None,
|
||||
_ => {
|
||||
// malformed attributes can get here. We can't crash, but somewhere else should've
|
||||
// already warned for this.
|
||||
|
|
|
|||
|
|
@ -247,9 +247,9 @@ builtin_macros_multiple_defaults = multiple declared defaults
|
|||
.suggestion = make `{$ident}` default
|
||||
|
||||
builtin_macros_naked_functions_testing_attribute =
|
||||
cannot use `#[naked]` with testing attributes
|
||||
cannot use `#[unsafe(naked)]` with testing attributes
|
||||
.label = function marked with testing attribute here
|
||||
.naked_attribute = `#[naked]` is incompatible with testing attributes
|
||||
.naked_attribute = `#[unsafe(naked)]` is incompatible with testing attributes
|
||||
|
||||
builtin_macros_no_default_variant = `#[derive(Default)]` on enum with no `#[default]`
|
||||
.label = this enum needs a unit variant marked with `#[default]`
|
||||
|
|
|
|||
|
|
@ -596,15 +596,14 @@ mod llvm_enzyme {
|
|||
}
|
||||
};
|
||||
let arg = ty.kind.is_simple_path().unwrap();
|
||||
let sl: Vec<Symbol> = vec![arg, kw::Default];
|
||||
let tmp = ecx.def_site_path(&sl);
|
||||
let tmp = ecx.def_site_path(&[arg, kw::Default]);
|
||||
let default_call_expr = ecx.expr_path(ecx.path(span, tmp));
|
||||
let default_call_expr = ecx.expr_call(new_decl_span, default_call_expr, thin_vec![]);
|
||||
body.stmts.push(ecx.stmt_expr(default_call_expr));
|
||||
return body;
|
||||
}
|
||||
|
||||
let mut exprs: P<ast::Expr> = primal_call.clone();
|
||||
let mut exprs: P<ast::Expr> = primal_call;
|
||||
let d_ret_ty = match d_sig.decl.output {
|
||||
FnRetTy::Ty(ref ty) => ty.clone(),
|
||||
FnRetTy::Default(span) => {
|
||||
|
|
@ -622,7 +621,7 @@ mod llvm_enzyme {
|
|||
// type due to the Const return activity.
|
||||
exprs = ecx.expr_call(new_decl_span, bb_call_expr, thin_vec![exprs]);
|
||||
} else {
|
||||
let q = QSelf { ty: d_ret_ty.clone(), path_span: span, position: 0 };
|
||||
let q = QSelf { ty: d_ret_ty, path_span: span, position: 0 };
|
||||
let y =
|
||||
ExprKind::Path(Some(P(q)), ecx.path_ident(span, Ident::from_str("default")));
|
||||
let default_call_expr = ecx.expr(span, y);
|
||||
|
|
@ -640,8 +639,7 @@ mod llvm_enzyme {
|
|||
let mut exprs2 = thin_vec![exprs];
|
||||
for arg in args.iter().skip(1) {
|
||||
let arg = arg.kind.is_simple_path().unwrap();
|
||||
let sl: Vec<Symbol> = vec![arg, kw::Default];
|
||||
let tmp = ecx.def_site_path(&sl);
|
||||
let tmp = ecx.def_site_path(&[arg, kw::Default]);
|
||||
let default_call_expr = ecx.expr_path(ecx.path(span, tmp));
|
||||
let default_call_expr =
|
||||
ecx.expr_call(new_decl_span, default_call_expr, thin_vec![]);
|
||||
|
|
|
|||
|
|
@ -1,13 +1,4 @@
|
|||
#![feature(
|
||||
no_core,
|
||||
lang_items,
|
||||
never_type,
|
||||
linkage,
|
||||
extern_types,
|
||||
naked_functions,
|
||||
thread_local,
|
||||
repr_simd
|
||||
)]
|
||||
#![feature(no_core, lang_items, never_type, linkage, extern_types, thread_local, repr_simd)]
|
||||
#![no_core]
|
||||
#![allow(dead_code, non_camel_case_types, internal_features)]
|
||||
|
||||
|
|
@ -387,11 +378,9 @@ global_asm! {
|
|||
}
|
||||
|
||||
#[cfg(all(not(jit), target_arch = "x86_64"))]
|
||||
#[naked]
|
||||
#[unsafe(naked)]
|
||||
extern "C" fn naked_test() {
|
||||
unsafe {
|
||||
naked_asm!("ret");
|
||||
}
|
||||
naked_asm!("ret")
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
|
|
|
|||
|
|
@ -447,9 +447,14 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
m_len == v_len,
|
||||
InvalidMonomorphization::MismatchedLengths { span, name, m_len, v_len }
|
||||
);
|
||||
// TODO: also support unsigned integers.
|
||||
match *m_elem_ty.kind() {
|
||||
ty::Int(_) => {}
|
||||
_ => return_error!(InvalidMonomorphization::MaskType { span, name, ty: m_elem_ty }),
|
||||
_ => return_error!(InvalidMonomorphization::MaskWrongElementType {
|
||||
span,
|
||||
name,
|
||||
ty: m_elem_ty
|
||||
}),
|
||||
}
|
||||
return Ok(bx.vector_select(args[0].immediate(), args[1].immediate(), args[2].immediate()));
|
||||
}
|
||||
|
|
@ -991,19 +996,15 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
assert_eq!(pointer_count - 1, ptr_count(element_ty0));
|
||||
assert_eq!(underlying_ty, non_ptr(element_ty0));
|
||||
|
||||
// The element type of the third argument must be a signed integer type of any width:
|
||||
// The element type of the third argument must be an integer type of any width:
|
||||
// TODO: also support unsigned integers.
|
||||
let (_, element_ty2) = arg_tys[2].simd_size_and_type(bx.tcx());
|
||||
match *element_ty2.kind() {
|
||||
ty::Int(_) => (),
|
||||
_ => {
|
||||
require!(
|
||||
false,
|
||||
InvalidMonomorphization::ThirdArgElementType {
|
||||
span,
|
||||
name,
|
||||
expected_element: element_ty2,
|
||||
third_arg: arg_tys[2]
|
||||
}
|
||||
InvalidMonomorphization::MaskWrongElementType { span, name, ty: element_ty2 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1109,17 +1110,13 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
assert_eq!(underlying_ty, non_ptr(element_ty0));
|
||||
|
||||
// The element type of the third argument must be a signed integer type of any width:
|
||||
// TODO: also support unsigned integers.
|
||||
match *element_ty2.kind() {
|
||||
ty::Int(_) => (),
|
||||
_ => {
|
||||
require!(
|
||||
false,
|
||||
InvalidMonomorphization::ThirdArgElementType {
|
||||
span,
|
||||
name,
|
||||
expected_element: element_ty2,
|
||||
third_arg: arg_tys[2]
|
||||
}
|
||||
InvalidMonomorphization::MaskWrongElementType { span, name, ty: element_ty2 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1184,18 +1184,6 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
}};
|
||||
}
|
||||
|
||||
/// Returns the bitwidth of the `$ty` argument if it is an `Int` type.
|
||||
macro_rules! require_int_ty {
|
||||
($ty: expr, $diag: expr) => {
|
||||
match $ty {
|
||||
ty::Int(i) => i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size.bits()),
|
||||
_ => {
|
||||
return_error!($diag);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns the bitwidth of the `$ty` argument if it is an `Int` or `Uint` type.
|
||||
macro_rules! require_int_or_uint_ty {
|
||||
($ty: expr, $diag: expr) => {
|
||||
|
|
@ -1485,9 +1473,9 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
m_len == v_len,
|
||||
InvalidMonomorphization::MismatchedLengths { span, name, m_len, v_len }
|
||||
);
|
||||
let in_elem_bitwidth = require_int_ty!(
|
||||
let in_elem_bitwidth = require_int_or_uint_ty!(
|
||||
m_elem_ty.kind(),
|
||||
InvalidMonomorphization::MaskType { span, name, ty: m_elem_ty }
|
||||
InvalidMonomorphization::MaskWrongElementType { span, name, ty: m_elem_ty }
|
||||
);
|
||||
let m_i1s = vector_mask_to_bitmask(bx, args[0].immediate(), in_elem_bitwidth, m_len);
|
||||
return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate()));
|
||||
|
|
@ -1508,7 +1496,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
// Integer vector <i{in_bitwidth} x in_len>:
|
||||
let in_elem_bitwidth = require_int_or_uint_ty!(
|
||||
in_elem.kind(),
|
||||
InvalidMonomorphization::VectorArgument { span, name, in_ty, in_elem }
|
||||
InvalidMonomorphization::MaskWrongElementType { span, name, ty: in_elem }
|
||||
);
|
||||
|
||||
let i1xn = vector_mask_to_bitmask(bx, args[0].immediate(), in_elem_bitwidth, in_len);
|
||||
|
|
@ -1732,14 +1720,9 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
}
|
||||
);
|
||||
|
||||
let mask_elem_bitwidth = require_int_ty!(
|
||||
let mask_elem_bitwidth = require_int_or_uint_ty!(
|
||||
element_ty2.kind(),
|
||||
InvalidMonomorphization::ThirdArgElementType {
|
||||
span,
|
||||
name,
|
||||
expected_element: element_ty2,
|
||||
third_arg: arg_tys[2]
|
||||
}
|
||||
InvalidMonomorphization::MaskWrongElementType { span, name, ty: element_ty2 }
|
||||
);
|
||||
|
||||
// Alignment of T, must be a constant integer value:
|
||||
|
|
@ -1834,14 +1817,9 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
}
|
||||
);
|
||||
|
||||
let m_elem_bitwidth = require_int_ty!(
|
||||
let m_elem_bitwidth = require_int_or_uint_ty!(
|
||||
mask_elem.kind(),
|
||||
InvalidMonomorphization::ThirdArgElementType {
|
||||
span,
|
||||
name,
|
||||
expected_element: values_elem,
|
||||
third_arg: mask_ty,
|
||||
}
|
||||
InvalidMonomorphization::MaskWrongElementType { span, name, ty: mask_elem }
|
||||
);
|
||||
|
||||
let mask = vector_mask_to_bitmask(bx, args[0].immediate(), m_elem_bitwidth, mask_len);
|
||||
|
|
@ -1924,14 +1902,9 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
}
|
||||
);
|
||||
|
||||
let m_elem_bitwidth = require_int_ty!(
|
||||
let m_elem_bitwidth = require_int_or_uint_ty!(
|
||||
mask_elem.kind(),
|
||||
InvalidMonomorphization::ThirdArgElementType {
|
||||
span,
|
||||
name,
|
||||
expected_element: values_elem,
|
||||
third_arg: mask_ty,
|
||||
}
|
||||
InvalidMonomorphization::MaskWrongElementType { span, name, ty: mask_elem }
|
||||
);
|
||||
|
||||
let mask = vector_mask_to_bitmask(bx, args[0].immediate(), m_elem_bitwidth, mask_len);
|
||||
|
|
@ -2019,15 +1992,10 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
}
|
||||
);
|
||||
|
||||
// The element type of the third argument must be a signed integer type of any width:
|
||||
let mask_elem_bitwidth = require_int_ty!(
|
||||
// The element type of the third argument must be an integer type of any width:
|
||||
let mask_elem_bitwidth = require_int_or_uint_ty!(
|
||||
element_ty2.kind(),
|
||||
InvalidMonomorphization::ThirdArgElementType {
|
||||
span,
|
||||
name,
|
||||
expected_element: element_ty2,
|
||||
third_arg: arg_tys[2]
|
||||
}
|
||||
InvalidMonomorphization::MaskWrongElementType { span, name, ty: element_ty2 }
|
||||
);
|
||||
|
||||
// Alignment of T, must be a constant integer value:
|
||||
|
|
|
|||
|
|
@ -125,8 +125,7 @@ codegen_ssa_invalid_monomorphization_inserted_type = invalid monomorphization of
|
|||
|
||||
codegen_ssa_invalid_monomorphization_invalid_bitmask = invalid monomorphization of `{$name}` intrinsic: invalid bitmask `{$mask_ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]`
|
||||
|
||||
codegen_ssa_invalid_monomorphization_mask_type = invalid monomorphization of `{$name}` intrinsic: found mask element type is `{$ty}`, expected a signed integer type
|
||||
.note = the mask may be widened, which only has the correct behavior for signed integers
|
||||
codegen_ssa_invalid_monomorphization_mask_wrong_element_type = invalid monomorphization of `{$name}` intrinsic: expected mask element type to be an integer, found `{$ty}`
|
||||
|
||||
codegen_ssa_invalid_monomorphization_mismatched_lengths = invalid monomorphization of `{$name}` intrinsic: mismatched lengths: mask length `{$m_len}` != other vector length `{$v_len}`
|
||||
|
||||
|
|
@ -158,8 +157,6 @@ codegen_ssa_invalid_monomorphization_simd_shuffle = invalid monomorphization of
|
|||
|
||||
codegen_ssa_invalid_monomorphization_simd_third = invalid monomorphization of `{$name}` intrinsic: expected SIMD third type, found non-SIMD `{$ty}`
|
||||
|
||||
codegen_ssa_invalid_monomorphization_third_arg_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of third argument `{$third_arg}` to be a signed integer type
|
||||
|
||||
codegen_ssa_invalid_monomorphization_third_argument_length = invalid monomorphization of `{$name}` intrinsic: expected third argument with length {$in_len} (same as input type `{$in_ty}`), found `{$arg_ty}` with length {$out_len}
|
||||
|
||||
codegen_ssa_invalid_monomorphization_unrecognized_intrinsic = invalid monomorphization of `{$name}` intrinsic: unrecognized intrinsic `{$name}`
|
||||
|
|
@ -172,8 +169,6 @@ codegen_ssa_invalid_monomorphization_unsupported_symbol = invalid monomorphizati
|
|||
|
||||
codegen_ssa_invalid_monomorphization_unsupported_symbol_of_size = invalid monomorphization of `{$name}` intrinsic: unsupported {$symbol} from `{$in_ty}` with element `{$in_elem}` of size `{$size}` to `{$ret_ty}`
|
||||
|
||||
codegen_ssa_invalid_monomorphization_vector_argument = invalid monomorphization of `{$name}` intrinsic: vector argument `{$in_ty}`'s element type `{$in_elem}`, expected integer element type
|
||||
|
||||
codegen_ssa_invalid_no_sanitize = invalid argument for `no_sanitize`
|
||||
.note = expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread`
|
||||
|
||||
|
|
|
|||
|
|
@ -1037,24 +1037,14 @@ pub enum InvalidMonomorphization<'tcx> {
|
|||
v_len: u64,
|
||||
},
|
||||
|
||||
#[diag(codegen_ssa_invalid_monomorphization_mask_type, code = E0511)]
|
||||
#[note]
|
||||
MaskType {
|
||||
#[diag(codegen_ssa_invalid_monomorphization_mask_wrong_element_type, code = E0511)]
|
||||
MaskWrongElementType {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
name: Symbol,
|
||||
ty: Ty<'tcx>,
|
||||
},
|
||||
|
||||
#[diag(codegen_ssa_invalid_monomorphization_vector_argument, code = E0511)]
|
||||
VectorArgument {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
name: Symbol,
|
||||
in_ty: Ty<'tcx>,
|
||||
in_elem: Ty<'tcx>,
|
||||
},
|
||||
|
||||
#[diag(codegen_ssa_invalid_monomorphization_cannot_return, code = E0511)]
|
||||
CannotReturn {
|
||||
#[primary_span]
|
||||
|
|
@ -1077,15 +1067,6 @@ pub enum InvalidMonomorphization<'tcx> {
|
|||
mutability: ExpectedPointerMutability,
|
||||
},
|
||||
|
||||
#[diag(codegen_ssa_invalid_monomorphization_third_arg_element_type, code = E0511)]
|
||||
ThirdArgElementType {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
name: Symbol,
|
||||
expected_element: Ty<'tcx>,
|
||||
third_arg: Ty<'tcx>,
|
||||
},
|
||||
|
||||
#[diag(codegen_ssa_invalid_monomorphization_unsupported_symbol_of_size, code = E0511)]
|
||||
UnsupportedSymbolOfSize {
|
||||
#[primary_span]
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ Erroneous code example:
|
|||
|
||||
```compile_fail,E0736
|
||||
#[inline]
|
||||
#[naked]
|
||||
#[unsafe(naked)]
|
||||
fn foo() {}
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@ An unsupported naked function definition.
|
|||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0787
|
||||
#![feature(naked_functions)]
|
||||
|
||||
#[naked]
|
||||
#[unsafe(naked)]
|
||||
pub extern "C" fn f() -> u32 {
|
||||
42
|
||||
}
|
||||
|
|
|
|||
|
|
@ -237,10 +237,7 @@ impl<'a> StripUnconfigured<'a> {
|
|||
inner = self.configure_tokens(&inner);
|
||||
Some(AttrTokenTree::Delimited(sp, spacing, delim, inner))
|
||||
}
|
||||
AttrTokenTree::Token(
|
||||
Token { kind: TokenKind::OpenDelim(_) | TokenKind::CloseDelim(_), .. },
|
||||
_,
|
||||
) => {
|
||||
AttrTokenTree::Token(Token { kind, .. }, _) if kind.is_delim() => {
|
||||
panic!("Should be `AttrTokenTree::Delimited`, not delim tokens: {:?}", tree);
|
||||
}
|
||||
AttrTokenTree::Token(token, spacing) => Some(AttrTokenTree::Token(token, spacing)),
|
||||
|
|
|
|||
|
|
@ -7,13 +7,12 @@ use std::{iter, mem};
|
|||
use rustc_ast as ast;
|
||||
use rustc_ast::mut_visit::*;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, Delimiter};
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::visit::{self, AssocCtxt, Visitor, VisitorResult, try_visit, walk_list};
|
||||
use rustc_ast::{
|
||||
AssocItemKind, AstNodeWrapper, AttrArgs, AttrStyle, AttrVec, ExprKind, ForeignItemKind,
|
||||
HasAttrs, HasNodeId, Inline, ItemKind, MacStmtStyle, MetaItemInner, MetaItemKind, ModKind,
|
||||
NodeId, PatKind, StmtKind, TyKind,
|
||||
NodeId, PatKind, StmtKind, TyKind, token,
|
||||
};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
|
||||
|
|
@ -1004,7 +1003,7 @@ pub fn parse_ast_fragment<'a>(
|
|||
AstFragmentKind::Stmts => {
|
||||
let mut stmts = SmallVec::new();
|
||||
// Won't make progress on a `}`.
|
||||
while this.token != token::Eof && this.token != token::CloseDelim(Delimiter::Brace) {
|
||||
while this.token != token::Eof && this.token != token::CloseBrace {
|
||||
if let Some(stmt) = this.parse_full_stmt(AttemptLocalParseRecovery::Yes)? {
|
||||
stmts.push(stmt);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use rustc_ast::token::{self, Delimiter, Token, TokenKind};
|
||||
use rustc_ast::token::{self, Token};
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_errors::{Applicability, Diag, DiagCtxtHandle, DiagMessage};
|
||||
use rustc_macros::Subdiagnostic;
|
||||
|
|
@ -66,8 +66,8 @@ pub(super) fn failed_to_match_macro(
|
|||
}
|
||||
|
||||
if let MatcherLoc::Token { token: expected_token } = &remaining_matcher
|
||||
&& (matches!(expected_token.kind, TokenKind::OpenDelim(Delimiter::Invisible(_)))
|
||||
|| matches!(token.kind, TokenKind::OpenDelim(Delimiter::Invisible(_))))
|
||||
&& (matches!(expected_token.kind, token::OpenInvisible(_))
|
||||
|| matches!(token.kind, token::OpenInvisible(_)))
|
||||
{
|
||||
err.note("captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens");
|
||||
err.note("see <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment> for more information");
|
||||
|
|
|
|||
|
|
@ -182,8 +182,8 @@ pub(super) fn compute_locs(matcher: &[TokenTree]) -> Vec<MatcherLoc> {
|
|||
locs.push(MatcherLoc::Token { token: *token });
|
||||
}
|
||||
TokenTree::Delimited(span, _, delimited) => {
|
||||
let open_token = Token::new(token::OpenDelim(delimited.delim), span.open);
|
||||
let close_token = Token::new(token::CloseDelim(delimited.delim), span.close);
|
||||
let open_token = Token::new(delimited.delim.as_open_token_kind(), span.open);
|
||||
let close_token = Token::new(delimited.delim.as_close_token_kind(), span.close);
|
||||
|
||||
locs.push(MatcherLoc::Delimited);
|
||||
locs.push(MatcherLoc::Token { token: open_token });
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use std::{mem, slice};
|
|||
use ast::token::IdentIsRaw;
|
||||
use rustc_ast::token::NtPatKind::*;
|
||||
use rustc_ast::token::TokenKind::*;
|
||||
use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind};
|
||||
use rustc_ast::token::{self, NonterminalKind, Token, TokenKind};
|
||||
use rustc_ast::tokenstream::{DelimSpan, TokenStream};
|
||||
use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId};
|
||||
use rustc_ast_pretty::pprust;
|
||||
|
|
@ -784,7 +784,7 @@ impl<'tt> FirstSets<'tt> {
|
|||
TokenTree::Delimited(span, _, delimited) => {
|
||||
build_recur(sets, &delimited.tts);
|
||||
first.replace_with(TtHandle::from_token_kind(
|
||||
token::OpenDelim(delimited.delim),
|
||||
delimited.delim.as_open_token_kind(),
|
||||
span.open,
|
||||
));
|
||||
}
|
||||
|
|
@ -852,7 +852,7 @@ impl<'tt> FirstSets<'tt> {
|
|||
}
|
||||
TokenTree::Delimited(span, _, delimited) => {
|
||||
first.add_one(TtHandle::from_token_kind(
|
||||
token::OpenDelim(delimited.delim),
|
||||
delimited.delim.as_open_token_kind(),
|
||||
span.open,
|
||||
));
|
||||
return first;
|
||||
|
|
@ -1099,7 +1099,7 @@ fn check_matcher_core<'tt>(
|
|||
}
|
||||
TokenTree::Delimited(span, _, d) => {
|
||||
let my_suffix = TokenSet::singleton(TtHandle::from_token_kind(
|
||||
token::CloseDelim(d.delim),
|
||||
d.delim.as_close_token_kind(),
|
||||
span.close,
|
||||
));
|
||||
check_matcher_core(sess, node_id, first_sets, &d.tts, &my_suffix)?;
|
||||
|
|
@ -1299,7 +1299,9 @@ enum IsInFollow {
|
|||
fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
|
||||
use mbe::TokenTree;
|
||||
|
||||
if let TokenTree::Token(Token { kind: token::CloseDelim(_), .. }) = *tok {
|
||||
if let TokenTree::Token(Token { kind, .. }) = tok
|
||||
&& kind.close_delim().is_some()
|
||||
{
|
||||
// closing a token tree can never be matched by any fragment;
|
||||
// iow, we always require that `(` and `)` match, etc.
|
||||
IsInFollow::Yes
|
||||
|
|
@ -1358,16 +1360,8 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
|
|||
];
|
||||
match tok {
|
||||
TokenTree::Token(token) => match token.kind {
|
||||
OpenDelim(Delimiter::Brace)
|
||||
| OpenDelim(Delimiter::Bracket)
|
||||
| Comma
|
||||
| FatArrow
|
||||
| Colon
|
||||
| Eq
|
||||
| Gt
|
||||
| Shr
|
||||
| Semi
|
||||
| Or => IsInFollow::Yes,
|
||||
OpenBrace | OpenBracket | Comma | FatArrow | Colon | Eq | Gt | Shr
|
||||
| Semi | Or => IsInFollow::Yes,
|
||||
Ident(name, IdentIsRaw::No) if name == kw::As || name == kw::Where => {
|
||||
IsInFollow::Yes
|
||||
}
|
||||
|
|
|
|||
|
|
@ -181,7 +181,10 @@ fn parse_tree<'a>(
|
|||
if delim != Delimiter::Parenthesis {
|
||||
span_dollar_dollar_or_metavar_in_the_lhs_err(
|
||||
sess,
|
||||
&Token { kind: token::OpenDelim(delim), span: delim_span.entire() },
|
||||
&Token {
|
||||
kind: delim.as_open_token_kind(),
|
||||
span: delim_span.entire(),
|
||||
},
|
||||
);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -217,7 +220,8 @@ fn parse_tree<'a>(
|
|||
}
|
||||
Delimiter::Parenthesis => {}
|
||||
_ => {
|
||||
let token = pprust::token_kind_to_string(&token::OpenDelim(delim));
|
||||
let token =
|
||||
pprust::token_kind_to_string(&delim.as_open_token_kind());
|
||||
sess.dcx().emit_err(errors::ExpectedParenOrBrace {
|
||||
span: delim_span.entire(),
|
||||
token,
|
||||
|
|
|
|||
|
|
@ -308,8 +308,8 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
|
|||
}));
|
||||
}
|
||||
|
||||
OpenDelim(..) | CloseDelim(..) => unreachable!(),
|
||||
Eof => unreachable!(),
|
||||
OpenParen | CloseParen | OpenBrace | CloseBrace | OpenBracket | CloseBracket
|
||||
| OpenInvisible(_) | CloseInvisible(_) | Eof => unreachable!(),
|
||||
}
|
||||
}
|
||||
trees
|
||||
|
|
|
|||
|
|
@ -300,6 +300,8 @@ declare_features! (
|
|||
/// Allows patterns with concurrent by-move and by-ref bindings.
|
||||
/// For example, you can write `Foo(a, ref b)` where `a` is by-move and `b` is by-ref.
|
||||
(accepted, move_ref_pattern, "1.49.0", Some(68354)),
|
||||
/// Allows using `#[naked]` on functions.
|
||||
(accepted, naked_functions, "CURRENT_RUSTC_VERSION", Some(90957)),
|
||||
/// Allows specifying modifiers in the link attribute: `#[link(modifiers = "...")]`
|
||||
(accepted, native_link_modifiers, "1.61.0", Some(81490)),
|
||||
/// Allows specifying the bundle link modifier
|
||||
|
|
|
|||
|
|
@ -443,6 +443,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
ungated!(unsafe(Edition2024) no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
|
||||
ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing, EncodeCrossCrate::No),
|
||||
ungated!(link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding, EncodeCrossCrate::Yes),
|
||||
ungated!(unsafe naked, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
|
||||
|
||||
// Limits:
|
||||
ungated!(
|
||||
|
|
@ -515,12 +516,6 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
// Unstable attributes:
|
||||
// ==========================================================================
|
||||
|
||||
// Linking:
|
||||
gated!(
|
||||
naked, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No,
|
||||
naked_functions, experimental!(naked)
|
||||
),
|
||||
|
||||
// Testing:
|
||||
gated!(
|
||||
test_runner, CrateLevel, template!(List: "path"), ErrorFollowing,
|
||||
|
|
@ -676,14 +671,6 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
"`rustc_never_type_options` is used to experiment with never type fallback and work on \
|
||||
never type stabilization, and will never be stable"
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_macro_edition_2021,
|
||||
Normal,
|
||||
template!(Word),
|
||||
ErrorFollowing,
|
||||
EncodeCrossCrate::No,
|
||||
"makes spans in this macro edition 2021"
|
||||
),
|
||||
|
||||
// ==========================================================================
|
||||
// Internal attributes: Runtime related:
|
||||
|
|
|
|||
|
|
@ -563,8 +563,6 @@ declare_features! (
|
|||
(unstable, must_not_suspend, "1.57.0", Some(83310)),
|
||||
/// Allows `mut ref` and `mut ref mut` identifier patterns.
|
||||
(incomplete, mut_ref, "1.79.0", Some(123076)),
|
||||
/// Allows using `#[naked]` on functions.
|
||||
(unstable, naked_functions, "1.9.0", Some(90957)),
|
||||
/// Allows using `#[naked]` on `extern "Rust"` functions.
|
||||
(unstable, naked_functions_rustic_abi, "CURRENT_RUSTC_VERSION", Some(138997)),
|
||||
/// Allows using `#[target_feature(enable = "...")]` on `#[naked]` on functions.
|
||||
|
|
|
|||
|
|
@ -486,15 +486,15 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
|
|||
let items: &AssocItems = self.tcx.associated_items(self.def_id);
|
||||
items
|
||||
.in_definition_order()
|
||||
.filter(|item| item.is_type())
|
||||
.filter(|item| {
|
||||
!self
|
||||
.gen_args
|
||||
.constraints
|
||||
.iter()
|
||||
.any(|constraint| constraint.ident.name == item.name())
|
||||
item.is_type()
|
||||
&& !item.is_impl_trait_in_trait()
|
||||
&& !self
|
||||
.gen_args
|
||||
.constraints
|
||||
.iter()
|
||||
.any(|constraint| constraint.ident.name == item.name())
|
||||
})
|
||||
.filter(|item| !item.is_impl_trait_in_trait())
|
||||
.map(|item| self.tcx.item_ident(item.def_id).to_string())
|
||||
.collect()
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ use rustc_errors::codes::*;
|
|||
use rustc_errors::{
|
||||
Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, struct_span_code_err,
|
||||
};
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Namespace, Res};
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::{self as hir, AnonConst, GenericArg, GenericArgs, HirId};
|
||||
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
||||
|
|
@ -1731,9 +1731,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
tcx.associated_items(*trait_def_id)
|
||||
.in_definition_order()
|
||||
.any(|i| {
|
||||
i.namespace() == Namespace::TypeNS
|
||||
i.is_type()
|
||||
&& !i.is_impl_trait_in_trait()
|
||||
&& i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
|
||||
&& i.is_type()
|
||||
})
|
||||
// Consider only accessible traits
|
||||
&& tcx.visibility(*trait_def_id)
|
||||
|
|
|
|||
|
|
@ -234,7 +234,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// us do better coercions than we would be able to do otherwise,
|
||||
// particularly for things like `String + &String`.
|
||||
let rhs_ty_var = self.next_ty_var(rhs_expr.span);
|
||||
|
||||
let result = self.lookup_op_method(
|
||||
(lhs_expr, lhs_ty),
|
||||
Some((rhs_expr, rhs_ty_var)),
|
||||
|
|
@ -698,6 +697,57 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
let lhs_name_str = match lhs_expr.kind {
|
||||
hir::ExprKind::Path(hir::QPath::Resolved(_, path)) => {
|
||||
path.segments.last().map_or("_".to_string(), |s| s.ident.to_string())
|
||||
}
|
||||
_ => self
|
||||
.tcx
|
||||
.sess
|
||||
.source_map()
|
||||
.span_to_snippet(lhs_expr.span)
|
||||
.unwrap_or("_".to_string()),
|
||||
};
|
||||
|
||||
if op.span().can_be_used_for_suggestions() {
|
||||
match op {
|
||||
Op::AssignOp(Spanned { node: hir::AssignOpKind::AddAssign, .. })
|
||||
if lhs_ty.is_raw_ptr() && rhs_ty.is_integral() =>
|
||||
{
|
||||
err.multipart_suggestion(
|
||||
"consider using `add` or `wrapping_add` to do pointer arithmetic",
|
||||
vec![
|
||||
(lhs_expr.span.shrink_to_lo(), format!("{} = ", lhs_name_str)),
|
||||
(
|
||||
lhs_expr.span.between(rhs_expr.span),
|
||||
".wrapping_add(".to_owned(),
|
||||
),
|
||||
(rhs_expr.span.shrink_to_hi(), ")".to_owned()),
|
||||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
Op::AssignOp(Spanned { node: hir::AssignOpKind::SubAssign, .. }) => {
|
||||
if lhs_ty.is_raw_ptr() && rhs_ty.is_integral() {
|
||||
err.multipart_suggestion(
|
||||
"consider using `sub` or `wrapping_sub` to do pointer arithmetic",
|
||||
vec![
|
||||
(lhs_expr.span.shrink_to_lo(), format!("{} = ", lhs_name_str)),
|
||||
(
|
||||
lhs_expr.span.between(rhs_expr.span),
|
||||
".wrapping_sub(".to_owned(),
|
||||
|
||||
),
|
||||
(rhs_expr.span.shrink_to_hi(), ")".to_owned()),
|
||||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let reported = err.emit();
|
||||
Ty::new_error(self.tcx, reported)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -427,12 +427,21 @@ impl<'a> CrateLocator<'a> {
|
|||
|
||||
let (rlibs, rmetas, dylibs) =
|
||||
candidates.entry(hash.to_string()).or_default();
|
||||
let path =
|
||||
try_canonicalize(&spf.path).unwrap_or_else(|_| spf.path.to_path_buf());
|
||||
if seen_paths.contains(&path) {
|
||||
continue;
|
||||
};
|
||||
seen_paths.insert(path.clone());
|
||||
{
|
||||
// As a perforamnce optimisation we canonicalize the path and skip
|
||||
// ones we've already seeen. This allows us to ignore crates
|
||||
// we know are exactual equal to ones we've already found.
|
||||
// Going to the same crate through different symlinks does not change the result.
|
||||
let path = try_canonicalize(&spf.path)
|
||||
.unwrap_or_else(|_| spf.path.to_path_buf());
|
||||
if seen_paths.contains(&path) {
|
||||
continue;
|
||||
};
|
||||
seen_paths.insert(path);
|
||||
}
|
||||
// Use the original path (potentially with unresolved symlinks),
|
||||
// filesystem code should not care, but this is nicer for diagnostics.
|
||||
let path = spf.path.to_path_buf();
|
||||
match kind {
|
||||
CrateFlavor::Rlib => rlibs.insert(path, search_path.kind),
|
||||
CrateFlavor::Rmeta => rmetas.insert(path, search_path.kind),
|
||||
|
|
|
|||
|
|
@ -246,6 +246,8 @@ impl AssocItems {
|
|||
}
|
||||
|
||||
/// Returns an iterator over all associated items with the given name, ignoring hygiene.
|
||||
///
|
||||
/// Panics if `name.is_empty()` returns `true`.
|
||||
pub fn filter_by_name_unhygienic(
|
||||
&self,
|
||||
name: Symbol,
|
||||
|
|
|
|||
|
|
@ -1530,7 +1530,7 @@ fn build_scope_drops<'tcx>(
|
|||
// path, then don't generate the drop. (We only take this into
|
||||
// account for non-unwind paths so as not to disturb the
|
||||
// caching mechanism.)
|
||||
if scope.moved_locals.iter().any(|&o| o == local) {
|
||||
if scope.moved_locals.contains(&local) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -564,13 +564,17 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
ExprKind::InlineAsm(box InlineAsmExpr {
|
||||
asm_macro: AsmMacro::Asm | AsmMacro::NakedAsm,
|
||||
asm_macro: asm_macro @ (AsmMacro::Asm | AsmMacro::NakedAsm),
|
||||
ref operands,
|
||||
template: _,
|
||||
options: _,
|
||||
line_spans: _,
|
||||
}) => {
|
||||
self.requires_unsafe(expr.span, UseOfInlineAssembly);
|
||||
// The `naked` attribute and the `naked_asm!` block form one atomic unit of
|
||||
// unsafety, and `naked_asm!` does not itself need to be wrapped in an unsafe block.
|
||||
if let AsmMacro::Asm = asm_macro {
|
||||
self.requires_unsafe(expr.span, UseOfInlineAssembly);
|
||||
}
|
||||
|
||||
// For inline asm, do not use `walk_expr`, since we want to handle the label block
|
||||
// specially.
|
||||
|
|
|
|||
|
|
@ -254,8 +254,9 @@ where
|
|||
always_export_generics,
|
||||
);
|
||||
|
||||
// We can't differentiate something that got inlined.
|
||||
// We can't differentiate a function that got inlined.
|
||||
let autodiff_active = cfg!(llvm_enzyme)
|
||||
&& matches!(mono_item, MonoItem::Fn(_))
|
||||
&& cx
|
||||
.tcx
|
||||
.codegen_fn_attrs(mono_item.def_id())
|
||||
|
|
|
|||
|
|
@ -288,6 +288,21 @@ where
|
|||
) -> Vec<Candidate<I>>;
|
||||
}
|
||||
|
||||
/// Allows callers of `assemble_and_evaluate_candidates` to choose whether to limit
|
||||
/// candidate assembly to param-env and alias-bound candidates.
|
||||
///
|
||||
/// On top of being a micro-optimization, as it avoids doing unnecessary work when
|
||||
/// a param-env trait bound candidate shadows impls for normalization, this is also
|
||||
/// required to prevent query cycles due to RPITIT inference. See the issue at:
|
||||
/// <https://github.com/rust-lang/trait-system-refactor-initiative/issues/173>.
|
||||
pub(super) enum AssembleCandidatesFrom {
|
||||
All,
|
||||
/// Only assemble candidates from the environment and alias bounds, ignoring
|
||||
/// user-written and built-in impls. We only expect `ParamEnv` and `AliasBound`
|
||||
/// candidates to be assembled.
|
||||
EnvAndBounds,
|
||||
}
|
||||
|
||||
impl<D, I> EvalCtxt<'_, D>
|
||||
where
|
||||
D: SolverDelegate<Interner = I>,
|
||||
|
|
@ -296,6 +311,7 @@ where
|
|||
pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<D>>(
|
||||
&mut self,
|
||||
goal: Goal<I, G>,
|
||||
assemble_from: AssembleCandidatesFrom,
|
||||
) -> Vec<Candidate<I>> {
|
||||
let Ok(normalized_self_ty) =
|
||||
self.structurally_normalize_ty(goal.param_env, goal.predicate.self_ty())
|
||||
|
|
@ -322,16 +338,18 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
self.assemble_impl_candidates(goal, &mut candidates);
|
||||
|
||||
self.assemble_builtin_impl_candidates(goal, &mut candidates);
|
||||
|
||||
self.assemble_alias_bound_candidates(goal, &mut candidates);
|
||||
|
||||
self.assemble_object_bound_candidates(goal, &mut candidates);
|
||||
|
||||
self.assemble_param_env_candidates(goal, &mut candidates);
|
||||
|
||||
match assemble_from {
|
||||
AssembleCandidatesFrom::All => {
|
||||
self.assemble_impl_candidates(goal, &mut candidates);
|
||||
self.assemble_builtin_impl_candidates(goal, &mut candidates);
|
||||
self.assemble_object_bound_candidates(goal, &mut candidates);
|
||||
}
|
||||
AssembleCandidatesFrom::EnvAndBounds => {}
|
||||
}
|
||||
|
||||
candidates
|
||||
}
|
||||
|
||||
|
|
@ -754,6 +772,9 @@ where
|
|||
})
|
||||
}
|
||||
|
||||
/// Assemble and merge candidates for goals which are related to an underlying trait
|
||||
/// goal. Right now, this is normalizes-to and host effect goals.
|
||||
///
|
||||
/// We sadly can't simply take all possible candidates for normalization goals
|
||||
/// and check whether they result in the same constraints. We want to make sure
|
||||
/// that trying to normalize an alias doesn't result in constraints which aren't
|
||||
|
|
@ -782,47 +803,44 @@ where
|
|||
///
|
||||
/// See trait-system-refactor-initiative#124 for more details.
|
||||
#[instrument(level = "debug", skip(self, inject_normalize_to_rigid_candidate), ret)]
|
||||
pub(super) fn merge_candidates(
|
||||
pub(super) fn assemble_and_merge_candidates<G: GoalKind<D>>(
|
||||
&mut self,
|
||||
proven_via: Option<TraitGoalProvenVia>,
|
||||
candidates: Vec<Candidate<I>>,
|
||||
goal: Goal<I, G>,
|
||||
inject_normalize_to_rigid_candidate: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
|
||||
) -> QueryResult<I> {
|
||||
let Some(proven_via) = proven_via else {
|
||||
// We don't care about overflow. If proving the trait goal overflowed, then
|
||||
// it's enough to report an overflow error for that, we don't also have to
|
||||
// overflow during normalization.
|
||||
return Ok(self.make_ambiguous_response_no_constraints(MaybeCause::Ambiguity));
|
||||
//
|
||||
// We use `forced_ambiguity` here over `make_ambiguous_response_no_constraints`
|
||||
// because the former will also record a built-in candidate in the inspector.
|
||||
return self.forced_ambiguity(MaybeCause::Ambiguity).map(|cand| cand.result);
|
||||
};
|
||||
|
||||
match proven_via {
|
||||
TraitGoalProvenVia::ParamEnv | TraitGoalProvenVia::AliasBound => {
|
||||
let mut considered_candidates = Vec::new();
|
||||
considered_candidates.extend(
|
||||
candidates
|
||||
.iter()
|
||||
.filter(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
|
||||
.map(|c| c.result),
|
||||
);
|
||||
|
||||
// Even when a trait bound has been proven using a where-bound, we
|
||||
// still need to consider alias-bounds for normalization, see
|
||||
// tests/ui/next-solver/alias-bound-shadowed-by-env.rs.
|
||||
//
|
||||
// `tests/ui/next-solver/alias-bound-shadowed-by-env.rs`.
|
||||
let candidates_from_env_and_bounds: Vec<_> = self
|
||||
.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::EnvAndBounds);
|
||||
|
||||
// We still need to prefer where-bounds over alias-bounds however.
|
||||
// See tests/ui/winnowing/norm-where-bound-gt-alias-bound.rs.
|
||||
//
|
||||
// FIXME(const_trait_impl): should this behavior also be used by
|
||||
// constness checking. Doing so is *at least theoretically* breaking,
|
||||
// see github.com/rust-lang/rust/issues/133044#issuecomment-2500709754
|
||||
if considered_candidates.is_empty() {
|
||||
considered_candidates.extend(
|
||||
candidates
|
||||
.iter()
|
||||
.filter(|c| matches!(c.source, CandidateSource::AliasBound))
|
||||
.map(|c| c.result),
|
||||
);
|
||||
}
|
||||
// See `tests/ui/winnowing/norm-where-bound-gt-alias-bound.rs`.
|
||||
let mut considered_candidates: Vec<_> = if candidates_from_env_and_bounds
|
||||
.iter()
|
||||
.any(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
|
||||
{
|
||||
candidates_from_env_and_bounds
|
||||
.into_iter()
|
||||
.filter(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
|
||||
.map(|c| c.result)
|
||||
.collect()
|
||||
} else {
|
||||
candidates_from_env_and_bounds.into_iter().map(|c| c.result).collect()
|
||||
};
|
||||
|
||||
// If the trait goal has been proven by using the environment, we want to treat
|
||||
// aliases as rigid if there are no applicable projection bounds in the environment.
|
||||
|
|
@ -839,6 +857,9 @@ where
|
|||
}
|
||||
}
|
||||
TraitGoalProvenVia::Misc => {
|
||||
let candidates =
|
||||
self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All);
|
||||
|
||||
// Prefer "orphaned" param-env normalization predicates, which are used
|
||||
// (for example, and ideally only) when proving item bounds for an impl.
|
||||
let candidates_from_env: Vec<_> = candidates
|
||||
|
|
|
|||
|
|
@ -399,12 +399,11 @@ where
|
|||
&mut self,
|
||||
goal: Goal<I, ty::HostEffectPredicate<I>>,
|
||||
) -> QueryResult<I> {
|
||||
let candidates = self.assemble_and_evaluate_candidates(goal);
|
||||
let (_, proven_via) = self.probe(|_| ProbeKind::ShadowedEnvProbing).enter(|ecx| {
|
||||
let trait_goal: Goal<I, ty::TraitPredicate<I>> =
|
||||
goal.with(ecx.cx(), goal.predicate.trait_ref);
|
||||
ecx.compute_trait_goal(trait_goal)
|
||||
})?;
|
||||
self.merge_candidates(proven_via, candidates, |_ecx| Err(NoSolution))
|
||||
self.assemble_and_merge_candidates(proven_via, goal, |_ecx| Err(NoSolution))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,14 +32,13 @@ where
|
|||
let cx = self.cx();
|
||||
match goal.predicate.alias.kind(cx) {
|
||||
ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => {
|
||||
let candidates = self.assemble_and_evaluate_candidates(goal);
|
||||
let trait_ref = goal.predicate.alias.trait_ref(cx);
|
||||
let (_, proven_via) =
|
||||
self.probe(|_| ProbeKind::ShadowedEnvProbing).enter(|ecx| {
|
||||
let trait_goal: Goal<I, ty::TraitPredicate<I>> = goal.with(cx, trait_ref);
|
||||
ecx.compute_trait_goal(trait_goal)
|
||||
})?;
|
||||
self.merge_candidates(proven_via, candidates, |ecx| {
|
||||
self.assemble_and_merge_candidates(proven_via, goal, |ecx| {
|
||||
ecx.probe(|&result| ProbeKind::RigidAlias { result }).enter(|this| {
|
||||
this.structurally_instantiate_normalizes_to_term(
|
||||
goal,
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use tracing::{instrument, trace};
|
|||
|
||||
use crate::delegate::SolverDelegate;
|
||||
use crate::solve::assembly::structural_traits::{self, AsyncCallableRelevantTypes};
|
||||
use crate::solve::assembly::{self, Candidate};
|
||||
use crate::solve::assembly::{self, AssembleCandidatesFrom, Candidate};
|
||||
use crate::solve::inspect::ProbeKind;
|
||||
use crate::solve::{
|
||||
BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause,
|
||||
|
|
@ -1365,7 +1365,7 @@ where
|
|||
&mut self,
|
||||
goal: Goal<I, TraitPredicate<I>>,
|
||||
) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
|
||||
let candidates = self.assemble_and_evaluate_candidates(goal);
|
||||
let candidates = self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All);
|
||||
self.merge_trait_candidates(goal, candidates)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -371,12 +371,12 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
|
|||
rustc_lexer::TokenKind::Semi => token::Semi,
|
||||
rustc_lexer::TokenKind::Comma => token::Comma,
|
||||
rustc_lexer::TokenKind::Dot => token::Dot,
|
||||
rustc_lexer::TokenKind::OpenParen => token::OpenDelim(Delimiter::Parenthesis),
|
||||
rustc_lexer::TokenKind::CloseParen => token::CloseDelim(Delimiter::Parenthesis),
|
||||
rustc_lexer::TokenKind::OpenBrace => token::OpenDelim(Delimiter::Brace),
|
||||
rustc_lexer::TokenKind::CloseBrace => token::CloseDelim(Delimiter::Brace),
|
||||
rustc_lexer::TokenKind::OpenBracket => token::OpenDelim(Delimiter::Bracket),
|
||||
rustc_lexer::TokenKind::CloseBracket => token::CloseDelim(Delimiter::Bracket),
|
||||
rustc_lexer::TokenKind::OpenParen => token::OpenParen,
|
||||
rustc_lexer::TokenKind::CloseParen => token::CloseParen,
|
||||
rustc_lexer::TokenKind::OpenBrace => token::OpenBrace,
|
||||
rustc_lexer::TokenKind::CloseBrace => token::CloseBrace,
|
||||
rustc_lexer::TokenKind::OpenBracket => token::OpenBracket,
|
||||
rustc_lexer::TokenKind::CloseBracket => token::CloseBracket,
|
||||
rustc_lexer::TokenKind::At => token::At,
|
||||
rustc_lexer::TokenKind::Pound => token::Pound,
|
||||
rustc_lexer::TokenKind::Tilde => token::Tilde,
|
||||
|
|
|
|||
|
|
@ -18,38 +18,33 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
|
|||
|
||||
let mut buf = Vec::new();
|
||||
loop {
|
||||
match self.token.kind {
|
||||
token::OpenDelim(delim) => {
|
||||
// Invisible delimiters cannot occur here because `TokenTreesReader` parses
|
||||
// code directly from strings, with no macro expansion involved.
|
||||
debug_assert!(!matches!(delim, Delimiter::Invisible(_)));
|
||||
buf.push(match self.lex_token_tree_open_delim(delim) {
|
||||
Ok(val) => val,
|
||||
Err(errs) => return Err(errs),
|
||||
})
|
||||
}
|
||||
token::CloseDelim(delim) => {
|
||||
// Invisible delimiters cannot occur here because `TokenTreesReader` parses
|
||||
// code directly from strings, with no macro expansion involved.
|
||||
debug_assert!(!matches!(delim, Delimiter::Invisible(_)));
|
||||
return if is_delimited {
|
||||
Ok((open_spacing, TokenStream::new(buf)))
|
||||
} else {
|
||||
Err(vec![self.close_delim_err(delim)])
|
||||
};
|
||||
}
|
||||
token::Eof => {
|
||||
return if is_delimited {
|
||||
Err(vec![self.eof_err()])
|
||||
} else {
|
||||
Ok((open_spacing, TokenStream::new(buf)))
|
||||
};
|
||||
}
|
||||
_ => {
|
||||
// Get the next normal token.
|
||||
let (this_tok, this_spacing) = self.bump();
|
||||
buf.push(TokenTree::Token(this_tok, this_spacing));
|
||||
}
|
||||
if let Some(delim) = self.token.kind.open_delim() {
|
||||
// Invisible delimiters cannot occur here because `TokenTreesReader` parses
|
||||
// code directly from strings, with no macro expansion involved.
|
||||
debug_assert!(!matches!(delim, Delimiter::Invisible(_)));
|
||||
buf.push(match self.lex_token_tree_open_delim(delim) {
|
||||
Ok(val) => val,
|
||||
Err(errs) => return Err(errs),
|
||||
})
|
||||
} else if let Some(delim) = self.token.kind.close_delim() {
|
||||
// Invisible delimiters cannot occur here because `TokenTreesReader` parses
|
||||
// code directly from strings, with no macro expansion involved.
|
||||
debug_assert!(!matches!(delim, Delimiter::Invisible(_)));
|
||||
return if is_delimited {
|
||||
Ok((open_spacing, TokenStream::new(buf)))
|
||||
} else {
|
||||
Err(vec![self.close_delim_err(delim)])
|
||||
};
|
||||
} else if self.token.kind == token::Eof {
|
||||
return if is_delimited {
|
||||
Err(vec![self.eof_err()])
|
||||
} else {
|
||||
Ok((open_spacing, TokenStream::new(buf)))
|
||||
};
|
||||
} else {
|
||||
// Get the next normal token.
|
||||
let (this_tok, this_spacing) = self.bump();
|
||||
buf.push(TokenTree::Token(this_tok, this_spacing));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -111,9 +106,9 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
|
|||
let delim_span = DelimSpan::from_pair(pre_span, self.token.span);
|
||||
let sm = self.psess.source_map();
|
||||
|
||||
let close_spacing = match self.token.kind {
|
||||
// Correct delimiter.
|
||||
token::CloseDelim(close_delim) if close_delim == open_delim => {
|
||||
let close_spacing = if let Some(close_delim) = self.token.kind.close_delim() {
|
||||
if close_delim == open_delim {
|
||||
// Correct delimiter.
|
||||
let (open_brace, open_brace_span) = self.diag_info.open_braces.pop().unwrap();
|
||||
let close_brace_span = self.token.span;
|
||||
|
||||
|
|
@ -134,9 +129,8 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
|
|||
|
||||
// Move past the closing delimiter.
|
||||
self.bump_minimal()
|
||||
}
|
||||
// Incorrect delimiter.
|
||||
token::CloseDelim(close_delim) => {
|
||||
} else {
|
||||
// Incorrect delimiter.
|
||||
let mut unclosed_delimiter = None;
|
||||
let mut candidate = None;
|
||||
|
||||
|
|
@ -182,14 +176,13 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
|
|||
Spacing::Alone
|
||||
}
|
||||
}
|
||||
token::Eof => {
|
||||
// Silently recover, the EOF token will be seen again
|
||||
// and an error emitted then. Thus we don't pop from
|
||||
// self.open_braces here. The choice of spacing value here
|
||||
// doesn't matter.
|
||||
Spacing::Alone
|
||||
}
|
||||
_ => unreachable!(),
|
||||
} else {
|
||||
assert_eq!(self.token.kind, token::Eof);
|
||||
// Silently recover, the EOF token will be seen again
|
||||
// and an error emitted then. Thus we don't pop from
|
||||
// self.open_braces here. The choice of spacing value here
|
||||
// doesn't matter.
|
||||
Spacing::Alone
|
||||
};
|
||||
|
||||
let spacing = DelimSpacing::new(open_spacing, close_spacing);
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use rustc_span::{BytePos, Pos, Span, kw};
|
|||
|
||||
use super::Lexer;
|
||||
use crate::errors::TokenSubstitution;
|
||||
use crate::token::{self, Delimiter};
|
||||
use crate::token;
|
||||
|
||||
#[rustfmt::skip] // for line breaks
|
||||
pub(super) static UNICODE_ARRAY: &[(char, &str, &str)] = &[
|
||||
|
|
@ -315,12 +315,12 @@ const ASCII_ARRAY: &[(&str, &str, Option<token::TokenKind>)] = &[
|
|||
("!", "Exclamation Mark", Some(token::Bang)),
|
||||
("?", "Question Mark", Some(token::Question)),
|
||||
(".", "Period", Some(token::Dot)),
|
||||
("(", "Left Parenthesis", Some(token::OpenDelim(Delimiter::Parenthesis))),
|
||||
(")", "Right Parenthesis", Some(token::CloseDelim(Delimiter::Parenthesis))),
|
||||
("[", "Left Square Bracket", Some(token::OpenDelim(Delimiter::Bracket))),
|
||||
("]", "Right Square Bracket", Some(token::CloseDelim(Delimiter::Bracket))),
|
||||
("{", "Left Curly Brace", Some(token::OpenDelim(Delimiter::Brace))),
|
||||
("}", "Right Curly Brace", Some(token::CloseDelim(Delimiter::Brace))),
|
||||
("(", "Left Parenthesis", Some(token::OpenParen)),
|
||||
(")", "Right Parenthesis", Some(token::CloseParen)),
|
||||
("[", "Left Square Bracket", Some(token::OpenBracket)),
|
||||
("]", "Right Square Bracket", Some(token::CloseBracket)),
|
||||
("{", "Left Curly Brace", Some(token::OpenBrace)),
|
||||
("}", "Right Curly Brace", Some(token::CloseBrace)),
|
||||
("*", "Asterisk", Some(token::Star)),
|
||||
("/", "Slash", Some(token::Slash)),
|
||||
("\\", "Backslash", None),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::borrow::Cow;
|
||||
use std::{iter, mem};
|
||||
|
||||
use rustc_ast::token::{Delimiter, Token, TokenKind};
|
||||
use rustc_ast::token::{Delimiter, Token};
|
||||
use rustc_ast::tokenstream::{
|
||||
AttrTokenStream, AttrTokenTree, AttrsTarget, DelimSpacing, DelimSpan, LazyAttrTokenStream,
|
||||
Spacing, ToAttrTokenStream,
|
||||
|
|
@ -501,27 +501,27 @@ fn make_attr_token_stream(
|
|||
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 }, 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!(
|
||||
open_delim.eq_ignoring_invisible_origin(&delim),
|
||||
"Mismatched open/close delims: open={open_delim:?} close={span:?}"
|
||||
);
|
||||
let dspan = DelimSpan::from_pair(open_sp, span);
|
||||
let dspacing = DelimSpacing::new(open_spacing, spacing);
|
||||
let stream = AttrTokenStream::new(frame_data.inner);
|
||||
let delimited = AttrTokenTree::Delimited(dspan, dspacing, delim, stream);
|
||||
stack_top.inner.push(delimited);
|
||||
}
|
||||
FlatToken::Token((token, spacing)) => {
|
||||
stack_top.inner.push(AttrTokenTree::Token(token, spacing))
|
||||
FlatToken::Token((token @ Token { kind, span }, spacing)) => {
|
||||
if let Some(delim) = kind.open_delim() {
|
||||
stack_rest.push(mem::replace(
|
||||
&mut stack_top,
|
||||
FrameData { open_delim_sp: Some((delim, span, spacing)), inner: vec![] },
|
||||
));
|
||||
} else if let Some(delim) = kind.close_delim() {
|
||||
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!(
|
||||
open_delim.eq_ignoring_invisible_origin(&delim),
|
||||
"Mismatched open/close delims: open={open_delim:?} close={span:?}"
|
||||
);
|
||||
let dspan = DelimSpan::from_pair(open_sp, span);
|
||||
let dspacing = DelimSpacing::new(open_spacing, spacing);
|
||||
let stream = AttrTokenStream::new(frame_data.inner);
|
||||
let delimited = AttrTokenTree::Delimited(dspan, dspacing, delim, stream);
|
||||
stack_top.inner.push(delimited);
|
||||
} else {
|
||||
stack_top.inner.push(AttrTokenTree::Token(token, spacing))
|
||||
}
|
||||
}
|
||||
FlatToken::AttrsTarget(target) => {
|
||||
stack_top.inner.push(AttrTokenTree::AttrsTarget(target))
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use std::ops::{Deref, DerefMut};
|
|||
use ast::token::IdentIsRaw;
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, Delimiter, Lit, LitKind, Token, TokenKind};
|
||||
use rustc_ast::token::{self, Lit, LitKind, Token, TokenKind};
|
||||
use rustc_ast::util::parser::AssocOp;
|
||||
use rustc_ast::{
|
||||
AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode, Block,
|
||||
|
|
@ -304,10 +304,10 @@ impl<'a> Parser<'a> {
|
|||
TokenKind::Comma,
|
||||
TokenKind::Semi,
|
||||
TokenKind::PathSep,
|
||||
TokenKind::OpenDelim(Delimiter::Brace),
|
||||
TokenKind::OpenDelim(Delimiter::Parenthesis),
|
||||
TokenKind::CloseDelim(Delimiter::Brace),
|
||||
TokenKind::CloseDelim(Delimiter::Parenthesis),
|
||||
TokenKind::OpenBrace,
|
||||
TokenKind::OpenParen,
|
||||
TokenKind::CloseBrace,
|
||||
TokenKind::CloseParen,
|
||||
];
|
||||
if let TokenKind::DocComment(..) = self.prev_token.kind
|
||||
&& valid_follow.contains(&self.token.kind)
|
||||
|
|
@ -507,7 +507,7 @@ impl<'a> Parser<'a> {
|
|||
} else if !sm.is_multiline(self.prev_token.span.until(self.token.span)) {
|
||||
// The current token is in the same line as the prior token, not recoverable.
|
||||
} else if [token::Comma, token::Colon].contains(&self.token.kind)
|
||||
&& self.prev_token == token::CloseDelim(Delimiter::Parenthesis)
|
||||
&& self.prev_token == token::CloseParen
|
||||
{
|
||||
// Likely typo: The current token is on a new line and is expected to be
|
||||
// `.`, `;`, `?`, or an operator after a close delimiter token.
|
||||
|
|
@ -518,8 +518,7 @@ impl<'a> Parser<'a> {
|
|||
// ^
|
||||
// https://github.com/rust-lang/rust/issues/72253
|
||||
} else if self.look_ahead(1, |t| {
|
||||
t == &token::CloseDelim(Delimiter::Brace)
|
||||
|| t.can_begin_expr() && *t != token::Colon
|
||||
t == &token::CloseBrace || t.can_begin_expr() && *t != token::Colon
|
||||
}) && [token::Comma, token::Colon].contains(&self.token.kind)
|
||||
{
|
||||
// Likely typo: `,` → `;` or `:` → `;`. This is triggered if the current token is
|
||||
|
|
@ -537,7 +536,7 @@ impl<'a> Parser<'a> {
|
|||
self.bump();
|
||||
return Ok(guar);
|
||||
} else if self.look_ahead(0, |t| {
|
||||
t == &token::CloseDelim(Delimiter::Brace)
|
||||
t == &token::CloseBrace
|
||||
|| ((t.can_begin_expr() || t.can_begin_item())
|
||||
&& t != &token::Semi
|
||||
&& t != &token::Pound)
|
||||
|
|
@ -675,8 +674,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
// `pub` may be used for an item or `pub(crate)`
|
||||
if self.prev_token.is_ident_named(sym::public)
|
||||
&& (self.token.can_begin_item()
|
||||
|| self.token == TokenKind::OpenDelim(Delimiter::Parenthesis))
|
||||
&& (self.token.can_begin_item() || self.token == TokenKind::OpenParen)
|
||||
{
|
||||
err.span_suggestion_short(
|
||||
self.prev_token.span,
|
||||
|
|
@ -843,9 +841,7 @@ impl<'a> Parser<'a> {
|
|||
if expr.attrs.len() == 1 { "this attribute" } else { "these attributes" },
|
||||
),
|
||||
);
|
||||
if self.token == token::Pound
|
||||
&& self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Bracket))
|
||||
{
|
||||
if self.token == token::Pound && self.look_ahead(1, |t| *t == token::OpenBracket) {
|
||||
// We have
|
||||
// #[attr]
|
||||
// expr
|
||||
|
|
@ -1037,9 +1033,7 @@ impl<'a> Parser<'a> {
|
|||
) -> PResult<'a, P<Expr>> {
|
||||
err.span_label(lo.to(decl_hi), "while parsing the body of this closure");
|
||||
let guar = match before.kind {
|
||||
token::OpenDelim(Delimiter::Brace)
|
||||
if !matches!(token.kind, token::OpenDelim(Delimiter::Brace)) =>
|
||||
{
|
||||
token::OpenBrace if token.kind != token::OpenBrace => {
|
||||
// `{ || () }` should have been `|| { () }`
|
||||
err.multipart_suggestion(
|
||||
"you might have meant to open the body of the closure, instead of enclosing \
|
||||
|
|
@ -1054,9 +1048,7 @@ impl<'a> Parser<'a> {
|
|||
self.eat_to_tokens(&[exp!(CloseBrace)]);
|
||||
guar
|
||||
}
|
||||
token::OpenDelim(Delimiter::Parenthesis)
|
||||
if !matches!(token.kind, token::OpenDelim(Delimiter::Brace)) =>
|
||||
{
|
||||
token::OpenParen if token.kind != token::OpenBrace => {
|
||||
// We are within a function call or tuple, we can emit the error
|
||||
// and recover.
|
||||
self.eat_to_tokens(&[exp!(CloseParen), exp!(Comma)]);
|
||||
|
|
@ -1071,7 +1063,7 @@ impl<'a> Parser<'a> {
|
|||
);
|
||||
err.emit()
|
||||
}
|
||||
_ if !matches!(token.kind, token::OpenDelim(Delimiter::Brace)) => {
|
||||
_ if token.kind != token::OpenBrace => {
|
||||
// We don't have a heuristic to correctly identify where the block
|
||||
// should be closed.
|
||||
err.multipart_suggestion_verbose(
|
||||
|
|
@ -1225,7 +1217,7 @@ impl<'a> Parser<'a> {
|
|||
trailing_span = trailing_span.to(self.token.span);
|
||||
self.bump();
|
||||
}
|
||||
if self.token == token::OpenDelim(Delimiter::Parenthesis) {
|
||||
if self.token == token::OpenParen {
|
||||
// Recover from bad turbofish: `foo.collect::Vec<_>()`.
|
||||
segment.args = Some(AngleBracketedArgs { args, span }.into());
|
||||
|
||||
|
|
@ -1470,9 +1462,7 @@ impl<'a> Parser<'a> {
|
|||
let modifiers = [(token::Lt, 1), (token::Gt, -1), (token::Shr, -2)];
|
||||
self.consume_tts(1, &modifiers);
|
||||
|
||||
if !&[token::OpenDelim(Delimiter::Parenthesis), token::PathSep]
|
||||
.contains(&self.token.kind)
|
||||
{
|
||||
if !matches!(self.token.kind, token::OpenParen | token::PathSep) {
|
||||
// We don't have `foo< bar >(` or `foo< bar >::`, so we rewind the
|
||||
// parser and bail out.
|
||||
self.restore_snapshot(snapshot);
|
||||
|
|
@ -1510,7 +1500,7 @@ impl<'a> Parser<'a> {
|
|||
Err(self.dcx().create_err(err))
|
||||
}
|
||||
}
|
||||
} else if self.token == token::OpenDelim(Delimiter::Parenthesis) {
|
||||
} else if self.token == token::OpenParen {
|
||||
// We have high certainty that this was a bad turbofish at this point.
|
||||
// `foo< bar >(`
|
||||
if let ExprKind::Binary(o, ..) = inner_op.kind
|
||||
|
|
@ -1570,10 +1560,7 @@ impl<'a> Parser<'a> {
|
|||
self.bump(); // `(`
|
||||
|
||||
// Consume the fn call arguments.
|
||||
let modifiers = [
|
||||
(token::OpenDelim(Delimiter::Parenthesis), 1),
|
||||
(token::CloseDelim(Delimiter::Parenthesis), -1),
|
||||
];
|
||||
let modifiers = [(token::OpenParen, 1), (token::CloseParen, -1)];
|
||||
self.consume_tts(1, &modifiers);
|
||||
|
||||
if self.token == token::Eof {
|
||||
|
|
@ -1978,7 +1965,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
fn recover_await_prefix(&mut self, await_sp: Span) -> PResult<'a, (Span, P<Expr>, bool)> {
|
||||
let is_question = self.eat(exp!(Question)); // Handle `await? <expr>`.
|
||||
let expr = if self.token == token::OpenDelim(Delimiter::Brace) {
|
||||
let expr = if self.token == token::OpenBrace {
|
||||
// Handle `await { <expr> }`.
|
||||
// This needs to be handled separately from the next arm to avoid
|
||||
// interpreting `await { <expr> }?` as `<expr>?.await`.
|
||||
|
|
@ -2014,9 +2001,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
/// If encountering `future.await()`, consumes and emits an error.
|
||||
pub(super) fn recover_from_await_method_call(&mut self) {
|
||||
if self.token == token::OpenDelim(Delimiter::Parenthesis)
|
||||
&& self.look_ahead(1, |t| t == &token::CloseDelim(Delimiter::Parenthesis))
|
||||
{
|
||||
if self.token == token::OpenParen && self.look_ahead(1, |t| t == &token::CloseParen) {
|
||||
// future.await()
|
||||
let lo = self.token.span;
|
||||
self.bump(); // (
|
||||
|
|
@ -2029,9 +2014,7 @@ impl<'a> Parser<'a> {
|
|||
///
|
||||
/// If encountering `x.use()`, consumes and emits an error.
|
||||
pub(super) fn recover_from_use(&mut self) {
|
||||
if self.token == token::OpenDelim(Delimiter::Parenthesis)
|
||||
&& self.look_ahead(1, |t| t == &token::CloseDelim(Delimiter::Parenthesis))
|
||||
{
|
||||
if self.token == token::OpenParen && self.look_ahead(1, |t| t == &token::CloseParen) {
|
||||
// var.use()
|
||||
let lo = self.token.span;
|
||||
self.bump(); // (
|
||||
|
|
@ -2045,7 +2028,7 @@ impl<'a> Parser<'a> {
|
|||
pub(super) fn try_macro_suggestion(&mut self) -> PResult<'a, P<Expr>> {
|
||||
let is_try = self.token.is_keyword(kw::Try);
|
||||
let is_questionmark = self.look_ahead(1, |t| t == &token::Bang); //check for !
|
||||
let is_open = self.look_ahead(2, |t| t == &token::OpenDelim(Delimiter::Parenthesis)); //check for (
|
||||
let is_open = self.look_ahead(2, |t| t == &token::OpenParen); //check for (
|
||||
|
||||
if is_try && is_questionmark && is_open {
|
||||
let lo = self.token.span;
|
||||
|
|
@ -2053,7 +2036,7 @@ impl<'a> Parser<'a> {
|
|||
self.bump(); //remove !
|
||||
let try_span = lo.to(self.token.span); //we take the try!( span
|
||||
self.bump(); //remove (
|
||||
let is_empty = self.token == token::CloseDelim(Delimiter::Parenthesis); //check if the block is empty
|
||||
let is_empty = self.token == token::CloseParen; //check if the block is empty
|
||||
self.consume_block(exp!(OpenParen), exp!(CloseParen), ConsumeClosingDelim::No); //eat the block
|
||||
let hi = self.token.span;
|
||||
self.bump(); //remove )
|
||||
|
|
@ -2148,7 +2131,7 @@ impl<'a> Parser<'a> {
|
|||
loop {
|
||||
debug!("recover_stmt_ loop {:?}", self.token);
|
||||
match self.token.kind {
|
||||
token::OpenDelim(Delimiter::Brace) => {
|
||||
token::OpenBrace => {
|
||||
brace_depth += 1;
|
||||
self.bump();
|
||||
if break_on_block == BlockMode::Break && brace_depth == 1 && bracket_depth == 0
|
||||
|
|
@ -2156,11 +2139,11 @@ impl<'a> Parser<'a> {
|
|||
in_block = true;
|
||||
}
|
||||
}
|
||||
token::OpenDelim(Delimiter::Bracket) => {
|
||||
token::OpenBracket => {
|
||||
bracket_depth += 1;
|
||||
self.bump();
|
||||
}
|
||||
token::CloseDelim(Delimiter::Brace) => {
|
||||
token::CloseBrace => {
|
||||
if brace_depth == 0 {
|
||||
debug!("recover_stmt_ return - close delim {:?}", self.token);
|
||||
break;
|
||||
|
|
@ -2172,7 +2155,7 @@ impl<'a> Parser<'a> {
|
|||
break;
|
||||
}
|
||||
}
|
||||
token::CloseDelim(Delimiter::Bracket) => {
|
||||
token::CloseBracket => {
|
||||
bracket_depth -= 1;
|
||||
if bracket_depth < 0 {
|
||||
bracket_depth = 0;
|
||||
|
|
@ -2219,12 +2202,10 @@ impl<'a> Parser<'a> {
|
|||
if let token::DocComment(..) = self.token.kind {
|
||||
self.dcx().emit_err(DocCommentOnParamType { span: self.token.span });
|
||||
self.bump();
|
||||
} else if self.token == token::Pound
|
||||
&& self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Bracket))
|
||||
{
|
||||
} else if self.token == token::Pound && self.look_ahead(1, |t| *t == token::OpenBracket) {
|
||||
let lo = self.token.span;
|
||||
// Skip every token until next possible arg.
|
||||
while self.token != token::CloseDelim(Delimiter::Bracket) {
|
||||
while self.token != token::CloseBracket {
|
||||
self.bump();
|
||||
}
|
||||
let sp = lo.to(self.token.span);
|
||||
|
|
@ -2243,9 +2224,7 @@ impl<'a> Parser<'a> {
|
|||
// If we find a pattern followed by an identifier, it could be an (incorrect)
|
||||
// C-style parameter declaration.
|
||||
if self.check_ident()
|
||||
&& self.look_ahead(1, |t| {
|
||||
*t == token::Comma || *t == token::CloseDelim(Delimiter::Parenthesis)
|
||||
})
|
||||
&& self.look_ahead(1, |t| *t == token::Comma || *t == token::CloseParen)
|
||||
{
|
||||
// `fn foo(String s) {}`
|
||||
let ident = self.parse_ident().unwrap();
|
||||
|
|
@ -2261,7 +2240,7 @@ impl<'a> Parser<'a> {
|
|||
} else if require_name
|
||||
&& (self.token == token::Comma
|
||||
|| self.token == token::Lt
|
||||
|| self.token == token::CloseDelim(Delimiter::Parenthesis))
|
||||
|| self.token == token::CloseParen)
|
||||
{
|
||||
let rfc_note = "anonymous parameters are removed in the 2018 edition (see RFC 1685)";
|
||||
|
||||
|
|
@ -2872,7 +2851,7 @@ impl<'a> Parser<'a> {
|
|||
// Check for `'a : {`
|
||||
if !(self.check_lifetime()
|
||||
&& self.look_ahead(1, |t| *t == token::Colon)
|
||||
&& self.look_ahead(2, |t| *t == token::OpenDelim(Delimiter::Brace)))
|
||||
&& self.look_ahead(2, |t| *t == token::OpenBrace))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -436,7 +436,7 @@ impl<'a> Parser<'a> {
|
|||
fn is_at_start_of_range_notation_rhs(&self) -> bool {
|
||||
if self.token.can_begin_expr() {
|
||||
// Parse `for i in 1.. { }` as infinite loop, not as `for i in (1..{})`.
|
||||
if self.token == token::OpenDelim(Delimiter::Brace) {
|
||||
if self.token == token::OpenBrace {
|
||||
return !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL);
|
||||
}
|
||||
true
|
||||
|
|
@ -542,8 +542,8 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
// Recover from `++x`:
|
||||
token::Plus if this.look_ahead(1, |t| *t == token::Plus) => {
|
||||
let starts_stmt = this.prev_token == token::Semi
|
||||
|| this.prev_token == token::CloseDelim(Delimiter::Brace);
|
||||
let starts_stmt =
|
||||
this.prev_token == token::Semi || this.prev_token == token::CloseBrace;
|
||||
let pre_span = this.token.span.to(this.look_ahead(1, |t| t.span));
|
||||
// Eat both `+`s.
|
||||
this.bump();
|
||||
|
|
@ -637,8 +637,8 @@ impl<'a> Parser<'a> {
|
|||
/// Returns the span of expr if it was not interpolated, or the span of the interpolated token.
|
||||
fn interpolated_or_expr_span(&self, expr: &Expr) -> Span {
|
||||
match self.prev_token.kind {
|
||||
TokenKind::NtIdent(..) | TokenKind::NtLifetime(..) => self.prev_token.span,
|
||||
TokenKind::CloseDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => {
|
||||
token::NtIdent(..) | token::NtLifetime(..) => self.prev_token.span,
|
||||
token::CloseInvisible(InvisibleOrigin::MetaVar(_)) => {
|
||||
// `expr.span` is the interpolated span, because invisible open
|
||||
// and close delims both get marked with the same span, one
|
||||
// that covers the entire thing between them. (See
|
||||
|
|
@ -912,8 +912,8 @@ impl<'a> Parser<'a> {
|
|||
return Ok(e);
|
||||
}
|
||||
e = match self.token.kind {
|
||||
token::OpenDelim(Delimiter::Parenthesis) => self.parse_expr_fn_call(lo, e),
|
||||
token::OpenDelim(Delimiter::Bracket) => self.parse_expr_index(lo, e)?,
|
||||
token::OpenParen => self.parse_expr_fn_call(lo, e),
|
||||
token::OpenBracket => self.parse_expr_index(lo, e)?,
|
||||
_ => return Ok(e),
|
||||
}
|
||||
}
|
||||
|
|
@ -1002,7 +1002,7 @@ impl<'a> Parser<'a> {
|
|||
(token::Eof, Some(_)) if let Ok(snippet) = sm.span_to_snippet(sm.next_point(span)) => {
|
||||
(span.shrink_to_hi(), format!("`{}`", snippet))
|
||||
}
|
||||
(token::CloseDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))), _) => {
|
||||
(token::CloseInvisible(InvisibleOrigin::MetaVar(_)), _) => {
|
||||
// No need to report an error. This case will only occur when parsing a pasted
|
||||
// metavariable, and we should have emitted an error when parsing the macro call in
|
||||
// the first place. E.g. in this code:
|
||||
|
|
@ -1202,7 +1202,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
if matches!(self.token.kind, token::CloseDelim(..) | token::Comma) {
|
||||
if self.token.kind.close_delim().is_some() || self.token.kind == token::Comma {
|
||||
break;
|
||||
} else if trailing_dot.is_none() {
|
||||
// This loop should only repeat if there is a trailing dot.
|
||||
|
|
@ -1232,7 +1232,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
/// Parse a function call expression, `expr(...)`.
|
||||
fn parse_expr_fn_call(&mut self, lo: Span, fun: P<Expr>) -> P<Expr> {
|
||||
let snapshot = if self.token == token::OpenDelim(Delimiter::Parenthesis) {
|
||||
let snapshot = if self.token == token::OpenParen {
|
||||
Some((self.create_snapshot_for_diagnostic(), fun.kind.clone()))
|
||||
} else {
|
||||
None
|
||||
|
|
@ -1676,14 +1676,11 @@ impl<'a> Parser<'a> {
|
|||
self.parse_expr_for(label, lo)
|
||||
} else if self.eat_keyword(exp!(Loop)) {
|
||||
self.parse_expr_loop(label, lo)
|
||||
} else if self.check_noexpect(&token::OpenDelim(Delimiter::Brace))
|
||||
|| self.token.is_metavar_block()
|
||||
{
|
||||
} else if self.check_noexpect(&token::OpenBrace) || self.token.is_metavar_block() {
|
||||
self.parse_expr_block(label, lo, BlockCheckMode::Default)
|
||||
} else if !ate_colon
|
||||
&& self.may_recover()
|
||||
&& (matches!(self.token.kind, token::CloseDelim(_) | token::Comma)
|
||||
|| self.token.is_punct())
|
||||
&& (self.token.kind.close_delim().is_some() || self.token.is_punct())
|
||||
&& could_be_unclosed_char_literal(label_.ident)
|
||||
{
|
||||
let (lit, _) =
|
||||
|
|
@ -1878,7 +1875,7 @@ impl<'a> Parser<'a> {
|
|||
},
|
||||
});
|
||||
Some(lexpr)
|
||||
} else if self.token != token::OpenDelim(Delimiter::Brace)
|
||||
} else if self.token != token::OpenBrace
|
||||
|| !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
|
||||
{
|
||||
let mut expr = self.parse_expr_opt()?;
|
||||
|
|
@ -2016,7 +2013,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
// Eat tokens until the macro call ends.
|
||||
if self.may_recover() {
|
||||
while !matches!(self.token.kind, token::CloseDelim(..) | token::Eof) {
|
||||
while !self.token.kind.is_close_delim_or_eof() {
|
||||
self.bump();
|
||||
}
|
||||
}
|
||||
|
|
@ -2157,9 +2154,7 @@ impl<'a> Parser<'a> {
|
|||
self.bump();
|
||||
Some(token_lit)
|
||||
}
|
||||
token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
|
||||
MetaVarKind::Literal,
|
||||
))) => {
|
||||
token::OpenInvisible(InvisibleOrigin::MetaVar(MetaVarKind::Literal)) => {
|
||||
let lit = self
|
||||
.eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus())
|
||||
.expect("metavar seq literal");
|
||||
|
|
@ -2168,9 +2163,9 @@ impl<'a> Parser<'a> {
|
|||
};
|
||||
Some(token_lit)
|
||||
}
|
||||
token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
|
||||
token::OpenInvisible(InvisibleOrigin::MetaVar(
|
||||
mv_kind @ MetaVarKind::Expr { can_begin_literal_maybe_minus: true, .. },
|
||||
))) => {
|
||||
)) => {
|
||||
let expr = self
|
||||
.eat_metavar_seq(mv_kind, |this| this.parse_expr())
|
||||
.expect("metavar seq expr");
|
||||
|
|
@ -2275,7 +2270,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
fn is_array_like_block(&mut self) -> bool {
|
||||
matches!(self.token.kind, TokenKind::OpenDelim(Delimiter::Brace))
|
||||
self.token.kind == TokenKind::OpenBrace
|
||||
&& self
|
||||
.look_ahead(1, |t| matches!(t.kind, TokenKind::Ident(..) | TokenKind::Literal(_)))
|
||||
&& self.look_ahead(2, |t| t == &token::Comma)
|
||||
|
|
@ -2328,8 +2323,8 @@ impl<'a> Parser<'a> {
|
|||
|p| p.parse_expr(),
|
||||
) {
|
||||
Ok(_)
|
||||
// When the close delim is `)`, `token.kind` is expected to be `token::CloseDelim(Delimiter::Parenthesis)`,
|
||||
// but the actual `token.kind` is `token::CloseDelim(Delimiter::Bracket)`.
|
||||
// When the close delim is `)`, `token.kind` is expected to be `token::CloseParen`,
|
||||
// but the actual `token.kind` is `token::CloseBracket`.
|
||||
// This is because the `token.kind` of the close delim is treated as the same as
|
||||
// that of the open delim in `TokenTreesReader::parse_token_tree`, even if the delimiters of them are different.
|
||||
// Therefore, `token.kind` should not be compared here.
|
||||
|
|
@ -2484,7 +2479,7 @@ impl<'a> Parser<'a> {
|
|||
fn parse_closure_block_body(&mut self, ret_span: Span) -> PResult<'a, P<Expr>> {
|
||||
if self.may_recover()
|
||||
&& self.token.can_begin_expr()
|
||||
&& !matches!(self.token.kind, TokenKind::OpenDelim(Delimiter::Brace))
|
||||
&& self.token.kind != TokenKind::OpenBrace
|
||||
&& !self.token.is_metavar_block()
|
||||
{
|
||||
let snapshot = self.create_snapshot_for_diagnostic();
|
||||
|
|
@ -2887,7 +2882,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
fn parse_for_head(&mut self) -> PResult<'a, (P<Pat>, P<Expr>)> {
|
||||
let begin_paren = if self.token == token::OpenDelim(Delimiter::Parenthesis) {
|
||||
let begin_paren = if self.token == token::OpenParen {
|
||||
// Record whether we are about to parse `for (`.
|
||||
// This is used below for recovery in case of `for ( $stuff ) $block`
|
||||
// in which case we will suggest `for $stuff $block`.
|
||||
|
|
@ -2921,7 +2916,7 @@ impl<'a> Parser<'a> {
|
|||
return Err(err);
|
||||
}
|
||||
};
|
||||
return if self.token == token::CloseDelim(Delimiter::Parenthesis) {
|
||||
return if self.token == token::CloseParen {
|
||||
// We know for sure we have seen `for ($SOMETHING in $EXPR)`, so we recover the
|
||||
// parser state and emit a targeted suggestion.
|
||||
let span = vec![start_span, self.token.span];
|
||||
|
|
@ -2965,7 +2960,7 @@ impl<'a> Parser<'a> {
|
|||
let (pat, expr) = self.parse_for_head()?;
|
||||
// Recover from missing expression in `for` loop
|
||||
if matches!(expr.kind, ExprKind::Block(..))
|
||||
&& !matches!(self.token.kind, token::OpenDelim(Delimiter::Brace))
|
||||
&& self.token.kind != token::OpenBrace
|
||||
&& self.may_recover()
|
||||
{
|
||||
let guar = self
|
||||
|
|
@ -3114,7 +3109,7 @@ impl<'a> Parser<'a> {
|
|||
let attrs = self.parse_inner_attributes()?;
|
||||
|
||||
let mut arms = ThinVec::new();
|
||||
while self.token != token::CloseDelim(Delimiter::Brace) {
|
||||
while self.token != token::CloseBrace {
|
||||
match self.parse_arm() {
|
||||
Ok(arm) => arms.push(arm),
|
||||
Err(e) => {
|
||||
|
|
@ -3122,7 +3117,7 @@ impl<'a> Parser<'a> {
|
|||
let guar = e.emit();
|
||||
self.recover_stmt();
|
||||
let span = lo.to(self.token.span);
|
||||
if self.token == token::CloseDelim(Delimiter::Brace) {
|
||||
if self.token == token::CloseBrace {
|
||||
self.bump();
|
||||
}
|
||||
// Always push at least one arm to make the match non-empty
|
||||
|
|
@ -3183,7 +3178,7 @@ impl<'a> Parser<'a> {
|
|||
// We might have either a `,` -> `;` typo, or a block without braces. We need
|
||||
// a more subtle parsing strategy.
|
||||
loop {
|
||||
if self.token == token::CloseDelim(Delimiter::Brace) {
|
||||
if self.token == token::CloseBrace {
|
||||
// We have reached the closing brace of the `match` expression.
|
||||
return Some(err(self, stmts));
|
||||
}
|
||||
|
|
@ -3242,7 +3237,7 @@ impl<'a> Parser<'a> {
|
|||
// this avoids the compiler saying that a `,` or `}` was expected even though
|
||||
// the pattern isn't a never pattern (and thus an arm body is required)
|
||||
let armless = (!is_fat_arrow && !is_almost_fat_arrow && pat.could_be_never_pattern())
|
||||
|| matches!(this.token.kind, token::Comma | token::CloseDelim(Delimiter::Brace));
|
||||
|| matches!(this.token.kind, token::Comma | token::CloseBrace);
|
||||
|
||||
let mut result = if armless {
|
||||
// A pattern without a body, allowed for never patterns.
|
||||
|
|
@ -3290,8 +3285,8 @@ impl<'a> Parser<'a> {
|
|||
err
|
||||
})?;
|
||||
|
||||
let require_comma = !classify::expr_is_complete(&expr)
|
||||
&& this.token != token::CloseDelim(Delimiter::Brace);
|
||||
let require_comma =
|
||||
!classify::expr_is_complete(&expr) && this.token != token::CloseBrace;
|
||||
|
||||
if !require_comma {
|
||||
arm_body = Some(expr);
|
||||
|
|
@ -3442,7 +3437,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (P<Pat>, Option<P<Expr>>)> {
|
||||
if self.token == token::OpenDelim(Delimiter::Parenthesis) {
|
||||
if self.token == token::OpenParen {
|
||||
let left = self.token.span;
|
||||
let pat = self.parse_pat_no_top_guard(
|
||||
None,
|
||||
|
|
@ -3488,7 +3483,7 @@ impl<'a> Parser<'a> {
|
|||
match self.parse_expr_res(Restrictions::ALLOW_LET | Restrictions::IN_IF_GUARD, attrs) {
|
||||
Ok((expr, _)) => Ok(expr),
|
||||
Err(mut err) => {
|
||||
if self.prev_token == token::OpenDelim(Delimiter::Brace) {
|
||||
if self.prev_token == token::OpenBrace {
|
||||
let sugg_sp = self.prev_token.span.shrink_to_lo();
|
||||
// Consume everything within the braces, let's avoid further parse
|
||||
// errors.
|
||||
|
|
@ -3531,8 +3526,7 @@ impl<'a> Parser<'a> {
|
|||
fn is_do_catch_block(&self) -> bool {
|
||||
self.token.is_keyword(kw::Do)
|
||||
&& self.is_keyword_ahead(1, &[kw::Catch])
|
||||
&& self
|
||||
.look_ahead(2, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_metavar_block())
|
||||
&& self.look_ahead(2, |t| *t == token::OpenBrace || t.is_metavar_block())
|
||||
&& !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
|
||||
}
|
||||
|
||||
|
|
@ -3542,8 +3536,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
fn is_try_block(&self) -> bool {
|
||||
self.token.is_keyword(kw::Try)
|
||||
&& self
|
||||
.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_metavar_block())
|
||||
&& self.look_ahead(1, |t| *t == token::OpenBrace || t.is_metavar_block())
|
||||
&& self.token_uninterpolated_span().at_least_rust_2018()
|
||||
}
|
||||
|
||||
|
|
@ -3577,13 +3570,11 @@ impl<'a> Parser<'a> {
|
|||
// `async move {`
|
||||
self.is_keyword_ahead(lookahead + 1, &[kw::Move, kw::Use])
|
||||
&& self.look_ahead(lookahead + 2, |t| {
|
||||
*t == token::OpenDelim(Delimiter::Brace) || t.is_metavar_block()
|
||||
*t == token::OpenBrace || t.is_metavar_block()
|
||||
})
|
||||
) || (
|
||||
// `async {`
|
||||
self.look_ahead(lookahead + 1, |t| {
|
||||
*t == token::OpenDelim(Delimiter::Brace) || t.is_metavar_block()
|
||||
})
|
||||
self.look_ahead(lookahead + 1, |t| *t == token::OpenBrace || t.is_metavar_block())
|
||||
))
|
||||
}
|
||||
|
||||
|
|
@ -3707,11 +3698,7 @@ impl<'a> Parser<'a> {
|
|||
AssocOp::from_token(t).is_some()
|
||||
|| matches!(
|
||||
t.kind,
|
||||
token::OpenDelim(
|
||||
Delimiter::Parenthesis
|
||||
| Delimiter::Bracket
|
||||
| Delimiter::Brace
|
||||
)
|
||||
token::OpenParen | token::OpenBracket | token::OpenBrace
|
||||
)
|
||||
|| *t == token::Dot
|
||||
})
|
||||
|
|
@ -3868,8 +3855,8 @@ impl<'a> Parser<'a> {
|
|||
t == &token::Colon
|
||||
|| t == &token::Eq
|
||||
|| t == &token::Comma
|
||||
|| t == &token::CloseDelim(Delimiter::Brace)
|
||||
|| t == &token::CloseDelim(Delimiter::Parenthesis)
|
||||
|| t == &token::CloseBrace
|
||||
|| t == &token::CloseParen
|
||||
});
|
||||
if is_wrong {
|
||||
return Err(this.dcx().create_err(errors::ExpectedStructField {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
use ast::token::Delimiter;
|
||||
use rustc_ast::{
|
||||
self as ast, AttrVec, DUMMY_NODE_ID, GenericBounds, GenericParam, GenericParamKind, TyKind,
|
||||
WhereClause, token,
|
||||
|
|
@ -437,7 +436,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
if let Some(struct_) = struct_
|
||||
&& self.may_recover()
|
||||
&& self.token == token::OpenDelim(Delimiter::Parenthesis)
|
||||
&& self.token == token::OpenParen
|
||||
{
|
||||
snapshot = Some((struct_, self.create_snapshot_for_diagnostic()));
|
||||
};
|
||||
|
|
@ -548,7 +547,7 @@ impl<'a> Parser<'a> {
|
|||
matches!(t.kind, token::Gt | token::Comma | token::Colon | token::Eq)
|
||||
// Recovery-only branch -- this could be removed,
|
||||
// since it only affects diagnostics currently.
|
||||
|| matches!(t.kind, token::Question)
|
||||
|| t.kind == token::Question
|
||||
})
|
||||
|| self.is_keyword_ahead(start + 1, &[kw::Const]))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -399,14 +399,9 @@ impl<'a> Parser<'a> {
|
|||
let insert_span = ident_span.shrink_to_lo();
|
||||
|
||||
let ident = if self.token.is_ident()
|
||||
&& (!is_const || self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Parenthesis)))
|
||||
&& (!is_const || self.look_ahead(1, |t| *t == token::OpenParen))
|
||||
&& self.look_ahead(1, |t| {
|
||||
[
|
||||
token::Lt,
|
||||
token::OpenDelim(Delimiter::Brace),
|
||||
token::OpenDelim(Delimiter::Parenthesis),
|
||||
]
|
||||
.contains(&t.kind)
|
||||
matches!(t.kind, token::Lt | token::OpenBrace | token::OpenParen)
|
||||
}) {
|
||||
self.parse_ident().unwrap()
|
||||
} else {
|
||||
|
|
@ -422,7 +417,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
let err = if self.check(exp!(OpenBrace)) {
|
||||
// possible struct or enum definition where `struct` or `enum` was forgotten
|
||||
if self.look_ahead(1, |t| *t == token::CloseDelim(Delimiter::Brace)) {
|
||||
if self.look_ahead(1, |t| *t == token::CloseBrace) {
|
||||
// `S {}` could be unit enum or struct
|
||||
Some(errors::MissingKeywordForItemDefinition::EnumOrStruct { span })
|
||||
} else if self.look_ahead(2, |t| *t == token::Colon)
|
||||
|
|
@ -764,11 +759,12 @@ impl<'a> Parser<'a> {
|
|||
match parse_item(self) {
|
||||
Ok(None) => {
|
||||
let mut is_unnecessary_semicolon = !items.is_empty()
|
||||
// When the close delim is `)` in a case like the following, `token.kind` is expected to be `token::CloseDelim(Delimiter::Parenthesis)`,
|
||||
// but the actual `token.kind` is `token::CloseDelim(Delimiter::Brace)`.
|
||||
// This is because the `token.kind` of the close delim is treated as the same as
|
||||
// that of the open delim in `TokenTreesReader::parse_token_tree`, even if the delimiters of them are different.
|
||||
// Therefore, `token.kind` should not be compared here.
|
||||
// When the close delim is `)` in a case like the following, `token.kind`
|
||||
// is expected to be `token::CloseParen`, but the actual `token.kind` is
|
||||
// `token::CloseBrace`. This is because the `token.kind` of the close delim
|
||||
// is treated as the same as that of the open delim in
|
||||
// `TokenTreesReader::parse_token_tree`, even if the delimiters of them are
|
||||
// different. Therefore, `token.kind` should not be compared here.
|
||||
//
|
||||
// issue-60075.rs
|
||||
// ```
|
||||
|
|
@ -787,8 +783,8 @@ impl<'a> Parser<'a> {
|
|||
let mut semicolon_span = self.token.span;
|
||||
if !is_unnecessary_semicolon {
|
||||
// #105369, Detect spurious `;` before assoc fn body
|
||||
is_unnecessary_semicolon = self.token == token::OpenDelim(Delimiter::Brace)
|
||||
&& self.prev_token == token::Semi;
|
||||
is_unnecessary_semicolon =
|
||||
self.token == token::OpenBrace && self.prev_token == token::Semi;
|
||||
semicolon_span = self.prev_token.span;
|
||||
}
|
||||
// We have to bail or we'll potentially never make progress.
|
||||
|
|
@ -840,7 +836,7 @@ impl<'a> Parser<'a> {
|
|||
/// Recover on a doc comment before `}`.
|
||||
fn recover_doc_comment_before_brace(&mut self) -> bool {
|
||||
if let token::DocComment(..) = self.token.kind {
|
||||
if self.look_ahead(1, |tok| tok == &token::CloseDelim(Delimiter::Brace)) {
|
||||
if self.look_ahead(1, |tok| tok == &token::CloseBrace) {
|
||||
// FIXME: merge with `DocCommentDoesNotDocumentAnything` (E0585)
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
|
|
@ -1206,7 +1202,7 @@ impl<'a> Parser<'a> {
|
|||
// FIXME: This recovery should be tested better.
|
||||
if safety == Safety::Default
|
||||
&& self.token.is_keyword(kw::Unsafe)
|
||||
&& self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace))
|
||||
&& self.look_ahead(1, |t| *t == token::OpenBrace)
|
||||
{
|
||||
self.expect(exp!(OpenBrace)).unwrap_err().emit();
|
||||
safety = Safety::Unsafe(self.token.span);
|
||||
|
|
@ -1718,7 +1714,7 @@ impl<'a> Parser<'a> {
|
|||
} else if self.eat(exp!(Semi)) {
|
||||
VariantData::Unit(DUMMY_NODE_ID)
|
||||
// Record-style struct definition
|
||||
} else if self.token == token::OpenDelim(Delimiter::Brace) {
|
||||
} else if self.token == token::OpenBrace {
|
||||
let (fields, recovered) = self.parse_record_struct_body(
|
||||
"struct",
|
||||
ident.span,
|
||||
|
|
@ -1726,7 +1722,7 @@ impl<'a> Parser<'a> {
|
|||
)?;
|
||||
VariantData::Struct { fields, recovered }
|
||||
// Tuple-style struct definition with optional where-clause.
|
||||
} else if self.token == token::OpenDelim(Delimiter::Parenthesis) {
|
||||
} else if self.token == token::OpenParen {
|
||||
let body = VariantData::Tuple(self.parse_tuple_struct_body()?, DUMMY_NODE_ID);
|
||||
generics.where_clause = self.parse_where_clause()?;
|
||||
self.expect_semi()?;
|
||||
|
|
@ -1753,7 +1749,7 @@ impl<'a> Parser<'a> {
|
|||
generics.where_clause.has_where_token,
|
||||
)?;
|
||||
VariantData::Struct { fields, recovered }
|
||||
} else if self.token == token::OpenDelim(Delimiter::Brace) {
|
||||
} else if self.token == token::OpenBrace {
|
||||
let (fields, recovered) = self.parse_record_struct_body(
|
||||
"union",
|
||||
ident.span,
|
||||
|
|
@ -1784,7 +1780,7 @@ impl<'a> Parser<'a> {
|
|||
let mut fields = ThinVec::new();
|
||||
let mut recovered = Recovered::No;
|
||||
if self.eat(exp!(OpenBrace)) {
|
||||
while self.token != token::CloseDelim(Delimiter::Brace) {
|
||||
while self.token != token::CloseBrace {
|
||||
match self.parse_field_def(adt_ty) {
|
||||
Ok(field) => {
|
||||
fields.push(field);
|
||||
|
|
@ -1941,7 +1937,7 @@ impl<'a> Parser<'a> {
|
|||
token::Comma => {
|
||||
self.bump();
|
||||
}
|
||||
token::CloseDelim(Delimiter::Brace) => {}
|
||||
token::CloseBrace => {}
|
||||
token::DocComment(..) => {
|
||||
let previous_span = self.prev_token.span;
|
||||
let mut err = errors::DocCommentDoesNotDocumentAnything {
|
||||
|
|
@ -1955,7 +1951,7 @@ impl<'a> Parser<'a> {
|
|||
if !seen_comma && comma_after_doc_seen {
|
||||
seen_comma = true;
|
||||
}
|
||||
if comma_after_doc_seen || self.token == token::CloseDelim(Delimiter::Brace) {
|
||||
if comma_after_doc_seen || self.token == token::CloseBrace {
|
||||
self.dcx().emit_err(err);
|
||||
} else {
|
||||
if !seen_comma {
|
||||
|
|
@ -1993,7 +1989,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
if self.token.is_ident()
|
||||
|| (self.token == TokenKind::Pound
|
||||
&& (self.look_ahead(1, |t| t == &token::OpenDelim(Delimiter::Bracket))))
|
||||
&& (self.look_ahead(1, |t| t == &token::OpenBracket)))
|
||||
{
|
||||
// This is likely another field, TokenKind::Pound is used for `#[..]`
|
||||
// attribute for next field. Emit the diagnostic and continue parsing.
|
||||
|
|
@ -2447,7 +2443,7 @@ impl<'a> Parser<'a> {
|
|||
match self.expected_one_of_not_found(&[], expected) {
|
||||
Ok(error_guaranteed) => Ok(error_guaranteed),
|
||||
Err(mut err) => {
|
||||
if self.token == token::CloseDelim(Delimiter::Brace) {
|
||||
if self.token == token::CloseBrace {
|
||||
// The enclosing `mod`, `trait` or `impl` is being closed, so keep the `fn` in
|
||||
// the AST for typechecking.
|
||||
err.span_label(ident_span, "while parsing this `fn`");
|
||||
|
|
@ -2874,7 +2870,7 @@ impl<'a> Parser<'a> {
|
|||
pub(super) fn parse_fn_params(&mut self, req_name: ReqName) -> PResult<'a, ThinVec<Param>> {
|
||||
let mut first_param = true;
|
||||
// Parse the arguments, starting out with `self` being allowed...
|
||||
if self.token != TokenKind::OpenDelim(Delimiter::Parenthesis)
|
||||
if self.token != TokenKind::OpenParen
|
||||
// might be typo'd trait impl, handled elsewhere
|
||||
&& !self.token.is_keyword(kw::For)
|
||||
{
|
||||
|
|
@ -2892,7 +2888,7 @@ impl<'a> Parser<'a> {
|
|||
// When parsing a param failed, we should check to make the span of the param
|
||||
// not contain '(' before it.
|
||||
// For example when parsing `*mut Self` in function `fn oof(*mut Self)`.
|
||||
let lo = if let TokenKind::OpenDelim(Delimiter::Parenthesis) = p.prev_token.kind {
|
||||
let lo = if let TokenKind::OpenParen = p.prev_token.kind {
|
||||
p.prev_token.span.shrink_to_hi()
|
||||
} else {
|
||||
p.prev_token.span
|
||||
|
|
@ -2969,9 +2965,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
if this.token != token::Comma
|
||||
&& this.token != token::CloseDelim(Delimiter::Parenthesis)
|
||||
{
|
||||
if this.token != token::Comma && this.token != token::CloseParen {
|
||||
// This wasn't actually a type, but a pattern looking like a type,
|
||||
// so we are going to rollback and re-parse for recovery.
|
||||
ty = this.unexpected_any();
|
||||
|
|
@ -3153,7 +3147,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
fn is_named_param(&self) -> bool {
|
||||
let offset = match &self.token.kind {
|
||||
token::OpenDelim(Delimiter::Invisible(origin)) => match origin {
|
||||
token::OpenInvisible(origin) => match origin {
|
||||
InvisibleOrigin::MetaVar(MetaVarKind::Pat(_)) => {
|
||||
return self.check_noexpect_past_close_delim(&token::Colon);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,8 +23,7 @@ pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma};
|
|||
use path::PathStyle;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{
|
||||
self, Delimiter, IdentIsRaw, InvisibleOrigin, MetaVarKind, NtExprKind, NtPatKind, Token,
|
||||
TokenKind,
|
||||
self, IdentIsRaw, InvisibleOrigin, MetaVarKind, NtExprKind, NtPatKind, Token, TokenKind,
|
||||
};
|
||||
use rustc_ast::tokenstream::{AttrsTarget, Spacing, TokenStream, TokenTree};
|
||||
use rustc_ast::util::case::Case;
|
||||
|
|
@ -327,10 +326,7 @@ impl TokenCursor {
|
|||
if let Some(tree) = self.curr.curr() {
|
||||
match tree {
|
||||
&TokenTree::Token(token, spacing) => {
|
||||
debug_assert!(!matches!(
|
||||
token.kind,
|
||||
token::OpenDelim(_) | token::CloseDelim(_)
|
||||
));
|
||||
debug_assert!(!token.kind.is_delim());
|
||||
let res = (token, spacing);
|
||||
self.curr.bump();
|
||||
return res;
|
||||
|
|
@ -339,7 +335,7 @@ impl TokenCursor {
|
|||
let trees = TokenTreeCursor::new(tts.clone());
|
||||
self.stack.push(mem::replace(&mut self.curr, trees));
|
||||
if !delim.skip() {
|
||||
return (Token::new(token::OpenDelim(delim), sp.open), spacing.open);
|
||||
return (Token::new(delim.as_open_token_kind(), sp.open), spacing.open);
|
||||
}
|
||||
// No open delimiter to return; continue on to the next iteration.
|
||||
}
|
||||
|
|
@ -352,7 +348,7 @@ impl TokenCursor {
|
|||
self.curr = parent;
|
||||
self.curr.bump(); // move past the `Delimited`
|
||||
if !delim.skip() {
|
||||
return (Token::new(token::CloseDelim(delim), span.close), spacing.close);
|
||||
return (Token::new(delim.as_close_token_kind(), span.close), spacing.close);
|
||||
}
|
||||
// No close delimiter to return; continue on to the next iteration.
|
||||
} else {
|
||||
|
|
@ -423,7 +419,7 @@ impl TokenDescription {
|
|||
_ if token.is_used_keyword() => Some(TokenDescription::Keyword),
|
||||
_ if token.is_unused_keyword() => Some(TokenDescription::ReservedKeyword),
|
||||
token::DocComment(..) => Some(TokenDescription::DocComment),
|
||||
token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(kind))) => {
|
||||
token::OpenInvisible(InvisibleOrigin::MetaVar(kind)) => {
|
||||
Some(TokenDescription::MetaVar(kind))
|
||||
}
|
||||
_ => None,
|
||||
|
|
@ -620,9 +616,8 @@ impl<'a> Parser<'a> {
|
|||
// past the entire `TokenTree::Delimited` in a single step, avoiding the
|
||||
// need for unbounded token lookahead.
|
||||
//
|
||||
// Primarily used when `self.token` matches
|
||||
// `OpenDelim(Delimiter::Invisible(_))`, to look ahead through the current
|
||||
// metavar expansion.
|
||||
// Primarily used when `self.token` matches `OpenInvisible(_))`, to look
|
||||
// ahead through the current metavar expansion.
|
||||
fn check_noexpect_past_close_delim(&self, tok: &TokenKind) -> bool {
|
||||
let mut tree_cursor = self.token_cursor.stack.last().unwrap().clone();
|
||||
tree_cursor.bump();
|
||||
|
|
@ -756,8 +751,7 @@ impl<'a> Parser<'a> {
|
|||
match_mv_kind: impl Fn(MetaVarKind) -> bool,
|
||||
mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
|
||||
) -> Option<T> {
|
||||
if let token::OpenDelim(delim) = self.token.kind
|
||||
&& let Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind)) = delim
|
||||
if let token::OpenInvisible(InvisibleOrigin::MetaVar(mv_kind)) = self.token.kind
|
||||
&& match_mv_kind(mv_kind)
|
||||
{
|
||||
self.bump();
|
||||
|
|
@ -776,8 +770,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
};
|
||||
|
||||
if let token::CloseDelim(delim) = self.token.kind
|
||||
&& let Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind)) = delim
|
||||
if let token::CloseInvisible(InvisibleOrigin::MetaVar(mv_kind)) = self.token.kind
|
||||
&& match_mv_kind(mv_kind)
|
||||
{
|
||||
self.bump();
|
||||
|
|
@ -838,10 +831,8 @@ impl<'a> Parser<'a> {
|
|||
fn check_inline_const(&self, dist: usize) -> bool {
|
||||
self.is_keyword_ahead(dist, &[kw::Const])
|
||||
&& self.look_ahead(dist + 1, |t| match &t.kind {
|
||||
token::OpenDelim(Delimiter::Brace) => true,
|
||||
token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
|
||||
MetaVarKind::Block,
|
||||
))) => true,
|
||||
token::OpenBrace => true,
|
||||
token::OpenInvisible(InvisibleOrigin::MetaVar(MetaVarKind::Block)) => true,
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
|
@ -960,7 +951,7 @@ impl<'a> Parser<'a> {
|
|||
let mut v = ThinVec::new();
|
||||
|
||||
while !self.expect_any_with_type(closes_expected, closes_not_expected) {
|
||||
if let token::CloseDelim(..) | token::Eof = self.token.kind {
|
||||
if self.token.kind.is_close_delim_or_eof() {
|
||||
break;
|
||||
}
|
||||
if let Some(exp) = sep.sep {
|
||||
|
|
@ -1244,7 +1235,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
debug_assert!(!matches!(
|
||||
next.0.kind,
|
||||
token::OpenDelim(delim) | token::CloseDelim(delim) if delim.skip()
|
||||
token::OpenInvisible(origin) | token::CloseInvisible(origin) if origin.skip()
|
||||
));
|
||||
self.inlined_bump_with(next)
|
||||
}
|
||||
|
|
@ -1269,7 +1260,7 @@ impl<'a> Parser<'a> {
|
|||
TokenTree::Token(token, _) => return looker(token),
|
||||
&TokenTree::Delimited(dspan, _, delim, _) => {
|
||||
if !delim.skip() {
|
||||
return looker(&Token::new(token::OpenDelim(delim), dspan.open));
|
||||
return looker(&Token::new(delim.as_open_token_kind(), dspan.open));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1283,7 +1274,7 @@ impl<'a> Parser<'a> {
|
|||
{
|
||||
// We are not in the outermost token stream, so we have
|
||||
// delimiters. Also, those delimiters are not skipped.
|
||||
return looker(&Token::new(token::CloseDelim(delim), span.close));
|
||||
return looker(&Token::new(delim.as_close_token_kind(), span.close));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1298,7 +1289,7 @@ impl<'a> Parser<'a> {
|
|||
token = cursor.next().0;
|
||||
if matches!(
|
||||
token.kind,
|
||||
token::OpenDelim(delim) | token::CloseDelim(delim) if delim.skip()
|
||||
token::OpenInvisible(origin) | token::CloseInvisible(origin) if origin.skip()
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -1386,8 +1377,7 @@ impl<'a> Parser<'a> {
|
|||
fn parse_constness_(&mut self, case: Case, is_closure: bool) -> Const {
|
||||
// Avoid const blocks and const closures to be parsed as const items
|
||||
if (self.check_const_closure() == is_closure)
|
||||
&& !self
|
||||
.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_metavar_block())
|
||||
&& !self.look_ahead(1, |t| *t == token::OpenBrace || t.is_metavar_block())
|
||||
&& self.eat_keyword_case(exp!(Const), case)
|
||||
{
|
||||
Const::Yes(self.prev_token_uninterpolated_span())
|
||||
|
|
@ -1486,48 +1476,46 @@ impl<'a> Parser<'a> {
|
|||
|
||||
/// Parses a single token tree from the input.
|
||||
pub fn parse_token_tree(&mut self) -> TokenTree {
|
||||
match self.token.kind {
|
||||
token::OpenDelim(..) => {
|
||||
// Clone the `TokenTree::Delimited` that we are currently
|
||||
// within. That's what we are going to return.
|
||||
let tree = self.token_cursor.stack.last().unwrap().curr().unwrap().clone();
|
||||
debug_assert_matches!(tree, TokenTree::Delimited(..));
|
||||
if self.token.kind.open_delim().is_some() {
|
||||
// Clone the `TokenTree::Delimited` that we are currently
|
||||
// within. That's what we are going to return.
|
||||
let tree = self.token_cursor.stack.last().unwrap().curr().unwrap().clone();
|
||||
debug_assert_matches!(tree, TokenTree::Delimited(..));
|
||||
|
||||
// Advance the token cursor through the entire delimited
|
||||
// sequence. After getting the `OpenDelim` we are *within* the
|
||||
// delimited sequence, i.e. at depth `d`. After getting the
|
||||
// matching `CloseDelim` we are *after* the delimited sequence,
|
||||
// i.e. at depth `d - 1`.
|
||||
let target_depth = self.token_cursor.stack.len() - 1;
|
||||
loop {
|
||||
// Advance one token at a time, so `TokenCursor::next()`
|
||||
// can capture these tokens if necessary.
|
||||
self.bump();
|
||||
if self.token_cursor.stack.len() == target_depth {
|
||||
debug_assert_matches!(self.token.kind, token::CloseDelim(_));
|
||||
break;
|
||||
}
|
||||
// Advance the token cursor through the entire delimited
|
||||
// sequence. After getting the `OpenDelim` we are *within* the
|
||||
// delimited sequence, i.e. at depth `d`. After getting the
|
||||
// matching `CloseDelim` we are *after* the delimited sequence,
|
||||
// i.e. at depth `d - 1`.
|
||||
let target_depth = self.token_cursor.stack.len() - 1;
|
||||
loop {
|
||||
// Advance one token at a time, so `TokenCursor::next()`
|
||||
// can capture these tokens if necessary.
|
||||
self.bump();
|
||||
if self.token_cursor.stack.len() == target_depth {
|
||||
debug_assert!(self.token.kind.close_delim().is_some());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Consume close delimiter
|
||||
self.bump();
|
||||
tree
|
||||
}
|
||||
token::CloseDelim(_) | token::Eof => unreachable!(),
|
||||
_ => {
|
||||
let prev_spacing = self.token_spacing;
|
||||
self.bump();
|
||||
TokenTree::Token(self.prev_token, prev_spacing)
|
||||
}
|
||||
// Consume close delimiter
|
||||
self.bump();
|
||||
tree
|
||||
} else {
|
||||
assert!(!self.token.kind.is_close_delim_or_eof());
|
||||
let prev_spacing = self.token_spacing;
|
||||
self.bump();
|
||||
TokenTree::Token(self.prev_token, prev_spacing)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_tokens(&mut self) -> TokenStream {
|
||||
let mut result = Vec::new();
|
||||
loop {
|
||||
match self.token.kind {
|
||||
token::Eof | token::CloseDelim(..) => break,
|
||||
_ => result.push(self.parse_token_tree()),
|
||||
if self.token.kind.is_close_delim_or_eof() {
|
||||
break;
|
||||
} else {
|
||||
result.push(self.parse_token_tree());
|
||||
}
|
||||
}
|
||||
TokenStream::new(result)
|
||||
|
|
@ -1590,7 +1578,7 @@ impl<'a> Parser<'a> {
|
|||
kind: vis,
|
||||
tokens: None,
|
||||
});
|
||||
} else if self.look_ahead(2, |t| t == &token::CloseDelim(Delimiter::Parenthesis))
|
||||
} else if self.look_ahead(2, |t| t == &token::CloseParen)
|
||||
&& self.is_keyword_ahead(1, &[kw::Crate, kw::Super, kw::SelfLower])
|
||||
{
|
||||
// Parse `pub(crate)`, `pub(self)`, or `pub(super)`.
|
||||
|
|
@ -1687,9 +1675,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
/// `::{` or `::*`
|
||||
fn is_import_coupler(&mut self) -> bool {
|
||||
self.check_path_sep_and_look_ahead(|t| {
|
||||
matches!(t.kind, token::OpenDelim(Delimiter::Brace) | token::Star)
|
||||
})
|
||||
self.check_path_sep_and_look_ahead(|t| matches!(t.kind, token::OpenBrace | token::Star))
|
||||
}
|
||||
|
||||
// Debug view of the parser's token stream, up to `{lookahead}` tokens.
|
||||
|
|
@ -1744,9 +1730,7 @@ impl<'a> Parser<'a> {
|
|||
pub fn token_uninterpolated_span(&self) -> Span {
|
||||
match &self.token.kind {
|
||||
token::NtIdent(ident, _) | token::NtLifetime(ident, _) => ident.span,
|
||||
token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => {
|
||||
self.look_ahead(1, |t| t.span)
|
||||
}
|
||||
token::OpenInvisible(InvisibleOrigin::MetaVar(_)) => self.look_ahead(1, |t| t.span),
|
||||
_ => self.token.span,
|
||||
}
|
||||
}
|
||||
|
|
@ -1755,9 +1739,7 @@ impl<'a> Parser<'a> {
|
|||
pub fn prev_token_uninterpolated_span(&self) -> Span {
|
||||
match &self.prev_token.kind {
|
||||
token::NtIdent(ident, _) | token::NtLifetime(ident, _) => ident.span,
|
||||
token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => {
|
||||
self.look_ahead(0, |t| t.span)
|
||||
}
|
||||
token::OpenInvisible(InvisibleOrigin::MetaVar(_)) => self.look_ahead(0, |t| t.span),
|
||||
_ => self.prev_token.span,
|
||||
}
|
||||
}
|
||||
|
|
@ -1776,7 +1758,7 @@ pub(crate) fn make_unclosed_delims_error(
|
|||
};
|
||||
let err = psess.dcx().create_err(MismatchedClosingDelimiter {
|
||||
spans,
|
||||
delimiter: pprust::token_kind_to_string(&token::CloseDelim(found_delim)).to_string(),
|
||||
delimiter: pprust::token_kind_to_string(&found_delim.as_close_token_kind()).to_string(),
|
||||
unmatched: unmatched.found_span,
|
||||
opening_candidate: unmatched.candidate_span,
|
||||
unclosed: unmatched.unclosed_span,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::NtExprKind::*;
|
||||
use rustc_ast::token::NtPatKind::*;
|
||||
use rustc_ast::token::{self, Delimiter, InvisibleOrigin, MetaVarKind, NonterminalKind, Token};
|
||||
use rustc_ast::token::{self, InvisibleOrigin, MetaVarKind, NonterminalKind, Token};
|
||||
use rustc_errors::PResult;
|
||||
use rustc_span::{Ident, kw};
|
||||
|
||||
|
|
@ -69,13 +69,13 @@ impl<'a> Parser<'a> {
|
|||
| token::Ident(..)
|
||||
| token::NtIdent(..)
|
||||
| token::NtLifetime(..)
|
||||
| token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => true,
|
||||
| token::OpenInvisible(InvisibleOrigin::MetaVar(_)) => true,
|
||||
_ => token.can_begin_type(),
|
||||
},
|
||||
NonterminalKind::Block => match &token.kind {
|
||||
token::OpenDelim(Delimiter::Brace) => true,
|
||||
token::OpenBrace => true,
|
||||
token::NtLifetime(..) => true,
|
||||
token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(k))) => match k {
|
||||
token::OpenInvisible(InvisibleOrigin::MetaVar(k)) => match k {
|
||||
MetaVarKind::Block
|
||||
| MetaVarKind::Stmt
|
||||
| MetaVarKind::Expr { .. }
|
||||
|
|
@ -94,9 +94,7 @@ impl<'a> Parser<'a> {
|
|||
},
|
||||
NonterminalKind::Path | NonterminalKind::Meta => match &token.kind {
|
||||
token::PathSep | token::Ident(..) | token::NtIdent(..) => true,
|
||||
token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(kind))) => {
|
||||
may_be_ident(*kind)
|
||||
}
|
||||
token::OpenInvisible(InvisibleOrigin::MetaVar(kind)) => may_be_ident(*kind),
|
||||
_ => false,
|
||||
},
|
||||
NonterminalKind::Pat(pat_kind) => token.can_begin_pattern(pat_kind),
|
||||
|
|
@ -105,7 +103,7 @@ impl<'a> Parser<'a> {
|
|||
_ => false,
|
||||
},
|
||||
NonterminalKind::TT | NonterminalKind::Item | NonterminalKind::Stmt => {
|
||||
!matches!(token.kind, token::CloseDelim(_))
|
||||
token.kind.close_delim().is_none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::ops::Bound;
|
|||
use rustc_ast::mut_visit::{self, MutVisitor};
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::NtPatKind::*;
|
||||
use rustc_ast::token::{self, Delimiter, IdentIsRaw, MetaVarKind, Token};
|
||||
use rustc_ast::token::{self, IdentIsRaw, MetaVarKind, Token};
|
||||
use rustc_ast::util::parser::ExprPrecedence;
|
||||
use rustc_ast::visit::{self, Visitor};
|
||||
use rustc_ast::{
|
||||
|
|
@ -323,7 +323,7 @@ impl<'a> Parser<'a> {
|
|||
fn eat_or_separator(&mut self, lo: Option<Span>) -> EatOrResult {
|
||||
if self.recover_trailing_vert(lo) {
|
||||
EatOrResult::TrailingVert
|
||||
} else if matches!(self.token.kind, token::OrOr) {
|
||||
} else if self.token.kind == token::OrOr {
|
||||
// Found `||`; Recover and pretend we parsed `|`.
|
||||
self.dcx().emit_err(UnexpectedVertVertInPattern { span: self.token.span, start: lo });
|
||||
self.bump();
|
||||
|
|
@ -352,9 +352,9 @@ impl<'a> Parser<'a> {
|
|||
| token::Semi // e.g. `let a |;`.
|
||||
| token::Colon // e.g. `let a | :`.
|
||||
| token::Comma // e.g. `let (a |,)`.
|
||||
| token::CloseDelim(Delimiter::Bracket) // e.g. `let [a | ]`.
|
||||
| token::CloseDelim(Delimiter::Parenthesis) // e.g. `let (a | )`.
|
||||
| token::CloseDelim(Delimiter::Brace) // e.g. `let A { f: a | }`.
|
||||
| token::CloseBracket // e.g. `let [a | ]`.
|
||||
| token::CloseParen // e.g. `let (a | )`.
|
||||
| token::CloseBrace // e.g. `let A { f: a | }`.
|
||||
)
|
||||
});
|
||||
match (is_end_ahead, &self.token.kind) {
|
||||
|
|
@ -364,7 +364,7 @@ impl<'a> Parser<'a> {
|
|||
span: self.token.span,
|
||||
start: lo,
|
||||
token: self.token,
|
||||
note_double_vert: matches!(self.token.kind, token::OrOr),
|
||||
note_double_vert: self.token.kind == token::OrOr,
|
||||
});
|
||||
self.bump();
|
||||
true
|
||||
|
|
@ -438,8 +438,8 @@ impl<'a> Parser<'a> {
|
|||
| token::Caret | token::And | token::Shl | token::Shr // excludes `Or`
|
||||
)
|
||||
|| self.token == token::Question
|
||||
|| (self.token == token::OpenDelim(Delimiter::Bracket)
|
||||
&& self.look_ahead(1, |t| *t != token::CloseDelim(Delimiter::Bracket))) // excludes `[]`
|
||||
|| (self.token == token::OpenBracket
|
||||
&& self.look_ahead(1, |t| *t != token::CloseBracket)) // excludes `[]`
|
||||
|| self.token.is_keyword(kw::As);
|
||||
|
||||
if !has_dot_expr && !has_trailing_operator {
|
||||
|
|
@ -481,7 +481,7 @@ impl<'a> Parser<'a> {
|
|||
let is_bound = is_end_bound
|
||||
// is_start_bound: either `..` or `)..`
|
||||
|| self.token.is_range_separator()
|
||||
|| self.token == token::CloseDelim(Delimiter::Parenthesis)
|
||||
|| self.token == token::CloseParen
|
||||
&& self.look_ahead(1, Token::is_range_separator);
|
||||
|
||||
let span = expr.span;
|
||||
|
|
@ -835,7 +835,7 @@ impl<'a> Parser<'a> {
|
|||
// because we never have `'a: label {}` in a pattern position anyways, but it does
|
||||
// keep us from suggesting something like `let 'a: Ty = ..` => `let 'a': Ty = ..`
|
||||
&& could_be_unclosed_char_literal(lt)
|
||||
&& !self.look_ahead(1, |token| matches!(token.kind, token::Colon))
|
||||
&& !self.look_ahead(1, |token| token.kind == token::Colon)
|
||||
{
|
||||
// Recover a `'a` as a `'a'` literal
|
||||
let lt = self.expect_lifetime();
|
||||
|
|
@ -1255,8 +1255,8 @@ impl<'a> Parser<'a> {
|
|||
|| t.is_metavar_expr()
|
||||
|| t.is_lifetime() // recover `'a` instead of `'a'`
|
||||
|| (self.may_recover() // recover leading `(`
|
||||
&& *t == token::OpenDelim(Delimiter::Parenthesis)
|
||||
&& self.look_ahead(dist + 1, |t| *t != token::OpenDelim(Delimiter::Parenthesis))
|
||||
&& *t == token::OpenParen
|
||||
&& self.look_ahead(dist + 1, |t| *t != token::OpenParen)
|
||||
&& self.is_pat_range_end_start(dist + 1))
|
||||
})
|
||||
}
|
||||
|
|
@ -1264,9 +1264,8 @@ impl<'a> Parser<'a> {
|
|||
/// Parse a range pattern end bound
|
||||
fn parse_pat_range_end(&mut self) -> PResult<'a, P<Expr>> {
|
||||
// recover leading `(`
|
||||
let open_paren = (self.may_recover()
|
||||
&& self.eat_noexpect(&token::OpenDelim(Delimiter::Parenthesis)))
|
||||
.then_some(self.prev_token.span);
|
||||
let open_paren = (self.may_recover() && self.eat_noexpect(&token::OpenParen))
|
||||
.then_some(self.prev_token.span);
|
||||
|
||||
let bound = if self.check_inline_const(0) {
|
||||
self.parse_const_block(self.token.span, true)
|
||||
|
|
@ -1322,8 +1321,8 @@ impl<'a> Parser<'a> {
|
|||
// Avoid `in`. Due to recovery in the list parser this messes with `for ( $pat in $expr )`.
|
||||
&& !self.token.is_keyword(kw::In)
|
||||
// Try to do something more complex?
|
||||
&& self.look_ahead(1, |t| !matches!(t.kind, token::OpenDelim(Delimiter::Parenthesis) // A tuple struct pattern.
|
||||
| token::OpenDelim(Delimiter::Brace) // A struct pattern.
|
||||
&& self.look_ahead(1, |t| !matches!(t.kind, token::OpenParen // A tuple struct pattern.
|
||||
| token::OpenBrace // A struct pattern.
|
||||
| token::DotDotDot | token::DotDotEq | token::DotDot // A range pattern.
|
||||
| token::PathSep // A tuple / struct variant pattern.
|
||||
| token::Bang)) // A macro expanding to a pattern.
|
||||
|
|
@ -1361,7 +1360,7 @@ impl<'a> Parser<'a> {
|
|||
// This shortly leads to a parse error. Note that if there is no explicit
|
||||
// binding mode then we do not end up here, because the lookahead
|
||||
// will direct us over to `parse_enum_variant()`.
|
||||
if self.token == token::OpenDelim(Delimiter::Parenthesis) {
|
||||
if self.token == token::OpenParen {
|
||||
return Err(self
|
||||
.dcx()
|
||||
.create_err(EnumPatternInsteadOfIdentifier { span: self.prev_token.span }));
|
||||
|
|
@ -1429,9 +1428,9 @@ impl<'a> Parser<'a> {
|
|||
token::Comma,
|
||||
token::Semi,
|
||||
token::At,
|
||||
token::OpenDelim(Delimiter::Brace),
|
||||
token::CloseDelim(Delimiter::Brace),
|
||||
token::CloseDelim(Delimiter::Parenthesis),
|
||||
token::OpenBrace,
|
||||
token::CloseBrace,
|
||||
token::CloseParen,
|
||||
]
|
||||
.contains(&self.token.kind)
|
||||
}
|
||||
|
|
@ -1489,7 +1488,7 @@ impl<'a> Parser<'a> {
|
|||
let mut first_etc_and_maybe_comma_span = None;
|
||||
let mut last_non_comma_dotdot_span = None;
|
||||
|
||||
while self.token != token::CloseDelim(Delimiter::Brace) {
|
||||
while self.token != token::CloseBrace {
|
||||
// check that a comma comes after every field
|
||||
if !ate_comma {
|
||||
let err = if self.token == token::At {
|
||||
|
|
@ -1538,7 +1537,7 @@ impl<'a> Parser<'a> {
|
|||
self.recover_bad_dot_dot();
|
||||
self.bump(); // `..` || `...` || `_`
|
||||
|
||||
if self.token == token::CloseDelim(Delimiter::Brace) {
|
||||
if self.token == token::CloseBrace {
|
||||
break;
|
||||
}
|
||||
let token_str = super::token_descr(&self.token);
|
||||
|
|
@ -1561,7 +1560,7 @@ impl<'a> Parser<'a> {
|
|||
ate_comma = true;
|
||||
}
|
||||
|
||||
if self.token == token::CloseDelim(Delimiter::Brace) {
|
||||
if self.token == token::CloseBrace {
|
||||
// If the struct looks otherwise well formed, recover and continue.
|
||||
if let Some(sp) = comma_sp {
|
||||
err.span_suggestion_short(
|
||||
|
|
@ -1681,7 +1680,7 @@ impl<'a> Parser<'a> {
|
|||
// We found `ref mut? ident:`, try to parse a `name,` or `name }`.
|
||||
&& let Some(name_span) = self.look_ahead(1, |t| t.is_ident().then(|| t.span))
|
||||
&& self.look_ahead(2, |t| {
|
||||
t == &token::Comma || t == &token::CloseDelim(Delimiter::Brace)
|
||||
t == &token::Comma || t == &token::CloseBrace
|
||||
})
|
||||
{
|
||||
let span = last.pat.span.with_hi(ident.span.lo());
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::mem;
|
|||
|
||||
use ast::token::IdentIsRaw;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, Delimiter, MetaVarKind, Token, TokenKind};
|
||||
use rustc_ast::token::{self, MetaVarKind, Token, TokenKind};
|
||||
use rustc_ast::{
|
||||
self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocItemConstraint,
|
||||
AssocItemConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs,
|
||||
|
|
@ -302,10 +302,7 @@ impl<'a> Parser<'a> {
|
|||
) -> PResult<'a, PathSegment> {
|
||||
let ident = self.parse_path_segment_ident()?;
|
||||
let is_args_start = |token: &Token| {
|
||||
matches!(
|
||||
token.kind,
|
||||
token::Lt | token::Shl | token::OpenDelim(Delimiter::Parenthesis) | token::LArrow
|
||||
)
|
||||
matches!(token.kind, token::Lt | token::Shl | token::OpenParen | token::LArrow)
|
||||
};
|
||||
let check_args_start = |this: &mut Self| {
|
||||
this.expected_token_types.insert(TokenType::Lt);
|
||||
|
|
@ -366,7 +363,7 @@ impl<'a> Parser<'a> {
|
|||
})?;
|
||||
let span = lo.to(self.prev_token.span);
|
||||
AngleBracketedArgs { args, span }.into()
|
||||
} else if self.token == token::OpenDelim(Delimiter::Parenthesis)
|
||||
} else if self.token == token::OpenParen
|
||||
// FIXME(return_type_notation): Could also recover `...` here.
|
||||
&& self.look_ahead(1, |t| *t == token::DotDot)
|
||||
{
|
||||
|
|
@ -852,7 +849,7 @@ impl<'a> Parser<'a> {
|
|||
/// the caller.
|
||||
pub(super) fn parse_const_arg(&mut self) -> PResult<'a, AnonConst> {
|
||||
// Parse const argument.
|
||||
let value = if let token::OpenDelim(Delimiter::Brace) = self.token.kind {
|
||||
let value = if self.token.kind == token::OpenBrace {
|
||||
self.parse_expr_block(None, self.token.span, BlockCheckMode::Default)?
|
||||
} else {
|
||||
self.handle_unambiguous_unbraced_const_arg()?
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ impl<'a> Parser<'a> {
|
|||
// Do not attempt to parse an expression if we're done here.
|
||||
self.error_outer_attrs(attrs);
|
||||
self.mk_stmt(lo, StmtKind::Empty)
|
||||
} else if self.token != token::CloseDelim(Delimiter::Brace) {
|
||||
} else if self.token != token::CloseBrace {
|
||||
// Remainder are line-expr stmts. This is similar to the `parse_stmt_path_start` case
|
||||
// above.
|
||||
let restrictions =
|
||||
|
|
@ -254,9 +254,7 @@ impl<'a> Parser<'a> {
|
|||
self.token.kind,
|
||||
token::Semi
|
||||
| token::Eof
|
||||
| token::CloseDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
|
||||
MetaVarKind::Stmt
|
||||
)))
|
||||
| token::CloseInvisible(InvisibleOrigin::MetaVar(MetaVarKind::Stmt))
|
||||
) {
|
||||
StmtKind::MacCall(P(MacCallStmt { mac, style, attrs, tokens: None }))
|
||||
} else {
|
||||
|
|
@ -547,7 +545,7 @@ impl<'a> Parser<'a> {
|
|||
// + +
|
||||
Ok(Some(_))
|
||||
if (!self.token.is_keyword(kw::Else)
|
||||
&& self.look_ahead(1, |t| t == &token::OpenDelim(Delimiter::Brace)))
|
||||
&& self.look_ahead(1, |t| t == &token::OpenBrace))
|
||||
|| do_not_suggest_help => {}
|
||||
// Do not suggest `if foo println!("") {;}` (as would be seen in test for #46836).
|
||||
Ok(Some(Stmt { kind: StmtKind::Empty, .. })) => {}
|
||||
|
|
@ -584,9 +582,7 @@ impl<'a> Parser<'a> {
|
|||
stmt_kind: &StmtKind,
|
||||
) {
|
||||
match (&self.token.kind, &stmt_kind) {
|
||||
(token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr))
|
||||
if let ExprKind::Call(..) = expr.kind =>
|
||||
{
|
||||
(token::OpenBrace, StmtKind::Expr(expr)) if let ExprKind::Call(..) = expr.kind => {
|
||||
// for _ in x y() {}
|
||||
e.span_suggestion_verbose(
|
||||
between,
|
||||
|
|
@ -595,9 +591,7 @@ impl<'a> Parser<'a> {
|
|||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
(token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr))
|
||||
if let ExprKind::Field(..) = expr.kind =>
|
||||
{
|
||||
(token::OpenBrace, StmtKind::Expr(expr)) if let ExprKind::Field(..) = expr.kind => {
|
||||
// for _ in x y.z {}
|
||||
e.span_suggestion_verbose(
|
||||
between,
|
||||
|
|
@ -606,7 +600,7 @@ impl<'a> Parser<'a> {
|
|||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
(token::CloseDelim(Delimiter::Brace), StmtKind::Expr(expr))
|
||||
(token::CloseBrace, StmtKind::Expr(expr))
|
||||
if let ExprKind::Struct(expr) = &expr.kind
|
||||
&& let None = expr.qself
|
||||
&& expr.path.segments.len() == 1 =>
|
||||
|
|
@ -621,7 +615,7 @@ impl<'a> Parser<'a> {
|
|||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
(token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr))
|
||||
(token::OpenBrace, StmtKind::Expr(expr))
|
||||
if let ExprKind::Lit(lit) = expr.kind
|
||||
&& let None = lit.suffix
|
||||
&& let token::LitKind::Integer | token::LitKind::Float = lit.kind =>
|
||||
|
|
@ -635,7 +629,7 @@ impl<'a> Parser<'a> {
|
|||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
(token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr))
|
||||
(token::OpenBrace, StmtKind::Expr(expr))
|
||||
if let ExprKind::Loop(..)
|
||||
| ExprKind::If(..)
|
||||
| ExprKind::While(..)
|
||||
|
|
@ -658,7 +652,7 @@ impl<'a> Parser<'a> {
|
|||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
(token::OpenDelim(Delimiter::Brace), _) => {}
|
||||
(token::OpenBrace, _) => {}
|
||||
(_, _) => {
|
||||
e.multipart_suggestion(
|
||||
"you might have meant to write this as part of a block",
|
||||
|
|
@ -809,7 +803,7 @@ impl<'a> Parser<'a> {
|
|||
// Likely `foo bar`
|
||||
} else if self.prev_token.kind == token::Question {
|
||||
// `foo? bar`
|
||||
} else if self.prev_token.kind == token::CloseDelim(Delimiter::Parenthesis) {
|
||||
} else if self.prev_token.kind == token::CloseParen {
|
||||
// `foo() bar`
|
||||
} else {
|
||||
return;
|
||||
|
|
@ -826,7 +820,7 @@ impl<'a> Parser<'a> {
|
|||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
if self.look_ahead(1, |t| t.kind == token::OpenDelim(Delimiter::Parenthesis)) {
|
||||
if self.look_ahead(1, |t| t.kind == token::OpenParen) {
|
||||
err.span_suggestion_verbose(
|
||||
self.prev_token.span.between(self.token.span),
|
||||
"you might have meant to write a method call",
|
||||
|
|
@ -870,8 +864,7 @@ impl<'a> Parser<'a> {
|
|||
StmtKind::Expr(expr)
|
||||
if classify::expr_requires_semi_to_be_stmt(expr)
|
||||
&& !expr.attrs.is_empty()
|
||||
&& ![token::Eof, token::Semi, token::CloseDelim(Delimiter::Brace)]
|
||||
.contains(&self.token.kind) =>
|
||||
&& !matches!(self.token.kind, token::Eof | token::Semi | token::CloseBrace) =>
|
||||
{
|
||||
// The user has written `#[attr] expr` which is unsupported. (#106020)
|
||||
let guar = self.attr_on_non_tail_expr(&expr);
|
||||
|
|
@ -919,7 +912,7 @@ impl<'a> Parser<'a> {
|
|||
token::Ident(
|
||||
kw::For | kw::Loop | kw::While,
|
||||
token::IdentIsRaw::No
|
||||
) | token::OpenDelim(Delimiter::Brace)
|
||||
) | token::OpenBrace
|
||||
)
|
||||
})
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2573,14 +2573,14 @@ fn look_ahead() {
|
|||
// Current position is the `fn`.
|
||||
look(&p, 0, token::Ident(kw::Fn, raw_no));
|
||||
look(&p, 1, token::Ident(sym_f, raw_no));
|
||||
look(&p, 2, token::OpenDelim(Delimiter::Parenthesis));
|
||||
look(&p, 2, token::OpenParen);
|
||||
look(&p, 3, token::Ident(sym_x, raw_no));
|
||||
look(&p, 4, token::Colon);
|
||||
look(&p, 5, token::Ident(sym::u32, raw_no));
|
||||
look(&p, 6, token::CloseDelim(Delimiter::Parenthesis));
|
||||
look(&p, 7, token::OpenDelim(Delimiter::Brace));
|
||||
look(&p, 6, token::CloseParen);
|
||||
look(&p, 7, token::OpenBrace);
|
||||
look(&p, 8, token::Ident(sym_x, raw_no));
|
||||
look(&p, 9, token::CloseDelim(Delimiter::Brace));
|
||||
look(&p, 9, token::CloseBrace);
|
||||
look(&p, 10, token::Ident(kw::Struct, raw_no));
|
||||
look(&p, 11, token::Ident(sym_S, raw_no));
|
||||
look(&p, 12, token::Semi);
|
||||
|
|
@ -2597,10 +2597,10 @@ fn look_ahead() {
|
|||
look(&p, 0, token::Ident(sym_x, raw_no));
|
||||
look(&p, 1, token::Colon);
|
||||
look(&p, 2, token::Ident(sym::u32, raw_no));
|
||||
look(&p, 3, token::CloseDelim(Delimiter::Parenthesis));
|
||||
look(&p, 4, token::OpenDelim(Delimiter::Brace));
|
||||
look(&p, 3, token::CloseParen);
|
||||
look(&p, 4, token::OpenBrace);
|
||||
look(&p, 5, token::Ident(sym_x, raw_no));
|
||||
look(&p, 6, token::CloseDelim(Delimiter::Brace));
|
||||
look(&p, 6, token::CloseBrace);
|
||||
look(&p, 7, token::Ident(kw::Struct, raw_no));
|
||||
look(&p, 8, token::Ident(sym_S, raw_no));
|
||||
look(&p, 9, token::Semi);
|
||||
|
|
@ -2652,18 +2652,18 @@ fn look_ahead_non_outermost_stream() {
|
|||
}
|
||||
look(&p, 0, token::Ident(kw::Fn, raw_no));
|
||||
look(&p, 1, token::Ident(sym_f, raw_no));
|
||||
look(&p, 2, token::OpenDelim(Delimiter::Parenthesis));
|
||||
look(&p, 2, token::OpenParen);
|
||||
look(&p, 3, token::Ident(sym_x, raw_no));
|
||||
look(&p, 4, token::Colon);
|
||||
look(&p, 5, token::Ident(sym::u32, raw_no));
|
||||
look(&p, 6, token::CloseDelim(Delimiter::Parenthesis));
|
||||
look(&p, 7, token::OpenDelim(Delimiter::Brace));
|
||||
look(&p, 6, token::CloseParen);
|
||||
look(&p, 7, token::OpenBrace);
|
||||
look(&p, 8, token::Ident(sym_x, raw_no));
|
||||
look(&p, 9, token::CloseDelim(Delimiter::Brace));
|
||||
look(&p, 9, token::CloseBrace);
|
||||
look(&p, 10, token::Ident(kw::Struct, raw_no));
|
||||
look(&p, 11, token::Ident(sym_S, raw_no));
|
||||
look(&p, 12, token::Semi);
|
||||
look(&p, 13, token::CloseDelim(Delimiter::Brace));
|
||||
look(&p, 13, token::CloseBrace);
|
||||
// Any lookahead past the end of the token stream returns `Eof`.
|
||||
look(&p, 14, token::Eof);
|
||||
look(&p, 15, token::Eof);
|
||||
|
|
@ -2723,9 +2723,7 @@ fn debug_lookahead() {
|
|||
\"f\",
|
||||
No,
|
||||
),
|
||||
OpenDelim(
|
||||
Parenthesis,
|
||||
),
|
||||
OpenParen,
|
||||
Ident(
|
||||
\"x\",
|
||||
No,
|
||||
|
|
@ -2735,9 +2733,7 @@ fn debug_lookahead() {
|
|||
\"u32\",
|
||||
No,
|
||||
),
|
||||
CloseDelim(
|
||||
Parenthesis,
|
||||
),
|
||||
CloseParen,
|
||||
],
|
||||
approx_token_stream_pos: 0,
|
||||
..
|
||||
|
|
@ -2768,9 +2764,7 @@ fn debug_lookahead() {
|
|||
\"f\",
|
||||
No,
|
||||
),
|
||||
OpenDelim(
|
||||
Parenthesis,
|
||||
),
|
||||
OpenParen,
|
||||
Ident(
|
||||
\"x\",
|
||||
No,
|
||||
|
|
@ -2780,19 +2774,13 @@ fn debug_lookahead() {
|
|||
\"u32\",
|
||||
No,
|
||||
),
|
||||
CloseDelim(
|
||||
Parenthesis,
|
||||
),
|
||||
OpenDelim(
|
||||
Brace,
|
||||
),
|
||||
CloseParen,
|
||||
OpenBrace,
|
||||
Ident(
|
||||
\"x\",
|
||||
No,
|
||||
),
|
||||
CloseDelim(
|
||||
Brace,
|
||||
),
|
||||
CloseBrace,
|
||||
Ident(
|
||||
\"struct\",
|
||||
No,
|
||||
|
|
@ -2817,9 +2805,7 @@ fn debug_lookahead() {
|
|||
&format!("{:#?}", p.debug_lookahead(1)),
|
||||
"Parser {
|
||||
prev_token: Token {
|
||||
kind: OpenDelim(
|
||||
Brace,
|
||||
),
|
||||
kind: OpenBrace,
|
||||
span: Span {
|
||||
lo: BytePos(
|
||||
13,
|
||||
|
|
@ -2844,9 +2830,7 @@ fn debug_lookahead() {
|
|||
&format!("{:#?}", p.debug_lookahead(4)),
|
||||
"Parser {
|
||||
prev_token: Token {
|
||||
kind: OpenDelim(
|
||||
Brace,
|
||||
),
|
||||
kind: OpenBrace,
|
||||
span: Span {
|
||||
lo: BytePos(
|
||||
13,
|
||||
|
|
@ -2862,9 +2846,7 @@ fn debug_lookahead() {
|
|||
\"x\",
|
||||
No,
|
||||
),
|
||||
CloseDelim(
|
||||
Brace,
|
||||
),
|
||||
CloseBrace,
|
||||
Ident(
|
||||
\"struct\",
|
||||
No,
|
||||
|
|
|
|||
|
|
@ -448,18 +448,6 @@ macro_rules! exp {
|
|||
token_type: $crate::parser::token_type::TokenType::$tok
|
||||
}
|
||||
};
|
||||
(@open, $delim:ident, $token_type:ident) => {
|
||||
$crate::parser::token_type::ExpTokenPair {
|
||||
tok: &rustc_ast::token::OpenDelim(rustc_ast::token::Delimiter::$delim),
|
||||
token_type: $crate::parser::token_type::TokenType::$token_type,
|
||||
}
|
||||
};
|
||||
(@close, $delim:ident, $token_type:ident) => {
|
||||
$crate::parser::token_type::ExpTokenPair {
|
||||
tok: &rustc_ast::token::CloseDelim(rustc_ast::token::Delimiter::$delim),
|
||||
token_type: $crate::parser::token_type::TokenType::$token_type,
|
||||
}
|
||||
};
|
||||
|
||||
// `ExpKeywordPair` helper rules.
|
||||
(@kw, $kw:ident, $token_type:ident) => {
|
||||
|
|
@ -504,12 +492,12 @@ macro_rules! exp {
|
|||
(Question) => { exp!(@tok, Question) };
|
||||
(Eof) => { exp!(@tok, Eof) };
|
||||
|
||||
(OpenParen) => { exp!(@open, Parenthesis, OpenParen) };
|
||||
(OpenBrace) => { exp!(@open, Brace, OpenBrace) };
|
||||
(OpenBracket) => { exp!(@open, Bracket, OpenBracket) };
|
||||
(CloseParen) => { exp!(@close, Parenthesis, CloseParen) };
|
||||
(CloseBrace) => { exp!(@close, Brace, CloseBrace) };
|
||||
(CloseBracket) => { exp!(@close, Bracket, CloseBracket) };
|
||||
(OpenParen) => { exp!(@tok, OpenParen) };
|
||||
(OpenBrace) => { exp!(@tok, OpenBrace) };
|
||||
(OpenBracket) => { exp!(@tok, OpenBracket) };
|
||||
(CloseParen) => { exp!(@tok, CloseParen) };
|
||||
(CloseBrace) => { exp!(@tok, CloseBrace) };
|
||||
(CloseBracket) => { exp!(@tok, CloseBracket) };
|
||||
|
||||
(As) => { exp!(@kw, As, KwAs) };
|
||||
(Async) => { exp!(@kw, Async, KwAsync) };
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, Delimiter, IdentIsRaw, MetaVarKind, Token, TokenKind};
|
||||
use rustc_ast::token::{self, IdentIsRaw, MetaVarKind, Token, TokenKind};
|
||||
use rustc_ast::util::case::Case;
|
||||
use rustc_ast::{
|
||||
self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, DUMMY_NODE_ID, FnRetTy,
|
||||
|
|
@ -98,7 +98,7 @@ fn can_begin_dyn_bound_in_edition_2015(t: &Token) -> bool {
|
|||
|| t.is_lifetime()
|
||||
|| t == &TokenKind::Question
|
||||
|| t.is_keyword(kw::For)
|
||||
|| t == &TokenKind::OpenDelim(Delimiter::Parenthesis)
|
||||
|| t == &TokenKind::OpenParen
|
||||
}
|
||||
|
||||
impl<'a> Parser<'a> {
|
||||
|
|
@ -355,7 +355,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
} else if self.check_keyword(exp!(Unsafe))
|
||||
&& self.look_ahead(1, |tok| matches!(tok.kind, token::Lt))
|
||||
&& self.look_ahead(1, |tok| tok.kind == token::Lt)
|
||||
{
|
||||
self.parse_unsafe_binder_ty()?
|
||||
} else {
|
||||
|
|
@ -534,7 +534,7 @@ impl<'a> Parser<'a> {
|
|||
let elt_ty = match self.parse_ty() {
|
||||
Ok(ty) => ty,
|
||||
Err(err)
|
||||
if self.look_ahead(1, |t| *t == token::CloseDelim(Delimiter::Bracket))
|
||||
if self.look_ahead(1, |t| *t == token::CloseBracket)
|
||||
| self.look_ahead(1, |t| *t == token::Semi) =>
|
||||
{
|
||||
// Recover from `[LIT; EXPR]` and `[LIT]`
|
||||
|
|
@ -1154,7 +1154,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
let mut path = if self.token.is_keyword(kw::Fn)
|
||||
&& self.look_ahead(1, |t| *t == TokenKind::OpenDelim(Delimiter::Parenthesis))
|
||||
&& self.look_ahead(1, |t| *t == TokenKind::OpenParen)
|
||||
&& let Some(path) = self.recover_path_from_fn()
|
||||
{
|
||||
path
|
||||
|
|
@ -1208,7 +1208,7 @@ impl<'a> Parser<'a> {
|
|||
self.parse_path(PathStyle::Type)?
|
||||
};
|
||||
|
||||
if self.may_recover() && self.token == TokenKind::OpenDelim(Delimiter::Parenthesis) {
|
||||
if self.may_recover() && self.token == TokenKind::OpenParen {
|
||||
self.recover_fn_trait_with_lifetime_params(&mut path, &mut lifetime_defs)?;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -194,12 +194,6 @@ pub fn check_attribute_safety(psess: &ParseSess, safety: AttributeSafety, attr:
|
|||
}
|
||||
}
|
||||
} else if let Safety::Unsafe(unsafe_span) = attr_item.unsafety {
|
||||
// Allow (but don't require) `#[unsafe(naked)]` so that compiler-builtins can upgrade to it.
|
||||
// FIXME(#139797): remove this special case when compiler-builtins has upgraded.
|
||||
if attr.has_name(sym::naked) {
|
||||
return;
|
||||
}
|
||||
|
||||
psess.dcx().emit_err(errors::InvalidAttrUnsafe {
|
||||
span: unsafe_span,
|
||||
name: attr_item.path.clone(),
|
||||
|
|
|
|||
|
|
@ -508,7 +508,7 @@ passes_must_use_no_effect =
|
|||
`#[must_use]` has no effect when applied to {$article} {$target}
|
||||
|
||||
passes_naked_asm_outside_naked_fn =
|
||||
the `naked_asm!` macro can only be used in functions marked with `#[naked]`
|
||||
the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]`
|
||||
|
||||
passes_naked_functions_asm_block =
|
||||
naked functions must contain a single `naked_asm!` invocation
|
||||
|
|
@ -516,9 +516,9 @@ passes_naked_functions_asm_block =
|
|||
.label_non_asm = not allowed in naked functions
|
||||
|
||||
passes_naked_functions_incompatible_attribute =
|
||||
attribute incompatible with `#[naked]`
|
||||
.label = the `{$attr}` attribute is incompatible with `#[naked]`
|
||||
.naked_attribute = function marked with `#[naked]` here
|
||||
attribute incompatible with `#[unsafe(naked)]`
|
||||
.label = the `{$attr}` attribute is incompatible with `#[unsafe(naked)]`
|
||||
.naked_attribute = function marked with `#[unsafe(naked)]` here
|
||||
|
||||
passes_naked_functions_must_naked_asm =
|
||||
the `asm!` macro is not allowed in naked functions
|
||||
|
|
|
|||
|
|
@ -693,13 +693,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
|
||||
// `#[naked]` attribute with just a lint, because we previously
|
||||
// erroneously allowed it and some crates used it accidentally, to be compatible
|
||||
// with crates depending on them, we can't throw an error here.
|
||||
Target::Field | Target::Arm | Target::MacroDef => {
|
||||
self.inline_attr_str_error_with_macro_def(hir_id, attr, "naked")
|
||||
}
|
||||
_ => {
|
||||
self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
|
||||
attr_span: attr.span(),
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use std::sync::Arc;
|
|||
use rustc_ast::expand::StrippedCfgItem;
|
||||
use rustc_ast::{self as ast, Crate, NodeId, attr};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_attr_parsing::{AttributeKind, StabilityLevel, find_attr};
|
||||
use rustc_attr_parsing::StabilityLevel;
|
||||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_errors::{Applicability, DiagCtxtHandle, StashKey};
|
||||
use rustc_expand::base::{
|
||||
|
|
@ -1128,13 +1128,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
edition,
|
||||
);
|
||||
|
||||
// The #[rustc_macro_edition_2021] attribute is used by the pin!() macro
|
||||
// as a temporary workaround for a regression in expressiveness in Rust 2024.
|
||||
// See https://github.com/rust-lang/rust/issues/138718.
|
||||
if find_attr!(attrs.iter(), AttributeKind::RustcMacroEdition2021) {
|
||||
ext.edition = Edition::Edition2021;
|
||||
}
|
||||
|
||||
if let Some(builtin_name) = ext.builtin_name {
|
||||
// The macro was marked with `#[rustc_builtin_macro]`.
|
||||
if let Some(builtin_ext_kind) = self.builtin_macros.get(&builtin_name) {
|
||||
|
|
|
|||
|
|
@ -72,6 +72,8 @@ pub struct TypeSizeInfo {
|
|||
|
||||
#[derive(Default)]
|
||||
pub struct CodeStats {
|
||||
/// The hash set that actually holds all the type size information.
|
||||
/// The field is public for use in external tools. See #139876.
|
||||
pub type_sizes: Lock<FxHashSet<TypeSizeInfo>>,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -568,122 +568,203 @@ impl FromStr for SplitDwarfKind {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, HashStable_Generic)]
|
||||
#[derive(Encodable, Decodable)]
|
||||
pub enum OutputType {
|
||||
/// This is the optimized bitcode, which could be either pre-LTO or non-LTO bitcode,
|
||||
/// depending on the specific request type.
|
||||
Bitcode,
|
||||
/// This is the summary or index data part of the ThinLTO bitcode.
|
||||
ThinLinkBitcode,
|
||||
Assembly,
|
||||
LlvmAssembly,
|
||||
Mir,
|
||||
Metadata,
|
||||
Object,
|
||||
Exe,
|
||||
DepInfo,
|
||||
}
|
||||
macro_rules! define_output_types {
|
||||
(
|
||||
$(
|
||||
$(#[doc = $doc:expr])*
|
||||
$Variant:ident => {
|
||||
shorthand: $shorthand:expr,
|
||||
extension: $extension:expr,
|
||||
description: $description:expr,
|
||||
default_filename: $default_filename:expr,
|
||||
is_text: $is_text:expr,
|
||||
compatible_with_cgus_and_single_output: $compatible:expr
|
||||
}
|
||||
),* $(,)?
|
||||
) => {
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, HashStable_Generic)]
|
||||
#[derive(Encodable, Decodable)]
|
||||
pub enum OutputType {
|
||||
$(
|
||||
$(#[doc = $doc])*
|
||||
$Variant,
|
||||
)*
|
||||
}
|
||||
|
||||
impl StableOrd for OutputType {
|
||||
const CAN_USE_UNSTABLE_SORT: bool = true;
|
||||
|
||||
// Trivial C-Style enums have a stable sort order across compilation sessions.
|
||||
const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
|
||||
}
|
||||
impl StableOrd for OutputType {
|
||||
const CAN_USE_UNSTABLE_SORT: bool = true;
|
||||
|
||||
impl<HCX: HashStableContext> ToStableHashKey<HCX> for OutputType {
|
||||
type KeyType = Self;
|
||||
// Trivial C-Style enums have a stable sort order across compilation sessions.
|
||||
const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
|
||||
}
|
||||
|
||||
fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType {
|
||||
*self
|
||||
impl<HCX: HashStableContext> ToStableHashKey<HCX> for OutputType {
|
||||
type KeyType = Self;
|
||||
|
||||
fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl OutputType {
|
||||
pub fn iter_all() -> impl Iterator<Item = OutputType> {
|
||||
static ALL_VARIANTS: &[OutputType] = &[
|
||||
$(
|
||||
OutputType::$Variant,
|
||||
)*
|
||||
];
|
||||
ALL_VARIANTS.iter().copied()
|
||||
}
|
||||
|
||||
fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
|
||||
match *self {
|
||||
$(
|
||||
OutputType::$Variant => $compatible,
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
pub fn shorthand(&self) -> &'static str {
|
||||
match *self {
|
||||
$(
|
||||
OutputType::$Variant => $shorthand,
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
fn from_shorthand(shorthand: &str) -> Option<Self> {
|
||||
match shorthand {
|
||||
$(
|
||||
s if s == $shorthand => Some(OutputType::$Variant),
|
||||
)*
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn shorthands_display() -> String {
|
||||
let shorthands = vec![
|
||||
$(
|
||||
format!("`{}`", $shorthand),
|
||||
)*
|
||||
];
|
||||
shorthands.join(", ")
|
||||
}
|
||||
|
||||
pub fn extension(&self) -> &'static str {
|
||||
match *self {
|
||||
$(
|
||||
OutputType::$Variant => $extension,
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_text_output(&self) -> bool {
|
||||
match *self {
|
||||
$(
|
||||
OutputType::$Variant => $is_text,
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
pub fn description(&self) -> &'static str {
|
||||
match *self {
|
||||
$(
|
||||
OutputType::$Variant => $description,
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
pub fn default_filename(&self) -> &'static str {
|
||||
match *self {
|
||||
$(
|
||||
OutputType::$Variant => $default_filename,
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl OutputType {
|
||||
fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
|
||||
match *self {
|
||||
OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
|
||||
OutputType::Bitcode
|
||||
| OutputType::ThinLinkBitcode
|
||||
| OutputType::Assembly
|
||||
| OutputType::LlvmAssembly
|
||||
| OutputType::Mir
|
||||
| OutputType::Object => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn shorthand(&self) -> &'static str {
|
||||
match *self {
|
||||
OutputType::Bitcode => "llvm-bc",
|
||||
OutputType::ThinLinkBitcode => "thin-link-bitcode",
|
||||
OutputType::Assembly => "asm",
|
||||
OutputType::LlvmAssembly => "llvm-ir",
|
||||
OutputType::Mir => "mir",
|
||||
OutputType::Object => "obj",
|
||||
OutputType::Metadata => "metadata",
|
||||
OutputType::Exe => "link",
|
||||
OutputType::DepInfo => "dep-info",
|
||||
}
|
||||
}
|
||||
|
||||
fn from_shorthand(shorthand: &str) -> Option<Self> {
|
||||
Some(match shorthand {
|
||||
"asm" => OutputType::Assembly,
|
||||
"llvm-ir" => OutputType::LlvmAssembly,
|
||||
"mir" => OutputType::Mir,
|
||||
"llvm-bc" => OutputType::Bitcode,
|
||||
"thin-link-bitcode" => OutputType::ThinLinkBitcode,
|
||||
"obj" => OutputType::Object,
|
||||
"metadata" => OutputType::Metadata,
|
||||
"link" => OutputType::Exe,
|
||||
"dep-info" => OutputType::DepInfo,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
fn shorthands_display() -> String {
|
||||
format!(
|
||||
"`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
|
||||
OutputType::Bitcode.shorthand(),
|
||||
OutputType::ThinLinkBitcode.shorthand(),
|
||||
OutputType::Assembly.shorthand(),
|
||||
OutputType::LlvmAssembly.shorthand(),
|
||||
OutputType::Mir.shorthand(),
|
||||
OutputType::Object.shorthand(),
|
||||
OutputType::Metadata.shorthand(),
|
||||
OutputType::Exe.shorthand(),
|
||||
OutputType::DepInfo.shorthand(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn extension(&self) -> &'static str {
|
||||
match *self {
|
||||
OutputType::Bitcode => "bc",
|
||||
OutputType::ThinLinkBitcode => "indexing.o",
|
||||
OutputType::Assembly => "s",
|
||||
OutputType::LlvmAssembly => "ll",
|
||||
OutputType::Mir => "mir",
|
||||
OutputType::Object => "o",
|
||||
OutputType::Metadata => "rmeta",
|
||||
OutputType::DepInfo => "d",
|
||||
OutputType::Exe => "",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_text_output(&self) -> bool {
|
||||
match *self {
|
||||
OutputType::Assembly
|
||||
| OutputType::LlvmAssembly
|
||||
| OutputType::Mir
|
||||
| OutputType::DepInfo => true,
|
||||
OutputType::Bitcode
|
||||
| OutputType::ThinLinkBitcode
|
||||
| OutputType::Object
|
||||
| OutputType::Metadata
|
||||
| OutputType::Exe => false,
|
||||
}
|
||||
}
|
||||
define_output_types! {
|
||||
Assembly => {
|
||||
shorthand: "asm",
|
||||
extension: "s",
|
||||
description: "Generates a file with the crate's assembly code",
|
||||
default_filename: "CRATE_NAME.s",
|
||||
is_text: true,
|
||||
compatible_with_cgus_and_single_output: false
|
||||
},
|
||||
#[doc = "This is the optimized bitcode, which could be either pre-LTO or non-LTO bitcode,"]
|
||||
#[doc = "depending on the specific request type."]
|
||||
Bitcode => {
|
||||
shorthand: "llvm-bc",
|
||||
extension: "bc",
|
||||
description: "Generates a binary file containing the LLVM bitcode",
|
||||
default_filename: "CRATE_NAME.bc",
|
||||
is_text: false,
|
||||
compatible_with_cgus_and_single_output: false
|
||||
},
|
||||
DepInfo => {
|
||||
shorthand: "dep-info",
|
||||
extension: "d",
|
||||
description: "Generates a file with Makefile syntax that indicates all the source files that were loaded to generate the crate",
|
||||
default_filename: "CRATE_NAME.d",
|
||||
is_text: true,
|
||||
compatible_with_cgus_and_single_output: true
|
||||
},
|
||||
Exe => {
|
||||
shorthand: "link",
|
||||
extension: "",
|
||||
description: "Generates the crates specified by --crate-type. This is the default if --emit is not specified",
|
||||
default_filename: "(platform and crate-type dependent)",
|
||||
is_text: false,
|
||||
compatible_with_cgus_and_single_output: true
|
||||
},
|
||||
LlvmAssembly => {
|
||||
shorthand: "llvm-ir",
|
||||
extension: "ll",
|
||||
description: "Generates a file containing LLVM IR",
|
||||
default_filename: "CRATE_NAME.ll",
|
||||
is_text: true,
|
||||
compatible_with_cgus_and_single_output: false
|
||||
},
|
||||
Metadata => {
|
||||
shorthand: "metadata",
|
||||
extension: "rmeta",
|
||||
description: "Generates a file containing metadata about the crate",
|
||||
default_filename: "libCRATE_NAME.rmeta",
|
||||
is_text: false,
|
||||
compatible_with_cgus_and_single_output: true
|
||||
},
|
||||
Mir => {
|
||||
shorthand: "mir",
|
||||
extension: "mir",
|
||||
description: "Generates a file containing rustc's mid-level intermediate representation",
|
||||
default_filename: "CRATE_NAME.mir",
|
||||
is_text: true,
|
||||
compatible_with_cgus_and_single_output: false
|
||||
},
|
||||
Object => {
|
||||
shorthand: "obj",
|
||||
extension: "o",
|
||||
description: "Generates a native object file",
|
||||
default_filename: "CRATE_NAME.o",
|
||||
is_text: false,
|
||||
compatible_with_cgus_and_single_output: false
|
||||
},
|
||||
#[doc = "This is the summary or index data part of the ThinLTO bitcode."]
|
||||
ThinLinkBitcode => {
|
||||
shorthand: "thin-link-bitcode",
|
||||
extension: "indexing.o",
|
||||
description: "Generates the ThinLTO summary as bitcode",
|
||||
default_filename: "CRATE_NAME.indexing.o",
|
||||
is_text: false,
|
||||
compatible_with_cgus_and_single_output: false
|
||||
},
|
||||
}
|
||||
|
||||
/// The type of diagnostics output to generate.
|
||||
|
|
@ -1565,13 +1646,32 @@ The default is {DEFAULT_EDITION} and the latest stable edition is {LATEST_STABLE
|
|||
static PRINT_HELP: LazyLock<String> = LazyLock::new(|| {
|
||||
format!(
|
||||
"Compiler information to print on stdout (or to a file)\n\
|
||||
INFO may be one of ({}).",
|
||||
INFO may be one of <{}>.",
|
||||
PRINT_KINDS.iter().map(|(name, _)| format!("{name}")).collect::<Vec<_>>().join("|")
|
||||
)
|
||||
});
|
||||
|
||||
static EMIT_HELP: LazyLock<String> = LazyLock::new(|| {
|
||||
let mut result =
|
||||
String::from("Comma separated list of types of output for the compiler to emit.\n");
|
||||
result.push_str("Each TYPE has the default FILE name:\n");
|
||||
|
||||
for output in OutputType::iter_all() {
|
||||
result.push_str(&format!("* {} - {}\n", output.shorthand(), output.default_filename()));
|
||||
}
|
||||
|
||||
result
|
||||
});
|
||||
|
||||
/// Returns all rustc command line options, including metadata for
|
||||
/// each option, such as whether the option is stable.
|
||||
///
|
||||
/// # Option style guidelines
|
||||
///
|
||||
/// - `<param>`: Indicates a required parameter
|
||||
/// - `[param]`: Indicates an optional parameter
|
||||
/// - `|`: Indicates a mutually exclusive option
|
||||
/// - `*`: a list element with description
|
||||
pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
|
||||
use OptionKind::{Flag, FlagMulti, Multi, Opt};
|
||||
use OptionStability::{Stable, Unstable};
|
||||
|
|
@ -1586,18 +1686,18 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
|
|||
"",
|
||||
"cfg",
|
||||
"Configure the compilation environment.\n\
|
||||
SPEC supports the syntax `NAME[=\"VALUE\"]`.",
|
||||
"SPEC",
|
||||
SPEC supports the syntax `<NAME>[=\"<VALUE>\"]`.",
|
||||
"<SPEC>",
|
||||
),
|
||||
opt(Stable, Multi, "", "check-cfg", "Provide list of expected cfgs for checking", "SPEC"),
|
||||
opt(Stable, Multi, "", "check-cfg", "Provide list of expected cfgs for checking", "<SPEC>"),
|
||||
opt(
|
||||
Stable,
|
||||
Multi,
|
||||
"L",
|
||||
"",
|
||||
"Add a directory to the library search path. \
|
||||
The optional KIND can be one of dependency, crate, native, framework, or all (the default).",
|
||||
"[KIND=]PATH",
|
||||
The optional KIND can be one of <dependency|crate|native|framework|all> (default: all).",
|
||||
"[<KIND>=]<PATH>",
|
||||
),
|
||||
opt(
|
||||
Stable,
|
||||
|
|
@ -1606,53 +1706,46 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
|
|||
"",
|
||||
"Link the generated crate(s) to the specified native\n\
|
||||
library NAME. The optional KIND can be one of\n\
|
||||
static, framework, or dylib (the default).\n\
|
||||
<static|framework|dylib> (default: dylib).\n\
|
||||
Optional comma separated MODIFIERS\n\
|
||||
(bundle|verbatim|whole-archive|as-needed)\n\
|
||||
<bundle|verbatim|whole-archive|as-needed>\n\
|
||||
may be specified each with a prefix of either '+' to\n\
|
||||
enable or '-' to disable.",
|
||||
"[KIND[:MODIFIERS]=]NAME[:RENAME]",
|
||||
"[<KIND>[:<MODIFIERS>]=]<NAME>[:<RENAME>]",
|
||||
),
|
||||
make_crate_type_option(),
|
||||
opt(Stable, Opt, "", "crate-name", "Specify the name of the crate being built", "NAME"),
|
||||
opt(Stable, Opt, "", "crate-name", "Specify the name of the crate being built", "<NAME>"),
|
||||
opt(Stable, Opt, "", "edition", &EDITION_STRING, EDITION_NAME_LIST),
|
||||
opt(
|
||||
Stable,
|
||||
Multi,
|
||||
"",
|
||||
"emit",
|
||||
"Comma separated list of types of output for the compiler to emit",
|
||||
"[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
|
||||
),
|
||||
opt(Stable, Multi, "", "print", &PRINT_HELP, "INFO[=FILE]"),
|
||||
opt(Stable, Multi, "", "emit", &EMIT_HELP, "<TYPE>[=<FILE>]"),
|
||||
opt(Stable, Multi, "", "print", &PRINT_HELP, "<INFO>[=<FILE>]"),
|
||||
opt(Stable, FlagMulti, "g", "", "Equivalent to -C debuginfo=2", ""),
|
||||
opt(Stable, FlagMulti, "O", "", "Equivalent to -C opt-level=3", ""),
|
||||
opt(Stable, Opt, "o", "", "Write output to <filename>", "FILENAME"),
|
||||
opt(Stable, Opt, "", "out-dir", "Write output to compiler-chosen filename in <dir>", "DIR"),
|
||||
opt(Stable, Opt, "o", "", "Write output to FILENAME", "<FILENAME>"),
|
||||
opt(Stable, Opt, "", "out-dir", "Write output to compiler-chosen filename in DIR", "<DIR>"),
|
||||
opt(
|
||||
Stable,
|
||||
Opt,
|
||||
"",
|
||||
"explain",
|
||||
"Provide a detailed explanation of an error message",
|
||||
"OPT",
|
||||
"<OPT>",
|
||||
),
|
||||
opt(Stable, Flag, "", "test", "Build a test harness", ""),
|
||||
opt(Stable, Opt, "", "target", "Target triple for which the code is compiled", "TARGET"),
|
||||
opt(Stable, Multi, "A", "allow", "Set lint allowed", "LINT"),
|
||||
opt(Stable, Multi, "W", "warn", "Set lint warnings", "LINT"),
|
||||
opt(Stable, Multi, "", "force-warn", "Set lint force-warn", "LINT"),
|
||||
opt(Stable, Multi, "D", "deny", "Set lint denied", "LINT"),
|
||||
opt(Stable, Multi, "F", "forbid", "Set lint forbidden", "LINT"),
|
||||
opt(Stable, Opt, "", "target", "Target triple for which the code is compiled", "<TARGET>"),
|
||||
opt(Stable, Multi, "A", "allow", "Set lint allowed", "<LINT>"),
|
||||
opt(Stable, Multi, "W", "warn", "Set lint warnings", "<LINT>"),
|
||||
opt(Stable, Multi, "", "force-warn", "Set lint force-warn", "<LINT>"),
|
||||
opt(Stable, Multi, "D", "deny", "Set lint denied", "<LINT>"),
|
||||
opt(Stable, Multi, "F", "forbid", "Set lint forbidden", "<LINT>"),
|
||||
opt(
|
||||
Stable,
|
||||
Multi,
|
||||
"",
|
||||
"cap-lints",
|
||||
"Set the most restrictive lint level. More restrictive lints are capped at this level",
|
||||
"LEVEL",
|
||||
"<LEVEL>",
|
||||
),
|
||||
opt(Stable, Multi, "C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
|
||||
opt(Stable, Multi, "C", "codegen", "Set a codegen option", "<OPT>[=<VALUE>]"),
|
||||
opt(Stable, Flag, "V", "version", "Print version info and exit", ""),
|
||||
opt(Stable, Flag, "v", "verbose", "Use verbose output", ""),
|
||||
];
|
||||
|
|
@ -1666,29 +1759,29 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
|
|||
"",
|
||||
"extern",
|
||||
"Specify where an external rust library is located",
|
||||
"NAME[=PATH]",
|
||||
"<NAME>[=<PATH>]",
|
||||
),
|
||||
opt(Stable, Opt, "", "sysroot", "Override the system root", "PATH"),
|
||||
opt(Unstable, Multi, "Z", "", "Set unstable / perma-unstable options", "FLAG"),
|
||||
opt(Stable, Opt, "", "sysroot", "Override the system root", "<PATH>"),
|
||||
opt(Unstable, Multi, "Z", "", "Set unstable / perma-unstable options", "<FLAG>"),
|
||||
opt(
|
||||
Stable,
|
||||
Opt,
|
||||
"",
|
||||
"error-format",
|
||||
"How errors and other messages are produced",
|
||||
"human|json|short",
|
||||
"<human|json|short>",
|
||||
),
|
||||
opt(Stable, Multi, "", "json", "Configure the JSON output of the compiler", "CONFIG"),
|
||||
opt(Stable, Multi, "", "json", "Configure the JSON output of the compiler", "<CONFIG>"),
|
||||
opt(
|
||||
Stable,
|
||||
Opt,
|
||||
"",
|
||||
"color",
|
||||
"Configure coloring of output:
|
||||
auto = colorize, if output goes to a tty (default);
|
||||
always = always colorize output;
|
||||
never = never colorize output",
|
||||
"auto|always|never",
|
||||
* auto = colorize, if output goes to a tty (default);
|
||||
* always = always colorize output;
|
||||
* never = never colorize output",
|
||||
"<auto|always|never>",
|
||||
),
|
||||
opt(
|
||||
Stable,
|
||||
|
|
@ -1696,7 +1789,7 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
|
|||
"",
|
||||
"diagnostic-width",
|
||||
"Inform rustc of the width of the output so that diagnostics can be truncated to fit",
|
||||
"WIDTH",
|
||||
"<WIDTH>",
|
||||
),
|
||||
opt(
|
||||
Stable,
|
||||
|
|
@ -1704,9 +1797,9 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
|
|||
"",
|
||||
"remap-path-prefix",
|
||||
"Remap source names in all output (compiler messages and output files)",
|
||||
"FROM=TO",
|
||||
"<FROM>=<TO>",
|
||||
),
|
||||
opt(Unstable, Multi, "", "env-set", "Inject an environment variable", "VAR=VALUE"),
|
||||
opt(Unstable, Multi, "", "env-set", "Inject an environment variable", "<VAR>=<VALUE>"),
|
||||
];
|
||||
options.extend(verbose_only.into_iter().map(|mut opt| {
|
||||
opt.is_verbose_help_only = true;
|
||||
|
|
@ -2706,7 +2799,7 @@ pub fn make_crate_type_option() -> RustcOptGroup {
|
|||
"crate-type",
|
||||
"Comma separated list of types of crates
|
||||
for the compiler to emit",
|
||||
"[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
|
||||
"<bin|lib|rlib|dylib|cdylib|staticlib|proc-macro>",
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ pub const ALL_EDITIONS: &[Edition] = &[
|
|||
Edition::EditionFuture,
|
||||
];
|
||||
|
||||
pub const EDITION_NAME_LIST: &str = "2015|2018|2021|2024";
|
||||
pub const EDITION_NAME_LIST: &str = "<2015|2018|2021|2024|future>";
|
||||
|
||||
pub const DEFAULT_EDITION: Edition = Edition::Edition2015;
|
||||
|
||||
|
|
|
|||
|
|
@ -1232,6 +1232,25 @@ impl DesugaringKind {
|
|||
DesugaringKind::PatTyRange => "pattern type",
|
||||
}
|
||||
}
|
||||
|
||||
/// For use with `rustc_unimplemented` to support conditions
|
||||
/// like `from_desugaring = "QuestionMark"`
|
||||
pub fn matches(&self, value: &str) -> bool {
|
||||
match self {
|
||||
DesugaringKind::CondTemporary => value == "CondTemporary",
|
||||
DesugaringKind::Async => value == "Async",
|
||||
DesugaringKind::Await => value == "Await",
|
||||
DesugaringKind::QuestionMark => value == "QuestionMark",
|
||||
DesugaringKind::TryBlock => value == "TryBlock",
|
||||
DesugaringKind::YeetExpr => value == "YeetExpr",
|
||||
DesugaringKind::OpaqueTy => value == "OpaqueTy",
|
||||
DesugaringKind::ForLoop => value == "ForLoop",
|
||||
DesugaringKind::WhileLoop => value == "WhileLoop",
|
||||
DesugaringKind::BoundModifier => value == "BoundModifier",
|
||||
DesugaringKind::Contract => value == "Contract",
|
||||
DesugaringKind::PatTyRange => value == "PatTyRange",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
|
|
|||
|
|
@ -372,6 +372,7 @@ symbols! {
|
|||
SyncUnsafeCell,
|
||||
T,
|
||||
Target,
|
||||
This,
|
||||
ToOwned,
|
||||
ToString,
|
||||
TokenStream,
|
||||
|
|
@ -1823,7 +1824,6 @@ symbols! {
|
|||
rustc_lint_opt_ty,
|
||||
rustc_lint_query_instability,
|
||||
rustc_lint_untracked_query_information,
|
||||
rustc_macro_edition_2021,
|
||||
rustc_macro_transparency,
|
||||
rustc_main,
|
||||
rustc_mir,
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
use crate::spec::{LinkSelfContainedDefault, TargetOptions, base, crt_objects};
|
||||
|
||||
pub(crate) fn opts() -> TargetOptions {
|
||||
let mut base = base::linux::opts();
|
||||
|
||||
base.env = "musl".into();
|
||||
base.pre_link_objects_self_contained = crt_objects::pre_musl_self_contained();
|
||||
base.post_link_objects_self_contained = crt_objects::post_musl_self_contained();
|
||||
base.link_self_contained = LinkSelfContainedDefault::InferredForMusl;
|
||||
|
||||
base
|
||||
TargetOptions {
|
||||
env: "musl".into(),
|
||||
pre_link_objects_self_contained: crt_objects::pre_musl_self_contained(),
|
||||
post_link_objects_self_contained: crt_objects::post_musl_self_contained(),
|
||||
link_self_contained: LinkSelfContainedDefault::InferredForMusl,
|
||||
..base::linux::opts()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
use crate::spec::{TargetOptions, TlsModel, base};
|
||||
|
||||
pub(crate) fn opts() -> TargetOptions {
|
||||
let mut base = base::linux::opts();
|
||||
|
||||
base.env = "ohos".into();
|
||||
base.crt_static_default = false;
|
||||
base.tls_model = TlsModel::Emulated;
|
||||
base.has_thread_local = false;
|
||||
|
||||
base
|
||||
TargetOptions {
|
||||
env: "ohos".into(),
|
||||
crt_static_default: false,
|
||||
tls_model: TlsModel::Emulated,
|
||||
has_thread_local: false,
|
||||
..base::linux::opts()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ pub mod ambiguity;
|
|||
pub mod call_kind;
|
||||
mod fulfillment_errors;
|
||||
pub mod on_unimplemented;
|
||||
pub mod on_unimplemented_condition;
|
||||
pub mod on_unimplemented_format;
|
||||
mod overflow;
|
||||
pub mod suggestions;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,44 +1,31 @@
|
|||
use std::iter;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use rustc_ast::MetaItemInner;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit};
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{ErrorGuaranteed, struct_span_code_err};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::{AttrArgs, Attribute};
|
||||
use rustc_macros::LintDiagnostic;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::print::PrintTraitRefExt as _;
|
||||
use rustc_middle::ty::{self, GenericArgsRef, GenericParamDefKind, TyCtxt};
|
||||
use rustc_parse_format::{ParseMode, Parser, Piece, Position};
|
||||
use rustc_middle::ty::print::PrintTraitRefExt;
|
||||
use rustc_middle::ty::{self, GenericArgsRef, GenericParamDef, GenericParamDefKind, TyCtxt};
|
||||
use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES;
|
||||
use rustc_span::{Ident, Span, Symbol, kw, sym};
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
use tracing::{debug, info};
|
||||
use {rustc_attr_parsing as attr, rustc_hir as hir};
|
||||
|
||||
use super::{ObligationCauseCode, PredicateObligation};
|
||||
use crate::error_reporting::TypeErrCtxt;
|
||||
use crate::error_reporting::traits::on_unimplemented_condition::{Condition, ConditionOptions};
|
||||
use crate::error_reporting::traits::on_unimplemented_format::{
|
||||
Ctx, FormatArgs, FormatString, FormatWarning,
|
||||
};
|
||||
use crate::errors::{
|
||||
EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented,
|
||||
};
|
||||
use crate::infer::InferCtxtExt;
|
||||
|
||||
/// The symbols which are always allowed in a format string
|
||||
static ALLOWED_FORMAT_SYMBOLS: &[Symbol] = &[
|
||||
kw::SelfUpper,
|
||||
sym::ItemContext,
|
||||
sym::from_desugaring,
|
||||
sym::direct,
|
||||
sym::cause,
|
||||
sym::integral,
|
||||
sym::integer_,
|
||||
sym::float,
|
||||
sym::_Self,
|
||||
sym::crate_local,
|
||||
sym::Trait,
|
||||
];
|
||||
|
||||
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
fn impl_similar_to(
|
||||
&self,
|
||||
|
|
@ -121,86 +108,78 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
.unwrap_or_else(|| (trait_pred.def_id(), trait_pred.skip_binder().trait_ref.args));
|
||||
let trait_pred = trait_pred.skip_binder();
|
||||
|
||||
let mut flags = vec![];
|
||||
let mut self_types = vec![];
|
||||
let mut generic_args: Vec<(Symbol, String)> = vec![];
|
||||
let mut crate_local = false;
|
||||
// FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): HIR is not present for RPITITs,
|
||||
// but I guess we could synthesize one here. We don't see any errors that rely on
|
||||
// that yet, though.
|
||||
let enclosure = self.describe_enclosure(obligation.cause.body_id).map(|t| t.to_owned());
|
||||
flags.push((sym::ItemContext, enclosure));
|
||||
let item_context = self.describe_enclosure(obligation.cause.body_id).unwrap_or("");
|
||||
|
||||
match obligation.cause.code() {
|
||||
let direct = match obligation.cause.code() {
|
||||
ObligationCauseCode::BuiltinDerived(..)
|
||||
| ObligationCauseCode::ImplDerived(..)
|
||||
| ObligationCauseCode::WellFormedDerived(..) => {}
|
||||
| ObligationCauseCode::WellFormedDerived(..) => false,
|
||||
_ => {
|
||||
// this is a "direct", user-specified, rather than derived,
|
||||
// obligation.
|
||||
flags.push((sym::direct, None));
|
||||
true
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(k) = obligation.cause.span.desugaring_kind() {
|
||||
flags.push((sym::from_desugaring, None));
|
||||
flags.push((sym::from_desugaring, Some(format!("{k:?}"))));
|
||||
}
|
||||
let from_desugaring = obligation.cause.span.desugaring_kind();
|
||||
|
||||
if let ObligationCauseCode::MainFunctionType = obligation.cause.code() {
|
||||
flags.push((sym::cause, Some("MainFunctionType".to_string())));
|
||||
}
|
||||
|
||||
flags.push((sym::Trait, Some(trait_pred.trait_ref.print_trait_sugared().to_string())));
|
||||
let cause = if let ObligationCauseCode::MainFunctionType = obligation.cause.code() {
|
||||
Some("MainFunctionType".to_string())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// Add all types without trimmed paths or visible paths, ensuring they end up with
|
||||
// their "canonical" def path.
|
||||
ty::print::with_no_trimmed_paths!(ty::print::with_no_visible_paths!({
|
||||
let generics = self.tcx.generics_of(def_id);
|
||||
let self_ty = trait_pred.self_ty();
|
||||
// This is also included through the generics list as `Self`,
|
||||
// but the parser won't allow you to use it
|
||||
flags.push((sym::_Self, Some(self_ty.to_string())));
|
||||
self_types.push(self_ty.to_string());
|
||||
if let Some(def) = self_ty.ty_adt_def() {
|
||||
// We also want to be able to select self's original
|
||||
// signature with no type arguments resolved
|
||||
flags.push((
|
||||
sym::_Self,
|
||||
Some(self.tcx.type_of(def.did()).instantiate_identity().to_string()),
|
||||
));
|
||||
self_types.push(self.tcx.type_of(def.did()).instantiate_identity().to_string());
|
||||
}
|
||||
|
||||
for param in generics.own_params.iter() {
|
||||
let value = match param.kind {
|
||||
for GenericParamDef { name, kind, index, .. } in generics.own_params.iter() {
|
||||
let value = match kind {
|
||||
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
|
||||
args[param.index as usize].to_string()
|
||||
args[*index as usize].to_string()
|
||||
}
|
||||
GenericParamDefKind::Lifetime => continue,
|
||||
};
|
||||
let name = param.name;
|
||||
flags.push((name, Some(value)));
|
||||
generic_args.push((*name, value));
|
||||
|
||||
if let GenericParamDefKind::Type { .. } = param.kind {
|
||||
let param_ty = args[param.index as usize].expect_ty();
|
||||
if let GenericParamDefKind::Type { .. } = kind {
|
||||
let param_ty = args[*index as usize].expect_ty();
|
||||
if let Some(def) = param_ty.ty_adt_def() {
|
||||
// We also want to be able to select the parameter's
|
||||
// original signature with no type arguments resolved
|
||||
flags.push((
|
||||
name,
|
||||
Some(self.tcx.type_of(def.did()).instantiate_identity().to_string()),
|
||||
generic_args.push((
|
||||
*name,
|
||||
self.tcx.type_of(def.did()).instantiate_identity().to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(true) = self_ty.ty_adt_def().map(|def| def.did().is_local()) {
|
||||
flags.push((sym::crate_local, None));
|
||||
crate_local = true;
|
||||
}
|
||||
|
||||
// Allow targeting all integers using `{integral}`, even if the exact type was resolved
|
||||
if self_ty.is_integral() {
|
||||
flags.push((sym::_Self, Some("{integral}".to_owned())));
|
||||
self_types.push("{integral}".to_owned());
|
||||
}
|
||||
|
||||
if self_ty.is_array_slice() {
|
||||
flags.push((sym::_Self, Some("&[]".to_owned())));
|
||||
self_types.push("&[]".to_owned());
|
||||
}
|
||||
|
||||
if self_ty.is_fn() {
|
||||
|
|
@ -215,53 +194,51 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
hir::Safety::Unsafe => "unsafe fn",
|
||||
}
|
||||
};
|
||||
flags.push((sym::_Self, Some(shortname.to_owned())));
|
||||
self_types.push(shortname.to_owned());
|
||||
}
|
||||
|
||||
// Slices give us `[]`, `[{ty}]`
|
||||
if let ty::Slice(aty) = self_ty.kind() {
|
||||
flags.push((sym::_Self, Some("[]".to_string())));
|
||||
self_types.push("[]".to_owned());
|
||||
if let Some(def) = aty.ty_adt_def() {
|
||||
// We also want to be able to select the slice's type's original
|
||||
// signature with no type arguments resolved
|
||||
flags.push((
|
||||
sym::_Self,
|
||||
Some(format!("[{}]", self.tcx.type_of(def.did()).instantiate_identity())),
|
||||
));
|
||||
self_types
|
||||
.push(format!("[{}]", self.tcx.type_of(def.did()).instantiate_identity()));
|
||||
}
|
||||
if aty.is_integral() {
|
||||
flags.push((sym::_Self, Some("[{integral}]".to_string())));
|
||||
self_types.push("[{integral}]".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
// Arrays give us `[]`, `[{ty}; _]` and `[{ty}; N]`
|
||||
if let ty::Array(aty, len) = self_ty.kind() {
|
||||
flags.push((sym::_Self, Some("[]".to_string())));
|
||||
self_types.push("[]".to_string());
|
||||
let len = len.try_to_target_usize(self.tcx);
|
||||
flags.push((sym::_Self, Some(format!("[{aty}; _]"))));
|
||||
self_types.push(format!("[{aty}; _]"));
|
||||
if let Some(n) = len {
|
||||
flags.push((sym::_Self, Some(format!("[{aty}; {n}]"))));
|
||||
self_types.push(format!("[{aty}; {n}]"));
|
||||
}
|
||||
if let Some(def) = aty.ty_adt_def() {
|
||||
// We also want to be able to select the array's type's original
|
||||
// signature with no type arguments resolved
|
||||
let def_ty = self.tcx.type_of(def.did()).instantiate_identity();
|
||||
flags.push((sym::_Self, Some(format!("[{def_ty}; _]"))));
|
||||
self_types.push(format!("[{def_ty}; _]"));
|
||||
if let Some(n) = len {
|
||||
flags.push((sym::_Self, Some(format!("[{def_ty}; {n}]"))));
|
||||
self_types.push(format!("[{def_ty}; {n}]"));
|
||||
}
|
||||
}
|
||||
if aty.is_integral() {
|
||||
flags.push((sym::_Self, Some("[{integral}; _]".to_string())));
|
||||
self_types.push("[{integral}; _]".to_string());
|
||||
if let Some(n) = len {
|
||||
flags.push((sym::_Self, Some(format!("[{{integral}}; {n}]"))));
|
||||
self_types.push(format!("[{{integral}}; {n}]"));
|
||||
}
|
||||
}
|
||||
}
|
||||
if let ty::Dynamic(traits, _, _) = self_ty.kind() {
|
||||
for t in traits.iter() {
|
||||
if let ty::ExistentialPredicate::Trait(trait_ref) = t.skip_binder() {
|
||||
flags.push((sym::_Self, Some(self.tcx.def_path_str(trait_ref.def_id))))
|
||||
self_types.push(self.tcx.def_path_str(trait_ref.def_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -271,31 +248,76 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
&& let ty::Slice(sty) = ref_ty.kind()
|
||||
&& sty.is_integral()
|
||||
{
|
||||
flags.push((sym::_Self, Some("&[{integral}]".to_owned())));
|
||||
self_types.push("&[{integral}]".to_owned());
|
||||
}
|
||||
}));
|
||||
|
||||
let this = self.tcx.def_path_str(trait_pred.trait_ref.def_id);
|
||||
let trait_sugared = trait_pred.trait_ref.print_trait_sugared();
|
||||
|
||||
let condition_options = ConditionOptions {
|
||||
self_types,
|
||||
from_desugaring,
|
||||
cause,
|
||||
crate_local,
|
||||
direct,
|
||||
generic_args,
|
||||
};
|
||||
|
||||
// Unlike the generic_args earlier,
|
||||
// this one is *not* collected under `with_no_trimmed_paths!`
|
||||
// for printing the type to the user
|
||||
//
|
||||
// This includes `Self`, as it is the first parameter in `own_params`.
|
||||
let generic_args = self
|
||||
.tcx
|
||||
.generics_of(trait_pred.trait_ref.def_id)
|
||||
.own_params
|
||||
.iter()
|
||||
.filter_map(|param| {
|
||||
let value = match param.kind {
|
||||
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
|
||||
if let Some(ty) = trait_pred.trait_ref.args[param.index as usize].as_type()
|
||||
{
|
||||
self.tcx.short_string(ty, long_ty_file)
|
||||
} else {
|
||||
trait_pred.trait_ref.args[param.index as usize].to_string()
|
||||
}
|
||||
}
|
||||
GenericParamDefKind::Lifetime => return None,
|
||||
};
|
||||
let name = param.name;
|
||||
Some((name, value))
|
||||
})
|
||||
.collect();
|
||||
|
||||
let format_args = FormatArgs { this, trait_sugared, generic_args, item_context };
|
||||
|
||||
if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, def_id) {
|
||||
command.evaluate(self.tcx, trait_pred.trait_ref, &flags, long_ty_file)
|
||||
command.evaluate(self.tcx, trait_pred.trait_ref, &condition_options, &format_args)
|
||||
} else {
|
||||
OnUnimplementedNote::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a format string in a on_unimplemented attribute,
|
||||
/// like the "content" in `#[diagnostic::on_unimplemented(message = "content")]`
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct OnUnimplementedFormatString {
|
||||
symbol: Symbol,
|
||||
span: Span,
|
||||
is_diagnostic_namespace_variant: bool,
|
||||
/// Symbol of the format string, i.e. `"content"`
|
||||
pub symbol: Symbol,
|
||||
///The span of the format string, i.e. `"content"`
|
||||
pub span: Span,
|
||||
pub is_diagnostic_namespace_variant: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct OnUnimplementedDirective {
|
||||
pub condition: Option<MetaItemInner>,
|
||||
pub condition: Option<Condition>,
|
||||
pub subcommands: Vec<OnUnimplementedDirective>,
|
||||
pub message: Option<OnUnimplementedFormatString>,
|
||||
pub label: Option<OnUnimplementedFormatString>,
|
||||
pub message: Option<(Span, OnUnimplementedFormatString)>,
|
||||
pub label: Option<(Span, OnUnimplementedFormatString)>,
|
||||
pub notes: Vec<OnUnimplementedFormatString>,
|
||||
pub parent_label: Option<OnUnimplementedFormatString>,
|
||||
pub append_const_msg: Option<AppendConstMessage>,
|
||||
|
|
@ -329,7 +351,7 @@ pub struct MalformedOnUnimplementedAttrLint {
|
|||
}
|
||||
|
||||
impl MalformedOnUnimplementedAttrLint {
|
||||
fn new(span: Span) -> Self {
|
||||
pub fn new(span: Span) -> Self {
|
||||
Self { span }
|
||||
}
|
||||
}
|
||||
|
|
@ -350,7 +372,7 @@ pub struct IgnoredDiagnosticOption {
|
|||
}
|
||||
|
||||
impl IgnoredDiagnosticOption {
|
||||
fn maybe_emit_warning<'tcx>(
|
||||
pub fn maybe_emit_warning<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
item_def_id: DefId,
|
||||
new: Option<Span>,
|
||||
|
|
@ -370,29 +392,11 @@ impl IgnoredDiagnosticOption {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(trait_selection_unknown_format_parameter_for_on_unimplemented_attr)]
|
||||
#[help]
|
||||
pub struct UnknownFormatParameterForOnUnimplementedAttr {
|
||||
argument_name: Symbol,
|
||||
trait_name: Ident,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(trait_selection_disallowed_positional_argument)]
|
||||
#[help]
|
||||
pub struct DisallowedPositionalArgument;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(trait_selection_invalid_format_specifier)]
|
||||
#[help]
|
||||
pub struct InvalidFormatSpecifier;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(trait_selection_wrapped_parser_error)]
|
||||
pub struct WrappedParserError {
|
||||
description: String,
|
||||
label: String,
|
||||
pub description: String,
|
||||
pub label: String,
|
||||
}
|
||||
|
||||
impl<'tcx> OnUnimplementedDirective {
|
||||
|
|
@ -407,12 +411,12 @@ impl<'tcx> OnUnimplementedDirective {
|
|||
let mut errored = None;
|
||||
let mut item_iter = items.iter();
|
||||
|
||||
let parse_value = |value_str, value_span| {
|
||||
let parse_value = |value_str, span| {
|
||||
OnUnimplementedFormatString::try_parse(
|
||||
tcx,
|
||||
item_def_id,
|
||||
value_str,
|
||||
value_span,
|
||||
span,
|
||||
is_diagnostic_namespace_variant,
|
||||
)
|
||||
.map(Some)
|
||||
|
|
@ -434,7 +438,7 @@ impl<'tcx> OnUnimplementedDirective {
|
|||
}
|
||||
true
|
||||
});
|
||||
Some(cond.clone())
|
||||
Some(Condition { inner: cond.clone() })
|
||||
};
|
||||
|
||||
let mut message = None;
|
||||
|
|
@ -444,24 +448,36 @@ impl<'tcx> OnUnimplementedDirective {
|
|||
let mut subcommands = vec![];
|
||||
let mut append_const_msg = None;
|
||||
|
||||
let get_value_and_span = |item: &_, key| {
|
||||
if let MetaItemInner::MetaItem(MetaItem {
|
||||
path,
|
||||
kind: MetaItemKind::NameValue(MetaItemLit { span, kind: LitKind::Str(s, _), .. }),
|
||||
..
|
||||
}) = item
|
||||
&& *path == key
|
||||
{
|
||||
Some((*s, *span))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
for item in item_iter {
|
||||
if item.has_name(sym::message) && message.is_none() {
|
||||
if let Some(message_) = item.value_str() {
|
||||
message = parse_value(message_, item.span())?;
|
||||
if let Some((message_, span)) = get_value_and_span(item, sym::message)
|
||||
&& message.is_none()
|
||||
{
|
||||
message = parse_value(message_, span)?.map(|l| (item.span(), l));
|
||||
continue;
|
||||
} else if let Some((label_, span)) = get_value_and_span(item, sym::label)
|
||||
&& label.is_none()
|
||||
{
|
||||
label = parse_value(label_, span)?.map(|l| (item.span(), l));
|
||||
continue;
|
||||
} else if let Some((note_, span)) = get_value_and_span(item, sym::note) {
|
||||
if let Some(note) = parse_value(note_, span)? {
|
||||
notes.push(note);
|
||||
continue;
|
||||
}
|
||||
} else if item.has_name(sym::label) && label.is_none() {
|
||||
if let Some(label_) = item.value_str() {
|
||||
label = parse_value(label_, item.span())?;
|
||||
continue;
|
||||
}
|
||||
} else if item.has_name(sym::note) {
|
||||
if let Some(note_) = item.value_str() {
|
||||
if let Some(note) = parse_value(note_, item.span())? {
|
||||
notes.push(note);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else if item.has_name(sym::parent_label)
|
||||
&& parent_label.is_none()
|
||||
&& !is_diagnostic_namespace_variant
|
||||
|
|
@ -539,6 +555,13 @@ impl<'tcx> OnUnimplementedDirective {
|
|||
}
|
||||
|
||||
pub fn of_item(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<Option<Self>, ErrorGuaranteed> {
|
||||
if !tcx.is_trait(item_def_id) {
|
||||
// It could be a trait_alias (`trait MyTrait = SomeOtherTrait`)
|
||||
// or an implementation (`impl MyTrait for Foo {}`)
|
||||
//
|
||||
// We don't support those.
|
||||
return Ok(None);
|
||||
}
|
||||
if let Some(attr) = tcx.get_attr(item_def_id, sym::rustc_on_unimplemented) {
|
||||
return Self::parse_attribute(attr, false, tcx, item_def_id);
|
||||
} else {
|
||||
|
|
@ -554,15 +577,15 @@ impl<'tcx> OnUnimplementedDirective {
|
|||
IgnoredDiagnosticOption::maybe_emit_warning(
|
||||
tcx,
|
||||
item_def_id,
|
||||
directive.message.as_ref().map(|f| f.span),
|
||||
aggr.message.as_ref().map(|f| f.span),
|
||||
directive.message.as_ref().map(|f| f.0),
|
||||
aggr.message.as_ref().map(|f| f.0),
|
||||
"message",
|
||||
);
|
||||
IgnoredDiagnosticOption::maybe_emit_warning(
|
||||
tcx,
|
||||
item_def_id,
|
||||
directive.label.as_ref().map(|f| f.span),
|
||||
aggr.label.as_ref().map(|f| f.span),
|
||||
directive.label.as_ref().map(|f| f.0),
|
||||
aggr.label.as_ref().map(|f| f.0),
|
||||
"label",
|
||||
);
|
||||
IgnoredDiagnosticOption::maybe_emit_warning(
|
||||
|
|
@ -636,13 +659,16 @@ impl<'tcx> OnUnimplementedDirective {
|
|||
condition: None,
|
||||
message: None,
|
||||
subcommands: vec![],
|
||||
label: Some(OnUnimplementedFormatString::try_parse(
|
||||
tcx,
|
||||
item_def_id,
|
||||
value,
|
||||
label: Some((
|
||||
attr.span(),
|
||||
is_diagnostic_namespace_variant,
|
||||
)?),
|
||||
OnUnimplementedFormatString::try_parse(
|
||||
tcx,
|
||||
item_def_id,
|
||||
value,
|
||||
attr.value_span().unwrap_or(attr.span()),
|
||||
is_diagnostic_namespace_variant,
|
||||
)?,
|
||||
)),
|
||||
notes: Vec::new(),
|
||||
parent_label: None,
|
||||
append_const_msg: None,
|
||||
|
|
@ -702,43 +728,23 @@ impl<'tcx> OnUnimplementedDirective {
|
|||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_ref: ty::TraitRef<'tcx>,
|
||||
options: &[(Symbol, Option<String>)],
|
||||
long_ty_file: &mut Option<PathBuf>,
|
||||
condition_options: &ConditionOptions,
|
||||
args: &FormatArgs<'tcx>,
|
||||
) -> OnUnimplementedNote {
|
||||
let mut message = None;
|
||||
let mut label = None;
|
||||
let mut notes = Vec::new();
|
||||
let mut parent_label = None;
|
||||
let mut append_const_msg = None;
|
||||
info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options);
|
||||
|
||||
let options_map: FxHashMap<Symbol, String> =
|
||||
options.iter().filter_map(|(k, v)| v.clone().map(|v| (*k, v))).collect();
|
||||
info!(
|
||||
"evaluate({:?}, trait_ref={:?}, options={:?}, args ={:?})",
|
||||
self, trait_ref, condition_options, args
|
||||
);
|
||||
|
||||
for command in self.subcommands.iter().chain(Some(self)).rev() {
|
||||
debug!(?command);
|
||||
if let Some(ref condition) = command.condition
|
||||
&& !attr::eval_condition(condition, &tcx.sess, Some(tcx.features()), &mut |cfg| {
|
||||
let value = cfg.value.map(|v| {
|
||||
// `with_no_visible_paths` is also used when generating the options,
|
||||
// so we need to match it here.
|
||||
ty::print::with_no_visible_paths!(
|
||||
OnUnimplementedFormatString {
|
||||
symbol: v,
|
||||
span: cfg.span,
|
||||
is_diagnostic_namespace_variant: false
|
||||
}
|
||||
.format(
|
||||
tcx,
|
||||
trait_ref,
|
||||
&options_map,
|
||||
long_ty_file
|
||||
)
|
||||
)
|
||||
});
|
||||
|
||||
options.contains(&(cfg.name, value))
|
||||
})
|
||||
&& !condition.matches_predicate(tcx, condition_options)
|
||||
{
|
||||
debug!("evaluate: skipping {:?} due to condition", command);
|
||||
continue;
|
||||
|
|
@ -762,14 +768,10 @@ impl<'tcx> OnUnimplementedDirective {
|
|||
}
|
||||
|
||||
OnUnimplementedNote {
|
||||
label: label.map(|l| l.format(tcx, trait_ref, &options_map, long_ty_file)),
|
||||
message: message.map(|m| m.format(tcx, trait_ref, &options_map, long_ty_file)),
|
||||
notes: notes
|
||||
.into_iter()
|
||||
.map(|n| n.format(tcx, trait_ref, &options_map, long_ty_file))
|
||||
.collect(),
|
||||
parent_label: parent_label
|
||||
.map(|e_s| e_s.format(tcx, trait_ref, &options_map, long_ty_file)),
|
||||
label: label.map(|l| l.1.format(tcx, trait_ref, args)),
|
||||
message: message.map(|m| m.1.format(tcx, trait_ref, args)),
|
||||
notes: notes.into_iter().map(|n| n.format(tcx, trait_ref, args)).collect(),
|
||||
parent_label: parent_label.map(|e_s| e_s.format(tcx, trait_ref, args)),
|
||||
append_const_msg,
|
||||
}
|
||||
}
|
||||
|
|
@ -780,142 +782,95 @@ impl<'tcx> OnUnimplementedFormatString {
|
|||
tcx: TyCtxt<'tcx>,
|
||||
item_def_id: DefId,
|
||||
from: Symbol,
|
||||
value_span: Span,
|
||||
span: Span,
|
||||
is_diagnostic_namespace_variant: bool,
|
||||
) -> Result<Self, ErrorGuaranteed> {
|
||||
let result = OnUnimplementedFormatString {
|
||||
symbol: from,
|
||||
span: value_span,
|
||||
is_diagnostic_namespace_variant,
|
||||
};
|
||||
let result =
|
||||
OnUnimplementedFormatString { symbol: from, span, is_diagnostic_namespace_variant };
|
||||
result.verify(tcx, item_def_id)?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn verify(&self, tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<(), ErrorGuaranteed> {
|
||||
let trait_def_id = if tcx.is_trait(item_def_id) {
|
||||
item_def_id
|
||||
} else {
|
||||
tcx.trait_id_of_impl(item_def_id)
|
||||
.expect("expected `on_unimplemented` to correspond to a trait")
|
||||
fn verify(&self, tcx: TyCtxt<'tcx>, trait_def_id: DefId) -> Result<(), ErrorGuaranteed> {
|
||||
if !tcx.is_trait(trait_def_id) {
|
||||
return Ok(());
|
||||
};
|
||||
let trait_name = tcx.item_ident(trait_def_id);
|
||||
let generics = tcx.generics_of(item_def_id);
|
||||
let s = self.symbol.as_str();
|
||||
let mut parser = Parser::new(s, None, None, false, ParseMode::Format);
|
||||
|
||||
let ctx = if self.is_diagnostic_namespace_variant {
|
||||
Ctx::DiagnosticOnUnimplemented { tcx, trait_def_id }
|
||||
} else {
|
||||
Ctx::RustcOnUnimplemented { tcx, trait_def_id }
|
||||
};
|
||||
|
||||
let mut result = Ok(());
|
||||
for token in &mut parser {
|
||||
match token {
|
||||
Piece::Lit(_) => (), // Normal string, no need to check it
|
||||
Piece::NextArgument(a) => {
|
||||
let format_spec = a.format;
|
||||
if self.is_diagnostic_namespace_variant
|
||||
&& (format_spec.ty_span.is_some()
|
||||
|| format_spec.width_span.is_some()
|
||||
|| format_spec.precision_span.is_some()
|
||||
|| format_spec.fill_span.is_some())
|
||||
{
|
||||
if let Some(item_def_id) = item_def_id.as_local() {
|
||||
tcx.emit_node_span_lint(
|
||||
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
tcx.local_def_id_to_hir_id(item_def_id),
|
||||
self.span,
|
||||
InvalidFormatSpecifier,
|
||||
);
|
||||
}
|
||||
|
||||
match FormatString::parse(self.symbol, self.span, &ctx) {
|
||||
// Warnings about format specifiers, deprecated parameters, wrong parameters etc.
|
||||
// In other words we'd like to let the author know, but we can still try to format the string later
|
||||
Ok(FormatString { warnings, .. }) => {
|
||||
if self.is_diagnostic_namespace_variant {
|
||||
for w in warnings {
|
||||
w.emit_warning(tcx, trait_def_id)
|
||||
}
|
||||
match a.position {
|
||||
Position::ArgumentNamed(s) => {
|
||||
match Symbol::intern(s) {
|
||||
// `{ThisTraitsName}` is allowed
|
||||
s if s == trait_name.name
|
||||
&& !self.is_diagnostic_namespace_variant =>
|
||||
{
|
||||
()
|
||||
}
|
||||
s if ALLOWED_FORMAT_SYMBOLS.contains(&s)
|
||||
&& !self.is_diagnostic_namespace_variant =>
|
||||
{
|
||||
()
|
||||
}
|
||||
// So is `{A}` if A is a type parameter
|
||||
s if generics.own_params.iter().any(|param| param.name == s) => (),
|
||||
s => {
|
||||
if self.is_diagnostic_namespace_variant {
|
||||
if let Some(item_def_id) = item_def_id.as_local() {
|
||||
tcx.emit_node_span_lint(
|
||||
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
tcx.local_def_id_to_hir_id(item_def_id),
|
||||
self.span,
|
||||
UnknownFormatParameterForOnUnimplementedAttr {
|
||||
argument_name: s,
|
||||
trait_name,
|
||||
},
|
||||
);
|
||||
}
|
||||
} else {
|
||||
result = Err(struct_span_code_err!(
|
||||
tcx.dcx(),
|
||||
self.span,
|
||||
E0230,
|
||||
"there is no parameter `{}` on {}",
|
||||
s,
|
||||
if trait_def_id == item_def_id {
|
||||
format!("trait `{trait_name}`")
|
||||
} else {
|
||||
"impl".to_string()
|
||||
}
|
||||
)
|
||||
.emit());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// `{:1}` and `{}` are not to be used
|
||||
Position::ArgumentIs(..) | Position::ArgumentImplicitlyIs(_) => {
|
||||
if self.is_diagnostic_namespace_variant {
|
||||
if let Some(item_def_id) = item_def_id.as_local() {
|
||||
tcx.emit_node_span_lint(
|
||||
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
tcx.local_def_id_to_hir_id(item_def_id),
|
||||
self.span,
|
||||
DisallowedPositionalArgument,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
} else {
|
||||
for w in warnings {
|
||||
match w {
|
||||
FormatWarning::UnknownParam { argument_name, span } => {
|
||||
let reported = struct_span_code_err!(
|
||||
tcx.dcx(),
|
||||
self.span,
|
||||
E0231,
|
||||
"only named generic parameters are allowed"
|
||||
span,
|
||||
E0230,
|
||||
"cannot find parameter {} on this trait",
|
||||
argument_name,
|
||||
)
|
||||
.emit();
|
||||
result = Err(reported);
|
||||
}
|
||||
FormatWarning::PositionalArgument { span, .. } => {
|
||||
let reported = struct_span_code_err!(
|
||||
tcx.dcx(),
|
||||
span,
|
||||
E0231,
|
||||
"positional format arguments are not allowed here"
|
||||
)
|
||||
.emit();
|
||||
result = Err(reported);
|
||||
}
|
||||
FormatWarning::InvalidSpecifier { .. }
|
||||
| FormatWarning::FutureIncompat { .. } => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// we cannot return errors from processing the format string as hard error here
|
||||
// as the diagnostic namespace guarantees that malformed input cannot cause an error
|
||||
//
|
||||
// if we encounter any error while processing we nevertheless want to show it as warning
|
||||
// so that users are aware that something is not correct
|
||||
for e in parser.errors {
|
||||
if self.is_diagnostic_namespace_variant {
|
||||
if let Some(item_def_id) = item_def_id.as_local() {
|
||||
tcx.emit_node_span_lint(
|
||||
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
tcx.local_def_id_to_hir_id(item_def_id),
|
||||
self.span,
|
||||
WrappedParserError { description: e.description, label: e.label },
|
||||
);
|
||||
// Errors from the underlying `rustc_parse_format::Parser`
|
||||
Err(errors) => {
|
||||
// we cannot return errors from processing the format string as hard error here
|
||||
// as the diagnostic namespace guarantees that malformed input cannot cause an error
|
||||
//
|
||||
// if we encounter any error while processing we nevertheless want to show it as warning
|
||||
// so that users are aware that something is not correct
|
||||
for e in errors {
|
||||
if self.is_diagnostic_namespace_variant {
|
||||
if let Some(trait_def_id) = trait_def_id.as_local() {
|
||||
tcx.emit_node_span_lint(
|
||||
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
tcx.local_def_id_to_hir_id(trait_def_id),
|
||||
self.span,
|
||||
WrappedParserError { description: e.description, label: e.label },
|
||||
);
|
||||
}
|
||||
} else {
|
||||
let reported = struct_span_code_err!(
|
||||
tcx.dcx(),
|
||||
self.span,
|
||||
E0231,
|
||||
"{}",
|
||||
e.description,
|
||||
)
|
||||
.emit();
|
||||
result = Err(reported);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let reported =
|
||||
struct_span_code_err!(tcx.dcx(), self.span, E0231, "{}", e.description,).emit();
|
||||
result = Err(reported);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -926,98 +881,28 @@ impl<'tcx> OnUnimplementedFormatString {
|
|||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_ref: ty::TraitRef<'tcx>,
|
||||
options: &FxHashMap<Symbol, String>,
|
||||
long_ty_file: &mut Option<PathBuf>,
|
||||
args: &FormatArgs<'tcx>,
|
||||
) -> String {
|
||||
let name = tcx.item_name(trait_ref.def_id);
|
||||
let trait_str = tcx.def_path_str(trait_ref.def_id);
|
||||
let generics = tcx.generics_of(trait_ref.def_id);
|
||||
let generic_map = generics
|
||||
.own_params
|
||||
.iter()
|
||||
.filter_map(|param| {
|
||||
let value = match param.kind {
|
||||
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
|
||||
if let Some(ty) = trait_ref.args[param.index as usize].as_type() {
|
||||
tcx.short_string(ty, long_ty_file)
|
||||
} else {
|
||||
trait_ref.args[param.index as usize].to_string()
|
||||
}
|
||||
}
|
||||
GenericParamDefKind::Lifetime => return None,
|
||||
};
|
||||
let name = param.name;
|
||||
Some((name, value))
|
||||
})
|
||||
.collect::<FxHashMap<Symbol, String>>();
|
||||
let empty_string = String::new();
|
||||
|
||||
let s = self.symbol.as_str();
|
||||
let mut parser = Parser::new(s, None, None, false, ParseMode::Format);
|
||||
let item_context = (options.get(&sym::ItemContext)).unwrap_or(&empty_string);
|
||||
let constructed_message = (&mut parser)
|
||||
.map(|p| match p {
|
||||
Piece::Lit(s) => s.to_owned(),
|
||||
Piece::NextArgument(a) => match a.position {
|
||||
Position::ArgumentNamed(arg) => {
|
||||
let s = Symbol::intern(arg);
|
||||
match generic_map.get(&s) {
|
||||
Some(val) => val.to_string(),
|
||||
None if self.is_diagnostic_namespace_variant => {
|
||||
format!("{{{arg}}}")
|
||||
}
|
||||
None if s == name => trait_str.clone(),
|
||||
None => {
|
||||
if let Some(val) = options.get(&s) {
|
||||
val.clone()
|
||||
} else if s == sym::from_desugaring {
|
||||
// don't break messages using these two arguments incorrectly
|
||||
String::new()
|
||||
} else if s == sym::ItemContext
|
||||
&& !self.is_diagnostic_namespace_variant
|
||||
{
|
||||
item_context.clone()
|
||||
} else if s == sym::integral {
|
||||
String::from("{integral}")
|
||||
} else if s == sym::integer_ {
|
||||
String::from("{integer}")
|
||||
} else if s == sym::float {
|
||||
String::from("{float}")
|
||||
} else {
|
||||
bug!(
|
||||
"broken on_unimplemented {:?} for {:?}: \
|
||||
no argument matching {:?}",
|
||||
self.symbol,
|
||||
trait_ref,
|
||||
s
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Position::ArgumentImplicitlyIs(_) if self.is_diagnostic_namespace_variant => {
|
||||
String::from("{}")
|
||||
}
|
||||
Position::ArgumentIs(idx) if self.is_diagnostic_namespace_variant => {
|
||||
format!("{{{idx}}}")
|
||||
}
|
||||
_ => bug!("broken on_unimplemented {:?} - bad format arg", self.symbol),
|
||||
},
|
||||
})
|
||||
.collect();
|
||||
// we cannot return errors from processing the format string as hard error here
|
||||
// as the diagnostic namespace guarantees that malformed input cannot cause an error
|
||||
//
|
||||
// if we encounter any error while processing the format string
|
||||
// we don't want to show the potentially half assembled formatted string,
|
||||
// therefore we fall back to just showing the input string in this case
|
||||
//
|
||||
// The actual parser errors are emitted earlier
|
||||
// as lint warnings in OnUnimplementedFormatString::verify
|
||||
if self.is_diagnostic_namespace_variant && !parser.errors.is_empty() {
|
||||
String::from(s)
|
||||
let trait_def_id = trait_ref.def_id;
|
||||
let ctx = if self.is_diagnostic_namespace_variant {
|
||||
Ctx::DiagnosticOnUnimplemented { tcx, trait_def_id }
|
||||
} else {
|
||||
constructed_message
|
||||
Ctx::RustcOnUnimplemented { tcx, trait_def_id }
|
||||
};
|
||||
|
||||
if let Ok(s) = FormatString::parse(self.symbol, self.span, &ctx) {
|
||||
s.format(args)
|
||||
} else {
|
||||
// we cannot return errors from processing the format string as hard error here
|
||||
// as the diagnostic namespace guarantees that malformed input cannot cause an error
|
||||
//
|
||||
// if we encounter any error while processing the format string
|
||||
// we don't want to show the potentially half assembled formatted string,
|
||||
// therefore we fall back to just showing the input string in this case
|
||||
//
|
||||
// The actual parser errors are emitted earlier
|
||||
// as lint warnings in OnUnimplementedFormatString::verify
|
||||
self.symbol.as_str().into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,120 @@
|
|||
use rustc_ast::MetaItemInner;
|
||||
use rustc_attr_parsing as attr;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_parse_format::{ParseMode, Parser, Piece, Position};
|
||||
use rustc_span::{DesugaringKind, Span, Symbol, kw, sym};
|
||||
|
||||
/// A predicate in an attribute using on, all, any,
|
||||
/// similar to a cfg predicate.
|
||||
#[derive(Debug)]
|
||||
pub struct Condition {
|
||||
pub inner: MetaItemInner,
|
||||
}
|
||||
|
||||
impl Condition {
|
||||
pub fn span(&self) -> Span {
|
||||
self.inner.span()
|
||||
}
|
||||
|
||||
pub fn matches_predicate<'tcx>(&self, tcx: TyCtxt<'tcx>, options: &ConditionOptions) -> bool {
|
||||
attr::eval_condition(&self.inner, tcx.sess, Some(tcx.features()), &mut |cfg| {
|
||||
let value = cfg.value.map(|v| {
|
||||
// `with_no_visible_paths` is also used when generating the options,
|
||||
// so we need to match it here.
|
||||
ty::print::with_no_visible_paths!({
|
||||
Parser::new(v.as_str(), None, None, false, ParseMode::Format)
|
||||
.map(|p| match p {
|
||||
Piece::Lit(s) => s.to_owned(),
|
||||
Piece::NextArgument(a) => match a.position {
|
||||
Position::ArgumentNamed(arg) => {
|
||||
let s = Symbol::intern(arg);
|
||||
match options.generic_args.iter().find(|(k, _)| *k == s) {
|
||||
Some((_, val)) => val.to_string(),
|
||||
None => format!("{{{arg}}}"),
|
||||
}
|
||||
}
|
||||
Position::ArgumentImplicitlyIs(_) => String::from("{}"),
|
||||
Position::ArgumentIs(idx) => format!("{{{idx}}}"),
|
||||
},
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
});
|
||||
|
||||
options.contains(cfg.name, &value)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Used with `Condition::matches_predicate` to test whether the condition applies
|
||||
///
|
||||
/// For example, given a
|
||||
/// ```rust,ignore (just an example)
|
||||
/// #[rustc_on_unimplemented(
|
||||
/// on(all(from_desugaring = "QuestionMark"),
|
||||
/// message = "the `?` operator can only be used in {ItemContext} \
|
||||
/// that returns `Result` or `Option` \
|
||||
/// (or another type that implements `{FromResidual}`)",
|
||||
/// label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`",
|
||||
/// parent_label = "this function should return `Result` or `Option` to accept `?`"
|
||||
/// ),
|
||||
/// )]
|
||||
/// pub trait FromResidual<R = <Self as Try>::Residual> {
|
||||
/// ...
|
||||
/// }
|
||||
///
|
||||
/// async fn an_async_function() -> u32 {
|
||||
/// let x: Option<u32> = None;
|
||||
/// x?; //~ ERROR the `?` operator
|
||||
/// 22
|
||||
/// }
|
||||
/// ```
|
||||
/// it will look like this:
|
||||
///
|
||||
/// ```rust,ignore (just an example)
|
||||
/// ConditionOptions {
|
||||
/// self_types: ["u32", "{integral}"],
|
||||
/// from_desugaring: Some("QuestionMark"),
|
||||
/// cause: None,
|
||||
/// crate_local: false,
|
||||
/// direct: true,
|
||||
/// generic_args: [("Self","u32"),
|
||||
/// ("R", "core::option::Option<core::convert::Infallible>"),
|
||||
/// ("R", "core::option::Option<T>" ),
|
||||
/// ],
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Debug)]
|
||||
pub struct ConditionOptions {
|
||||
/// All the self types that may apply.
|
||||
/// for example
|
||||
pub self_types: Vec<String>,
|
||||
// The kind of compiler desugaring.
|
||||
pub from_desugaring: Option<DesugaringKind>,
|
||||
/// Match on a variant of [rustc_infer::traits::ObligationCauseCode]
|
||||
pub cause: Option<String>,
|
||||
pub crate_local: bool,
|
||||
/// Is the obligation "directly" user-specified, rather than derived?
|
||||
pub direct: bool,
|
||||
// A list of the generic arguments and their reified types
|
||||
pub generic_args: Vec<(Symbol, String)>,
|
||||
}
|
||||
|
||||
impl ConditionOptions {
|
||||
pub fn contains(&self, key: Symbol, value: &Option<String>) -> bool {
|
||||
match (key, value) {
|
||||
(sym::_Self | kw::SelfUpper, Some(value)) => self.self_types.contains(&value),
|
||||
// from_desugaring as a flag
|
||||
(sym::from_desugaring, None) => self.from_desugaring.is_some(),
|
||||
// from_desugaring as key == value
|
||||
(sym::from_desugaring, Some(v)) if let Some(ds) = self.from_desugaring => ds.matches(v),
|
||||
(sym::cause, Some(value)) => self.cause.as_deref() == Some(value),
|
||||
(sym::crate_local, None) => self.crate_local,
|
||||
(sym::direct, None) => self.direct,
|
||||
(other, Some(value)) => {
|
||||
self.generic_args.iter().any(|(k, v)| *k == other && v == value)
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,414 @@
|
|||
use std::fmt;
|
||||
|
||||
use errors::*;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_middle::ty::print::TraitRefPrintSugared;
|
||||
use rustc_parse_format::{
|
||||
Alignment, Argument, Count, FormatSpec, InnerSpan, ParseError, ParseMode, Parser,
|
||||
Piece as RpfPiece, Position,
|
||||
};
|
||||
use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES;
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::{BytePos, Pos, Span, Symbol, kw, sym};
|
||||
|
||||
/// Like [std::fmt::Arguments] this is a string that has been parsed into "pieces",
|
||||
/// either as string pieces or dynamic arguments.
|
||||
#[derive(Debug)]
|
||||
pub struct FormatString {
|
||||
#[allow(dead_code, reason = "Debug impl")]
|
||||
input: Symbol,
|
||||
span: Span,
|
||||
pieces: Vec<Piece>,
|
||||
/// The formatting string was parsed succesfully but with warnings
|
||||
pub warnings: Vec<FormatWarning>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Piece {
|
||||
Lit(String),
|
||||
Arg(FormatArg),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum FormatArg {
|
||||
// A generic parameter, like `{T}` if we're on the `From<T>` trait.
|
||||
GenericParam {
|
||||
generic_param: Symbol,
|
||||
},
|
||||
// `{Self}`
|
||||
SelfUpper,
|
||||
/// `{This}` or `{TraitName}`
|
||||
This,
|
||||
/// The sugared form of the trait
|
||||
Trait,
|
||||
/// what we're in, like a function, method, closure etc.
|
||||
ItemContext,
|
||||
/// What the user typed, if it doesn't match anything we can use.
|
||||
AsIs(String),
|
||||
}
|
||||
|
||||
pub enum Ctx<'tcx> {
|
||||
// `#[rustc_on_unimplemented]`
|
||||
RustcOnUnimplemented { tcx: TyCtxt<'tcx>, trait_def_id: DefId },
|
||||
// `#[diagnostic::...]`
|
||||
DiagnosticOnUnimplemented { tcx: TyCtxt<'tcx>, trait_def_id: DefId },
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum FormatWarning {
|
||||
UnknownParam { argument_name: Symbol, span: Span },
|
||||
PositionalArgument { span: Span, help: String },
|
||||
InvalidSpecifier { name: String, span: Span },
|
||||
FutureIncompat { span: Span, help: String },
|
||||
}
|
||||
|
||||
impl FormatWarning {
|
||||
pub fn emit_warning<'tcx>(&self, tcx: TyCtxt<'tcx>, item_def_id: DefId) {
|
||||
match *self {
|
||||
FormatWarning::UnknownParam { argument_name, span } => {
|
||||
let this = tcx.item_ident(item_def_id);
|
||||
if let Some(item_def_id) = item_def_id.as_local() {
|
||||
tcx.emit_node_span_lint(
|
||||
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
tcx.local_def_id_to_hir_id(item_def_id),
|
||||
span,
|
||||
UnknownFormatParameterForOnUnimplementedAttr {
|
||||
argument_name,
|
||||
trait_name: this,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
FormatWarning::PositionalArgument { span, .. } => {
|
||||
if let Some(item_def_id) = item_def_id.as_local() {
|
||||
tcx.emit_node_span_lint(
|
||||
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
tcx.local_def_id_to_hir_id(item_def_id),
|
||||
span,
|
||||
DisallowedPositionalArgument,
|
||||
);
|
||||
}
|
||||
}
|
||||
FormatWarning::InvalidSpecifier { span, .. } => {
|
||||
if let Some(item_def_id) = item_def_id.as_local() {
|
||||
tcx.emit_node_span_lint(
|
||||
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
tcx.local_def_id_to_hir_id(item_def_id),
|
||||
span,
|
||||
InvalidFormatSpecifier,
|
||||
);
|
||||
}
|
||||
}
|
||||
FormatWarning::FutureIncompat { .. } => {
|
||||
// We've never deprecated anything in diagnostic namespace format strings
|
||||
// but if we do we will emit a warning here
|
||||
|
||||
// FIXME(mejrs) in a couple releases, start emitting warnings for
|
||||
// #[rustc_on_unimplemented] deprecated args
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Arguments to fill a [FormatString] with.
|
||||
///
|
||||
/// For example, given a
|
||||
/// ```rust,ignore (just an example)
|
||||
///
|
||||
/// #[rustc_on_unimplemented(
|
||||
/// on(all(from_desugaring = "QuestionMark"),
|
||||
/// message = "the `?` operator can only be used in {ItemContext} \
|
||||
/// that returns `Result` or `Option` \
|
||||
/// (or another type that implements `{FromResidual}`)",
|
||||
/// label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`",
|
||||
/// parent_label = "this function should return `Result` or `Option` to accept `?`"
|
||||
/// ),
|
||||
/// )]
|
||||
/// pub trait FromResidual<R = <Self as Try>::Residual> {
|
||||
/// ...
|
||||
/// }
|
||||
///
|
||||
/// async fn an_async_function() -> u32 {
|
||||
/// let x: Option<u32> = None;
|
||||
/// x?; //~ ERROR the `?` operator
|
||||
/// 22
|
||||
/// }
|
||||
/// ```
|
||||
/// it will look like this:
|
||||
///
|
||||
/// ```rust,ignore (just an example)
|
||||
/// FormatArgs {
|
||||
/// this: "FromResidual",
|
||||
/// trait_sugared: "FromResidual<Option<Infallible>>",
|
||||
/// item_context: "an async function",
|
||||
/// generic_args: [("Self", "u32"), ("R", "Option<Infallible>")],
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Debug)]
|
||||
pub struct FormatArgs<'tcx> {
|
||||
pub this: String,
|
||||
pub trait_sugared: TraitRefPrintSugared<'tcx>,
|
||||
pub item_context: &'static str,
|
||||
pub generic_args: Vec<(Symbol, String)>,
|
||||
}
|
||||
|
||||
impl FormatString {
|
||||
pub fn span(&self) -> Span {
|
||||
self.span
|
||||
}
|
||||
|
||||
pub fn parse<'tcx>(
|
||||
input: Symbol,
|
||||
span: Span,
|
||||
ctx: &Ctx<'tcx>,
|
||||
) -> Result<Self, Vec<ParseError>> {
|
||||
let s = input.as_str();
|
||||
let mut parser = Parser::new(s, None, None, false, ParseMode::Format);
|
||||
let mut pieces = Vec::new();
|
||||
let mut warnings = Vec::new();
|
||||
|
||||
for piece in &mut parser {
|
||||
match piece {
|
||||
RpfPiece::Lit(lit) => {
|
||||
pieces.push(Piece::Lit(lit.into()));
|
||||
}
|
||||
RpfPiece::NextArgument(arg) => {
|
||||
warn_on_format_spec(arg.format, &mut warnings, span);
|
||||
let arg = parse_arg(&arg, ctx, &mut warnings, span);
|
||||
pieces.push(Piece::Arg(arg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if parser.errors.is_empty() {
|
||||
Ok(FormatString { input, pieces, span, warnings })
|
||||
} else {
|
||||
Err(parser.errors)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn format(&self, args: &FormatArgs<'_>) -> String {
|
||||
let mut ret = String::new();
|
||||
for piece in &self.pieces {
|
||||
match piece {
|
||||
Piece::Lit(s) | Piece::Arg(FormatArg::AsIs(s)) => ret.push_str(&s),
|
||||
|
||||
// `A` if we have `trait Trait<A> {}` and `note = "i'm the actual type of {A}"`
|
||||
Piece::Arg(FormatArg::GenericParam { generic_param }) => {
|
||||
// Should always be some but we can't raise errors here
|
||||
let value = match args.generic_args.iter().find(|(p, _)| p == generic_param) {
|
||||
Some((_, val)) => val.to_string(),
|
||||
None => generic_param.to_string(),
|
||||
};
|
||||
ret.push_str(&value);
|
||||
}
|
||||
// `{Self}`
|
||||
Piece::Arg(FormatArg::SelfUpper) => {
|
||||
let slf = match args.generic_args.iter().find(|(p, _)| *p == kw::SelfUpper) {
|
||||
Some((_, val)) => val.to_string(),
|
||||
None => "Self".to_string(),
|
||||
};
|
||||
ret.push_str(&slf);
|
||||
}
|
||||
|
||||
// It's only `rustc_onunimplemented` from here
|
||||
Piece::Arg(FormatArg::This) => ret.push_str(&args.this),
|
||||
Piece::Arg(FormatArg::Trait) => {
|
||||
let _ = fmt::write(&mut ret, format_args!("{}", &args.trait_sugared));
|
||||
}
|
||||
Piece::Arg(FormatArg::ItemContext) => ret.push_str(args.item_context),
|
||||
}
|
||||
}
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_arg<'tcx>(
|
||||
arg: &Argument<'_>,
|
||||
ctx: &Ctx<'tcx>,
|
||||
warnings: &mut Vec<FormatWarning>,
|
||||
input_span: Span,
|
||||
) -> FormatArg {
|
||||
let (Ctx::RustcOnUnimplemented { tcx, trait_def_id }
|
||||
| Ctx::DiagnosticOnUnimplemented { tcx, trait_def_id }) = ctx;
|
||||
let trait_name = tcx.item_ident(*trait_def_id);
|
||||
let generics = tcx.generics_of(trait_def_id);
|
||||
let span = slice_span(input_span, arg.position_span);
|
||||
|
||||
match arg.position {
|
||||
// Something like "hello {name}"
|
||||
Position::ArgumentNamed(name) => match (ctx, Symbol::intern(name)) {
|
||||
// accepted, but deprecated
|
||||
(Ctx::RustcOnUnimplemented { .. }, sym::_Self) => {
|
||||
warnings
|
||||
.push(FormatWarning::FutureIncompat { span, help: String::from("use {Self}") });
|
||||
FormatArg::SelfUpper
|
||||
}
|
||||
(
|
||||
Ctx::RustcOnUnimplemented { .. },
|
||||
sym::from_desugaring
|
||||
| sym::crate_local
|
||||
| sym::direct
|
||||
| sym::cause
|
||||
| sym::float
|
||||
| sym::integer_
|
||||
| sym::integral,
|
||||
) => {
|
||||
warnings.push(FormatWarning::FutureIncompat {
|
||||
span,
|
||||
help: String::from("don't use this in a format string"),
|
||||
});
|
||||
FormatArg::AsIs(String::new())
|
||||
}
|
||||
|
||||
// Only `#[rustc_on_unimplemented]` can use these
|
||||
(Ctx::RustcOnUnimplemented { .. }, sym::ItemContext) => FormatArg::ItemContext,
|
||||
(Ctx::RustcOnUnimplemented { .. }, sym::This) => FormatArg::This,
|
||||
(Ctx::RustcOnUnimplemented { .. }, sym::Trait) => FormatArg::Trait,
|
||||
// `{ThisTraitsName}`. Some attrs in std use this, but I'd like to change it to the more general `{This}`
|
||||
// because that'll be simpler to parse and extend in the future
|
||||
(Ctx::RustcOnUnimplemented { .. }, name) if name == trait_name.name => {
|
||||
warnings
|
||||
.push(FormatWarning::FutureIncompat { span, help: String::from("use {This}") });
|
||||
FormatArg::This
|
||||
}
|
||||
|
||||
// Any attribute can use these
|
||||
(
|
||||
Ctx::RustcOnUnimplemented { .. } | Ctx::DiagnosticOnUnimplemented { .. },
|
||||
kw::SelfUpper,
|
||||
) => FormatArg::SelfUpper,
|
||||
(
|
||||
Ctx::RustcOnUnimplemented { .. } | Ctx::DiagnosticOnUnimplemented { .. },
|
||||
generic_param,
|
||||
) if generics.own_params.iter().any(|param| param.name == generic_param) => {
|
||||
FormatArg::GenericParam { generic_param }
|
||||
}
|
||||
|
||||
(_, argument_name) => {
|
||||
warnings.push(FormatWarning::UnknownParam { argument_name, span });
|
||||
FormatArg::AsIs(format!("{{{}}}", argument_name.as_str()))
|
||||
}
|
||||
},
|
||||
|
||||
// `{:1}` and `{}` are ignored
|
||||
Position::ArgumentIs(idx) => {
|
||||
warnings.push(FormatWarning::PositionalArgument {
|
||||
span,
|
||||
help: format!("use `{{{idx}}}` to print a number in braces"),
|
||||
});
|
||||
FormatArg::AsIs(format!("{{{idx}}}"))
|
||||
}
|
||||
Position::ArgumentImplicitlyIs(_) => {
|
||||
warnings.push(FormatWarning::PositionalArgument {
|
||||
span,
|
||||
help: String::from("use `{{}}` to print empty braces"),
|
||||
});
|
||||
FormatArg::AsIs(String::from("{}"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `#[rustc_on_unimplemented]` and `#[diagnostic::...]` don't actually do anything
|
||||
/// with specifiers, so emit a warning if they are used.
|
||||
fn warn_on_format_spec(spec: FormatSpec<'_>, warnings: &mut Vec<FormatWarning>, input_span: Span) {
|
||||
if !matches!(
|
||||
spec,
|
||||
FormatSpec {
|
||||
fill: None,
|
||||
fill_span: None,
|
||||
align: Alignment::AlignUnknown,
|
||||
sign: None,
|
||||
alternate: false,
|
||||
zero_pad: false,
|
||||
debug_hex: None,
|
||||
precision: Count::CountImplied,
|
||||
precision_span: None,
|
||||
width: Count::CountImplied,
|
||||
width_span: None,
|
||||
ty: _,
|
||||
ty_span: _,
|
||||
},
|
||||
) {
|
||||
let span = spec.ty_span.map(|inner| slice_span(input_span, inner)).unwrap_or(input_span);
|
||||
warnings.push(FormatWarning::InvalidSpecifier { span, name: spec.ty.into() })
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper function because `Span` and `rustc_parse_format::InnerSpan` don't know about each other
|
||||
fn slice_span(input: Span, inner: InnerSpan) -> Span {
|
||||
let InnerSpan { start, end } = inner;
|
||||
let span = input.data();
|
||||
|
||||
Span::new(
|
||||
span.lo + BytePos::from_usize(start),
|
||||
span.lo + BytePos::from_usize(end),
|
||||
span.ctxt,
|
||||
span.parent,
|
||||
)
|
||||
}
|
||||
|
||||
pub mod errors {
|
||||
use rustc_macros::LintDiagnostic;
|
||||
use rustc_span::Ident;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(trait_selection_unknown_format_parameter_for_on_unimplemented_attr)]
|
||||
#[help]
|
||||
pub struct UnknownFormatParameterForOnUnimplementedAttr {
|
||||
pub argument_name: Symbol,
|
||||
pub trait_name: Ident,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(trait_selection_disallowed_positional_argument)]
|
||||
#[help]
|
||||
pub struct DisallowedPositionalArgument;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(trait_selection_invalid_format_specifier)]
|
||||
#[help]
|
||||
pub struct InvalidFormatSpecifier;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(trait_selection_missing_options_for_on_unimplemented_attr)]
|
||||
#[help]
|
||||
pub struct MissingOptionsForOnUnimplementedAttr;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(trait_selection_ignored_diagnostic_option)]
|
||||
pub struct IgnoredDiagnosticOption {
|
||||
pub option_name: &'static str,
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[label(trait_selection_other_label)]
|
||||
pub prev_span: Span,
|
||||
}
|
||||
|
||||
impl IgnoredDiagnosticOption {
|
||||
pub fn maybe_emit_warning<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
item_def_id: DefId,
|
||||
new: Option<Span>,
|
||||
old: Option<Span>,
|
||||
option_name: &'static str,
|
||||
) {
|
||||
if let (Some(new_item), Some(old_item)) = (new, old) {
|
||||
if let Some(item_def_id) = item_def_id.as_local() {
|
||||
tcx.emit_node_span_lint(
|
||||
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
tcx.local_def_id_to_hir_id(item_def_id),
|
||||
new_item,
|
||||
IgnoredDiagnosticOption {
|
||||
span: new_item,
|
||||
prev_span: old_item,
|
||||
option_name,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -77,7 +77,15 @@ impl<'tcx> At<'_, 'tcx> {
|
|||
.into_value_registering_obligations(self.infcx, &mut *fulfill_cx);
|
||||
let errors = fulfill_cx.select_all_or_error(self.infcx);
|
||||
let value = self.infcx.resolve_vars_if_possible(value);
|
||||
if errors.is_empty() { Ok(value) } else { Err(errors) }
|
||||
if errors.is_empty() {
|
||||
Ok(value)
|
||||
} else {
|
||||
// Drop pending obligations, since deep normalization may happen
|
||||
// in a loop and we don't want to trigger the assertion on the next
|
||||
// iteration due to pending ambiguous obligations we've left over.
|
||||
let _ = fulfill_cx.collect_remaining_errors(self.infcx);
|
||||
Err(errors)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,18 @@
|
|||
use std::fmt;
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
|
||||
use tracing::instrument;
|
||||
|
||||
use super::{Byte, Nfa, Ref, nfa};
|
||||
use super::{Byte, Ref, Tree, Uninhabited};
|
||||
use crate::Map;
|
||||
|
||||
#[derive(PartialEq, Clone, Debug)]
|
||||
#[derive(PartialEq)]
|
||||
#[cfg_attr(test, derive(Clone))]
|
||||
pub(crate) struct Dfa<R>
|
||||
where
|
||||
R: Ref,
|
||||
{
|
||||
pub(crate) transitions: Map<State, Transitions<R>>,
|
||||
pub(crate) start: State,
|
||||
pub(crate) accepting: State,
|
||||
pub(crate) accept: State,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone, Debug)]
|
||||
|
|
@ -34,35 +33,15 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<R> Transitions<R>
|
||||
where
|
||||
R: Ref,
|
||||
{
|
||||
#[cfg(test)]
|
||||
fn insert(&mut self, transition: Transition<R>, state: State) {
|
||||
match transition {
|
||||
Transition::Byte(b) => {
|
||||
self.byte_transitions.insert(b, state);
|
||||
}
|
||||
Transition::Ref(r) => {
|
||||
self.ref_transitions.insert(r, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The states in a `Nfa` represent byte offsets.
|
||||
/// The states in a [`Dfa`] represent byte offsets.
|
||||
#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Copy, Clone)]
|
||||
pub(crate) struct State(u32);
|
||||
pub(crate) struct State(pub(crate) u32);
|
||||
|
||||
#[cfg(test)]
|
||||
#[derive(Hash, Eq, PartialEq, Clone, Copy)]
|
||||
pub(crate) enum Transition<R>
|
||||
where
|
||||
R: Ref,
|
||||
{
|
||||
Byte(Byte),
|
||||
Ref(R),
|
||||
impl State {
|
||||
pub(crate) fn new() -> Self {
|
||||
static COUNTER: AtomicU32 = AtomicU32::new(0);
|
||||
Self(COUNTER.fetch_add(1, Ordering::SeqCst))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for State {
|
||||
|
|
@ -71,19 +50,6 @@ impl fmt::Debug for State {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl<R> fmt::Debug for Transition<R>
|
||||
where
|
||||
R: Ref,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match &self {
|
||||
Self::Byte(b) => b.fmt(f),
|
||||
Self::Ref(r) => r.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> Dfa<R>
|
||||
where
|
||||
R: Ref,
|
||||
|
|
@ -92,60 +58,167 @@ where
|
|||
pub(crate) fn bool() -> Self {
|
||||
let mut transitions: Map<State, Transitions<R>> = Map::default();
|
||||
let start = State::new();
|
||||
let accepting = State::new();
|
||||
let accept = State::new();
|
||||
|
||||
transitions.entry(start).or_default().insert(Transition::Byte(Byte::Init(0x00)), accepting);
|
||||
transitions.entry(start).or_default().byte_transitions.insert(Byte::Init(0x00), accept);
|
||||
|
||||
transitions.entry(start).or_default().insert(Transition::Byte(Byte::Init(0x01)), accepting);
|
||||
transitions.entry(start).or_default().byte_transitions.insert(Byte::Init(0x01), accept);
|
||||
|
||||
Self { transitions, start, accepting }
|
||||
Self { transitions, start, accept }
|
||||
}
|
||||
|
||||
#[instrument(level = "debug")]
|
||||
pub(crate) fn from_nfa(nfa: Nfa<R>) -> Self {
|
||||
let Nfa { transitions: nfa_transitions, start: nfa_start, accepting: nfa_accepting } = nfa;
|
||||
pub(crate) fn unit() -> Self {
|
||||
let transitions: Map<State, Transitions<R>> = Map::default();
|
||||
let start = State::new();
|
||||
let accept = start;
|
||||
|
||||
let mut dfa_transitions: Map<State, Transitions<R>> = Map::default();
|
||||
let mut nfa_to_dfa: Map<nfa::State, State> = Map::default();
|
||||
let dfa_start = State::new();
|
||||
nfa_to_dfa.insert(nfa_start, dfa_start);
|
||||
Self { transitions, start, accept }
|
||||
}
|
||||
|
||||
let mut queue = vec![(nfa_start, dfa_start)];
|
||||
pub(crate) fn from_byte(byte: Byte) -> Self {
|
||||
let mut transitions: Map<State, Transitions<R>> = Map::default();
|
||||
let start = State::new();
|
||||
let accept = State::new();
|
||||
|
||||
while let Some((nfa_state, dfa_state)) = queue.pop() {
|
||||
if nfa_state == nfa_accepting {
|
||||
continue;
|
||||
transitions.entry(start).or_default().byte_transitions.insert(byte, accept);
|
||||
|
||||
Self { transitions, start, accept }
|
||||
}
|
||||
|
||||
pub(crate) fn from_ref(r: R) -> Self {
|
||||
let mut transitions: Map<State, Transitions<R>> = Map::default();
|
||||
let start = State::new();
|
||||
let accept = State::new();
|
||||
|
||||
transitions.entry(start).or_default().ref_transitions.insert(r, accept);
|
||||
|
||||
Self { transitions, start, accept }
|
||||
}
|
||||
|
||||
pub(crate) fn from_tree(tree: Tree<!, R>) -> Result<Self, Uninhabited> {
|
||||
Ok(match tree {
|
||||
Tree::Byte(b) => Self::from_byte(b),
|
||||
Tree::Ref(r) => Self::from_ref(r),
|
||||
Tree::Alt(alts) => {
|
||||
// Convert and filter the inhabited alternatives.
|
||||
let mut alts = alts.into_iter().map(Self::from_tree).filter_map(Result::ok);
|
||||
// If there are no alternatives, return `Uninhabited`.
|
||||
let dfa = alts.next().ok_or(Uninhabited)?;
|
||||
// Combine the remaining alternatives with `dfa`.
|
||||
alts.fold(dfa, |dfa, alt| dfa.union(alt, State::new))
|
||||
}
|
||||
Tree::Seq(elts) => {
|
||||
let mut dfa = Self::unit();
|
||||
for elt in elts.into_iter().map(Self::from_tree) {
|
||||
dfa = dfa.concat(elt?);
|
||||
}
|
||||
dfa
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Concatenate two `Dfa`s.
|
||||
pub(crate) fn concat(self, other: Self) -> Self {
|
||||
if self.start == self.accept {
|
||||
return other;
|
||||
} else if other.start == other.accept {
|
||||
return self;
|
||||
}
|
||||
|
||||
let start = self.start;
|
||||
let accept = other.accept;
|
||||
|
||||
let mut transitions: Map<State, Transitions<R>> = self.transitions;
|
||||
|
||||
for (source, transition) in other.transitions {
|
||||
let fix_state = |state| if state == other.start { self.accept } else { state };
|
||||
let entry = transitions.entry(fix_state(source)).or_default();
|
||||
for (edge, destination) in transition.byte_transitions {
|
||||
entry.byte_transitions.insert(edge, fix_state(destination));
|
||||
}
|
||||
for (edge, destination) in transition.ref_transitions {
|
||||
entry.ref_transitions.insert(edge, fix_state(destination));
|
||||
}
|
||||
}
|
||||
|
||||
Self { transitions, start, accept }
|
||||
}
|
||||
|
||||
/// Compute the union of two `Dfa`s.
|
||||
pub(crate) fn union(self, other: Self, mut new_state: impl FnMut() -> State) -> Self {
|
||||
// We implement `union` by lazily initializing a set of states
|
||||
// corresponding to the product of states in `self` and `other`, and
|
||||
// then add transitions between these states that correspond to where
|
||||
// they exist between `self` and `other`.
|
||||
|
||||
let a = self;
|
||||
let b = other;
|
||||
|
||||
let accept = new_state();
|
||||
|
||||
let mut mapping: Map<(Option<State>, Option<State>), State> = Map::default();
|
||||
|
||||
let mut mapped = |(a_state, b_state)| {
|
||||
if Some(a.accept) == a_state || Some(b.accept) == b_state {
|
||||
// If either `a_state` or `b_state` are accepting, map to a
|
||||
// common `accept` state.
|
||||
accept
|
||||
} else {
|
||||
*mapping.entry((a_state, b_state)).or_insert_with(&mut new_state)
|
||||
}
|
||||
};
|
||||
|
||||
let start = mapped((Some(a.start), Some(b.start)));
|
||||
let mut transitions: Map<State, Transitions<R>> = Map::default();
|
||||
let mut queue = vec![(Some(a.start), Some(b.start))];
|
||||
let empty_transitions = Transitions::default();
|
||||
|
||||
while let Some((a_src, b_src)) = queue.pop() {
|
||||
let a_transitions =
|
||||
a_src.and_then(|a_src| a.transitions.get(&a_src)).unwrap_or(&empty_transitions);
|
||||
let b_transitions =
|
||||
b_src.and_then(|b_src| b.transitions.get(&b_src)).unwrap_or(&empty_transitions);
|
||||
|
||||
let byte_transitions =
|
||||
a_transitions.byte_transitions.keys().chain(b_transitions.byte_transitions.keys());
|
||||
|
||||
for byte_transition in byte_transitions {
|
||||
let a_dst = a_transitions.byte_transitions.get(byte_transition).copied();
|
||||
let b_dst = b_transitions.byte_transitions.get(byte_transition).copied();
|
||||
|
||||
assert!(a_dst.is_some() || b_dst.is_some());
|
||||
|
||||
let src = mapped((a_src, b_src));
|
||||
let dst = mapped((a_dst, b_dst));
|
||||
|
||||
transitions.entry(src).or_default().byte_transitions.insert(*byte_transition, dst);
|
||||
|
||||
if !transitions.contains_key(&dst) {
|
||||
queue.push((a_dst, b_dst))
|
||||
}
|
||||
}
|
||||
|
||||
for (nfa_transition, next_nfa_states) in nfa_transitions[&nfa_state].iter() {
|
||||
let dfa_transitions =
|
||||
dfa_transitions.entry(dfa_state).or_insert_with(Default::default);
|
||||
let ref_transitions =
|
||||
a_transitions.ref_transitions.keys().chain(b_transitions.ref_transitions.keys());
|
||||
|
||||
let mapped_state = next_nfa_states.iter().find_map(|x| nfa_to_dfa.get(x).copied());
|
||||
for ref_transition in ref_transitions {
|
||||
let a_dst = a_transitions.ref_transitions.get(ref_transition).copied();
|
||||
let b_dst = b_transitions.ref_transitions.get(ref_transition).copied();
|
||||
|
||||
let next_dfa_state = match nfa_transition {
|
||||
&nfa::Transition::Byte(b) => *dfa_transitions
|
||||
.byte_transitions
|
||||
.entry(b)
|
||||
.or_insert_with(|| mapped_state.unwrap_or_else(State::new)),
|
||||
&nfa::Transition::Ref(r) => *dfa_transitions
|
||||
.ref_transitions
|
||||
.entry(r)
|
||||
.or_insert_with(|| mapped_state.unwrap_or_else(State::new)),
|
||||
};
|
||||
assert!(a_dst.is_some() || b_dst.is_some());
|
||||
|
||||
for &next_nfa_state in next_nfa_states {
|
||||
nfa_to_dfa.entry(next_nfa_state).or_insert_with(|| {
|
||||
queue.push((next_nfa_state, next_dfa_state));
|
||||
next_dfa_state
|
||||
});
|
||||
let src = mapped((a_src, b_src));
|
||||
let dst = mapped((a_dst, b_dst));
|
||||
|
||||
transitions.entry(src).or_default().ref_transitions.insert(*ref_transition, dst);
|
||||
|
||||
if !transitions.contains_key(&dst) {
|
||||
queue.push((a_dst, b_dst))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let dfa_accepting = nfa_to_dfa[&nfa_accepting];
|
||||
|
||||
Self { transitions: dfa_transitions, start: dfa_start, accepting: dfa_accepting }
|
||||
Self { transitions, start, accept }
|
||||
}
|
||||
|
||||
pub(crate) fn bytes_from(&self, start: State) -> Option<&Map<Byte, State>> {
|
||||
|
|
@ -159,24 +232,48 @@ where
|
|||
pub(crate) fn refs_from(&self, start: State) -> Option<&Map<R, State>> {
|
||||
Some(&self.transitions.get(&start)?.ref_transitions)
|
||||
}
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub(crate) fn new() -> Self {
|
||||
static COUNTER: AtomicU32 = AtomicU32::new(0);
|
||||
Self(COUNTER.fetch_add(1, Ordering::SeqCst))
|
||||
#[cfg(test)]
|
||||
pub(crate) fn from_edges<B: Copy + Into<Byte>>(
|
||||
start: u32,
|
||||
accept: u32,
|
||||
edges: &[(u32, B, u32)],
|
||||
) -> Self {
|
||||
let start = State(start);
|
||||
let accept = State(accept);
|
||||
let mut transitions: Map<State, Transitions<R>> = Map::default();
|
||||
|
||||
for &(src, edge, dst) in edges {
|
||||
let src = State(src);
|
||||
let dst = State(dst);
|
||||
let old = transitions.entry(src).or_default().byte_transitions.insert(edge.into(), dst);
|
||||
assert!(old.is_none());
|
||||
}
|
||||
|
||||
Self { start, accept, transitions }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl<R> From<nfa::Transition<R>> for Transition<R>
|
||||
/// Serialize the DFA using the Graphviz DOT format.
|
||||
impl<R> fmt::Debug for Dfa<R>
|
||||
where
|
||||
R: Ref,
|
||||
{
|
||||
fn from(nfa_transition: nfa::Transition<R>) -> Self {
|
||||
match nfa_transition {
|
||||
nfa::Transition::Byte(byte) => Transition::Byte(byte),
|
||||
nfa::Transition::Ref(r) => Transition::Ref(r),
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
writeln!(f, "digraph {{")?;
|
||||
writeln!(f, " {:?} [shape = doublecircle]", self.start)?;
|
||||
writeln!(f, " {:?} [shape = doublecircle]", self.accept)?;
|
||||
|
||||
for (src, transitions) in self.transitions.iter() {
|
||||
for (t, dst) in transitions.byte_transitions.iter() {
|
||||
writeln!(f, " {src:?} -> {dst:?} [label=\"{t:?}\"]")?;
|
||||
}
|
||||
|
||||
for (t, dst) in transitions.ref_transitions.iter() {
|
||||
writeln!(f, " {src:?} -> {dst:?} [label=\"{t:?}\"]")?;
|
||||
}
|
||||
}
|
||||
|
||||
writeln!(f, "}}")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,9 +4,6 @@ use std::hash::Hash;
|
|||
pub(crate) mod tree;
|
||||
pub(crate) use tree::Tree;
|
||||
|
||||
pub(crate) mod nfa;
|
||||
pub(crate) use nfa::Nfa;
|
||||
|
||||
pub(crate) mod dfa;
|
||||
pub(crate) use dfa::Dfa;
|
||||
|
||||
|
|
@ -29,6 +26,13 @@ impl fmt::Debug for Byte {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl From<u8> for Byte {
|
||||
fn from(src: u8) -> Self {
|
||||
Self::Init(src)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait Def: Debug + Hash + Eq + PartialEq + Copy + Clone {
|
||||
fn has_safety_invariants(&self) -> bool;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,169 +0,0 @@
|
|||
use std::fmt;
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
|
||||
use super::{Byte, Ref, Tree, Uninhabited};
|
||||
use crate::{Map, Set};
|
||||
|
||||
/// A non-deterministic finite automaton (NFA) that represents the layout of a type.
|
||||
/// The transmutability of two given types is computed by comparing their `Nfa`s.
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub(crate) struct Nfa<R>
|
||||
where
|
||||
R: Ref,
|
||||
{
|
||||
pub(crate) transitions: Map<State, Map<Transition<R>, Set<State>>>,
|
||||
pub(crate) start: State,
|
||||
pub(crate) accepting: State,
|
||||
}
|
||||
|
||||
/// The states in a `Nfa` represent byte offsets.
|
||||
#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Copy, Clone)]
|
||||
pub(crate) struct State(u32);
|
||||
|
||||
/// The transitions between states in a `Nfa` reflect bit validity.
|
||||
#[derive(Hash, Eq, PartialEq, Clone, Copy)]
|
||||
pub(crate) enum Transition<R>
|
||||
where
|
||||
R: Ref,
|
||||
{
|
||||
Byte(Byte),
|
||||
Ref(R),
|
||||
}
|
||||
|
||||
impl fmt::Debug for State {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "S_{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> fmt::Debug for Transition<R>
|
||||
where
|
||||
R: Ref,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match &self {
|
||||
Self::Byte(b) => b.fmt(f),
|
||||
Self::Ref(r) => r.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> Nfa<R>
|
||||
where
|
||||
R: Ref,
|
||||
{
|
||||
pub(crate) fn unit() -> Self {
|
||||
let transitions: Map<State, Map<Transition<R>, Set<State>>> = Map::default();
|
||||
let start = State::new();
|
||||
let accepting = start;
|
||||
|
||||
Nfa { transitions, start, accepting }
|
||||
}
|
||||
|
||||
pub(crate) fn from_byte(byte: Byte) -> Self {
|
||||
let mut transitions: Map<State, Map<Transition<R>, Set<State>>> = Map::default();
|
||||
let start = State::new();
|
||||
let accepting = State::new();
|
||||
|
||||
let source = transitions.entry(start).or_default();
|
||||
let edge = source.entry(Transition::Byte(byte)).or_default();
|
||||
edge.insert(accepting);
|
||||
|
||||
Nfa { transitions, start, accepting }
|
||||
}
|
||||
|
||||
pub(crate) fn from_ref(r: R) -> Self {
|
||||
let mut transitions: Map<State, Map<Transition<R>, Set<State>>> = Map::default();
|
||||
let start = State::new();
|
||||
let accepting = State::new();
|
||||
|
||||
let source = transitions.entry(start).or_default();
|
||||
let edge = source.entry(Transition::Ref(r)).or_default();
|
||||
edge.insert(accepting);
|
||||
|
||||
Nfa { transitions, start, accepting }
|
||||
}
|
||||
|
||||
pub(crate) fn from_tree(tree: Tree<!, R>) -> Result<Self, Uninhabited> {
|
||||
Ok(match tree {
|
||||
Tree::Byte(b) => Self::from_byte(b),
|
||||
Tree::Ref(r) => Self::from_ref(r),
|
||||
Tree::Alt(alts) => {
|
||||
let mut alts = alts.into_iter().map(Self::from_tree);
|
||||
let mut nfa = alts.next().ok_or(Uninhabited)??;
|
||||
for alt in alts {
|
||||
nfa = nfa.union(alt?);
|
||||
}
|
||||
nfa
|
||||
}
|
||||
Tree::Seq(elts) => {
|
||||
let mut nfa = Self::unit();
|
||||
for elt in elts.into_iter().map(Self::from_tree) {
|
||||
nfa = nfa.concat(elt?);
|
||||
}
|
||||
nfa
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Concatenate two `Nfa`s.
|
||||
pub(crate) fn concat(self, other: Self) -> Self {
|
||||
if self.start == self.accepting {
|
||||
return other;
|
||||
} else if other.start == other.accepting {
|
||||
return self;
|
||||
}
|
||||
|
||||
let start = self.start;
|
||||
let accepting = other.accepting;
|
||||
|
||||
let mut transitions: Map<State, Map<Transition<R>, Set<State>>> = self.transitions;
|
||||
|
||||
for (source, transition) in other.transitions {
|
||||
let fix_state = |state| if state == other.start { self.accepting } else { state };
|
||||
let entry = transitions.entry(fix_state(source)).or_default();
|
||||
for (edge, destinations) in transition {
|
||||
let entry = entry.entry(edge).or_default();
|
||||
for destination in destinations {
|
||||
entry.insert(fix_state(destination));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Self { transitions, start, accepting }
|
||||
}
|
||||
|
||||
/// Compute the union of two `Nfa`s.
|
||||
pub(crate) fn union(self, other: Self) -> Self {
|
||||
let start = self.start;
|
||||
let accepting = self.accepting;
|
||||
|
||||
let mut transitions: Map<State, Map<Transition<R>, Set<State>>> = self.transitions.clone();
|
||||
|
||||
for (&(mut source), transition) in other.transitions.iter() {
|
||||
// if source is starting state of `other`, replace with starting state of `self`
|
||||
if source == other.start {
|
||||
source = self.start;
|
||||
}
|
||||
let entry = transitions.entry(source).or_default();
|
||||
for (edge, destinations) in transition {
|
||||
let entry = entry.entry(*edge).or_default();
|
||||
for &(mut destination) in destinations {
|
||||
// if dest is accepting state of `other`, replace with accepting state of `self`
|
||||
if destination == other.accepting {
|
||||
destination = self.accepting;
|
||||
}
|
||||
entry.insert(destination);
|
||||
}
|
||||
}
|
||||
}
|
||||
Self { transitions, start, accepting }
|
||||
}
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub(crate) fn new() -> Self {
|
||||
static COUNTER: AtomicU32 = AtomicU32::new(0);
|
||||
Self(COUNTER.fetch_add(1, Ordering::SeqCst))
|
||||
}
|
||||
}
|
||||
|
|
@ -514,7 +514,7 @@ pub(crate) mod rustc {
|
|||
}
|
||||
}
|
||||
ty::Tuple(fields) => fields[i.as_usize()],
|
||||
kind @ _ => unimplemented!(
|
||||
kind => unimplemented!(
|
||||
"only a subset of `Ty::ty_and_layout_field`'s functionality is implemented. implementation needed for {:?}",
|
||||
kind
|
||||
),
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#![feature(never_type)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
pub(crate) use rustc_data_structures::fx::{FxIndexMap as Map, FxIndexSet as Set};
|
||||
pub(crate) use rustc_data_structures::fx::FxIndexMap as Map;
|
||||
|
||||
pub mod layout;
|
||||
mod maybe_transmutable;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ pub(crate) mod query_context;
|
|||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use crate::layout::{self, Byte, Def, Dfa, Nfa, Ref, Tree, Uninhabited, dfa};
|
||||
use crate::layout::{self, Byte, Def, Dfa, Ref, Tree, Uninhabited, dfa};
|
||||
use crate::maybe_transmutable::query_context::QueryContext;
|
||||
use crate::{Answer, Condition, Map, Reason};
|
||||
|
||||
|
|
@ -73,7 +73,7 @@ where
|
|||
/// Answers whether a `Tree` is transmutable into another `Tree`.
|
||||
///
|
||||
/// This method begins by de-def'ing `src` and `dst`, and prunes private paths from `dst`,
|
||||
/// then converts `src` and `dst` to `Nfa`s, and computes an answer using those NFAs.
|
||||
/// then converts `src` and `dst` to `Dfa`s, and computes an answer using those DFAs.
|
||||
#[inline(always)]
|
||||
#[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))]
|
||||
pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Ref> {
|
||||
|
|
@ -105,22 +105,22 @@ where
|
|||
|
||||
trace!(?dst, "pruned dst");
|
||||
|
||||
// Convert `src` from a tree-based representation to an NFA-based
|
||||
// Convert `src` from a tree-based representation to an DFA-based
|
||||
// representation. If the conversion fails because `src` is uninhabited,
|
||||
// conclude that the transmutation is acceptable, because instances of
|
||||
// the `src` type do not exist.
|
||||
let src = match Nfa::from_tree(src) {
|
||||
let src = match Dfa::from_tree(src) {
|
||||
Ok(src) => src,
|
||||
Err(Uninhabited) => return Answer::Yes,
|
||||
};
|
||||
|
||||
// Convert `dst` from a tree-based representation to an NFA-based
|
||||
// Convert `dst` from a tree-based representation to an DFA-based
|
||||
// representation. If the conversion fails because `src` is uninhabited,
|
||||
// conclude that the transmutation is unacceptable. Valid instances of
|
||||
// the `dst` type do not exist, either because it's genuinely
|
||||
// uninhabited, or because there are no branches of the tree that are
|
||||
// free of safety invariants.
|
||||
let dst = match Nfa::from_tree(dst) {
|
||||
let dst = match Dfa::from_tree(dst) {
|
||||
Ok(dst) => dst,
|
||||
Err(Uninhabited) => return Answer::No(Reason::DstMayHaveSafetyInvariants),
|
||||
};
|
||||
|
|
@ -129,23 +129,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<C> MaybeTransmutableQuery<Nfa<<C as QueryContext>::Ref>, C>
|
||||
where
|
||||
C: QueryContext,
|
||||
{
|
||||
/// Answers whether a `Nfa` is transmutable into another `Nfa`.
|
||||
///
|
||||
/// This method converts `src` and `dst` to DFAs, then computes an answer using those DFAs.
|
||||
#[inline(always)]
|
||||
#[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))]
|
||||
pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Ref> {
|
||||
let Self { src, dst, assume, context } = self;
|
||||
let src = Dfa::from_nfa(src);
|
||||
let dst = Dfa::from_nfa(dst);
|
||||
MaybeTransmutableQuery { src, dst, assume, context }.answer()
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> MaybeTransmutableQuery<Dfa<<C as QueryContext>::Ref>, C>
|
||||
where
|
||||
C: QueryContext,
|
||||
|
|
@ -173,7 +156,7 @@ where
|
|||
src_transitions_len = self.src.transitions.len(),
|
||||
dst_transitions_len = self.dst.transitions.len()
|
||||
);
|
||||
let answer = if dst_state == self.dst.accepting {
|
||||
let answer = if dst_state == self.dst.accept {
|
||||
// truncation: `size_of(Src) >= size_of(Dst)`
|
||||
//
|
||||
// Why is truncation OK to do? Because even though the Src is bigger, all we care about
|
||||
|
|
@ -190,7 +173,7 @@ where
|
|||
// that none of the actually-used data can introduce an invalid state for Dst's type, we
|
||||
// are able to safely transmute, even with truncation.
|
||||
Answer::Yes
|
||||
} else if src_state == self.src.accepting {
|
||||
} else if src_state == self.src.accept {
|
||||
// extension: `size_of(Src) >= size_of(Dst)`
|
||||
if let Some(dst_state_prime) = self.dst.byte_from(dst_state, Byte::Uninit) {
|
||||
self.answer_memo(cache, src_state, dst_state_prime)
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ mod bool {
|
|||
|
||||
let into_set = |alts: Vec<_>| {
|
||||
#[cfg(feature = "rustc")]
|
||||
let mut set = crate::Set::default();
|
||||
let mut set = rustc_data_structures::fx::FxIndexSet::default();
|
||||
#[cfg(not(feature = "rustc"))]
|
||||
let mut set = std::collections::HashSet::new();
|
||||
set.extend(alts);
|
||||
|
|
@ -174,3 +174,32 @@ mod bool {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod union {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn union() {
|
||||
let [a, b, c, d] = [0, 1, 2, 3];
|
||||
let s = Dfa::from_edges(a, d, &[(a, 0, b), (b, 0, d), (a, 1, c), (c, 1, d)]);
|
||||
|
||||
let t = Dfa::from_edges(a, c, &[(a, 1, b), (b, 0, c)]);
|
||||
|
||||
let mut ctr = 0;
|
||||
let new_state = || {
|
||||
let state = crate::layout::dfa::State(ctr);
|
||||
ctr += 1;
|
||||
state
|
||||
};
|
||||
|
||||
let u = s.clone().union(t.clone(), new_state);
|
||||
|
||||
let expected_u =
|
||||
Dfa::from_edges(b, a, &[(b, 0, c), (b, 1, d), (d, 1, a), (d, 0, a), (c, 0, a)]);
|
||||
|
||||
assert_eq!(u, expected_u);
|
||||
|
||||
assert_eq!(is_transmutable(&s, &u, Assume::default()), Answer::Yes);
|
||||
assert_eq!(is_transmutable(&t, &u, Assume::default()), Answer::Yes);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -157,9 +157,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.171"
|
||||
version = "0.2.172"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
|
||||
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
||||
dependencies = [
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -574,7 +574,7 @@ impl CString {
|
|||
#[stable(feature = "as_c_str", since = "1.20.0")]
|
||||
#[rustc_diagnostic_item = "cstring_as_c_str"]
|
||||
pub fn as_c_str(&self) -> &CStr {
|
||||
&*self
|
||||
unsafe { CStr::from_bytes_with_nul_unchecked(self.as_bytes_with_nul()) }
|
||||
}
|
||||
|
||||
/// Converts this `CString` into a boxed [`CStr`].
|
||||
|
|
@ -705,14 +705,14 @@ impl ops::Deref for CString {
|
|||
|
||||
#[inline]
|
||||
fn deref(&self) -> &CStr {
|
||||
unsafe { CStr::from_bytes_with_nul_unchecked(self.as_bytes_with_nul()) }
|
||||
self.as_c_str()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl fmt::Debug for CString {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(&**self, f)
|
||||
fmt::Debug::fmt(self.as_c_str(), f)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,12 +33,6 @@ fn build_with_zero2() {
|
|||
assert!(CString::new(vec![0]).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn formatted() {
|
||||
let s = CString::new(&b"abc\x01\x02\n\xE2\x80\xA6\xFF"[..]).unwrap();
|
||||
assert_eq!(format!("{s:?}"), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn borrowed() {
|
||||
unsafe {
|
||||
|
|
|
|||
|
|
@ -772,8 +772,8 @@ impl hash::Hash for TypeId {
|
|||
// (especially given the previous point about the lower 64 bits being
|
||||
// high quality on their own).
|
||||
// - It is correct to do so -- only hashing a subset of `self` is still
|
||||
// with an `Eq` implementation that considers the entire value, as
|
||||
// ours does.
|
||||
// compatible with an `Eq` implementation that considers the entire
|
||||
// value, as ours does.
|
||||
self.t.1.hash(state);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ pub macro asm("assembly template", $(operands,)* $(options($(option),*))?) {
|
|||
///
|
||||
/// [Rust By Example]: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html
|
||||
/// [reference]: https://doc.rust-lang.org/nightly/reference/inline-assembly.html
|
||||
#[unstable(feature = "naked_functions", issue = "90957")]
|
||||
#[stable(feature = "naked_functions", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[rustc_builtin_macro]
|
||||
pub macro naked_asm("assembly template", $(operands,)* $(options($(option),*))?) {
|
||||
/* compiler built-in */
|
||||
|
|
|
|||
|
|
@ -36,8 +36,7 @@ use crate::ops::{Deref, DerefMut, DerefPure};
|
|||
/// presented as hex escape sequences.
|
||||
///
|
||||
/// The `Display` implementation behaves as if the `ByteStr` were first lossily converted to a
|
||||
/// `str`, with invalid UTF-8 presented as the Unicode replacement character: <20>
|
||||
///
|
||||
/// `str`, with invalid UTF-8 presented as the Unicode replacement character (<28>).
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
#[repr(transparent)]
|
||||
#[doc(alias = "BStr")]
|
||||
|
|
|
|||
|
|
@ -150,7 +150,6 @@ impl Error for FromBytesWithNulError {
|
|||
/// within the slice.
|
||||
///
|
||||
/// This error is created by the [`CStr::from_bytes_until_nul`] method.
|
||||
///
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
#[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")]
|
||||
pub struct FromBytesUntilNulError(());
|
||||
|
|
|
|||
|
|
@ -304,7 +304,7 @@ pub unsafe fn simd_shuffle<T, U, V>(x: T, y: T, idx: U) -> V;
|
|||
///
|
||||
/// `U` must be a vector of pointers to the element type of `T`, with the same length as `T`.
|
||||
///
|
||||
/// `V` must be a vector of signed integers with the same length as `T` (but any element size).
|
||||
/// `V` must be a vector of integers with the same length as `T` (but any element size).
|
||||
///
|
||||
/// For each pointer in `ptr`, if the corresponding value in `mask` is `!0`, read the pointer.
|
||||
/// Otherwise if the corresponding value in `mask` is `0`, return the corresponding value from
|
||||
|
|
@ -325,7 +325,7 @@ pub unsafe fn simd_gather<T, U, V>(val: T, ptr: U, mask: V) -> T;
|
|||
///
|
||||
/// `U` must be a vector of pointers to the element type of `T`, with the same length as `T`.
|
||||
///
|
||||
/// `V` must be a vector of signed integers with the same length as `T` (but any element size).
|
||||
/// `V` must be a vector of integers with the same length as `T` (but any element size).
|
||||
///
|
||||
/// For each pointer in `ptr`, if the corresponding value in `mask` is `!0`, write the
|
||||
/// corresponding value in `val` to the pointer.
|
||||
|
|
@ -349,7 +349,7 @@ pub unsafe fn simd_scatter<T, U, V>(val: T, ptr: U, mask: V);
|
|||
///
|
||||
/// `U` must be a pointer to the element type of `T`
|
||||
///
|
||||
/// `V` must be a vector of signed integers with the same length as `T` (but any element size).
|
||||
/// `V` must be a vector of integers with the same length as `T` (but any element size).
|
||||
///
|
||||
/// For each element, if the corresponding value in `mask` is `!0`, read the corresponding
|
||||
/// pointer offset from `ptr`.
|
||||
|
|
@ -372,7 +372,7 @@ pub unsafe fn simd_masked_load<V, U, T>(mask: V, ptr: U, val: T) -> T;
|
|||
///
|
||||
/// `U` must be a pointer to the element type of `T`
|
||||
///
|
||||
/// `V` must be a vector of signed integers with the same length as `T` (but any element size).
|
||||
/// `V` must be a vector of integers with the same length as `T` (but any element size).
|
||||
///
|
||||
/// For each element, if the corresponding value in `mask` is `!0`, write the corresponding
|
||||
/// value in `val` to the pointer offset from `ptr`.
|
||||
|
|
@ -556,7 +556,7 @@ pub unsafe fn simd_bitmask<T, U>(x: T) -> U;
|
|||
///
|
||||
/// `T` must be a vector.
|
||||
///
|
||||
/// `M` must be a signed integer vector with the same length as `T` (but any element size).
|
||||
/// `M` must be an integer vector with the same length as `T` (but any element size).
|
||||
///
|
||||
/// For each element, if the corresponding value in `mask` is `!0`, select the element from
|
||||
/// `if_true`. If the corresponding value in `mask` is `0`, select the element from
|
||||
|
|
|
|||
|
|
@ -1307,10 +1307,12 @@ mod prim_f16 {}
|
|||
// FIXME: Is there a better place to put this?
|
||||
///
|
||||
/// | `target_arch` | Extra payloads possible on this platform |
|
||||
/// |---------------|---------|
|
||||
/// | `x86`, `x86_64`, `arm`, `aarch64`, `riscv32`, `riscv64` | None |
|
||||
/// |---------------|------------------------------------------|
|
||||
// Sorted alphabetically
|
||||
/// | `aarch64`, `arm`, `arm64ec`, `loongarch64`, `powerpc` (except when `target_abi = "spe"`), `powerpc64`, `riscv32`, `riscv64`, `s390x`, `x86`, `x86_64` | None |
|
||||
/// | `nvptx64` | All payloads |
|
||||
/// | `sparc`, `sparc64` | The all-one payload |
|
||||
/// | `wasm32`, `wasm64` | If all input NaNs are quiet with all-zero payload: None.<br> Otherwise: all possible payloads. |
|
||||
/// | `wasm32`, `wasm64` | If all input NaNs are quiet with all-zero payload: None.<br> Otherwise: all payloads. |
|
||||
///
|
||||
/// For targets not in this table, all payloads are possible.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -2820,7 +2820,7 @@ impl<T> [T] {
|
|||
let half = size / 2;
|
||||
let mid = base + half;
|
||||
|
||||
// SAFETY: the call is made safe by the following inconstants:
|
||||
// SAFETY: the call is made safe by the following invariants:
|
||||
// - `mid >= 0`: by definition
|
||||
// - `mid < size`: `mid = size / 2 + size / 4 + size / 8 ...`
|
||||
let cmp = f(unsafe { self.get_unchecked(mid) });
|
||||
|
|
|
|||
|
|
@ -13,3 +13,9 @@ fn compares_as_u8s() {
|
|||
assert_eq!(Ord::cmp(a, b), Ord::cmp(a_bytes, b_bytes));
|
||||
assert_eq!(PartialOrd::partial_cmp(a, b), PartialOrd::partial_cmp(a_bytes, b_bytes));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn debug() {
|
||||
let s = c"abc\x01\x02\n\xE2\x80\xA6\xFF";
|
||||
assert_eq!(format!("{s:?}"), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ miniz_oxide = { version = "0.8.0", optional = true, default-features = false }
|
|||
addr2line = { version = "0.24.0", optional = true, default-features = false }
|
||||
|
||||
[target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
|
||||
libc = { version = "0.2.171", default-features = false, features = [
|
||||
libc = { version = "0.2.172", default-features = false, features = [
|
||||
'rustc-dep-of-std',
|
||||
], public = true }
|
||||
|
||||
|
|
|
|||
|
|
@ -950,7 +950,7 @@ impl fmt::Debug for ArgsOs {
|
|||
/// Constants associated with the current target
|
||||
#[stable(feature = "env", since = "1.0.0")]
|
||||
pub mod consts {
|
||||
use crate::sys::env::os;
|
||||
use crate::sys::env_consts::os;
|
||||
|
||||
/// A string describing the architecture of the CPU that is currently in use.
|
||||
/// An example value may be: `"x86"`, `"arm"` or `"riscv64"`.
|
||||
|
|
|
|||
|
|
@ -3265,7 +3265,7 @@ impl Hash for Path {
|
|||
if !verbatim {
|
||||
component_start += match tail {
|
||||
[b'.'] => 1,
|
||||
[b'.', sep @ _, ..] if is_sep_byte(*sep) => 1,
|
||||
[b'.', sep, ..] if is_sep_byte(*sep) => 1,
|
||||
_ => 0,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ macro_rules! rtprintpanic {
|
|||
macro_rules! rtabort {
|
||||
($($t:tt)*) => {
|
||||
{
|
||||
rtprintpanic!("fatal runtime error: {}\n", format_args!($($t)*));
|
||||
rtprintpanic!("fatal runtime error: {}, aborting\n", format_args!($($t)*));
|
||||
crate::sys::abort_internal();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,8 +10,10 @@ use crate::sys::pal::waitqueue::SpinMutex;
|
|||
// The current allocator here is the `dlmalloc` crate which we've got included
|
||||
// in the rust-lang/rust repository as a submodule. The crate is a port of
|
||||
// dlmalloc.c from C to Rust.
|
||||
//
|
||||
// Specifying linkage/symbol name is solely to ensure a single instance between this crate and its unit tests
|
||||
#[cfg_attr(test, linkage = "available_externally")]
|
||||
#[unsafe(export_name = "_ZN16__rust_internals3std3sys3sgx5alloc8DLMALLOCE")]
|
||||
#[unsafe(export_name = "_ZN16__rust_internals3std3sys5alloc3sgx8DLMALLOCE")]
|
||||
static DLMALLOC: SpinMutex<dlmalloc::Dlmalloc<Sgx>> =
|
||||
SpinMutex::new(dlmalloc::Dlmalloc::new_with_allocator(Sgx {}));
|
||||
|
||||
|
|
|
|||
|
|
@ -1,35 +0,0 @@
|
|||
use crate::ffi::{CStr, OsString, c_char};
|
||||
use crate::os::hermit::ffi::OsStringExt;
|
||||
use crate::ptr;
|
||||
use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
|
||||
use crate::sync::atomic::{AtomicIsize, AtomicPtr};
|
||||
|
||||
#[path = "common.rs"]
|
||||
mod common;
|
||||
pub use common::Args;
|
||||
|
||||
static ARGC: AtomicIsize = AtomicIsize::new(0);
|
||||
static ARGV: AtomicPtr<*const u8> = AtomicPtr::new(ptr::null_mut());
|
||||
|
||||
/// One-time global initialization.
|
||||
pub unsafe fn init(argc: isize, argv: *const *const u8) {
|
||||
ARGC.store(argc, Relaxed);
|
||||
// Use release ordering here to broadcast writes by the OS.
|
||||
ARGV.store(argv as *mut *const u8, Release);
|
||||
}
|
||||
|
||||
/// Returns the command line arguments
|
||||
pub fn args() -> Args {
|
||||
// Synchronize with the store above.
|
||||
let argv = ARGV.load(Acquire);
|
||||
// If argv has not been initialized yet, do not return any arguments.
|
||||
let argc = if argv.is_null() { 0 } else { ARGC.load(Relaxed) };
|
||||
let args: Vec<OsString> = (0..argc)
|
||||
.map(|i| unsafe {
|
||||
let cstr = CStr::from_ptr(*argv.offset(i) as *const c_char);
|
||||
OsStringExt::from_vec(cstr.to_bytes().to_vec())
|
||||
})
|
||||
.collect();
|
||||
|
||||
Args::new(args)
|
||||
}
|
||||
|
|
@ -3,15 +3,15 @@
|
|||
#![forbid(unsafe_op_in_unsafe_fn)]
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(all(target_family = "unix", not(any(target_os = "espidf", target_os = "vita"))))] {
|
||||
if #[cfg(any(
|
||||
all(target_family = "unix", not(any(target_os = "espidf", target_os = "vita"))),
|
||||
target_os = "hermit",
|
||||
))] {
|
||||
mod unix;
|
||||
pub use unix::*;
|
||||
} else if #[cfg(target_family = "windows")] {
|
||||
mod windows;
|
||||
pub use windows::*;
|
||||
} else if #[cfg(target_os = "hermit")] {
|
||||
mod hermit;
|
||||
pub use hermit::*;
|
||||
} else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
|
||||
mod sgx;
|
||||
pub use sgx::*;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use crate::sys::pal::abi::usercalls::raw::ByteBuffer;
|
|||
use crate::sys_common::FromInner;
|
||||
use crate::{fmt, slice};
|
||||
|
||||
// Specifying linkage/symbol name is solely to ensure a single instance between this crate and its unit tests
|
||||
#[cfg_attr(test, linkage = "available_externally")]
|
||||
#[unsafe(export_name = "_ZN16__rust_internals3std3sys3sgx4args4ARGSE")]
|
||||
static ARGS: AtomicUsize = AtomicUsize::new(0);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@
|
|||
#![allow(dead_code)] // runtime init functions not used during testing
|
||||
|
||||
use crate::ffi::CStr;
|
||||
#[cfg(target_os = "hermit")]
|
||||
use crate::os::hermit::ffi::OsStringExt;
|
||||
#[cfg(not(target_os = "hermit"))]
|
||||
use crate::os::unix::ffi::OsStringExt;
|
||||
|
||||
#[path = "common.rs"]
|
||||
|
|
@ -73,6 +76,7 @@ pub fn args() -> Args {
|
|||
target_os = "illumos",
|
||||
target_os = "emscripten",
|
||||
target_os = "haiku",
|
||||
target_os = "hermit",
|
||||
target_os = "l4re",
|
||||
target_os = "fuchsia",
|
||||
target_os = "redox",
|
||||
|
|
@ -100,7 +104,7 @@ mod imp {
|
|||
|
||||
unsafe fn really_init(argc: isize, argv: *const *const u8) {
|
||||
// These don't need to be ordered with each other or other stores,
|
||||
// because they only hold the unmodified system-provide argv/argc.
|
||||
// because they only hold the unmodified system-provided argv/argc.
|
||||
ARGC.store(argc, Ordering::Relaxed);
|
||||
ARGV.store(argv as *mut _, Ordering::Relaxed);
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue