Auto merge of #134470 - jieyouxu:rollup-kld7kmk, r=jieyouxu
Rollup of 11 pull requests Successful merges: - #130786 ( mir-opt: a sub-BB of a cleanup BB must also be a cleanup BB in `EarlyOtherwiseBranch`) - #133926 (Fix const conditions for RPITITs) - #134161 (Overhaul token cursors) - #134253 (Overhaul keyword handling) - #134394 (Clarify the match ergonomics 2024 migration lint's output) - #134399 (Do not do if ! else, use unnegated cond and swap the branches instead) - #134420 (refactor: replace &PathBuf with &Path to enhance generality) - #134436 (tests/assembly/asm: Remove uses of rustc_attrs and lang_items features by using minicore) - #134444 (Fix `x build --stage 1 std` when using cg_cranelift as the default backend) - #134452 (fix(LazyCell): documentation of get[_mut] was wrong) - #134460 (Merge some patterns together) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
a52085d9f6
87 changed files with 1714 additions and 1190 deletions
|
|
@ -1,7 +1,6 @@
|
|||
//! Functions dealing with attributes and meta items.
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::iter;
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
|
||||
use rustc_index::bit_set::GrowableBitSet;
|
||||
|
|
@ -16,7 +15,9 @@ use crate::ast::{
|
|||
};
|
||||
use crate::ptr::P;
|
||||
use crate::token::{self, CommentKind, Delimiter, Token};
|
||||
use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, Spacing, TokenStream, TokenTree};
|
||||
use crate::tokenstream::{
|
||||
DelimSpan, LazyAttrTokenStream, Spacing, TokenStream, TokenStreamIter, TokenTree,
|
||||
};
|
||||
use crate::util::comments;
|
||||
use crate::util::literal::escape_string_symbol;
|
||||
|
||||
|
|
@ -365,12 +366,9 @@ impl MetaItem {
|
|||
}
|
||||
}
|
||||
|
||||
fn from_tokens<'a, I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItem>
|
||||
where
|
||||
I: Iterator<Item = &'a TokenTree>,
|
||||
{
|
||||
fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItem> {
|
||||
// FIXME: Share code with `parse_path`.
|
||||
let tt = tokens.next().map(|tt| TokenTree::uninterpolate(tt));
|
||||
let tt = iter.next().map(|tt| TokenTree::uninterpolate(tt));
|
||||
let path = match tt.as_deref() {
|
||||
Some(&TokenTree::Token(
|
||||
Token { kind: ref kind @ (token::Ident(..) | token::PathSep), span },
|
||||
|
|
@ -378,9 +376,9 @@ impl MetaItem {
|
|||
)) => 'arm: {
|
||||
let mut segments = if let &token::Ident(name, _) = kind {
|
||||
if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) =
|
||||
tokens.peek()
|
||||
iter.peek()
|
||||
{
|
||||
tokens.next();
|
||||
iter.next();
|
||||
thin_vec![PathSegment::from_ident(Ident::new(name, span))]
|
||||
} else {
|
||||
break 'arm Path::from_ident(Ident::new(name, span));
|
||||
|
|
@ -390,16 +388,16 @@ impl MetaItem {
|
|||
};
|
||||
loop {
|
||||
if let Some(&TokenTree::Token(Token { kind: token::Ident(name, _), span }, _)) =
|
||||
tokens.next().map(|tt| TokenTree::uninterpolate(tt)).as_deref()
|
||||
iter.next().map(|tt| TokenTree::uninterpolate(tt)).as_deref()
|
||||
{
|
||||
segments.push(PathSegment::from_ident(Ident::new(name, span)));
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) =
|
||||
tokens.peek()
|
||||
iter.peek()
|
||||
{
|
||||
tokens.next();
|
||||
iter.next();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
|
@ -420,8 +418,8 @@ impl MetaItem {
|
|||
}
|
||||
_ => return None,
|
||||
};
|
||||
let list_closing_paren_pos = tokens.peek().map(|tt| tt.span().hi());
|
||||
let kind = MetaItemKind::from_tokens(tokens)?;
|
||||
let list_closing_paren_pos = iter.peek().map(|tt| tt.span().hi());
|
||||
let kind = MetaItemKind::from_tokens(iter)?;
|
||||
let hi = match &kind {
|
||||
MetaItemKind::NameValue(lit) => lit.span.hi(),
|
||||
MetaItemKind::List(..) => list_closing_paren_pos.unwrap_or(path.span.hi()),
|
||||
|
|
@ -438,12 +436,12 @@ impl MetaItem {
|
|||
impl MetaItemKind {
|
||||
// public because it can be called in the hir
|
||||
pub fn list_from_tokens(tokens: TokenStream) -> Option<ThinVec<MetaItemInner>> {
|
||||
let mut tokens = tokens.trees().peekable();
|
||||
let mut iter = tokens.iter();
|
||||
let mut result = ThinVec::new();
|
||||
while tokens.peek().is_some() {
|
||||
let item = MetaItemInner::from_tokens(&mut tokens)?;
|
||||
while iter.peek().is_some() {
|
||||
let item = MetaItemInner::from_tokens(&mut iter)?;
|
||||
result.push(item);
|
||||
match tokens.next() {
|
||||
match iter.next() {
|
||||
None | Some(TokenTree::Token(Token { kind: token::Comma, .. }, _)) => {}
|
||||
_ => return None,
|
||||
}
|
||||
|
|
@ -451,12 +449,10 @@ impl MetaItemKind {
|
|||
Some(result)
|
||||
}
|
||||
|
||||
fn name_value_from_tokens<'a>(
|
||||
tokens: &mut impl Iterator<Item = &'a TokenTree>,
|
||||
) -> Option<MetaItemKind> {
|
||||
match tokens.next() {
|
||||
fn name_value_from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItemKind> {
|
||||
match iter.next() {
|
||||
Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => {
|
||||
MetaItemKind::name_value_from_tokens(&mut inner_tokens.trees())
|
||||
MetaItemKind::name_value_from_tokens(&mut inner_tokens.iter())
|
||||
}
|
||||
Some(TokenTree::Token(token, _)) => {
|
||||
MetaItemLit::from_token(token).map(MetaItemKind::NameValue)
|
||||
|
|
@ -465,19 +461,17 @@ impl MetaItemKind {
|
|||
}
|
||||
}
|
||||
|
||||
fn from_tokens<'a>(
|
||||
tokens: &mut iter::Peekable<impl Iterator<Item = &'a TokenTree>>,
|
||||
) -> Option<MetaItemKind> {
|
||||
match tokens.peek() {
|
||||
fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItemKind> {
|
||||
match iter.peek() {
|
||||
Some(TokenTree::Delimited(.., Delimiter::Parenthesis, inner_tokens)) => {
|
||||
let inner_tokens = inner_tokens.clone();
|
||||
tokens.next();
|
||||
iter.next();
|
||||
MetaItemKind::list_from_tokens(inner_tokens).map(MetaItemKind::List)
|
||||
}
|
||||
Some(TokenTree::Delimited(..)) => None,
|
||||
Some(TokenTree::Token(Token { kind: token::Eq, .. }, _)) => {
|
||||
tokens.next();
|
||||
MetaItemKind::name_value_from_tokens(tokens)
|
||||
iter.next();
|
||||
MetaItemKind::name_value_from_tokens(iter)
|
||||
}
|
||||
_ => Some(MetaItemKind::Word),
|
||||
}
|
||||
|
|
@ -593,22 +587,19 @@ impl MetaItemInner {
|
|||
self.meta_item().is_some()
|
||||
}
|
||||
|
||||
fn from_tokens<'a, I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItemInner>
|
||||
where
|
||||
I: Iterator<Item = &'a TokenTree>,
|
||||
{
|
||||
match tokens.peek() {
|
||||
fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItemInner> {
|
||||
match iter.peek() {
|
||||
Some(TokenTree::Token(token, _)) if let Some(lit) = MetaItemLit::from_token(token) => {
|
||||
tokens.next();
|
||||
iter.next();
|
||||
return Some(MetaItemInner::Lit(lit));
|
||||
}
|
||||
Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => {
|
||||
tokens.next();
|
||||
return MetaItemInner::from_tokens(&mut inner_tokens.trees().peekable());
|
||||
iter.next();
|
||||
return MetaItemInner::from_tokens(&mut inner_tokens.iter());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
MetaItem::from_tokens(tokens).map(MetaItemInner::MetaItem)
|
||||
MetaItem::from_tokens(iter).map(MetaItemInner::MetaItem)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -903,7 +903,8 @@ impl Token {
|
|||
self.is_non_raw_ident_where(|id| id.name == kw)
|
||||
}
|
||||
|
||||
/// Returns `true` if the token is a given keyword, `kw` or if `case` is `Insensitive` and this token is an identifier equal to `kw` ignoring the case.
|
||||
/// Returns `true` if the token is a given keyword, `kw` or if `case` is `Insensitive` and this
|
||||
/// token is an identifier equal to `kw` ignoring the case.
|
||||
pub fn is_keyword_case(&self, kw: Symbol, case: Case) -> bool {
|
||||
self.is_keyword(kw)
|
||||
|| (case == Case::Insensitive
|
||||
|
|
@ -916,6 +917,11 @@ impl Token {
|
|||
self.is_non_raw_ident_where(Ident::is_path_segment_keyword)
|
||||
}
|
||||
|
||||
/// Don't use this unless you're doing something very loose and heuristic-y.
|
||||
pub fn is_any_keyword(&self) -> bool {
|
||||
self.is_non_raw_ident_where(Ident::is_any_keyword)
|
||||
}
|
||||
|
||||
/// Returns true for reserved identifiers used internally for elided lifetimes,
|
||||
/// unnamed method parameters, crate root module, error recovery etc.
|
||||
pub fn is_special_ident(&self) -> bool {
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ where
|
|||
CTX: crate::HashStableContext,
|
||||
{
|
||||
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
|
||||
for sub_tt in self.trees() {
|
||||
for sub_tt in self.iter() {
|
||||
sub_tt.hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
|
|
@ -406,7 +406,7 @@ impl Eq for TokenStream {}
|
|||
|
||||
impl PartialEq<TokenStream> for TokenStream {
|
||||
fn eq(&self, other: &TokenStream) -> bool {
|
||||
self.trees().eq(other.trees())
|
||||
self.iter().eq(other.iter())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -423,24 +423,24 @@ impl TokenStream {
|
|||
self.0.len()
|
||||
}
|
||||
|
||||
pub fn trees(&self) -> RefTokenTreeCursor<'_> {
|
||||
RefTokenTreeCursor::new(self)
|
||||
pub fn get(&self, index: usize) -> Option<&TokenTree> {
|
||||
self.0.get(index)
|
||||
}
|
||||
|
||||
pub fn into_trees(self) -> TokenTreeCursor {
|
||||
TokenTreeCursor::new(self)
|
||||
pub fn iter(&self) -> TokenStreamIter<'_> {
|
||||
TokenStreamIter::new(self)
|
||||
}
|
||||
|
||||
/// Compares two `TokenStream`s, checking equality without regarding span information.
|
||||
pub fn eq_unspanned(&self, other: &TokenStream) -> bool {
|
||||
let mut t1 = self.trees();
|
||||
let mut t2 = other.trees();
|
||||
for (t1, t2) in iter::zip(&mut t1, &mut t2) {
|
||||
if !t1.eq_unspanned(t2) {
|
||||
let mut iter1 = self.iter();
|
||||
let mut iter2 = other.iter();
|
||||
for (tt1, tt2) in iter::zip(&mut iter1, &mut iter2) {
|
||||
if !tt1.eq_unspanned(tt2) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
t1.next().is_none() && t2.next().is_none()
|
||||
iter1.next().is_none() && iter2.next().is_none()
|
||||
}
|
||||
|
||||
/// Create a token stream containing a single token with alone spacing. The
|
||||
|
|
@ -509,7 +509,7 @@ impl TokenStream {
|
|||
#[must_use]
|
||||
pub fn flattened(&self) -> TokenStream {
|
||||
fn can_skip(stream: &TokenStream) -> bool {
|
||||
stream.trees().all(|tree| match tree {
|
||||
stream.iter().all(|tree| match tree {
|
||||
TokenTree::Token(token, _) => !matches!(
|
||||
token.kind,
|
||||
token::NtIdent(..) | token::NtLifetime(..) | token::Interpolated(..)
|
||||
|
|
@ -522,7 +522,7 @@ impl TokenStream {
|
|||
return self.clone();
|
||||
}
|
||||
|
||||
self.trees().map(|tree| TokenStream::flatten_token_tree(tree)).collect()
|
||||
self.iter().map(|tree| TokenStream::flatten_token_tree(tree)).collect()
|
||||
}
|
||||
|
||||
// If `vec` is not empty, try to glue `tt` onto its last token. The return
|
||||
|
|
@ -665,25 +665,26 @@ impl TokenStream {
|
|||
}
|
||||
}
|
||||
|
||||
/// By-reference iterator over a [`TokenStream`], that produces `&TokenTree`
|
||||
/// items.
|
||||
#[derive(Clone)]
|
||||
pub struct RefTokenTreeCursor<'t> {
|
||||
pub struct TokenStreamIter<'t> {
|
||||
stream: &'t TokenStream,
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl<'t> RefTokenTreeCursor<'t> {
|
||||
impl<'t> TokenStreamIter<'t> {
|
||||
fn new(stream: &'t TokenStream) -> Self {
|
||||
RefTokenTreeCursor { stream, index: 0 }
|
||||
TokenStreamIter { stream, index: 0 }
|
||||
}
|
||||
|
||||
pub fn look_ahead(&self, n: usize) -> Option<&TokenTree> {
|
||||
self.stream.0.get(self.index + n)
|
||||
// Peeking could be done via `Peekable`, but most iterators need peeking,
|
||||
// and this is simple and avoids the need to use `peekable` and `Peekable`
|
||||
// at all the use sites.
|
||||
pub fn peek(&self) -> Option<&'t TokenTree> {
|
||||
self.stream.0.get(self.index)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'t> Iterator for RefTokenTreeCursor<'t> {
|
||||
impl<'t> Iterator for TokenStreamIter<'t> {
|
||||
type Item = &'t TokenTree;
|
||||
|
||||
fn next(&mut self) -> Option<&'t TokenTree> {
|
||||
|
|
@ -694,39 +695,6 @@ impl<'t> Iterator for RefTokenTreeCursor<'t> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Owning by-value iterator over a [`TokenStream`], that produces `&TokenTree`
|
||||
/// items.
|
||||
///
|
||||
/// Doesn't impl `Iterator` because Rust doesn't permit an owning iterator to
|
||||
/// return `&T` from `next`; the need for an explicit lifetime in the `Item`
|
||||
/// associated type gets in the way. Instead, use `next_ref` (which doesn't
|
||||
/// involve associated types) for getting individual elements, or
|
||||
/// `RefTokenTreeCursor` if you really want an `Iterator`, e.g. in a `for`
|
||||
/// loop.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TokenTreeCursor {
|
||||
pub stream: TokenStream,
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl TokenTreeCursor {
|
||||
fn new(stream: TokenStream) -> Self {
|
||||
TokenTreeCursor { stream, index: 0 }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn next_ref(&mut self) -> Option<&TokenTree> {
|
||||
self.stream.0.get(self.index).map(|tree| {
|
||||
self.index += 1;
|
||||
tree
|
||||
})
|
||||
}
|
||||
|
||||
pub fn look_ahead(&self, n: usize) -> Option<&TokenTree> {
|
||||
self.stream.0.get(self.index + n)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]
|
||||
pub struct DelimSpan {
|
||||
pub open: Span,
|
||||
|
|
|
|||
|
|
@ -725,7 +725,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
// E.g. we have seen cases where a proc macro can handle `a :: b` but not
|
||||
// `a::b`. See #117433 for some examples.
|
||||
fn print_tts(&mut self, tts: &TokenStream, convert_dollar_crate: bool) {
|
||||
let mut iter = tts.trees().peekable();
|
||||
let mut iter = tts.iter().peekable();
|
||||
while let Some(tt) = iter.next() {
|
||||
let spacing = self.print_tt(tt, convert_dollar_crate);
|
||||
if let Some(next) = iter.peek() {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ pub(crate) fn expand_concat_idents<'cx>(
|
|||
}
|
||||
|
||||
let mut res_str = String::new();
|
||||
for (i, e) in tts.trees().enumerate() {
|
||||
for (i, e) in tts.iter().enumerate() {
|
||||
if i & 1 == 1 {
|
||||
match e {
|
||||
TokenTree::Token(Token { kind: token::Comma, .. }, _) => {}
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ pub(crate) fn expand_trace_macros(
|
|||
sp: Span,
|
||||
tt: TokenStream,
|
||||
) -> MacroExpanderResult<'static> {
|
||||
let mut cursor = tt.trees();
|
||||
let mut iter = tt.iter();
|
||||
let mut err = false;
|
||||
let value = match &cursor.next() {
|
||||
let value = match iter.next() {
|
||||
Some(TokenTree::Token(token, _)) if token.is_keyword(kw::True) => true,
|
||||
Some(TokenTree::Token(token, _)) if token.is_keyword(kw::False) => false,
|
||||
_ => {
|
||||
|
|
@ -19,7 +19,7 @@ pub(crate) fn expand_trace_macros(
|
|||
false
|
||||
}
|
||||
};
|
||||
err |= cursor.next().is_some();
|
||||
err |= iter.next().is_some();
|
||||
if err {
|
||||
cx.dcx().emit_err(errors::TraceMacros { span: sp });
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ use std::fmt::Write as _;
|
|||
use std::fs::{self, File};
|
||||
use std::io::{self, IsTerminal, Read, Write};
|
||||
use std::panic::{self, PanicHookInfo, catch_unwind};
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{self, Command, Stdio};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, OnceLock};
|
||||
|
|
@ -460,7 +460,7 @@ fn run_compiler(
|
|||
})
|
||||
}
|
||||
|
||||
fn dump_feature_usage_metrics(tcxt: TyCtxt<'_>, metrics_dir: &PathBuf) {
|
||||
fn dump_feature_usage_metrics(tcxt: TyCtxt<'_>, metrics_dir: &Path) {
|
||||
let output_filenames = tcxt.output_filenames(());
|
||||
let mut metrics_file_name = std::ffi::OsString::from("unstable_feature_usage_metrics-");
|
||||
let mut metrics_path = output_filenames.with_directory_and_extension(metrics_dir, "json");
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use rustc_ast::token::{self, Delimiter, IdentIsRaw, Lit, Token, TokenKind};
|
||||
use rustc_ast::tokenstream::{RefTokenTreeCursor, TokenStream, TokenTree};
|
||||
use rustc_ast::tokenstream::{TokenStream, TokenStreamIter, TokenTree};
|
||||
use rustc_ast::{LitIntType, LitKind};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_errors::{Applicability, PResult};
|
||||
|
|
@ -38,14 +38,14 @@ impl MetaVarExpr {
|
|||
outer_span: Span,
|
||||
psess: &'psess ParseSess,
|
||||
) -> PResult<'psess, MetaVarExpr> {
|
||||
let mut tts = input.trees();
|
||||
let ident = parse_ident(&mut tts, psess, outer_span)?;
|
||||
let Some(TokenTree::Delimited(.., Delimiter::Parenthesis, args)) = tts.next() else {
|
||||
let mut iter = input.iter();
|
||||
let ident = parse_ident(&mut iter, psess, outer_span)?;
|
||||
let Some(TokenTree::Delimited(.., Delimiter::Parenthesis, args)) = iter.next() else {
|
||||
let msg = "meta-variable expression parameter must be wrapped in parentheses";
|
||||
return Err(psess.dcx().struct_span_err(ident.span, msg));
|
||||
};
|
||||
check_trailing_token(&mut tts, psess)?;
|
||||
let mut iter = args.trees();
|
||||
check_trailing_token(&mut iter, psess)?;
|
||||
let mut iter = args.iter();
|
||||
let rslt = match ident.as_str() {
|
||||
"concat" => {
|
||||
let mut result = Vec::new();
|
||||
|
|
@ -73,7 +73,7 @@ impl MetaVarExpr {
|
|||
}
|
||||
};
|
||||
result.push(element);
|
||||
if iter.look_ahead(0).is_none() {
|
||||
if iter.peek().is_none() {
|
||||
break;
|
||||
}
|
||||
if !try_eat_comma(&mut iter) {
|
||||
|
|
@ -142,7 +142,7 @@ pub(crate) enum MetaVarExprConcatElem {
|
|||
|
||||
// Checks if there are any remaining tokens. For example, `${ignore(ident ... a b c ...)}`
|
||||
fn check_trailing_token<'psess>(
|
||||
iter: &mut RefTokenTreeCursor<'_>,
|
||||
iter: &mut TokenStreamIter<'_>,
|
||||
psess: &'psess ParseSess,
|
||||
) -> PResult<'psess, ()> {
|
||||
if let Some(tt) = iter.next() {
|
||||
|
|
@ -158,14 +158,14 @@ fn check_trailing_token<'psess>(
|
|||
|
||||
/// Parse a meta-variable `count` expression: `count(ident[, depth])`
|
||||
fn parse_count<'psess>(
|
||||
iter: &mut RefTokenTreeCursor<'_>,
|
||||
iter: &mut TokenStreamIter<'_>,
|
||||
psess: &'psess ParseSess,
|
||||
span: Span,
|
||||
) -> PResult<'psess, MetaVarExpr> {
|
||||
eat_dollar(iter, psess, span)?;
|
||||
let ident = parse_ident(iter, psess, span)?;
|
||||
let depth = if try_eat_comma(iter) {
|
||||
if iter.look_ahead(0).is_none() {
|
||||
if iter.peek().is_none() {
|
||||
return Err(psess.dcx().struct_span_err(
|
||||
span,
|
||||
"`count` followed by a comma must have an associated index indicating its depth",
|
||||
|
|
@ -180,7 +180,7 @@ fn parse_count<'psess>(
|
|||
|
||||
/// Parses the depth used by index(depth) and len(depth).
|
||||
fn parse_depth<'psess>(
|
||||
iter: &mut RefTokenTreeCursor<'_>,
|
||||
iter: &mut TokenStreamIter<'_>,
|
||||
psess: &'psess ParseSess,
|
||||
span: Span,
|
||||
) -> PResult<'psess, usize> {
|
||||
|
|
@ -203,7 +203,7 @@ fn parse_depth<'psess>(
|
|||
|
||||
/// Parses an generic ident
|
||||
fn parse_ident<'psess>(
|
||||
iter: &mut RefTokenTreeCursor<'_>,
|
||||
iter: &mut TokenStreamIter<'_>,
|
||||
psess: &'psess ParseSess,
|
||||
fallback_span: Span,
|
||||
) -> PResult<'psess, Ident> {
|
||||
|
|
@ -235,7 +235,7 @@ fn parse_ident_from_token<'psess>(
|
|||
}
|
||||
|
||||
fn parse_token<'psess, 't>(
|
||||
iter: &mut RefTokenTreeCursor<'t>,
|
||||
iter: &mut TokenStreamIter<'t>,
|
||||
psess: &'psess ParseSess,
|
||||
fallback_span: Span,
|
||||
) -> PResult<'psess, &'t Token> {
|
||||
|
|
@ -250,8 +250,8 @@ fn parse_token<'psess, 't>(
|
|||
|
||||
/// Tries to move the iterator forward returning `true` if there is a comma. If not, then the
|
||||
/// iterator is not modified and the result is `false`.
|
||||
fn try_eat_comma(iter: &mut RefTokenTreeCursor<'_>) -> bool {
|
||||
if let Some(TokenTree::Token(Token { kind: token::Comma, .. }, _)) = iter.look_ahead(0) {
|
||||
fn try_eat_comma(iter: &mut TokenStreamIter<'_>) -> bool {
|
||||
if let Some(TokenTree::Token(Token { kind: token::Comma, .. }, _)) = iter.peek() {
|
||||
let _ = iter.next();
|
||||
return true;
|
||||
}
|
||||
|
|
@ -260,8 +260,8 @@ fn try_eat_comma(iter: &mut RefTokenTreeCursor<'_>) -> bool {
|
|||
|
||||
/// Tries to move the iterator forward returning `true` if there is a dollar sign. If not, then the
|
||||
/// iterator is not modified and the result is `false`.
|
||||
fn try_eat_dollar(iter: &mut RefTokenTreeCursor<'_>) -> bool {
|
||||
if let Some(TokenTree::Token(Token { kind: token::Dollar, .. }, _)) = iter.look_ahead(0) {
|
||||
fn try_eat_dollar(iter: &mut TokenStreamIter<'_>) -> bool {
|
||||
if let Some(TokenTree::Token(Token { kind: token::Dollar, .. }, _)) = iter.peek() {
|
||||
let _ = iter.next();
|
||||
return true;
|
||||
}
|
||||
|
|
@ -270,12 +270,11 @@ fn try_eat_dollar(iter: &mut RefTokenTreeCursor<'_>) -> bool {
|
|||
|
||||
/// Expects that the next item is a dollar sign.
|
||||
fn eat_dollar<'psess>(
|
||||
iter: &mut RefTokenTreeCursor<'_>,
|
||||
iter: &mut TokenStreamIter<'_>,
|
||||
psess: &'psess ParseSess,
|
||||
span: Span,
|
||||
) -> PResult<'psess, ()> {
|
||||
if let Some(TokenTree::Token(Token { kind: token::Dollar, .. }, _)) = iter.look_ahead(0) {
|
||||
let _ = iter.next();
|
||||
if try_eat_dollar(iter) {
|
||||
return Ok(());
|
||||
}
|
||||
Err(psess.dcx().struct_span_err(
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use rustc_ast::token::{self, Delimiter, IdentIsRaw, NonterminalKind, Token};
|
||||
use rustc_ast::tokenstream::TokenStreamIter;
|
||||
use rustc_ast::{NodeId, tokenstream};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_feature::Features;
|
||||
|
|
@ -48,25 +49,25 @@ pub(super) fn parse(
|
|||
|
||||
// For each token tree in `input`, parse the token into a `self::TokenTree`, consuming
|
||||
// additional trees if need be.
|
||||
let mut trees = input.trees().peekable();
|
||||
while let Some(tree) = trees.next() {
|
||||
let mut iter = input.iter();
|
||||
while let Some(tree) = iter.next() {
|
||||
// Given the parsed tree, if there is a metavar and we are expecting matchers, actually
|
||||
// parse out the matcher (i.e., in `$id:ident` this would parse the `:` and `ident`).
|
||||
let tree = parse_tree(tree, &mut trees, parsing_patterns, sess, node_id, features, edition);
|
||||
let tree = parse_tree(tree, &mut iter, parsing_patterns, sess, node_id, features, edition);
|
||||
match tree {
|
||||
TokenTree::MetaVar(start_sp, ident) if parsing_patterns => {
|
||||
// Not consuming the next token immediately, as it may not be a colon
|
||||
let span = match trees.peek() {
|
||||
let span = match iter.peek() {
|
||||
Some(&tokenstream::TokenTree::Token(
|
||||
Token { kind: token::Colon, span: colon_span },
|
||||
_,
|
||||
)) => {
|
||||
// Consume the colon first
|
||||
trees.next();
|
||||
iter.next();
|
||||
|
||||
// It's ok to consume the next tree no matter how,
|
||||
// since if it's not a token then it will be an invalid declaration.
|
||||
match trees.next() {
|
||||
match iter.next() {
|
||||
Some(tokenstream::TokenTree::Token(token, _)) => match token.ident() {
|
||||
Some((fragment, _)) => {
|
||||
let span = token.span.with_lo(start_sp.lo());
|
||||
|
|
@ -142,14 +143,14 @@ fn maybe_emit_macro_metavar_expr_concat_feature(features: &Features, sess: &Sess
|
|||
/// # Parameters
|
||||
///
|
||||
/// - `tree`: the tree we wish to convert.
|
||||
/// - `outer_trees`: an iterator over trees. We may need to read more tokens from it in order to finish
|
||||
/// - `outer_iter`: an iterator over trees. We may need to read more tokens from it in order to finish
|
||||
/// converting `tree`
|
||||
/// - `parsing_patterns`: same as [parse].
|
||||
/// - `sess`: the parsing session. Any errors will be emitted to this session.
|
||||
/// - `features`: language features so we can do feature gating.
|
||||
fn parse_tree<'a>(
|
||||
tree: &'a tokenstream::TokenTree,
|
||||
outer_trees: &mut impl Iterator<Item = &'a tokenstream::TokenTree>,
|
||||
outer_iter: &mut TokenStreamIter<'a>,
|
||||
parsing_patterns: bool,
|
||||
sess: &Session,
|
||||
node_id: NodeId,
|
||||
|
|
@ -162,15 +163,16 @@ fn parse_tree<'a>(
|
|||
&tokenstream::TokenTree::Token(Token { kind: token::Dollar, span: dollar_span }, _) => {
|
||||
// FIXME: Handle `Invisible`-delimited groups in a more systematic way
|
||||
// during parsing.
|
||||
let mut next = outer_trees.next();
|
||||
let mut trees: Box<dyn Iterator<Item = &tokenstream::TokenTree>>;
|
||||
match next {
|
||||
let mut next = outer_iter.next();
|
||||
let mut iter_storage;
|
||||
let mut iter: &mut TokenStreamIter<'_> = match next {
|
||||
Some(tokenstream::TokenTree::Delimited(.., delim, tts)) if delim.skip() => {
|
||||
trees = Box::new(tts.trees());
|
||||
next = trees.next();
|
||||
iter_storage = tts.iter();
|
||||
next = iter_storage.next();
|
||||
&mut iter_storage
|
||||
}
|
||||
_ => trees = Box::new(outer_trees),
|
||||
}
|
||||
_ => outer_iter,
|
||||
};
|
||||
|
||||
match next {
|
||||
// `tree` is followed by a delimited set of token trees.
|
||||
|
|
@ -229,7 +231,7 @@ fn parse_tree<'a>(
|
|||
let sequence = parse(tts, parsing_patterns, sess, node_id, features, edition);
|
||||
// Get the Kleene operator and optional separator
|
||||
let (separator, kleene) =
|
||||
parse_sep_and_kleene_op(&mut trees, delim_span.entire(), sess);
|
||||
parse_sep_and_kleene_op(&mut iter, delim_span.entire(), sess);
|
||||
// Count the number of captured "names" (i.e., named metavars)
|
||||
let num_captures =
|
||||
if parsing_patterns { count_metavar_decls(&sequence) } else { 0 };
|
||||
|
|
@ -312,11 +314,11 @@ fn kleene_op(token: &Token) -> Option<KleeneOp> {
|
|||
/// - Ok(Ok((op, span))) if the next token tree is a KleeneOp
|
||||
/// - Ok(Err(tok, span)) if the next token tree is a token but not a KleeneOp
|
||||
/// - Err(span) if the next token tree is not a token
|
||||
fn parse_kleene_op<'a>(
|
||||
input: &mut impl Iterator<Item = &'a tokenstream::TokenTree>,
|
||||
fn parse_kleene_op(
|
||||
iter: &mut TokenStreamIter<'_>,
|
||||
span: Span,
|
||||
) -> Result<Result<(KleeneOp, Span), Token>, Span> {
|
||||
match input.next() {
|
||||
match iter.next() {
|
||||
Some(tokenstream::TokenTree::Token(token, _)) => match kleene_op(token) {
|
||||
Some(op) => Ok(Ok((op, token.span))),
|
||||
None => Ok(Err(token.clone())),
|
||||
|
|
@ -333,22 +335,22 @@ fn parse_kleene_op<'a>(
|
|||
/// itself. Note that here we are parsing the _macro_ itself, rather than trying to match some
|
||||
/// stream of tokens in an invocation of a macro.
|
||||
///
|
||||
/// This function will take some input iterator `input` corresponding to `span` and a parsing
|
||||
/// session `sess`. If the next one (or possibly two) tokens in `input` correspond to a Kleene
|
||||
/// This function will take some input iterator `iter` corresponding to `span` and a parsing
|
||||
/// session `sess`. If the next one (or possibly two) tokens in `iter` correspond to a Kleene
|
||||
/// operator and separator, then a tuple with `(separator, KleeneOp)` is returned. Otherwise, an
|
||||
/// error with the appropriate span is emitted to `sess` and a dummy value is returned.
|
||||
fn parse_sep_and_kleene_op<'a>(
|
||||
input: &mut impl Iterator<Item = &'a tokenstream::TokenTree>,
|
||||
fn parse_sep_and_kleene_op(
|
||||
iter: &mut TokenStreamIter<'_>,
|
||||
span: Span,
|
||||
sess: &Session,
|
||||
) -> (Option<Token>, KleeneToken) {
|
||||
// We basically look at two token trees here, denoted as #1 and #2 below
|
||||
let span = match parse_kleene_op(input, span) {
|
||||
let span = match parse_kleene_op(iter, span) {
|
||||
// #1 is a `?`, `+`, or `*` KleeneOp
|
||||
Ok(Ok((op, span))) => return (None, KleeneToken::new(op, span)),
|
||||
|
||||
// #1 is a separator followed by #2, a KleeneOp
|
||||
Ok(Err(token)) => match parse_kleene_op(input, token.span) {
|
||||
Ok(Err(token)) => match parse_kleene_op(iter, token.span) {
|
||||
// #2 is the `?` Kleene op, which does not take a separator (error)
|
||||
Ok(Ok((KleeneOp::ZeroOrOne, span))) => {
|
||||
// Error!
|
||||
|
|
|
|||
|
|
@ -111,9 +111,9 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
|
|||
// Estimate the capacity as `stream.len()` rounded up to the next power
|
||||
// of two to limit the number of required reallocations.
|
||||
let mut trees = Vec::with_capacity(stream.len().next_power_of_two());
|
||||
let mut cursor = stream.trees();
|
||||
let mut iter = stream.iter();
|
||||
|
||||
while let Some(tree) = cursor.next() {
|
||||
while let Some(tree) = iter.next() {
|
||||
let (Token { kind, span }, joint) = match tree.clone() {
|
||||
tokenstream::TokenTree::Delimited(span, _, delim, tts) => {
|
||||
let delimiter = pm::Delimiter::from_internal(delim);
|
||||
|
|
|
|||
|
|
@ -371,10 +371,9 @@ pub(super) fn explicit_item_bounds_with_filter(
|
|||
associated_type_bounds(tcx, def_id, opaque_ty.bounds, opaque_ty.span, filter);
|
||||
return ty::EarlyBinder::bind(bounds);
|
||||
}
|
||||
Some(ty::ImplTraitInTraitData::Impl { .. }) => span_bug!(
|
||||
tcx.def_span(def_id),
|
||||
"item bounds for RPITIT in impl to be fed on def-id creation"
|
||||
),
|
||||
Some(ty::ImplTraitInTraitData::Impl { .. }) => {
|
||||
span_bug!(tcx.def_span(def_id), "RPITIT in impl should not have item bounds")
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -956,6 +956,15 @@ pub(super) fn const_conditions<'tcx>(
|
|||
bug!("const_conditions invoked for item that is not conditionally const: {def_id:?}");
|
||||
}
|
||||
|
||||
match tcx.opt_rpitit_info(def_id.to_def_id()) {
|
||||
// RPITITs inherit const conditions of their parent fn
|
||||
Some(
|
||||
ty::ImplTraitInTraitData::Impl { fn_def_id }
|
||||
| ty::ImplTraitInTraitData::Trait { fn_def_id, .. },
|
||||
) => return tcx.const_conditions(fn_def_id),
|
||||
None => {}
|
||||
}
|
||||
|
||||
let (generics, trait_def_id_and_supertraits, has_parent) = match tcx.hir_node_by_def_id(def_id)
|
||||
{
|
||||
Node::Item(item) => match item.kind {
|
||||
|
|
@ -1059,19 +1068,29 @@ pub(super) fn explicit_implied_const_bounds<'tcx>(
|
|||
bug!("const_conditions invoked for item that is not conditionally const: {def_id:?}");
|
||||
}
|
||||
|
||||
let bounds = match tcx.hir_node_by_def_id(def_id) {
|
||||
Node::Item(hir::Item { kind: hir::ItemKind::Trait(..), .. }) => {
|
||||
implied_predicates_with_filter(
|
||||
tcx,
|
||||
def_id.to_def_id(),
|
||||
PredicateFilter::SelfConstIfConst,
|
||||
)
|
||||
}
|
||||
Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(..), .. })
|
||||
| Node::OpaqueTy(_) => {
|
||||
let bounds = match tcx.opt_rpitit_info(def_id.to_def_id()) {
|
||||
// RPITIT's bounds are the same as opaque type bounds, but with
|
||||
// a projection self type.
|
||||
Some(ty::ImplTraitInTraitData::Trait { .. }) => {
|
||||
explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::ConstIfConst)
|
||||
}
|
||||
_ => bug!("explicit_implied_const_bounds called on wrong item: {def_id:?}"),
|
||||
Some(ty::ImplTraitInTraitData::Impl { .. }) => {
|
||||
span_bug!(tcx.def_span(def_id), "RPITIT in impl should not have item bounds")
|
||||
}
|
||||
None => match tcx.hir_node_by_def_id(def_id) {
|
||||
Node::Item(hir::Item { kind: hir::ItemKind::Trait(..), .. }) => {
|
||||
implied_predicates_with_filter(
|
||||
tcx,
|
||||
def_id.to_def_id(),
|
||||
PredicateFilter::SelfConstIfConst,
|
||||
)
|
||||
}
|
||||
Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(..), .. })
|
||||
| Node::OpaqueTy(_) => {
|
||||
explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::ConstIfConst)
|
||||
}
|
||||
_ => bug!("explicit_implied_const_bounds called on wrong item: {def_id:?}"),
|
||||
},
|
||||
};
|
||||
|
||||
bounds.map_bound(|bounds| {
|
||||
|
|
|
|||
|
|
@ -717,12 +717,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
BindingMode(def_br, Mutability::Mut)
|
||||
} else {
|
||||
// `mut` resets the binding mode on edition <= 2021
|
||||
*self
|
||||
.typeck_results
|
||||
.borrow_mut()
|
||||
.rust_2024_migration_desugared_pats_mut()
|
||||
.entry(pat_info.top_info.hir_id)
|
||||
.or_default() |= pat.span.at_least_rust_2024();
|
||||
self.add_rust_2024_migration_desugared_pat(
|
||||
pat_info.top_info.hir_id,
|
||||
pat.span,
|
||||
ident.span,
|
||||
"requires binding by-value, but the implicit default is by-reference",
|
||||
);
|
||||
BindingMode(ByRef::No, Mutability::Mut)
|
||||
}
|
||||
}
|
||||
|
|
@ -730,12 +730,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
BindingMode(ByRef::Yes(_), _) => {
|
||||
if matches!(def_br, ByRef::Yes(_)) {
|
||||
// `ref`/`ref mut` overrides the binding mode on edition <= 2021
|
||||
*self
|
||||
.typeck_results
|
||||
.borrow_mut()
|
||||
.rust_2024_migration_desugared_pats_mut()
|
||||
.entry(pat_info.top_info.hir_id)
|
||||
.or_default() |= pat.span.at_least_rust_2024();
|
||||
self.add_rust_2024_migration_desugared_pat(
|
||||
pat_info.top_info.hir_id,
|
||||
pat.span,
|
||||
ident.span,
|
||||
"cannot override to bind by-reference when that is the implicit default",
|
||||
);
|
||||
}
|
||||
user_bind_annot
|
||||
}
|
||||
|
|
@ -2265,12 +2265,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// Reset binding mode on old editions
|
||||
if pat_info.binding_mode != ByRef::No {
|
||||
pat_info.binding_mode = ByRef::No;
|
||||
*self
|
||||
.typeck_results
|
||||
.borrow_mut()
|
||||
.rust_2024_migration_desugared_pats_mut()
|
||||
.entry(pat_info.top_info.hir_id)
|
||||
.or_default() |= pat.span.at_least_rust_2024();
|
||||
self.add_rust_2024_migration_desugared_pat(
|
||||
pat_info.top_info.hir_id,
|
||||
pat.span,
|
||||
inner.span,
|
||||
"cannot implicitly match against multiple layers of reference",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2629,4 +2629,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
_ => (false, ty),
|
||||
}
|
||||
}
|
||||
|
||||
/// Record a pattern that's invalid under Rust 2024 match ergonomics, along with a problematic
|
||||
/// span, so that the pattern migration lint can desugar it during THIR construction.
|
||||
fn add_rust_2024_migration_desugared_pat(
|
||||
&self,
|
||||
pat_id: HirId,
|
||||
subpat_span: Span,
|
||||
cutoff_span: Span,
|
||||
detailed_label: &str,
|
||||
) {
|
||||
// Try to trim the span we're labeling to just the `&` or binding mode that's an issue.
|
||||
// If the subpattern's span is is from an expansion, the emitted label will not be trimmed.
|
||||
let source_map = self.tcx.sess.source_map();
|
||||
let cutoff_span = source_map
|
||||
.span_extend_prev_while(cutoff_span, char::is_whitespace)
|
||||
.unwrap_or(cutoff_span);
|
||||
// Ensure we use the syntax context and thus edition of `subpat_span`; this will be a hard
|
||||
// error if the subpattern is of edition >= 2024.
|
||||
let trimmed_span = subpat_span.until(cutoff_span).with_ctxt(subpat_span.ctxt());
|
||||
|
||||
// Only provide a detailed label if the problematic subpattern isn't from an expansion.
|
||||
// In the case that it's from a macro, we'll add a more detailed note in the emitter.
|
||||
let desc = if subpat_span.from_expansion() {
|
||||
"default binding mode is reset within expansion"
|
||||
} else {
|
||||
detailed_label
|
||||
};
|
||||
|
||||
self.typeck_results
|
||||
.borrow_mut()
|
||||
.rust_2024_migration_desugared_pats_mut()
|
||||
.entry(pat_id)
|
||||
.or_default()
|
||||
.push((trimmed_span, desc.to_owned()));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1828,7 +1828,7 @@ impl KeywordIdents {
|
|||
fn check_tokens(&mut self, cx: &EarlyContext<'_>, tokens: &TokenStream) {
|
||||
// Check if the preceding token is `$`, because we want to allow `$async`, etc.
|
||||
let mut prev_dollar = false;
|
||||
for tt in tokens.trees() {
|
||||
for tt in tokens.iter() {
|
||||
match tt {
|
||||
// Only report non-raw idents.
|
||||
TokenTree::Token(token, _) => {
|
||||
|
|
|
|||
|
|
@ -170,27 +170,11 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
|
|||
| PatKind::TupleStruct(qpath, ..)
|
||||
| PatKind::Struct(qpath, ..),
|
||||
..
|
||||
}) => {
|
||||
if let QPath::TypeRelative(qpath_ty, ..) = qpath
|
||||
&& qpath_ty.hir_id == ty.hir_id
|
||||
{
|
||||
Some(path.span)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Node::Expr(Expr { kind: ExprKind::Path(qpath), .. }) => {
|
||||
if let QPath::TypeRelative(qpath_ty, ..) = qpath
|
||||
&& qpath_ty.hir_id == ty.hir_id
|
||||
{
|
||||
Some(path.span)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
// Can't unify these two branches because qpath below is `&&` and above is `&`
|
||||
// and `A | B` paths don't play well together with adjustments, apparently.
|
||||
Node::Expr(Expr { kind: ExprKind::Struct(qpath, ..), .. }) => {
|
||||
})
|
||||
| Node::Expr(
|
||||
Expr { kind: ExprKind::Path(qpath), .. }
|
||||
| &Expr { kind: ExprKind::Struct(qpath, ..), .. },
|
||||
) => {
|
||||
if let QPath::TypeRelative(qpath_ty, ..) = qpath
|
||||
&& qpath_ty.hir_id == ty.hir_id
|
||||
{
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ impl Expr2024 {
|
|||
let mut prev_colon = false;
|
||||
let mut prev_identifier = false;
|
||||
let mut prev_dollar = false;
|
||||
for tt in tokens.trees() {
|
||||
for tt in tokens.iter() {
|
||||
debug!(
|
||||
"check_tokens: {:?} - colon {prev_dollar} - ident {prev_identifier} - colon {prev_colon}",
|
||||
tt
|
||||
|
|
|
|||
|
|
@ -1348,8 +1348,8 @@ pub struct BasicBlockData<'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> BasicBlockData<'tcx> {
|
||||
pub fn new(terminator: Option<Terminator<'tcx>>) -> BasicBlockData<'tcx> {
|
||||
BasicBlockData { statements: vec![], terminator, is_cleanup: false }
|
||||
pub fn new(terminator: Option<Terminator<'tcx>>, is_cleanup: bool) -> BasicBlockData<'tcx> {
|
||||
BasicBlockData { statements: vec![], terminator, is_cleanup }
|
||||
}
|
||||
|
||||
/// Accessor for terminator.
|
||||
|
|
|
|||
|
|
@ -74,9 +74,8 @@ pub struct TypeckResults<'tcx> {
|
|||
pat_binding_modes: ItemLocalMap<BindingMode>,
|
||||
|
||||
/// Top-level patterns whose match ergonomics need to be desugared by the Rust 2021 -> 2024
|
||||
/// migration lint. The boolean indicates whether the emitted diagnostic should be a hard error
|
||||
/// (if any of the incompatible pattern elements are in edition 2024).
|
||||
rust_2024_migration_desugared_pats: ItemLocalMap<bool>,
|
||||
/// migration lint. Problematic subpatterns are stored in the `Vec` for the lint to highlight.
|
||||
rust_2024_migration_desugared_pats: ItemLocalMap<Vec<(Span, String)>>,
|
||||
|
||||
/// Stores the types which were implicitly dereferenced in pattern binding modes
|
||||
/// for later usage in THIR lowering. For example,
|
||||
|
|
@ -419,14 +418,18 @@ impl<'tcx> TypeckResults<'tcx> {
|
|||
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments }
|
||||
}
|
||||
|
||||
pub fn rust_2024_migration_desugared_pats(&self) -> LocalTableInContext<'_, bool> {
|
||||
pub fn rust_2024_migration_desugared_pats(
|
||||
&self,
|
||||
) -> LocalTableInContext<'_, Vec<(Span, String)>> {
|
||||
LocalTableInContext {
|
||||
hir_owner: self.hir_owner,
|
||||
data: &self.rust_2024_migration_desugared_pats,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rust_2024_migration_desugared_pats_mut(&mut self) -> LocalTableInContextMut<'_, bool> {
|
||||
pub fn rust_2024_migration_desugared_pats_mut(
|
||||
&mut self,
|
||||
) -> LocalTableInContextMut<'_, Vec<(Span, String)>> {
|
||||
LocalTableInContextMut {
|
||||
hir_owner: self.hir_owner,
|
||||
data: &mut self.rust_2024_migration_desugared_pats,
|
||||
|
|
|
|||
|
|
@ -285,7 +285,7 @@ mir_build_pointer_pattern = function pointers and raw pointers not derived from
|
|||
|
||||
mir_build_privately_uninhabited = pattern `{$witness_1}` is currently uninhabited, but this variant contains private fields which may become inhabited in the future
|
||||
|
||||
mir_build_rust_2024_incompatible_pat = patterns are not allowed to reset the default binding mode in edition 2024
|
||||
mir_build_rust_2024_incompatible_pat = this pattern relies on behavior which may change in edition 2024
|
||||
|
||||
mir_build_rustc_box_attribute_error = `#[rustc_box]` attribute used incorrectly
|
||||
.attributes = no other attributes may be applied
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ impl<'tcx> CFG<'tcx> {
|
|||
// it as #[inline(never)] to keep rustc's stack use in check.
|
||||
#[inline(never)]
|
||||
pub(crate) fn start_new_block(&mut self) -> BasicBlock {
|
||||
self.basic_blocks.push(BasicBlockData::new(None))
|
||||
self.basic_blocks.push(BasicBlockData::new(None, false))
|
||||
}
|
||||
|
||||
pub(crate) fn start_new_cleanup_block(&mut self) -> BasicBlock {
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ pub(super) fn build_custom_mir<'tcx>(
|
|||
};
|
||||
|
||||
body.local_decls.push(LocalDecl::new(return_ty, return_ty_span));
|
||||
body.basic_blocks_mut().push(BasicBlockData::new(None));
|
||||
body.basic_blocks_mut().push(BasicBlockData::new(None, false));
|
||||
body.source_scopes.push(SourceScopeData {
|
||||
span,
|
||||
parent_scope: None,
|
||||
|
|
|
|||
|
|
@ -199,10 +199,12 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
|
|||
match &self.thir[stmt].kind {
|
||||
StmtKind::Let { pattern, initializer: Some(initializer), .. } => {
|
||||
let (var, ..) = self.parse_var(pattern)?;
|
||||
let mut data = BasicBlockData::new(None);
|
||||
data.is_cleanup = parse_by_kind!(self, *initializer, _, "basic block declaration",
|
||||
@variant(mir_basic_block, Normal) => false,
|
||||
@variant(mir_basic_block, Cleanup) => true,
|
||||
let data = BasicBlockData::new(
|
||||
None,
|
||||
parse_by_kind!(self, *initializer, _, "basic block declaration",
|
||||
@variant(mir_basic_block, Normal) => false,
|
||||
@variant(mir_basic_block, Cleanup) => true,
|
||||
),
|
||||
);
|
||||
let block = self.body.basic_blocks_mut().push(data);
|
||||
self.block_map.insert(var, block);
|
||||
|
|
@ -308,8 +310,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
|
|||
ExprKind::Block { block } => &self.thir[*block],
|
||||
);
|
||||
|
||||
let mut data = BasicBlockData::new(None);
|
||||
data.is_cleanup = is_cleanup;
|
||||
let mut data = BasicBlockData::new(None, is_cleanup);
|
||||
for stmt_id in &*block.stmts {
|
||||
let stmt = self.statement_as_expr(*stmt_id)?;
|
||||
let span = self.thir[stmt].span;
|
||||
|
|
|
|||
|
|
@ -56,10 +56,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
pub(crate) fn consume_by_copy_or_move(&self, place: Place<'tcx>) -> Operand<'tcx> {
|
||||
let tcx = self.tcx;
|
||||
let ty = place.ty(&self.local_decls, tcx).ty;
|
||||
if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty) {
|
||||
Operand::Move(place)
|
||||
} else {
|
||||
if self.infcx.type_is_copy_modulo_regions(self.param_env, ty) {
|
||||
Operand::Copy(place)
|
||||
} else {
|
||||
Operand::Move(place)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level,
|
||||
MultiSpan, SubdiagMessageOp, Subdiagnostic,
|
||||
MultiSpan, SubdiagMessageOp, Subdiagnostic, pluralize,
|
||||
};
|
||||
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
|
|
@ -1088,18 +1088,20 @@ pub(crate) enum RustcBoxAttrReason {
|
|||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_rust_2024_incompatible_pat)]
|
||||
pub(crate) struct Rust2024IncompatiblePat {
|
||||
pub(crate) struct Rust2024IncompatiblePat<'a> {
|
||||
#[subdiagnostic]
|
||||
pub(crate) sugg: Rust2024IncompatiblePatSugg,
|
||||
pub(crate) sugg: Rust2024IncompatiblePatSugg<'a>,
|
||||
}
|
||||
|
||||
pub(crate) struct Rust2024IncompatiblePatSugg {
|
||||
pub(crate) struct Rust2024IncompatiblePatSugg<'a> {
|
||||
pub(crate) suggestion: Vec<(Span, String)>,
|
||||
/// Whether the incompatibility is a hard error because a relevant span is in edition 2024.
|
||||
pub(crate) is_hard_error: bool,
|
||||
pub(crate) ref_pattern_count: usize,
|
||||
pub(crate) binding_mode_count: usize,
|
||||
/// Labeled spans for subpatterns invalid in Rust 2024.
|
||||
pub(crate) labels: &'a [(Span, String)],
|
||||
}
|
||||
|
||||
impl Subdiagnostic for Rust2024IncompatiblePatSugg {
|
||||
impl<'a> Subdiagnostic for Rust2024IncompatiblePatSugg<'a> {
|
||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
|
|
@ -1111,6 +1113,16 @@ impl Subdiagnostic for Rust2024IncompatiblePatSugg {
|
|||
} else {
|
||||
Applicability::MaybeIncorrect
|
||||
};
|
||||
diag.multipart_suggestion("desugar the match ergonomics", self.suggestion, applicability);
|
||||
let plural_derefs = pluralize!(self.ref_pattern_count);
|
||||
let and_modes = if self.binding_mode_count > 0 {
|
||||
format!(" and variable binding mode{}", pluralize!(self.binding_mode_count))
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
diag.multipart_suggestion_verbose(
|
||||
format!("make the implied reference pattern{plural_derefs}{and_modes} explicit"),
|
||||
self.suggestion,
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ mod const_to_pat;
|
|||
use std::cmp::Ordering;
|
||||
|
||||
use rustc_abi::{FieldIdx, Integer};
|
||||
use rustc_errors::MultiSpan;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_hir::def::{CtorOf, DefKind, Res};
|
||||
use rustc_hir::pat_util::EnumerateAndAdjustIterator;
|
||||
|
|
@ -34,7 +35,7 @@ struct PatCtxt<'a, 'tcx> {
|
|||
typeck_results: &'a ty::TypeckResults<'tcx>,
|
||||
|
||||
/// Used by the Rust 2024 migration lint.
|
||||
rust_2024_migration_suggestion: Option<Rust2024IncompatiblePatSugg>,
|
||||
rust_2024_migration_suggestion: Option<Rust2024IncompatiblePatSugg<'a>>,
|
||||
}
|
||||
|
||||
pub(super) fn pat_from_hir<'a, 'tcx>(
|
||||
|
|
@ -50,24 +51,36 @@ pub(super) fn pat_from_hir<'a, 'tcx>(
|
|||
rust_2024_migration_suggestion: typeck_results
|
||||
.rust_2024_migration_desugared_pats()
|
||||
.get(pat.hir_id)
|
||||
.map(|&is_hard_error| Rust2024IncompatiblePatSugg {
|
||||
.map(|labels| Rust2024IncompatiblePatSugg {
|
||||
suggestion: Vec::new(),
|
||||
is_hard_error,
|
||||
ref_pattern_count: 0,
|
||||
binding_mode_count: 0,
|
||||
labels: labels.as_slice(),
|
||||
}),
|
||||
};
|
||||
let result = pcx.lower_pattern(pat);
|
||||
debug!("pat_from_hir({:?}) = {:?}", pat, result);
|
||||
if let Some(sugg) = pcx.rust_2024_migration_suggestion {
|
||||
if sugg.is_hard_error {
|
||||
let mut spans = MultiSpan::from_spans(sugg.labels.iter().map(|(span, _)| *span).collect());
|
||||
for (span, label) in sugg.labels {
|
||||
spans.push_span_label(*span, label.clone());
|
||||
}
|
||||
// If a relevant span is from at least edition 2024, this is a hard error.
|
||||
let is_hard_error = spans.primary_spans().iter().any(|span| span.at_least_rust_2024());
|
||||
if is_hard_error {
|
||||
let mut err =
|
||||
tcx.dcx().struct_span_err(pat.span, fluent::mir_build_rust_2024_incompatible_pat);
|
||||
tcx.dcx().struct_span_err(spans, fluent::mir_build_rust_2024_incompatible_pat);
|
||||
if let Some(info) = lint::builtin::RUST_2024_INCOMPATIBLE_PAT.future_incompatible {
|
||||
// provide the same reference link as the lint
|
||||
err.note(format!("for more information, see {}", info.reference));
|
||||
}
|
||||
err.subdiagnostic(sugg);
|
||||
err.emit();
|
||||
} else {
|
||||
tcx.emit_node_span_lint(
|
||||
lint::builtin::RUST_2024_INCOMPATIBLE_PAT,
|
||||
pat.hir_id,
|
||||
pat.span,
|
||||
spans,
|
||||
Rust2024IncompatiblePat { sugg },
|
||||
);
|
||||
}
|
||||
|
|
@ -133,6 +146,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
})
|
||||
.collect();
|
||||
s.suggestion.push((pat.span.shrink_to_lo(), suggestion_str));
|
||||
s.ref_pattern_count += adjustments.len();
|
||||
};
|
||||
|
||||
adjusted_pat
|
||||
|
|
@ -371,7 +385,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
s.suggestion.push((
|
||||
pat.span.with_lo(ident.span.lo()).shrink_to_lo(),
|
||||
sugg_str.to_owned(),
|
||||
))
|
||||
));
|
||||
s.binding_mode_count += 1;
|
||||
}
|
||||
|
||||
// A ref x pattern is the same node used for x, and as such it has
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ where
|
|||
{
|
||||
fn visit_block_start(&mut self, _state: &A::Domain) {}
|
||||
|
||||
/// // njn: grep for "before", "primary", etc.
|
||||
/// Called after the "early" effect of the given statement is applied to `state`.
|
||||
fn visit_after_early_statement_effect(
|
||||
&mut self,
|
||||
|
|
|
|||
|
|
@ -129,18 +129,29 @@ impl<'tcx> crate::MirPass<'tcx> for EarlyOtherwiseBranch {
|
|||
|
||||
let mut patch = MirPatch::new(body);
|
||||
|
||||
// create temp to store second discriminant in, `_s` in example above
|
||||
let second_discriminant_temp =
|
||||
patch.new_temp(opt_data.child_ty, opt_data.child_source.span);
|
||||
let (second_discriminant_temp, second_operand) = if opt_data.need_hoist_discriminant {
|
||||
// create temp to store second discriminant in, `_s` in example above
|
||||
let second_discriminant_temp =
|
||||
patch.new_temp(opt_data.child_ty, opt_data.child_source.span);
|
||||
|
||||
patch.add_statement(parent_end, StatementKind::StorageLive(second_discriminant_temp));
|
||||
patch.add_statement(
|
||||
parent_end,
|
||||
StatementKind::StorageLive(second_discriminant_temp),
|
||||
);
|
||||
|
||||
// create assignment of discriminant
|
||||
patch.add_assign(
|
||||
parent_end,
|
||||
Place::from(second_discriminant_temp),
|
||||
Rvalue::Discriminant(opt_data.child_place),
|
||||
);
|
||||
// create assignment of discriminant
|
||||
patch.add_assign(
|
||||
parent_end,
|
||||
Place::from(second_discriminant_temp),
|
||||
Rvalue::Discriminant(opt_data.child_place),
|
||||
);
|
||||
(
|
||||
Some(second_discriminant_temp),
|
||||
Operand::Move(Place::from(second_discriminant_temp)),
|
||||
)
|
||||
} else {
|
||||
(None, Operand::Copy(opt_data.child_place))
|
||||
};
|
||||
|
||||
// create temp to store inequality comparison between the two discriminants, `_t` in
|
||||
// example above
|
||||
|
|
@ -149,11 +160,9 @@ impl<'tcx> crate::MirPass<'tcx> for EarlyOtherwiseBranch {
|
|||
let comp_temp = patch.new_temp(comp_res_type, opt_data.child_source.span);
|
||||
patch.add_statement(parent_end, StatementKind::StorageLive(comp_temp));
|
||||
|
||||
// create inequality comparison between the two discriminants
|
||||
let comp_rvalue = Rvalue::BinaryOp(
|
||||
nequal,
|
||||
Box::new((parent_op.clone(), Operand::Move(Place::from(second_discriminant_temp)))),
|
||||
);
|
||||
// create inequality comparison
|
||||
let comp_rvalue =
|
||||
Rvalue::BinaryOp(nequal, Box::new((parent_op.clone(), second_operand)));
|
||||
patch.add_statement(
|
||||
parent_end,
|
||||
StatementKind::Assign(Box::new((Place::from(comp_temp), comp_rvalue))),
|
||||
|
|
@ -170,14 +179,17 @@ impl<'tcx> crate::MirPass<'tcx> for EarlyOtherwiseBranch {
|
|||
let eq_targets = SwitchTargets::new(eq_new_targets, parent_targets.otherwise());
|
||||
|
||||
// Create `bbEq` in example above
|
||||
let eq_switch = BasicBlockData::new(Some(Terminator {
|
||||
source_info: bbs[parent].terminator().source_info,
|
||||
kind: TerminatorKind::SwitchInt {
|
||||
// switch on the first discriminant, so we can mark the second one as dead
|
||||
discr: parent_op,
|
||||
targets: eq_targets,
|
||||
},
|
||||
}));
|
||||
let eq_switch = BasicBlockData::new(
|
||||
Some(Terminator {
|
||||
source_info: bbs[parent].terminator().source_info,
|
||||
kind: TerminatorKind::SwitchInt {
|
||||
// switch on the first discriminant, so we can mark the second one as dead
|
||||
discr: parent_op,
|
||||
targets: eq_targets,
|
||||
},
|
||||
}),
|
||||
bbs[parent].is_cleanup,
|
||||
);
|
||||
|
||||
let eq_bb = patch.new_block(eq_switch);
|
||||
|
||||
|
|
@ -189,8 +201,13 @@ impl<'tcx> crate::MirPass<'tcx> for EarlyOtherwiseBranch {
|
|||
TerminatorKind::if_(Operand::Move(Place::from(comp_temp)), true_case, false_case),
|
||||
);
|
||||
|
||||
// generate StorageDead for the second_discriminant_temp not in use anymore
|
||||
patch.add_statement(parent_end, StatementKind::StorageDead(second_discriminant_temp));
|
||||
if let Some(second_discriminant_temp) = second_discriminant_temp {
|
||||
// generate StorageDead for the second_discriminant_temp not in use anymore
|
||||
patch.add_statement(
|
||||
parent_end,
|
||||
StatementKind::StorageDead(second_discriminant_temp),
|
||||
);
|
||||
}
|
||||
|
||||
// Generate a StorageDead for comp_temp in each of the targets, since we moved it into
|
||||
// the switch
|
||||
|
|
@ -218,6 +235,7 @@ struct OptimizationData<'tcx> {
|
|||
child_place: Place<'tcx>,
|
||||
child_ty: Ty<'tcx>,
|
||||
child_source: SourceInfo,
|
||||
need_hoist_discriminant: bool,
|
||||
}
|
||||
|
||||
fn evaluate_candidate<'tcx>(
|
||||
|
|
@ -226,49 +244,21 @@ fn evaluate_candidate<'tcx>(
|
|||
parent: BasicBlock,
|
||||
) -> Option<OptimizationData<'tcx>> {
|
||||
let bbs = &body.basic_blocks;
|
||||
// NB: If this BB is a cleanup, we may need to figure out what else needs to be handled.
|
||||
if bbs[parent].is_cleanup {
|
||||
return None;
|
||||
}
|
||||
let TerminatorKind::SwitchInt { targets, discr: parent_discr } = &bbs[parent].terminator().kind
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
let parent_ty = parent_discr.ty(body.local_decls(), tcx);
|
||||
if !bbs[targets.otherwise()].is_empty_unreachable() {
|
||||
// Someone could write code like this:
|
||||
// ```rust
|
||||
// let Q = val;
|
||||
// if discriminant(P) == otherwise {
|
||||
// let ptr = &mut Q as *mut _ as *mut u8;
|
||||
// // It may be difficult for us to effectively determine whether values are valid.
|
||||
// // Invalid values can come from all sorts of corners.
|
||||
// unsafe { *ptr = 10; }
|
||||
// }
|
||||
//
|
||||
// match P {
|
||||
// A => match Q {
|
||||
// A => {
|
||||
// // code
|
||||
// }
|
||||
// _ => {
|
||||
// // don't use Q
|
||||
// }
|
||||
// }
|
||||
// _ => {
|
||||
// // don't use Q
|
||||
// }
|
||||
// };
|
||||
// ```
|
||||
//
|
||||
// Hoisting the `discriminant(Q)` out of the `A` arm causes us to compute the discriminant
|
||||
// of an invalid value, which is UB.
|
||||
// In order to fix this, **we would either need to show that the discriminant computation of
|
||||
// `place` is computed in all branches**.
|
||||
// FIXME(#95162) For the moment, we adopt a conservative approach and
|
||||
// consider only the `otherwise` branch has no statements and an unreachable terminator.
|
||||
return None;
|
||||
}
|
||||
let (_, child) = targets.iter().next()?;
|
||||
let child_terminator = &bbs[child].terminator();
|
||||
let TerminatorKind::SwitchInt { targets: child_targets, discr: child_discr } =
|
||||
&child_terminator.kind
|
||||
|
||||
let Terminator {
|
||||
kind: TerminatorKind::SwitchInt { targets: child_targets, discr: child_discr },
|
||||
source_info,
|
||||
} = bbs[child].terminator()
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
|
|
@ -276,25 +266,115 @@ fn evaluate_candidate<'tcx>(
|
|||
if child_ty != parent_ty {
|
||||
return None;
|
||||
}
|
||||
let Some(StatementKind::Assign(boxed)) = &bbs[child].statements.first().map(|x| &x.kind) else {
|
||||
|
||||
// We only handle:
|
||||
// ```
|
||||
// bb4: {
|
||||
// _8 = discriminant((_3.1: Enum1));
|
||||
// switchInt(move _8) -> [2: bb7, otherwise: bb1];
|
||||
// }
|
||||
// ```
|
||||
// and
|
||||
// ```
|
||||
// bb2: {
|
||||
// switchInt((_3.1: u64)) -> [1: bb5, otherwise: bb1];
|
||||
// }
|
||||
// ```
|
||||
if bbs[child].statements.len() > 1 {
|
||||
return None;
|
||||
}
|
||||
|
||||
// When thie BB has exactly one statement, this statement should be discriminant.
|
||||
let need_hoist_discriminant = bbs[child].statements.len() == 1;
|
||||
let child_place = if need_hoist_discriminant {
|
||||
if !bbs[targets.otherwise()].is_empty_unreachable() {
|
||||
// Someone could write code like this:
|
||||
// ```rust
|
||||
// let Q = val;
|
||||
// if discriminant(P) == otherwise {
|
||||
// let ptr = &mut Q as *mut _ as *mut u8;
|
||||
// // It may be difficult for us to effectively determine whether values are valid.
|
||||
// // Invalid values can come from all sorts of corners.
|
||||
// unsafe { *ptr = 10; }
|
||||
// }
|
||||
//
|
||||
// match P {
|
||||
// A => match Q {
|
||||
// A => {
|
||||
// // code
|
||||
// }
|
||||
// _ => {
|
||||
// // don't use Q
|
||||
// }
|
||||
// }
|
||||
// _ => {
|
||||
// // don't use Q
|
||||
// }
|
||||
// };
|
||||
// ```
|
||||
//
|
||||
// Hoisting the `discriminant(Q)` out of the `A` arm causes us to compute the discriminant of an
|
||||
// invalid value, which is UB.
|
||||
// In order to fix this, **we would either need to show that the discriminant computation of
|
||||
// `place` is computed in all branches**.
|
||||
// FIXME(#95162) For the moment, we adopt a conservative approach and
|
||||
// consider only the `otherwise` branch has no statements and an unreachable terminator.
|
||||
return None;
|
||||
}
|
||||
// Handle:
|
||||
// ```
|
||||
// bb4: {
|
||||
// _8 = discriminant((_3.1: Enum1));
|
||||
// switchInt(move _8) -> [2: bb7, otherwise: bb1];
|
||||
// }
|
||||
// ```
|
||||
let [
|
||||
Statement {
|
||||
kind: StatementKind::Assign(box (_, Rvalue::Discriminant(child_place))),
|
||||
..
|
||||
},
|
||||
] = bbs[child].statements.as_slice()
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
*child_place
|
||||
} else {
|
||||
// Handle:
|
||||
// ```
|
||||
// bb2: {
|
||||
// switchInt((_3.1: u64)) -> [1: bb5, otherwise: bb1];
|
||||
// }
|
||||
// ```
|
||||
let Operand::Copy(child_place) = child_discr else {
|
||||
return None;
|
||||
};
|
||||
*child_place
|
||||
};
|
||||
let (_, Rvalue::Discriminant(child_place)) = &**boxed else {
|
||||
return None;
|
||||
let destination = if need_hoist_discriminant || bbs[targets.otherwise()].is_empty_unreachable()
|
||||
{
|
||||
child_targets.otherwise()
|
||||
} else {
|
||||
targets.otherwise()
|
||||
};
|
||||
let destination = child_targets.otherwise();
|
||||
|
||||
// Verify that the optimization is legal for each branch
|
||||
for (value, child) in targets.iter() {
|
||||
if !verify_candidate_branch(&bbs[child], value, *child_place, destination) {
|
||||
if !verify_candidate_branch(
|
||||
&bbs[child],
|
||||
value,
|
||||
child_place,
|
||||
destination,
|
||||
need_hoist_discriminant,
|
||||
) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
Some(OptimizationData {
|
||||
destination,
|
||||
child_place: *child_place,
|
||||
child_place,
|
||||
child_ty,
|
||||
child_source: child_terminator.source_info,
|
||||
child_source: *source_info,
|
||||
need_hoist_discriminant,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -303,31 +383,48 @@ fn verify_candidate_branch<'tcx>(
|
|||
value: u128,
|
||||
place: Place<'tcx>,
|
||||
destination: BasicBlock,
|
||||
need_hoist_discriminant: bool,
|
||||
) -> bool {
|
||||
// In order for the optimization to be correct, the branch must...
|
||||
// ...have exactly one statement
|
||||
if let [statement] = branch.statements.as_slice()
|
||||
// ...assign the discriminant of `place` in that statement
|
||||
&& let StatementKind::Assign(boxed) = &statement.kind
|
||||
&& let (discr_place, Rvalue::Discriminant(from_place)) = &**boxed
|
||||
&& *from_place == place
|
||||
// ...make that assignment to a local
|
||||
&& discr_place.projection.is_empty()
|
||||
// ...terminate on a `SwitchInt` that invalidates that local
|
||||
&& let TerminatorKind::SwitchInt { discr: switch_op, targets, .. } =
|
||||
&branch.terminator().kind
|
||||
&& *switch_op == Operand::Move(*discr_place)
|
||||
// ...fall through to `destination` if the switch misses
|
||||
&& destination == targets.otherwise()
|
||||
// ...have a branch for value `value`
|
||||
&& let mut iter = targets.iter()
|
||||
&& let Some((target_value, _)) = iter.next()
|
||||
&& target_value == value
|
||||
// ...and have no more branches
|
||||
&& iter.next().is_none()
|
||||
{
|
||||
true
|
||||
// In order for the optimization to be correct, the terminator must be a `SwitchInt`.
|
||||
let TerminatorKind::SwitchInt { discr: switch_op, targets } = &branch.terminator().kind else {
|
||||
return false;
|
||||
};
|
||||
if need_hoist_discriminant {
|
||||
// If we need hoist discriminant, the branch must have exactly one statement.
|
||||
let [statement] = branch.statements.as_slice() else {
|
||||
return false;
|
||||
};
|
||||
// The statement must assign the discriminant of `place`.
|
||||
let StatementKind::Assign(box (discr_place, Rvalue::Discriminant(from_place))) =
|
||||
statement.kind
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
if from_place != place {
|
||||
return false;
|
||||
}
|
||||
// The assignment must invalidate a local that terminate on a `SwitchInt`.
|
||||
if !discr_place.projection.is_empty() || *switch_op != Operand::Move(discr_place) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
false
|
||||
// If we don't need hoist discriminant, the branch must not have any statements.
|
||||
if !branch.statements.is_empty() {
|
||||
return false;
|
||||
}
|
||||
// The place on `SwitchInt` must be the same.
|
||||
if *switch_op != Operand::Copy(place) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// It must fall through to `destination` if the switch misses.
|
||||
if destination != targets.otherwise() {
|
||||
return false;
|
||||
}
|
||||
// It must have exactly one branch for value `value` and have no more branches.
|
||||
let mut iter = targets.iter();
|
||||
let (Some((target_value, _)), None) = (iter.next(), iter.next()) else {
|
||||
return false;
|
||||
};
|
||||
target_value == value
|
||||
}
|
||||
|
|
|
|||
|
|
@ -572,11 +572,13 @@ impl<'tcx> Inliner<'tcx> {
|
|||
let return_block = if let Some(block) = target {
|
||||
// Prepare a new block for code that should execute when call returns. We don't use
|
||||
// target block directly since it might have other predecessors.
|
||||
let mut data = BasicBlockData::new(Some(Terminator {
|
||||
source_info: terminator.source_info,
|
||||
kind: TerminatorKind::Goto { target: block },
|
||||
}));
|
||||
data.is_cleanup = caller_body[block].is_cleanup;
|
||||
let data = BasicBlockData::new(
|
||||
Some(Terminator {
|
||||
source_info: terminator.source_info,
|
||||
kind: TerminatorKind::Goto { target: block },
|
||||
}),
|
||||
caller_body[block].is_cleanup,
|
||||
);
|
||||
Some(caller_body.basic_blocks_mut().push(data))
|
||||
} else {
|
||||
None
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ impl<'tcx> AsyncDestructorCtorShimBuilder<'tcx> {
|
|||
typing_env,
|
||||
|
||||
stack: Vec::with_capacity(Self::MAX_STACK_LEN),
|
||||
last_bb: bbs.push(BasicBlockData::new(None)),
|
||||
last_bb: bbs.push(BasicBlockData::new(None, false)),
|
||||
top_cleanup_bb: match tcx.sess.panic_strategy() {
|
||||
PanicStrategy::Unwind => {
|
||||
// Don't drop input arg because it's just a pointer
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ use rustc_errors::{
|
|||
use rustc_session::errors::ExprParenthesesNeeded;
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::symbol::AllKeywords;
|
||||
use rustc_span::symbol::used_keywords;
|
||||
use rustc_span::{BytePos, DUMMY_SP, Ident, Span, SpanSnippetError, Symbol, kw, sym};
|
||||
use thin_vec::{ThinVec, thin_vec};
|
||||
use tracing::{debug, trace};
|
||||
|
|
@ -811,12 +811,12 @@ impl<'a> Parser<'a> {
|
|||
// so that it gets generated only when the diagnostic needs it.
|
||||
// Also, it is unlikely that this list is generated multiple times because the
|
||||
// parser halts after execution hits this path.
|
||||
let all_keywords = AllKeywords::new().collect_used(|| prev_ident.span.edition());
|
||||
let all_keywords = used_keywords(|| prev_ident.span.edition());
|
||||
|
||||
// Otherwise, check the previous token with all the keywords as possible candidates.
|
||||
// This handles code like `Struct Human;` and `While a < b {}`.
|
||||
// We check the previous token only when the current token is an identifier to avoid false
|
||||
// positives like suggesting keyword `for` for `extern crate foo {}`.
|
||||
// We check the previous token only when the current token is an identifier to avoid
|
||||
// false positives like suggesting keyword `for` for `extern crate foo {}`.
|
||||
if let Some(misspelled_kw) = find_similar_kw(prev_ident, &all_keywords) {
|
||||
err.subdiagnostic(misspelled_kw);
|
||||
// We don't want other suggestions to be added as they are most likely meaningless
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use ast::token::IdentIsRaw;
|
|||
use ast::{CoroutineKind, ForLoopKind, GenBlockKind, MatchKind, Pat, Path, PathSegment, Recovered};
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, Delimiter, Token, TokenKind};
|
||||
use rustc_ast::tokenstream::TokenTree;
|
||||
use rustc_ast::util::case::Case;
|
||||
use rustc_ast::util::classify;
|
||||
use rustc_ast::util::parser::{AssocOp, ExprPrecedence, Fixity, prec_let_scrutinee_needs_par};
|
||||
|
|
@ -2392,7 +2393,8 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
if self.token == TokenKind::Semi
|
||||
&& matches!(self.token_cursor.stack.last(), Some((.., Delimiter::Parenthesis)))
|
||||
&& let Some(last) = self.token_cursor.stack.last()
|
||||
&& let Some(TokenTree::Delimited(_, _, Delimiter::Parenthesis, _)) = last.curr()
|
||||
&& self.may_recover()
|
||||
{
|
||||
// It is likely that the closure body is a block but where the
|
||||
|
|
|
|||
|
|
@ -24,9 +24,7 @@ use rustc_ast::ptr::P;
|
|||
use rustc_ast::token::{
|
||||
self, Delimiter, IdentIsRaw, InvisibleOrigin, MetaVarKind, Nonterminal, Token, TokenKind,
|
||||
};
|
||||
use rustc_ast::tokenstream::{
|
||||
AttrsTarget, DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree, TokenTreeCursor,
|
||||
};
|
||||
use rustc_ast::tokenstream::{AttrsTarget, Spacing, TokenStream, TokenTree};
|
||||
use rustc_ast::util::case::Case;
|
||||
use rustc_ast::{
|
||||
self as ast, AnonConst, AttrArgs, AttrId, ByRef, Const, CoroutineKind, DUMMY_NODE_ID,
|
||||
|
|
@ -272,21 +270,48 @@ struct CaptureState {
|
|||
seen_attrs: IntervalSet<AttrId>,
|
||||
}
|
||||
|
||||
/// Iterator over a `TokenStream` that produces `Token`s. It's a bit odd that
|
||||
#[derive(Clone, Debug)]
|
||||
struct TokenTreeCursor {
|
||||
stream: TokenStream,
|
||||
/// Points to the current token tree in the stream. In `TokenCursor::curr`,
|
||||
/// this can be any token tree. In `TokenCursor::stack`, this is always a
|
||||
/// `TokenTree::Delimited`.
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl TokenTreeCursor {
|
||||
#[inline]
|
||||
fn new(stream: TokenStream) -> Self {
|
||||
TokenTreeCursor { stream, index: 0 }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn curr(&self) -> Option<&TokenTree> {
|
||||
self.stream.get(self.index)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn bump(&mut self) {
|
||||
self.index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// A `TokenStream` cursor that produces `Token`s. It's a bit odd that
|
||||
/// we (a) lex tokens into a nice tree structure (`TokenStream`), and then (b)
|
||||
/// use this type to emit them as a linear sequence. But a linear sequence is
|
||||
/// what the parser expects, for the most part.
|
||||
#[derive(Clone, Debug)]
|
||||
struct TokenCursor {
|
||||
// Cursor for the current (innermost) token stream. The delimiters for this
|
||||
// token stream are found in `self.stack.last()`; when that is `None` then
|
||||
// we are in the outermost token stream which never has delimiters.
|
||||
tree_cursor: TokenTreeCursor,
|
||||
// Cursor for the current (innermost) token stream. The index within the
|
||||
// cursor can point to any token tree in the stream (or one past the end).
|
||||
// The delimiters for this token stream are found in `self.stack.last()`;
|
||||
// if that is `None` we are in the outermost token stream which never has
|
||||
// delimiters.
|
||||
curr: TokenTreeCursor,
|
||||
|
||||
// Token streams surrounding the current one. The delimiters for stack[n]'s
|
||||
// tokens are in `stack[n-1]`. `stack[0]` (when present) has no delimiters
|
||||
// because it's the outermost token stream which never has delimiters.
|
||||
stack: Vec<(TokenTreeCursor, DelimSpan, DelimSpacing, Delimiter)>,
|
||||
// Token streams surrounding the current one. The index within each cursor
|
||||
// always points to a `TokenTree::Delimited`.
|
||||
stack: Vec<TokenTreeCursor>,
|
||||
}
|
||||
|
||||
impl TokenCursor {
|
||||
|
|
@ -301,32 +326,33 @@ impl TokenCursor {
|
|||
// FIXME: we currently don't return `Delimiter::Invisible` open/close delims. To fix
|
||||
// #67062 we will need to, whereupon the `delim != Delimiter::Invisible` conditions
|
||||
// below can be removed.
|
||||
if let Some(tree) = self.tree_cursor.next_ref() {
|
||||
if let Some(tree) = self.curr.curr() {
|
||||
match tree {
|
||||
&TokenTree::Token(ref token, spacing) => {
|
||||
debug_assert!(!matches!(
|
||||
token.kind,
|
||||
token::OpenDelim(_) | token::CloseDelim(_)
|
||||
));
|
||||
return (token.clone(), spacing);
|
||||
let res = (token.clone(), spacing);
|
||||
self.curr.bump();
|
||||
return res;
|
||||
}
|
||||
&TokenTree::Delimited(sp, spacing, delim, ref tts) => {
|
||||
let trees = tts.clone().into_trees();
|
||||
self.stack.push((
|
||||
mem::replace(&mut self.tree_cursor, trees),
|
||||
sp,
|
||||
spacing,
|
||||
delim,
|
||||
));
|
||||
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);
|
||||
}
|
||||
// No open delimiter to return; continue on to the next iteration.
|
||||
}
|
||||
};
|
||||
} else if let Some((tree_cursor, span, spacing, delim)) = self.stack.pop() {
|
||||
} else if let Some(parent) = self.stack.pop() {
|
||||
// We have exhausted this token stream. Move back to its parent token stream.
|
||||
self.tree_cursor = tree_cursor;
|
||||
let Some(&TokenTree::Delimited(span, spacing, delim, _)) = parent.curr() else {
|
||||
panic!("parent should be Delimited")
|
||||
};
|
||||
self.curr = parent;
|
||||
self.curr.bump(); // move past the `Delimited`
|
||||
if !delim.skip() {
|
||||
return (Token::new(token::CloseDelim(delim), span.close), spacing.close);
|
||||
}
|
||||
|
|
@ -465,7 +491,7 @@ impl<'a> Parser<'a> {
|
|||
capture_cfg: false,
|
||||
restrictions: Restrictions::empty(),
|
||||
expected_tokens: Vec::new(),
|
||||
token_cursor: TokenCursor { tree_cursor: stream.into_trees(), stack: Vec::new() },
|
||||
token_cursor: TokenCursor { curr: TokenTreeCursor::new(stream), stack: Vec::new() },
|
||||
num_bump_calls: 0,
|
||||
break_last_token: 0,
|
||||
unmatched_angle_bracket_count: 0,
|
||||
|
|
@ -1191,7 +1217,7 @@ impl<'a> Parser<'a> {
|
|||
if dist == 1 {
|
||||
// The index is zero because the tree cursor's index always points
|
||||
// to the next token to be gotten.
|
||||
match self.token_cursor.tree_cursor.look_ahead(0) {
|
||||
match self.token_cursor.curr.curr() {
|
||||
Some(tree) => {
|
||||
// Indexing stayed within the current token tree.
|
||||
match tree {
|
||||
|
|
@ -1201,12 +1227,13 @@ impl<'a> Parser<'a> {
|
|||
return looker(&Token::new(token::OpenDelim(delim), dspan.open));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// The tree cursor lookahead went (one) past the end of the
|
||||
// current token tree. Try to return a close delimiter.
|
||||
if let Some(&(_, span, _, delim)) = self.token_cursor.stack.last()
|
||||
if let Some(last) = self.token_cursor.stack.last()
|
||||
&& let Some(&TokenTree::Delimited(span, _, delim, _)) = last.curr()
|
||||
&& !delim.skip()
|
||||
{
|
||||
// We are not in the outermost token stream, so we have
|
||||
|
|
@ -1398,9 +1425,10 @@ impl<'a> Parser<'a> {
|
|||
pub fn parse_token_tree(&mut self) -> TokenTree {
|
||||
match self.token.kind {
|
||||
token::OpenDelim(..) => {
|
||||
// Grab the tokens within the delimiters.
|
||||
let stream = self.token_cursor.tree_cursor.stream.clone();
|
||||
let (_, span, spacing, delim) = *self.token_cursor.stack.last().unwrap();
|
||||
// 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
|
||||
|
|
@ -1420,7 +1448,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
// Consume close delimiter
|
||||
self.bump();
|
||||
TokenTree::Delimited(span, spacing, delim, stream)
|
||||
tree
|
||||
}
|
||||
token::CloseDelim(_) | token::Eof => unreachable!(),
|
||||
_ => {
|
||||
|
|
|
|||
|
|
@ -2286,7 +2286,7 @@ fn bad_path_expr_1() {
|
|||
fn string_to_tts_macro() {
|
||||
create_default_session_globals_then(|| {
|
||||
let stream = string_to_stream("macro_rules! zip (($a)=>($a))".to_string());
|
||||
let tts = &stream.trees().collect::<Vec<_>>()[..];
|
||||
let tts = &stream.iter().collect::<Vec<_>>()[..];
|
||||
|
||||
match tts {
|
||||
[
|
||||
|
|
@ -2298,14 +2298,14 @@ fn string_to_tts_macro() {
|
|||
TokenTree::Token(Token { kind: token::Ident(name_zip, IdentIsRaw::No), .. }, _),
|
||||
TokenTree::Delimited(.., macro_delim, macro_tts),
|
||||
] if name_macro_rules == &kw::MacroRules && name_zip.as_str() == "zip" => {
|
||||
let tts = ¯o_tts.trees().collect::<Vec<_>>();
|
||||
let tts = ¯o_tts.iter().collect::<Vec<_>>();
|
||||
match &tts[..] {
|
||||
[
|
||||
TokenTree::Delimited(.., first_delim, first_tts),
|
||||
TokenTree::Token(Token { kind: token::FatArrow, .. }, _),
|
||||
TokenTree::Delimited(.., second_delim, second_tts),
|
||||
] if macro_delim == &Delimiter::Parenthesis => {
|
||||
let tts = &first_tts.trees().collect::<Vec<_>>();
|
||||
let tts = &first_tts.iter().collect::<Vec<_>>();
|
||||
match &tts[..] {
|
||||
[
|
||||
TokenTree::Token(Token { kind: token::Dollar, .. }, _),
|
||||
|
|
@ -2317,7 +2317,7 @@ fn string_to_tts_macro() {
|
|||
}
|
||||
_ => panic!("value 3: {:?} {:?}", first_delim, first_tts),
|
||||
}
|
||||
let tts = &second_tts.trees().collect::<Vec<_>>();
|
||||
let tts = &second_tts.iter().collect::<Vec<_>>();
|
||||
match &tts[..] {
|
||||
[
|
||||
TokenTree::Token(Token { kind: token::Dollar, .. }, _),
|
||||
|
|
@ -2545,7 +2545,7 @@ fn ttdelim_span() {
|
|||
.unwrap();
|
||||
|
||||
let ast::ExprKind::MacCall(mac) = &expr.kind else { panic!("not a macro") };
|
||||
let span = mac.args.tokens.trees().last().unwrap().span();
|
||||
let span = mac.args.tokens.iter().last().unwrap().span();
|
||||
|
||||
match psess.source_map().span_to_snippet(span) {
|
||||
Ok(s) => assert_eq!(&s[..], "{ body }"),
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ fn test_concat() {
|
|||
let mut eq_res = TokenStream::default();
|
||||
eq_res.push_stream(test_fst);
|
||||
eq_res.push_stream(test_snd);
|
||||
assert_eq!(test_res.trees().count(), 5);
|
||||
assert_eq!(eq_res.trees().count(), 5);
|
||||
assert_eq!(test_res.iter().count(), 5);
|
||||
assert_eq!(eq_res.iter().count(), 5);
|
||||
assert_eq!(test_res.eq_unspanned(&eq_res), true);
|
||||
})
|
||||
}
|
||||
|
|
@ -33,7 +33,7 @@ fn test_concat() {
|
|||
fn test_to_from_bijection() {
|
||||
create_default_session_globals_then(|| {
|
||||
let test_start = string_to_ts("foo::bar(baz)");
|
||||
let test_end = test_start.trees().cloned().collect();
|
||||
let test_end = test_start.iter().cloned().collect();
|
||||
assert_eq!(test_start, test_end)
|
||||
})
|
||||
}
|
||||
|
|
@ -105,6 +105,6 @@ fn test_dotdotdot() {
|
|||
stream.push_tree(TokenTree::token_joint(token::Dot, sp(1, 2)));
|
||||
stream.push_tree(TokenTree::token_alone(token::Dot, sp(2, 3)));
|
||||
assert!(stream.eq_unspanned(&string_to_ts("...")));
|
||||
assert_eq!(stream.trees().count(), 1);
|
||||
assert_eq!(stream.iter().count(), 1);
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1076,7 +1076,7 @@ impl OutputFilenames {
|
|||
self.with_directory_and_extension(&self.out_directory, extension)
|
||||
}
|
||||
|
||||
pub fn with_directory_and_extension(&self, directory: &PathBuf, extension: &str) -> PathBuf {
|
||||
pub fn with_directory_and_extension(&self, directory: &Path, extension: &str) -> PathBuf {
|
||||
let mut path = directory.join(&self.filestem);
|
||||
path.set_extension(extension);
|
||||
path
|
||||
|
|
|
|||
|
|
@ -20,18 +20,26 @@ mod tests;
|
|||
|
||||
// The proc macro code for this is in `compiler/rustc_macros/src/symbols.rs`.
|
||||
symbols! {
|
||||
// If you modify this list, adjust `is_special`, `is_used_keyword`/`is_unused_keyword`
|
||||
// and `AllKeywords`.
|
||||
// This list includes things that are definitely keywords (e.g. `if`),
|
||||
// a few things that are definitely not keywords (e.g. the empty symbol,
|
||||
// `{{root}}`) and things where there is disagreement between people and/or
|
||||
// documents (such as the Rust Reference) about whether it is a keyword
|
||||
// (e.g. `_`).
|
||||
//
|
||||
// If you modify this list, adjust any relevant `Symbol::{is,can_be}_*` predicates and
|
||||
// `used_keywords`.
|
||||
// But this should rarely be necessary if the keywords are kept in alphabetic order.
|
||||
Keywords {
|
||||
// Special reserved identifiers used internally for elided lifetimes,
|
||||
// unnamed method parameters, crate root module, error recovery etc.
|
||||
// Matching predicates: `is_any_keyword`, `is_special`/`is_reserved`
|
||||
Empty: "",
|
||||
PathRoot: "{{root}}",
|
||||
DollarCrate: "$crate",
|
||||
Underscore: "_",
|
||||
|
||||
// Keywords that are used in stable Rust.
|
||||
// Matching predicates: `is_any_keyword`, `is_used_keyword_always`/`is_reserved`
|
||||
As: "as",
|
||||
Break: "break",
|
||||
Const: "const",
|
||||
|
|
@ -69,6 +77,7 @@ symbols! {
|
|||
While: "while",
|
||||
|
||||
// Keywords that are used in unstable Rust or reserved for future use.
|
||||
// Matching predicates: `is_any_keyword`, `is_unused_keyword_always`/`is_reserved`
|
||||
Abstract: "abstract",
|
||||
Become: "become",
|
||||
Box: "box",
|
||||
|
|
@ -83,23 +92,29 @@ symbols! {
|
|||
Yield: "yield",
|
||||
|
||||
// Edition-specific keywords that are used in stable Rust.
|
||||
// Matching predicates: `is_any_keyword`, `is_used_keyword_conditional`/`is_reserved` (if
|
||||
// the edition suffices)
|
||||
Async: "async", // >= 2018 Edition only
|
||||
Await: "await", // >= 2018 Edition only
|
||||
Dyn: "dyn", // >= 2018 Edition only
|
||||
|
||||
// Edition-specific keywords that are used in unstable Rust or reserved for future use.
|
||||
// Matching predicates: `is_any_keyword`, `is_unused_keyword_conditional`/`is_reserved` (if
|
||||
// the edition suffices)
|
||||
Gen: "gen", // >= 2024 Edition only
|
||||
Try: "try", // >= 2018 Edition only
|
||||
|
||||
// Special lifetime names
|
||||
// "Lifetime keywords": regular keywords with a leading `'`.
|
||||
// Matching predicates: `is_any_keyword`
|
||||
UnderscoreLifetime: "'_",
|
||||
StaticLifetime: "'static",
|
||||
|
||||
// Weak keywords, have special meaning only in specific contexts.
|
||||
// Matching predicates: `is_any_keyword`
|
||||
Auto: "auto",
|
||||
Builtin: "builtin",
|
||||
Catch: "catch",
|
||||
Default: "default",
|
||||
Gen: "gen",
|
||||
MacroRules: "macro_rules",
|
||||
Raw: "raw",
|
||||
Reuse: "reuse",
|
||||
|
|
@ -2589,6 +2604,11 @@ pub mod sym {
|
|||
}
|
||||
|
||||
impl Symbol {
|
||||
/// Don't use this unless you're doing something very loose and heuristic-y.
|
||||
pub fn is_any_keyword(self) -> bool {
|
||||
self >= kw::As && self <= kw::Yeet
|
||||
}
|
||||
|
||||
fn is_special(self) -> bool {
|
||||
self <= kw::Underscore
|
||||
}
|
||||
|
|
@ -2606,8 +2626,8 @@ impl Symbol {
|
|||
}
|
||||
|
||||
fn is_unused_keyword_conditional(self, edition: impl Copy + FnOnce() -> Edition) -> bool {
|
||||
self == kw::Try && edition().at_least_rust_2018()
|
||||
|| self == kw::Gen && edition().at_least_rust_2024()
|
||||
self == kw::Gen && edition().at_least_rust_2024()
|
||||
|| self == kw::Try && edition().at_least_rust_2018()
|
||||
}
|
||||
|
||||
pub fn is_reserved(self, edition: impl Copy + FnOnce() -> Edition) -> bool {
|
||||
|
|
@ -2645,6 +2665,11 @@ impl Symbol {
|
|||
}
|
||||
|
||||
impl Ident {
|
||||
/// Don't use this unless you're doing something very loose and heuristic-y.
|
||||
pub fn is_any_keyword(self) -> bool {
|
||||
self.name.is_any_keyword()
|
||||
}
|
||||
|
||||
/// Returns `true` for reserved identifiers used internally for elided lifetimes,
|
||||
/// unnamed method parameters, crate root module, error recovery etc.
|
||||
pub fn is_special(self) -> bool {
|
||||
|
|
@ -2683,41 +2708,19 @@ impl Ident {
|
|||
}
|
||||
}
|
||||
|
||||
/// An iterator over all the keywords in Rust.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct AllKeywords {
|
||||
curr_idx: u32,
|
||||
end_idx: u32,
|
||||
}
|
||||
|
||||
impl AllKeywords {
|
||||
/// Initialize a new iterator over all the keywords.
|
||||
///
|
||||
/// *Note:* Please update this if a new keyword is added beyond the current
|
||||
/// range.
|
||||
pub fn new() -> Self {
|
||||
AllKeywords { curr_idx: kw::Empty.as_u32(), end_idx: kw::Yeet.as_u32() }
|
||||
}
|
||||
|
||||
/// Collect all the keywords in a given edition into a vector.
|
||||
pub fn collect_used(&self, edition: impl Copy + FnOnce() -> Edition) -> Vec<Symbol> {
|
||||
self.filter(|&keyword| {
|
||||
keyword.is_used_keyword_always() || keyword.is_used_keyword_conditional(edition)
|
||||
/// Collect all the keywords in a given edition into a vector.
|
||||
///
|
||||
/// *Note:* Please update this if a new keyword is added beyond the current
|
||||
/// range.
|
||||
pub fn used_keywords(edition: impl Copy + FnOnce() -> Edition) -> Vec<Symbol> {
|
||||
(kw::Empty.as_u32()..kw::Yeet.as_u32())
|
||||
.filter_map(|kw| {
|
||||
let kw = Symbol::new(kw);
|
||||
if kw.is_used_keyword_always() || kw.is_used_keyword_conditional(edition) {
|
||||
Some(kw)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for AllKeywords {
|
||||
type Item = Symbol;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.curr_idx <= self.end_idx {
|
||||
let keyword = Symbol::new(self.curr_idx);
|
||||
self.curr_idx += 1;
|
||||
Some(keyword)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> {
|
|||
}
|
||||
|
||||
impl<T, F> LazyCell<T, F> {
|
||||
/// Returns a reference to the value if initialized, or `None` if not.
|
||||
/// Returns a mutable reference to the value if initialized, or `None` if not.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -245,7 +245,7 @@ impl<T, F> LazyCell<T, F> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the value if initialized, or `None` if not.
|
||||
/// Returns a reference to the value if initialized, or `None` if not.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
|
|||
|
|
@ -523,6 +523,11 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car
|
|||
|
||||
let mut features = String::new();
|
||||
|
||||
if stage != 0 && builder.config.default_codegen_backend(target).as_deref() == Some("cranelift")
|
||||
{
|
||||
features += "compiler-builtins-no-f16-f128 ";
|
||||
}
|
||||
|
||||
if builder.no_std(target) == Some(true) {
|
||||
features += " compiler-builtins-mem";
|
||||
if !target.starts_with("bpf") {
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ pub fn setup(config: &Config, profile: Profile) {
|
|||
setup_config_toml(path, profile, config);
|
||||
}
|
||||
|
||||
fn setup_config_toml(path: &PathBuf, profile: Profile, config: &Config) {
|
||||
fn setup_config_toml(path: &Path, profile: Profile, config: &Config) {
|
||||
if profile == Profile::None {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1942,7 +1942,7 @@ impl Config {
|
|||
);
|
||||
|
||||
let channel = config
|
||||
.read_file_by_commit(&PathBuf::from("src/ci/channel"), commit)
|
||||
.read_file_by_commit(Path::new("src/ci/channel"), commit)
|
||||
.trim()
|
||||
.to_owned();
|
||||
|
||||
|
|
@ -2383,12 +2383,10 @@ impl Config {
|
|||
/// Return the version it would have used for the given commit.
|
||||
pub(crate) fn artifact_version_part(&self, commit: &str) -> String {
|
||||
let (channel, version) = if self.rust_info.is_managed_git_subrepository() {
|
||||
let channel = self
|
||||
.read_file_by_commit(&PathBuf::from("src/ci/channel"), commit)
|
||||
.trim()
|
||||
.to_owned();
|
||||
let channel =
|
||||
self.read_file_by_commit(Path::new("src/ci/channel"), commit).trim().to_owned();
|
||||
let version =
|
||||
self.read_file_by_commit(&PathBuf::from("src/version"), commit).trim().to_owned();
|
||||
self.read_file_by_commit(Path::new("src/version"), commit).trim().to_owned();
|
||||
(channel, version)
|
||||
} else {
|
||||
let channel = fs::read_to_string(self.src.join("src/ci/channel"));
|
||||
|
|
|
|||
|
|
@ -2604,7 +2604,7 @@ fn filter_tokens_from_list(
|
|||
) -> Vec<TokenTree> {
|
||||
let mut tokens = Vec::with_capacity(args_tokens.len());
|
||||
let mut skip_next_comma = false;
|
||||
for token in args_tokens.trees() {
|
||||
for token in args_tokens.iter() {
|
||||
match token {
|
||||
TokenTree::Token(Token { kind: TokenKind::Comma, .. }, _) if skip_next_comma => {
|
||||
skip_next_comma = false;
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ fn print_tts(printer: &mut Printer<'_>, tts: &TokenStream) {
|
|||
use State::*;
|
||||
|
||||
let mut state = Start;
|
||||
for tt in tts.trees() {
|
||||
for tt in tts.iter() {
|
||||
let (needs_space, next_state) = match &tt {
|
||||
TokenTree::Token(tt, _) => match (state, &tt.kind) {
|
||||
(Dollar, token::Ident(..)) => (false, DollarIdent),
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, attr: &Attribute) {
|
|||
}
|
||||
|
||||
if let AttrArgs::Delimited(args) = &normal_attr.item.args
|
||||
&& let mut tt_iter = args.tokens.trees()
|
||||
&& let mut tt_iter = args.tokens.iter()
|
||||
&& let Some(TokenTree::Token(
|
||||
Token {
|
||||
kind: TokenKind::Ident(sym::expected, _),
|
||||
|
|
|
|||
|
|
@ -82,11 +82,11 @@ fn is_macro_export(attr: &Attribute) -> bool {
|
|||
|
||||
fn contains_unhygienic_crate_reference(tts: &TokenStream) -> Option<Span> {
|
||||
let mut prev_is_dollar = false;
|
||||
let mut cursor = tts.trees();
|
||||
while let Some(curr) = cursor.next() {
|
||||
let mut iter = tts.iter();
|
||||
while let Some(curr) = iter.next() {
|
||||
if !prev_is_dollar
|
||||
&& let Some(span) = is_crate_keyword(curr)
|
||||
&& let Some(next) = cursor.look_ahead(0)
|
||||
&& let Some(next) = iter.peek()
|
||||
&& is_token(next, &TokenKind::PathSep)
|
||||
{
|
||||
return Some(span);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
|
@ -141,7 +141,7 @@ pub(crate) fn extract_cdb_version(full_version_line: &str) -> Option<[u16; 4]> {
|
|||
pub(crate) fn analyze_gdb(
|
||||
gdb: Option<String>,
|
||||
target: &str,
|
||||
android_cross_path: &PathBuf,
|
||||
android_cross_path: &Path,
|
||||
) -> (Option<String>, Option<u32>) {
|
||||
#[cfg(not(windows))]
|
||||
const GDB_FALLBACK: &str = "gdb";
|
||||
|
|
|
|||
|
|
@ -598,10 +598,9 @@ pub fn collect_and_make_tests(config: Arc<Config>) -> Vec<test::TestDescAndFn> {
|
|||
let mut collector =
|
||||
TestCollector { tests: vec![], found_path_stems: HashSet::new(), poisoned: false };
|
||||
|
||||
collect_tests_from_dir(&cx, &mut collector, &cx.config.src_base, &PathBuf::new())
|
||||
.unwrap_or_else(|reason| {
|
||||
panic!("Could not read tests from {}: {reason}", cx.config.src_base.display())
|
||||
});
|
||||
collect_tests_from_dir(&cx, &mut collector, &cx.config.src_base, Path::new("")).unwrap_or_else(
|
||||
|reason| panic!("Could not read tests from {}: {reason}", cx.config.src_base.display()),
|
||||
);
|
||||
|
||||
let TestCollector { tests, found_path_stems, poisoned } = collector;
|
||||
|
||||
|
|
|
|||
|
|
@ -2560,7 +2560,7 @@ impl<'test> TestCx<'test> {
|
|||
})
|
||||
}
|
||||
|
||||
fn delete_file(&self, file: &PathBuf) {
|
||||
fn delete_file(&self, file: &Path) {
|
||||
if !file.exists() {
|
||||
// Deleting a nonexistent file would error.
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ fn apply_shared_opts(cmd: &mut Command, opts: &SharedOpts) {
|
|||
}
|
||||
}
|
||||
|
||||
fn execute_benchmark(cmd: &mut Command, compiler: &PathBuf) {
|
||||
fn execute_benchmark(cmd: &mut Command, compiler: &Path) {
|
||||
cmd.arg(compiler);
|
||||
println!("Running `rustc-perf` using `{}`", compiler.display());
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use std::collections::HashMap;
|
|||
use std::panic::{AssertUnwindSafe, catch_unwind};
|
||||
|
||||
use rustc_ast::token::{BinOpToken, Delimiter, Token, TokenKind};
|
||||
use rustc_ast::tokenstream::{RefTokenTreeCursor, TokenStream, TokenTree};
|
||||
use rustc_ast::tokenstream::{TokenStream, TokenStreamIter, TokenTree};
|
||||
use rustc_ast::{ast, ptr};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_span::{
|
||||
|
|
@ -443,7 +443,7 @@ pub(crate) fn rewrite_macro_def(
|
|||
}
|
||||
|
||||
let ts = def.body.tokens.clone();
|
||||
let mut parser = MacroParser::new(ts.trees());
|
||||
let mut parser = MacroParser::new(ts.iter());
|
||||
let parsed_def = match parser.parse() {
|
||||
Some(def) => def,
|
||||
None => return snippet,
|
||||
|
|
@ -794,7 +794,7 @@ impl MacroArgParser {
|
|||
self.buf.clear();
|
||||
}
|
||||
|
||||
fn add_meta_variable(&mut self, iter: &mut RefTokenTreeCursor<'_>) -> Option<()> {
|
||||
fn add_meta_variable(&mut self, iter: &mut TokenStreamIter<'_>) -> Option<()> {
|
||||
match iter.next() {
|
||||
Some(&TokenTree::Token(
|
||||
Token {
|
||||
|
|
@ -826,7 +826,7 @@ impl MacroArgParser {
|
|||
&mut self,
|
||||
inner: Vec<ParsedMacroArg>,
|
||||
delim: Delimiter,
|
||||
iter: &mut RefTokenTreeCursor<'_>,
|
||||
iter: &mut TokenStreamIter<'_>,
|
||||
) -> Option<()> {
|
||||
let mut buffer = String::new();
|
||||
let mut first = true;
|
||||
|
|
@ -926,7 +926,7 @@ impl MacroArgParser {
|
|||
|
||||
/// Returns a collection of parsed macro def's arguments.
|
||||
fn parse(mut self, tokens: TokenStream) -> Option<Vec<ParsedMacroArg>> {
|
||||
let mut iter = tokens.trees();
|
||||
let mut iter = tokens.iter();
|
||||
|
||||
while let Some(tok) = iter.next() {
|
||||
match tok {
|
||||
|
|
@ -1063,7 +1063,7 @@ fn format_macro_args(
|
|||
}
|
||||
|
||||
fn span_for_token_stream(token_stream: &TokenStream) -> Option<Span> {
|
||||
token_stream.trees().next().map(|tt| tt.span())
|
||||
token_stream.iter().next().map(|tt| tt.span())
|
||||
}
|
||||
|
||||
// We should insert a space if the next token is a:
|
||||
|
|
@ -1179,18 +1179,18 @@ pub(crate) fn macro_style(mac: &ast::MacCall, context: &RewriteContext<'_>) -> D
|
|||
// A very simple parser that just parses a macros 2.0 definition into its branches.
|
||||
// Currently we do not attempt to parse any further than that.
|
||||
struct MacroParser<'a> {
|
||||
toks: RefTokenTreeCursor<'a>,
|
||||
iter: TokenStreamIter<'a>,
|
||||
}
|
||||
|
||||
impl<'a> MacroParser<'a> {
|
||||
const fn new(toks: RefTokenTreeCursor<'a>) -> Self {
|
||||
Self { toks }
|
||||
const fn new(iter: TokenStreamIter<'a>) -> Self {
|
||||
Self { iter }
|
||||
}
|
||||
|
||||
// (`(` ... `)` `=>` `{` ... `}`)*
|
||||
fn parse(&mut self) -> Option<Macro> {
|
||||
let mut branches = vec![];
|
||||
while self.toks.look_ahead(1).is_some() {
|
||||
while self.iter.peek().is_some() {
|
||||
branches.push(self.parse_branch()?);
|
||||
}
|
||||
|
||||
|
|
@ -1199,13 +1199,13 @@ impl<'a> MacroParser<'a> {
|
|||
|
||||
// `(` ... `)` `=>` `{` ... `}`
|
||||
fn parse_branch(&mut self) -> Option<MacroBranch> {
|
||||
let tok = self.toks.next()?;
|
||||
let tok = self.iter.next()?;
|
||||
let (lo, args_paren_kind) = match tok {
|
||||
TokenTree::Token(..) => return None,
|
||||
&TokenTree::Delimited(delimited_span, _, d, _) => (delimited_span.open.lo(), d),
|
||||
};
|
||||
let args = TokenStream::new(vec![tok.clone()]);
|
||||
match self.toks.next()? {
|
||||
match self.iter.next()? {
|
||||
TokenTree::Token(
|
||||
Token {
|
||||
kind: TokenKind::FatArrow,
|
||||
|
|
@ -1215,7 +1215,7 @@ impl<'a> MacroParser<'a> {
|
|||
) => {}
|
||||
_ => return None,
|
||||
}
|
||||
let (mut hi, body, whole_body) = match self.toks.next()? {
|
||||
let (mut hi, body, whole_body) = match self.iter.next()? {
|
||||
TokenTree::Token(..) => return None,
|
||||
TokenTree::Delimited(delimited_span, ..) => {
|
||||
let data = delimited_span.entire().data();
|
||||
|
|
@ -1237,10 +1237,10 @@ impl<'a> MacroParser<'a> {
|
|||
span,
|
||||
},
|
||||
_,
|
||||
)) = self.toks.look_ahead(0)
|
||||
)) = self.iter.peek()
|
||||
{
|
||||
hi = span.hi();
|
||||
self.toks.next();
|
||||
self.iter.next();
|
||||
}
|
||||
Some(MacroBranch {
|
||||
span: mk_sp(lo, hi),
|
||||
|
|
|
|||
|
|
@ -4,8 +4,7 @@ use rustc_ast::{ast, ptr};
|
|||
use rustc_parse::MACRO_ARGUMENTS;
|
||||
use rustc_parse::parser::{ForceCollect, Parser, Recovery};
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::Symbol;
|
||||
use rustc_span::symbol::{self, kw};
|
||||
use rustc_span::symbol;
|
||||
|
||||
use crate::macros::MacroArg;
|
||||
use crate::rewrite::RewriteContext;
|
||||
|
|
@ -82,18 +81,18 @@ pub(crate) struct ParsedMacroArgs {
|
|||
}
|
||||
|
||||
fn check_keyword<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> {
|
||||
for &keyword in RUST_KW.iter() {
|
||||
if parser.token.is_keyword(keyword)
|
||||
&& parser.look_ahead(1, |t| *t == TokenKind::Eof || *t == TokenKind::Comma)
|
||||
{
|
||||
parser.bump();
|
||||
return Some(MacroArg::Keyword(
|
||||
symbol::Ident::with_dummy_span(keyword),
|
||||
parser.prev_token.span,
|
||||
));
|
||||
}
|
||||
if parser.token.is_any_keyword()
|
||||
&& parser.look_ahead(1, |t| *t == TokenKind::Eof || *t == TokenKind::Comma)
|
||||
{
|
||||
let keyword = parser.token.ident().unwrap().0.name;
|
||||
parser.bump();
|
||||
Some(MacroArg::Keyword(
|
||||
symbol::Ident::with_dummy_span(keyword),
|
||||
parser.prev_token.span,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub(crate) fn parse_macro_args(
|
||||
|
|
@ -169,65 +168,3 @@ pub(crate) fn parse_expr(
|
|||
let mut parser = build_parser(context, tokens);
|
||||
parser.parse_expr().ok()
|
||||
}
|
||||
|
||||
const RUST_KW: [Symbol; 59] = [
|
||||
kw::PathRoot,
|
||||
kw::DollarCrate,
|
||||
kw::Underscore,
|
||||
kw::As,
|
||||
kw::Box,
|
||||
kw::Break,
|
||||
kw::Const,
|
||||
kw::Continue,
|
||||
kw::Crate,
|
||||
kw::Else,
|
||||
kw::Enum,
|
||||
kw::Extern,
|
||||
kw::False,
|
||||
kw::Fn,
|
||||
kw::For,
|
||||
kw::If,
|
||||
kw::Impl,
|
||||
kw::In,
|
||||
kw::Let,
|
||||
kw::Loop,
|
||||
kw::Match,
|
||||
kw::Mod,
|
||||
kw::Move,
|
||||
kw::Mut,
|
||||
kw::Pub,
|
||||
kw::Ref,
|
||||
kw::Return,
|
||||
kw::SelfLower,
|
||||
kw::SelfUpper,
|
||||
kw::Static,
|
||||
kw::Struct,
|
||||
kw::Super,
|
||||
kw::Trait,
|
||||
kw::True,
|
||||
kw::Type,
|
||||
kw::Unsafe,
|
||||
kw::Use,
|
||||
kw::Where,
|
||||
kw::While,
|
||||
kw::Abstract,
|
||||
kw::Become,
|
||||
kw::Do,
|
||||
kw::Final,
|
||||
kw::Macro,
|
||||
kw::Override,
|
||||
kw::Priv,
|
||||
kw::Typeof,
|
||||
kw::Unsized,
|
||||
kw::Virtual,
|
||||
kw::Yield,
|
||||
kw::Dyn,
|
||||
kw::Async,
|
||||
kw::Try,
|
||||
kw::UnderscoreLifetime,
|
||||
kw::StaticLifetime,
|
||||
kw::Auto,
|
||||
kw::Catch,
|
||||
kw::Default,
|
||||
kw::Union,
|
||||
];
|
||||
|
|
|
|||
|
|
@ -1,18 +1,14 @@
|
|||
//@ add-core-stubs
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: --target aarch64-unknown-linux-gnu
|
||||
//@ needs-llvm-components: aarch64
|
||||
|
||||
#![feature(no_core, lang_items, rustc_attrs)]
|
||||
#![feature(no_core)]
|
||||
#![crate_type = "rlib"]
|
||||
#![no_core]
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! asm {
|
||||
() => {};
|
||||
}
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
// CHECK-LABEL: ttbr0_el2:
|
||||
#[no_mangle]
|
||||
|
|
|
|||
|
|
@ -1,29 +1,17 @@
|
|||
//@ add-core-stubs
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: -O -C panic=abort
|
||||
//@ compile-flags: --target aarch64-unknown-linux-gnu
|
||||
//@ compile-flags: -Zmerge-functions=disabled
|
||||
//@ needs-llvm-components: aarch64
|
||||
|
||||
#![feature(no_core, lang_items, rustc_attrs)]
|
||||
#![feature(no_core)]
|
||||
#![crate_type = "rlib"]
|
||||
#![no_core]
|
||||
#![allow(asm_sub_register)]
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! asm {
|
||||
() => {};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! stringify {
|
||||
() => {};
|
||||
}
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
|
||||
impl Copy for i32 {}
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
macro_rules! check {
|
||||
($func:ident $reg:ident $code:literal) => {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//@ add-core-stubs
|
||||
//@ revisions: aarch64 arm64ec
|
||||
//@ assembly-output: emit-asm
|
||||
//@ [aarch64] compile-flags: --target aarch64-unknown-linux-gnu
|
||||
|
|
@ -6,33 +7,15 @@
|
|||
//@ [arm64ec] needs-llvm-components: aarch64
|
||||
//@ compile-flags: -Zmerge-functions=disabled
|
||||
|
||||
#![feature(no_core, lang_items, rustc_attrs, repr_simd, f16, f128)]
|
||||
#![feature(no_core, repr_simd, f16, f128)]
|
||||
#![crate_type = "rlib"]
|
||||
#![no_core]
|
||||
#![allow(asm_sub_register, non_camel_case_types)]
|
||||
// FIXME(f16_f128): Only needed for FIXME in check! and check_reg!
|
||||
#![feature(auto_traits)]
|
||||
#![feature(auto_traits, lang_items)]
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! asm {
|
||||
() => {};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! concat {
|
||||
() => {};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! stringify {
|
||||
() => {};
|
||||
}
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
|
||||
// Do we really need to use no_core for this?!?
|
||||
impl<T: Copy, const N: usize> Copy for [T; N] {}
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
type ptr = *mut u8;
|
||||
|
||||
|
|
@ -65,15 +48,6 @@ pub struct f32x4([f32; 4]);
|
|||
#[repr(simd)]
|
||||
pub struct f64x2([f64; 2]);
|
||||
|
||||
impl Copy for i8 {}
|
||||
impl Copy for i16 {}
|
||||
impl Copy for f16 {}
|
||||
impl Copy for i32 {}
|
||||
impl Copy for f32 {}
|
||||
impl Copy for i64 {}
|
||||
impl Copy for f64 {}
|
||||
impl Copy for f128 {}
|
||||
impl Copy for ptr {}
|
||||
impl Copy for i8x8 {}
|
||||
impl Copy for i16x4 {}
|
||||
impl Copy for i32x2 {}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//@ add-core-stubs
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: -O -C panic=abort
|
||||
//@ compile-flags: --target armv7-unknown-linux-gnueabihf
|
||||
|
|
@ -5,38 +6,17 @@
|
|||
//@ compile-flags: -Zmerge-functions=disabled
|
||||
//@ needs-llvm-components: arm
|
||||
|
||||
#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
|
||||
#![feature(no_core, repr_simd)]
|
||||
#![crate_type = "rlib"]
|
||||
#![no_core]
|
||||
#![allow(asm_sub_register, non_camel_case_types)]
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! asm {
|
||||
() => {};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! concat {
|
||||
() => {};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! stringify {
|
||||
() => {};
|
||||
}
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
|
||||
// Do we really need to use no_core for this?!?
|
||||
impl<T: Copy, const N: usize> Copy for [T; N] {}
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
#[repr(simd)]
|
||||
pub struct f32x4([f32; 4]);
|
||||
|
||||
impl Copy for i32 {}
|
||||
impl Copy for f32 {}
|
||||
impl Copy for f64 {}
|
||||
impl Copy for f32x4 {}
|
||||
|
||||
macro_rules! check {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//@ add-core-stubs
|
||||
//@ revisions: base d32 neon
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: --target armv7-unknown-linux-gnueabihf
|
||||
|
|
@ -8,31 +9,13 @@
|
|||
//@[neon] filecheck-flags: --check-prefix d32
|
||||
//@ needs-llvm-components: arm
|
||||
|
||||
#![feature(no_core, lang_items, rustc_attrs, repr_simd, f16)]
|
||||
#![feature(no_core, repr_simd, f16)]
|
||||
#![crate_type = "rlib"]
|
||||
#![no_core]
|
||||
#![allow(asm_sub_register, non_camel_case_types)]
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! asm {
|
||||
() => {};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! concat {
|
||||
() => {};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! stringify {
|
||||
() => {};
|
||||
}
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
|
||||
// Do we really need to use no_core for this?!?
|
||||
impl<T: Copy, const N: usize> Copy for [T; N] {}
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
type ptr = *mut u8;
|
||||
|
||||
|
|
@ -61,14 +44,6 @@ pub struct f16x8([f16; 8]);
|
|||
#[repr(simd)]
|
||||
pub struct f32x4([f32; 4]);
|
||||
|
||||
impl Copy for i8 {}
|
||||
impl Copy for i16 {}
|
||||
impl Copy for i32 {}
|
||||
impl Copy for f16 {}
|
||||
impl Copy for f32 {}
|
||||
impl Copy for i64 {}
|
||||
impl Copy for f64 {}
|
||||
impl Copy for ptr {}
|
||||
impl Copy for i8x8 {}
|
||||
impl Copy for i16x4 {}
|
||||
impl Copy for i32x2 {}
|
||||
|
|
|
|||
|
|
@ -1,34 +1,18 @@
|
|||
//@ add-core-stubs
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: --target avr-unknown-gnu-atmega328
|
||||
//@ needs-llvm-components: avr
|
||||
|
||||
#![feature(no_core, lang_items, rustc_attrs, asm_experimental_arch)]
|
||||
#![feature(no_core, asm_experimental_arch)]
|
||||
#![crate_type = "rlib"]
|
||||
#![no_core]
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! asm {
|
||||
() => {};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! concat {
|
||||
() => {};
|
||||
}
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
type ptr = *const u64;
|
||||
|
||||
impl Copy for i8 {}
|
||||
impl Copy for i16 {}
|
||||
impl Copy for i32 {}
|
||||
impl Copy for i64 {}
|
||||
impl Copy for ptr {}
|
||||
|
||||
macro_rules! check {
|
||||
($func:ident $hi:literal $lo:literal $reg:tt) => {
|
||||
#[no_mangle]
|
||||
|
|
|
|||
|
|
@ -1,34 +1,18 @@
|
|||
//@ add-core-stubs
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: --target avr-unknown-gnu-atmega328
|
||||
//@ needs-llvm-components: avr
|
||||
|
||||
#![feature(no_core, lang_items, rustc_attrs, asm_experimental_arch)]
|
||||
#![feature(no_core, asm_experimental_arch)]
|
||||
#![crate_type = "rlib"]
|
||||
#![no_core]
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! asm {
|
||||
() => {};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! concat {
|
||||
() => {};
|
||||
}
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
type ptr = *const u64;
|
||||
|
||||
impl Copy for i8 {}
|
||||
impl Copy for i16 {}
|
||||
impl Copy for i32 {}
|
||||
impl Copy for i64 {}
|
||||
impl Copy for ptr {}
|
||||
|
||||
macro_rules! check {
|
||||
($func:ident $ty:ident $class:ident) => {
|
||||
#[no_mangle]
|
||||
|
|
|
|||
|
|
@ -1,38 +1,18 @@
|
|||
//@ add-core-stubs
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: --target bpfel-unknown-none -C target_feature=+alu32
|
||||
//@ needs-llvm-components: bpf
|
||||
|
||||
#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_experimental_arch)]
|
||||
#![feature(no_core, asm_experimental_arch)]
|
||||
#![crate_type = "rlib"]
|
||||
#![no_core]
|
||||
#![allow(asm_sub_register, non_camel_case_types)]
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! asm {
|
||||
() => {};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! concat {
|
||||
() => {};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! stringify {
|
||||
() => {};
|
||||
}
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
type ptr = *const u64;
|
||||
|
||||
impl Copy for i8 {}
|
||||
impl Copy for i16 {}
|
||||
impl Copy for i32 {}
|
||||
impl Copy for i64 {}
|
||||
impl Copy for ptr {}
|
||||
|
||||
macro_rules! check {
|
||||
($func:ident $ty:ident $class:ident) => {
|
||||
#[no_mangle]
|
||||
|
|
|
|||
|
|
@ -1,38 +1,19 @@
|
|||
//@ add-core-stubs
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: --target hexagon-unknown-linux-musl
|
||||
//@ compile-flags: -Zmerge-functions=disabled
|
||||
//@ needs-llvm-components: hexagon
|
||||
|
||||
#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_experimental_arch)]
|
||||
#![feature(no_core, asm_experimental_arch)]
|
||||
#![crate_type = "rlib"]
|
||||
#![no_core]
|
||||
#![allow(asm_sub_register, non_camel_case_types)]
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! asm {
|
||||
() => {};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! concat {
|
||||
() => {};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! stringify {
|
||||
() => {};
|
||||
}
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
type ptr = *const i32;
|
||||
|
||||
impl Copy for i8 {}
|
||||
impl Copy for i16 {}
|
||||
impl Copy for i32 {}
|
||||
impl Copy for f32 {}
|
||||
impl Copy for ptr {}
|
||||
extern "C" {
|
||||
fn extern_func();
|
||||
static extern_static: u8;
|
||||
|
|
|
|||
|
|
@ -1,40 +1,19 @@
|
|||
//@ add-core-stubs
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: --target loongarch64-unknown-linux-gnu
|
||||
//@ compile-flags: -Zmerge-functions=disabled
|
||||
//@ needs-llvm-components: loongarch
|
||||
|
||||
#![feature(no_core, lang_items, rustc_attrs)]
|
||||
#![feature(no_core)]
|
||||
#![crate_type = "rlib"]
|
||||
#![no_core]
|
||||
#![allow(asm_sub_register, non_camel_case_types)]
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! asm {
|
||||
() => {};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! concat {
|
||||
() => {};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! stringify {
|
||||
() => {};
|
||||
}
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
type ptr = *const i32;
|
||||
|
||||
impl Copy for i8 {}
|
||||
impl Copy for i16 {}
|
||||
impl Copy for i32 {}
|
||||
impl Copy for i64 {}
|
||||
impl Copy for f32 {}
|
||||
impl Copy for f64 {}
|
||||
impl Copy for ptr {}
|
||||
extern "C" {
|
||||
fn extern_func();
|
||||
static extern_static: u8;
|
||||
|
|
|
|||
|
|
@ -1,34 +1,18 @@
|
|||
//@ add-core-stubs
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: --target m68k-unknown-linux-gnu
|
||||
//@ needs-llvm-components: m68k
|
||||
|
||||
#![feature(no_core, lang_items, rustc_attrs, asm_experimental_arch)]
|
||||
#![feature(no_core, asm_experimental_arch)]
|
||||
#![crate_type = "rlib"]
|
||||
#![no_core]
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! asm {
|
||||
() => {};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! concat {
|
||||
() => {};
|
||||
}
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
type ptr = *const u64;
|
||||
|
||||
impl Copy for i8 {}
|
||||
impl Copy for i16 {}
|
||||
impl Copy for i32 {}
|
||||
impl Copy for i64 {}
|
||||
impl Copy for ptr {}
|
||||
|
||||
macro_rules! check {
|
||||
($func:ident $ty:ident $class:ident $mov:literal) => {
|
||||
#[no_mangle]
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//@ add-core-stubs
|
||||
//@ revisions: mips32 mips64
|
||||
//@ assembly-output: emit-asm
|
||||
//@[mips32] compile-flags: --target mips-unknown-linux-gnu
|
||||
|
|
@ -6,39 +7,16 @@
|
|||
//@[mips64] needs-llvm-components: mips
|
||||
//@ compile-flags: -Zmerge-functions=disabled
|
||||
|
||||
#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_experimental_arch)]
|
||||
#![feature(no_core, asm_experimental_arch)]
|
||||
#![crate_type = "rlib"]
|
||||
#![no_core]
|
||||
#![allow(asm_sub_register, non_camel_case_types)]
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! asm {
|
||||
() => {};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! concat {
|
||||
() => {};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! stringify {
|
||||
() => {};
|
||||
}
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
type ptr = *const i32;
|
||||
|
||||
impl Copy for i8 {}
|
||||
impl Copy for u8 {}
|
||||
impl Copy for i16 {}
|
||||
impl Copy for i32 {}
|
||||
impl Copy for i64 {}
|
||||
impl Copy for f32 {}
|
||||
impl Copy for f64 {}
|
||||
impl Copy for ptr {}
|
||||
extern "C" {
|
||||
fn extern_func();
|
||||
static extern_static: u8;
|
||||
|
|
|
|||
|
|
@ -1,34 +1,18 @@
|
|||
//@ add-core-stubs
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: --target msp430-none-elf
|
||||
//@ needs-llvm-components: msp430
|
||||
|
||||
#![feature(no_core, lang_items, rustc_attrs, asm_experimental_arch)]
|
||||
#![feature(no_core, asm_experimental_arch)]
|
||||
#![crate_type = "rlib"]
|
||||
#![no_core]
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! asm {
|
||||
() => {};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! concat {
|
||||
() => {};
|
||||
}
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
type ptr = *const i16;
|
||||
|
||||
impl Copy for i8 {}
|
||||
impl Copy for i16 {}
|
||||
impl Copy for i32 {}
|
||||
impl Copy for i64 {}
|
||||
impl Copy for ptr {}
|
||||
|
||||
macro_rules! check {
|
||||
($func:ident $ty:ident $class:ident) => {
|
||||
#[no_mangle]
|
||||
|
|
|
|||
|
|
@ -1,35 +1,17 @@
|
|||
//@ add-core-stubs
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: --target nvptx64-nvidia-cuda
|
||||
//@ compile-flags: --crate-type cdylib
|
||||
//@ needs-llvm-components: nvptx
|
||||
|
||||
#![feature(no_core, lang_items, rustc_attrs, asm_experimental_arch)]
|
||||
#![feature(no_core, asm_experimental_arch)]
|
||||
#![crate_type = "rlib"]
|
||||
#![no_core]
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! asm {
|
||||
() => {};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! concat {
|
||||
() => {};
|
||||
}
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
type ptr = *mut u8;
|
||||
|
||||
impl Copy for i8 {}
|
||||
impl Copy for i16 {}
|
||||
impl Copy for i32 {}
|
||||
impl Copy for f32 {}
|
||||
impl Copy for i64 {}
|
||||
impl Copy for f64 {}
|
||||
impl Copy for ptr {}
|
||||
|
||||
// NVPTX does not support static variables
|
||||
#[no_mangle]
|
||||
fn extern_func() {}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//@ add-core-stubs
|
||||
//@ revisions: powerpc powerpc_altivec powerpc_vsx powerpc64 powerpc64_vsx
|
||||
//@ assembly-output: emit-asm
|
||||
//@[powerpc] compile-flags: --target powerpc-unknown-linux-gnu
|
||||
|
|
@ -12,11 +13,14 @@
|
|||
//@[powerpc64_vsx] needs-llvm-components: powerpc
|
||||
//@ compile-flags: -Zmerge-functions=disabled
|
||||
|
||||
#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_experimental_arch)]
|
||||
#![feature(no_core, repr_simd, asm_experimental_arch)]
|
||||
#![crate_type = "rlib"]
|
||||
#![no_core]
|
||||
#![allow(asm_sub_register, non_camel_case_types)]
|
||||
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
#[cfg_attr(altivec, cfg(not(target_feature = "altivec")))]
|
||||
#[cfg_attr(not(altivec), cfg(target_feature = "altivec"))]
|
||||
compile_error!("altivec cfg and target feature mismatch");
|
||||
|
|
@ -24,26 +28,6 @@ compile_error!("altivec cfg and target feature mismatch");
|
|||
#[cfg_attr(not(vsx), cfg(target_feature = "vsx"))]
|
||||
compile_error!("vsx cfg and target feature mismatch");
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! asm {
|
||||
() => {};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! concat {
|
||||
() => {};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! stringify {
|
||||
() => {};
|
||||
}
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
|
||||
impl<T: Copy, const N: usize> Copy for [T; N] {}
|
||||
|
||||
type ptr = *const i32;
|
||||
|
||||
#[repr(simd)]
|
||||
|
|
@ -59,14 +43,6 @@ pub struct f32x4([f32; 4]);
|
|||
#[repr(simd)]
|
||||
pub struct f64x2([f64; 2]);
|
||||
|
||||
impl Copy for i8 {}
|
||||
impl Copy for u8 {}
|
||||
impl Copy for i16 {}
|
||||
impl Copy for i32 {}
|
||||
impl Copy for i64 {}
|
||||
impl Copy for f32 {}
|
||||
impl Copy for f64 {}
|
||||
impl Copy for ptr {}
|
||||
impl Copy for i8x16 {}
|
||||
impl Copy for i16x8 {}
|
||||
impl Copy for i32x4 {}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//@ add-core-stubs
|
||||
//@ revisions: riscv64 riscv32 riscv64-zfhmin riscv32-zfhmin riscv64-zfh riscv32-zfh
|
||||
//@ assembly-output: emit-asm
|
||||
|
||||
|
|
@ -29,40 +30,16 @@
|
|||
//@ compile-flags: -C target-feature=+d
|
||||
//@ compile-flags: -Zmerge-functions=disabled
|
||||
|
||||
#![feature(no_core, lang_items, rustc_attrs, f16)]
|
||||
#![feature(no_core, f16)]
|
||||
#![crate_type = "rlib"]
|
||||
#![no_core]
|
||||
#![allow(asm_sub_register)]
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! asm {
|
||||
() => {};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! concat {
|
||||
() => {};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! stringify {
|
||||
() => {};
|
||||
}
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
type ptr = *mut u8;
|
||||
|
||||
impl Copy for i8 {}
|
||||
impl Copy for i16 {}
|
||||
impl Copy for f16 {}
|
||||
impl Copy for i32 {}
|
||||
impl Copy for f32 {}
|
||||
impl Copy for i64 {}
|
||||
impl Copy for f64 {}
|
||||
impl Copy for ptr {}
|
||||
|
||||
extern "C" {
|
||||
fn extern_func();
|
||||
static extern_static: u8;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//@ add-core-stubs
|
||||
//@ revisions: s390x s390x_vector
|
||||
//@ assembly-output: emit-asm
|
||||
//@[s390x] compile-flags: --target s390x-unknown-linux-gnu
|
||||
|
|
@ -6,31 +7,14 @@
|
|||
//@[s390x_vector] needs-llvm-components: systemz
|
||||
//@ compile-flags: -Zmerge-functions=disabled
|
||||
|
||||
#![feature(no_core, lang_items, rustc_attrs, repr_simd, f128)]
|
||||
#![feature(no_core, repr_simd, f128)]
|
||||
#![cfg_attr(s390x_vector, feature(asm_experimental_reg))]
|
||||
#![crate_type = "rlib"]
|
||||
#![no_core]
|
||||
#![allow(asm_sub_register, non_camel_case_types)]
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! asm {
|
||||
() => {};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! concat {
|
||||
() => {};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! stringify {
|
||||
() => {};
|
||||
}
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
|
||||
impl<T: Copy, const N: usize> Copy for [T; N] {}
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
type ptr = *const i32;
|
||||
|
||||
|
|
@ -47,16 +31,6 @@ pub struct f32x4([f32; 4]);
|
|||
#[repr(simd)]
|
||||
pub struct f64x2([f64; 2]);
|
||||
|
||||
impl Copy for i8 {}
|
||||
impl Copy for u8 {}
|
||||
impl Copy for i16 {}
|
||||
impl Copy for i32 {}
|
||||
impl Copy for i64 {}
|
||||
impl Copy for i128 {}
|
||||
impl Copy for f32 {}
|
||||
impl Copy for f64 {}
|
||||
impl Copy for f128 {}
|
||||
impl Copy for ptr {}
|
||||
impl Copy for i8x16 {}
|
||||
impl Copy for i16x8 {}
|
||||
impl Copy for i32x4 {}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//@ add-core-stubs
|
||||
//@ revisions: sparc sparcv8plus sparc64
|
||||
//@ assembly-output: emit-asm
|
||||
//@[sparc] compile-flags: --target sparc-unknown-none-elf
|
||||
|
|
@ -8,40 +9,16 @@
|
|||
//@[sparc64] needs-llvm-components: sparc
|
||||
//@ compile-flags: -Zmerge-functions=disabled
|
||||
|
||||
#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_experimental_arch)]
|
||||
#![feature(no_core, asm_experimental_arch)]
|
||||
#![crate_type = "rlib"]
|
||||
#![no_core]
|
||||
#![allow(asm_sub_register, non_camel_case_types)]
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! asm {
|
||||
() => {};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! concat {
|
||||
() => {};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! stringify {
|
||||
() => {};
|
||||
}
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
type ptr = *const i32;
|
||||
|
||||
impl Copy for i8 {}
|
||||
impl Copy for u8 {}
|
||||
impl Copy for i16 {}
|
||||
impl Copy for i32 {}
|
||||
impl Copy for i64 {}
|
||||
impl Copy for f32 {}
|
||||
impl Copy for f64 {}
|
||||
impl Copy for ptr {}
|
||||
|
||||
extern "C" {
|
||||
fn extern_func();
|
||||
static extern_static: u8;
|
||||
|
|
|
|||
|
|
@ -1,35 +1,17 @@
|
|||
//@ add-core-stubs
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: --target wasm32-unknown-unknown
|
||||
//@ compile-flags: --crate-type cdylib
|
||||
//@ needs-llvm-components: webassembly
|
||||
|
||||
#![feature(no_core, lang_items, rustc_attrs, asm_experimental_arch)]
|
||||
#![feature(no_core, asm_experimental_arch)]
|
||||
#![crate_type = "rlib"]
|
||||
#![no_core]
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! asm {
|
||||
() => {};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! concat {
|
||||
() => {};
|
||||
}
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
type ptr = *mut u8;
|
||||
|
||||
impl Copy for i8 {}
|
||||
impl Copy for i16 {}
|
||||
impl Copy for i32 {}
|
||||
impl Copy for f32 {}
|
||||
impl Copy for i64 {}
|
||||
impl Copy for f64 {}
|
||||
impl Copy for ptr {}
|
||||
|
||||
extern "C" {
|
||||
fn extern_func();
|
||||
static extern_static: u8;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//@ add-core-stubs
|
||||
//@ revisions: x86_64 i686
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: -O -C panic=abort
|
||||
|
|
@ -9,30 +10,13 @@
|
|||
//@ compile-flags: -C target-feature=+avx512bw
|
||||
//@ compile-flags: -Zmerge-functions=disabled
|
||||
|
||||
#![feature(no_core, lang_items, rustc_attrs)]
|
||||
#![feature(no_core)]
|
||||
#![crate_type = "rlib"]
|
||||
#![no_core]
|
||||
#![allow(asm_sub_register)]
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! asm {
|
||||
() => {};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! concat {
|
||||
() => {};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! stringify {
|
||||
() => {};
|
||||
}
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
|
||||
impl Copy for i32 {}
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
macro_rules! check {
|
||||
($func:ident $modifier:literal $reg:ident $mov:literal) => {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//@ add-core-stubs
|
||||
//@ revisions: x86_64 i686
|
||||
//@ assembly-output: emit-asm
|
||||
//@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu
|
||||
|
|
@ -8,31 +9,13 @@
|
|||
//@ compile-flags: -C target-feature=+avx512bw
|
||||
//@ compile-flags: -Zmerge-functions=disabled
|
||||
|
||||
#![feature(no_core, lang_items, rustc_attrs, repr_simd, f16, f128)]
|
||||
#![feature(no_core, repr_simd, f16, f128)]
|
||||
#![crate_type = "rlib"]
|
||||
#![no_core]
|
||||
#![allow(asm_sub_register, non_camel_case_types)]
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! asm {
|
||||
() => {};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! concat {
|
||||
() => {};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! stringify {
|
||||
() => {};
|
||||
}
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
|
||||
// Do we really need to use no_core for this?!?
|
||||
impl<T: Copy, const N: usize> Copy for [T; N] {}
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
type ptr = *mut u8;
|
||||
|
||||
|
|
@ -90,7 +73,6 @@ macro_rules! impl_copy {
|
|||
}
|
||||
|
||||
impl_copy!(
|
||||
i8 i16 f16 i32 f32 i64 f64 f128 ptr
|
||||
i8x16 i16x8 i32x4 i64x2 f16x8 f32x4 f64x2
|
||||
i8x32 i16x16 i32x8 i64x4 f16x16 f32x8 f64x4
|
||||
i8x64 i16x32 i32x16 i64x8 f16x32 f32x16 f64x8
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
//! <https://github.com/rust-lang/rust/blob/c0b5cc9003f6464c11ae1c0662c6a7e06f6f5cab/compiler/rustc_codegen_cranelift/example/mini_core.rs>.
|
||||
// ignore-tidy-linelength
|
||||
|
||||
#![feature(no_core, lang_items, rustc_attrs, decl_macro, naked_functions)]
|
||||
#![feature(no_core, lang_items, rustc_attrs, decl_macro, naked_functions, f16, f128)]
|
||||
#![allow(unused, improper_ctypes_definitions, internal_features)]
|
||||
#![feature(asm_experimental_arch)]
|
||||
#![no_std]
|
||||
|
|
@ -40,7 +40,12 @@ impl<T: ?Sized> LegacyReceiver for &mut T {}
|
|||
pub trait Copy: Sized {}
|
||||
|
||||
impl_marker_trait!(
|
||||
Copy => [ bool, char, isize, usize, i8, i16, i32, i64, u8, u16, u32, u64, f32, f64 ]
|
||||
Copy => [
|
||||
bool, char,
|
||||
isize, i8, i16, i32, i64, i128,
|
||||
usize, u8, u16, u32, u64, u128,
|
||||
f16, f32, f64, f128,
|
||||
]
|
||||
);
|
||||
impl<'a, T: ?Sized> Copy for &'a T {}
|
||||
impl<T: ?Sized> Copy for *const T {}
|
||||
|
|
@ -88,3 +93,18 @@ pub macro naked_asm("assembly template", $(operands,)* $(options($(option),*))?)
|
|||
pub macro global_asm("assembly template", $(operands,)* $(options($(option),*))?) {
|
||||
/* compiler built-in */
|
||||
}
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
#[macro_export]
|
||||
macro_rules! concat {
|
||||
($($e:expr),* $(,)?) => {
|
||||
/* compiler built-in */
|
||||
};
|
||||
}
|
||||
#[rustc_builtin_macro]
|
||||
#[macro_export]
|
||||
macro_rules! stringify {
|
||||
($($t:tt)*) => {
|
||||
/* compiler built-in */
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
- // MIR for `opt5` before EarlyOtherwiseBranch
|
||||
+ // MIR for `opt5` after EarlyOtherwiseBranch
|
||||
|
||||
fn opt5(_1: u32, _2: u32) -> u32 {
|
||||
debug x => _1;
|
||||
debug y => _2;
|
||||
let mut _0: u32;
|
||||
let mut _3: (u32, u32);
|
||||
let mut _4: u32;
|
||||
let mut _5: u32;
|
||||
+ let mut _6: bool;
|
||||
|
||||
bb0: {
|
||||
StorageLive(_3);
|
||||
StorageLive(_4);
|
||||
_4 = copy _1;
|
||||
StorageLive(_5);
|
||||
_5 = copy _2;
|
||||
_3 = (move _4, move _5);
|
||||
StorageDead(_5);
|
||||
StorageDead(_4);
|
||||
- switchInt(copy (_3.0: u32)) -> [1: bb2, 2: bb3, 3: bb4, otherwise: bb1];
|
||||
+ StorageLive(_6);
|
||||
+ _6 = Ne(copy (_3.0: u32), copy (_3.1: u32));
|
||||
+ switchInt(move _6) -> [0: bb6, otherwise: bb1];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
+ StorageDead(_6);
|
||||
_0 = const 0_u32;
|
||||
- goto -> bb8;
|
||||
+ goto -> bb5;
|
||||
}
|
||||
|
||||
bb2: {
|
||||
- switchInt(copy (_3.1: u32)) -> [1: bb7, otherwise: bb1];
|
||||
+ _0 = const 6_u32;
|
||||
+ goto -> bb5;
|
||||
}
|
||||
|
||||
bb3: {
|
||||
- switchInt(copy (_3.1: u32)) -> [2: bb6, otherwise: bb1];
|
||||
+ _0 = const 5_u32;
|
||||
+ goto -> bb5;
|
||||
}
|
||||
|
||||
bb4: {
|
||||
- switchInt(copy (_3.1: u32)) -> [3: bb5, otherwise: bb1];
|
||||
+ _0 = const 4_u32;
|
||||
+ goto -> bb5;
|
||||
}
|
||||
|
||||
bb5: {
|
||||
- _0 = const 6_u32;
|
||||
- goto -> bb8;
|
||||
+ StorageDead(_3);
|
||||
+ return;
|
||||
}
|
||||
|
||||
bb6: {
|
||||
- _0 = const 5_u32;
|
||||
- goto -> bb8;
|
||||
- }
|
||||
-
|
||||
- bb7: {
|
||||
- _0 = const 4_u32;
|
||||
- goto -> bb8;
|
||||
- }
|
||||
-
|
||||
- bb8: {
|
||||
- StorageDead(_3);
|
||||
- return;
|
||||
+ StorageDead(_6);
|
||||
+ switchInt(copy (_3.0: u32)) -> [1: bb4, 2: bb3, 3: bb2, otherwise: bb1];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
- // MIR for `opt5_failed` before EarlyOtherwiseBranch
|
||||
+ // MIR for `opt5_failed` after EarlyOtherwiseBranch
|
||||
|
||||
fn opt5_failed(_1: u32, _2: u32) -> u32 {
|
||||
debug x => _1;
|
||||
debug y => _2;
|
||||
let mut _0: u32;
|
||||
let mut _3: (u32, u32);
|
||||
let mut _4: u32;
|
||||
let mut _5: u32;
|
||||
|
||||
bb0: {
|
||||
StorageLive(_3);
|
||||
StorageLive(_4);
|
||||
_4 = copy _1;
|
||||
StorageLive(_5);
|
||||
_5 = copy _2;
|
||||
_3 = (move _4, move _5);
|
||||
StorageDead(_5);
|
||||
StorageDead(_4);
|
||||
switchInt(copy (_3.0: u32)) -> [1: bb2, 2: bb3, 3: bb4, otherwise: bb1];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
_0 = const 0_u32;
|
||||
goto -> bb8;
|
||||
}
|
||||
|
||||
bb2: {
|
||||
switchInt(copy (_3.1: u32)) -> [1: bb7, otherwise: bb1];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
switchInt(copy (_3.1: u32)) -> [2: bb6, otherwise: bb1];
|
||||
}
|
||||
|
||||
bb4: {
|
||||
switchInt(copy (_3.1: u32)) -> [2: bb5, otherwise: bb1];
|
||||
}
|
||||
|
||||
bb5: {
|
||||
_0 = const 6_u32;
|
||||
goto -> bb8;
|
||||
}
|
||||
|
||||
bb6: {
|
||||
_0 = const 5_u32;
|
||||
goto -> bb8;
|
||||
}
|
||||
|
||||
bb7: {
|
||||
_0 = const 4_u32;
|
||||
goto -> bb8;
|
||||
}
|
||||
|
||||
bb8: {
|
||||
StorageDead(_3);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
- // MIR for `opt5_failed_type` before EarlyOtherwiseBranch
|
||||
+ // MIR for `opt5_failed_type` after EarlyOtherwiseBranch
|
||||
|
||||
fn opt5_failed_type(_1: u32, _2: u64) -> u32 {
|
||||
debug x => _1;
|
||||
debug y => _2;
|
||||
let mut _0: u32;
|
||||
let mut _3: (u32, u64);
|
||||
let mut _4: u32;
|
||||
let mut _5: u64;
|
||||
|
||||
bb0: {
|
||||
StorageLive(_3);
|
||||
StorageLive(_4);
|
||||
_4 = copy _1;
|
||||
StorageLive(_5);
|
||||
_5 = copy _2;
|
||||
_3 = (move _4, move _5);
|
||||
StorageDead(_5);
|
||||
StorageDead(_4);
|
||||
switchInt(copy (_3.0: u32)) -> [1: bb2, 2: bb3, 3: bb4, otherwise: bb1];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
_0 = const 0_u32;
|
||||
goto -> bb8;
|
||||
}
|
||||
|
||||
bb2: {
|
||||
switchInt(copy (_3.1: u64)) -> [1: bb7, otherwise: bb1];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
switchInt(copy (_3.1: u64)) -> [2: bb6, otherwise: bb1];
|
||||
}
|
||||
|
||||
bb4: {
|
||||
switchInt(copy (_3.1: u64)) -> [3: bb5, otherwise: bb1];
|
||||
}
|
||||
|
||||
bb5: {
|
||||
_0 = const 6_u32;
|
||||
goto -> bb8;
|
||||
}
|
||||
|
||||
bb6: {
|
||||
_0 = const 5_u32;
|
||||
goto -> bb8;
|
||||
}
|
||||
|
||||
bb7: {
|
||||
_0 = const 4_u32;
|
||||
goto -> bb8;
|
||||
}
|
||||
|
||||
bb8: {
|
||||
StorageDead(_3);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -78,9 +78,57 @@ fn opt4(x: Option2<u32>, y: Option2<u32>) -> u32 {
|
|||
}
|
||||
}
|
||||
|
||||
// EMIT_MIR early_otherwise_branch.opt5.EarlyOtherwiseBranch.diff
|
||||
fn opt5(x: u32, y: u32) -> u32 {
|
||||
// CHECK-LABEL: fn opt5(
|
||||
// CHECK: let mut [[CMP_LOCAL:_.*]]: bool;
|
||||
// CHECK: bb0: {
|
||||
// CHECK: [[CMP_LOCAL]] = Ne(
|
||||
// CHECK: switchInt(move [[CMP_LOCAL]]) -> [
|
||||
// CHECK-NEXT: }
|
||||
match (x, y) {
|
||||
(1, 1) => 4,
|
||||
(2, 2) => 5,
|
||||
(3, 3) => 6,
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
// EMIT_MIR early_otherwise_branch.opt5_failed.EarlyOtherwiseBranch.diff
|
||||
fn opt5_failed(x: u32, y: u32) -> u32 {
|
||||
// CHECK-LABEL: fn opt5_failed(
|
||||
// CHECK: bb0: {
|
||||
// CHECK-NOT: Ne(
|
||||
// CHECK: switchInt(
|
||||
// CHECK-NEXT: }
|
||||
match (x, y) {
|
||||
(1, 1) => 4,
|
||||
(2, 2) => 5,
|
||||
(3, 2) => 6,
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
// EMIT_MIR early_otherwise_branch.opt5_failed_type.EarlyOtherwiseBranch.diff
|
||||
fn opt5_failed_type(x: u32, y: u64) -> u32 {
|
||||
// CHECK-LABEL: fn opt5_failed_type(
|
||||
// CHECK: bb0: {
|
||||
// CHECK-NOT: Ne(
|
||||
// CHECK: switchInt(
|
||||
// CHECK-NEXT: }
|
||||
match (x, y) {
|
||||
(1, 1) => 4,
|
||||
(2, 2) => 5,
|
||||
(3, 3) => 6,
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
opt1(None, Some(0));
|
||||
opt2(None, Some(0));
|
||||
opt3(Option2::None, Option2::Some(false));
|
||||
opt4(Option2::None, Option2::Some(0));
|
||||
opt5(0, 0);
|
||||
opt5_failed(0, 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,126 @@
|
|||
- // MIR for `poll` before EarlyOtherwiseBranch
|
||||
+ // MIR for `poll` after EarlyOtherwiseBranch
|
||||
|
||||
fn poll(_1: Poll<Result<Option<Vec<u8>>, u8>>) -> () {
|
||||
debug val => _1;
|
||||
let mut _0: ();
|
||||
let mut _2: isize;
|
||||
let mut _3: isize;
|
||||
let mut _4: isize;
|
||||
let _5: std::vec::Vec<u8>;
|
||||
let _6: u8;
|
||||
let mut _7: bool;
|
||||
let mut _8: bool;
|
||||
let mut _9: isize;
|
||||
scope 1 {
|
||||
debug _trailers => _5;
|
||||
}
|
||||
scope 2 {
|
||||
debug _err => _6;
|
||||
}
|
||||
|
||||
bb0: {
|
||||
_7 = const false;
|
||||
_8 = const false;
|
||||
_7 = const true;
|
||||
_8 = const true;
|
||||
_4 = discriminant(_1);
|
||||
switchInt(copy _4) -> [0: bb2, 1: bb4, otherwise: bb1];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
unreachable;
|
||||
}
|
||||
|
||||
bb2: {
|
||||
_3 = discriminant(((_1 as Ready).0: std::result::Result<std::option::Option<std::vec::Vec<u8>>, u8>));
|
||||
switchInt(copy _3) -> [0: bb3, 1: bb6, otherwise: bb1];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
_2 = discriminant(((((_1 as Ready).0: std::result::Result<std::option::Option<std::vec::Vec<u8>>, u8>) as Ok).0: std::option::Option<std::vec::Vec<u8>>));
|
||||
switchInt(copy _2) -> [0: bb5, 1: bb7, otherwise: bb1];
|
||||
}
|
||||
|
||||
bb4: {
|
||||
_0 = const ();
|
||||
goto -> bb17;
|
||||
}
|
||||
|
||||
bb5: {
|
||||
_0 = const ();
|
||||
goto -> bb17;
|
||||
}
|
||||
|
||||
bb6: {
|
||||
StorageLive(_6);
|
||||
_6 = copy ((((_1 as Ready).0: std::result::Result<std::option::Option<std::vec::Vec<u8>>, u8>) as Err).0: u8);
|
||||
_0 = const ();
|
||||
StorageDead(_6);
|
||||
goto -> bb17;
|
||||
}
|
||||
|
||||
bb7: {
|
||||
StorageLive(_5);
|
||||
_5 = move ((((((_1 as Ready).0: std::result::Result<std::option::Option<std::vec::Vec<u8>>, u8>) as Ok).0: std::option::Option<std::vec::Vec<u8>>) as Some).0: std::vec::Vec<u8>);
|
||||
_0 = const ();
|
||||
drop(_5) -> [return: bb8, unwind: bb20];
|
||||
}
|
||||
|
||||
bb8: {
|
||||
StorageDead(_5);
|
||||
goto -> bb17;
|
||||
}
|
||||
|
||||
bb9 (cleanup): {
|
||||
resume;
|
||||
}
|
||||
|
||||
bb10: {
|
||||
return;
|
||||
}
|
||||
|
||||
bb11: {
|
||||
switchInt(copy _7) -> [0: bb12, otherwise: bb16];
|
||||
}
|
||||
|
||||
bb12: {
|
||||
_7 = const false;
|
||||
goto -> bb10;
|
||||
}
|
||||
|
||||
bb13: {
|
||||
switchInt(copy _8) -> [0: bb14, otherwise: bb15];
|
||||
}
|
||||
|
||||
bb14: {
|
||||
_8 = const false;
|
||||
goto -> bb12;
|
||||
}
|
||||
|
||||
bb15: {
|
||||
goto -> bb14;
|
||||
}
|
||||
|
||||
bb16: {
|
||||
_9 = discriminant(((_1 as Ready).0: std::result::Result<std::option::Option<std::vec::Vec<u8>>, u8>));
|
||||
switchInt(move _9) -> [0: bb13, otherwise: bb12];
|
||||
}
|
||||
|
||||
bb17: {
|
||||
switchInt(copy _4) -> [0: bb11, otherwise: bb10];
|
||||
}
|
||||
|
||||
bb18 (cleanup): {
|
||||
switchInt(copy _3) -> [0: bb19, otherwise: bb9];
|
||||
}
|
||||
|
||||
bb19 (cleanup): {
|
||||
goto -> bb9;
|
||||
}
|
||||
|
||||
bb20 (cleanup): {
|
||||
switchInt(copy _4) -> [0: bb18, otherwise: bb9];
|
||||
}
|
||||
}
|
||||
|
||||
38
tests/mir-opt/early_otherwise_branch_unwind.rs
Normal file
38
tests/mir-opt/early_otherwise_branch_unwind.rs
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
//@ test-mir-pass: EarlyOtherwiseBranch
|
||||
//@ compile-flags: -Zmir-enable-passes=+GVN,+SimplifyLocals-after-value-numbering
|
||||
//@ needs-unwind
|
||||
|
||||
use std::task::Poll;
|
||||
|
||||
// We find a matching pattern in the unwind path,
|
||||
// and we need to create a cleanup BB for this case to meet the unwind invariants rule.
|
||||
// NB: This transform is not happening currently.
|
||||
|
||||
// EMIT_MIR early_otherwise_branch_unwind.unwind.EarlyOtherwiseBranch.diff
|
||||
fn unwind<T>(val: Option<Option<Option<T>>>) {
|
||||
// CHECK-LABEL: fn unwind(
|
||||
// CHECK: drop({{.*}}) -> [return: bb{{.*}}, unwind: [[PARENT_UNWIND_BB:bb.*]]];
|
||||
// CHECK: [[PARENT_UNWIND_BB]] (cleanup): {
|
||||
// CHECK-NEXT: switchInt
|
||||
match val {
|
||||
Some(Some(Some(_v))) => {}
|
||||
Some(Some(None)) => {}
|
||||
Some(None) => {}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
||||
// From https://github.com/rust-lang/rust/issues/130769#issuecomment-2370443086.
|
||||
// EMIT_MIR early_otherwise_branch_unwind.poll.EarlyOtherwiseBranch.diff
|
||||
pub fn poll(val: Poll<Result<Option<Vec<u8>>, u8>>) {
|
||||
// CHECK-LABEL: fn poll(
|
||||
// CHECK: drop({{.*}}) -> [return: bb{{.*}}, unwind: [[PARENT_UNWIND_BB:bb.*]]];
|
||||
// CHECK: [[PARENT_UNWIND_BB]] (cleanup): {
|
||||
// CHECK-NEXT: switchInt
|
||||
match val {
|
||||
Poll::Ready(Ok(Some(_trailers))) => {}
|
||||
Poll::Ready(Err(_err)) => {}
|
||||
Poll::Ready(Ok(None)) => {}
|
||||
Poll::Pending => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
- // MIR for `unwind` before EarlyOtherwiseBranch
|
||||
+ // MIR for `unwind` after EarlyOtherwiseBranch
|
||||
|
||||
fn unwind(_1: Option<Option<Option<T>>>) -> () {
|
||||
debug val => _1;
|
||||
let mut _0: ();
|
||||
let mut _2: isize;
|
||||
let mut _3: isize;
|
||||
let mut _4: isize;
|
||||
let _5: T;
|
||||
let mut _6: bool;
|
||||
let mut _7: bool;
|
||||
let mut _8: isize;
|
||||
scope 1 {
|
||||
debug _v => _5;
|
||||
}
|
||||
|
||||
bb0: {
|
||||
_6 = const false;
|
||||
_7 = const false;
|
||||
_6 = const true;
|
||||
_7 = const true;
|
||||
_4 = discriminant(_1);
|
||||
switchInt(copy _4) -> [0: bb4, 1: bb2, otherwise: bb1];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
unreachable;
|
||||
}
|
||||
|
||||
bb2: {
|
||||
_3 = discriminant(((_1 as Some).0: std::option::Option<std::option::Option<T>>));
|
||||
switchInt(copy _3) -> [0: bb5, 1: bb3, otherwise: bb1];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
_2 = discriminant(((((_1 as Some).0: std::option::Option<std::option::Option<T>>) as Some).0: std::option::Option<T>));
|
||||
switchInt(copy _2) -> [0: bb6, 1: bb7, otherwise: bb1];
|
||||
}
|
||||
|
||||
bb4: {
|
||||
_0 = const ();
|
||||
goto -> bb17;
|
||||
}
|
||||
|
||||
bb5: {
|
||||
_0 = const ();
|
||||
goto -> bb17;
|
||||
}
|
||||
|
||||
bb6: {
|
||||
_0 = const ();
|
||||
goto -> bb17;
|
||||
}
|
||||
|
||||
bb7: {
|
||||
StorageLive(_5);
|
||||
_5 = move ((((((_1 as Some).0: std::option::Option<std::option::Option<T>>) as Some).0: std::option::Option<T>) as Some).0: T);
|
||||
_0 = const ();
|
||||
drop(_5) -> [return: bb8, unwind: bb20];
|
||||
}
|
||||
|
||||
bb8: {
|
||||
StorageDead(_5);
|
||||
goto -> bb17;
|
||||
}
|
||||
|
||||
bb9 (cleanup): {
|
||||
resume;
|
||||
}
|
||||
|
||||
bb10: {
|
||||
return;
|
||||
}
|
||||
|
||||
bb11: {
|
||||
switchInt(copy _6) -> [0: bb12, otherwise: bb16];
|
||||
}
|
||||
|
||||
bb12: {
|
||||
_6 = const false;
|
||||
goto -> bb10;
|
||||
}
|
||||
|
||||
bb13: {
|
||||
switchInt(copy _7) -> [0: bb14, otherwise: bb15];
|
||||
}
|
||||
|
||||
bb14: {
|
||||
_7 = const false;
|
||||
goto -> bb12;
|
||||
}
|
||||
|
||||
bb15: {
|
||||
goto -> bb14;
|
||||
}
|
||||
|
||||
bb16: {
|
||||
_8 = discriminant(((_1 as Some).0: std::option::Option<std::option::Option<T>>));
|
||||
switchInt(move _8) -> [1: bb13, otherwise: bb12];
|
||||
}
|
||||
|
||||
bb17: {
|
||||
switchInt(copy _4) -> [1: bb11, otherwise: bb10];
|
||||
}
|
||||
|
||||
bb18 (cleanup): {
|
||||
switchInt(copy _3) -> [1: bb19, otherwise: bb9];
|
||||
}
|
||||
|
||||
bb19 (cleanup): {
|
||||
goto -> bb9;
|
||||
}
|
||||
|
||||
bb20 (cleanup): {
|
||||
switchInt(copy _4) -> [1: bb18, otherwise: bb9];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -23,22 +23,22 @@ fn main() {
|
|||
assert_type_eq(x, &mut 0u8);
|
||||
|
||||
let &Foo(mut x) = &Foo(0);
|
||||
//~^ ERROR: patterns are not allowed to reset the default binding mode
|
||||
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
assert_type_eq(x, 0u8);
|
||||
|
||||
let &mut Foo(mut x) = &mut Foo(0);
|
||||
//~^ ERROR: patterns are not allowed to reset the default binding mode
|
||||
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
assert_type_eq(x, 0u8);
|
||||
|
||||
let &Foo(ref x) = &Foo(0);
|
||||
//~^ ERROR: patterns are not allowed to reset the default binding mode
|
||||
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
assert_type_eq(x, &0u8);
|
||||
|
||||
let &mut Foo(ref x) = &mut Foo(0);
|
||||
//~^ ERROR: patterns are not allowed to reset the default binding mode
|
||||
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
assert_type_eq(x, &0u8);
|
||||
|
||||
|
|
@ -55,22 +55,22 @@ fn main() {
|
|||
assert_type_eq(x, &0u8);
|
||||
|
||||
let &Foo(&x) = &Foo(&0);
|
||||
//~^ ERROR: patterns are not allowed to reset the default binding mode
|
||||
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
assert_type_eq(x, 0u8);
|
||||
|
||||
let &Foo(&mut x) = &Foo(&mut 0);
|
||||
//~^ ERROR: patterns are not allowed to reset the default binding mode
|
||||
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
assert_type_eq(x, 0u8);
|
||||
|
||||
let &mut Foo(&x) = &mut Foo(&0);
|
||||
//~^ ERROR: patterns are not allowed to reset the default binding mode
|
||||
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
assert_type_eq(x, 0u8);
|
||||
|
||||
let &mut Foo(&mut x) = &mut Foo(&mut 0);
|
||||
//~^ ERROR: patterns are not allowed to reset the default binding mode
|
||||
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
assert_type_eq(x, 0u8);
|
||||
|
||||
|
|
@ -79,25 +79,25 @@ fn main() {
|
|||
}
|
||||
|
||||
if let &&&&&Some(&x) = &&&&&Some(&0u8) {
|
||||
//~^ ERROR: patterns are not allowed to reset the default binding mode
|
||||
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
assert_type_eq(x, 0u8);
|
||||
}
|
||||
|
||||
if let &&&&&Some(&mut x) = &&&&&Some(&mut 0u8) {
|
||||
//~^ ERROR: patterns are not allowed to reset the default binding mode
|
||||
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
assert_type_eq(x, 0u8);
|
||||
}
|
||||
|
||||
if let &&&&&mut Some(&x) = &&&&&mut Some(&0u8) {
|
||||
//~^ ERROR: patterns are not allowed to reset the default binding mode
|
||||
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
assert_type_eq(x, 0u8);
|
||||
}
|
||||
|
||||
if let &mut Some(&mut Some(&mut Some(ref mut x))) = &mut Some(&mut Some(&mut Some(0u8))) {
|
||||
//~^ ERROR: patterns are not allowed to reset the default binding mode
|
||||
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
assert_type_eq(x, &mut 0u8);
|
||||
}
|
||||
|
|
@ -109,20 +109,20 @@ fn main() {
|
|||
}
|
||||
|
||||
let &Struct { ref a, mut b, ref c } = &Struct { a: 0, b: 0, c: 0 };
|
||||
//~^ ERROR: patterns are not allowed to reset the default binding mode
|
||||
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
assert_type_eq(a, &0u32);
|
||||
assert_type_eq(b, 0u32);
|
||||
|
||||
let &Struct { a: &a, ref b, ref c } = &Struct { a: &0, b: &0, c: &0 };
|
||||
//~^ ERROR: patterns are not allowed to reset the default binding mode
|
||||
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
assert_type_eq(a, 0u32);
|
||||
assert_type_eq(b, &&0u32);
|
||||
assert_type_eq(c, &&0u32);
|
||||
|
||||
if let &Struct { a: &Some(a), b: &Some(&b), c: &Some(ref c) } =
|
||||
//~^ ERROR: patterns are not allowed to reset the default binding mode
|
||||
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
&(Struct { a: &Some(&0), b: &Some(&0), c: &Some(&0) })
|
||||
{
|
||||
|
|
@ -135,7 +135,7 @@ fn main() {
|
|||
// The two patterns are the same syntactically, but because they're defined in different
|
||||
// editions they don't mean the same thing.
|
||||
&(Some(mut x), migration_lint_macros::mixed_edition_pat!(y)) => {
|
||||
//~^ ERROR: patterns are not allowed to reset the default binding mode
|
||||
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
|
||||
assert_type_eq(x, 0u32);
|
||||
assert_type_eq(y, 0u32);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,22 +23,22 @@ fn main() {
|
|||
assert_type_eq(x, &mut 0u8);
|
||||
|
||||
let Foo(mut x) = &Foo(0);
|
||||
//~^ ERROR: patterns are not allowed to reset the default binding mode
|
||||
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
assert_type_eq(x, 0u8);
|
||||
|
||||
let Foo(mut x) = &mut Foo(0);
|
||||
//~^ ERROR: patterns are not allowed to reset the default binding mode
|
||||
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
assert_type_eq(x, 0u8);
|
||||
|
||||
let Foo(ref x) = &Foo(0);
|
||||
//~^ ERROR: patterns are not allowed to reset the default binding mode
|
||||
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
assert_type_eq(x, &0u8);
|
||||
|
||||
let Foo(ref x) = &mut Foo(0);
|
||||
//~^ ERROR: patterns are not allowed to reset the default binding mode
|
||||
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
assert_type_eq(x, &0u8);
|
||||
|
||||
|
|
@ -55,22 +55,22 @@ fn main() {
|
|||
assert_type_eq(x, &0u8);
|
||||
|
||||
let Foo(&x) = &Foo(&0);
|
||||
//~^ ERROR: patterns are not allowed to reset the default binding mode
|
||||
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
assert_type_eq(x, 0u8);
|
||||
|
||||
let Foo(&mut x) = &Foo(&mut 0);
|
||||
//~^ ERROR: patterns are not allowed to reset the default binding mode
|
||||
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
assert_type_eq(x, 0u8);
|
||||
|
||||
let Foo(&x) = &mut Foo(&0);
|
||||
//~^ ERROR: patterns are not allowed to reset the default binding mode
|
||||
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
assert_type_eq(x, 0u8);
|
||||
|
||||
let Foo(&mut x) = &mut Foo(&mut 0);
|
||||
//~^ ERROR: patterns are not allowed to reset the default binding mode
|
||||
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
assert_type_eq(x, 0u8);
|
||||
|
||||
|
|
@ -79,25 +79,25 @@ fn main() {
|
|||
}
|
||||
|
||||
if let Some(&x) = &&&&&Some(&0u8) {
|
||||
//~^ ERROR: patterns are not allowed to reset the default binding mode
|
||||
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
assert_type_eq(x, 0u8);
|
||||
}
|
||||
|
||||
if let Some(&mut x) = &&&&&Some(&mut 0u8) {
|
||||
//~^ ERROR: patterns are not allowed to reset the default binding mode
|
||||
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
assert_type_eq(x, 0u8);
|
||||
}
|
||||
|
||||
if let Some(&x) = &&&&&mut Some(&0u8) {
|
||||
//~^ ERROR: patterns are not allowed to reset the default binding mode
|
||||
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
assert_type_eq(x, 0u8);
|
||||
}
|
||||
|
||||
if let Some(&mut Some(Some(x))) = &mut Some(&mut Some(&mut Some(0u8))) {
|
||||
//~^ ERROR: patterns are not allowed to reset the default binding mode
|
||||
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
assert_type_eq(x, &mut 0u8);
|
||||
}
|
||||
|
|
@ -109,20 +109,20 @@ fn main() {
|
|||
}
|
||||
|
||||
let Struct { a, mut b, c } = &Struct { a: 0, b: 0, c: 0 };
|
||||
//~^ ERROR: patterns are not allowed to reset the default binding mode
|
||||
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
assert_type_eq(a, &0u32);
|
||||
assert_type_eq(b, 0u32);
|
||||
|
||||
let Struct { a: &a, b, ref c } = &Struct { a: &0, b: &0, c: &0 };
|
||||
//~^ ERROR: patterns are not allowed to reset the default binding mode
|
||||
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
assert_type_eq(a, 0u32);
|
||||
assert_type_eq(b, &&0u32);
|
||||
assert_type_eq(c, &&0u32);
|
||||
|
||||
if let Struct { a: &Some(a), b: Some(&b), c: Some(c) } =
|
||||
//~^ ERROR: patterns are not allowed to reset the default binding mode
|
||||
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
&(Struct { a: &Some(&0), b: &Some(&0), c: &Some(&0) })
|
||||
{
|
||||
|
|
@ -135,7 +135,7 @@ fn main() {
|
|||
// The two patterns are the same syntactically, but because they're defined in different
|
||||
// editions they don't mean the same thing.
|
||||
(Some(mut x), migration_lint_macros::mixed_edition_pat!(y)) => {
|
||||
//~^ ERROR: patterns are not allowed to reset the default binding mode
|
||||
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
|
||||
assert_type_eq(x, 0u32);
|
||||
assert_type_eq(y, 0u32);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
error: patterns are not allowed to reset the default binding mode in edition 2024
|
||||
--> $DIR/migration_lint.rs:25:9
|
||||
error: this pattern relies on behavior which may change in edition 2024
|
||||
--> $DIR/migration_lint.rs:25:13
|
||||
|
|
||||
LL | let Foo(mut x) = &Foo(0);
|
||||
| -^^^^^^^^^
|
||||
| |
|
||||
| help: desugar the match ergonomics: `&`
|
||||
| ^^^ requires binding by-value, but the implicit default is by-reference
|
||||
|
|
||||
= warning: this changes meaning in Rust 2024
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
|
||||
|
|
@ -13,176 +11,211 @@ note: the lint level is defined here
|
|||
|
|
||||
LL | #![deny(rust_2024_incompatible_pat)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: make the implied reference pattern explicit
|
||||
|
|
||||
LL | let &Foo(mut x) = &Foo(0);
|
||||
| +
|
||||
|
||||
error: patterns are not allowed to reset the default binding mode in edition 2024
|
||||
--> $DIR/migration_lint.rs:30:9
|
||||
error: this pattern relies on behavior which may change in edition 2024
|
||||
--> $DIR/migration_lint.rs:30:13
|
||||
|
|
||||
LL | let Foo(mut x) = &mut Foo(0);
|
||||
| -^^^^^^^^^
|
||||
| |
|
||||
| help: desugar the match ergonomics: `&mut`
|
||||
| ^^^ requires binding by-value, but the implicit default is by-reference
|
||||
|
|
||||
= warning: this changes meaning in Rust 2024
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
|
||||
help: make the implied reference pattern explicit
|
||||
|
|
||||
LL | let &mut Foo(mut x) = &mut Foo(0);
|
||||
| ++++
|
||||
|
||||
error: patterns are not allowed to reset the default binding mode in edition 2024
|
||||
--> $DIR/migration_lint.rs:35:9
|
||||
error: this pattern relies on behavior which may change in edition 2024
|
||||
--> $DIR/migration_lint.rs:35:13
|
||||
|
|
||||
LL | let Foo(ref x) = &Foo(0);
|
||||
| -^^^^^^^^^
|
||||
| |
|
||||
| help: desugar the match ergonomics: `&`
|
||||
| ^^^ cannot override to bind by-reference when that is the implicit default
|
||||
|
|
||||
= warning: this changes meaning in Rust 2024
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
|
||||
help: make the implied reference pattern explicit
|
||||
|
|
||||
LL | let &Foo(ref x) = &Foo(0);
|
||||
| +
|
||||
|
||||
error: patterns are not allowed to reset the default binding mode in edition 2024
|
||||
--> $DIR/migration_lint.rs:40:9
|
||||
error: this pattern relies on behavior which may change in edition 2024
|
||||
--> $DIR/migration_lint.rs:40:13
|
||||
|
|
||||
LL | let Foo(ref x) = &mut Foo(0);
|
||||
| -^^^^^^^^^
|
||||
| |
|
||||
| help: desugar the match ergonomics: `&mut`
|
||||
| ^^^ cannot override to bind by-reference when that is the implicit default
|
||||
|
|
||||
= warning: this changes meaning in Rust 2024
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
|
||||
help: make the implied reference pattern explicit
|
||||
|
|
||||
LL | let &mut Foo(ref x) = &mut Foo(0);
|
||||
| ++++
|
||||
|
||||
error: patterns are not allowed to reset the default binding mode in edition 2024
|
||||
--> $DIR/migration_lint.rs:57:9
|
||||
error: this pattern relies on behavior which may change in edition 2024
|
||||
--> $DIR/migration_lint.rs:57:13
|
||||
|
|
||||
LL | let Foo(&x) = &Foo(&0);
|
||||
| -^^^^^^
|
||||
| |
|
||||
| help: desugar the match ergonomics: `&`
|
||||
| ^ cannot implicitly match against multiple layers of reference
|
||||
|
|
||||
= warning: this changes meaning in Rust 2024
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
|
||||
help: make the implied reference pattern explicit
|
||||
|
|
||||
LL | let &Foo(&x) = &Foo(&0);
|
||||
| +
|
||||
|
||||
error: patterns are not allowed to reset the default binding mode in edition 2024
|
||||
--> $DIR/migration_lint.rs:62:9
|
||||
error: this pattern relies on behavior which may change in edition 2024
|
||||
--> $DIR/migration_lint.rs:62:13
|
||||
|
|
||||
LL | let Foo(&mut x) = &Foo(&mut 0);
|
||||
| -^^^^^^^^^^
|
||||
| |
|
||||
| help: desugar the match ergonomics: `&`
|
||||
| ^^^^ cannot implicitly match against multiple layers of reference
|
||||
|
|
||||
= warning: this changes meaning in Rust 2024
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
|
||||
help: make the implied reference pattern explicit
|
||||
|
|
||||
LL | let &Foo(&mut x) = &Foo(&mut 0);
|
||||
| +
|
||||
|
||||
error: patterns are not allowed to reset the default binding mode in edition 2024
|
||||
--> $DIR/migration_lint.rs:67:9
|
||||
error: this pattern relies on behavior which may change in edition 2024
|
||||
--> $DIR/migration_lint.rs:67:13
|
||||
|
|
||||
LL | let Foo(&x) = &mut Foo(&0);
|
||||
| -^^^^^^
|
||||
| |
|
||||
| help: desugar the match ergonomics: `&mut`
|
||||
| ^ cannot implicitly match against multiple layers of reference
|
||||
|
|
||||
= warning: this changes meaning in Rust 2024
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
|
||||
help: make the implied reference pattern explicit
|
||||
|
|
||||
LL | let &mut Foo(&x) = &mut Foo(&0);
|
||||
| ++++
|
||||
|
||||
error: patterns are not allowed to reset the default binding mode in edition 2024
|
||||
--> $DIR/migration_lint.rs:72:9
|
||||
error: this pattern relies on behavior which may change in edition 2024
|
||||
--> $DIR/migration_lint.rs:72:13
|
||||
|
|
||||
LL | let Foo(&mut x) = &mut Foo(&mut 0);
|
||||
| -^^^^^^^^^^
|
||||
| |
|
||||
| help: desugar the match ergonomics: `&mut`
|
||||
| ^^^^ cannot implicitly match against multiple layers of reference
|
||||
|
|
||||
= warning: this changes meaning in Rust 2024
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
|
||||
help: make the implied reference pattern explicit
|
||||
|
|
||||
LL | let &mut Foo(&mut x) = &mut Foo(&mut 0);
|
||||
| ++++
|
||||
|
||||
error: patterns are not allowed to reset the default binding mode in edition 2024
|
||||
--> $DIR/migration_lint.rs:81:12
|
||||
error: this pattern relies on behavior which may change in edition 2024
|
||||
--> $DIR/migration_lint.rs:81:17
|
||||
|
|
||||
LL | if let Some(&x) = &&&&&Some(&0u8) {
|
||||
| -^^^^^^^
|
||||
| |
|
||||
| help: desugar the match ergonomics: `&&&&&`
|
||||
| ^ cannot implicitly match against multiple layers of reference
|
||||
|
|
||||
= warning: this changes meaning in Rust 2024
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
|
||||
help: make the implied reference patterns explicit
|
||||
|
|
||||
LL | if let &&&&&Some(&x) = &&&&&Some(&0u8) {
|
||||
| +++++
|
||||
|
||||
error: patterns are not allowed to reset the default binding mode in edition 2024
|
||||
--> $DIR/migration_lint.rs:87:12
|
||||
error: this pattern relies on behavior which may change in edition 2024
|
||||
--> $DIR/migration_lint.rs:87:17
|
||||
|
|
||||
LL | if let Some(&mut x) = &&&&&Some(&mut 0u8) {
|
||||
| -^^^^^^^^^^^
|
||||
| |
|
||||
| help: desugar the match ergonomics: `&&&&&`
|
||||
| ^^^^ cannot implicitly match against multiple layers of reference
|
||||
|
|
||||
= warning: this changes meaning in Rust 2024
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
|
||||
help: make the implied reference patterns explicit
|
||||
|
|
||||
LL | if let &&&&&Some(&mut x) = &&&&&Some(&mut 0u8) {
|
||||
| +++++
|
||||
|
||||
error: patterns are not allowed to reset the default binding mode in edition 2024
|
||||
--> $DIR/migration_lint.rs:93:12
|
||||
error: this pattern relies on behavior which may change in edition 2024
|
||||
--> $DIR/migration_lint.rs:93:17
|
||||
|
|
||||
LL | if let Some(&x) = &&&&&mut Some(&0u8) {
|
||||
| -^^^^^^^
|
||||
| |
|
||||
| help: desugar the match ergonomics: `&&&&&mut`
|
||||
| ^ cannot implicitly match against multiple layers of reference
|
||||
|
|
||||
= warning: this changes meaning in Rust 2024
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
|
||||
help: make the implied reference patterns explicit
|
||||
|
|
||||
LL | if let &&&&&mut Some(&x) = &&&&&mut Some(&0u8) {
|
||||
| ++++++++
|
||||
|
||||
error: patterns are not allowed to reset the default binding mode in edition 2024
|
||||
--> $DIR/migration_lint.rs:99:12
|
||||
error: this pattern relies on behavior which may change in edition 2024
|
||||
--> $DIR/migration_lint.rs:99:17
|
||||
|
|
||||
LL | if let Some(&mut Some(Some(x))) = &mut Some(&mut Some(&mut Some(0u8))) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^ cannot implicitly match against multiple layers of reference
|
||||
|
|
||||
= warning: this changes meaning in Rust 2024
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
|
||||
help: desugar the match ergonomics
|
||||
help: make the implied reference patterns and variable binding mode explicit
|
||||
|
|
||||
LL | if let &mut Some(&mut Some(&mut Some(ref mut x))) = &mut Some(&mut Some(&mut Some(0u8))) {
|
||||
| ++++ ++++ +++++++
|
||||
|
||||
error: patterns are not allowed to reset the default binding mode in edition 2024
|
||||
--> $DIR/migration_lint.rs:111:9
|
||||
error: this pattern relies on behavior which may change in edition 2024
|
||||
--> $DIR/migration_lint.rs:111:21
|
||||
|
|
||||
LL | let Struct { a, mut b, c } = &Struct { a: 0, b: 0, c: 0 };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^ requires binding by-value, but the implicit default is by-reference
|
||||
|
|
||||
= warning: this changes meaning in Rust 2024
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
|
||||
help: desugar the match ergonomics
|
||||
help: make the implied reference pattern and variable binding modes explicit
|
||||
|
|
||||
LL | let &Struct { ref a, mut b, ref c } = &Struct { a: 0, b: 0, c: 0 };
|
||||
| + +++ +++
|
||||
|
||||
error: patterns are not allowed to reset the default binding mode in edition 2024
|
||||
--> $DIR/migration_lint.rs:117:9
|
||||
error: this pattern relies on behavior which may change in edition 2024
|
||||
--> $DIR/migration_lint.rs:117:21
|
||||
|
|
||||
LL | let Struct { a: &a, b, ref c } = &Struct { a: &0, b: &0, c: &0 };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^ ^^^ cannot override to bind by-reference when that is the implicit default
|
||||
| |
|
||||
| cannot implicitly match against multiple layers of reference
|
||||
|
|
||||
= warning: this changes meaning in Rust 2024
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
|
||||
help: desugar the match ergonomics
|
||||
help: make the implied reference pattern and variable binding mode explicit
|
||||
|
|
||||
LL | let &Struct { a: &a, ref b, ref c } = &Struct { a: &0, b: &0, c: &0 };
|
||||
| + +++
|
||||
|
||||
error: patterns are not allowed to reset the default binding mode in edition 2024
|
||||
--> $DIR/migration_lint.rs:124:12
|
||||
error: this pattern relies on behavior which may change in edition 2024
|
||||
--> $DIR/migration_lint.rs:124:24
|
||||
|
|
||||
LL | if let Struct { a: &Some(a), b: Some(&b), c: Some(c) } =
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^ ^ cannot implicitly match against multiple layers of reference
|
||||
| |
|
||||
| cannot implicitly match against multiple layers of reference
|
||||
|
|
||||
= warning: this changes meaning in Rust 2024
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
|
||||
help: desugar the match ergonomics
|
||||
help: make the implied reference patterns and variable binding mode explicit
|
||||
|
|
||||
LL | if let &Struct { a: &Some(a), b: &Some(&b), c: &Some(ref c) } =
|
||||
| + + + +++
|
||||
|
||||
error: patterns are not allowed to reset the default binding mode in edition 2024
|
||||
--> $DIR/migration_lint.rs:137:9
|
||||
error: this pattern relies on behavior which may change in edition 2024
|
||||
--> $DIR/migration_lint.rs:137:15
|
||||
|
|
||||
LL | (Some(mut x), migration_lint_macros::mixed_edition_pat!(y)) => {
|
||||
| -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| help: desugar the match ergonomics: `&`
|
||||
| ^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ default binding mode is reset within expansion
|
||||
| |
|
||||
| requires binding by-value, but the implicit default is by-reference
|
||||
|
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
|
||||
= note: this error originates in the macro `migration_lint_macros::mixed_edition_pat` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: make the implied reference pattern explicit
|
||||
|
|
||||
LL | &(Some(mut x), migration_lint_macros::mixed_edition_pat!(y)) => {
|
||||
| +
|
||||
|
||||
error: aborting due to 16 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -21,17 +21,17 @@ macro_rules! test_pat_on_type {
|
|||
}
|
||||
|
||||
test_pat_on_type![(&x,): &(T,)]; //~ ERROR mismatched types
|
||||
test_pat_on_type![(&x,): &(&T,)]; //~ ERROR patterns are not allowed to reset the default binding mode
|
||||
test_pat_on_type![(&x,): &(&T,)]; //~ ERROR this pattern relies on behavior which may change in edition 2024
|
||||
test_pat_on_type![(&x,): &(&mut T,)]; //~ ERROR mismatched types
|
||||
test_pat_on_type![(&mut x,): &(&T,)]; //~ ERROR mismatched types
|
||||
test_pat_on_type![(&mut x,): &(&mut T,)]; //~ ERROR patterns are not allowed to reset the default binding mode
|
||||
test_pat_on_type![(&mut x,): &(&mut T,)]; //~ ERROR this pattern relies on behavior which may change in edition 2024
|
||||
test_pat_on_type![(&x,): &&mut &(T,)]; //~ ERROR mismatched types
|
||||
test_pat_on_type![Foo { f: (&x,) }: Foo]; //~ ERROR mismatched types
|
||||
test_pat_on_type![Foo { f: (&x,) }: &mut Foo]; //~ ERROR mismatched types
|
||||
test_pat_on_type![Foo { f: &(x,) }: &Foo]; //~ ERROR patterns are not allowed to reset the default binding mode
|
||||
test_pat_on_type![(mut x,): &(T,)]; //~ ERROR patterns are not allowed to reset the default binding mode
|
||||
test_pat_on_type![(ref x,): &(T,)]; //~ ERROR patterns are not allowed to reset the default binding mode
|
||||
test_pat_on_type![(ref mut x,): &mut (T,)]; //~ ERROR patterns are not allowed to reset the default binding mode
|
||||
test_pat_on_type![Foo { f: &(x,) }: &Foo]; //~ ERROR this pattern relies on behavior which may change in edition 2024
|
||||
test_pat_on_type![(mut x,): &(T,)]; //~ ERROR this pattern relies on behavior which may change in edition 2024
|
||||
test_pat_on_type![(ref x,): &(T,)]; //~ ERROR this pattern relies on behavior which may change in edition 2024
|
||||
test_pat_on_type![(ref mut x,): &mut (T,)]; //~ ERROR this pattern relies on behavior which may change in edition 2024
|
||||
|
||||
fn get<X>() -> X {
|
||||
unimplemented!()
|
||||
|
|
@ -40,6 +40,6 @@ fn get<X>() -> X {
|
|||
// Make sure this works even when the underlying type is inferred. This test passes on rust stable.
|
||||
fn infer<X: Copy>() -> X {
|
||||
match &get() {
|
||||
(&x,) => x, //~ ERROR patterns are not allowed to reset the default binding mode
|
||||
(&x,) => x, //~ ERROR this pattern relies on behavior which may change in edition 2024
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,61 +99,89 @@ LL - test_pat_on_type![Foo { f: (&x,) }: &mut Foo];
|
|||
LL + test_pat_on_type![Foo { f: (x,) }: &mut Foo];
|
||||
|
|
||||
|
||||
error: patterns are not allowed to reset the default binding mode in edition 2024
|
||||
--> $DIR/min_match_ergonomics_fail.rs:24:19
|
||||
error: this pattern relies on behavior which may change in edition 2024
|
||||
--> $DIR/min_match_ergonomics_fail.rs:24:20
|
||||
|
|
||||
LL | test_pat_on_type![(&x,): &(&T,)];
|
||||
| -^^^^
|
||||
| |
|
||||
| help: desugar the match ergonomics: `&`
|
||||
| ^ cannot implicitly match against multiple layers of reference
|
||||
|
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
|
||||
help: make the implied reference pattern explicit
|
||||
|
|
||||
LL | test_pat_on_type![&(&x,): &(&T,)];
|
||||
| +
|
||||
|
||||
error: patterns are not allowed to reset the default binding mode in edition 2024
|
||||
--> $DIR/min_match_ergonomics_fail.rs:27:19
|
||||
error: this pattern relies on behavior which may change in edition 2024
|
||||
--> $DIR/min_match_ergonomics_fail.rs:27:20
|
||||
|
|
||||
LL | test_pat_on_type![(&mut x,): &(&mut T,)];
|
||||
| -^^^^^^^^
|
||||
| |
|
||||
| help: desugar the match ergonomics: `&`
|
||||
| ^^^^ cannot implicitly match against multiple layers of reference
|
||||
|
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
|
||||
help: make the implied reference pattern explicit
|
||||
|
|
||||
LL | test_pat_on_type![&(&mut x,): &(&mut T,)];
|
||||
| +
|
||||
|
||||
error: patterns are not allowed to reset the default binding mode in edition 2024
|
||||
--> $DIR/min_match_ergonomics_fail.rs:31:19
|
||||
error: this pattern relies on behavior which may change in edition 2024
|
||||
--> $DIR/min_match_ergonomics_fail.rs:31:28
|
||||
|
|
||||
LL | test_pat_on_type![Foo { f: &(x,) }: &Foo];
|
||||
| -^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| help: desugar the match ergonomics: `&`
|
||||
| ^ cannot implicitly match against multiple layers of reference
|
||||
|
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
|
||||
help: make the implied reference pattern explicit
|
||||
|
|
||||
LL | test_pat_on_type![&Foo { f: &(x,) }: &Foo];
|
||||
| +
|
||||
|
||||
error: patterns are not allowed to reset the default binding mode in edition 2024
|
||||
--> $DIR/min_match_ergonomics_fail.rs:32:19
|
||||
error: this pattern relies on behavior which may change in edition 2024
|
||||
--> $DIR/min_match_ergonomics_fail.rs:32:20
|
||||
|
|
||||
LL | test_pat_on_type![(mut x,): &(T,)];
|
||||
| -^^^^^^^
|
||||
| |
|
||||
| help: desugar the match ergonomics: `&`
|
||||
| ^^^ requires binding by-value, but the implicit default is by-reference
|
||||
|
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
|
||||
help: make the implied reference pattern explicit
|
||||
|
|
||||
LL | test_pat_on_type![&(mut x,): &(T,)];
|
||||
| +
|
||||
|
||||
error: patterns are not allowed to reset the default binding mode in edition 2024
|
||||
--> $DIR/min_match_ergonomics_fail.rs:33:19
|
||||
error: this pattern relies on behavior which may change in edition 2024
|
||||
--> $DIR/min_match_ergonomics_fail.rs:33:20
|
||||
|
|
||||
LL | test_pat_on_type![(ref x,): &(T,)];
|
||||
| -^^^^^^^
|
||||
| |
|
||||
| help: desugar the match ergonomics: `&`
|
||||
| ^^^ cannot override to bind by-reference when that is the implicit default
|
||||
|
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
|
||||
help: make the implied reference pattern explicit
|
||||
|
|
||||
LL | test_pat_on_type![&(ref x,): &(T,)];
|
||||
| +
|
||||
|
||||
error: patterns are not allowed to reset the default binding mode in edition 2024
|
||||
--> $DIR/min_match_ergonomics_fail.rs:34:19
|
||||
error: this pattern relies on behavior which may change in edition 2024
|
||||
--> $DIR/min_match_ergonomics_fail.rs:34:20
|
||||
|
|
||||
LL | test_pat_on_type![(ref mut x,): &mut (T,)];
|
||||
| -^^^^^^^^^^^
|
||||
| |
|
||||
| help: desugar the match ergonomics: `&mut`
|
||||
| ^^^^^^^ cannot override to bind by-reference when that is the implicit default
|
||||
|
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
|
||||
help: make the implied reference pattern explicit
|
||||
|
|
||||
LL | test_pat_on_type![&mut (ref mut x,): &mut (T,)];
|
||||
| ++++
|
||||
|
||||
error: patterns are not allowed to reset the default binding mode in edition 2024
|
||||
--> $DIR/min_match_ergonomics_fail.rs:43:9
|
||||
error: this pattern relies on behavior which may change in edition 2024
|
||||
--> $DIR/min_match_ergonomics_fail.rs:43:10
|
||||
|
|
||||
LL | (&x,) => x,
|
||||
| -^^^^
|
||||
| |
|
||||
| help: desugar the match ergonomics: `&`
|
||||
| ^ cannot implicitly match against multiple layers of reference
|
||||
|
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
|
||||
help: make the implied reference pattern explicit
|
||||
|
|
||||
LL | &(&x,) => x,
|
||||
| +
|
||||
|
||||
error: aborting due to 13 previous errors
|
||||
|
||||
|
|
|
|||
22
tests/ui/traits/const-traits/const-cond-for-rpitit.rs
Normal file
22
tests/ui/traits/const-traits/const-cond-for-rpitit.rs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
//@ compile-flags: -Znext-solver
|
||||
//@ check-pass
|
||||
|
||||
#![feature(const_trait_impl)]
|
||||
#![allow(refining_impl_trait)]
|
||||
|
||||
#[const_trait]
|
||||
pub trait Foo {
|
||||
fn method(self) -> impl ~const Bar;
|
||||
}
|
||||
|
||||
#[const_trait]
|
||||
pub trait Bar {}
|
||||
|
||||
struct A<T>(T);
|
||||
impl<T> const Foo for A<T> where A<T>: ~const Bar {
|
||||
fn method(self) -> impl ~const Bar {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -1,15 +1,10 @@
|
|||
//@ compile-flags: -Znext-solver
|
||||
//@ known-bug: #110395
|
||||
//@ failure-status: 101
|
||||
//@ dont-check-compiler-stderr
|
||||
// Broken until we have `&T: const Deref` impl in stdlib
|
||||
|
||||
// Broken until we have `const PartialEq` impl in stdlib
|
||||
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(
|
||||
const_trait_impl,
|
||||
effects,
|
||||
const_cmp,
|
||||
)]
|
||||
#![feature(const_trait_impl, const_cmp, const_destruct)]
|
||||
|
||||
use std::marker::Destruct;
|
||||
|
||||
|
|
@ -17,9 +12,9 @@ const fn cmp(a: &impl ~const PartialEq) -> bool {
|
|||
a == a
|
||||
}
|
||||
|
||||
const fn wrap(x: impl ~const PartialEq + ~const Destruct)
|
||||
-> impl ~const PartialEq + ~const Destruct
|
||||
{
|
||||
const fn wrap(
|
||||
x: impl ~const PartialEq + ~const Destruct,
|
||||
) -> impl ~const PartialEq + ~const Destruct {
|
||||
x
|
||||
}
|
||||
|
||||
|
|
@ -48,11 +43,15 @@ trait T {}
|
|||
struct S;
|
||||
impl const T for S {}
|
||||
|
||||
const fn rpit() -> impl ~const T { S }
|
||||
const fn rpit() -> impl ~const T {
|
||||
S
|
||||
}
|
||||
|
||||
const fn apit(_: impl ~const T + ~const Destruct) {}
|
||||
|
||||
const fn rpit_assoc_bound() -> impl IntoIterator<Item: ~const T> { Some(S) }
|
||||
const fn rpit_assoc_bound() -> impl IntoIterator<Item: ~const T> {
|
||||
Some(S)
|
||||
}
|
||||
|
||||
const fn apit_assoc_bound(_: impl IntoIterator<Item: ~const T> + ~const Destruct) {}
|
||||
|
||||
|
|
|
|||
187
tests/ui/traits/const-traits/const-impl-trait.stderr
Normal file
187
tests/ui/traits/const-traits/const-impl-trait.stderr
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
error[E0635]: unknown feature `const_cmp`
|
||||
--> $DIR/const-impl-trait.rs:7:30
|
||||
|
|
||||
LL | #![feature(const_trait_impl, const_cmp, const_destruct)]
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: `~const` can only be applied to `#[const_trait]` traits
|
||||
--> $DIR/const-impl-trait.rs:11:23
|
||||
|
|
||||
LL | const fn cmp(a: &impl ~const PartialEq) -> bool {
|
||||
| ^^^^^^ can't be applied to `PartialEq`
|
||||
|
|
||||
note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]`
|
||||
--> $SRC_DIR/core/src/cmp.rs:LL:COL
|
||||
|
||||
error: `~const` can only be applied to `#[const_trait]` traits
|
||||
--> $DIR/const-impl-trait.rs:11:23
|
||||
|
|
||||
LL | const fn cmp(a: &impl ~const PartialEq) -> bool {
|
||||
| ^^^^^^ can't be applied to `PartialEq`
|
||||
|
|
||||
note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]`
|
||||
--> $SRC_DIR/core/src/cmp.rs:LL:COL
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error: `~const` can only be applied to `#[const_trait]` traits
|
||||
--> $DIR/const-impl-trait.rs:16:13
|
||||
|
|
||||
LL | x: impl ~const PartialEq + ~const Destruct,
|
||||
| ^^^^^^ can't be applied to `PartialEq`
|
||||
|
|
||||
note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]`
|
||||
--> $SRC_DIR/core/src/cmp.rs:LL:COL
|
||||
|
||||
error: `~const` can only be applied to `#[const_trait]` traits
|
||||
--> $DIR/const-impl-trait.rs:17:11
|
||||
|
|
||||
LL | ) -> impl ~const PartialEq + ~const Destruct {
|
||||
| ^^^^^^ can't be applied to `PartialEq`
|
||||
|
|
||||
note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]`
|
||||
--> $SRC_DIR/core/src/cmp.rs:LL:COL
|
||||
|
||||
error: `~const` can only be applied to `#[const_trait]` traits
|
||||
--> $DIR/const-impl-trait.rs:17:11
|
||||
|
|
||||
LL | ) -> impl ~const PartialEq + ~const Destruct {
|
||||
| ^^^^^^ can't be applied to `PartialEq`
|
||||
|
|
||||
note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]`
|
||||
--> $SRC_DIR/core/src/cmp.rs:LL:COL
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error: `~const` can only be applied to `#[const_trait]` traits
|
||||
--> $DIR/const-impl-trait.rs:17:11
|
||||
|
|
||||
LL | ) -> impl ~const PartialEq + ~const Destruct {
|
||||
| ^^^^^^ can't be applied to `PartialEq`
|
||||
|
|
||||
note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]`
|
||||
--> $SRC_DIR/core/src/cmp.rs:LL:COL
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error: `~const` can only be applied to `#[const_trait]` traits
|
||||
--> $DIR/const-impl-trait.rs:16:13
|
||||
|
|
||||
LL | x: impl ~const PartialEq + ~const Destruct,
|
||||
| ^^^^^^ can't be applied to `PartialEq`
|
||||
|
|
||||
note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]`
|
||||
--> $SRC_DIR/core/src/cmp.rs:LL:COL
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error: `~const` can only be applied to `#[const_trait]` traits
|
||||
--> $DIR/const-impl-trait.rs:23:22
|
||||
|
|
||||
LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
|
||||
| ^^^^^^ can't be applied to `PartialEq`
|
||||
|
|
||||
note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]`
|
||||
--> $SRC_DIR/core/src/cmp.rs:LL:COL
|
||||
|
||||
error: `~const` can only be applied to `#[const_trait]` traits
|
||||
--> $DIR/const-impl-trait.rs:27:22
|
||||
|
|
||||
LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy {
|
||||
| ^^^^^^ can't be applied to `PartialEq`
|
||||
|
|
||||
note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]`
|
||||
--> $SRC_DIR/core/src/cmp.rs:LL:COL
|
||||
|
||||
error: `~const` can only be applied to `#[const_trait]` traits
|
||||
--> $DIR/const-impl-trait.rs:27:22
|
||||
|
|
||||
LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy {
|
||||
| ^^^^^^ can't be applied to `PartialEq`
|
||||
|
|
||||
note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]`
|
||||
--> $SRC_DIR/core/src/cmp.rs:LL:COL
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error: `~const` can only be applied to `#[const_trait]` traits
|
||||
--> $DIR/const-impl-trait.rs:23:22
|
||||
|
|
||||
LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
|
||||
| ^^^^^^ can't be applied to `PartialEq`
|
||||
|
|
||||
note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]`
|
||||
--> $SRC_DIR/core/src/cmp.rs:LL:COL
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error: `~const` can only be applied to `#[const_trait]` traits
|
||||
--> $DIR/const-impl-trait.rs:23:22
|
||||
|
|
||||
LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
|
||||
| ^^^^^^ can't be applied to `PartialEq`
|
||||
|
|
||||
note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]`
|
||||
--> $SRC_DIR/core/src/cmp.rs:LL:COL
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error: `~const` can only be applied to `#[const_trait]` traits
|
||||
--> $DIR/const-impl-trait.rs:27:22
|
||||
|
|
||||
LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy {
|
||||
| ^^^^^^ can't be applied to `PartialEq`
|
||||
|
|
||||
note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]`
|
||||
--> $SRC_DIR/core/src/cmp.rs:LL:COL
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error: `~const` can only be applied to `#[const_trait]` traits
|
||||
--> $DIR/const-impl-trait.rs:23:22
|
||||
|
|
||||
LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
|
||||
| ^^^^^^ can't be applied to `PartialEq`
|
||||
|
|
||||
note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]`
|
||||
--> $SRC_DIR/core/src/cmp.rs:LL:COL
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error: `~const` can only be applied to `#[const_trait]` traits
|
||||
--> $DIR/const-impl-trait.rs:23:22
|
||||
|
|
||||
LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
|
||||
| ^^^^^^ can't be applied to `PartialEq`
|
||||
|
|
||||
note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]`
|
||||
--> $SRC_DIR/core/src/cmp.rs:LL:COL
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error[E0015]: cannot call non-const operator in constants
|
||||
--> $DIR/const-impl-trait.rs:35:13
|
||||
|
|
||||
LL | assert!(wrap(123) == wrap(123));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||
|
||||
error[E0015]: cannot call non-const operator in constants
|
||||
--> $DIR/const-impl-trait.rs:36:13
|
||||
|
|
||||
LL | assert!(wrap(123) != wrap(456));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||
|
||||
error[E0015]: cannot call non-const operator in constants
|
||||
--> $DIR/const-impl-trait.rs:38:13
|
||||
|
|
||||
LL | assert!(x == x);
|
||||
| ^^^^^^
|
||||
|
|
||||
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||
|
||||
error[E0015]: cannot call non-const operator in constant functions
|
||||
--> $DIR/const-impl-trait.rs:12:5
|
||||
|
|
||||
LL | a == a
|
||||
| ^^^^^^
|
||||
|
|
||||
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||
|
||||
error: aborting due to 20 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0015, E0635.
|
||||
For more information about an error, try `rustc --explain E0015`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue