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:
bors 2024-12-18 16:21:57 +00:00
commit a52085d9f6
87 changed files with 1714 additions and 1190 deletions

View file

@ -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)
}
}

View file

@ -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 {

View file

@ -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,

View file

@ -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() {

View file

@ -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, .. }, _) => {}

View file

@ -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 {

View file

@ -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");

View file

@ -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(

View file

@ -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!

View file

@ -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);

View file

@ -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 => {}
}

View file

@ -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| {

View file

@ -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()));
}
}

View file

@ -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, _) => {

View file

@ -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
{

View file

@ -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

View file

@ -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.

View file

@ -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,

View file

@ -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

View file

@ -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 {

View file

@ -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,

View file

@ -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;

View file

@ -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)
}
}
}

View file

@ -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,
);
}
}

View file

@ -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

View file

@ -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,

View file

@ -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
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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!(),
_ => {

View file

@ -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 = &macro_tts.trees().collect::<Vec<_>>();
let tts = &macro_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 }"),

View file

@ -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);
})
}

View file

@ -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

View file

@ -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
}
}
}

View file

@ -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
///

View file

@ -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") {

View file

@ -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;
}

View file

@ -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"));

View file

@ -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;

View file

@ -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),

View file

@ -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, _),

View file

@ -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);

View file

@ -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";

View file

@ -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;

View file

@ -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;

View file

@ -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());

View file

@ -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),

View file

@ -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,
];

View file

@ -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]

View file

@ -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) => {

View file

@ -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 {}

View file

@ -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 {

View file

@ -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 {}

View file

@ -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]

View file

@ -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]

View file

@ -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]

View file

@ -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;

View file

@ -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;

View file

@ -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]

View file

@ -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;

View file

@ -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]

View file

@ -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() {}

View file

@ -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 {}

View file

@ -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;

View file

@ -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 {}

View file

@ -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;

View file

@ -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;

View file

@ -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) => {

View file

@ -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

View file

@ -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 */
};
}

View file

@ -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];
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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);
}

View file

@ -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];
}
}

View 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 => {}
}
}

View file

@ -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];
}
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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

View file

@ -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
}
}

View file

@ -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

View 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() {}

View file

@ -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) {}

View 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`.