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
87 changed files with 1714 additions and 1190 deletions
+30 -39
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::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 @@ pub fn value_str(&self) -> Option<Symbol> {
}
}
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 @@ fn from_tokens<'a, I>(tokens: &mut iter::Peekable<I>) -> Option<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 @@ fn from_tokens<'a, I>(tokens: &mut iter::Peekable<I>) -> Option<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 @@ fn from_tokens<'a, I>(tokens: &mut iter::Peekable<I>) -> Option<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 @@ fn from_tokens<'a, I>(tokens: &mut iter::Peekable<I>) -> Option<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 @@ pub fn list_from_tokens(tokens: TokenStream) -> Option<ThinVec<MetaItemInner>> {
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 @@ fn name_value_from_tokens<'a>(
}
}
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 @@ pub fn is_meta_item(&self) -> bool {
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)
}
}
+7 -1
View File
@@ -903,7 +903,8 @@ pub fn is_keyword(&self, kw: Symbol) -> bool {
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 @@ pub fn is_path_segment_keyword(&self) -> bool {
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 {
+22 -54
View File
@@ -99,7 +99,7 @@ impl<CTX> HashStable<CTX> for TokenStream
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 @@ pub fn len(&self) -> usize {
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 @@ fn flatten_token_tree(tree: &TokenTree) -> TokenTree {
#[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 @@ fn can_skip(stream: &TokenStream) -> bool {
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 @@ fn desugared_tts(attr_style: AttrStyle, data: Symbol, span: Span) -> Vec<TokenTr
}
}
/// 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 @@ fn next(&mut self) -> Option<&'t TokenTree> {
}
}
/// Owning by-value iterator over a [`TokenStream`], that produces `&TokenTree`
/// items.
///
/// Doesn't impl `Iterator` because Rust doesn't permit an owning iterator to
/// return `&T` from `next`; the need for an explicit lifetime in the `Item`
/// associated type gets in the way. Instead, use `next_ref` (which doesn't
/// involve associated types) for getting individual elements, or
/// `RefTokenTreeCursor` if you really want an `Iterator`, e.g. in a `for`
/// loop.
#[derive(Clone, Debug)]
pub struct TokenTreeCursor {
pub stream: TokenStream,
index: usize,
}
impl TokenTreeCursor {
fn new(stream: TokenStream) -> Self {
TokenTreeCursor { stream, index: 0 }
}
#[inline]
pub fn next_ref(&mut self) -> Option<&TokenTree> {
self.stream.0.get(self.index).map(|tree| {
self.index += 1;
tree
})
}
pub fn look_ahead(&self, n: usize) -> Option<&TokenTree> {
self.stream.0.get(self.index + n)
}
}
#[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]
pub struct DelimSpan {
pub open: Span,
@@ -725,7 +725,7 @@ fn print_tt(&mut self, tt: &TokenTree, convert_dollar_crate: bool) -> Spacing {
// E.g. we have seen cases where a proc macro can handle `a :: b` but not
// `a::b`. See #117433 for some examples.
fn print_tts(&mut self, tts: &TokenStream, convert_dollar_crate: bool) {
let mut iter = tts.trees().peekable();
let mut iter = tts.iter().peekable();
while let Some(tt) = iter.next() {
let spacing = self.print_tt(tt, convert_dollar_crate);
if let Some(next) = iter.peek() {
@@ -18,7 +18,7 @@ pub(crate) fn expand_concat_idents<'cx>(
}
let mut res_str = String::new();
for (i, e) in tts.trees().enumerate() {
for (i, e) in tts.iter().enumerate() {
if i & 1 == 1 {
match e {
TokenTree::Token(Token { kind: token::Comma, .. }, _) => {}
@@ -9,9 +9,9 @@ pub(crate) fn expand_trace_macros(
sp: Span,
tt: TokenStream,
) -> MacroExpanderResult<'static> {
let mut cursor = tt.trees();
let mut iter = tt.iter();
let mut err = false;
let value = match &cursor.next() {
let value = match iter.next() {
Some(TokenTree::Token(token, _)) if token.is_keyword(kw::True) => true,
Some(TokenTree::Token(token, _)) if token.is_keyword(kw::False) => false,
_ => {
@@ -19,7 +19,7 @@ pub(crate) fn expand_trace_macros(
false
}
};
err |= cursor.next().is_some();
err |= iter.next().is_some();
if err {
cx.dcx().emit_err(errors::TraceMacros { span: sp });
} else {
+2 -2
View File
@@ -26,7 +26,7 @@
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");
+19 -20
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 @@ pub(crate) fn parse<'psess>(
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 @@ pub(crate) fn parse<'psess>(
}
};
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(
+27 -25
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!
@@ -111,9 +111,9 @@ fn from_internal((stream, rustc): (TokenStream, &mut Rustc<'_, '_>)) -> Self {
// Estimate the capacity as `stream.len()` rounded up to the next power
// of two to limit the number of required reallocations.
let mut trees = Vec::with_capacity(stream.len().next_power_of_two());
let mut cursor = stream.trees();
let mut iter = stream.iter();
while let Some(tree) = cursor.next() {
while let Some(tree) = iter.next() {
let (Token { kind, span }, joint) = match tree.clone() {
tokenstream::TokenTree::Delimited(span, _, delim, tts) => {
let delimiter = pm::Delimiter::from_internal(delim);
@@ -371,10 +371,9 @@ pub(super) fn explicit_item_bounds_with_filter(
associated_type_bounds(tcx, def_id, opaque_ty.bounds, opaque_ty.span, filter);
return ty::EarlyBinder::bind(bounds);
}
Some(ty::ImplTraitInTraitData::Impl { .. }) => span_bug!(
tcx.def_span(def_id),
"item bounds for RPITIT in impl to be fed on def-id creation"
),
Some(ty::ImplTraitInTraitData::Impl { .. }) => {
span_bug!(tcx.def_span(def_id), "RPITIT in impl should not have item bounds")
}
None => {}
}
@@ -956,6 +956,15 @@ pub(super) fn const_conditions<'tcx>(
bug!("const_conditions invoked for item that is not conditionally const: {def_id:?}");
}
match tcx.opt_rpitit_info(def_id.to_def_id()) {
// RPITITs inherit const conditions of their parent fn
Some(
ty::ImplTraitInTraitData::Impl { fn_def_id }
| ty::ImplTraitInTraitData::Trait { fn_def_id, .. },
) => return tcx.const_conditions(fn_def_id),
None => {}
}
let (generics, trait_def_id_and_supertraits, has_parent) = match tcx.hir_node_by_def_id(def_id)
{
Node::Item(item) => match item.kind {
@@ -1059,19 +1068,29 @@ pub(super) fn explicit_implied_const_bounds<'tcx>(
bug!("const_conditions invoked for item that is not conditionally const: {def_id:?}");
}
let bounds = match tcx.hir_node_by_def_id(def_id) {
Node::Item(hir::Item { kind: hir::ItemKind::Trait(..), .. }) => {
implied_predicates_with_filter(
tcx,
def_id.to_def_id(),
PredicateFilter::SelfConstIfConst,
)
}
Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(..), .. })
| Node::OpaqueTy(_) => {
let bounds = match tcx.opt_rpitit_info(def_id.to_def_id()) {
// RPITIT's bounds are the same as opaque type bounds, but with
// a projection self type.
Some(ty::ImplTraitInTraitData::Trait { .. }) => {
explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::ConstIfConst)
}
_ => bug!("explicit_implied_const_bounds called on wrong item: {def_id:?}"),
Some(ty::ImplTraitInTraitData::Impl { .. }) => {
span_bug!(tcx.def_span(def_id), "RPITIT in impl should not have item bounds")
}
None => match tcx.hir_node_by_def_id(def_id) {
Node::Item(hir::Item { kind: hir::ItemKind::Trait(..), .. }) => {
implied_predicates_with_filter(
tcx,
def_id.to_def_id(),
PredicateFilter::SelfConstIfConst,
)
}
Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(..), .. })
| Node::OpaqueTy(_) => {
explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::ConstIfConst)
}
_ => bug!("explicit_implied_const_bounds called on wrong item: {def_id:?}"),
},
};
bounds.map_bound(|bounds| {
+53 -18
View File
@@ -717,12 +717,12 @@ fn check_pat_ident(
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 @@ fn check_pat_ident(
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 @@ fn check_pat_ref(
// 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 @@ fn is_slice_or_array_or_vector(&self, ty: Ty<'tcx>) -> (bool, Ty<'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()));
}
}
+1 -1
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, _) => {
+5 -21
View File
@@ -170,27 +170,11 @@ fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx Ty<'tcx>) {
| PatKind::TupleStruct(qpath, ..)
| PatKind::Struct(qpath, ..),
..
}) => {
if let QPath::TypeRelative(qpath_ty, ..) = qpath
&& qpath_ty.hir_id == ty.hir_id
{
Some(path.span)
} else {
None
}
}
Node::Expr(Expr { kind: ExprKind::Path(qpath), .. }) => {
if let QPath::TypeRelative(qpath_ty, ..) = qpath
&& qpath_ty.hir_id == ty.hir_id
{
Some(path.span)
} else {
None
}
}
// Can't unify these two branches because qpath below is `&&` and above is `&`
// and `A | B` paths don't play well together with adjustments, apparently.
Node::Expr(Expr { kind: ExprKind::Struct(qpath, ..), .. }) => {
})
| Node::Expr(
Expr { kind: ExprKind::Path(qpath), .. }
| &Expr { kind: ExprKind::Struct(qpath, ..), .. },
) => {
if let QPath::TypeRelative(qpath_ty, ..) = qpath
&& qpath_ty.hir_id == ty.hir_id
{
@@ -84,7 +84,7 @@ fn check_tokens(&mut self, cx: &crate::EarlyContext<'_>, tokens: &TokenStream) {
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
+2 -2
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.
@@ -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 @@ pub fn pat_adjustments_mut(&mut self) -> LocalTableInContextMut<'_, Vec<Ty<'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,
+1 -1
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
+1 -1
View File
@@ -19,7 +19,7 @@ pub(crate) fn block_data_mut(&mut self, blk: BasicBlock) -> &mut BasicBlockData<
// it as #[inline(never)] to keep rustc's stack use in check.
#[inline(never)]
pub(crate) fn start_new_block(&mut self) -> BasicBlock {
self.basic_blocks.push(BasicBlockData::new(None))
self.basic_blocks.push(BasicBlockData::new(None, false))
}
pub(crate) fn start_new_cleanup_block(&mut self) -> BasicBlock {
@@ -64,7 +64,7 @@ pub(super) fn build_custom_mir<'tcx>(
};
body.local_decls.push(LocalDecl::new(return_ty, return_ty_span));
body.basic_blocks_mut().push(BasicBlockData::new(None));
body.basic_blocks_mut().push(BasicBlockData::new(None, false));
body.source_scopes.push(SourceScopeData {
span,
parent_scope: None,
@@ -199,10 +199,12 @@ fn parse_basic_block_decl(&mut self, stmt: StmtId) -> PResult<()> {
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 @@ fn parse_block_def(&self, expr_id: ExprId, is_cleanup: bool) -> PResult<BasicBlo
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;
+3 -3
View File
@@ -56,10 +56,10 @@ pub(crate) fn push_usize(
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)
}
}
}
+20 -8
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 @@ fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
} else {
Applicability::MaybeIncorrect
};
diag.multipart_suggestion("desugar the match ergonomics", self.suggestion, applicability);
let plural_derefs = pluralize!(self.ref_pattern_count);
let and_modes = if self.binding_mode_count > 0 {
format!(" and variable binding mode{}", pluralize!(self.binding_mode_count))
} else {
String::new()
};
diag.multipart_suggestion_verbose(
format!("make the implied reference pattern{plural_derefs}{and_modes} explicit"),
self.suggestion,
applicability,
);
}
}
@@ -6,6 +6,7 @@
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 @@ fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> {
})
.collect();
s.suggestion.push((pat.span.shrink_to_lo(), suggestion_str));
s.ref_pattern_count += adjustments.len();
};
adjusted_pat
@@ -371,7 +385,8 @@ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tc
s.suggestion.push((
pat.span.with_lo(ident.span.lo()).shrink_to_lo(),
sugg_str.to_owned(),
))
));
s.binding_mode_count += 1;
}
// A ref x pattern is the same node used for x, and as such it has
@@ -35,7 +35,6 @@ pub trait ResultsVisitor<'mir, 'tcx, A>
{
fn visit_block_start(&mut self, _state: &A::Domain) {}
/// // njn: grep for "before", "primary", etc.
/// Called after the "early" effect of the given statement is applied to `state`.
fn visit_after_early_statement_effect(
&mut self,
@@ -129,18 +129,29 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
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 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
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 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
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 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
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
}
+7 -5
View File
@@ -572,11 +572,13 @@ fn inline_call(
let return_block = if let Some(block) = target {
// Prepare a new block for code that should execute when call returns. We don't use
// target block directly since it might have other predecessors.
let mut data = BasicBlockData::new(Some(Terminator {
source_info: terminator.source_info,
kind: TerminatorKind::Goto { target: block },
}));
data.is_cleanup = caller_body[block].is_cleanup;
let data = BasicBlockData::new(
Some(Terminator {
source_info: terminator.source_info,
kind: TerminatorKind::Goto { target: block },
}),
caller_body[block].is_cleanup,
);
Some(caller_body.basic_blocks_mut().push(data))
} else {
None
@@ -96,7 +96,7 @@ fn new(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Option<Ty<'tcx>>) -> Self {
typing_env,
stack: Vec::with_capacity(Self::MAX_STACK_LEN),
last_bb: bbs.push(BasicBlockData::new(None)),
last_bb: bbs.push(BasicBlockData::new(None, false)),
top_cleanup_bb: match tcx.sess.panic_strategy() {
PanicStrategy::Unwind => {
// Don't drop input arg because it's just a pointer
@@ -22,7 +22,7 @@
use rustc_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 @@ fn check_for_misspelled_kw(&self, err: &mut Diag<'_>, expected: &[TokenType]) {
// 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
+3 -1
View File
@@ -8,6 +8,7 @@
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 @@ fn parse_expr_closure(&mut self) -> PResult<'a, P<Expr>> {
}
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
+59 -31
View File
@@ -24,9 +24,7 @@
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 @@ fn inlined_next(&mut self) -> (Token, Spacing) {
// 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 @@ pub fn new(
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 @@ pub fn look_ahead<R>(&self, dist: usize, looker: impl FnOnce(&Token) -> R) -> R
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 @@ pub fn look_ahead<R>(&self, dist: usize, looker: impl FnOnce(&Token) -> R) -> R
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 @@ fn parse_delim_args_inner(&mut self) -> Option<DelimArgs> {
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 @@ pub fn parse_token_tree(&mut self) -> TokenTree {
// Consume close delimiter
self.bump();
TokenTree::Delimited(span, spacing, delim, stream)
tree
}
token::CloseDelim(_) | token::Eof => unreachable!(),
_ => {
+5 -5
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 parse_expr_from_source_str(
.unwrap();
let ast::ExprKind::MacCall(mac) = &expr.kind else { panic!("not a macro") };
let span = mac.args.tokens.trees().last().unwrap().span();
let span = mac.args.tokens.iter().last().unwrap().span();
match psess.source_map().span_to_snippet(span) {
Ok(s) => assert_eq!(&s[..], "{ body }"),
@@ -23,8 +23,8 @@ fn test_concat() {
let mut eq_res = TokenStream::default();
eq_res.push_stream(test_fst);
eq_res.push_stream(test_snd);
assert_eq!(test_res.trees().count(), 5);
assert_eq!(eq_res.trees().count(), 5);
assert_eq!(test_res.iter().count(), 5);
assert_eq!(eq_res.iter().count(), 5);
assert_eq!(test_res.eq_unspanned(&eq_res), true);
})
}
@@ -33,7 +33,7 @@ fn test_concat() {
fn test_to_from_bijection() {
create_default_session_globals_then(|| {
let test_start = string_to_ts("foo::bar(baz)");
let test_end = test_start.trees().cloned().collect();
let test_end = test_start.iter().cloned().collect();
assert_eq!(test_start, test_end)
})
}
@@ -105,6 +105,6 @@ fn test_dotdotdot() {
stream.push_tree(TokenTree::token_joint(token::Dot, sp(1, 2)));
stream.push_tree(TokenTree::token_alone(token::Dot, sp(2, 3)));
assert!(stream.eq_unspanned(&string_to_ts("...")));
assert_eq!(stream.trees().count(), 1);
assert_eq!(stream.iter().count(), 1);
})
}
+1 -1
View File
@@ -1076,7 +1076,7 @@ pub fn with_extension(&self, extension: &str) -> PathBuf {
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
+44 -41
View File
@@ -20,18 +20,26 @@
// 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 @@
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 @@
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 fn integer<N: TryInto<usize> + Copy + itoa::Integer>(n: N) -> Symbol {
}
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 @@ fn is_unused_keyword_always(self) -> bool {
}
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 @@ pub fn is_preinterned(self) -> bool {
}
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 @@ pub fn is_raw_guess(self) -> bool {
}
}
/// 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
}
}
}
+2 -2
View File
@@ -219,7 +219,7 @@ unsafe fn really_init(this: &LazyCell<T, F>) -> &T {
}
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 @@ pub fn get_mut(this: &mut LazyCell<T, F>) -> Option<&mut T> {
}
}
/// Returns a mutable reference to the value if initialized, or `None` if not.
/// Returns a reference to the value if initialized, or `None` if not.
///
/// # Examples
///
@@ -523,6 +523,11 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car
let mut features = String::new();
if stage != 0 && builder.config.default_codegen_backend(target).as_deref() == Some("cranelift")
{
features += "compiler-builtins-no-f16-f128 ";
}
if builder.no_std(target) == Some(true) {
features += " compiler-builtins-mem";
if !target.starts_with("bpf") {
+1 -1
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;
}
+4 -6
View File
@@ -1942,7 +1942,7 @@ fn get_table(option: &str) -> Result<TomlConfig, toml::de::Error> {
);
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 @@ pub(crate) fn read_file_by_commit(&self, file: &Path, commit: &str) -> String {
/// 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"));
+1 -1
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;
@@ -131,7 +131,7 @@ enum State {
use State::*;
let mut state = Start;
for tt in tts.trees() {
for tt in tts.iter() {
let (needs_space, next_state) = match &tt {
TokenTree::Token(tt, _) => match (state, &tt.kind) {
(Dollar, token::Ident(..)) => (false, DollarIdent),
@@ -15,7 +15,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, attr: &Attribute) {
}
if let AttrArgs::Delimited(args) = &normal_attr.item.args
&& let mut tt_iter = args.tokens.trees()
&& let mut tt_iter = args.tokens.iter()
&& let Some(TokenTree::Token(
Token {
kind: TokenKind::Ident(sym::expected, _),
@@ -82,11 +82,11 @@ fn is_macro_export(attr: &Attribute) -> bool {
fn contains_unhygienic_crate_reference(tts: &TokenStream) -> Option<Span> {
let mut prev_is_dollar = false;
let mut cursor = tts.trees();
while let Some(curr) = cursor.next() {
let mut iter = tts.iter();
while let Some(curr) = iter.next() {
if !prev_is_dollar
&& let Some(span) = is_crate_keyword(curr)
&& let Some(next) = cursor.look_ahead(0)
&& let Some(next) = iter.peek()
&& is_token(next, &TokenKind::PathSep)
{
return Some(span);
+2 -2
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 analyze_cdb(
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";
+3 -4
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;
+1 -1
View File
@@ -2560,7 +2560,7 @@ fn load_expected_output_from_path(&self, path: &Path) -> Result<String, String>
})
}
fn delete_file(&self, file: &PathBuf) {
fn delete_file(&self, file: &Path) {
if !file.exists() {
// Deleting a nonexistent file would error.
return;
+1 -1
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());
+15 -15
View File
@@ -13,7 +13,7 @@
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 @@ fn add_other(&mut self) {
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 @@ fn add_repeat(
&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 @@ fn need_space_prefix(&self) -> bool {
/// 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 @@ fn parse(&mut self) -> Option<Macro> {
// `(` ... `)` `=>` `{` ... `}`
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 @@ fn parse_branch(&mut self) -> Option<MacroBranch> {
) => {}
_ => 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 @@ fn parse_branch(&mut self) -> Option<MacroBranch> {
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),
+12 -75
View File
@@ -4,8 +4,7 @@
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,
];
+4 -8
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]
+4 -16
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) => {
+5 -31
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 @@ trait Copy {}
#[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 {}
+4 -24
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 {
+4 -29
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 @@ trait Copy {}
#[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 {}
+4 -20
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]
+4 -20
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]
+4 -24
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]
+4 -23
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;
+4 -25
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;
+4 -20
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]
+4 -26
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;
+4 -20
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]
+5 -23
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() {}
+5 -29
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 @@
#[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 @@ trait Copy {}
#[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 {}
+4 -27
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;
+4 -30
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 @@ trait Copy {}
#[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 {}
+4 -27
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;
+5 -23
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;
+4 -20
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) => {
+4 -22
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 @@ impl Copy for $ty {}
}
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
+22 -2
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 struct UnsafeCell<T: ?Sized> {
pub macro global_asm("assembly template", $(operands,)* $(options($(option),*))?) {
/* compiler built-in */
}
#[rustc_builtin_macro]
#[macro_export]
macro_rules! concat {
($($e:expr),* $(,)?) => {
/* compiler built-in */
};
}
#[rustc_builtin_macro]
#[macro_export]
macro_rules! stringify {
($($t:tt)*) => {
/* compiler built-in */
};
}
@@ -0,0 +1,77 @@
- // MIR for `opt5` before EarlyOtherwiseBranch
+ // MIR for `opt5` after EarlyOtherwiseBranch
fn opt5(_1: u32, _2: u32) -> u32 {
debug x => _1;
debug y => _2;
let mut _0: u32;
let mut _3: (u32, u32);
let mut _4: u32;
let mut _5: u32;
+ let mut _6: bool;
bb0: {
StorageLive(_3);
StorageLive(_4);
_4 = copy _1;
StorageLive(_5);
_5 = copy _2;
_3 = (move _4, move _5);
StorageDead(_5);
StorageDead(_4);
- switchInt(copy (_3.0: u32)) -> [1: bb2, 2: bb3, 3: bb4, otherwise: bb1];
+ StorageLive(_6);
+ _6 = Ne(copy (_3.0: u32), copy (_3.1: u32));
+ switchInt(move _6) -> [0: bb6, otherwise: bb1];
}
bb1: {
+ StorageDead(_6);
_0 = const 0_u32;
- goto -> bb8;
+ goto -> bb5;
}
bb2: {
- switchInt(copy (_3.1: u32)) -> [1: bb7, otherwise: bb1];
+ _0 = const 6_u32;
+ goto -> bb5;
}
bb3: {
- switchInt(copy (_3.1: u32)) -> [2: bb6, otherwise: bb1];
+ _0 = const 5_u32;
+ goto -> bb5;
}
bb4: {
- switchInt(copy (_3.1: u32)) -> [3: bb5, otherwise: bb1];
+ _0 = const 4_u32;
+ goto -> bb5;
}
bb5: {
- _0 = const 6_u32;
- goto -> bb8;
+ StorageDead(_3);
+ return;
}
bb6: {
- _0 = const 5_u32;
- goto -> bb8;
- }
-
- bb7: {
- _0 = const 4_u32;
- goto -> bb8;
- }
-
- bb8: {
- StorageDead(_3);
- return;
+ StorageDead(_6);
+ switchInt(copy (_3.0: u32)) -> [1: bb4, 2: bb3, 3: bb2, otherwise: bb1];
}
}
@@ -0,0 +1,61 @@
- // MIR for `opt5_failed` before EarlyOtherwiseBranch
+ // MIR for `opt5_failed` after EarlyOtherwiseBranch
fn opt5_failed(_1: u32, _2: u32) -> u32 {
debug x => _1;
debug y => _2;
let mut _0: u32;
let mut _3: (u32, u32);
let mut _4: u32;
let mut _5: u32;
bb0: {
StorageLive(_3);
StorageLive(_4);
_4 = copy _1;
StorageLive(_5);
_5 = copy _2;
_3 = (move _4, move _5);
StorageDead(_5);
StorageDead(_4);
switchInt(copy (_3.0: u32)) -> [1: bb2, 2: bb3, 3: bb4, otherwise: bb1];
}
bb1: {
_0 = const 0_u32;
goto -> bb8;
}
bb2: {
switchInt(copy (_3.1: u32)) -> [1: bb7, otherwise: bb1];
}
bb3: {
switchInt(copy (_3.1: u32)) -> [2: bb6, otherwise: bb1];
}
bb4: {
switchInt(copy (_3.1: u32)) -> [2: bb5, otherwise: bb1];
}
bb5: {
_0 = const 6_u32;
goto -> bb8;
}
bb6: {
_0 = const 5_u32;
goto -> bb8;
}
bb7: {
_0 = const 4_u32;
goto -> bb8;
}
bb8: {
StorageDead(_3);
return;
}
}
@@ -0,0 +1,61 @@
- // MIR for `opt5_failed_type` before EarlyOtherwiseBranch
+ // MIR for `opt5_failed_type` after EarlyOtherwiseBranch
fn opt5_failed_type(_1: u32, _2: u64) -> u32 {
debug x => _1;
debug y => _2;
let mut _0: u32;
let mut _3: (u32, u64);
let mut _4: u32;
let mut _5: u64;
bb0: {
StorageLive(_3);
StorageLive(_4);
_4 = copy _1;
StorageLive(_5);
_5 = copy _2;
_3 = (move _4, move _5);
StorageDead(_5);
StorageDead(_4);
switchInt(copy (_3.0: u32)) -> [1: bb2, 2: bb3, 3: bb4, otherwise: bb1];
}
bb1: {
_0 = const 0_u32;
goto -> bb8;
}
bb2: {
switchInt(copy (_3.1: u64)) -> [1: bb7, otherwise: bb1];
}
bb3: {
switchInt(copy (_3.1: u64)) -> [2: bb6, otherwise: bb1];
}
bb4: {
switchInt(copy (_3.1: u64)) -> [3: bb5, otherwise: bb1];
}
bb5: {
_0 = const 6_u32;
goto -> bb8;
}
bb6: {
_0 = const 5_u32;
goto -> bb8;
}
bb7: {
_0 = const 4_u32;
goto -> bb8;
}
bb8: {
StorageDead(_3);
return;
}
}
+48
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);
}
@@ -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];
}
}
@@ -0,0 +1,38 @@
//@ test-mir-pass: EarlyOtherwiseBranch
//@ compile-flags: -Zmir-enable-passes=+GVN,+SimplifyLocals-after-value-numbering
//@ needs-unwind
use std::task::Poll;
// We find a matching pattern in the unwind path,
// and we need to create a cleanup BB for this case to meet the unwind invariants rule.
// NB: This transform is not happening currently.
// EMIT_MIR early_otherwise_branch_unwind.unwind.EarlyOtherwiseBranch.diff
fn unwind<T>(val: Option<Option<Option<T>>>) {
// CHECK-LABEL: fn unwind(
// CHECK: drop({{.*}}) -> [return: bb{{.*}}, unwind: [[PARENT_UNWIND_BB:bb.*]]];
// CHECK: [[PARENT_UNWIND_BB]] (cleanup): {
// CHECK-NEXT: switchInt
match val {
Some(Some(Some(_v))) => {}
Some(Some(None)) => {}
Some(None) => {}
None => {}
}
}
// From https://github.com/rust-lang/rust/issues/130769#issuecomment-2370443086.
// EMIT_MIR early_otherwise_branch_unwind.poll.EarlyOtherwiseBranch.diff
pub fn poll(val: Poll<Result<Option<Vec<u8>>, u8>>) {
// CHECK-LABEL: fn poll(
// CHECK: drop({{.*}}) -> [return: bb{{.*}}, unwind: [[PARENT_UNWIND_BB:bb.*]]];
// CHECK: [[PARENT_UNWIND_BB]] (cleanup): {
// CHECK-NEXT: switchInt
match val {
Poll::Ready(Ok(Some(_trailers))) => {}
Poll::Ready(Err(_err)) => {}
Poll::Ready(Ok(None)) => {}
Poll::Pending => {}
}
}
@@ -0,0 +1,119 @@
- // MIR for `unwind` before EarlyOtherwiseBranch
+ // MIR for `unwind` after EarlyOtherwiseBranch
fn unwind(_1: Option<Option<Option<T>>>) -> () {
debug val => _1;
let mut _0: ();
let mut _2: isize;
let mut _3: isize;
let mut _4: isize;
let _5: T;
let mut _6: bool;
let mut _7: bool;
let mut _8: isize;
scope 1 {
debug _v => _5;
}
bb0: {
_6 = const false;
_7 = const false;
_6 = const true;
_7 = const true;
_4 = discriminant(_1);
switchInt(copy _4) -> [0: bb4, 1: bb2, otherwise: bb1];
}
bb1: {
unreachable;
}
bb2: {
_3 = discriminant(((_1 as Some).0: std::option::Option<std::option::Option<T>>));
switchInt(copy _3) -> [0: bb5, 1: bb3, otherwise: bb1];
}
bb3: {
_2 = discriminant(((((_1 as Some).0: std::option::Option<std::option::Option<T>>) as Some).0: std::option::Option<T>));
switchInt(copy _2) -> [0: bb6, 1: bb7, otherwise: bb1];
}
bb4: {
_0 = const ();
goto -> bb17;
}
bb5: {
_0 = const ();
goto -> bb17;
}
bb6: {
_0 = const ();
goto -> bb17;
}
bb7: {
StorageLive(_5);
_5 = move ((((((_1 as Some).0: std::option::Option<std::option::Option<T>>) as Some).0: std::option::Option<T>) as Some).0: T);
_0 = const ();
drop(_5) -> [return: bb8, unwind: bb20];
}
bb8: {
StorageDead(_5);
goto -> bb17;
}
bb9 (cleanup): {
resume;
}
bb10: {
return;
}
bb11: {
switchInt(copy _6) -> [0: bb12, otherwise: bb16];
}
bb12: {
_6 = const false;
goto -> bb10;
}
bb13: {
switchInt(copy _7) -> [0: bb14, otherwise: bb15];
}
bb14: {
_7 = const false;
goto -> bb12;
}
bb15: {
goto -> bb14;
}
bb16: {
_8 = discriminant(((_1 as Some).0: std::option::Option<std::option::Option<T>>));
switchInt(move _8) -> [1: bb13, otherwise: bb12];
}
bb17: {
switchInt(copy _4) -> [1: bb11, otherwise: bb10];
}
bb18 (cleanup): {
switchInt(copy _3) -> [1: bb19, otherwise: bb9];
}
bb19 (cleanup): {
goto -> bb9;
}
bb20 (cleanup): {
switchInt(copy _4) -> [1: bb18, otherwise: bb9];
}
}
@@ -23,22 +23,22 @@ fn main() {
assert_type_eq(x, &mut 0u8);
let &Foo(mut x) = &Foo(0);
//~^ ERROR: patterns are not allowed to reset the default binding mode
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
//~| WARN: this changes meaning in Rust 2024
assert_type_eq(x, 0u8);
let &mut Foo(mut x) = &mut Foo(0);
//~^ ERROR: patterns are not allowed to reset the default binding mode
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
//~| WARN: this changes meaning in Rust 2024
assert_type_eq(x, 0u8);
let &Foo(ref x) = &Foo(0);
//~^ ERROR: patterns are not allowed to reset the default binding mode
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
//~| WARN: this changes meaning in Rust 2024
assert_type_eq(x, &0u8);
let &mut Foo(ref x) = &mut Foo(0);
//~^ ERROR: patterns are not allowed to reset the default binding mode
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
//~| WARN: this changes meaning in Rust 2024
assert_type_eq(x, &0u8);
@@ -55,22 +55,22 @@ fn main() {
assert_type_eq(x, &0u8);
let &Foo(&x) = &Foo(&0);
//~^ ERROR: patterns are not allowed to reset the default binding mode
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
//~| WARN: this changes meaning in Rust 2024
assert_type_eq(x, 0u8);
let &Foo(&mut x) = &Foo(&mut 0);
//~^ ERROR: patterns are not allowed to reset the default binding mode
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
//~| WARN: this changes meaning in Rust 2024
assert_type_eq(x, 0u8);
let &mut Foo(&x) = &mut Foo(&0);
//~^ ERROR: patterns are not allowed to reset the default binding mode
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
//~| WARN: this changes meaning in Rust 2024
assert_type_eq(x, 0u8);
let &mut Foo(&mut x) = &mut Foo(&mut 0);
//~^ ERROR: patterns are not allowed to reset the default binding mode
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
//~| WARN: this changes meaning in Rust 2024
assert_type_eq(x, 0u8);
@@ -79,25 +79,25 @@ fn main() {
}
if let &&&&&Some(&x) = &&&&&Some(&0u8) {
//~^ ERROR: patterns are not allowed to reset the default binding mode
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
//~| WARN: this changes meaning in Rust 2024
assert_type_eq(x, 0u8);
}
if let &&&&&Some(&mut x) = &&&&&Some(&mut 0u8) {
//~^ ERROR: patterns are not allowed to reset the default binding mode
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
//~| WARN: this changes meaning in Rust 2024
assert_type_eq(x, 0u8);
}
if let &&&&&mut Some(&x) = &&&&&mut Some(&0u8) {
//~^ ERROR: patterns are not allowed to reset the default binding mode
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
//~| WARN: this changes meaning in Rust 2024
assert_type_eq(x, 0u8);
}
if let &mut Some(&mut Some(&mut Some(ref mut x))) = &mut Some(&mut Some(&mut Some(0u8))) {
//~^ ERROR: patterns are not allowed to reset the default binding mode
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
//~| WARN: this changes meaning in Rust 2024
assert_type_eq(x, &mut 0u8);
}
@@ -109,20 +109,20 @@ fn main() {
}
let &Struct { ref a, mut b, ref c } = &Struct { a: 0, b: 0, c: 0 };
//~^ ERROR: patterns are not allowed to reset the default binding mode
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
//~| WARN: this changes meaning in Rust 2024
assert_type_eq(a, &0u32);
assert_type_eq(b, 0u32);
let &Struct { a: &a, ref b, ref c } = &Struct { a: &0, b: &0, c: &0 };
//~^ ERROR: patterns are not allowed to reset the default binding mode
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
//~| WARN: this changes meaning in Rust 2024
assert_type_eq(a, 0u32);
assert_type_eq(b, &&0u32);
assert_type_eq(c, &&0u32);
if let &Struct { a: &Some(a), b: &Some(&b), c: &Some(ref c) } =
//~^ ERROR: patterns are not allowed to reset the default binding mode
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
//~| WARN: this changes meaning in Rust 2024
&(Struct { a: &Some(&0), b: &Some(&0), c: &Some(&0) })
{
@@ -135,7 +135,7 @@ fn main() {
// The two patterns are the same syntactically, but because they're defined in different
// editions they don't mean the same thing.
&(Some(mut x), migration_lint_macros::mixed_edition_pat!(y)) => {
//~^ ERROR: patterns are not allowed to reset the default binding mode
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
assert_type_eq(x, 0u32);
assert_type_eq(y, 0u32);
}
@@ -23,22 +23,22 @@ fn main() {
assert_type_eq(x, &mut 0u8);
let Foo(mut x) = &Foo(0);
//~^ ERROR: patterns are not allowed to reset the default binding mode
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
//~| WARN: this changes meaning in Rust 2024
assert_type_eq(x, 0u8);
let Foo(mut x) = &mut Foo(0);
//~^ ERROR: patterns are not allowed to reset the default binding mode
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
//~| WARN: this changes meaning in Rust 2024
assert_type_eq(x, 0u8);
let Foo(ref x) = &Foo(0);
//~^ ERROR: patterns are not allowed to reset the default binding mode
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
//~| WARN: this changes meaning in Rust 2024
assert_type_eq(x, &0u8);
let Foo(ref x) = &mut Foo(0);
//~^ ERROR: patterns are not allowed to reset the default binding mode
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
//~| WARN: this changes meaning in Rust 2024
assert_type_eq(x, &0u8);
@@ -55,22 +55,22 @@ fn main() {
assert_type_eq(x, &0u8);
let Foo(&x) = &Foo(&0);
//~^ ERROR: patterns are not allowed to reset the default binding mode
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
//~| WARN: this changes meaning in Rust 2024
assert_type_eq(x, 0u8);
let Foo(&mut x) = &Foo(&mut 0);
//~^ ERROR: patterns are not allowed to reset the default binding mode
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
//~| WARN: this changes meaning in Rust 2024
assert_type_eq(x, 0u8);
let Foo(&x) = &mut Foo(&0);
//~^ ERROR: patterns are not allowed to reset the default binding mode
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
//~| WARN: this changes meaning in Rust 2024
assert_type_eq(x, 0u8);
let Foo(&mut x) = &mut Foo(&mut 0);
//~^ ERROR: patterns are not allowed to reset the default binding mode
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
//~| WARN: this changes meaning in Rust 2024
assert_type_eq(x, 0u8);
@@ -79,25 +79,25 @@ fn main() {
}
if let Some(&x) = &&&&&Some(&0u8) {
//~^ ERROR: patterns are not allowed to reset the default binding mode
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
//~| WARN: this changes meaning in Rust 2024
assert_type_eq(x, 0u8);
}
if let Some(&mut x) = &&&&&Some(&mut 0u8) {
//~^ ERROR: patterns are not allowed to reset the default binding mode
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
//~| WARN: this changes meaning in Rust 2024
assert_type_eq(x, 0u8);
}
if let Some(&x) = &&&&&mut Some(&0u8) {
//~^ ERROR: patterns are not allowed to reset the default binding mode
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
//~| WARN: this changes meaning in Rust 2024
assert_type_eq(x, 0u8);
}
if let Some(&mut Some(Some(x))) = &mut Some(&mut Some(&mut Some(0u8))) {
//~^ ERROR: patterns are not allowed to reset the default binding mode
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
//~| WARN: this changes meaning in Rust 2024
assert_type_eq(x, &mut 0u8);
}
@@ -109,20 +109,20 @@ struct Struct<A, B, C> {
}
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 @@ struct Struct<A, B, C> {
// The two patterns are the same syntactically, but because they're defined in different
// editions they don't mean the same thing.
(Some(mut x), migration_lint_macros::mixed_edition_pat!(y)) => {
//~^ ERROR: patterns are not allowed to reset the default binding mode
//~^ ERROR: this pattern relies on behavior which may change in edition 2024
assert_type_eq(x, 0u32);
assert_type_eq(y, 0u32);
}
@@ -1,10 +1,8 @@
error: patterns are not allowed to reset the default binding mode in edition 2024
--> $DIR/migration_lint.rs:25:9
error: this pattern relies on behavior which may change in edition 2024
--> $DIR/migration_lint.rs:25:13
|
LL | let Foo(mut x) = &Foo(0);
| -^^^^^^^^^
| |
| help: desugar the match ergonomics: `&`
| ^^^ requires binding by-value, but the implicit default is by-reference
|
= warning: this changes meaning in Rust 2024
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
@@ -13,176 +11,211 @@ note: the lint level is defined here
|
LL | #![deny(rust_2024_incompatible_pat)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
help: make the implied reference pattern explicit
|
LL | let &Foo(mut x) = &Foo(0);
| +
error: patterns are not allowed to reset the default binding mode in edition 2024
--> $DIR/migration_lint.rs:30:9
error: this pattern relies on behavior which may change in edition 2024
--> $DIR/migration_lint.rs:30:13
|
LL | let Foo(mut x) = &mut Foo(0);
| -^^^^^^^^^
| |
| help: desugar the match ergonomics: `&mut`
| ^^^ requires binding by-value, but the implicit default is by-reference
|
= warning: this changes meaning in Rust 2024
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
help: make the implied reference pattern explicit
|
LL | let &mut Foo(mut x) = &mut Foo(0);
| ++++
error: patterns are not allowed to reset the default binding mode in edition 2024
--> $DIR/migration_lint.rs:35:9
error: this pattern relies on behavior which may change in edition 2024
--> $DIR/migration_lint.rs:35:13
|
LL | let Foo(ref x) = &Foo(0);
| -^^^^^^^^^
| |
| help: desugar the match ergonomics: `&`
| ^^^ cannot override to bind by-reference when that is the implicit default
|
= warning: this changes meaning in Rust 2024
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
help: make the implied reference pattern explicit
|
LL | let &Foo(ref x) = &Foo(0);
| +
error: patterns are not allowed to reset the default binding mode in edition 2024
--> $DIR/migration_lint.rs:40:9
error: this pattern relies on behavior which may change in edition 2024
--> $DIR/migration_lint.rs:40:13
|
LL | let Foo(ref x) = &mut Foo(0);
| -^^^^^^^^^
| |
| help: desugar the match ergonomics: `&mut`
| ^^^ cannot override to bind by-reference when that is the implicit default
|
= warning: this changes meaning in Rust 2024
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
help: make the implied reference pattern explicit
|
LL | let &mut Foo(ref x) = &mut Foo(0);
| ++++
error: patterns are not allowed to reset the default binding mode in edition 2024
--> $DIR/migration_lint.rs:57:9
error: this pattern relies on behavior which may change in edition 2024
--> $DIR/migration_lint.rs:57:13
|
LL | let Foo(&x) = &Foo(&0);
| -^^^^^^
| |
| help: desugar the match ergonomics: `&`
| ^ cannot implicitly match against multiple layers of reference
|
= warning: this changes meaning in Rust 2024
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
help: make the implied reference pattern explicit
|
LL | let &Foo(&x) = &Foo(&0);
| +
error: patterns are not allowed to reset the default binding mode in edition 2024
--> $DIR/migration_lint.rs:62:9
error: this pattern relies on behavior which may change in edition 2024
--> $DIR/migration_lint.rs:62:13
|
LL | let Foo(&mut x) = &Foo(&mut 0);
| -^^^^^^^^^^
| |
| help: desugar the match ergonomics: `&`
| ^^^^ cannot implicitly match against multiple layers of reference
|
= warning: this changes meaning in Rust 2024
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
help: make the implied reference pattern explicit
|
LL | let &Foo(&mut x) = &Foo(&mut 0);
| +
error: patterns are not allowed to reset the default binding mode in edition 2024
--> $DIR/migration_lint.rs:67:9
error: this pattern relies on behavior which may change in edition 2024
--> $DIR/migration_lint.rs:67:13
|
LL | let Foo(&x) = &mut Foo(&0);
| -^^^^^^
| |
| help: desugar the match ergonomics: `&mut`
| ^ cannot implicitly match against multiple layers of reference
|
= warning: this changes meaning in Rust 2024
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
help: make the implied reference pattern explicit
|
LL | let &mut Foo(&x) = &mut Foo(&0);
| ++++
error: patterns are not allowed to reset the default binding mode in edition 2024
--> $DIR/migration_lint.rs:72:9
error: this pattern relies on behavior which may change in edition 2024
--> $DIR/migration_lint.rs:72:13
|
LL | let Foo(&mut x) = &mut Foo(&mut 0);
| -^^^^^^^^^^
| |
| help: desugar the match ergonomics: `&mut`
| ^^^^ cannot implicitly match against multiple layers of reference
|
= warning: this changes meaning in Rust 2024
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
help: make the implied reference pattern explicit
|
LL | let &mut Foo(&mut x) = &mut Foo(&mut 0);
| ++++
error: patterns are not allowed to reset the default binding mode in edition 2024
--> $DIR/migration_lint.rs:81:12
error: this pattern relies on behavior which may change in edition 2024
--> $DIR/migration_lint.rs:81:17
|
LL | if let Some(&x) = &&&&&Some(&0u8) {
| -^^^^^^^
| |
| help: desugar the match ergonomics: `&&&&&`
| ^ cannot implicitly match against multiple layers of reference
|
= warning: this changes meaning in Rust 2024
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
help: make the implied reference patterns explicit
|
LL | if let &&&&&Some(&x) = &&&&&Some(&0u8) {
| +++++
error: patterns are not allowed to reset the default binding mode in edition 2024
--> $DIR/migration_lint.rs:87:12
error: this pattern relies on behavior which may change in edition 2024
--> $DIR/migration_lint.rs:87:17
|
LL | if let Some(&mut x) = &&&&&Some(&mut 0u8) {
| -^^^^^^^^^^^
| |
| help: desugar the match ergonomics: `&&&&&`
| ^^^^ cannot implicitly match against multiple layers of reference
|
= warning: this changes meaning in Rust 2024
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
help: make the implied reference patterns explicit
|
LL | if let &&&&&Some(&mut x) = &&&&&Some(&mut 0u8) {
| +++++
error: patterns are not allowed to reset the default binding mode in edition 2024
--> $DIR/migration_lint.rs:93:12
error: this pattern relies on behavior which may change in edition 2024
--> $DIR/migration_lint.rs:93:17
|
LL | if let Some(&x) = &&&&&mut Some(&0u8) {
| -^^^^^^^
| |
| help: desugar the match ergonomics: `&&&&&mut`
| ^ cannot implicitly match against multiple layers of reference
|
= warning: this changes meaning in Rust 2024
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
help: make the implied reference patterns explicit
|
LL | if let &&&&&mut Some(&x) = &&&&&mut Some(&0u8) {
| ++++++++
error: patterns are not allowed to reset the default binding mode in edition 2024
--> $DIR/migration_lint.rs:99:12
error: this pattern relies on behavior which may change in edition 2024
--> $DIR/migration_lint.rs:99:17
|
LL | if let Some(&mut Some(Some(x))) = &mut Some(&mut Some(&mut Some(0u8))) {
| ^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^ cannot implicitly match against multiple layers of reference
|
= warning: this changes meaning in Rust 2024
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
help: desugar the match ergonomics
help: make the implied reference patterns and variable binding mode explicit
|
LL | if let &mut Some(&mut Some(&mut Some(ref mut x))) = &mut Some(&mut Some(&mut Some(0u8))) {
| ++++ ++++ +++++++
error: patterns are not allowed to reset the default binding mode in edition 2024
--> $DIR/migration_lint.rs:111:9
error: this pattern relies on behavior which may change in edition 2024
--> $DIR/migration_lint.rs:111:21
|
LL | let Struct { a, mut b, c } = &Struct { a: 0, b: 0, c: 0 };
| ^^^^^^^^^^^^^^^^^^^^^^
| ^^^ requires binding by-value, but the implicit default is by-reference
|
= warning: this changes meaning in Rust 2024
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
help: desugar the match ergonomics
help: make the implied reference pattern and variable binding modes explicit
|
LL | let &Struct { ref a, mut b, ref c } = &Struct { a: 0, b: 0, c: 0 };
| + +++ +++
error: patterns are not allowed to reset the default binding mode in edition 2024
--> $DIR/migration_lint.rs:117:9
error: this pattern relies on behavior which may change in edition 2024
--> $DIR/migration_lint.rs:117:21
|
LL | let Struct { a: &a, b, ref c } = &Struct { a: &0, b: &0, c: &0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^ ^^^ cannot override to bind by-reference when that is the implicit default
| |
| cannot implicitly match against multiple layers of reference
|
= warning: this changes meaning in Rust 2024
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
help: desugar the match ergonomics
help: make the implied reference pattern and variable binding mode explicit
|
LL | let &Struct { a: &a, ref b, ref c } = &Struct { a: &0, b: &0, c: &0 };
| + +++
error: patterns are not allowed to reset the default binding mode in edition 2024
--> $DIR/migration_lint.rs:124:12
error: this pattern relies on behavior which may change in edition 2024
--> $DIR/migration_lint.rs:124:24
|
LL | if let Struct { a: &Some(a), b: Some(&b), c: Some(c) } =
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^ ^ cannot implicitly match against multiple layers of reference
| |
| cannot implicitly match against multiple layers of reference
|
= warning: this changes meaning in Rust 2024
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
help: desugar the match ergonomics
help: make the implied reference patterns and variable binding mode explicit
|
LL | if let &Struct { a: &Some(a), b: &Some(&b), c: &Some(ref c) } =
| + + + +++
error: patterns are not allowed to reset the default binding mode in edition 2024
--> $DIR/migration_lint.rs:137:9
error: this pattern relies on behavior which may change in edition 2024
--> $DIR/migration_lint.rs:137:15
|
LL | (Some(mut x), migration_lint_macros::mixed_edition_pat!(y)) => {
| -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| help: desugar the match ergonomics: `&`
| ^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ default binding mode is reset within expansion
| |
| requires binding by-value, but the implicit default is by-reference
|
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
= note: this error originates in the macro `migration_lint_macros::mixed_edition_pat` (in Nightly builds, run with -Z macro-backtrace for more info)
help: make the implied reference pattern explicit
|
LL | &(Some(mut x), migration_lint_macros::mixed_edition_pat!(y)) => {
| +
error: aborting due to 16 previous errors
@@ -21,17 +21,17 @@ fn foo($($tt)*) {}
}
test_pat_on_type![(&x,): &(T,)]; //~ ERROR mismatched types
test_pat_on_type![(&x,): &(&T,)]; //~ ERROR patterns are not allowed to reset the default binding mode
test_pat_on_type![(&x,): &(&T,)]; //~ ERROR this pattern relies on behavior which may change in edition 2024
test_pat_on_type![(&x,): &(&mut T,)]; //~ ERROR mismatched types
test_pat_on_type![(&mut x,): &(&T,)]; //~ ERROR mismatched types
test_pat_on_type![(&mut x,): &(&mut T,)]; //~ ERROR patterns are not allowed to reset the default binding mode
test_pat_on_type![(&mut x,): &(&mut T,)]; //~ ERROR this pattern relies on behavior which may change in edition 2024
test_pat_on_type![(&x,): &&mut &(T,)]; //~ ERROR mismatched types
test_pat_on_type![Foo { f: (&x,) }: Foo]; //~ ERROR mismatched types
test_pat_on_type![Foo { f: (&x,) }: &mut Foo]; //~ ERROR mismatched types
test_pat_on_type![Foo { f: &(x,) }: &Foo]; //~ ERROR patterns are not allowed to reset the default binding mode
test_pat_on_type![(mut x,): &(T,)]; //~ ERROR patterns are not allowed to reset the default binding mode
test_pat_on_type![(ref x,): &(T,)]; //~ ERROR patterns are not allowed to reset the default binding mode
test_pat_on_type![(ref mut x,): &mut (T,)]; //~ ERROR patterns are not allowed to reset the default binding mode
test_pat_on_type![Foo { f: &(x,) }: &Foo]; //~ ERROR this pattern relies on behavior which may change in edition 2024
test_pat_on_type![(mut x,): &(T,)]; //~ ERROR this pattern relies on behavior which may change in edition 2024
test_pat_on_type![(ref x,): &(T,)]; //~ ERROR this pattern relies on behavior which may change in edition 2024
test_pat_on_type![(ref mut x,): &mut (T,)]; //~ ERROR this pattern relies on behavior which may change in edition 2024
fn get<X>() -> X {
unimplemented!()
@@ -40,6 +40,6 @@ fn get<X>() -> X {
// Make sure this works even when the underlying type is inferred. This test passes on rust stable.
fn infer<X: Copy>() -> X {
match &get() {
(&x,) => x, //~ ERROR patterns are not allowed to reset the default binding mode
(&x,) => x, //~ ERROR this pattern relies on behavior which may change in edition 2024
}
}
@@ -99,61 +99,89 @@ LL - test_pat_on_type![Foo { f: (&x,) }: &mut Foo];
LL + test_pat_on_type![Foo { f: (x,) }: &mut Foo];
|
error: patterns are not allowed to reset the default binding mode in edition 2024
--> $DIR/min_match_ergonomics_fail.rs:24:19
error: this pattern relies on behavior which may change in edition 2024
--> $DIR/min_match_ergonomics_fail.rs:24:20
|
LL | test_pat_on_type![(&x,): &(&T,)];
| -^^^^
| |
| help: desugar the match ergonomics: `&`
| ^ cannot implicitly match against multiple layers of reference
|
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
help: make the implied reference pattern explicit
|
LL | test_pat_on_type![&(&x,): &(&T,)];
| +
error: patterns are not allowed to reset the default binding mode in edition 2024
--> $DIR/min_match_ergonomics_fail.rs:27:19
error: this pattern relies on behavior which may change in edition 2024
--> $DIR/min_match_ergonomics_fail.rs:27:20
|
LL | test_pat_on_type![(&mut x,): &(&mut T,)];
| -^^^^^^^^
| |
| help: desugar the match ergonomics: `&`
| ^^^^ cannot implicitly match against multiple layers of reference
|
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
help: make the implied reference pattern explicit
|
LL | test_pat_on_type![&(&mut x,): &(&mut T,)];
| +
error: patterns are not allowed to reset the default binding mode in edition 2024
--> $DIR/min_match_ergonomics_fail.rs:31:19
error: this pattern relies on behavior which may change in edition 2024
--> $DIR/min_match_ergonomics_fail.rs:31:28
|
LL | test_pat_on_type![Foo { f: &(x,) }: &Foo];
| -^^^^^^^^^^^^^^^
| |
| help: desugar the match ergonomics: `&`
| ^ cannot implicitly match against multiple layers of reference
|
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
help: make the implied reference pattern explicit
|
LL | test_pat_on_type![&Foo { f: &(x,) }: &Foo];
| +
error: patterns are not allowed to reset the default binding mode in edition 2024
--> $DIR/min_match_ergonomics_fail.rs:32:19
error: this pattern relies on behavior which may change in edition 2024
--> $DIR/min_match_ergonomics_fail.rs:32:20
|
LL | test_pat_on_type![(mut x,): &(T,)];
| -^^^^^^^
| |
| help: desugar the match ergonomics: `&`
| ^^^ requires binding by-value, but the implicit default is by-reference
|
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
help: make the implied reference pattern explicit
|
LL | test_pat_on_type![&(mut x,): &(T,)];
| +
error: patterns are not allowed to reset the default binding mode in edition 2024
--> $DIR/min_match_ergonomics_fail.rs:33:19
error: this pattern relies on behavior which may change in edition 2024
--> $DIR/min_match_ergonomics_fail.rs:33:20
|
LL | test_pat_on_type![(ref x,): &(T,)];
| -^^^^^^^
| |
| help: desugar the match ergonomics: `&`
| ^^^ cannot override to bind by-reference when that is the implicit default
|
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
help: make the implied reference pattern explicit
|
LL | test_pat_on_type![&(ref x,): &(T,)];
| +
error: patterns are not allowed to reset the default binding mode in edition 2024
--> $DIR/min_match_ergonomics_fail.rs:34:19
error: this pattern relies on behavior which may change in edition 2024
--> $DIR/min_match_ergonomics_fail.rs:34:20
|
LL | test_pat_on_type![(ref mut x,): &mut (T,)];
| -^^^^^^^^^^^
| |
| help: desugar the match ergonomics: `&mut`
| ^^^^^^^ cannot override to bind by-reference when that is the implicit default
|
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
help: make the implied reference pattern explicit
|
LL | test_pat_on_type![&mut (ref mut x,): &mut (T,)];
| ++++
error: patterns are not allowed to reset the default binding mode in edition 2024
--> $DIR/min_match_ergonomics_fail.rs:43:9
error: this pattern relies on behavior which may change in edition 2024
--> $DIR/min_match_ergonomics_fail.rs:43:10
|
LL | (&x,) => x,
| -^^^^
| |
| help: desugar the match ergonomics: `&`
| ^ cannot implicitly match against multiple layers of reference
|
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html>
help: make the implied reference pattern explicit
|
LL | &(&x,) => x,
| +
error: aborting due to 13 previous errors
@@ -0,0 +1,22 @@
//@ compile-flags: -Znext-solver
//@ check-pass
#![feature(const_trait_impl)]
#![allow(refining_impl_trait)]
#[const_trait]
pub trait Foo {
fn method(self) -> impl ~const Bar;
}
#[const_trait]
pub trait Bar {}
struct A<T>(T);
impl<T> const Foo for A<T> where A<T>: ~const Bar {
fn method(self) -> impl ~const Bar {
self
}
}
fn main() {}
@@ -1,15 +1,10 @@
//@ compile-flags: -Znext-solver
//@ known-bug: #110395
//@ failure-status: 101
//@ dont-check-compiler-stderr
// Broken until we have `&T: const Deref` impl in stdlib
// Broken until we have `const PartialEq` impl in stdlib
#![allow(incomplete_features)]
#![feature(
const_trait_impl,
effects,
const_cmp,
)]
#![feature(const_trait_impl, const_cmp, const_destruct)]
use std::marker::Destruct;
@@ -17,9 +12,9 @@ const fn cmp(a: &impl ~const PartialEq) -> bool {
a == a
}
const fn wrap(x: impl ~const PartialEq + ~const Destruct)
-> impl ~const PartialEq + ~const Destruct
{
const fn wrap(
x: impl ~const PartialEq + ~const Destruct,
) -> impl ~const PartialEq + ~const Destruct {
x
}
@@ -48,11 +43,15 @@ trait T {}
struct S;
impl const T for S {}
const fn rpit() -> impl ~const T { S }
const fn rpit() -> impl ~const T {
S
}
const fn apit(_: impl ~const T + ~const Destruct) {}
const fn rpit_assoc_bound() -> impl IntoIterator<Item: ~const T> { Some(S) }
const fn rpit_assoc_bound() -> impl IntoIterator<Item: ~const T> {
Some(S)
}
const fn apit_assoc_bound(_: impl IntoIterator<Item: ~const T> + ~const Destruct) {}
@@ -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`.