diff options
166 files changed, 2736 insertions, 1982 deletions
diff --git a/Cargo.lock b/Cargo.lock index d1889fb6861..afeb9faec09 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4168,6 +4168,7 @@ dependencies = [ "rustc_index", "rustc_macros", "rustc_middle", + "rustc_next_trait_solver", "rustc_span", "rustc_target", "rustc_type_ir", diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs index 2cf811e9122..7754ca0a0f5 100644 --- a/compiler/rustc_ast/src/ast_traits.rs +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -10,8 +10,6 @@ use crate::{AssocItem, Expr, ForeignItem, Item, NodeId}; use crate::{AttrItem, AttrKind, Block, Pat, Path, Ty, Visibility}; use crate::{AttrVec, Attribute, Stmt, StmtKind}; -use rustc_span::Span; - use std::fmt; use std::marker::PhantomData; @@ -91,37 +89,6 @@ impl<T: AstDeref<Target: HasNodeId>> HasNodeId for T { } } -/// A trait for AST nodes having a span. -pub trait HasSpan { - fn span(&self) -> Span; -} - -macro_rules! impl_has_span { - ($($T:ty),+ $(,)?) => { - $( - impl HasSpan for $T { - fn span(&self) -> Span { - self.span - } - } - )+ - }; -} - -impl_has_span!(AssocItem, Block, Expr, ForeignItem, Item, Pat, Path, Stmt, Ty, Visibility); - -impl<T: AstDeref<Target: HasSpan>> HasSpan for T { - fn span(&self) -> Span { - self.ast_deref().span() - } -} - -impl HasSpan for AttrItem { - fn span(&self) -> Span { - self.span() - } -} - /// A trait for AST nodes having (or not having) collected tokens. pub trait HasTokens { fn tokens(&self) -> Option<&LazyAttrTokenStream>; diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 65f1b5dbaf5..088ae9ba441 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -202,7 +202,8 @@ impl Attribute { } } - pub fn tokens(&self) -> TokenStream { + // Named `get_tokens` to distinguish it from the `<Attribute as HasTokens>::tokens` method. + pub fn get_tokens(&self) -> TokenStream { match &self.kind { AttrKind::Normal(normal) => TokenStream::new( normal diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 7ca950e50e6..846a108091f 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -44,7 +44,7 @@ pub mod tokenstream; pub mod visit; pub use self::ast::*; -pub use self::ast_traits::{AstDeref, AstNodeWrapper, HasAttrs, HasNodeId, HasSpan, HasTokens}; +pub use self::ast_traits::{AstDeref, AstNodeWrapper, HasAttrs, HasNodeId, HasTokens}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index f816375b912..cbf21317f1a 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -704,7 +704,7 @@ fn visit_attr_tt<T: MutVisitor>(tt: &mut AttrTokenTree, vis: &mut T) { visit_attr_tts(tts, vis); visit_delim_span(dspan, vis); } - AttrTokenTree::Attributes(AttributesData { attrs, tokens }) => { + AttrTokenTree::AttrsTarget(AttrsTarget { attrs, tokens }) => { visit_attrs(attrs, vis); visit_lazy_tts_opt_mut(Some(tokens), vis); } diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 655c18e4559..ee068f19332 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -14,7 +14,7 @@ //! ownership of the original. use crate::ast::{AttrStyle, StmtKind}; -use crate::ast_traits::{HasAttrs, HasSpan, HasTokens}; +use crate::ast_traits::{HasAttrs, HasTokens}; use crate::token::{self, Delimiter, Nonterminal, Token, TokenKind}; use crate::AttrVec; @@ -170,8 +170,8 @@ pub enum AttrTokenTree { Delimited(DelimSpan, DelimSpacing, Delimiter, AttrTokenStream), /// Stores the attributes for an attribute target, /// along with the tokens for that attribute target. - /// See `AttributesData` for more information - Attributes(AttributesData), + /// See `AttrsTarget` for more information + AttrsTarget(AttrsTarget), } impl AttrTokenStream { @@ -180,7 +180,7 @@ impl AttrTokenStream { } /// Converts this `AttrTokenStream` to a plain `Vec<TokenTree>`. - /// During conversion, `AttrTokenTree::Attributes` get 'flattened' + /// During conversion, `AttrTokenTree::AttrsTarget` get 'flattened' /// back to a `TokenStream` of the form `outer_attr attr_target`. /// If there are inner attributes, they are inserted into the proper /// place in the attribute target tokens. @@ -199,13 +199,13 @@ impl AttrTokenStream { TokenStream::new(stream.to_token_trees()), )) } - AttrTokenTree::Attributes(data) => { - let idx = data + AttrTokenTree::AttrsTarget(target) => { + let idx = target .attrs .partition_point(|attr| matches!(attr.style, crate::AttrStyle::Outer)); - let (outer_attrs, inner_attrs) = data.attrs.split_at(idx); + let (outer_attrs, inner_attrs) = target.attrs.split_at(idx); - let mut target_tokens = data.tokens.to_attr_token_stream().to_token_trees(); + let mut target_tokens = target.tokens.to_attr_token_stream().to_token_trees(); if !inner_attrs.is_empty() { let mut found = false; // Check the last two trees (to account for a trailing semi) @@ -227,7 +227,7 @@ impl AttrTokenStream { let mut stream = TokenStream::default(); for inner_attr in inner_attrs { - stream.push_stream(inner_attr.tokens()); + stream.push_stream(inner_attr.get_tokens()); } stream.push_stream(delim_tokens.clone()); *tree = TokenTree::Delimited(*span, *spacing, *delim, stream); @@ -242,7 +242,7 @@ impl AttrTokenStream { ); } for attr in outer_attrs { - res.extend(attr.tokens().0.iter().cloned()); + res.extend(attr.get_tokens().0.iter().cloned()); } res.extend(target_tokens); } @@ -262,7 +262,7 @@ impl AttrTokenStream { /// have an `attrs` field containing the `#[cfg(FALSE)]` attr, /// and a `tokens` field storing the (unparsed) tokens `struct Foo {}` #[derive(Clone, Debug, Encodable, Decodable)] -pub struct AttributesData { +pub struct AttrsTarget { /// Attributes, both outer and inner. /// These are stored in the original order that they were parsed in. pub attrs: AttrVec, @@ -436,17 +436,17 @@ impl TokenStream { TokenStream::new(vec![TokenTree::token_alone(kind, span)]) } - pub fn from_ast(node: &(impl HasAttrs + HasSpan + HasTokens + fmt::Debug)) -> TokenStream { + pub fn from_ast(node: &(impl HasAttrs + HasTokens + fmt::Debug)) -> TokenStream { let Some(tokens) = node.tokens() else { - panic!("missing tokens for node at {:?}: {:?}", node.span(), node); + panic!("missing tokens for node: {:?}", node); }; let attrs = node.attrs(); let attr_stream = if attrs.is_empty() { tokens.to_attr_token_stream() } else { - let attr_data = - AttributesData { attrs: attrs.iter().cloned().collect(), tokens: tokens.clone() }; - AttrTokenStream::new(vec![AttrTokenTree::Attributes(attr_data)]) + let target = + AttrsTarget { attrs: attrs.iter().cloned().collect(), tokens: tokens.clone() }; + AttrTokenStream::new(vec![AttrTokenTree::AttrsTarget(target)]) }; TokenStream::new(attr_stream.to_token_trees()) } @@ -765,6 +765,7 @@ mod size_asserts { static_assert_size!(AttrTokenStream, 8); static_assert_size!(AttrTokenTree, 32); static_assert_size!(LazyAttrTokenStream, 8); + static_assert_size!(Option<LazyAttrTokenStream>, 8); // must be small, used in many AST nodes static_assert_size!(TokenStream, 8); static_assert_size!(TokenTree, 32); // tidy-alphabetical-end diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index b9a82046e59..02b9c2d48b1 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -1,8 +1,9 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorGuaranteed; -use rustc_infer::infer::relate::{PredicateEmittingRelation, StructurallyRelateAliases}; -use rustc_infer::infer::relate::{Relate, RelateResult, TypeRelation}; -use rustc_infer::infer::NllRegionVariableOrigin; +use rustc_infer::infer::relate::{ + PredicateEmittingRelation, Relate, RelateResult, StructurallyRelateAliases, TypeRelation, +}; +use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin}; use rustc_infer::traits::solve::Goal; use rustc_infer::traits::Obligation; use rustc_middle::mir::ConstraintCategory; @@ -522,7 +523,7 @@ impl<'bccx, 'tcx> TypeRelation<TyCtxt<'tcx>> for NllTypeRelating<'_, 'bccx, 'tcx } } -impl<'bccx, 'tcx> PredicateEmittingRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> { +impl<'bccx, 'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for NllTypeRelating<'_, 'bccx, 'tcx> { fn span(&self) -> Span { self.locations.span(self.type_checker.body) } diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index 884cebf1939..b09975c0ba7 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -193,7 +193,7 @@ impl CfgEval<'_> { // Re-parse the tokens, setting the `capture_cfg` flag to save extra information // to the captured `AttrTokenStream` (specifically, we capture - // `AttrTokenTree::AttributesData` for all occurrences of `#[cfg]` and `#[cfg_attr]`) + // `AttrTokenTree::AttrsTarget` for all occurrences of `#[cfg]` and `#[cfg_attr]`) let mut parser = Parser::new(&self.0.sess.psess, orig_tokens, None); parser.capture_cfg = true; match parse_annotatable_with(&mut parser) { diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 1d54da267ee..d86f1a7a34f 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -301,9 +301,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } // The signed form of the intrinsic allows this. If we interpret the // difference as isize, we'll get the proper signed difference. If that - // seems *positive*, they were more than isize::MAX apart. + // seems *positive* or equal to isize::MIN, they were more than isize::MAX apart. let dist = val.to_target_isize(self)?; - if dist >= 0 { + if dist >= 0 || i128::from(dist) == self.pointer_size().signed_int_min() { throw_ub_custom!( fluent::const_eval_offset_from_underflow, name = intrinsic_name, diff --git a/compiler/rustc_error_codes/src/error_codes/E0502.md b/compiler/rustc_error_codes/src/error_codes/E0502.md index dc3ffdfddd9..85f38b9286f 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0502.md +++ b/compiler/rustc_error_codes/src/error_codes/E0502.md @@ -1,4 +1,5 @@ -A variable already borrowed as immutable was borrowed as mutable. +A variable already borrowed with a certain mutability (either mutable or +immutable) was borrowed again with a different mutability. Erroneous code example: @@ -13,7 +14,7 @@ fn foo(a: &mut i32) { ``` To fix this error, ensure that you don't have any other references to the -variable before trying to access it mutably: +variable before trying to access it with a different mutability: ``` fn bar(x: &mut i32) {} diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 56cbb54fcec..40e16b45115 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -172,7 +172,7 @@ impl<'a> StripUnconfigured<'a> { fn configure_tokens(&self, stream: &AttrTokenStream) -> AttrTokenStream { fn can_skip(stream: &AttrTokenStream) -> bool { stream.0.iter().all(|tree| match tree { - AttrTokenTree::Attributes(_) => false, + AttrTokenTree::AttrsTarget(_) => false, AttrTokenTree::Token(..) => true, AttrTokenTree::Delimited(.., inner) => can_skip(inner), }) @@ -185,22 +185,22 @@ impl<'a> StripUnconfigured<'a> { let trees: Vec<_> = stream .0 .iter() - .flat_map(|tree| match tree.clone() { - AttrTokenTree::Attributes(mut data) => { - data.attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr)); + .filter_map(|tree| match tree.clone() { + AttrTokenTree::AttrsTarget(mut target) => { + target.attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr)); - if self.in_cfg(&data.attrs) { - data.tokens = LazyAttrTokenStream::new( - self.configure_tokens(&data.tokens.to_attr_token_stream()), + if self.in_cfg(&target.attrs) { + target.tokens = LazyAttrTokenStream::new( + self.configure_tokens(&target.tokens.to_attr_token_stream()), ); - Some(AttrTokenTree::Attributes(data)).into_iter() + Some(AttrTokenTree::AttrsTarget(target)) } else { - None.into_iter() + None } } AttrTokenTree::Delimited(sp, spacing, delim, mut inner) => { inner = self.configure_tokens(&inner); - Some(AttrTokenTree::Delimited(sp, spacing, delim, inner)).into_iter() + Some(AttrTokenTree::Delimited(sp, spacing, delim, inner)) } AttrTokenTree::Token( Token { @@ -220,9 +220,7 @@ impl<'a> StripUnconfigured<'a> { ) => { panic!("Should be `AttrTokenTree::Delimited`, not delim tokens: {:?}", tree); } - AttrTokenTree::Token(token, spacing) => { - Some(AttrTokenTree::Token(token, spacing)).into_iter() - } + AttrTokenTree::Token(token, spacing) => Some(AttrTokenTree::Token(token, spacing)), }) .collect(); AttrTokenStream::new(trees) @@ -294,7 +292,7 @@ impl<'a> StripUnconfigured<'a> { attr: &Attribute, (item, item_span): (ast::AttrItem, Span), ) -> Attribute { - let orig_tokens = attr.tokens(); + let orig_tokens = attr.get_tokens(); // We are taking an attribute of the form `#[cfg_attr(pred, attr)]` // and producing an attribute of the form `#[attr]`. We @@ -310,12 +308,11 @@ impl<'a> StripUnconfigured<'a> { else { panic!("Bad tokens for attribute {attr:?}"); }; - let pound_span = pound_token.span; // We don't really have a good span to use for the synthesized `[]` // in `#[attr]`, so just use the span of the `#` token. let bracket_group = AttrTokenTree::Delimited( - DelimSpan::from_single(pound_span), + DelimSpan::from_single(pound_token.span), DelimSpacing::new(Spacing::JointHidden, Spacing::Alone), Delimiter::Bracket, item.tokens diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs index 25958e03028..dbbd948fd70 100644 --- a/compiler/rustc_expand/src/mbe/metavar_expr.rs +++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs @@ -1,4 +1,4 @@ -use rustc_ast::token::{self, Delimiter, IdentIsRaw}; +use rustc_ast::token::{self, Delimiter, IdentIsRaw, Lit, Token, TokenKind}; use rustc_ast::tokenstream::{RefTokenTreeCursor, TokenStream, TokenTree}; use rustc_ast::{LitIntType, LitKind}; use rustc_ast_pretty::pprust; @@ -6,9 +6,10 @@ use rustc_errors::{Applicability, PResult}; use rustc_macros::{Decodable, Encodable}; use rustc_session::parse::ParseSess; use rustc_span::symbol::Ident; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; pub(crate) const RAW_IDENT_ERR: &str = "`${concat(..)}` currently does not support raw identifiers"; +pub(crate) const UNSUPPORTED_CONCAT_ELEM_ERR: &str = "expected identifier or string literal"; /// A meta-variable expression, for expansions based on properties of meta-variables. #[derive(Debug, PartialEq, Encodable, Decodable)] @@ -51,11 +52,26 @@ impl MetaVarExpr { let mut result = Vec::new(); loop { let is_var = try_eat_dollar(&mut iter); - let element_ident = parse_ident(&mut iter, psess, outer_span)?; + let token = parse_token(&mut iter, psess, outer_span)?; let element = if is_var { - MetaVarExprConcatElem::Var(element_ident) + MetaVarExprConcatElem::Var(parse_ident_from_token(psess, token)?) + } else if let TokenKind::Literal(Lit { + kind: token::LitKind::Str, + symbol, + suffix: None, + }) = token.kind + { + MetaVarExprConcatElem::Literal(symbol) } else { - MetaVarExprConcatElem::Ident(element_ident) + match parse_ident_from_token(psess, token) { + Err(err) => { + err.cancel(); + return Err(psess + .dcx() + .struct_span_err(token.span, UNSUPPORTED_CONCAT_ELEM_ERR)); + } + Ok(elem) => MetaVarExprConcatElem::Ident(elem), + } }; result.push(element); if iter.look_ahead(0).is_none() { @@ -105,11 +121,13 @@ impl MetaVarExpr { #[derive(Debug, Decodable, Encodable, PartialEq)] pub(crate) enum MetaVarExprConcatElem { - /// There is NO preceding dollar sign, which means that this identifier should be interpreted - /// as a literal. + /// Identifier WITHOUT a preceding dollar sign, which means that this identifier should be + /// interpreted as a literal. Ident(Ident), - /// There is a preceding dollar sign, which means that this identifier should be expanded - /// and interpreted as a variable. + /// For example, a number or a string. + Literal(Symbol), + /// Identifier WITH a preceding dollar sign, which means that this identifier should be + /// expanded and interpreted as a variable. Var(Ident), } @@ -158,7 +176,7 @@ fn parse_depth<'psess>( span: Span, ) -> PResult<'psess, usize> { let Some(tt) = iter.next() else { return Ok(0) }; - let TokenTree::Token(token::Token { kind: token::TokenKind::Literal(lit), .. }, _) = tt else { + let TokenTree::Token(Token { kind: TokenKind::Literal(lit), .. }, _) = tt else { return Err(psess .dcx() .struct_span_err(span, "meta-variable expression depth must be a literal")); @@ -180,12 +198,14 @@ fn parse_ident<'psess>( psess: &'psess ParseSess, fallback_span: Span, ) -> PResult<'psess, Ident> { - let Some(tt) = iter.next() else { - return Err(psess.dcx().struct_span_err(fallback_span, "expected identifier")); - }; - let TokenTree::Token(token, _) = tt else { - return Err(psess.dcx().struct_span_err(tt.span(), "expected identifier")); - }; + let token = parse_token(iter, psess, fallback_span)?; + parse_ident_from_token(psess, token) +} + +fn parse_ident_from_token<'psess>( + psess: &'psess ParseSess, + token: &Token, +) -> PResult<'psess, Ident> { if let Some((elem, is_raw)) = token.ident() { if let IdentIsRaw::Yes = is_raw { return Err(psess.dcx().struct_span_err(elem.span, RAW_IDENT_ERR)); @@ -205,10 +225,24 @@ fn parse_ident<'psess>( Err(err) } +fn parse_token<'psess, 't>( + iter: &mut RefTokenTreeCursor<'t>, + psess: &'psess ParseSess, + fallback_span: Span, +) -> PResult<'psess, &'t Token> { + let Some(tt) = iter.next() else { + return Err(psess.dcx().struct_span_err(fallback_span, UNSUPPORTED_CONCAT_ELEM_ERR)); + }; + let TokenTree::Token(token, _) = tt else { + return Err(psess.dcx().struct_span_err(tt.span(), UNSUPPORTED_CONCAT_ELEM_ERR)); + }; + Ok(token) +} + /// 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::Token { kind: token::Comma, .. }, _)) = iter.look_ahead(0) { + if let Some(TokenTree::Token(Token { kind: token::Comma, .. }, _)) = iter.look_ahead(0) { let _ = iter.next(); return true; } @@ -218,8 +252,7 @@ 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::Token { kind: token::Dollar, .. }, _)) = iter.look_ahead(0) - { + if let Some(TokenTree::Token(Token { kind: token::Dollar, .. }, _)) = iter.look_ahead(0) { let _ = iter.next(); return true; } @@ -232,8 +265,7 @@ fn eat_dollar<'psess>( psess: &'psess ParseSess, span: Span, ) -> PResult<'psess, ()> { - if let Some(TokenTree::Token(token::Token { kind: token::Dollar, .. }, _)) = iter.look_ahead(0) - { + if let Some(TokenTree::Token(Token { kind: token::Dollar, .. }, _)) = iter.look_ahead(0) { let _ = iter.next(); return Ok(()); } diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index f935f1b77e0..9b4dc13c703 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -11,11 +11,13 @@ use rustc_ast::token::{self, Delimiter, Token, TokenKind}; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{pluralize, Diag, DiagCtxtHandle, PResult}; +use rustc_parse::lexer::nfc_normalize; use rustc_parse::parser::ParseNtResult; use rustc_session::parse::ParseSess; +use rustc_session::parse::SymbolGallery; use rustc_span::hygiene::{LocalExpnId, Transparency}; use rustc_span::symbol::{sym, Ident, MacroRulesNormalizedIdent}; -use rustc_span::{with_metavar_spans, Span, Symbol, SyntaxContext}; +use rustc_span::{with_metavar_spans, Span, SyntaxContext}; use smallvec::{smallvec, SmallVec}; use std::mem; @@ -312,7 +314,16 @@ pub(super) fn transcribe<'a>( // Replace meta-variable expressions with the result of their expansion. mbe::TokenTree::MetaVarExpr(sp, expr) => { - transcribe_metavar_expr(dcx, expr, interp, &mut marker, &repeats, &mut result, sp)?; + transcribe_metavar_expr( + dcx, + expr, + interp, + &mut marker, + &repeats, + &mut result, + sp, + &psess.symbol_gallery, + )?; } // If we are entering a new delimiter, we push its contents to the `stack` to be @@ -669,6 +680,7 @@ fn transcribe_metavar_expr<'a>( repeats: &[(usize, usize)], result: &mut Vec<TokenTree>, sp: &DelimSpan, + symbol_gallery: &SymbolGallery, ) -> PResult<'a, ()> { let mut visited_span = || { let mut span = sp.entire(); @@ -680,16 +692,26 @@ fn transcribe_metavar_expr<'a>( let mut concatenated = String::new(); for element in elements.into_iter() { let string = match element { - MetaVarExprConcatElem::Ident(ident) => ident.to_string(), - MetaVarExprConcatElem::Var(ident) => extract_ident(dcx, *ident, interp)?, + MetaVarExprConcatElem::Ident(elem) => elem.to_string(), + MetaVarExprConcatElem::Literal(elem) => elem.as_str().into(), + MetaVarExprConcatElem::Var(elem) => extract_ident(dcx, *elem, interp)?, }; concatenated.push_str(&string); } + let symbol = nfc_normalize(&concatenated); + let concatenated_span = visited_span(); + if !rustc_lexer::is_ident(symbol.as_str()) { + return Err(dcx.struct_span_err( + concatenated_span, + "`${concat(..)}` is not generating a valid identifier", + )); + } + symbol_gallery.insert(symbol, concatenated_span); // The current implementation marks the span as coming from the macro regardless of // contexts of the concatenated identifiers but this behavior may change in the // future. result.push(TokenTree::Token( - Token::from_ast_ident(Ident::new(Symbol::intern(&concatenated), visited_span())), + Token::from_ast_ident(Ident::new(symbol, concatenated_span)), Spacing::Alone, )); } diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 0dbe64c3ea7..8a1ee9374c3 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -21,6 +21,7 @@ use rustc_middle::ty::{ use rustc_middle::ty::{GenericParamDefKind, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_span::Span; +use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::regions::InferCtxtRegionExt; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 2230528a5ae..30ff272ce12 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -39,6 +39,7 @@ use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _ use rustc_trait_selection::traits::{ self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt, WellFormedLoc, }; +use rustc_type_ir::solve::NoSolution; use rustc_type_ir::TypeFlags; use std::cell::LazyCell; @@ -1712,13 +1713,12 @@ fn receiver_is_valid<'tcx>( let cause = ObligationCause::new(span, wfcx.body_def_id, traits::ObligationCauseCode::MethodReceiver); - let can_eq_self = |ty| infcx.can_eq(wfcx.param_env, self_ty, ty); - - // `self: Self` is always valid. - if can_eq_self(receiver_ty) { - if let Err(err) = wfcx.eq(&cause, wfcx.param_env, self_ty, receiver_ty) { - infcx.err_ctxt().report_mismatched_types(&cause, self_ty, receiver_ty, err).emit(); - } + // Special case `receiver == self_ty`, which doesn't necessarily require the `Receiver` lang item. + if let Ok(()) = wfcx.infcx.commit_if_ok(|_| { + let ocx = ObligationCtxt::new(wfcx.infcx); + ocx.eq(&cause, wfcx.param_env, self_ty, receiver_ty)?; + if ocx.select_all_or_error().is_empty() { Ok(()) } else { Err(NoSolution) } + }) { return true; } @@ -1729,58 +1729,51 @@ fn receiver_is_valid<'tcx>( autoderef = autoderef.include_raw_pointers(); } - // The first type is `receiver_ty`, which we know its not equal to `self_ty`; skip it. - autoderef.next(); - let receiver_trait_def_id = tcx.require_lang_item(LangItem::Receiver, Some(span)); // Keep dereferencing `receiver_ty` until we get to `self_ty`. - loop { - if let Some((potential_self_ty, _)) = autoderef.next() { - debug!( - "receiver_is_valid: potential self type `{:?}` to match `{:?}`", - potential_self_ty, self_ty - ); - - if can_eq_self(potential_self_ty) { - wfcx.register_obligations(autoderef.into_obligations()); + while let Some((potential_self_ty, _)) = autoderef.next() { + debug!( + "receiver_is_valid: potential self type `{:?}` to match `{:?}`", + potential_self_ty, self_ty + ); - if let Err(err) = wfcx.eq(&cause, wfcx.param_env, self_ty, potential_self_ty) { - infcx - .err_ctxt() - .report_mismatched_types(&cause, self_ty, potential_self_ty, err) - .emit(); - } + // Check if the self type unifies. If it does, then commit the result + // since it may have region side-effects. + if let Ok(()) = wfcx.infcx.commit_if_ok(|_| { + let ocx = ObligationCtxt::new(wfcx.infcx); + ocx.eq(&cause, wfcx.param_env, self_ty, potential_self_ty)?; + if ocx.select_all_or_error().is_empty() { Ok(()) } else { Err(NoSolution) } + }) { + wfcx.register_obligations(autoderef.into_obligations()); + return true; + } + // Without `feature(arbitrary_self_types)`, we require that each step in the + // deref chain implement `receiver`. + if !arbitrary_self_types_enabled { + if !receiver_is_implemented( + wfcx, + receiver_trait_def_id, + cause.clone(), + potential_self_ty, + ) { + // We cannot proceed. break; - } else { - // Without `feature(arbitrary_self_types)`, we require that each step in the - // deref chain implement `receiver` - if !arbitrary_self_types_enabled - && !receiver_is_implemented( - wfcx, - receiver_trait_def_id, - cause.clone(), - potential_self_ty, - ) - { - return false; - } } - } else { - debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`", receiver_ty, self_ty); - return false; - } - } - // Without `feature(arbitrary_self_types)`, we require that `receiver_ty` implements `Receiver`. - if !arbitrary_self_types_enabled - && !receiver_is_implemented(wfcx, receiver_trait_def_id, cause.clone(), receiver_ty) - { - return false; + // Register the bound, in case it has any region side-effects. + wfcx.register_bound( + cause.clone(), + wfcx.param_env, + potential_self_ty, + receiver_trait_def_id, + ); + } } - true + debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`", receiver_ty, self_ty); + false } fn receiver_is_implemented<'tcx>( diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 2a68d3915bb..02db0352daa 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -49,6 +49,7 @@ use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::{sym, Span, DUMMY_SP}; use rustc_target::spec::abi; +use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::wf::object_region_bounds; use rustc_trait_selection::traits::{self, ObligationCtxt}; diff --git a/compiler/rustc_hir_analysis/src/outlives/utils.rs b/compiler/rustc_hir_analysis/src/outlives/utils.rs index 5086c2af3f6..08015c28a26 100644 --- a/compiler/rustc_hir_analysis/src/outlives/utils.rs +++ b/compiler/rustc_hir_analysis/src/outlives/utils.rs @@ -1,9 +1,9 @@ use rustc_data_structures::fx::FxIndexMap; -use rustc_infer::infer::outlives::components::{push_outlives_components, Component}; use rustc_middle::ty::{self, Region, Ty, TyCtxt}; use rustc_middle::ty::{GenericArg, GenericArgKind}; use rustc_middle::{bug, span_bug}; use rustc_span::Span; +use rustc_type_ir::outlives::{push_outlives_components, Component}; use smallvec::smallvec; /// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index ad9c1e28211..4f1c2fdd922 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -13,6 +13,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, AssocItem, Ty, TypeFoldable, TypeVisitableExt}; use rustc_span::symbol::sym; use rustc_span::{Span, DUMMY_SP}; +use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::ObligationCause; use super::method::probe; diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index e49b921e63c..f1ed2ade3d4 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -501,6 +501,7 @@ pub enum SuggestBoxing { #[suggestion( hir_typeck_suggest_ptr_null_mut, applicability = "maybe-incorrect", + style = "verbose", code = "core::ptr::null_mut()" )] pub struct SuggestPtrNullMut { diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index c8ab0429ffc..193dbbbcdf4 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -734,7 +734,9 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx // struct; however, when EUV is run during typeck, it // may not. This will generate an error earlier in typeck, // so we can just ignore it. - span_bug!(with_expr.span, "with expression doesn't evaluate to a struct"); + if self.cx.tainted_by_errors().is_ok() { + span_bug!(with_expr.span, "with expression doesn't evaluate to a struct"); + } } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 047d0850d4c..10092dce587 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -40,6 +40,7 @@ use rustc_middle::{bug, span_bug}; use rustc_session::Session; use rustc_span::symbol::{kw, Ident}; use rustc_span::{sym, BytePos, Span, DUMMY_SP}; +use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext}; use std::iter; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 8d380caf916..fca0a3e195d 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -2582,7 +2582,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } (hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr), _, &ty::Ref(_, checked, _)) - if self.can_sub(self.param_env, checked, expected) => + if self.can_eq(self.param_env, checked, expected) => { let make_sugg = |start: Span, end: BytePos| { // skip `(` for tuples such as `(c) = (&123)`. diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 63b30d79aba..6a7af5510e0 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -33,6 +33,7 @@ use rustc_span::edit_distance::{ }; use rustc_span::symbol::sym; use rustc_span::{symbol::Ident, Span, Symbol, DUMMY_SP}; +use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::query::method_autoderef::MethodAutoderefBadTy; use rustc_trait_selection::traits::query::method_autoderef::{ @@ -857,7 +858,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let args = self.fresh_args_for_item(self.span, method.def_id); let fty = self.tcx.fn_sig(method.def_id).instantiate(self.tcx, args); let fty = self.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, fty); - self.can_sub(self.param_env, fty.output(), expected) + self.can_eq(self.param_env, fty.output(), expected) }), _ => false, } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 5e0f37ed792..be526e1c26c 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -19,6 +19,7 @@ use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{BytePos, Span, DUMMY_SP}; use rustc_target::abi::FieldIdx; +use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode}; use ty::VariantDef; diff --git a/compiler/rustc_infer/Cargo.toml b/compiler/rustc_infer/Cargo.toml index 5136ab79a0f..1f616710200 100644 --- a/compiler/rustc_infer/Cargo.toml +++ b/compiler/rustc_infer/Cargo.toml @@ -16,6 +16,7 @@ rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } +rustc_next_trait_solver = { path = "../rustc_next_trait_solver" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_type_ir = { path = "../rustc_type_ir" } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index a8fd3ca8c59..cebb9d09a47 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1168,14 +1168,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let output1 = sig1.output(); let output2 = sig2.output(); let (x1, x2) = self.cmp(output1, output2); - if !output1.is_unit() { + let output_diff = x1 != x2; + if !output1.is_unit() || output_diff { values.0.push_normal(" -> "); (values.0).0.extend(x1.0); } - if !output2.is_unit() { + if !output2.is_unit() || output_diff { values.1.push_normal(" -> "); (values.1).0.extend(x2.0); } + values } diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs index fd50d1eb438..d5e7de897d0 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -820,7 +820,7 @@ fn foo(&self) -> Self::T { String::new() } tcx.defaultness(item.id.owner_id) { let assoc_ty = tcx.type_of(item.id.owner_id).instantiate_identity(); - if self.infcx.can_eq(param_env, assoc_ty, found) { + if self.infcx.can_eq_shallow(param_env, assoc_ty, found) { diag.span_label( item.span, "associated type defaults can't be assumed inside the \ @@ -843,7 +843,7 @@ fn foo(&self) -> Self::T { String::new() } let assoc_ty = tcx.type_of(item.id.owner_id).instantiate_identity(); if let hir::Defaultness::Default { has_value: true } = tcx.defaultness(item.id.owner_id) - && self.infcx.can_eq(param_env, assoc_ty, found) + && self.infcx.can_eq_shallow(param_env, assoc_ty, found) { diag.span_label( item.span, diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index edbb741036f..9f55939c165 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -768,19 +768,9 @@ impl<'tcx> InferCtxt<'tcx> { .collect() } - pub fn can_sub<T>(&self, param_env: ty::ParamEnv<'tcx>, expected: T, actual: T) -> bool - where - T: at::ToTrace<'tcx>, - { - let origin = &ObligationCause::dummy(); - self.probe(|_| { - // We're only answering whether there could be a subtyping relation, and with - // opaque types, "there could be one", via registering a hidden type. - self.at(origin, param_env).sub(DefineOpaqueTypes::Yes, expected, actual).is_ok() - }) - } - - pub fn can_eq<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool + // FIXME(-Znext-solver): Get rid of this method, it's never correct. Either that, + // or we need to process the obligations. + pub fn can_eq_shallow<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool where T: at::ToTrace<'tcx>, { diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs deleted file mode 100644 index 6bab3ad6ba3..00000000000 --- a/compiler/rustc_infer/src/infer/outlives/components.rs +++ /dev/null @@ -1,266 +0,0 @@ -// The outlines relation `T: 'a` or `'a: 'b`. This code frequently -// refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that -// RFC for reference. - -use rustc_data_structures::sso::SsoHashSet; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; -use rustc_middle::ty::{GenericArg, GenericArgKind}; -use smallvec::{smallvec, SmallVec}; - -#[derive(Debug)] -pub enum Component<'tcx> { - Region(ty::Region<'tcx>), - Param(ty::ParamTy), - Placeholder(ty::PlaceholderType), - UnresolvedInferenceVariable(ty::InferTy), - - // Projections like `T::Foo` are tricky because a constraint like - // `T::Foo: 'a` can be satisfied in so many ways. There may be a - // where-clause that says `T::Foo: 'a`, or the defining trait may - // include a bound like `type Foo: 'static`, or -- in the most - // conservative way -- we can prove that `T: 'a` (more generally, - // that all components in the projection outlive `'a`). This code - // is not in a position to judge which is the best technique, so - // we just product the projection as a component and leave it to - // the consumer to decide (but see `EscapingProjection` below). - Alias(ty::AliasTy<'tcx>), - - // In the case where a projection has escaping regions -- meaning - // regions bound within the type itself -- we always use - // the most conservative rule, which requires that all components - // outlive the bound. So for example if we had a type like this: - // - // for<'a> Trait1< <T as Trait2<'a,'b>>::Foo > - // ~~~~~~~~~~~~~~~~~~~~~~~~~ - // - // then the inner projection (underlined) has an escaping region - // `'a`. We consider that outer trait `'c` to meet a bound if `'b` - // outlives `'b: 'c`, and we don't consider whether the trait - // declares that `Foo: 'static` etc. Therefore, we just return the - // free components of such a projection (in this case, `'b`). - // - // However, in the future, we may want to get smarter, and - // actually return a "higher-ranked projection" here. Therefore, - // we mark that these components are part of an escaping - // projection, so that implied bounds code can avoid relying on - // them. This gives us room to improve the regionck reasoning in - // the future without breaking backwards compat. - EscapingAlias(Vec<Component<'tcx>>), -} - -/// Push onto `out` all the things that must outlive `'a` for the condition -/// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**. -pub fn push_outlives_components<'tcx>( - tcx: TyCtxt<'tcx>, - ty0: Ty<'tcx>, - out: &mut SmallVec<[Component<'tcx>; 4]>, -) { - let mut visited = SsoHashSet::new(); - compute_components(tcx, ty0, out, &mut visited); - debug!("components({:?}) = {:?}", ty0, out); -} - -fn compute_components<'tcx>( - tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, - out: &mut SmallVec<[Component<'tcx>; 4]>, - visited: &mut SsoHashSet<GenericArg<'tcx>>, -) { - // Descend through the types, looking for the various "base" - // components and collecting them into `out`. This is not written - // with `collect()` because of the need to sometimes skip subtrees - // in the `subtys` iterator (e.g., when encountering a - // projection). - match *ty.kind() { - ty::FnDef(_, args) => { - // HACK(eddyb) ignore lifetimes found shallowly in `args`. - // This is inconsistent with `ty::Adt` (including all args) - // and with `ty::Closure` (ignoring all args other than - // upvars, of which a `ty::FnDef` doesn't have any), but - // consistent with previous (accidental) behavior. - // See https://github.com/rust-lang/rust/issues/70917 - // for further background and discussion. - for child in args { - match child.unpack() { - GenericArgKind::Type(ty) => { - compute_components(tcx, ty, out, visited); - } - GenericArgKind::Lifetime(_) => {} - GenericArgKind::Const(_) => { - compute_components_recursive(tcx, child, out, visited); - } - } - } - } - - ty::Pat(element, _) | - ty::Array(element, _) => { - // Don't look into the len const as it doesn't affect regions - compute_components(tcx, element, out, visited); - } - - ty::Closure(_, args) => { - let tupled_ty = args.as_closure().tupled_upvars_ty(); - compute_components(tcx, tupled_ty, out, visited); - } - - ty::CoroutineClosure(_, args) => { - let tupled_ty = args.as_coroutine_closure().tupled_upvars_ty(); - compute_components(tcx, tupled_ty, out, visited); - } - - ty::Coroutine(_, args) => { - // Same as the closure case - let tupled_ty = args.as_coroutine().tupled_upvars_ty(); - compute_components(tcx, tupled_ty, out, visited); - - // We ignore regions in the coroutine interior as we don't - // want these to affect region inference - } - - // All regions are bound inside a witness - ty::CoroutineWitness(..) => (), - - // OutlivesTypeParameterEnv -- the actual checking that `X:'a` - // is implied by the environment is done in regionck. - ty::Param(p) => { - out.push(Component::Param(p)); - } - - ty::Placeholder(p) => { - out.push(Component::Placeholder(p)); - } - - // For projections, we prefer to generate an obligation like - // `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the - // regionck more ways to prove that it holds. However, - // regionck is not (at least currently) prepared to deal with - // higher-ranked regions that may appear in the - // trait-ref. Therefore, if we see any higher-ranked regions, - // we simply fallback to the most restrictive rule, which - // requires that `Pi: 'a` for all `i`. - ty::Alias(_, alias_ty) => { - if !alias_ty.has_escaping_bound_vars() { - // best case: no escaping regions, so push the - // projection and skip the subtree (thus generating no - // constraints for Pi). This defers the choice between - // the rules OutlivesProjectionEnv, - // OutlivesProjectionTraitDef, and - // OutlivesProjectionComponents to regionck. - out.push(Component::Alias(alias_ty)); - } else { - // fallback case: hard code - // OutlivesProjectionComponents. Continue walking - // through and constrain Pi. - let mut subcomponents = smallvec![]; - let mut subvisited = SsoHashSet::new(); - compute_alias_components_recursive(tcx, ty, &mut subcomponents, &mut subvisited); - out.push(Component::EscapingAlias(subcomponents.into_iter().collect())); - } - } - - // We assume that inference variables are fully resolved. - // So, if we encounter an inference variable, just record - // the unresolved variable as a component. - ty::Infer(infer_ty) => { - out.push(Component::UnresolvedInferenceVariable(infer_ty)); - } - - // Most types do not introduce any region binders, nor - // involve any other subtle cases, and so the WF relation - // simply constraints any regions referenced directly by - // the type and then visits the types that are lexically - // contained within. (The comments refer to relevant rules - // from RFC1214.) - ty::Bool | // OutlivesScalar - ty::Char | // OutlivesScalar - ty::Int(..) | // OutlivesScalar - ty::Uint(..) | // OutlivesScalar - ty::Float(..) | // OutlivesScalar - ty::Never | // ... - ty::Adt(..) | // OutlivesNominalType - ty::Foreign(..) | // OutlivesNominalType - ty::Str | // OutlivesScalar (ish) - ty::Slice(..) | // ... - ty::RawPtr(..) | // ... - ty::Ref(..) | // OutlivesReference - ty::Tuple(..) | // ... - ty::FnPtr(_) | // OutlivesFunction (*) - ty::Dynamic(..) | // OutlivesObject, OutlivesFragment (*) - ty::Bound(..) | - ty::Error(_) => { - // (*) Function pointers and trait objects are both binders. - // In the RFC, this means we would add the bound regions to - // the "bound regions list". In our representation, no such - // list is maintained explicitly, because bound regions - // themselves can be readily identified. - compute_components_recursive(tcx, ty.into(), out, visited); - } - } -} - -/// Collect [Component]s for *all* the args of `parent`. -/// -/// This should not be used to get the components of `parent` itself. -/// Use [push_outlives_components] instead. -pub(super) fn compute_alias_components_recursive<'tcx>( - tcx: TyCtxt<'tcx>, - alias_ty: Ty<'tcx>, - out: &mut SmallVec<[Component<'tcx>; 4]>, - visited: &mut SsoHashSet<GenericArg<'tcx>>, -) { - let ty::Alias(kind, alias_ty) = alias_ty.kind() else { - unreachable!("can only call `compute_alias_components_recursive` on an alias type") - }; - let opt_variances = if *kind == ty::Opaque { tcx.variances_of(alias_ty.def_id) } else { &[] }; - for (index, child) in alias_ty.args.iter().enumerate() { - if opt_variances.get(index) == Some(&ty::Bivariant) { - continue; - } - if !visited.insert(child) { - continue; - } - match child.unpack() { - GenericArgKind::Type(ty) => { - compute_components(tcx, ty, out, visited); - } - GenericArgKind::Lifetime(lt) => { - // Ignore higher ranked regions. - if !lt.is_bound() { - out.push(Component::Region(lt)); - } - } - GenericArgKind::Const(_) => { - compute_components_recursive(tcx, child, out, visited); - } - } - } -} - -/// Collect [Component]s for *all* the args of `parent`. -/// -/// This should not be used to get the components of `parent` itself. -/// Use [push_outlives_components] instead. -fn compute_components_recursive<'tcx>( - tcx: TyCtxt<'tcx>, - parent: GenericArg<'tcx>, - out: &mut SmallVec<[Component<'tcx>; 4]>, - visited: &mut SsoHashSet<GenericArg<'tcx>>, -) { - for child in parent.walk_shallow(visited) { - match child.unpack() { - GenericArgKind::Type(ty) => { - compute_components(tcx, ty, out, visited); - } - GenericArgKind::Lifetime(lt) => { - // Ignore higher ranked regions. - if !lt.is_bound() { - out.push(Component::Region(lt)); - } - } - GenericArgKind::Const(_) => { - compute_components_recursive(tcx, child, out, visited); - } - } - } -} diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index 48d006e7fbc..89ff4604560 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -8,7 +8,6 @@ use crate::infer::lexical_region_resolve; use rustc_middle::traits::query::{NoSolution, OutlivesBound}; use rustc_middle::ty; -pub mod components; pub mod env; pub mod for_liveness; pub mod obligations; diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 32c790523b6..9bb5f775e4a 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -59,7 +59,6 @@ //! might later infer `?U` to something like `&'b u32`, which would //! imply that `'b: 'a`. -use crate::infer::outlives::components::{push_outlives_components, Component}; use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::outlives::verify::VerifyBoundCx; use crate::infer::resolve::OpportunisticRegionResolver; @@ -75,6 +74,7 @@ use rustc_middle::ty::{ }; use rustc_middle::ty::{GenericArgKind, PolyTypeOutlivesPredicate}; use rustc_span::DUMMY_SP; +use rustc_type_ir::outlives::{push_outlives_components, Component}; use smallvec::smallvec; use super::env::OutlivesEnvironment; @@ -291,7 +291,7 @@ where fn components_must_outlive( &mut self, origin: infer::SubregionOrigin<'tcx>, - components: &[Component<'tcx>], + components: &[Component<TyCtxt<'tcx>>], region: ty::Region<'tcx>, category: ConstraintCategory<'tcx>, ) { diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index 7e977b9b954..ad102dfcc1f 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -1,10 +1,10 @@ -use crate::infer::outlives::components::{compute_alias_components_recursive, Component}; use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::region_constraints::VerifyIfEq; use crate::infer::{GenericKind, VerifyBound}; use rustc_data_structures::sso::SsoHashSet; use rustc_middle::ty::GenericArg; use rustc_middle::ty::{self, OutlivesPredicate, Ty, TyCtxt}; +use rustc_type_ir::outlives::{compute_alias_components_recursive, Component}; use smallvec::smallvec; @@ -139,7 +139,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { fn bound_from_components( &self, - components: &[Component<'tcx>], + components: &[Component<TyCtxt<'tcx>>], visited: &mut SsoHashSet<GenericArg<'tcx>>, ) -> VerifyBound<'tcx> { let mut bounds = components @@ -158,7 +158,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { fn bound_from_single_component( &self, - component: &Component<'tcx>, + component: &Component<TyCtxt<'tcx>>, visited: &mut SsoHashSet<GenericArg<'tcx>>, ) -> VerifyBound<'tcx> { match *component { diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs index 0a2e85cc891..c93b89756f9 100644 --- a/compiler/rustc_infer/src/infer/relate/combine.rs +++ b/compiler/rustc_infer/src/infer/relate/combine.rs @@ -18,11 +18,13 @@ //! On success, the LUB/GLB operations return the appropriate bound. The //! return value of `Equate` or `Sub` shouldn't really be used. +pub use rustc_next_trait_solver::relate::combine::*; + use super::glb::Glb; use super::lub::Lub; use super::type_relating::TypeRelating; +use super::RelateResult; use super::StructurallyRelateAliases; -use super::{RelateResult, TypeRelation}; use crate::infer::relate; use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace}; use crate::traits::{Obligation, PredicateObligation}; @@ -32,7 +34,6 @@ use rustc_middle::traits::solve::Goal; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, InferConst, Ty, TyCtxt, TypeVisitableExt, Upcast}; use rustc_middle::ty::{IntType, UintType}; -use rustc_span::Span; #[derive(Clone)] pub struct CombineFields<'infcx, 'tcx> { @@ -76,7 +77,7 @@ impl<'tcx> InferCtxt<'tcx> { b: Ty<'tcx>, ) -> RelateResult<'tcx, Ty<'tcx>> where - R: PredicateEmittingRelation<'tcx>, + R: PredicateEmittingRelation<InferCtxt<'tcx>>, { debug_assert!(!a.has_escaping_bound_vars()); debug_assert!(!b.has_escaping_bound_vars()); @@ -171,7 +172,7 @@ impl<'tcx> InferCtxt<'tcx> { b: ty::Const<'tcx>, ) -> RelateResult<'tcx, ty::Const<'tcx>> where - R: PredicateEmittingRelation<'tcx>, + R: PredicateEmittingRelation<InferCtxt<'tcx>>, { debug!("{}.consts({:?}, {:?})", relation.tag(), a, b); debug_assert!(!a.has_escaping_bound_vars()); @@ -323,30 +324,3 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { ) } } - -pub trait PredicateEmittingRelation<'tcx>: TypeRelation<TyCtxt<'tcx>> { - fn span(&self) -> Span; - - fn param_env(&self) -> ty::ParamEnv<'tcx>; - - /// Whether aliases should be related structurally. This is pretty much - /// always `No` unless you're equating in some specific locations of the - /// new solver. See the comments in these use-cases for more details. - fn structurally_relate_aliases(&self) -> StructurallyRelateAliases; - - /// Register obligations that must hold in order for this relation to hold - fn register_goals( - &mut self, - obligations: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>, - ); - - /// Register predicates that must hold in order for this relation to hold. - /// This uses the default `param_env` of the obligation. - fn register_predicates( - &mut self, - obligations: impl IntoIterator<Item: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>, - ); - - /// Register `AliasRelate` obligation(s) that both types must be related to each other. - fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>); -} diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index d6e57d85387..fe3b8d60fb9 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -30,7 +30,7 @@ impl<'tcx> InferCtxt<'tcx> { /// `TypeRelation`. Do not use this, and instead please use `At::eq`, for all /// other usecases (i.e. setting the value of a type var). #[instrument(level = "debug", skip(self, relation))] - pub fn instantiate_ty_var<R: PredicateEmittingRelation<'tcx>>( + pub fn instantiate_ty_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>( &self, relation: &mut R, target_is_expected: bool, @@ -178,7 +178,7 @@ impl<'tcx> InferCtxt<'tcx> { /// /// See `tests/ui/const-generics/occurs-check/` for more examples where this is relevant. #[instrument(level = "debug", skip(self, relation))] - pub(super) fn instantiate_const_var<R: PredicateEmittingRelation<'tcx>>( + pub(super) fn instantiate_const_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>( &self, relation: &mut R, target_is_expected: bool, diff --git a/compiler/rustc_infer/src/infer/relate/glb.rs b/compiler/rustc_infer/src/infer/relate/glb.rs index 067004ecaeb..5bb8a113e17 100644 --- a/compiler/rustc_infer/src/infer/relate/glb.rs +++ b/compiler/rustc_infer/src/infer/relate/glb.rs @@ -123,7 +123,7 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx, } } -impl<'tcx> PredicateEmittingRelation<'tcx> for Glb<'_, '_, 'tcx> { +impl<'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for Glb<'_, '_, 'tcx> { fn span(&self) -> Span { self.fields.trace.span() } diff --git a/compiler/rustc_infer/src/infer/relate/lattice.rs b/compiler/rustc_infer/src/infer/relate/lattice.rs index 6cc8d6d910a..46e7466141a 100644 --- a/compiler/rustc_infer/src/infer/relate/lattice.rs +++ b/compiler/rustc_infer/src/infer/relate/lattice.rs @@ -30,7 +30,7 @@ use rustc_middle::ty::{self, Ty}; /// /// GLB moves "down" the lattice (to smaller values); LUB moves /// "up" the lattice (to bigger values). -pub trait LatticeDir<'f, 'tcx>: PredicateEmittingRelation<'tcx> { +pub trait LatticeDir<'f, 'tcx>: PredicateEmittingRelation<InferCtxt<'tcx>> { fn infcx(&self) -> &'f InferCtxt<'tcx>; fn cause(&self) -> &ObligationCause<'tcx>; diff --git a/compiler/rustc_infer/src/infer/relate/lub.rs b/compiler/rustc_infer/src/infer/relate/lub.rs index 2184416b4cc..94c1464817f 100644 --- a/compiler/rustc_infer/src/infer/relate/lub.rs +++ b/compiler/rustc_infer/src/infer/relate/lub.rs @@ -123,7 +123,7 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx, } } -impl<'tcx> PredicateEmittingRelation<'tcx> for Lub<'_, '_, 'tcx> { +impl<'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for Lub<'_, '_, 'tcx> { fn span(&self) -> Span { self.fields.trace.span() } diff --git a/compiler/rustc_infer/src/infer/relate/mod.rs b/compiler/rustc_infer/src/infer/relate/mod.rs index 41cc945492d..dd97dc061fe 100644 --- a/compiler/rustc_infer/src/infer/relate/mod.rs +++ b/compiler/rustc_infer/src/infer/relate/mod.rs @@ -2,11 +2,13 @@ //! (except for some relations used for diagnostics and heuristics in the compiler). //! As well as the implementation of `Relate` for interned things (`Ty`/`Const`/etc). -pub use rustc_middle::ty::relate::*; +pub use rustc_middle::ty::relate::RelateResult; +pub use rustc_next_trait_solver::relate::*; pub use self::combine::CombineFields; pub use self::combine::PredicateEmittingRelation; +#[allow(hidden_glob_reexports)] pub(super) mod combine; mod generalize; mod glb; diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs index f2bec9392d5..e206f530519 100644 --- a/compiler/rustc_infer/src/infer/relate/type_relating.rs +++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs @@ -1,7 +1,7 @@ use super::combine::CombineFields; use crate::infer::relate::{PredicateEmittingRelation, StructurallyRelateAliases}; use crate::infer::BoundRegionConversionTime::HigherRankedType; -use crate::infer::{DefineOpaqueTypes, SubregionOrigin}; +use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin}; use rustc_middle::traits::solve::Goal; use rustc_middle::ty::relate::{ relate_args_invariantly, relate_args_with_variances, Relate, RelateResult, TypeRelation, @@ -296,7 +296,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> { } } -impl<'tcx> PredicateEmittingRelation<'tcx> for TypeRelating<'_, '_, 'tcx> { +impl<'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> { fn span(&self) -> Span { self.fields.trace.span() } diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 24cf9f03fcd..b269bfcbfeb 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -1,11 +1,12 @@ use smallvec::smallvec; -use crate::infer::outlives::components::{push_outlives_components, Component}; use crate::traits::{self, Obligation, ObligationCauseCode, PredicateObligation}; use rustc_data_structures::fx::FxHashSet; +use rustc_middle::ty::ToPolyTraitRef; use rustc_middle::ty::{self, Ty, TyCtxt, Upcast}; use rustc_span::symbol::Ident; use rustc_span::Span; +use rustc_type_ir::outlives::{push_outlives_components, Component}; pub fn anonymize_predicate<'tcx>( tcx: TyCtxt<'tcx>, @@ -82,7 +83,6 @@ pub struct Elaborator<'tcx, O> { enum Filter { All, OnlySelf, - OnlySelfThatDefines(Ident), } /// Describes how to elaborate an obligation into a sub-obligation. @@ -252,12 +252,6 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { self } - /// Filter to only the supertraits of trait predicates that define the assoc_ty. - pub fn filter_only_self_that_defines(mut self, assoc_ty: Ident) -> Self { - self.mode = Filter::OnlySelfThatDefines(assoc_ty); - self - } - fn elaborate(&mut self, elaboratable: &O) { let tcx = self.visited.tcx; @@ -277,9 +271,6 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { let predicates = match self.mode { Filter::All => tcx.explicit_implied_predicates_of(data.def_id()), Filter::OnlySelf => tcx.explicit_super_predicates_of(data.def_id()), - Filter::OnlySelfThatDefines(ident) => { - tcx.explicit_supertraits_containing_assoc_item((data.def_id(), ident)) - } }; let obligations = @@ -405,14 +396,14 @@ impl<'tcx, O: Elaboratable<'tcx>> Iterator for Elaborator<'tcx, O> { pub fn supertraits<'tcx>( tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, -) -> FilterToTraits<Elaborator<'tcx, ty::Predicate<'tcx>>> { +) -> FilterToTraits<Elaborator<'tcx, ty::Clause<'tcx>>> { elaborate(tcx, [trait_ref.upcast(tcx)]).filter_only_self().filter_to_traits() } pub fn transitive_bounds<'tcx>( tcx: TyCtxt<'tcx>, trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>, -) -> FilterToTraits<Elaborator<'tcx, ty::Predicate<'tcx>>> { +) -> FilterToTraits<Elaborator<'tcx, ty::Clause<'tcx>>> { elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.upcast(tcx))) .filter_only_self() .filter_to_traits() @@ -427,17 +418,37 @@ pub fn transitive_bounds_that_define_assoc_item<'tcx>( tcx: TyCtxt<'tcx>, trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>, assoc_name: Ident, -) -> FilterToTraits<Elaborator<'tcx, ty::Predicate<'tcx>>> { - elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.upcast(tcx))) - .filter_only_self_that_defines(assoc_name) - .filter_to_traits() +) -> impl Iterator<Item = ty::PolyTraitRef<'tcx>> { + let mut seen = FxHashSet::default(); + let mut stack: Vec<_> = trait_refs.collect(); + + std::iter::from_fn(move || { + while let Some(trait_ref) = stack.pop() { + if !seen.insert(tcx.anonymize_bound_vars(trait_ref)) { + continue; + } + + stack.extend( + tcx.explicit_supertraits_containing_assoc_item((trait_ref.def_id(), assoc_name)) + .instantiate_own_identity() + .map(|(clause, _)| clause.instantiate_supertrait(tcx, trait_ref)) + .filter_map(|clause| clause.as_trait_clause()) + // FIXME: Negative supertraits are elaborated here lol + .map(|trait_pred| trait_pred.to_poly_trait_ref()), + ); + + return Some(trait_ref); + } + + None + }) } /////////////////////////////////////////////////////////////////////////// // Other /////////////////////////////////////////////////////////////////////////// -impl<'tcx> Elaborator<'tcx, ty::Predicate<'tcx>> { +impl<'tcx> Elaborator<'tcx, ty::Clause<'tcx>> { fn filter_to_traits(self) -> FilterToTraits<Self> { FilterToTraits { base_iterator: self } } @@ -449,7 +460,7 @@ pub struct FilterToTraits<I> { base_iterator: I, } -impl<'tcx, I: Iterator<Item = ty::Predicate<'tcx>>> Iterator for FilterToTraits<I> { +impl<'tcx, I: Iterator<Item = ty::Clause<'tcx>>> Iterator for FilterToTraits<I> { type Item = ty::PolyTraitRef<'tcx>; fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> { diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 2ade6964ca8..048c2fb4e67 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -4189,6 +4189,7 @@ declare_lint! { reason: FutureIncompatibilityReason::FutureReleaseSemanticsChange, reference: "issue #123748 <https://github.com/rust-lang/rust/issues/123748>", }; + @edition Edition2024 => Deny; report_in_external_macro } diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 305ba1ef3bb..2f3a6ee601b 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -31,9 +31,18 @@ pub struct Map<'hir> { /// An iterator that walks up the ancestor tree of a given `HirId`. /// Constructed using `tcx.hir().parent_iter(hir_id)`. -pub struct ParentHirIterator<'hir> { +struct ParentHirIterator<'hir> { current_id: HirId, map: Map<'hir>, + // Cache the current value of `hir_owner_nodes` to avoid repeatedly calling the same query for + // the same owner, which will uselessly record many times the same query dependency. + current_owner_nodes: Option<&'hir OwnerNodes<'hir>>, +} + +impl<'hir> ParentHirIterator<'hir> { + fn new(map: Map<'hir>, current_id: HirId) -> ParentHirIterator<'hir> { + ParentHirIterator { current_id, map, current_owner_nodes: None } + } } impl<'hir> Iterator for ParentHirIterator<'hir> { @@ -44,13 +53,22 @@ impl<'hir> Iterator for ParentHirIterator<'hir> { return None; } - // There are nodes that do not have entries, so we need to skip them. - let parent_id = self.map.tcx.parent_hir_id(self.current_id); + let HirId { owner, local_id } = self.current_id; - if parent_id == self.current_id { - self.current_id = CRATE_HIR_ID; - return None; - } + let parent_id = if local_id == ItemLocalId::ZERO { + // We go from an owner to its parent, so clear the cache. + self.current_owner_nodes = None; + self.map.tcx.hir_owner_parent(owner) + } else { + let owner_nodes = + self.current_owner_nodes.get_or_insert_with(|| self.map.tcx.hir_owner_nodes(owner)); + let parent_local_id = owner_nodes.nodes[local_id].parent; + // HIR indexing should have checked that. + debug_assert_ne!(parent_local_id, local_id); + HirId { owner, local_id: parent_local_id } + }; + + debug_assert_ne!(parent_id, self.current_id); self.current_id = parent_id; return Some(parent_id); @@ -479,7 +497,7 @@ impl<'hir> Map<'hir> { /// until the crate root is reached. Prefer this over your own loop using `parent_id`. #[inline] pub fn parent_id_iter(self, current_id: HirId) -> impl Iterator<Item = HirId> + 'hir { - ParentHirIterator { current_id, map: self } + ParentHirIterator::new(self, current_id) } /// Returns an iterator for the nodes in the ancestor tree of the `current_id` diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index bf834ef7607..98f35b6b8ab 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -54,6 +54,13 @@ pub struct Expr<'tcx> { pub kind: ExprKind, args: ty::GenericArgsRef<'tcx>, } + +impl<'tcx> rustc_type_ir::inherent::ExprConst<TyCtxt<'tcx>> for Expr<'tcx> { + fn args(self) -> ty::GenericArgsRef<'tcx> { + self.args + } +} + impl<'tcx> Expr<'tcx> { pub fn new_binop( tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 055749ba3a3..dca48069974 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -92,6 +92,8 @@ use std::ops::{Bound, Deref}; impl<'tcx> Interner for TyCtxt<'tcx> { type DefId = DefId; type LocalDefId = LocalDefId; + type Span = Span; + type GenericArgs = ty::GenericArgsRef<'tcx>; type GenericArgsSlice = &'tcx [ty::GenericArg<'tcx>]; diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index b169d672a84..ebf0d7ed737 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -10,18 +10,6 @@ use crate::ty::{self as ty, Ty, TyCtxt}; pub type RelateResult<'tcx, T> = rustc_type_ir::relate::RelateResult<TyCtxt<'tcx>, T>; -/// Whether aliases should be related structurally or not. Used -/// to adjust the behavior of generalization and combine. -/// -/// This should always be `No` unless in a few special-cases when -/// instantiating canonical responses and in the new solver. Each -/// such case should have a comment explaining why it is used. -#[derive(Debug, Copy, Clone)] -pub enum StructurallyRelateAliases { - Yes, - No, -} - impl<'tcx> Relate<TyCtxt<'tcx>> for ty::ImplSubject<'tcx> { #[inline] fn relate<R: TypeRelation<TyCtxt<'tcx>>>( diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index e0f204a687f..efcaf89081f 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -78,23 +78,6 @@ impl<'tcx> GenericArg<'tcx> { pub fn walk(self) -> TypeWalker<'tcx> { TypeWalker::new(self) } - - /// Iterator that walks the immediate children of `self`. Hence - /// `Foo<Bar<i32>, u32>` yields the sequence `[Bar<i32>, u32]` - /// (but not `i32`, like `walk`). - /// - /// Iterator only walks items once. - /// It accepts visited set, updates it with all visited types - /// and skips any types that are already there. - pub fn walk_shallow( - self, - visited: &mut SsoHashSet<GenericArg<'tcx>>, - ) -> impl Iterator<Item = GenericArg<'tcx>> { - let mut stack = SmallVec::new(); - push_inner(&mut stack, self); - stack.retain(|a| visited.insert(*a)); - stack.into_iter() - } } impl<'tcx> Ty<'tcx> { diff --git a/compiler/rustc_next_trait_solver/src/lib.rs b/compiler/rustc_next_trait_solver/src/lib.rs index a6a9c01faaa..761475d3d6b 100644 --- a/compiler/rustc_next_trait_solver/src/lib.rs +++ b/compiler/rustc_next_trait_solver/src/lib.rs @@ -6,5 +6,6 @@ pub mod canonicalizer; pub mod delegate; +pub mod relate; pub mod resolve; pub mod solve; diff --git a/compiler/rustc_next_trait_solver/src/relate.rs b/compiler/rustc_next_trait_solver/src/relate.rs new file mode 100644 index 00000000000..db819961bbd --- /dev/null +++ b/compiler/rustc_next_trait_solver/src/relate.rs @@ -0,0 +1,15 @@ +pub use rustc_type_ir::relate::*; + +pub mod combine; + +/// Whether aliases should be related structurally or not. Used +/// to adjust the behavior of generalization and combine. +/// +/// This should always be `No` unless in a few special-cases when +/// instantiating canonical responses and in the new solver. Each +/// such case should have a comment explaining why it is used. +#[derive(Debug, Copy, Clone)] +pub enum StructurallyRelateAliases { + Yes, + No, +} diff --git a/compiler/rustc_next_trait_solver/src/relate/combine.rs b/compiler/rustc_next_trait_solver/src/relate/combine.rs new file mode 100644 index 00000000000..96968327d8e --- /dev/null +++ b/compiler/rustc_next_trait_solver/src/relate/combine.rs @@ -0,0 +1,34 @@ +pub use rustc_type_ir::relate::*; +use rustc_type_ir::solve::Goal; +use rustc_type_ir::{InferCtxtLike, Interner, Upcast}; + +use super::StructurallyRelateAliases; + +pub trait PredicateEmittingRelation<Infcx, I = <Infcx as InferCtxtLike>::Interner>: + TypeRelation<I> +where + Infcx: InferCtxtLike<Interner = I>, + I: Interner, +{ + fn span(&self) -> I::Span; + + fn param_env(&self) -> I::ParamEnv; + + /// Whether aliases should be related structurally. This is pretty much + /// always `No` unless you're equating in some specific locations of the + /// new solver. See the comments in these use-cases for more details. + fn structurally_relate_aliases(&self) -> StructurallyRelateAliases; + + /// Register obligations that must hold in order for this relation to hold + fn register_goals(&mut self, obligations: impl IntoIterator<Item = Goal<I, I::Predicate>>); + + /// Register predicates that must hold in order for this relation to hold. + /// This uses the default `param_env` of the obligation. + fn register_predicates( + &mut self, + obligations: impl IntoIterator<Item: Upcast<I, I::Predicate>>, + ); + + /// Register `AliasRelate` obligation(s) that both types must be related to each other. + fn register_alias_relate_predicate(&mut self, a: I::Ty, b: I::Ty); +} diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 58fef9b6c45..a8fe35f45b3 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -282,7 +282,7 @@ impl<'a> Parser<'a> { pub fn parse_inner_attributes(&mut self) -> PResult<'a, ast::AttrVec> { let mut attrs = ast::AttrVec::new(); loop { - let start_pos: u32 = self.num_bump_calls.try_into().unwrap(); + let start_pos = self.num_bump_calls; // Only try to parse if it is an inner attribute (has `!`). let attr = if self.check(&token::Pound) && self.look_ahead(1, |t| t == &token::Not) { Some(self.parse_attribute(InnerAttrPolicy::Permitted)?) @@ -303,7 +303,7 @@ impl<'a> Parser<'a> { None }; if let Some(attr) = attr { - let end_pos: u32 = self.num_bump_calls.try_into().unwrap(); + let end_pos = self.num_bump_calls; // If we are currently capturing tokens, mark the location of this inner attribute. // If capturing ends up creating a `LazyAttrTokenStream`, we will include // this replace range with it, removing the inner attribute from the final @@ -313,7 +313,7 @@ impl<'a> Parser<'a> { // corresponding macro). let range = start_pos..end_pos; if let Capturing::Yes = self.capture_state.capturing { - self.capture_state.inner_attr_ranges.insert(attr.id, (range, vec![])); + self.capture_state.inner_attr_ranges.insert(attr.id, (range, None)); } attrs.push(attr); } else { diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 13a647adfe3..38f18022e3c 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -1,6 +1,6 @@ use super::{Capturing, FlatToken, ForceCollect, Parser, ReplaceRange, TokenCursor, TrailingToken}; use rustc_ast::token::{self, Delimiter, Token, TokenKind}; -use rustc_ast::tokenstream::{AttrTokenStream, AttrTokenTree, AttributesData, DelimSpacing}; +use rustc_ast::tokenstream::{AttrTokenStream, AttrTokenTree, AttrsTarget, DelimSpacing}; use rustc_ast::tokenstream::{DelimSpan, LazyAttrTokenStream, Spacing, ToAttrTokenStream}; use rustc_ast::{self as ast}; use rustc_ast::{AttrVec, Attribute, HasAttrs, HasTokens}; @@ -8,7 +8,6 @@ use rustc_errors::PResult; use rustc_session::parse::ParseSess; use rustc_span::{sym, Span, DUMMY_SP}; -use std::ops::Range; use std::{iter, mem}; /// A wrapper type to ensure that the parser handles outer attributes correctly. @@ -88,7 +87,6 @@ fn has_cfg_or_cfg_attr(attrs: &[Attribute]) -> bool { // // This also makes `Parser` very cheap to clone, since // there is no intermediate collection buffer to clone. -#[derive(Clone)] struct LazyAttrTokenStreamImpl { start_token: (Token, Spacing), cursor_snapshot: TokenCursor, @@ -146,24 +144,23 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { // start position, we ensure that any replace range which encloses // another replace range will capture the *replaced* tokens for the inner // range, not the original tokens. - for (range, new_tokens) in replace_ranges.into_iter().rev() { + for (range, target) in replace_ranges.into_iter().rev() { assert!(!range.is_empty(), "Cannot replace an empty range: {range:?}"); - // Replace ranges are only allowed to decrease the number of tokens. - assert!( - range.len() >= new_tokens.len(), - "Range {range:?} has greater len than {new_tokens:?}" - ); - - // Replace any removed tokens with `FlatToken::Empty`. - // This keeps the total length of `tokens` constant throughout the - // replacement process, allowing us to use all of the `ReplaceRanges` entries - // without adjusting indices. - let filler = iter::repeat((FlatToken::Empty, Spacing::Alone)) - .take(range.len() - new_tokens.len()); + // Replace the tokens in range with zero or one `FlatToken::AttrsTarget`s, plus + // enough `FlatToken::Empty`s to fill up the rest of the range. This keeps the + // total length of `tokens` constant throughout the replacement process, allowing + // us to use all of the `ReplaceRanges` entries without adjusting indices. + let target_len = target.is_some() as usize; tokens.splice( (range.start as usize)..(range.end as usize), - new_tokens.into_iter().chain(filler), + target + .into_iter() + .map(|target| (FlatToken::AttrsTarget(target), Spacing::Alone)) + .chain( + iter::repeat((FlatToken::Empty, Spacing::Alone)) + .take(range.len() - target_len), + ), ); } make_attr_token_stream(tokens.into_iter(), self.break_last_token) @@ -316,7 +313,7 @@ impl<'a> Parser<'a> { .iter() .cloned() .chain(inner_attr_replace_ranges.iter().cloned()) - .map(|(range, tokens)| ((range.start - start_pos)..(range.end - start_pos), tokens)) + .map(|(range, data)| ((range.start - start_pos)..(range.end - start_pos), data)) .collect() }; @@ -346,18 +343,14 @@ impl<'a> Parser<'a> { && matches!(self.capture_state.capturing, Capturing::Yes) && has_cfg_or_cfg_attr(final_attrs) { - let attr_data = AttributesData { attrs: final_attrs.iter().cloned().collect(), tokens }; + assert!(!self.break_last_token, "Should not have unglued last token with cfg attr"); - // Replace the entire AST node that we just parsed, including attributes, - // with a `FlatToken::AttrTarget`. If this AST node is inside an item - // that has `#[derive]`, then this will allow us to cfg-expand this - // AST node. + // Replace the entire AST node that we just parsed, including attributes, with + // `target`. If this AST node is inside an item that has `#[derive]`, then this will + // allow us to cfg-expand this AST node. let start_pos = if has_outer_attrs { attrs.start_pos } else { start_pos }; - let new_tokens = vec![(FlatToken::AttrTarget(attr_data), Spacing::Alone)]; - - assert!(!self.break_last_token, "Should not have unglued last token with cfg attr"); - let range: Range<u32> = (start_pos.try_into().unwrap())..(end_pos.try_into().unwrap()); - self.capture_state.replace_ranges.push((range, new_tokens)); + let target = AttrsTarget { attrs: final_attrs.iter().cloned().collect(), tokens }; + self.capture_state.replace_ranges.push((start_pos..end_pos, Some(target))); self.capture_state.replace_ranges.extend(inner_attr_replace_ranges); } @@ -419,11 +412,11 @@ fn make_attr_token_stream( .expect("Bottom token frame is missing!") .inner .push(AttrTokenTree::Token(token, spacing)), - FlatToken::AttrTarget(data) => stack + FlatToken::AttrsTarget(target) => stack .last_mut() .expect("Bottom token frame is missing!") .inner - .push(AttrTokenTree::Attributes(data)), + .push(AttrTokenTree::AttrsTarget(target)), FlatToken::Empty => {} } token_and_spacing = iter.next(); diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 5f16a3e1f37..45ca267fe5d 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -20,7 +20,7 @@ use path::PathStyle; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, IdentIsRaw, Nonterminal, Token, TokenKind}; -use rustc_ast::tokenstream::{AttributesData, DelimSpacing, DelimSpan, Spacing}; +use rustc_ast::tokenstream::{AttrsTarget, DelimSpacing, DelimSpan, Spacing}; use rustc_ast::tokenstream::{TokenStream, TokenTree, TokenTreeCursor}; use rustc_ast::util::case::Case; use rustc_ast::{ @@ -203,13 +203,13 @@ struct ClosureSpans { } /// Indicates a range of tokens that should be replaced by -/// the tokens in the provided vector. This is used in two +/// the tokens in the provided `AttrsTarget`. This is used in two /// places during token collection: /// /// 1. During the parsing of an AST node that may have a `#[derive]` /// attribute, we parse a nested AST node that has `#[cfg]` or `#[cfg_attr]` /// In this case, we use a `ReplaceRange` to replace the entire inner AST node -/// with `FlatToken::AttrTarget`, allowing us to perform eager cfg-expansion +/// with `FlatToken::AttrsTarget`, allowing us to perform eager cfg-expansion /// on an `AttrTokenStream`. /// /// 2. When we parse an inner attribute while collecting tokens. We @@ -219,7 +219,7 @@ struct ClosureSpans { /// the first macro inner attribute to invoke a proc-macro). /// When create a `TokenStream`, the inner attributes get inserted /// into the proper place in the token stream. -type ReplaceRange = (Range<u32>, Vec<(FlatToken, Spacing)>); +type ReplaceRange = (Range<u32>, Option<AttrsTarget>); /// Controls how we capture tokens. Capturing can be expensive, /// so we try to avoid performing capturing in cases where @@ -1608,11 +1608,10 @@ enum FlatToken { /// A token - this holds both delimiter (e.g. '{' and '}') /// and non-delimiter tokens Token(Token), - /// Holds the `AttributesData` for an AST node. The - /// `AttributesData` is inserted directly into the - /// constructed `AttrTokenStream` as - /// an `AttrTokenTree::Attributes`. - AttrTarget(AttributesData), + /// Holds the `AttrsTarget` for an AST node. The `AttrsTarget` is inserted + /// directly into the constructed `AttrTokenStream` as an + /// `AttrTokenTree::AttrsTarget`. + AttrsTarget(AttrsTarget), /// A special 'empty' token that is ignored during the conversion /// to an `AttrTokenStream`. This is used to simplify the /// handling of replace ranges. diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 80619c59cc3..a4fdb4a0baf 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -8,6 +8,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_span::hygiene::LocalExpnId; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; +use std::mem; use tracing::debug; pub(crate) fn collect_definitions( @@ -15,8 +16,9 @@ pub(crate) fn collect_definitions( fragment: &AstFragment, expansion: LocalExpnId, ) { - let (parent_def, impl_trait_context) = resolver.invocation_parents[&expansion]; - fragment.visit_with(&mut DefCollector { resolver, parent_def, expansion, impl_trait_context }); + let (parent_def, impl_trait_context, in_attr) = resolver.invocation_parents[&expansion]; + let mut visitor = DefCollector { resolver, parent_def, expansion, impl_trait_context, in_attr }; + fragment.visit_with(&mut visitor); } /// Creates `DefId`s for nodes in the AST. @@ -24,6 +26,7 @@ struct DefCollector<'a, 'b, 'tcx> { resolver: &'a mut Resolver<'b, 'tcx>, parent_def: LocalDefId, impl_trait_context: ImplTraitContext, + in_attr: bool, expansion: LocalExpnId, } @@ -53,7 +56,7 @@ impl<'a, 'b, 'tcx> DefCollector<'a, 'b, 'tcx> { } fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: LocalDefId, f: F) { - let orig_parent_def = std::mem::replace(&mut self.parent_def, parent_def); + let orig_parent_def = mem::replace(&mut self.parent_def, parent_def); f(self); self.parent_def = orig_parent_def; } @@ -63,7 +66,7 @@ impl<'a, 'b, 'tcx> DefCollector<'a, 'b, 'tcx> { impl_trait_context: ImplTraitContext, f: F, ) { - let orig_itc = std::mem::replace(&mut self.impl_trait_context, impl_trait_context); + let orig_itc = mem::replace(&mut self.impl_trait_context, impl_trait_context); f(self); self.impl_trait_context = orig_itc; } @@ -105,8 +108,10 @@ impl<'a, 'b, 'tcx> DefCollector<'a, 'b, 'tcx> { fn visit_macro_invoc(&mut self, id: NodeId) { let id = id.placeholder_to_expn_id(); - let old_parent = - self.resolver.invocation_parents.insert(id, (self.parent_def, self.impl_trait_context)); + let old_parent = self + .resolver + .invocation_parents + .insert(id, (self.parent_def, self.impl_trait_context, self.in_attr)); assert!(old_parent.is_none(), "parent `LocalDefId` is reset for an invocation"); } } @@ -413,4 +418,10 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { visit::walk_crate(self, krate) } } + + fn visit_attribute(&mut self, attr: &'a Attribute) -> Self::Result { + let orig_in_attr = mem::replace(&mut self.in_attr, true); + visit::walk_attribute(self, attr); + self.in_attr = orig_in_attr; + } } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index ad4e222f4de..1d37264f96a 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1744,7 +1744,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { ) { self.r.dcx().emit_err(errors::LendingIteratorReportError { lifetime: lifetime.ident.span, - ty: ty.span(), + ty: ty.span, }); } else { self.r.dcx().emit_err(errors::AnonymousLivetimeNonGatReportError { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 7bf32a023f1..7cb5a3fb2fd 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1139,7 +1139,7 @@ pub struct Resolver<'a, 'tcx> { /// When collecting definitions from an AST fragment produced by a macro invocation `ExpnId` /// we know what parent node that fragment should be attached to thanks to this table, /// and how the `impl Trait` fragments were introduced. - invocation_parents: FxHashMap<LocalExpnId, (LocalDefId, ImplTraitContext)>, + invocation_parents: FxHashMap<LocalExpnId, (LocalDefId, ImplTraitContext, bool /*in_attr*/)>, /// Some way to know that we are in a *trait* impl in `visit_assoc_item`. /// FIXME: Replace with a more general AST map (together with some other fields). @@ -1371,7 +1371,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { node_id_to_def_id.insert(CRATE_NODE_ID, crate_feed); let mut invocation_parents = FxHashMap::default(); - invocation_parents.insert(LocalExpnId::ROOT, (CRATE_DEF_ID, ImplTraitContext::Existential)); + invocation_parents + .insert(LocalExpnId::ROOT, (CRATE_DEF_ID, ImplTraitContext::Existential, false)); let mut extern_prelude: FxHashMap<Ident, ExternPreludeEntry<'_>> = tcx .sess diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 026a2ca1412..cb9bebd33d3 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -297,11 +297,12 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> { .invocation_parents .get(&invoc_id) .or_else(|| self.invocation_parents.get(&eager_expansion_root)) - .map(|&(mod_def_id, _)| mod_def_id) - .filter(|&mod_def_id| { - invoc.fragment_kind == AstFragmentKind::Expr + .filter(|&&(mod_def_id, _, in_attr)| { + in_attr + && invoc.fragment_kind == AstFragmentKind::Expr && self.tcx.def_kind(mod_def_id) == DefKind::Mod - }); + }) + .map(|&(mod_def_id, ..)| mod_def_id); let (ext, res) = self.smart_resolve_macro_path( path, kind, diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index c95649e2ffb..ad087620ae0 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -1,3 +1,4 @@ +use crate::infer::at::ToTrace; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use crate::traits::{self, Obligation, ObligationCause, ObligationCtxt, SelectionContext}; @@ -17,6 +18,16 @@ pub use rustc_infer::infer::*; #[extension(pub trait InferCtxtExt<'tcx>)] impl<'tcx> InferCtxt<'tcx> { + fn can_eq<T: ToTrace<'tcx>>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool { + self.probe(|_| { + let ocx = ObligationCtxt::new(self); + let Ok(()) = ocx.eq(&ObligationCause::dummy(), param_env, a, b) else { + return false; + }; + ocx.select_where_possible().is_empty() + }) + } + fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { let ty = self.resolve_vars_if_possible(ty); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 32c8a454b40..94b28426f43 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -1,5 +1,10 @@ use super::{ObligationCauseCode, PredicateObligation}; +use crate::errors::{ + EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented, +}; use crate::infer::error_reporting::TypeErrCtxt; +use crate::infer::InferCtxtExt; +use crate::traits::error_reporting::type_err_ctxt_ext::InferCtxtPrivExt; use rustc_ast::AttrArgs; use rustc_ast::AttrArgsEq; use rustc_ast::AttrKind; @@ -21,12 +26,6 @@ use rustc_span::Span; use std::iter; use std::path::PathBuf; -use crate::errors::{ - EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented, -}; - -use crate::traits::error_reporting::type_err_ctxt_ext::InferCtxtPrivExt; - /// The symbols which are always allowed in a format string static ALLOWED_FORMAT_SYMBOLS: &[Symbol] = &[ kw::SelfUpper, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index a0a8e5963f1..52edffce614 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -3472,6 +3472,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) }); } + // Suppress `compare_type_predicate_entailment` errors for RPITITs, since they + // should be implied by the parent method. + ObligationCauseCode::CompareImplItem { trait_item_def_id, .. } + if tcx.is_impl_trait_in_trait(trait_item_def_id) => {} ObligationCauseCode::CompareImplItem { trait_item_def_id, kind, .. } => { let item_name = tcx.item_name(trait_item_def_id); let msg = format!( diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 17b6dd2bc58..5461f9e65af 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -1073,7 +1073,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // mismatched, then we have a totally different error to report. if self.enter_forall(found_args, |found_args| { self.enter_forall(expected_args, |expected_args| { - !self.can_sub(obligation.param_env, expected_args, found_args) + !self.can_eq(obligation.param_env, expected_args, found_args) }) }) { return None; diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index b38841db923..8525215a3bc 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -3,7 +3,6 @@ use crate::traits::wf; use crate::traits::ObligationCtxt; use rustc_infer::infer::canonical::Canonical; -use rustc_infer::infer::outlives::components::{push_outlives_components, Component}; use rustc_infer::infer::resolve::OpportunisticRegionResolver; use rustc_infer::traits::query::OutlivesBound; use rustc_macros::{HashStable, TypeFoldable, TypeVisitable}; @@ -12,6 +11,7 @@ use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFolder, TypeVisitableExt}; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::DUMMY_SP; +use rustc_type_ir::outlives::{push_outlives_components, Component}; use smallvec::{smallvec, SmallVec}; #[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable)] @@ -284,7 +284,7 @@ pub fn compute_implied_outlives_bounds_compat_inner<'tcx>( /// those relationships. fn implied_bounds_from_components<'tcx>( sub_region: ty::Region<'tcx>, - sup_components: SmallVec<[Component<'tcx>; 4]>, + sup_components: SmallVec<[Component<TyCtxt<'tcx>>; 4]>, ) -> Vec<OutlivesBound<'tcx>> { sup_components .into_iter() diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 68cc04bc8e6..fa130420174 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -18,7 +18,7 @@ use super::{ TraitQueryMode, }; -use crate::infer::{InferCtxt, InferOk, TypeFreshener}; +use crate::infer::{InferCtxt, InferCtxtExt, InferOk, TypeFreshener}; use crate::solve::InferCtxtSelectExt as _; use crate::traits::error_reporting::TypeErrCtxtExt; use crate::traits::normalize::normalize_with_depth; diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index ffe16964ae5..68c2575258d 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -232,6 +232,10 @@ pub trait Region<I: Interner<Region = Self>>: fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self; fn new_static(interner: I) -> Self; + + fn is_bound(self) -> bool { + matches!(self.kind(), ty::ReBound(..)) + } } pub trait Const<I: Interner<Const = Self>>: @@ -272,6 +276,10 @@ pub trait Const<I: Interner<Const = Self>>: } } +pub trait ExprConst<I: Interner<ExprConst = Self>>: Copy + Debug + Hash + Eq + Relate<I> { + fn args(self) -> I::GenericArgs; +} + pub trait GenericsOf<I: Interner<GenericsOf = Self>> { fn count(&self) -> usize; } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index db97bdca382..6e013768c3e 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -32,6 +32,7 @@ pub trait Interner: { type DefId: DefId<Self>; type LocalDefId: Copy + Debug + Hash + Eq + Into<Self::DefId> + TypeFoldable<Self>; + type Span: Copy + Debug + Hash + Eq; type GenericArgs: GenericArgs<Self>; type GenericArgsSlice: Copy + Debug + Hash + Eq + SliceLike<Item = Self::GenericArg>; @@ -109,7 +110,7 @@ pub trait Interner: type ParamConst: Copy + Debug + Hash + Eq + ParamLike; type BoundConst: Copy + Debug + Hash + Eq + BoundVarLike<Self>; type ValueConst: Copy + Debug + Hash + Eq; - type ExprConst: Copy + Debug + Hash + Eq + Relate<Self>; + type ExprConst: ExprConst<Self>; // Kinds of regions type Region: Region<Self>; diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index c57ac74cdfd..2a909b06baf 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -27,6 +27,7 @@ pub mod inherent; pub mod ir_print; pub mod lang_items; pub mod lift; +pub mod outlives; pub mod relate; pub mod solve; diff --git a/compiler/rustc_type_ir/src/outlives.rs b/compiler/rustc_type_ir/src/outlives.rs new file mode 100644 index 00000000000..61dfa2643d8 --- /dev/null +++ b/compiler/rustc_type_ir/src/outlives.rs @@ -0,0 +1,335 @@ +//! The outlives relation `T: 'a` or `'a: 'b`. This code frequently +//! refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that +//! RFC for reference. + +use smallvec::{smallvec, SmallVec}; +use tracing::debug; + +use crate::data_structures::SsoHashSet; +use crate::inherent::*; +use crate::visit::TypeVisitableExt as _; +use crate::{self as ty, Interner}; + +#[derive(derivative::Derivative)] +#[derivative(Debug(bound = ""))] +pub enum Component<I: Interner> { + Region(I::Region), + Param(I::ParamTy), + Placeholder(I::PlaceholderTy), + UnresolvedInferenceVariable(ty::InferTy), + + // Projections like `T::Foo` are tricky because a constraint like + // `T::Foo: 'a` can be satisfied in so many ways. There may be a + // where-clause that says `T::Foo: 'a`, or the defining trait may + // include a bound like `type Foo: 'static`, or -- in the most + // conservative way -- we can prove that `T: 'a` (more generally, + // that all components in the projection outlive `'a`). This code + // is not in a position to judge which is the best technique, so + // we just product the projection as a component and leave it to + // the consumer to decide (but see `EscapingProjection` below). + Alias(ty::AliasTy<I>), + + // In the case where a projection has escaping regions -- meaning + // regions bound within the type itself -- we always use + // the most conservative rule, which requires that all components + // outlive the bound. So for example if we had a type like this: + // + // for<'a> Trait1< <T as Trait2<'a,'b>>::Foo > + // ~~~~~~~~~~~~~~~~~~~~~~~~~ + // + // then the inner projection (underlined) has an escaping region + // `'a`. We consider that outer trait `'c` to meet a bound if `'b` + // outlives `'b: 'c`, and we don't consider whether the trait + // declares that `Foo: 'static` etc. Therefore, we just return the + // free components of such a projection (in this case, `'b`). + // + // However, in the future, we may want to get smarter, and + // actually return a "higher-ranked projection" here. Therefore, + // we mark that these components are part of an escaping + // projection, so that implied bounds code can avoid relying on + // them. This gives us room to improve the regionck reasoning in + // the future without breaking backwards compat. + EscapingAlias(Vec<Component<I>>), +} + +/// Push onto `out` all the things that must outlive `'a` for the condition +/// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**. +pub fn push_outlives_components<I: Interner>( + tcx: I, + ty0: I::Ty, + out: &mut SmallVec<[Component<I>; 4]>, +) { + let mut visited = SsoHashSet::new(); + compute_components_for_ty(tcx, ty0, out, &mut visited); + debug!("components({:?}) = {:?}", ty0, out); +} + +fn compute_components_for_arg<I: Interner>( + tcx: I, + arg: I::GenericArg, + out: &mut SmallVec<[Component<I>; 4]>, + visited: &mut SsoHashSet<I::GenericArg>, +) { + match arg.kind() { + ty::GenericArgKind::Type(ty) => { + compute_components_for_ty(tcx, ty, out, visited); + } + ty::GenericArgKind::Lifetime(lt) => { + compute_components_for_lt(lt, out); + } + ty::GenericArgKind::Const(ct) => { + compute_components_for_const(tcx, ct, out, visited); + } + } +} + +fn compute_components_for_ty<I: Interner>( + tcx: I, + ty: I::Ty, + out: &mut SmallVec<[Component<I>; 4]>, + visited: &mut SsoHashSet<I::GenericArg>, +) { + if !visited.insert(ty.into()) { + return; + } + // Descend through the types, looking for the various "base" + // components and collecting them into `out`. This is not written + // with `collect()` because of the need to sometimes skip subtrees + // in the `subtys` iterator (e.g., when encountering a + // projection). + match ty.kind() { + ty::FnDef(_, args) => { + // HACK(eddyb) ignore lifetimes found shallowly in `args`. + // This is inconsistent with `ty::Adt` (including all args) + // and with `ty::Closure` (ignoring all args other than + // upvars, of which a `ty::FnDef` doesn't have any), but + // consistent with previous (accidental) behavior. + // See https://github.com/rust-lang/rust/issues/70917 + // for further background and discussion. + for child in args.iter() { + match child.kind() { + ty::GenericArgKind::Type(ty) => { + compute_components_for_ty(tcx, ty, out, visited); + } + ty::GenericArgKind::Lifetime(_) => {} + ty::GenericArgKind::Const(ct) => { + compute_components_for_const(tcx, ct, out, visited); + } + } + } + } + + ty::Pat(element, _) | ty::Array(element, _) => { + compute_components_for_ty(tcx, element, out, visited); + } + + ty::Closure(_, args) => { + let tupled_ty = args.as_closure().tupled_upvars_ty(); + compute_components_for_ty(tcx, tupled_ty, out, visited); + } + + ty::CoroutineClosure(_, args) => { + let tupled_ty = args.as_coroutine_closure().tupled_upvars_ty(); + compute_components_for_ty(tcx, tupled_ty, out, visited); + } + + ty::Coroutine(_, args) => { + // Same as the closure case + let tupled_ty = args.as_coroutine().tupled_upvars_ty(); + compute_components_for_ty(tcx, tupled_ty, out, visited); + + // We ignore regions in the coroutine interior as we don't + // want these to affect region inference + } + + // All regions are bound inside a witness, and we don't emit + // higher-ranked outlives components currently. + ty::CoroutineWitness(..) => {}, + + // OutlivesTypeParameterEnv -- the actual checking that `X:'a` + // is implied by the environment is done in regionck. + ty::Param(p) => { + out.push(Component::Param(p)); + } + + ty::Placeholder(p) => { + out.push(Component::Placeholder(p)); + } + + // For projections, we prefer to generate an obligation like + // `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the + // regionck more ways to prove that it holds. However, + // regionck is not (at least currently) prepared to deal with + // higher-ranked regions that may appear in the + // trait-ref. Therefore, if we see any higher-ranked regions, + // we simply fallback to the most restrictive rule, which + // requires that `Pi: 'a` for all `i`. + ty::Alias(_, alias_ty) => { + if !alias_ty.has_escaping_bound_vars() { + // best case: no escaping regions, so push the + // projection and skip the subtree (thus generating no + // constraints for Pi). This defers the choice between + // the rules OutlivesProjectionEnv, + // OutlivesProjectionTraitDef, and + // OutlivesProjectionComponents to regionck. + out.push(Component::Alias(alias_ty)); + } else { + // fallback case: hard code + // OutlivesProjectionComponents. Continue walking + // through and constrain Pi. + let mut subcomponents = smallvec![]; + let mut subvisited = SsoHashSet::new(); + compute_alias_components_recursive(tcx, ty, &mut subcomponents, &mut subvisited); + out.push(Component::EscapingAlias(subcomponents.into_iter().collect())); + } + } + + // We assume that inference variables are fully resolved. + // So, if we encounter an inference variable, just record + // the unresolved variable as a component. + ty::Infer(infer_ty) => { + out.push(Component::UnresolvedInferenceVariable(infer_ty)); + } + + // Most types do not introduce any region binders, nor + // involve any other subtle cases, and so the WF relation + // simply constraints any regions referenced directly by + // the type and then visits the types that are lexically + // contained within. (The comments refer to relevant rules + // from RFC1214.) + + ty::Bool | // OutlivesScalar + ty::Char | // OutlivesScalar + ty::Int(..) | // OutlivesScalar + ty::Uint(..) | // OutlivesScalar + ty::Float(..) | // OutlivesScalar + ty::Never | // OutlivesScalar + ty::Foreign(..) | // OutlivesNominalType + ty::Str | // OutlivesScalar (ish) + ty::Bound(..) | + ty::Error(_) => { + // Trivial. + } + + // OutlivesNominalType + ty::Adt(_, args) => { + for arg in args.iter() { + compute_components_for_arg(tcx, arg, out, visited); + } + } + + // OutlivesNominalType + ty::Slice(ty) | + ty::RawPtr(ty, _) => { + compute_components_for_ty(tcx, ty, out, visited); + } + ty::Tuple(tys) => { + for ty in tys.iter() { + compute_components_for_ty(tcx, ty, out, visited); + } + } + + // OutlivesReference + ty::Ref(lt, ty, _) => { + compute_components_for_lt(lt, out); + compute_components_for_ty(tcx, ty, out, visited); + } + + ty::Dynamic(preds, lt, _) => { + compute_components_for_lt(lt, out); + for pred in preds.iter() { + match pred.skip_binder() { + ty::ExistentialPredicate::Trait(tr) => { + for arg in tr.args.iter() { + compute_components_for_arg(tcx, arg, out, visited); + } + } + ty::ExistentialPredicate::Projection(proj) => { + for arg in proj.args.iter() { + compute_components_for_arg(tcx, arg, out, visited); + } + match proj.term.kind() { + ty::TermKind::Ty(ty) => { + compute_components_for_ty(tcx, ty, out, visited) + } + ty::TermKind::Const(ct) => { + compute_components_for_const(tcx, ct, out, visited) + } + } + } + ty::ExistentialPredicate::AutoTrait(..) => {} + } + } + } + + ty::FnPtr(sig) => { + for ty in sig.skip_binder().inputs_and_output.iter() { + compute_components_for_ty(tcx, ty, out, visited); + } + } + } +} + +/// Collect [Component]s for *all* the args of `parent`. +/// +/// This should not be used to get the components of `parent` itself. +/// Use [push_outlives_components] instead. +pub fn compute_alias_components_recursive<I: Interner>( + tcx: I, + alias_ty: I::Ty, + out: &mut SmallVec<[Component<I>; 4]>, + visited: &mut SsoHashSet<I::GenericArg>, +) { + let ty::Alias(kind, alias_ty) = alias_ty.kind() else { + unreachable!("can only call `compute_alias_components_recursive` on an alias type") + }; + + let opt_variances = + if kind == ty::Opaque { Some(tcx.variances_of(alias_ty.def_id)) } else { None }; + + for (index, child) in alias_ty.args.iter().enumerate() { + if opt_variances.and_then(|variances| variances.get(index)) == Some(ty::Bivariant) { + continue; + } + compute_components_for_arg(tcx, child, out, visited); + } +} + +fn compute_components_for_lt<I: Interner>(lt: I::Region, out: &mut SmallVec<[Component<I>; 4]>) { + if !lt.is_bound() { + out.push(Component::Region(lt)); + } +} + +fn compute_components_for_const<I: Interner>( + tcx: I, + ct: I::Const, + out: &mut SmallVec<[Component<I>; 4]>, + visited: &mut SsoHashSet<I::GenericArg>, +) { + if !visited.insert(ct.into()) { + return; + } + match ct.kind() { + ty::ConstKind::Param(_) + | ty::ConstKind::Bound(_, _) + | ty::ConstKind::Infer(_) + | ty::ConstKind::Placeholder(_) + | ty::ConstKind::Error(_) => { + // Trivial + } + ty::ConstKind::Expr(e) => { + for arg in e.args().iter() { + compute_components_for_arg(tcx, arg, out, visited); + } + } + ty::ConstKind::Value(ty, _) => { + compute_components_for_ty(tcx, ty, out, visited); + } + ty::ConstKind::Unevaluated(uv) => { + for arg in uv.args.iter() { + compute_components_for_arg(tcx, arg, out, visited); + } + } + } +} diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index 01510a61405..077483a174b 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -1495,6 +1495,14 @@ impl<'a, T, A: Allocator> Cursor<'a, T, A> { pub fn back(&self) -> Option<&'a T> { self.list.back() } + + /// Provides a reference to the cursor's parent list. + #[must_use] + #[inline(always)] + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn as_list(&self) -> &'a LinkedList<T, A> { + self.list + } } impl<'a, T, A: Allocator> CursorMut<'a, T, A> { @@ -1605,6 +1613,18 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> { pub fn as_cursor(&self) -> Cursor<'_, T, A> { Cursor { list: self.list, current: self.current, index: self.index } } + + /// Provides a read-only reference to the cursor's parent list. + /// + /// The lifetime of the returned reference is bound to that of the + /// `CursorMut`, which means it cannot outlive the `CursorMut` and that the + /// `CursorMut` is frozen for the lifetime of the reference. + #[must_use] + #[inline(always)] + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn as_list(&self) -> &LinkedList<T, A> { + self.list + } } // Now the list editing operations diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 61d05afccfd..a07f250d7d8 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -164,6 +164,20 @@ impl<T, A: Allocator> VecDeque<T, A> { self.buf.ptr() } + /// Appends an element to the buffer. + /// + /// # Safety + /// + /// May only be called if `deque.len() < deque.capacity()` + #[inline] + unsafe fn push_unchecked(&mut self, element: T) { + // SAFETY: Because of the precondition, it's guaranteed that there is space + // in the logical array after the last element. + unsafe { self.buffer_write(self.to_physical_idx(self.len), element) }; + // This can't overflow because `deque.len() < deque.capacity() <= usize::MAX`. + self.len += 1; + } + /// Moves an element out of the buffer #[inline] unsafe fn buffer_read(&mut self, off: usize) -> T { @@ -2911,6 +2925,14 @@ impl<T, A: Allocator> Extend<T> for VecDeque<T, A> { fn extend_reserve(&mut self, additional: usize) { self.reserve(additional); } + + #[inline] + unsafe fn extend_one_unchecked(&mut self, item: T) { + // SAFETY: Our preconditions ensure the space has been reserved, and `extend_reserve` is implemented correctly. + unsafe { + self.push_unchecked(item); + } + } } #[stable(feature = "extend_ref", since = "1.2.0")] @@ -2928,6 +2950,14 @@ impl<'a, T: 'a + Copy, A: Allocator> Extend<&'a T> for VecDeque<T, A> { fn extend_reserve(&mut self, additional: usize) { self.reserve(additional); } + + #[inline] + unsafe fn extend_one_unchecked(&mut self, &item: &'a T) { + // SAFETY: Our preconditions ensure the space has been reserved, and `extend_reserve` is implemented correctly. + unsafe { + self.push_unchecked(item); + } + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/alloc/src/collections/vec_deque/spec_extend.rs b/library/alloc/src/collections/vec_deque/spec_extend.rs index dccf40ccb38..6a89abc3ef9 100644 --- a/library/alloc/src/collections/vec_deque/spec_extend.rs +++ b/library/alloc/src/collections/vec_deque/spec_extend.rs @@ -21,21 +21,12 @@ where // self.push_back(item); // } - // May only be called if `deque.len() < deque.capacity()` - unsafe fn push_unchecked<T, A: Allocator>(deque: &mut VecDeque<T, A>, element: T) { - // SAFETY: Because of the precondition, it's guaranteed that there is space - // in the logical array after the last element. - unsafe { deque.buffer_write(deque.to_physical_idx(deque.len), element) }; - // This can't overflow because `deque.len() < deque.capacity() <= usize::MAX`. - deque.len += 1; - } - while let Some(element) = iter.next() { let (lower, _) = iter.size_hint(); self.reserve(lower.saturating_add(1)); // SAFETY: We just reserved space for at least one element. - unsafe { push_unchecked(self, element) }; + unsafe { self.push_unchecked(element) }; // Inner loop to avoid repeatedly calling `reserve`. while self.len < self.capacity() { @@ -43,7 +34,7 @@ where return; }; // SAFETY: The loop condition guarantees that `self.len() < self.capacity()`. - unsafe { push_unchecked(self, element) }; + unsafe { self.push_unchecked(element) }; } } } diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 703538d0f35..3237d8654c2 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -124,6 +124,7 @@ #![feature(error_generic_member_access)] #![feature(exact_size_is_empty)] #![feature(extend_one)] +#![feature(extend_one_unchecked)] #![feature(fmt_internals)] #![feature(fn_traits)] #![feature(hasher_prefixfree_extras)] diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 90672164cb9..1983ea8281a 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -197,11 +197,7 @@ macro_rules! acquire { /// /// Sharing some immutable data between threads: /// -// Note that we **do not** run these tests here. The windows builders get super -// unhappy if a thread outlives the main thread and then exits at the same time -// (something deadlocks) so we just avoid this entirely by not running these -// tests. -/// ```no_run +/// ``` /// use std::sync::Arc; /// use std::thread; /// @@ -220,7 +216,7 @@ macro_rules! acquire { /// /// [`AtomicUsize`]: core::sync::atomic::AtomicUsize "sync::atomic::AtomicUsize" /// -/// ```no_run +/// ``` /// use std::sync::Arc; /// use std::sync::atomic::{AtomicUsize, Ordering}; /// use std::thread; diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index f1706e31bb8..6e9b017ad75 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -3048,6 +3048,16 @@ impl<T, A: Allocator> Extend<T> for Vec<T, A> { fn extend_reserve(&mut self, additional: usize) { self.reserve(additional); } + + #[inline] + unsafe fn extend_one_unchecked(&mut self, item: T) { + // SAFETY: Our preconditions ensure the space has been reserved, and `extend_reserve` is implemented correctly. + unsafe { + let len = self.len(); + ptr::write(self.as_mut_ptr().add(len), item); + self.set_len(len + 1); + } + } } impl<T, A: Allocator> Vec<T, A> { @@ -3244,6 +3254,16 @@ impl<'a, T: Copy + 'a, A: Allocator> Extend<&'a T> for Vec<T, A> { fn extend_reserve(&mut self, additional: usize) { self.reserve(additional); } + + #[inline] + unsafe fn extend_one_unchecked(&mut self, &item: &'a T) { + // SAFETY: Our preconditions ensure the space has been reserved, and `extend_reserve` is implemented correctly. + unsafe { + let len = self.len(); + ptr::write(self.as_mut_ptr().add(len), item); + self.set_len(len + 1); + } + } } /// Implements comparison of vectors, [lexicographically](Ord#lexicographical-comparison). diff --git a/library/core/src/any.rs b/library/core/src/any.rs index eab11ae288a..59f3b6841d5 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -673,7 +673,7 @@ impl hash::Hash for TypeId { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for TypeId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - f.debug_tuple("TypeId").field(&self.as_u128()).finish() + write!(f, "TypeId({:#034x})", self.as_u128()) } } diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs index 6d1f10f5211..88adc378477 100644 --- a/library/core/src/ffi/mod.rs +++ b/library/core/src/ffi/mod.rs @@ -10,8 +10,6 @@ #![allow(non_camel_case_types)] use crate::fmt; -use crate::marker::PhantomData; -use crate::ops::{Deref, DerefMut}; #[doc(no_inline)] #[stable(feature = "core_c_str", since = "1.64.0")] @@ -28,6 +26,20 @@ pub use self::c_str::CStr; #[unstable(feature = "c_str_module", issue = "112134")] pub mod c_str; +#[unstable( + feature = "c_variadic", + issue = "44930", + reason = "the `c_variadic` feature has not been properly tested on all supported platforms" +)] +pub use self::va_list::{VaList, VaListImpl}; + +#[unstable( + feature = "c_variadic", + issue = "44930", + reason = "the `c_variadic` feature has not been properly tested on all supported platforms" +)] +pub mod va_list; + macro_rules! type_alias { { $Docfile:tt, $Alias:ident = $Real:ty; @@ -205,404 +217,6 @@ impl fmt::Debug for c_void { } } -/// Basic implementation of a `va_list`. -// The name is WIP, using `VaListImpl` for now. -#[cfg(any( - all( - not(target_arch = "aarch64"), - not(target_arch = "powerpc"), - not(target_arch = "s390x"), - not(target_arch = "x86_64") - ), - all(target_arch = "aarch64", target_vendor = "apple"), - target_family = "wasm", - target_os = "uefi", - windows, -))] -#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435 -#[unstable( - feature = "c_variadic", - reason = "the `c_variadic` feature has not been properly tested on \ - all supported platforms", - issue = "44930" -)] -#[lang = "va_list"] -pub struct VaListImpl<'f> { - ptr: *mut c_void, - - // Invariant over `'f`, so each `VaListImpl<'f>` object is tied to - // the region of the function it's defined in - _marker: PhantomData<&'f mut &'f c_void>, -} - -#[cfg(any( - all( - not(target_arch = "aarch64"), - not(target_arch = "powerpc"), - not(target_arch = "s390x"), - not(target_arch = "x86_64") - ), - all(target_arch = "aarch64", target_vendor = "apple"), - target_family = "wasm", - target_os = "uefi", - windows, -))] -#[unstable( - feature = "c_variadic", - reason = "the `c_variadic` feature has not been properly tested on \ - all supported platforms", - issue = "44930" -)] -impl<'f> fmt::Debug for VaListImpl<'f> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "va_list* {:p}", self.ptr) - } -} - -/// AArch64 ABI implementation of a `va_list`. See the -/// [AArch64 Procedure Call Standard] for more details. -/// -/// [AArch64 Procedure Call Standard]: -/// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf -#[cfg(all( - target_arch = "aarch64", - not(target_vendor = "apple"), - not(target_os = "uefi"), - not(windows), -))] -#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401 -#[derive(Debug)] -#[unstable( - feature = "c_variadic", - reason = "the `c_variadic` feature has not been properly tested on \ - all supported platforms", - issue = "44930" -)] -#[lang = "va_list"] -pub struct VaListImpl<'f> { - stack: *mut c_void, - gr_top: *mut c_void, - vr_top: *mut c_void, - gr_offs: i32, - vr_offs: i32, - _marker: PhantomData<&'f mut &'f c_void>, -} - -/// PowerPC ABI implementation of a `va_list`. -#[cfg(all(target_arch = "powerpc", not(target_os = "uefi"), not(windows)))] -#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401 -#[derive(Debug)] -#[unstable( - feature = "c_variadic", - reason = "the `c_variadic` feature has not been properly tested on \ - all supported platforms", - issue = "44930" -)] -#[lang = "va_list"] -pub struct VaListImpl<'f> { - gpr: u8, - fpr: u8, - reserved: u16, - overflow_arg_area: *mut c_void, - reg_save_area: *mut c_void, - _marker: PhantomData<&'f mut &'f c_void>, -} - -/// s390x ABI implementation of a `va_list`. -#[cfg(target_arch = "s390x")] -#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401 -#[derive(Debug)] -#[unstable( - feature = "c_variadic", - reason = "the `c_variadic` feature has not been properly tested on \ - all supported platforms", - issue = "44930" -)] -#[lang = "va_list"] -pub struct VaListImpl<'f> { - gpr: i64, - fpr: i64, - overflow_arg_area: *mut c_void, - reg_save_area: *mut c_void, - _marker: PhantomData<&'f mut &'f c_void>, -} - -/// x86_64 ABI implementation of a `va_list`. -#[cfg(all(target_arch = "x86_64", not(target_os = "uefi"), not(windows)))] -#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401 -#[derive(Debug)] -#[unstable( - feature = "c_variadic", - reason = "the `c_variadic` feature has not been properly tested on \ - all supported platforms", - issue = "44930" -)] -#[lang = "va_list"] -pub struct VaListImpl<'f> { - gp_offset: i32, - fp_offset: i32, - overflow_arg_area: *mut c_void, - reg_save_area: *mut c_void, - _marker: PhantomData<&'f mut &'f c_void>, -} - -/// A wrapper for a `va_list` -#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435 -#[derive(Debug)] -#[unstable( - feature = "c_variadic", - reason = "the `c_variadic` feature has not been properly tested on \ - all supported platforms", - issue = "44930" -)] -pub struct VaList<'a, 'f: 'a> { - #[cfg(any( - all( - not(target_arch = "aarch64"), - not(target_arch = "powerpc"), - not(target_arch = "s390x"), - not(target_arch = "x86_64") - ), - all(target_arch = "aarch64", target_vendor = "apple"), - target_family = "wasm", - target_os = "uefi", - windows, - ))] - inner: VaListImpl<'f>, - - #[cfg(all( - any( - target_arch = "aarch64", - target_arch = "powerpc", - target_arch = "s390x", - target_arch = "x86_64" - ), - any(not(target_arch = "aarch64"), not(target_vendor = "apple")), - not(target_family = "wasm"), - not(target_os = "uefi"), - not(windows), - ))] - inner: &'a mut VaListImpl<'f>, - - _marker: PhantomData<&'a mut VaListImpl<'f>>, -} - -#[cfg(any( - all( - not(target_arch = "aarch64"), - not(target_arch = "powerpc"), - not(target_arch = "s390x"), - not(target_arch = "x86_64") - ), - all(target_arch = "aarch64", target_vendor = "apple"), - target_family = "wasm", - target_os = "uefi", - windows, -))] -#[unstable( - feature = "c_variadic", - reason = "the `c_variadic` feature has not been properly tested on \ - all supported platforms", - issue = "44930" -)] -impl<'f> VaListImpl<'f> { - /// Convert a `VaListImpl` into a `VaList` that is binary-compatible with C's `va_list`. - #[inline] - pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> { - VaList { inner: VaListImpl { ..*self }, _marker: PhantomData } - } -} - -#[cfg(all( - any( - target_arch = "aarch64", - target_arch = "powerpc", - target_arch = "s390x", - target_arch = "x86_64" - ), - any(not(target_arch = "aarch64"), not(target_vendor = "apple")), - not(target_family = "wasm"), - not(target_os = "uefi"), - not(windows), -))] -#[unstable( - feature = "c_variadic", - reason = "the `c_variadic` feature has not been properly tested on \ - all supported platforms", - issue = "44930" -)] -impl<'f> VaListImpl<'f> { - /// Convert a `VaListImpl` into a `VaList` that is binary-compatible with C's `va_list`. - #[inline] - pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> { - VaList { inner: self, _marker: PhantomData } - } -} - -#[unstable( - feature = "c_variadic", - reason = "the `c_variadic` feature has not been properly tested on \ - all supported platforms", - issue = "44930" -)] -impl<'a, 'f: 'a> Deref for VaList<'a, 'f> { - type Target = VaListImpl<'f>; - - #[inline] - fn deref(&self) -> &VaListImpl<'f> { - &self.inner - } -} - -#[unstable( - feature = "c_variadic", - reason = "the `c_variadic` feature has not been properly tested on \ - all supported platforms", - issue = "44930" -)] -impl<'a, 'f: 'a> DerefMut for VaList<'a, 'f> { - #[inline] - fn deref_mut(&mut self) -> &mut VaListImpl<'f> { - &mut self.inner - } -} - -// The VaArgSafe trait needs to be used in public interfaces, however, the trait -// itself must not be allowed to be used outside this module. Allowing users to -// implement the trait for a new type (thereby allowing the va_arg intrinsic to -// be used on a new type) is likely to cause undefined behavior. -// -// FIXME(dlrobertson): In order to use the VaArgSafe trait in a public interface -// but also ensure it cannot be used elsewhere, the trait needs to be public -// within a private module. Once RFC 2145 has been implemented look into -// improving this. -mod sealed_trait { - /// Trait which permits the allowed types to be used with [super::VaListImpl::arg]. - #[unstable( - feature = "c_variadic", - reason = "the `c_variadic` feature has not been properly tested on \ - all supported platforms", - issue = "44930" - )] - pub unsafe trait VaArgSafe {} -} - -macro_rules! impl_va_arg_safe { - ($($t:ty),+) => { - $( - #[unstable(feature = "c_variadic", - reason = "the `c_variadic` feature has not been properly tested on \ - all supported platforms", - issue = "44930")] - unsafe impl sealed_trait::VaArgSafe for $t {} - )+ - } -} - -impl_va_arg_safe! {i8, i16, i32, i64, usize} -impl_va_arg_safe! {u8, u16, u32, u64, isize} -impl_va_arg_safe! {f64} - -#[unstable( - feature = "c_variadic", - reason = "the `c_variadic` feature has not been properly tested on \ - all supported platforms", - issue = "44930" -)] -unsafe impl<T> sealed_trait::VaArgSafe for *mut T {} - -#[unstable( - feature = "c_variadic", - reason = "the `c_variadic` feature has not been properly tested on \ - all supported platforms", - issue = "44930" -)] -unsafe impl<T> sealed_trait::VaArgSafe for *const T {} - -#[unstable( - feature = "c_variadic", - reason = "the `c_variadic` feature has not been properly tested on \ - all supported platforms", - issue = "44930" -)] -impl<'f> VaListImpl<'f> { - /// Advance to the next arg. - #[inline] - pub unsafe fn arg<T: sealed_trait::VaArgSafe>(&mut self) -> T { - // SAFETY: the caller must uphold the safety contract for `va_arg`. - unsafe { va_arg(self) } - } - - /// Copies the `va_list` at the current location. - pub unsafe fn with_copy<F, R>(&self, f: F) -> R - where - F: for<'copy> FnOnce(VaList<'copy, 'f>) -> R, - { - let mut ap = self.clone(); - let ret = f(ap.as_va_list()); - // SAFETY: the caller must uphold the safety contract for `va_end`. - unsafe { - va_end(&mut ap); - } - ret - } -} - -#[unstable( - feature = "c_variadic", - reason = "the `c_variadic` feature has not been properly tested on \ - all supported platforms", - issue = "44930" -)] -impl<'f> Clone for VaListImpl<'f> { - #[inline] - fn clone(&self) -> Self { - let mut dest = crate::mem::MaybeUninit::uninit(); - // SAFETY: we write to the `MaybeUninit`, thus it is initialized and `assume_init` is legal - unsafe { - va_copy(dest.as_mut_ptr(), self); - dest.assume_init() - } - } -} - -#[unstable( - feature = "c_variadic", - reason = "the `c_variadic` feature has not been properly tested on \ - all supported platforms", - issue = "44930" -)] -impl<'f> Drop for VaListImpl<'f> { - fn drop(&mut self) { - // FIXME: this should call `va_end`, but there's no clean way to - // guarantee that `drop` always gets inlined into its caller, - // so the `va_end` would get directly called from the same function as - // the corresponding `va_copy`. `man va_end` states that C requires this, - // and LLVM basically follows the C semantics, so we need to make sure - // that `va_end` is always called from the same function as `va_copy`. - // For more details, see https://github.com/rust-lang/rust/pull/59625 - // and https://llvm.org/docs/LangRef.html#llvm-va-end-intrinsic. - // - // This works for now, since `va_end` is a no-op on all current LLVM targets. - } -} - -extern "rust-intrinsic" { - /// Destroy the arglist `ap` after initialization with `va_start` or - /// `va_copy`. - #[rustc_nounwind] - fn va_end(ap: &mut VaListImpl<'_>); - - /// Copies the current location of arglist `src` to the arglist `dst`. - #[rustc_nounwind] - fn va_copy<'f>(dest: *mut VaListImpl<'f>, src: &VaListImpl<'f>); - - /// Loads an argument of type `T` from the `va_list` `ap` and increment the - /// argument `ap` points to. - #[rustc_nounwind] - fn va_arg<T: sealed_trait::VaArgSafe>(ap: &mut VaListImpl<'_>) -> T; -} - // Link the MSVC default lib #[cfg(all(windows, target_env = "msvc"))] #[link( diff --git a/library/core/src/ffi/va_list.rs b/library/core/src/ffi/va_list.rs new file mode 100644 index 00000000000..6a2e8b67d0c --- /dev/null +++ b/library/core/src/ffi/va_list.rs @@ -0,0 +1,301 @@ +//! C's "variable arguments" +//! +//! Better known as "varargs". + +use crate::ffi::c_void; + +#[allow(unused_imports)] +use crate::fmt; +use crate::marker::PhantomData; +use crate::ops::{Deref, DerefMut}; + +/// Basic implementation of a `va_list`. +// The name is WIP, using `VaListImpl` for now. +#[cfg(any( + all( + not(target_arch = "aarch64"), + not(target_arch = "powerpc"), + not(target_arch = "s390x"), + not(target_arch = "x86_64") + ), + all(target_arch = "aarch64", target_vendor = "apple"), + target_family = "wasm", + target_os = "uefi", + windows, +))] +#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435 +#[lang = "va_list"] +pub struct VaListImpl<'f> { + ptr: *mut c_void, + + // Invariant over `'f`, so each `VaListImpl<'f>` object is tied to + // the region of the function it's defined in + _marker: PhantomData<&'f mut &'f c_void>, +} + +#[cfg(any( + all( + not(target_arch = "aarch64"), + not(target_arch = "powerpc"), + not(target_arch = "s390x"), + not(target_arch = "x86_64") + ), + all(target_arch = "aarch64", target_vendor = "apple"), + target_family = "wasm", + target_os = "uefi", + windows, +))] +impl<'f> fmt::Debug for VaListImpl<'f> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "va_list* {:p}", self.ptr) + } +} + +/// AArch64 ABI implementation of a `va_list`. See the +/// [AArch64 Procedure Call Standard] for more details. +/// +/// [AArch64 Procedure Call Standard]: +/// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf +#[cfg(all( + target_arch = "aarch64", + not(target_vendor = "apple"), + not(target_os = "uefi"), + not(windows), +))] +#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401 +#[derive(Debug)] +#[lang = "va_list"] +pub struct VaListImpl<'f> { + stack: *mut c_void, + gr_top: *mut c_void, + vr_top: *mut c_void, + gr_offs: i32, + vr_offs: i32, + _marker: PhantomData<&'f mut &'f c_void>, +} + +/// PowerPC ABI implementation of a `va_list`. +#[cfg(all(target_arch = "powerpc", not(target_os = "uefi"), not(windows)))] +#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401 +#[derive(Debug)] +#[lang = "va_list"] +pub struct VaListImpl<'f> { + gpr: u8, + fpr: u8, + reserved: u16, + overflow_arg_area: *mut c_void, + reg_save_area: *mut c_void, + _marker: PhantomData<&'f mut &'f c_void>, +} + +/// s390x ABI implementation of a `va_list`. +#[cfg(target_arch = "s390x")] +#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401 +#[derive(Debug)] +#[lang = "va_list"] +pub struct VaListImpl<'f> { + gpr: i64, + fpr: i64, + overflow_arg_area: *mut c_void, + reg_save_area: *mut c_void, + _marker: PhantomData<&'f mut &'f c_void>, +} + +/// x86_64 ABI implementation of a `va_list`. +#[cfg(all(target_arch = "x86_64", not(target_os = "uefi"), not(windows)))] +#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401 +#[derive(Debug)] +#[lang = "va_list"] +pub struct VaListImpl<'f> { + gp_offset: i32, + fp_offset: i32, + overflow_arg_area: *mut c_void, + reg_save_area: *mut c_void, + _marker: PhantomData<&'f mut &'f c_void>, +} + +/// A wrapper for a `va_list` +#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435 +#[derive(Debug)] +pub struct VaList<'a, 'f: 'a> { + #[cfg(any( + all( + not(target_arch = "aarch64"), + not(target_arch = "powerpc"), + not(target_arch = "s390x"), + not(target_arch = "x86_64") + ), + all(target_arch = "aarch64", target_vendor = "apple"), + target_family = "wasm", + target_os = "uefi", + windows, + ))] + inner: VaListImpl<'f>, + + #[cfg(all( + any( + target_arch = "aarch64", + target_arch = "powerpc", + target_arch = "s390x", + target_arch = "x86_64" + ), + any(not(target_arch = "aarch64"), not(target_vendor = "apple")), + not(target_family = "wasm"), + not(target_os = "uefi"), + not(windows), + ))] + inner: &'a mut VaListImpl<'f>, + + _marker: PhantomData<&'a mut VaListImpl<'f>>, +} + +#[cfg(any( + all( + not(target_arch = "aarch64"), + not(target_arch = "powerpc"), + not(target_arch = "s390x"), + not(target_arch = "x86_64") + ), + all(target_arch = "aarch64", target_vendor = "apple"), + target_family = "wasm", + target_os = "uefi", + windows, +))] +impl<'f> VaListImpl<'f> { + /// Convert a `VaListImpl` into a `VaList` that is binary-compatible with C's `va_list`. + #[inline] + pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> { + VaList { inner: VaListImpl { ..*self }, _marker: PhantomData } + } +} + +#[cfg(all( + any( + target_arch = "aarch64", + target_arch = "powerpc", + target_arch = "s390x", + target_arch = "x86_64" + ), + any(not(target_arch = "aarch64"), not(target_vendor = "apple")), + not(target_family = "wasm"), + not(target_os = "uefi"), + not(windows), +))] +impl<'f> VaListImpl<'f> { + /// Convert a `VaListImpl` into a `VaList` that is binary-compatible with C's `va_list`. + #[inline] + pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> { + VaList { inner: self, _marker: PhantomData } + } +} + +impl<'a, 'f: 'a> Deref for VaList<'a, 'f> { + type Target = VaListImpl<'f>; + + #[inline] + fn deref(&self) -> &VaListImpl<'f> { + &self.inner + } +} + +impl<'a, 'f: 'a> DerefMut for VaList<'a, 'f> { + #[inline] + fn deref_mut(&mut self) -> &mut VaListImpl<'f> { + &mut self.inner + } +} + +// The VaArgSafe trait needs to be used in public interfaces, however, the trait +// itself must not be allowed to be used outside this module. Allowing users to +// implement the trait for a new type (thereby allowing the va_arg intrinsic to +// be used on a new type) is likely to cause undefined behavior. +// +// FIXME(dlrobertson): In order to use the VaArgSafe trait in a public interface +// but also ensure it cannot be used elsewhere, the trait needs to be public +// within a private module. Once RFC 2145 has been implemented look into +// improving this. +mod sealed_trait { + /// Trait which permits the allowed types to be used with [super::VaListImpl::arg]. + pub unsafe trait VaArgSafe {} +} + +macro_rules! impl_va_arg_safe { + ($($t:ty),+) => { + $( + unsafe impl sealed_trait::VaArgSafe for $t {} + )+ + } +} + +impl_va_arg_safe! {i8, i16, i32, i64, usize} +impl_va_arg_safe! {u8, u16, u32, u64, isize} +impl_va_arg_safe! {f64} + +unsafe impl<T> sealed_trait::VaArgSafe for *mut T {} +unsafe impl<T> sealed_trait::VaArgSafe for *const T {} + +impl<'f> VaListImpl<'f> { + /// Advance to the next arg. + #[inline] + pub unsafe fn arg<T: sealed_trait::VaArgSafe>(&mut self) -> T { + // SAFETY: the caller must uphold the safety contract for `va_arg`. + unsafe { va_arg(self) } + } + + /// Copies the `va_list` at the current location. + pub unsafe fn with_copy<F, R>(&self, f: F) -> R + where + F: for<'copy> FnOnce(VaList<'copy, 'f>) -> R, + { + let mut ap = self.clone(); + let ret = f(ap.as_va_list()); + // SAFETY: the caller must uphold the safety contract for `va_end`. + unsafe { + va_end(&mut ap); + } + ret + } +} + +impl<'f> Clone for VaListImpl<'f> { + #[inline] + fn clone(&self) -> Self { + let mut dest = crate::mem::MaybeUninit::uninit(); + // SAFETY: we write to the `MaybeUninit`, thus it is initialized and `assume_init` is legal + unsafe { + va_copy(dest.as_mut_ptr(), self); + dest.assume_init() + } + } +} + +impl<'f> Drop for VaListImpl<'f> { + fn drop(&mut self) { + // FIXME: this should call `va_end`, but there's no clean way to + // guarantee that `drop` always gets inlined into its caller, + // so the `va_end` would get directly called from the same function as + // the corresponding `va_copy`. `man va_end` states that C requires this, + // and LLVM basically follows the C semantics, so we need to make sure + // that `va_end` is always called from the same function as `va_copy`. + // For more details, see https://github.com/rust-lang/rust/pull/59625 + // and https://llvm.org/docs/LangRef.html#llvm-va-end-intrinsic. + // + // This works for now, since `va_end` is a no-op on all current LLVM targets. + } +} + +extern "rust-intrinsic" { + /// Destroy the arglist `ap` after initialization with `va_start` or + /// `va_copy`. + #[rustc_nounwind] + fn va_end(ap: &mut VaListImpl<'_>); + + /// Copies the current location of arglist `src` to the arglist `dst`. + #[rustc_nounwind] + fn va_copy<'f>(dest: *mut VaListImpl<'f>, src: &VaListImpl<'f>); + + /// Loads an argument of type `T` from the `va_list` `ap` and increment the + /// argument `ap` points to. + #[rustc_nounwind] + fn va_arg<T: sealed_trait::VaArgSafe>(ap: &mut VaListImpl<'_>) -> T; +} diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs index 61a45789013..86660f2e375 100644 --- a/library/core/src/iter/traits/collect.rs +++ b/library/core/src/iter/traits/collect.rs @@ -1,3 +1,5 @@ +use super::TrustedLen; + /// Conversion from an [`Iterator`]. /// /// By implementing `FromIterator` for a type, you define how it will be @@ -460,6 +462,27 @@ pub trait Extend<A> { fn extend_reserve(&mut self, additional: usize) { let _ = additional; } + + /// Extends a collection with one element, without checking there is enough capacity for it. + /// + /// # Safety + /// + /// **For callers:** This must only be called when we know the collection has enough capacity + /// to contain the new item, for example because we previously called `extend_reserve`. + /// + /// **For implementors:** For a collection to unsafely rely on this method's safety precondition (that is, + /// invoke UB if they are violated), it must implement `extend_reserve` correctly. In other words, + /// callers may assume that if they `extend_reserve`ed enough space they can call this method. + + // This method is for internal usage only. It is only on the trait because of specialization's limitations. + #[unstable(feature = "extend_one_unchecked", issue = "none")] + #[doc(hidden)] + unsafe fn extend_one_unchecked(&mut self, item: A) + where + Self: Sized, + { + self.extend_one(item); + } } #[stable(feature = "extend_for_unit", since = "1.28.0")] @@ -499,33 +522,102 @@ where fn extend<T: IntoIterator<Item = (A, B)>>(&mut self, into_iter: T) { let (a, b) = self; let iter = into_iter.into_iter(); + SpecTupleExtend::extend(iter, a, b); + } + + fn extend_one(&mut self, item: (A, B)) { + self.0.extend_one(item.0); + self.1.extend_one(item.1); + } + + fn extend_reserve(&mut self, additional: usize) { + self.0.extend_reserve(additional); + self.1.extend_reserve(additional); + } + + unsafe fn extend_one_unchecked(&mut self, item: (A, B)) { + // SAFETY: Those are our safety preconditions, and we correctly forward `extend_reserve`. + unsafe { + self.0.extend_one_unchecked(item.0); + self.1.extend_one_unchecked(item.1); + } + } +} + +fn default_extend_tuple<A, B, ExtendA, ExtendB>( + iter: impl Iterator<Item = (A, B)>, + a: &mut ExtendA, + b: &mut ExtendB, +) where + ExtendA: Extend<A>, + ExtendB: Extend<B>, +{ + fn extend<'a, A, B>( + a: &'a mut impl Extend<A>, + b: &'a mut impl Extend<B>, + ) -> impl FnMut((), (A, B)) + 'a { + move |(), (t, u)| { + a.extend_one(t); + b.extend_one(u); + } + } + + let (lower_bound, _) = iter.size_hint(); + if lower_bound > 0 { + a.extend_reserve(lower_bound); + b.extend_reserve(lower_bound); + } + + iter.fold((), extend(a, b)); +} + +trait SpecTupleExtend<A, B> { + fn extend(self, a: &mut A, b: &mut B); +} +impl<A, B, ExtendA, ExtendB, Iter> SpecTupleExtend<ExtendA, ExtendB> for Iter +where + ExtendA: Extend<A>, + ExtendB: Extend<B>, + Iter: Iterator<Item = (A, B)>, +{ + default fn extend(self, a: &mut ExtendA, b: &mut ExtendB) { + default_extend_tuple(self, a, b); + } +} + +impl<A, B, ExtendA, ExtendB, Iter> SpecTupleExtend<ExtendA, ExtendB> for Iter +where + ExtendA: Extend<A>, + ExtendB: Extend<B>, + Iter: TrustedLen<Item = (A, B)>, +{ + fn extend(self, a: &mut ExtendA, b: &mut ExtendB) { fn extend<'a, A, B>( a: &'a mut impl Extend<A>, b: &'a mut impl Extend<B>, ) -> impl FnMut((), (A, B)) + 'a { - move |(), (t, u)| { - a.extend_one(t); - b.extend_one(u); + // SAFETY: We reserve enough space for the `size_hint`, and the iterator is `TrustedLen` + // so its `size_hint` is exact. + move |(), (t, u)| unsafe { + a.extend_one_unchecked(t); + b.extend_one_unchecked(u); } } - let (lower_bound, _) = iter.size_hint(); + let (lower_bound, upper_bound) = self.size_hint(); + + if upper_bound.is_none() { + // We cannot reserve more than `usize::MAX` items, and this is likely to go out of memory anyway. + default_extend_tuple(self, a, b); + return; + } + if lower_bound > 0 { a.extend_reserve(lower_bound); b.extend_reserve(lower_bound); } - iter.fold((), extend(a, b)); - } - - fn extend_one(&mut self, item: (A, B)) { - self.0.extend_one(item.0); - self.1.extend_one(item.1); - } - - fn extend_reserve(&mut self, additional: usize) { - self.0.extend_reserve(additional); - self.1.extend_reserve(additional); + self.fold((), extend(a, b)); } } diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 9054ade2d79..dd4b6e82343 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1266,6 +1266,20 @@ impl<T> SizedTypeProperties for T {} /// // ^^^ error[E0616]: field `private` of struct `Struct` is private /// ``` /// +/// Only [`Sized`] fields are supported, but the container may be unsized: +/// ``` +/// # use core::mem; +/// #[repr(C)] +/// pub struct Struct { +/// a: u8, +/// b: [u8], +/// } +/// +/// assert_eq!(mem::offset_of!(Struct, a), 0); // OK +/// // assert_eq!(mem::offset_of!(Struct, b), 1); +/// // ^^^ error[E0277]: doesn't have a size known at compile-time +/// ``` +/// /// Note that type layout is, in general, [subject to change and /// platform-specific](https://doc.rust-lang.org/reference/type-layout.html). If /// layout stability is required, consider using an [explicit `repr` attribute]. diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 5537d26669a..68cf8203433 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -390,37 +390,26 @@ impl<T: ?Sized> *const T { if self.is_null() { None } else { Some(unsafe { &*(self as *const MaybeUninit<T>) }) } } - /// Calculates the offset from a pointer. + /// Adds an offset to a pointer. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::<T>()` bytes. /// /// # Safety /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: + /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting - /// pointer must be either in bounds or at the end of the same [allocated object]. - /// (If it is zero, then the function is always well-defined.) + /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`. /// - /// * The computed offset, **in bytes**, cannot overflow an `isize`. + /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some + /// [allocated object], and the entire memory range between `self` and the result must be in + /// bounds of that allocated object. In particular, this range must not "wrap around" the edge + /// of the address space. /// - /// * The offset being in bounds cannot rely on "wrapping around" the address - /// space. That is, the infinite-precision sum, **in bytes** must fit in a usize. - /// - /// The compiler and standard library generally tries to ensure allocations - /// never reach a size where an offset is a concern. For instance, `Vec` - /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so - /// `vec.as_ptr().add(vec.len())` is always safe. - /// - /// Most platforms fundamentally can't even construct such an allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. + /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset + /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement. + /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always + /// safe. /// /// Consider using [`wrapping_offset`] instead if these constraints are /// difficult to satisfy. The only advantage of this method is that it @@ -611,8 +600,7 @@ impl<T: ?Sized> *const T { /// /// # Safety /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: + /// If any of the following conditions are violated, the result is Undefined Behavior: /// /// * `self` and `origin` must either /// @@ -623,26 +611,10 @@ impl<T: ?Sized> *const T { /// * The distance between the pointers, in bytes, must be an exact multiple /// of the size of `T`. /// - /// * The distance between the pointers, **in bytes**, cannot overflow an `isize`. - /// - /// * The distance being in bounds cannot rely on "wrapping around" the address space. - /// - /// Rust types are never larger than `isize::MAX` and Rust allocations never wrap around the - /// address space, so two pointers within some value of any Rust type `T` will always satisfy - /// the last two conditions. The standard library also generally ensures that allocations - /// never reach a size where an offset is a concern. For instance, `Vec` and `Box` ensure they - /// never allocate more than `isize::MAX` bytes, so `ptr_into_vec.offset_from(vec.as_ptr())` - /// always satisfies the last two conditions. - /// - /// Most platforms fundamentally can't even construct such a large allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. - /// (Note that [`offset`] and [`add`] also have a similar limitation and hence cannot be used on - /// such large allocations either.) + /// As a consequence, the absolute distance between the pointers, in bytes, computed on + /// mathematical integers (without "wrapping around"), cannot overflow an `isize`. This is + /// implied by the in-bounds requirement, and the fact that no allocated object can be larger + /// than `isize::MAX` bytes. /// /// The requirement for pointers to be derived from the same allocated object is primarily /// needed for `const`-compatibility: the distance between pointers into *different* allocated @@ -879,37 +851,26 @@ impl<T: ?Sized> *const T { } } - /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`). + /// Adds an offset to a pointer (convenience for `.offset(count as isize)`). /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::<T>()` bytes. /// /// # Safety /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: + /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting - /// pointer must be either in bounds or at the end of the same [allocated object]. - /// (If it is zero, then the function is always well-defined.) + /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`. /// - /// * The computed offset, **in bytes**, cannot overflow an `isize`. + /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some + /// [allocated object], and the entire memory range between `self` and the result must be in + /// bounds of that allocated object. In particular, this range must not "wrap around" the edge + /// of the address space. /// - /// * The offset being in bounds cannot rely on "wrapping around" the address - /// space. That is, the infinite-precision sum must fit in a `usize`. - /// - /// The compiler and standard library generally tries to ensure allocations - /// never reach a size where an offset is a concern. For instance, `Vec` - /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so - /// `vec.as_ptr().add(vec.len())` is always safe. - /// - /// Most platforms fundamentally can't even construct such an allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. + /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset + /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement. + /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always + /// safe. /// /// Consider using [`wrapping_add`] instead if these constraints are /// difficult to satisfy. The only advantage of this method is that it @@ -963,7 +924,7 @@ impl<T: ?Sized> *const T { unsafe { self.cast::<u8>().add(count).with_metadata_of(self) } } - /// Calculates the offset from a pointer (convenience for + /// Subtracts an offset from a pointer (convenience for /// `.offset((count as isize).wrapping_neg())`). /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer @@ -971,30 +932,19 @@ impl<T: ?Sized> *const T { /// /// # Safety /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: - /// - /// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting - /// pointer must be either in bounds or at the end of the same [allocated object]. - /// (If it is zero, then the function is always well-defined.) - /// - /// * The computed offset cannot exceed `isize::MAX` **bytes**. + /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * The offset being in bounds cannot rely on "wrapping around" the address - /// space. That is, the infinite-precision sum must fit in a usize. + /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`. /// - /// The compiler and standard library generally tries to ensure allocations - /// never reach a size where an offset is a concern. For instance, `Vec` - /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so - /// `vec.as_ptr().add(vec.len()).sub(vec.len())` is always safe. + /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some + /// [allocated object], and the entire memory range between `self` and the result must be in + /// bounds of that allocated object. In particular, this range must not "wrap around" the edge + /// of the address space. /// - /// Most platforms fundamentally can't even construct such an allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. + /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset + /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement. + /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always + /// safe. /// /// Consider using [`wrapping_sub`] instead if these constraints are /// difficult to satisfy. The only advantage of this method is that it diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 30d5b2cfc5a..0dc910db5b9 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -404,37 +404,26 @@ impl<T: ?Sized> *mut T { if self.is_null() { None } else { Some(unsafe { &*(self as *const MaybeUninit<T>) }) } } - /// Calculates the offset from a pointer. + /// Adds an offset to a pointer. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::<T>()` bytes. /// /// # Safety /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: + /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting - /// pointer must be either in bounds or at the end of the same [allocated object]. - /// (If it is zero, then the function is always well-defined.) + /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`. /// - /// * The computed offset, **in bytes**, cannot overflow an `isize`. + /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some + /// [allocated object], and the entire memory range between `self` and the result must be in + /// bounds of that allocated object. In particular, this range must not "wrap around" the edge + /// of the address space. /// - /// * The offset being in bounds cannot rely on "wrapping around" the address - /// space. That is, the infinite-precision sum, **in bytes** must fit in a usize. - /// - /// The compiler and standard library generally tries to ensure allocations - /// never reach a size where an offset is a concern. For instance, `Vec` - /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so - /// `vec.as_ptr().add(vec.len())` is always safe. - /// - /// Most platforms fundamentally can't even construct such an allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. + /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset + /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement. + /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always + /// safe. /// /// Consider using [`wrapping_offset`] instead if these constraints are /// difficult to satisfy. The only advantage of this method is that it @@ -836,8 +825,7 @@ impl<T: ?Sized> *mut T { /// /// # Safety /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: + /// If any of the following conditions are violated, the result is Undefined Behavior: /// /// * `self` and `origin` must either /// @@ -848,26 +836,10 @@ impl<T: ?Sized> *mut T { /// * The distance between the pointers, in bytes, must be an exact multiple /// of the size of `T`. /// - /// * The distance between the pointers, **in bytes**, cannot overflow an `isize`. - /// - /// * The distance being in bounds cannot rely on "wrapping around" the address space. - /// - /// Rust types are never larger than `isize::MAX` and Rust allocations never wrap around the - /// address space, so two pointers within some value of any Rust type `T` will always satisfy - /// the last two conditions. The standard library also generally ensures that allocations - /// never reach a size where an offset is a concern. For instance, `Vec` and `Box` ensure they - /// never allocate more than `isize::MAX` bytes, so `ptr_into_vec.offset_from(vec.as_ptr())` - /// always satisfies the last two conditions. - /// - /// Most platforms fundamentally can't even construct such a large allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. - /// (Note that [`offset`] and [`add`] also have a similar limitation and hence cannot be used on - /// such large allocations either.) + /// As a consequence, the absolute distance between the pointers, in bytes, computed on + /// mathematical integers (without "wrapping around"), cannot overflow an `isize`. This is + /// implied by the in-bounds requirement, and the fact that no allocated object can be larger + /// than `isize::MAX` bytes. /// /// The requirement for pointers to be derived from the same allocated object is primarily /// needed for `const`-compatibility: the distance between pointers into *different* allocated @@ -1020,37 +992,26 @@ impl<T: ?Sized> *mut T { unsafe { (self as *const T).sub_ptr(origin) } } - /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`). + /// Adds an offset to a pointer (convenience for `.offset(count as isize)`). /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::<T>()` bytes. /// /// # Safety /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: + /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting - /// pointer must be either in bounds or at the end of the same [allocated object]. - /// (If it is zero, then the function is always well-defined.) + /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`. /// - /// * The computed offset, **in bytes**, cannot overflow an `isize`. + /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some + /// [allocated object], and the entire memory range between `self` and the result must be in + /// bounds of that allocated object. In particular, this range must not "wrap around" the edge + /// of the address space. /// - /// * The offset being in bounds cannot rely on "wrapping around" the address - /// space. That is, the infinite-precision sum must fit in a `usize`. - /// - /// The compiler and standard library generally tries to ensure allocations - /// never reach a size where an offset is a concern. For instance, `Vec` - /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so - /// `vec.as_ptr().add(vec.len())` is always safe. - /// - /// Most platforms fundamentally can't even construct such an allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. + /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset + /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement. + /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always + /// safe. /// /// Consider using [`wrapping_add`] instead if these constraints are /// difficult to satisfy. The only advantage of this method is that it @@ -1104,7 +1065,7 @@ impl<T: ?Sized> *mut T { unsafe { self.cast::<u8>().add(count).with_metadata_of(self) } } - /// Calculates the offset from a pointer (convenience for + /// Subtracts an offset from a pointer (convenience for /// `.offset((count as isize).wrapping_neg())`). /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer @@ -1112,30 +1073,19 @@ impl<T: ?Sized> *mut T { /// /// # Safety /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: - /// - /// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting - /// pointer must be either in bounds or at the end of the same [allocated object]. - /// (If it is zero, then the function is always well-defined.) - /// - /// * The computed offset cannot exceed `isize::MAX` **bytes**. + /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * The offset being in bounds cannot rely on "wrapping around" the address - /// space. That is, the infinite-precision sum must fit in a usize. + /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`. /// - /// The compiler and standard library generally tries to ensure allocations - /// never reach a size where an offset is a concern. For instance, `Vec` - /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so - /// `vec.as_ptr().add(vec.len()).sub(vec.len())` is always safe. + /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some + /// [allocated object], and the entire memory range between `self` and the result must be in + /// bounds of that allocated object. In particular, this range must not "wrap around" the edge + /// of the address space. /// - /// Most platforms fundamentally can't even construct such an allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. + /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset + /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement. + /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always + /// safe. /// /// Consider using [`wrapping_sub`] instead if these constraints are /// difficult to satisfy. The only advantage of this method is that it diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 0504a0fc32f..75a99e14fda 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -476,36 +476,26 @@ impl<T: ?Sized> NonNull<T> { unsafe { NonNull { pointer: self.as_ptr() as *mut U } } } - /// Calculates the offset from a pointer. + /// Adds an offset to a pointer. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::<T>()` bytes. /// /// # Safety /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: + /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * Both the starting and resulting pointer must be either in bounds or one - /// byte past the end of the same [allocated object]. + /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`. /// - /// * The computed offset, **in bytes**, cannot overflow an `isize`. + /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some + /// [allocated object], and the entire memory range between `self` and the result must be in + /// bounds of that allocated object. In particular, this range must not "wrap around" the edge + /// of the address space. /// - /// * The offset being in bounds cannot rely on "wrapping around" the address - /// space. That is, the infinite-precision sum, **in bytes** must fit in a usize. - /// - /// The compiler and standard library generally tries to ensure allocations - /// never reach a size where an offset is a concern. For instance, `Vec` - /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so - /// `vec.as_ptr().add(vec.len())` is always safe. - /// - /// Most platforms fundamentally can't even construct such an allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. + /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset + /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement. + /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always + /// safe. /// /// [allocated object]: crate::ptr#allocated-object /// @@ -562,36 +552,26 @@ impl<T: ?Sized> NonNull<T> { unsafe { NonNull { pointer: self.pointer.byte_offset(count) } } } - /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`). + /// Adds an offset to a pointer (convenience for `.offset(count as isize)`). /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::<T>()` bytes. /// /// # Safety /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: - /// - /// * Both the starting and resulting pointer must be either in bounds or one - /// byte past the end of the same [allocated object]. + /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * The computed offset, **in bytes**, cannot overflow an `isize`. + /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`. /// - /// * The offset being in bounds cannot rely on "wrapping around" the address - /// space. That is, the infinite-precision sum must fit in a `usize`. + /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some + /// [allocated object], and the entire memory range between `self` and the result must be in + /// bounds of that allocated object. In particular, this range must not "wrap around" the edge + /// of the address space. /// - /// The compiler and standard library generally tries to ensure allocations - /// never reach a size where an offset is a concern. For instance, `Vec` - /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so - /// `vec.as_ptr().add(vec.len())` is always safe. - /// - /// Most platforms fundamentally can't even construct such an allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. + /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset + /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement. + /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always + /// safe. /// /// [allocated object]: crate::ptr#allocated-object /// @@ -649,7 +629,7 @@ impl<T: ?Sized> NonNull<T> { unsafe { NonNull { pointer: self.pointer.byte_add(count) } } } - /// Calculates the offset from a pointer (convenience for + /// Subtracts an offset from a pointer (convenience for /// `.offset((count as isize).wrapping_neg())`). /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer @@ -657,29 +637,19 @@ impl<T: ?Sized> NonNull<T> { /// /// # Safety /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: - /// - /// * Both the starting and resulting pointer must be either in bounds or one - /// byte past the end of the same [allocated object]. - /// - /// * The computed offset cannot exceed `isize::MAX` **bytes**. + /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * The offset being in bounds cannot rely on "wrapping around" the address - /// space. That is, the infinite-precision sum must fit in a usize. + /// * The computed offset, `count * size_of::<T>()` bytes, must not overflow `isize`. /// - /// The compiler and standard library generally tries to ensure allocations - /// never reach a size where an offset is a concern. For instance, `Vec` - /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so - /// `vec.as_ptr().add(vec.len()).sub(vec.len())` is always safe. + /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some + /// [allocated object], and the entire memory range between `self` and the result must be in + /// bounds of that allocated object. In particular, this range must not "wrap around" the edge + /// of the address space. /// - /// Most platforms fundamentally can't even construct such an allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. + /// Allocated objects can never be larger than `isize::MAX` bytes, so if the computed offset + /// stays in bounds of the allocated object, it is guaranteed to satisfy the first requirement. + /// This implies, for instance, that `vec.as_ptr().add(vec.len())` (for `vec: Vec<T>`) is always + /// safe. /// /// [allocated object]: crate::ptr#allocated-object /// @@ -761,38 +731,21 @@ impl<T: ?Sized> NonNull<T> { /// /// # Safety /// - /// If any of the following conditions are violated, the result is Undefined - /// Behavior: + /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * Both `self` and `origin` must be either in bounds or one - /// byte past the end of the same [allocated object]. + /// * `self` and `origin` must either /// - /// * Both pointers must be *derived from* a pointer to the same object. - /// (See below for an example.) + /// * both be *derived from* a pointer to the same [allocated object], and the memory range between + /// the two pointers must be either empty or in bounds of that object. (See below for an example.) + /// * or both be derived from an integer literal/constant, and point to the same address. /// /// * The distance between the pointers, in bytes, must be an exact multiple /// of the size of `T`. /// - /// * The distance between the pointers, **in bytes**, cannot overflow an `isize`. - /// - /// * The distance being in bounds cannot rely on "wrapping around" the address space. - /// - /// Rust types are never larger than `isize::MAX` and Rust allocations never wrap around the - /// address space, so two pointers within some value of any Rust type `T` will always satisfy - /// the last two conditions. The standard library also generally ensures that allocations - /// never reach a size where an offset is a concern. For instance, `Vec` and `Box` ensure they - /// never allocate more than `isize::MAX` bytes, so `ptr_into_vec.offset_from(vec.as_ptr())` - /// always satisfies the last two conditions. - /// - /// Most platforms fundamentally can't even construct such a large allocation. - /// For instance, no known 64-bit platform can ever serve a request - /// for 2<sup>63</sup> bytes due to page-table limitations or splitting the address space. - /// However, some 32-bit and 16-bit platforms may successfully serve a request for - /// more than `isize::MAX` bytes with things like Physical Address - /// Extension. As such, memory acquired directly from allocators or memory - /// mapped files *may* be too large to handle with this function. - /// (Note that [`offset`] and [`add`] also have a similar limitation and hence cannot be used on - /// such large allocations either.) + /// As a consequence, the absolute distance between the pointers, in bytes, computed on + /// mathematical integers (without "wrapping around"), cannot overflow an `isize`. This is + /// implied by the in-bounds requirement, and the fact that no allocated object can be larger + /// than `isize::MAX` bytes. /// /// The requirement for pointers to be derived from the same allocated object is primarily /// needed for `const`-compatibility: the distance between pointers into *different* allocated diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 8d565e26a16..d5121a554bf 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -3192,15 +3192,19 @@ impl Hash for Path { let bytes = &bytes[prefix_len..]; let mut component_start = 0; - let mut bytes_hashed = 0; + // track some extra state to avoid prefix collisions. + // ["foo", "bar"] and ["foobar"], will have the same payload bytes + // but result in different chunk_bits + let mut chunk_bits: usize = 0; for i in 0..bytes.len() { let is_sep = if verbatim { is_verbatim_sep(bytes[i]) } else { is_sep_byte(bytes[i]) }; if is_sep { if i > component_start { let to_hash = &bytes[component_start..i]; + chunk_bits = chunk_bits.wrapping_add(to_hash.len()); + chunk_bits = chunk_bits.rotate_right(2); h.write(to_hash); - bytes_hashed += to_hash.len(); } // skip over separator and optionally a following CurDir item @@ -3221,11 +3225,12 @@ impl Hash for Path { if component_start < bytes.len() { let to_hash = &bytes[component_start..]; + chunk_bits = chunk_bits.wrapping_add(to_hash.len()); + chunk_bits = chunk_bits.rotate_right(2); h.write(to_hash); - bytes_hashed += to_hash.len(); } - h.write_usize(bytes_hashed); + h.write_usize(chunk_bits); } } diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs index bb6126e4941..3ade4fb892f 100644 --- a/library/std/src/path/tests.rs +++ b/library/std/src/path/tests.rs @@ -1619,6 +1619,20 @@ pub fn test_compare() { relative_from: Some("") ); + tc!("foo//", "foo", + eq: true, + starts_with: true, + ends_with: true, + relative_from: Some("") + ); + + tc!("foo///", "foo", + eq: true, + starts_with: true, + ends_with: true, + relative_from: Some("") + ); + tc!("foo/.", "foo", eq: true, starts_with: true, @@ -1633,6 +1647,20 @@ pub fn test_compare() { relative_from: Some("") ); + tc!("foo/.//bar", "foo/bar", + eq: true, + starts_with: true, + ends_with: true, + relative_from: Some("") + ); + + tc!("foo//./bar", "foo/bar", + eq: true, + starts_with: true, + ends_with: true, + relative_from: Some("") + ); + tc!("foo/bar", "foo", eq: false, starts_with: true, @@ -1640,6 +1668,13 @@ pub fn test_compare() { relative_from: Some("bar") ); + tc!("foo/bar", "foobar", + eq: false, + starts_with: false, + ends_with: false, + relative_from: None + ); + tc!("foo/bar/baz", "foo/bar", eq: false, starts_with: true, diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs index f52b9e52c54..fe243550606 100644 --- a/library/std/src/sync/once_lock.rs +++ b/library/std/src/sync/once_lock.rs @@ -80,14 +80,21 @@ use crate::sync::Once; /// static LIST: OnceList<u32> = OnceList::new(); /// static COUNTER: AtomicU32 = AtomicU32::new(0); /// -/// let vec = (0..thread::available_parallelism().unwrap().get()).map(|_| thread::spawn(|| { -/// while let i @ 0..=1000 = COUNTER.fetch_add(1, Ordering::Relaxed) { -/// LIST.push(i); +/// # const LEN: u32 = if cfg!(miri) { 50 } else { 1000 }; +/// # /* +/// const LEN: u32 = 1000; +/// # */ +/// thread::scope(|s| { +/// for _ in 0..thread::available_parallelism().unwrap().get() { +/// s.spawn(|| { +/// while let i @ 0..LEN = COUNTER.fetch_add(1, Ordering::Relaxed) { +/// LIST.push(i); +/// } +/// }); /// } -/// })).collect::<Vec<thread::JoinHandle<_>>>(); -/// vec.into_iter().for_each(|handle| handle.join().unwrap()); +/// }); /// -/// for i in 0..=1000 { +/// for i in 0..LEN { /// assert!(LIST.contains(&i)); /// } /// diff --git a/src/bootstrap/src/core/build_steps/clean.rs b/src/bootstrap/src/core/build_steps/clean.rs index 479af4af666..a4be6bc56c5 100644 --- a/src/bootstrap/src/core/build_steps/clean.rs +++ b/src/bootstrap/src/core/build_steps/clean.rs @@ -85,7 +85,7 @@ macro_rules! clean_crate_tree { // NOTE: doesn't use `run_cargo` because we don't want to save a stamp file, // and doesn't use `stream_cargo` to avoid passing `--message-format` which `clean` doesn't accept. - builder.run(cargo); + cargo.run(builder); } } )+ } diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 01b25224de4..11a7a404535 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -27,7 +27,7 @@ use crate::core::builder::crate_description; use crate::core::builder::Cargo; use crate::core::builder::{Builder, Kind, PathSet, RunConfig, ShouldRun, Step, TaskPath}; use crate::core::config::{DebuginfoLevel, LlvmLibunwind, RustcLto, TargetSelection}; -use crate::utils::exec::BootstrapCommand; +use crate::utils::exec::command; use crate::utils::helpers::{ exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, symlink_dir, t, up_to_date, }; @@ -773,20 +773,19 @@ impl Step for StartupObjects { let src_file = &src_dir.join(file.to_string() + ".rs"); let dst_file = &dst_dir.join(file.to_string() + ".o"); if !up_to_date(src_file, dst_file) { - let mut cmd = BootstrapCommand::new(&builder.initial_rustc); + let mut cmd = command(&builder.initial_rustc); cmd.env("RUSTC_BOOTSTRAP", "1"); if !builder.local_rebuild { // a local_rebuild compiler already has stage1 features cmd.arg("--cfg").arg("bootstrap"); } - builder.run( - cmd.arg("--target") - .arg(target.rustc_target_arg()) - .arg("--emit=obj") - .arg("-o") - .arg(dst_file) - .arg(src_file), - ); + cmd.arg("--target") + .arg(target.rustc_target_arg()) + .arg("--emit=obj") + .arg("-o") + .arg(dst_file) + .arg(src_file) + .run(builder); } let target = sysroot_dir.join((*file).to_string() + ".o"); @@ -1488,10 +1487,10 @@ pub fn compiler_file( if builder.config.dry_run() { return PathBuf::new(); } - let mut cmd = BootstrapCommand::new(compiler); + let mut cmd = command(compiler); cmd.args(builder.cflags(target, GitRepo::Rustc, c)); cmd.arg(format!("-print-file-name={file}")); - let out = builder.run(cmd.capture_stdout()).stdout(); + let out = cmd.capture_stdout().run(builder).stdout(); PathBuf::from(out.trim()) } @@ -1836,9 +1835,8 @@ impl Step for Assemble { let llvm::LlvmResult { llvm_config, .. } = builder.ensure(llvm::Llvm { target: target_compiler.host }); if !builder.config.dry_run() && builder.config.llvm_tools_enabled { - let llvm_bin_dir = builder - .run(BootstrapCommand::new(llvm_config).capture_stdout().arg("--bindir")) - .stdout(); + let llvm_bin_dir = + command(llvm_config).capture_stdout().arg("--bindir").run(builder).stdout(); let llvm_bin_dir = Path::new(llvm_bin_dir.trim()); // Since we've already built the LLVM tools, install them to the sysroot. @@ -2163,7 +2161,7 @@ pub fn strip_debug(builder: &Builder<'_>, target: TargetSelection, path: &Path) } let previous_mtime = FileTime::from_last_modification_time(&path.metadata().unwrap()); - builder.run(BootstrapCommand::new("strip").capture().arg("--strip-debug").arg(path)); + command("strip").capture().arg("--strip-debug").arg(path).run(builder); // After running `strip`, we have to set the file modification time to what it was before, // otherwise we risk Cargo invalidating its fingerprint and rebuilding the world next time diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 3dc871b1ca9..7bc5405e92f 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -25,7 +25,7 @@ use crate::core::build_steps::tool::{self, Tool}; use crate::core::builder::{Builder, Kind, RunConfig, ShouldRun, Step}; use crate::core::config::TargetSelection; use crate::utils::channel::{self, Info}; -use crate::utils::exec::BootstrapCommand; +use crate::utils::exec::{command, BootstrapCommand}; use crate::utils::helpers::{ exe, is_dylib, move_file, t, target_supports_cranelift_backend, timeit, }; @@ -180,9 +180,9 @@ fn make_win_dist( } //Ask gcc where it keeps its stuff - let mut cmd = BootstrapCommand::new(builder.cc(target)); + let mut cmd = command(builder.cc(target)); cmd.arg("-print-search-dirs"); - let gcc_out = builder.run(cmd.capture_stdout()).stdout(); + let gcc_out = cmd.capture_stdout().run(builder).stdout(); let mut bin_path: Vec<_> = env::split_paths(&env::var_os("PATH").unwrap_or_default()).collect(); let mut lib_path = Vec::new(); @@ -1023,7 +1023,7 @@ impl Step for PlainSourceTarball { } // Vendor all Cargo dependencies - let mut cmd = BootstrapCommand::new(&builder.initial_cargo); + let mut cmd = command(&builder.initial_cargo); cmd.arg("vendor") .arg("--versioned-dirs") .arg("--sync") @@ -1061,7 +1061,7 @@ impl Step for PlainSourceTarball { } let config = if !builder.config.dry_run() { - builder.run(cmd.capture()).stdout() + cmd.capture().run(builder).stdout() } else { String::new() }; @@ -1599,14 +1599,14 @@ impl Step for Extended { let _ = fs::remove_dir_all(&pkg); let pkgbuild = |component: &str| { - let mut cmd = BootstrapCommand::new("pkgbuild"); + let mut cmd = command("pkgbuild"); cmd.arg("--identifier") .arg(format!("org.rust-lang.{}", component)) .arg("--scripts") .arg(pkg.join(component)) .arg("--nopayload") .arg(pkg.join(component).with_extension("pkg")); - builder.run(cmd); + cmd.run(builder); }; let prepare = |name: &str| { @@ -1636,7 +1636,7 @@ impl Step for Extended { builder.create_dir(&pkg.join("res")); builder.create(&pkg.join("res/LICENSE.txt"), &license); builder.install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), 0o644); - let mut cmd = BootstrapCommand::new("productbuild"); + let mut cmd = command("productbuild"); cmd.arg("--distribution") .arg(xform(&etc.join("pkg/Distribution.xml"))) .arg("--resources") @@ -1649,7 +1649,7 @@ impl Step for Extended { .arg("--package-path") .arg(&pkg); let _time = timeit(builder); - builder.run(cmd); + cmd.run(builder); } if target.is_windows() { @@ -1703,168 +1703,159 @@ impl Step for Extended { let light = wix.join("bin/light.exe"); let heat_flags = ["-nologo", "-gg", "-sfrag", "-srd", "-sreg"]; - builder.run( - BootstrapCommand::new(&heat) + command(&heat) + .current_dir(&exe) + .arg("dir") + .arg("rustc") + .args(heat_flags) + .arg("-cg") + .arg("RustcGroup") + .arg("-dr") + .arg("Rustc") + .arg("-var") + .arg("var.RustcDir") + .arg("-out") + .arg(exe.join("RustcGroup.wxs")) + .run(builder); + if built_tools.contains("rust-docs") { + command(&heat) .current_dir(&exe) .arg("dir") - .arg("rustc") + .arg("rust-docs") .args(heat_flags) .arg("-cg") - .arg("RustcGroup") + .arg("DocsGroup") .arg("-dr") - .arg("Rustc") + .arg("Docs") .arg("-var") - .arg("var.RustcDir") + .arg("var.DocsDir") .arg("-out") - .arg(exe.join("RustcGroup.wxs")), - ); - if built_tools.contains("rust-docs") { - builder.run( - BootstrapCommand::new(&heat) - .current_dir(&exe) - .arg("dir") - .arg("rust-docs") - .args(heat_flags) - .arg("-cg") - .arg("DocsGroup") - .arg("-dr") - .arg("Docs") - .arg("-var") - .arg("var.DocsDir") - .arg("-out") - .arg(exe.join("DocsGroup.wxs")) - .arg("-t") - .arg(etc.join("msi/squash-components.xsl")), - ); + .arg(exe.join("DocsGroup.wxs")) + .arg("-t") + .arg(etc.join("msi/squash-components.xsl")) + .run(builder); } - builder.run( - BootstrapCommand::new(&heat) + command(&heat) + .current_dir(&exe) + .arg("dir") + .arg("cargo") + .args(heat_flags) + .arg("-cg") + .arg("CargoGroup") + .arg("-dr") + .arg("Cargo") + .arg("-var") + .arg("var.CargoDir") + .arg("-out") + .arg(exe.join("CargoGroup.wxs")) + .arg("-t") + .arg(etc.join("msi/remove-duplicates.xsl")) + .run(builder); + command(&heat) + .current_dir(&exe) + .arg("dir") + .arg("rust-std") + .args(heat_flags) + .arg("-cg") + .arg("StdGroup") + .arg("-dr") + .arg("Std") + .arg("-var") + .arg("var.StdDir") + .arg("-out") + .arg(exe.join("StdGroup.wxs")) + .run(builder); + if built_tools.contains("rust-analyzer") { + command(&heat) .current_dir(&exe) .arg("dir") - .arg("cargo") + .arg("rust-analyzer") .args(heat_flags) .arg("-cg") - .arg("CargoGroup") + .arg("RustAnalyzerGroup") .arg("-dr") - .arg("Cargo") + .arg("RustAnalyzer") .arg("-var") - .arg("var.CargoDir") + .arg("var.RustAnalyzerDir") .arg("-out") - .arg(exe.join("CargoGroup.wxs")) + .arg(exe.join("RustAnalyzerGroup.wxs")) .arg("-t") - .arg(etc.join("msi/remove-duplicates.xsl")), - ); - builder.run( - BootstrapCommand::new(&heat) + .arg(etc.join("msi/remove-duplicates.xsl")) + .run(builder); + } + if built_tools.contains("clippy") { + command(&heat) .current_dir(&exe) .arg("dir") - .arg("rust-std") + .arg("clippy") .args(heat_flags) .arg("-cg") - .arg("StdGroup") + .arg("ClippyGroup") .arg("-dr") - .arg("Std") + .arg("Clippy") .arg("-var") - .arg("var.StdDir") + .arg("var.ClippyDir") .arg("-out") - .arg(exe.join("StdGroup.wxs")), - ); - if built_tools.contains("rust-analyzer") { - builder.run( - BootstrapCommand::new(&heat) - .current_dir(&exe) - .arg("dir") - .arg("rust-analyzer") - .args(heat_flags) - .arg("-cg") - .arg("RustAnalyzerGroup") - .arg("-dr") - .arg("RustAnalyzer") - .arg("-var") - .arg("var.RustAnalyzerDir") - .arg("-out") - .arg(exe.join("RustAnalyzerGroup.wxs")) - .arg("-t") - .arg(etc.join("msi/remove-duplicates.xsl")), - ); - } - if built_tools.contains("clippy") { - builder.run( - BootstrapCommand::new(&heat) - .current_dir(&exe) - .arg("dir") - .arg("clippy") - .args(heat_flags) - .arg("-cg") - .arg("ClippyGroup") - .arg("-dr") - .arg("Clippy") - .arg("-var") - .arg("var.ClippyDir") - .arg("-out") - .arg(exe.join("ClippyGroup.wxs")) - .arg("-t") - .arg(etc.join("msi/remove-duplicates.xsl")), - ); + .arg(exe.join("ClippyGroup.wxs")) + .arg("-t") + .arg(etc.join("msi/remove-duplicates.xsl")) + .run(builder); } if built_tools.contains("miri") { - builder.run( - BootstrapCommand::new(&heat) - .current_dir(&exe) - .arg("dir") - .arg("miri") - .args(heat_flags) - .arg("-cg") - .arg("MiriGroup") - .arg("-dr") - .arg("Miri") - .arg("-var") - .arg("var.MiriDir") - .arg("-out") - .arg(exe.join("MiriGroup.wxs")) - .arg("-t") - .arg(etc.join("msi/remove-duplicates.xsl")), - ); - } - builder.run( - BootstrapCommand::new(&heat) + command(&heat) .current_dir(&exe) .arg("dir") - .arg("rust-analysis") + .arg("miri") .args(heat_flags) .arg("-cg") - .arg("AnalysisGroup") + .arg("MiriGroup") .arg("-dr") - .arg("Analysis") + .arg("Miri") .arg("-var") - .arg("var.AnalysisDir") + .arg("var.MiriDir") .arg("-out") - .arg(exe.join("AnalysisGroup.wxs")) + .arg(exe.join("MiriGroup.wxs")) .arg("-t") - .arg(etc.join("msi/remove-duplicates.xsl")), - ); + .arg(etc.join("msi/remove-duplicates.xsl")) + .run(builder); + } + command(&heat) + .current_dir(&exe) + .arg("dir") + .arg("rust-analysis") + .args(heat_flags) + .arg("-cg") + .arg("AnalysisGroup") + .arg("-dr") + .arg("Analysis") + .arg("-var") + .arg("var.AnalysisDir") + .arg("-out") + .arg(exe.join("AnalysisGroup.wxs")) + .arg("-t") + .arg(etc.join("msi/remove-duplicates.xsl")) + .run(builder); if target.ends_with("windows-gnu") { - builder.run( - BootstrapCommand::new(&heat) - .current_dir(&exe) - .arg("dir") - .arg("rust-mingw") - .args(heat_flags) - .arg("-cg") - .arg("GccGroup") - .arg("-dr") - .arg("Gcc") - .arg("-var") - .arg("var.GccDir") - .arg("-out") - .arg(exe.join("GccGroup.wxs")), - ); + command(&heat) + .current_dir(&exe) + .arg("dir") + .arg("rust-mingw") + .args(heat_flags) + .arg("-cg") + .arg("GccGroup") + .arg("-dr") + .arg("Gcc") + .arg("-var") + .arg("var.GccDir") + .arg("-out") + .arg(exe.join("GccGroup.wxs")) + .run(builder); } let candle = |input: &Path| { let output = exe.join(input.file_stem().unwrap()).with_extension("wixobj"); let arch = if target.contains("x86_64") { "x64" } else { "x86" }; - let mut cmd = BootstrapCommand::new(&candle); + let mut cmd = command(&candle); cmd.current_dir(&exe) .arg("-nologo") .arg("-dRustcDir=rustc") @@ -1893,7 +1884,7 @@ impl Step for Extended { if target.ends_with("windows-gnu") { cmd.arg("-dGccDir=rust-mingw"); } - builder.run(cmd); + cmd.run(builder); }; candle(&xform(&etc.join("msi/rust.wxs"))); candle(&etc.join("msi/ui.wxs")); @@ -1925,7 +1916,7 @@ impl Step for Extended { builder.info(&format!("building `msi` installer with {light:?}")); let filename = format!("{}-{}.msi", pkgname(builder, "rust"), target.triple); - let mut cmd = BootstrapCommand::new(&light); + let mut cmd = command(&light); cmd.arg("-nologo") .arg("-ext") .arg("WixUIExtension") @@ -1962,7 +1953,7 @@ impl Step for Extended { cmd.arg("-sice:ICE57"); let _time = timeit(builder); - builder.run(cmd); + cmd.run(builder); if !builder.config.dry_run() { t!(move_file(exe.join(&filename), distdir(builder).join(&filename))); @@ -2078,13 +2069,13 @@ fn maybe_install_llvm( } else if let llvm::LlvmBuildStatus::AlreadyBuilt(llvm::LlvmResult { llvm_config, .. }) = llvm::prebuilt_llvm_config(builder, target) { - let mut cmd = BootstrapCommand::new(llvm_config); + let mut cmd = command(llvm_config); cmd.arg("--libfiles"); builder.verbose(|| println!("running {cmd:?}")); let files = if builder.config.dry_run() { "".into() } else { - builder.run(cmd.capture_stdout()).stdout() + cmd.capture_stdout().run(builder).stdout() }; let build_llvm_out = &builder.llvm_out(builder.config.build); let target_llvm_out = &builder.llvm_out(target); diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 823e842693e..4b35d6c5d4c 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -154,7 +154,7 @@ impl<P: Step> Step for RustbookSrc<P> { builder.info(&format!("Rustbook ({target}) - {name}")); let _ = fs::remove_dir_all(&out); - builder.run(rustbook_cmd.arg("build").arg(&src).arg("-d").arg(&out)); + rustbook_cmd.arg("build").arg(&src).arg("-d").arg(&out).run(builder); for lang in &self.languages { let out = out.join(lang); @@ -162,10 +162,15 @@ impl<P: Step> Step for RustbookSrc<P> { builder.info(&format!("Rustbook ({target}) - {name} - {lang}")); let _ = fs::remove_dir_all(&out); - let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook); - builder.run( - rustbook_cmd.arg("build").arg(&src).arg("-d").arg(&out).arg("-l").arg(lang), - ); + builder + .tool_cmd(Tool::Rustbook) + .arg("build") + .arg(&src) + .arg("-d") + .arg(&out) + .arg("-l") + .arg(lang) + .run(builder); } } @@ -301,7 +306,7 @@ fn invoke_rustdoc( cmd.arg("-Z").arg("unstable-options").arg("--disable-minification"); } - builder.run(cmd); + cmd.run(builder); } #[derive(Debug, Clone, Hash, PartialEq, Eq)] @@ -395,7 +400,7 @@ impl Step for Standalone { } else { cmd.arg("--markdown-css").arg("rust.css"); } - builder.run(cmd); + cmd.run(builder); } // We open doc/index.html as the default if invoked as `x.py doc --open` @@ -494,7 +499,7 @@ impl Step for Releases { cmd.arg("--disable-minification"); } - builder.run(cmd); + cmd.run(builder); } // We open doc/RELEASES.html as the default if invoked as `x.py doc --open RELEASES.md` @@ -738,7 +743,7 @@ fn doc_std( format!("library{} in {} format", crate_description(requested_crates), format.as_str()); let _guard = builder.msg_doc(compiler, description, target); - builder.run(cargo.into_cmd()); + cargo.into_cmd().run(builder); builder.cp_link_r(&out_dir, out); } @@ -863,7 +868,7 @@ impl Step for Rustc { let proc_macro_out_dir = builder.stage_out(compiler, Mode::Rustc).join("doc"); symlink_dir_force(&builder.config, &out, &proc_macro_out_dir); - builder.run(cargo.into_cmd()); + cargo.into_cmd().run(builder); if !builder.config.dry_run() { // Sanity check on linked compiler crates @@ -996,7 +1001,7 @@ macro_rules! tool_doc { symlink_dir_force(&builder.config, &out, &proc_macro_out_dir); let _guard = builder.msg_doc(compiler, stringify!($tool).to_lowercase(), target); - builder.run(cargo.into_cmd()); + cargo.into_cmd().run(builder); if !builder.config.dry_run() { // Sanity check on linked doc directories @@ -1075,12 +1080,7 @@ impl Step for ErrorIndex { builder.info(&format!("Documenting error index ({})", self.target)); let out = builder.doc_out(self.target); t!(fs::create_dir_all(&out)); - let mut index = tool::ErrorIndex::command(builder); - index.arg("html"); - index.arg(out); - index.arg(&builder.version); - - builder.run(index); + tool::ErrorIndex::command(builder).arg("html").arg(out).arg(&builder.version).run(builder); } } @@ -1116,7 +1116,7 @@ impl Step for UnstableBookGen { cmd.arg(builder.src.join("src")); cmd.arg(out); - builder.run(cmd); + cmd.run(builder); } } @@ -1211,7 +1211,7 @@ impl Step for RustcBook { self.compiler.host, self.target, ); - builder.run(cmd); + cmd.run(builder); drop(doc_generator_guard); // Run rustbook/mdbook to generate the HTML pages. diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index 66286a52813..d3ac2bae1e8 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -1,7 +1,7 @@ //! Runs rustfmt on the repository. use crate::core::builder::Builder; -use crate::utils::exec::BootstrapCommand; +use crate::utils::exec::command; use crate::utils::helpers::{self, program_out_of_date, t}; use build_helper::ci::CiEnv; use build_helper::git::get_git_modified_files; @@ -54,13 +54,13 @@ fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl F fn get_rustfmt_version(build: &Builder<'_>) -> Option<(String, PathBuf)> { let stamp_file = build.out.join("rustfmt.stamp"); - let mut cmd = BootstrapCommand::new(match build.initial_rustfmt() { + let mut cmd = command(match build.initial_rustfmt() { Some(p) => p, None => return None, }); cmd.arg("--version"); - let output = build.run(cmd.capture().allow_failure()); + let output = cmd.capture().allow_failure().run(build); if output.is_failure() { return None; } @@ -160,29 +160,25 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) { } } let git_available = - build.run(helpers::git(None).capture().allow_failure().arg("--version")).is_success(); + helpers::git(None).capture().allow_failure().arg("--version").run(build).is_success(); let mut adjective = None; if git_available { - let in_working_tree = build - .run( - helpers::git(Some(&build.src)) - .capture() - .allow_failure() - .arg("rev-parse") - .arg("--is-inside-work-tree"), - ) + let in_working_tree = helpers::git(Some(&build.src)) + .capture() + .allow_failure() + .arg("rev-parse") + .arg("--is-inside-work-tree") + .run(build) .is_success(); if in_working_tree { - let untracked_paths_output = build - .run( - helpers::git(Some(&build.src)) - .capture_stdout() - .arg("status") - .arg("--porcelain") - .arg("-z") - .arg("--untracked-files=normal"), - ) + let untracked_paths_output = helpers::git(Some(&build.src)) + .capture_stdout() + .arg("status") + .arg("--porcelain") + .arg("-z") + .arg("--untracked-files=normal") + .run(build) .stdout(); let untracked_paths: Vec<_> = untracked_paths_output .split_terminator('\0') diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs index 7ee1aca2abc..d3e9d6d7875 100644 --- a/src/bootstrap/src/core/build_steps/install.rs +++ b/src/bootstrap/src/core/build_steps/install.rs @@ -10,7 +10,7 @@ use std::path::{Component, Path, PathBuf}; use crate::core::build_steps::dist; use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::core::config::{Config, TargetSelection}; -use crate::utils::exec::BootstrapCommand; +use crate::utils::exec::command; use crate::utils::helpers::t; use crate::utils::tarball::GeneratedTarball; use crate::{Compiler, Kind}; @@ -102,7 +102,7 @@ fn install_sh( let empty_dir = builder.out.join("tmp/empty_dir"); t!(fs::create_dir_all(&empty_dir)); - let mut cmd = BootstrapCommand::new(SHELL); + let mut cmd = command(SHELL); cmd.current_dir(&empty_dir) .arg(sanitize_sh(&tarball.decompressed_output().join("install.sh"))) .arg(format!("--prefix={}", prepare_dir(&destdir_env, prefix))) @@ -113,7 +113,7 @@ fn install_sh( .arg(format!("--libdir={}", prepare_dir(&destdir_env, libdir))) .arg(format!("--mandir={}", prepare_dir(&destdir_env, mandir))) .arg("--disable-ldconfig"); - builder.run(cmd); + cmd.run(builder); t!(fs::remove_dir_all(&empty_dir)); } diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 4f1c1f87d1c..bff731e13b0 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -24,7 +24,7 @@ use crate::utils::helpers::{ }; use crate::{generate_smart_stamp_hash, CLang, GitRepo, Kind}; -use crate::utils::exec::BootstrapCommand; +use crate::utils::exec::command; use build_helper::ci::CiEnv; use build_helper::git::get_git_merge_base; @@ -478,9 +478,8 @@ impl Step for Llvm { let LlvmResult { llvm_config, .. } = builder.ensure(Llvm { target: builder.config.build }); if !builder.config.dry_run() { - let llvm_bindir = builder - .run(BootstrapCommand::new(&llvm_config).capture_stdout().arg("--bindir")) - .stdout(); + let llvm_bindir = + command(&llvm_config).capture_stdout().arg("--bindir").run(builder).stdout(); let host_bin = Path::new(llvm_bindir.trim()); cfg.define( "LLVM_TABLEGEN", @@ -530,8 +529,8 @@ impl Step for Llvm { // Helper to find the name of LLVM's shared library on darwin and linux. let find_llvm_lib_name = |extension| { - let cmd = BootstrapCommand::new(&res.llvm_config); - let version = builder.run(cmd.capture_stdout().arg("--version")).stdout(); + let version = + command(&res.llvm_config).capture_stdout().arg("--version").run(builder).stdout(); let major = version.split('.').next().unwrap(); match &llvm_version_suffix { @@ -587,8 +586,7 @@ fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) { return; } - let cmd = BootstrapCommand::new(llvm_config); - let version = builder.run(cmd.capture_stdout().arg("--version")).stdout(); + let version = command(llvm_config).capture_stdout().arg("--version").run(builder).stdout(); let mut parts = version.split('.').take(2).filter_map(|s| s.parse::<u32>().ok()); if let (Some(major), Some(_minor)) = (parts.next(), parts.next()) { if major >= 17 { diff --git a/src/bootstrap/src/core/build_steps/perf.rs b/src/bootstrap/src/core/build_steps/perf.rs index f41b5fe10f1..5b83080a326 100644 --- a/src/bootstrap/src/core/build_steps/perf.rs +++ b/src/bootstrap/src/core/build_steps/perf.rs @@ -31,5 +31,5 @@ Consider setting `rust.debuginfo-level = 1` in `config.toml`."#); .env("PERF_COLLECTOR", collector) .env("PERF_RESULT_DIR", profile_results_dir) .args(args); - builder.run(&mut cmd); + cmd.run(builder); } diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index 316a03a2171..3a2d3f67522 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -11,7 +11,7 @@ use crate::core::build_steps::tool::{self, SourceType, Tool}; use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::core::config::flags::get_completion; use crate::core::config::TargetSelection; -use crate::utils::exec::BootstrapCommand; +use crate::utils::exec::command; use crate::Mode; #[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] @@ -40,8 +40,7 @@ impl Step for BuildManifest { panic!("\n\nfailed to specify `dist.upload-addr` in `config.toml`\n\n") }); - let today = - builder.run(BootstrapCommand::new("date").capture_stdout().arg("+%Y-%m-%d")).stdout(); + let today = command("date").capture_stdout().arg("+%Y-%m-%d").run(builder).stdout(); cmd.arg(sign); cmd.arg(distdir(builder)); @@ -50,7 +49,7 @@ impl Step for BuildManifest { cmd.arg(&builder.config.channel); builder.create_dir(&distdir(builder)); - builder.run(cmd); + cmd.run(builder); } } @@ -72,7 +71,7 @@ impl Step for BumpStage0 { fn run(self, builder: &Builder<'_>) -> Self::Output { let mut cmd = builder.tool_cmd(Tool::BumpStage0); cmd.args(builder.config.args()); - builder.run(cmd); + cmd.run(builder); } } @@ -94,7 +93,7 @@ impl Step for ReplaceVersionPlaceholder { fn run(self, builder: &Builder<'_>) -> Self::Output { let mut cmd = builder.tool_cmd(Tool::ReplaceVersionPlaceholder); cmd.arg(&builder.src); - builder.run(cmd); + cmd.run(builder); } } @@ -158,7 +157,7 @@ impl Step for Miri { // after another --, so this must be at the end. miri.args(builder.config.args()); - builder.run(miri.into_cmd()); + miri.into_cmd().run(builder); } } @@ -188,7 +187,7 @@ impl Step for CollectLicenseMetadata { let mut cmd = builder.tool_cmd(Tool::CollectLicenseMetadata); cmd.env("REUSE_EXE", reuse); cmd.env("DEST", &dest); - builder.run(cmd); + cmd.run(builder); dest } @@ -218,7 +217,7 @@ impl Step for GenerateCopyright { let mut cmd = builder.tool_cmd(Tool::GenerateCopyright); cmd.env("LICENSE_METADATA", &license_metadata); cmd.env("DEST", &dest); - builder.run(cmd); + cmd.run(builder); dest } @@ -242,7 +241,7 @@ impl Step for GenerateWindowsSys { fn run(self, builder: &Builder<'_>) { let mut cmd = builder.tool_cmd(Tool::GenerateWindowsSys); cmd.arg(&builder.src); - builder.run(cmd); + cmd.run(builder); } } diff --git a/src/bootstrap/src/core/build_steps/suggest.rs b/src/bootstrap/src/core/build_steps/suggest.rs index 5412b3c807b..2d4409d27c6 100644 --- a/src/bootstrap/src/core/build_steps/suggest.rs +++ b/src/bootstrap/src/core/build_steps/suggest.rs @@ -13,13 +13,11 @@ use crate::core::builder::Builder; pub fn suggest(builder: &Builder<'_>, run: bool) { let git_config = builder.config.git_config(); let suggestions = builder - .run( - builder - .tool_cmd(Tool::SuggestTests) - .capture_stdout() - .env("SUGGEST_TESTS_GIT_REPOSITORY", git_config.git_repository) - .env("SUGGEST_TESTS_NIGHTLY_BRANCH", git_config.nightly_branch), - ) + .tool_cmd(Tool::SuggestTests) + .capture_stdout() + .env("SUGGEST_TESTS_GIT_REPOSITORY", git_config.git_repository) + .env("SUGGEST_TESTS_NIGHTLY_BRANCH", git_config.nightly_branch) + .run(builder) .stdout(); let suggestions = suggestions diff --git a/src/bootstrap/src/core/build_steps/synthetic_targets.rs b/src/bootstrap/src/core/build_steps/synthetic_targets.rs index a115ba2d8b2..021680302cd 100644 --- a/src/bootstrap/src/core/build_steps/synthetic_targets.rs +++ b/src/bootstrap/src/core/build_steps/synthetic_targets.rs @@ -9,7 +9,7 @@ use crate::core::builder::{Builder, ShouldRun, Step}; use crate::core::config::TargetSelection; -use crate::utils::exec::BootstrapCommand; +use crate::utils::exec::command; use crate::Compiler; #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -56,7 +56,7 @@ fn create_synthetic_target( return TargetSelection::create_synthetic(&name, path.to_str().unwrap()); } - let mut cmd = BootstrapCommand::new(builder.rustc(compiler)); + let mut cmd = command(builder.rustc(compiler)); cmd.arg("--target").arg(base.rustc_target_arg()); cmd.args(["-Zunstable-options", "--print", "target-spec-json"]); @@ -64,7 +64,7 @@ fn create_synthetic_target( // we cannot use nightly features. So `RUSTC_BOOTSTRAP` is needed here. cmd.env("RUSTC_BOOTSTRAP", "1"); - let output = builder.run(cmd.capture()).stdout(); + let output = cmd.capture().run(builder).stdout(); let mut spec: serde_json::Value = serde_json::from_slice(output.as_bytes()).unwrap(); let spec_map = spec.as_object_mut().unwrap(); diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index dc53bd3cfa7..7f4c4bd53df 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -26,7 +26,7 @@ use crate::core::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step}; use crate::core::config::flags::get_completion; use crate::core::config::flags::Subcommand; use crate::core::config::TargetSelection; -use crate::utils::exec::BootstrapCommand; +use crate::utils::exec::{command, BootstrapCommand}; use crate::utils::helpers::{ self, add_link_lib_path, add_rustdoc_cargo_linker_args, dylib_path, dylib_path_var, linker_args, linker_flags, t, target_supports_cranelift_backend, up_to_date, LldThreads, @@ -155,7 +155,7 @@ You can skip linkcheck with --skip src/tools/linkchecker" let _guard = builder.msg(Kind::Test, compiler.stage, "Linkcheck", bootstrap_host, bootstrap_host); let _time = helpers::timeit(builder); - builder.run(linkchecker.delay_failure().arg(builder.out.join(host.triple).join("doc"))); + linkchecker.delay_failure().arg(builder.out.join(host.triple).join("doc")).run(builder); } fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -212,9 +212,11 @@ impl Step for HtmlCheck { builder, )); - builder.run( - builder.tool_cmd(Tool::HtmlChecker).delay_failure().arg(builder.doc_out(self.target)), - ); + builder + .tool_cmd(Tool::HtmlChecker) + .delay_failure() + .arg(builder.doc_out(self.target)) + .run(builder); } } @@ -259,7 +261,7 @@ impl Step for Cargotest { .env("RUSTC", builder.rustc(compiler)) .env("RUSTDOC", builder.rustdoc(compiler)); add_rustdoc_cargo_linker_args(&mut cmd, builder, compiler.host, LldThreads::No); - builder.run(cmd.delay_failure()); + cmd.delay_failure().run(builder); } } @@ -460,7 +462,7 @@ impl Miri { let mut cargo = BootstrapCommand::from(cargo); let _guard = builder.msg(Kind::Build, compiler.stage, "miri sysroot", compiler.host, target); - builder.run(&mut cargo); + cargo.run(builder); // # Determine where Miri put its sysroot. // To this end, we run `cargo miri setup --print-sysroot` and capture the output. @@ -473,7 +475,7 @@ impl Miri { String::new() } else { builder.verbose(|| println!("running: {cargo:?}")); - let stdout = builder.run(cargo.capture_stdout()).stdout(); + let stdout = cargo.capture_stdout().run(builder).stdout(); // Output is "<sysroot>\n". let sysroot = stdout.trim_end(); builder.verbose(|| println!("`cargo miri setup --print-sysroot` said: {sysroot:?}")); @@ -561,7 +563,7 @@ impl Step for Miri { { let _guard = builder.msg_sysroot_tool(Kind::Test, stage, "miri", host, target); let _time = helpers::timeit(builder); - builder.run(&mut cargo); + cargo.run(builder); } // Run it again for mir-opt-level 4 to catch some miscompilations. @@ -583,7 +585,7 @@ impl Step for Miri { target, ); let _time = helpers::timeit(builder); - builder.run(cargo); + cargo.run(builder); } } } @@ -648,11 +650,11 @@ impl Step for CargoMiri { // Finally, pass test-args and run everything. cargo.arg("--").args(builder.config.test_args()); - let cargo = BootstrapCommand::from(cargo); + let mut cargo = BootstrapCommand::from(cargo); { let _guard = builder.msg_sysroot_tool(Kind::Test, stage, "cargo-miri", host, target); let _time = helpers::timeit(builder); - builder.run(cargo); + cargo.run(builder); } } } @@ -753,7 +755,7 @@ impl Step for Clippy { let _guard = builder.msg_sysroot_tool(Kind::Test, compiler.stage, "clippy", host, host); // Clippy reports errors if it blessed the outputs - if builder.run(cargo.allow_failure()).is_success() { + if cargo.allow_failure().run(builder).is_success() { // The tests succeeded; nothing to do. return; } @@ -806,7 +808,7 @@ impl Step for RustdocTheme { .env("RUSTC_BOOTSTRAP", "1"); cmd.args(linker_args(builder, self.compiler.host, LldThreads::No)); - builder.run(cmd.delay_failure()); + cmd.delay_failure().run(builder); } } @@ -832,7 +834,7 @@ impl Step for RustdocJSStd { fn run(self, builder: &Builder<'_>) { let nodejs = builder.config.nodejs.as_ref().expect("need nodejs to run rustdoc-js-std tests"); - let mut command = BootstrapCommand::new(nodejs); + let mut command = command(nodejs); command .arg(builder.src.join("src/tools/rustdoc-js/tester.js")) .arg("--crate-name") @@ -866,7 +868,7 @@ impl Step for RustdocJSStd { builder.config.build, self.target, ); - builder.run(command); + command.run(builder); } } @@ -908,12 +910,12 @@ fn get_browser_ui_test_version_inner( npm: &Path, global: bool, ) -> Option<String> { - let mut command = BootstrapCommand::new(npm).capture(); + let mut command = command(npm).capture(); command.arg("list").arg("--parseable").arg("--long").arg("--depth=0"); if global { command.arg("--global"); } - let lines = builder.run(command.allow_failure()).stdout(); + let lines = command.allow_failure().run(builder).stdout(); lines .lines() .find_map(|l| l.split(':').nth(1)?.strip_prefix("browser-ui-test@")) @@ -1085,7 +1087,7 @@ HELP: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to } builder.info("tidy check"); - builder.run(cmd.delay_failure()); + cmd.delay_failure().run(builder); builder.info("x.py completions check"); let [bash, zsh, fish, powershell] = ["x.py.sh", "x.py.zsh", "x.py.fish", "x.py.ps1"] @@ -1292,7 +1294,7 @@ impl Step for RunMakeSupport { &[], ); - builder.run(cargo.into_cmd()); + cargo.into_cmd().run(builder); let lib_name = "librun_make_support.rlib"; let lib = builder.tools_dir(self.compiler).join(lib_name); @@ -1804,14 +1806,20 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the } let lldb_exe = builder.config.lldb.clone().unwrap_or_else(|| PathBuf::from("lldb")); - let lldb_version = builder - .run(BootstrapCommand::new(&lldb_exe).capture().allow_failure().arg("--version")) + let lldb_version = command(&lldb_exe) + .capture() + .allow_failure() + .arg("--version") + .run(builder) .stdout_if_ok() .and_then(|v| if v.trim().is_empty() { None } else { Some(v) }); if let Some(ref vers) = lldb_version { cmd.arg("--lldb-version").arg(vers); - let lldb_python_dir = builder - .run(BootstrapCommand::new(&lldb_exe).allow_failure().capture_stdout().arg("-P")) + let lldb_python_dir = command(&lldb_exe) + .allow_failure() + .capture_stdout() + .arg("-P") + .run(builder) .stdout_if_ok() .map(|p| p.lines().next().expect("lldb Python dir not found").to_string()); if let Some(ref dir) = lldb_python_dir { @@ -1869,11 +1877,10 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the let llvm::LlvmResult { llvm_config, .. } = builder.ensure(llvm::Llvm { target: builder.config.build }); if !builder.config.dry_run() { - let llvm_version = builder - .run(BootstrapCommand::new(&llvm_config).capture_stdout().arg("--version")) - .stdout(); + let llvm_version = + builder.run(command(&llvm_config).capture_stdout().arg("--version")).stdout(); let llvm_components = builder - .run(BootstrapCommand::new(&llvm_config).capture_stdout().arg("--components")) + .run(command(&llvm_config).capture_stdout().arg("--components")) .stdout(); // Remove trailing newline from llvm-config output. cmd.arg("--llvm-version") @@ -1893,9 +1900,8 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the // separate compilations. We can add LLVM's library path to the // platform-specific environment variable as a workaround. if !builder.config.dry_run() && suite.ends_with("fulldeps") { - let llvm_libdir = builder - .run(BootstrapCommand::new(&llvm_config).capture_stdout().arg("--libdir")) - .stdout(); + let llvm_libdir = + builder.run(command(&llvm_config).capture_stdout().arg("--libdir")).stdout(); add_link_lib_path(vec![llvm_libdir.trim().into()], &mut cmd); } @@ -2169,9 +2175,11 @@ impl BookTest { compiler.host, ); let _time = helpers::timeit(builder); - let cmd = rustbook_cmd.delay_failure(); - let toolstate = - if builder.run(cmd).is_success() { ToolState::TestPass } else { ToolState::TestFail }; + let toolstate = if rustbook_cmd.delay_failure().run(builder).is_success() { + ToolState::TestPass + } else { + ToolState::TestFail + }; builder.save_toolstate(self.name, toolstate); } @@ -2300,7 +2308,7 @@ impl Step for ErrorIndex { let guard = builder.msg(Kind::Test, compiler.stage, "error-index", compiler.host, compiler.host); let _time = helpers::timeit(builder); - builder.run(tool.capture()); + tool.capture().run(builder); drop(guard); // The tests themselves need to link to std, so make sure it is // available. @@ -2333,7 +2341,7 @@ fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> if !builder.config.verbose_tests { cmd = cmd.capture(); } - builder.run(cmd).is_success() + cmd.run(builder).is_success() } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -2359,7 +2367,7 @@ impl Step for RustcGuide { let src = builder.src.join(relative_path); let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook).delay_failure(); rustbook_cmd.arg("linkcheck").arg(&src); - let toolstate = if builder.run(rustbook_cmd).is_success() { + let toolstate = if rustbook_cmd.run(builder).is_success() { ToolState::TestPass } else { ToolState::TestFail @@ -2863,19 +2871,19 @@ impl Step for RemoteCopyLibs { // Spawn the emulator and wait for it to come online let tool = builder.tool_exe(Tool::RemoteTestClient); - let mut cmd = BootstrapCommand::new(&tool); + let mut cmd = command(&tool); cmd.arg("spawn-emulator").arg(target.triple).arg(&server).arg(builder.tempdir()); if let Some(rootfs) = builder.qemu_rootfs(target) { cmd.arg(rootfs); } - builder.run(cmd); + cmd.run(builder); // Push all our dylibs to the emulator for f in t!(builder.sysroot_libdir(compiler, target).read_dir()) { let f = t!(f); let name = f.file_name().into_string().unwrap(); if helpers::is_dylib(&name) { - builder.run(BootstrapCommand::new(&tool).arg("push").arg(f.path())); + builder.run(command(&tool).arg("push").arg(f.path())); } } } @@ -2906,22 +2914,20 @@ impl Step for Distcheck { builder.ensure(dist::PlainSourceTarball); builder.ensure(dist::Src); - let mut cmd = BootstrapCommand::new("tar"); + let mut cmd = command("tar"); cmd.arg("-xf") .arg(builder.ensure(dist::PlainSourceTarball).tarball()) .arg("--strip-components=1") .current_dir(&dir); - builder.run(cmd); + cmd.run(builder); builder.run( - BootstrapCommand::new("./configure") + command("./configure") .args(&builder.config.configure_args) .arg("--enable-vendor") .current_dir(&dir), ); builder.run( - BootstrapCommand::new(helpers::make(&builder.config.build.triple)) - .arg("check") - .current_dir(&dir), + command(helpers::make(&builder.config.build.triple)).arg("check").current_dir(&dir), ); // Now make sure that rust-src has all of libstd's dependencies @@ -2930,16 +2936,16 @@ impl Step for Distcheck { let _ = fs::remove_dir_all(&dir); t!(fs::create_dir_all(&dir)); - let mut cmd = BootstrapCommand::new("tar"); + let mut cmd = command("tar"); cmd.arg("-xf") .arg(builder.ensure(dist::Src).tarball()) .arg("--strip-components=1") .current_dir(&dir); - builder.run(cmd); + cmd.run(builder); let toml = dir.join("rust-src/lib/rustlib/src/rust/library/std/Cargo.toml"); builder.run( - BootstrapCommand::new(&builder.initial_cargo) + command(&builder.initial_cargo) // Will read the libstd Cargo.toml // which uses the unstable `public-dependency` feature. .env("RUSTC_BOOTSTRAP", "1") @@ -2968,7 +2974,7 @@ impl Step for Bootstrap { // Some tests require cargo submodule to be present. builder.build.update_submodule(Path::new("src/tools/cargo")); - let mut check_bootstrap = BootstrapCommand::new(builder.python()); + let mut check_bootstrap = command(builder.python()); check_bootstrap .args(["-m", "unittest", "bootstrap_test.py"]) .env("BUILD_DIR", &builder.out) @@ -2976,9 +2982,9 @@ impl Step for Bootstrap { .current_dir(builder.src.join("src/bootstrap/")); // NOTE: we intentionally don't pass test_args here because the args for unittest and cargo test are mutually incompatible. // Use `python -m unittest` manually if you want to pass arguments. - builder.run(check_bootstrap.delay_failure()); + check_bootstrap.delay_failure().run(builder); - let mut cmd = BootstrapCommand::new(&builder.initial_cargo); + let mut cmd = command(&builder.initial_cargo); cmd.arg("test") .args(["--features", "bootstrap-self-test"]) .current_dir(builder.src.join("src/bootstrap")) @@ -3053,7 +3059,7 @@ impl Step for TierCheck { self.compiler.host, self.compiler.host, ); - builder.run(BootstrapCommand::from(cargo).delay_failure()); + BootstrapCommand::from(cargo).delay_failure().run(builder); } } @@ -3129,7 +3135,7 @@ impl Step for RustInstaller { return; } - let mut cmd = BootstrapCommand::new(builder.src.join("src/tools/rust-installer/test.sh")); + let mut cmd = command(builder.src.join("src/tools/rust-installer/test.sh")); let tmpdir = testdir(builder, compiler.host).join("rust-installer"); let _ = std::fs::remove_dir_all(&tmpdir); let _ = std::fs::create_dir_all(&tmpdir); @@ -3138,7 +3144,7 @@ impl Step for RustInstaller { cmd.env("CARGO", &builder.initial_cargo); cmd.env("RUSTC", &builder.initial_rustc); cmd.env("TMP_DIR", &tmpdir); - builder.run(cmd.delay_failure()); + cmd.delay_failure().run(builder); } fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -3332,7 +3338,7 @@ impl Step for CodegenCranelift { .arg("testsuite.extended_sysroot"); cargo.args(builder.config.test_args()); - builder.run(cargo.into_cmd()); + cargo.into_cmd().run(builder); } } @@ -3457,6 +3463,6 @@ impl Step for CodegenGCC { .arg("--std-tests"); cargo.args(builder.config.test_args()); - builder.run(cargo.into_cmd()); + cargo.into_cmd().run(builder); } } diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 5fb282db90a..ad92a01bce7 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -8,7 +8,7 @@ use crate::core::builder; use crate::core::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step}; use crate::core::config::TargetSelection; use crate::utils::channel::GitInfo; -use crate::utils::exec::BootstrapCommand; +use crate::utils::exec::{command, BootstrapCommand}; use crate::utils::helpers::{add_dylib_path, exe, t}; use crate::Compiler; use crate::Mode; @@ -438,7 +438,7 @@ impl ErrorIndex { // for rustc_private and libLLVM.so, and `sysroot_lib` for libstd, etc. let host = builder.config.build; let compiler = builder.compiler_for(builder.top_stage, host, host); - let mut cmd = BootstrapCommand::new(builder.ensure(ErrorIndex { compiler })); + let mut cmd = command(builder.ensure(ErrorIndex { compiler })); let mut dylib_paths = builder.rustc_lib_paths(compiler); dylib_paths.push(PathBuf::from(&builder.sysroot_libdir(compiler, compiler.host))); add_dylib_path(dylib_paths, &mut cmd); @@ -602,7 +602,7 @@ impl Step for Rustdoc { &self.compiler.host, &target, ); - builder.run(cargo.into_cmd()); + cargo.into_cmd().run(builder); // Cargo adds a number of paths to the dylib search path on windows, which results in // the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool" @@ -857,7 +857,7 @@ impl Step for LlvmBitcodeLinker { &self.extra_features, ); - builder.run(cargo.into_cmd()); + cargo.into_cmd().run(builder); let tool_out = builder .cargo_out(self.compiler, Mode::ToolRustc, self.target) @@ -912,21 +912,20 @@ impl Step for LibcxxVersionTool { } let compiler = builder.cxx(self.target).unwrap(); - let mut cmd = BootstrapCommand::new(compiler); + let mut cmd = command(compiler); cmd.arg("-o") .arg(&executable) .arg(builder.src.join("src/tools/libcxx-version/main.cpp")); - builder.run(cmd); + cmd.run(builder); if !executable.exists() { panic!("Something went wrong. {} is not present", executable.display()); } } - let version_output = - builder.run(BootstrapCommand::new(executable).capture_stdout()).stdout(); + let version_output = command(executable).capture_stdout().run(builder).stdout(); let version_str = version_output.split_once("version:").unwrap().1; let version = version_str.trim().parse::<usize>().unwrap(); @@ -1050,7 +1049,7 @@ impl<'a> Builder<'a> { /// Gets a `BootstrapCommand` which is ready to run `tool` in `stage` built for /// `host`. pub fn tool_cmd(&self, tool: Tool) -> BootstrapCommand { - let mut cmd = BootstrapCommand::new(self.tool_exe(tool)); + let mut cmd = command(self.tool_exe(tool)); let compiler = self.compiler(0, self.config.build); let host = &compiler.host; // Prepares the `cmd` provided to be able to run the `compiler` provided. diff --git a/src/bootstrap/src/core/build_steps/vendor.rs b/src/bootstrap/src/core/build_steps/vendor.rs index 0b999a24a1f..62342ee4792 100644 --- a/src/bootstrap/src/core/build_steps/vendor.rs +++ b/src/bootstrap/src/core/build_steps/vendor.rs @@ -1,5 +1,5 @@ use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; -use crate::utils::exec::BootstrapCommand; +use crate::utils::exec::command; use std::path::{Path, PathBuf}; #[derive(Debug, Clone, Hash, PartialEq, Eq)] @@ -27,7 +27,7 @@ impl Step for Vendor { } fn run(self, builder: &Builder<'_>) -> Self::Output { - let mut cmd = BootstrapCommand::new(&builder.initial_cargo); + let mut cmd = command(&builder.initial_cargo); cmd.arg("vendor"); if self.versioned_dirs { @@ -59,6 +59,6 @@ impl Step for Vendor { cmd.current_dir(self.root_dir); - builder.run(cmd); + cmd.run(builder); } } diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 4da912994c3..24bb96c6b88 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -23,7 +23,7 @@ use crate::utils::helpers::{check_cfg_arg, libdir, linker_flags, t, LldThreads}; use crate::EXTRA_CHECK_CFGS; use crate::{Build, CLang, Crate, DocTests, GitRepo, Mode}; -use crate::utils::exec::BootstrapCommand; +use crate::utils::exec::{command, BootstrapCommand}; pub use crate::Compiler; use clap::ValueEnum; @@ -1254,7 +1254,7 @@ impl<'a> Builder<'a> { if run_compiler.stage == 0 { // `ensure(Clippy { stage: 0 })` *builds* clippy with stage0, it doesn't use the beta clippy. let cargo_clippy = self.build.config.download_clippy(); - let mut cmd = BootstrapCommand::new(cargo_clippy); + let mut cmd = command(cargo_clippy); cmd.env("CARGO", &self.initial_cargo); return cmd; } @@ -1273,7 +1273,7 @@ impl<'a> Builder<'a> { let mut dylib_path = helpers::dylib_path(); dylib_path.insert(0, self.sysroot(run_compiler).join("lib")); - let mut cmd = BootstrapCommand::new(cargo_clippy); + let mut cmd = command(cargo_clippy); cmd.env(helpers::dylib_path_var(), env::join_paths(&dylib_path).unwrap()); cmd.env("CARGO", &self.initial_cargo); cmd @@ -1295,7 +1295,7 @@ impl<'a> Builder<'a> { extra_features: Vec::new(), }); // Invoke cargo-miri, make sure it can find miri and cargo. - let mut cmd = BootstrapCommand::new(cargo_miri); + let mut cmd = command(cargo_miri); cmd.env("MIRI", &miri); cmd.env("CARGO", &self.initial_cargo); // Need to add the `run_compiler` libs. Those are the libs produces *by* `build_compiler`, @@ -1311,7 +1311,7 @@ impl<'a> Builder<'a> { } pub fn rustdoc_cmd(&self, compiler: Compiler) -> BootstrapCommand { - let mut cmd = BootstrapCommand::new(self.bootstrap_out.join("rustdoc")); + let mut cmd = command(self.bootstrap_out.join("rustdoc")); cmd.env("RUSTC_STAGE", compiler.stage.to_string()) .env("RUSTC_SYSROOT", self.sysroot(compiler)) // Note that this is *not* the sysroot_libdir because rustdoc must be linked @@ -1365,7 +1365,7 @@ impl<'a> Builder<'a> { cargo = self.cargo_miri_cmd(compiler); cargo.arg("miri").arg(subcmd); } else { - cargo = BootstrapCommand::new(&self.initial_cargo); + cargo = command(&self.initial_cargo); cargo.arg(cmd); } @@ -1918,9 +1918,8 @@ impl<'a> Builder<'a> { // platform-specific environment variable as a workaround. if mode == Mode::ToolRustc || mode == Mode::Codegen { if let Some(llvm_config) = self.llvm_config(target) { - let llvm_libdir = self - .run(BootstrapCommand::new(llvm_config).capture_stdout().arg("--libdir")) - .stdout(); + let llvm_libdir = + command(llvm_config).capture_stdout().arg("--libdir").run(self).stdout(); add_link_lib_path(vec![llvm_libdir.trim().into()], &mut cargo); } } diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index c35398e2eb7..a7f4bb0cf14 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -11,7 +11,7 @@ use std::{ use build_helper::ci::CiEnv; use xz2::bufread::XzDecoder; -use crate::utils::exec::BootstrapCommand; +use crate::utils::exec::{command, BootstrapCommand}; use crate::utils::helpers::hex_encode; use crate::utils::helpers::{check_run, exe, move_file, program_out_of_date}; use crate::{t, Config}; @@ -212,7 +212,7 @@ impl Config { fn download_http_with_retries(&self, tempfile: &Path, url: &str, help_on_error: &str) { println!("downloading {url}"); // Try curl. If that fails and we are on windows, fallback to PowerShell. - let mut curl = BootstrapCommand::new("curl"); + let mut curl = command("curl"); curl.args([ "-y", "30", diff --git a/src/bootstrap/src/core/metadata.rs b/src/bootstrap/src/core/metadata.rs index 49d17107125..b18da844014 100644 --- a/src/bootstrap/src/core/metadata.rs +++ b/src/bootstrap/src/core/metadata.rs @@ -2,7 +2,7 @@ use std::path::PathBuf; use serde_derive::Deserialize; -use crate::utils::exec::BootstrapCommand; +use crate::utils::exec::command; use crate::{t, Build, Crate}; /// For more information, see the output of @@ -70,7 +70,7 @@ pub fn build(build: &mut Build) { /// particular crate (e.g., `x build sysroot` to build library/sysroot). fn workspace_members(build: &Build) -> Vec<Package> { let collect_metadata = |manifest_path| { - let mut cargo = BootstrapCommand::new(&build.initial_cargo); + let mut cargo = command(&build.initial_cargo); cargo // Will read the libstd Cargo.toml // which uses the unstable `public-dependency` feature. @@ -81,7 +81,7 @@ fn workspace_members(build: &Build) -> Vec<Package> { .arg("--no-deps") .arg("--manifest-path") .arg(build.src.join(manifest_path)); - let metadata_output = build.run(cargo.capture_stdout().run_always()).stdout(); + let metadata_output = cargo.capture_stdout().run_always().run(build).stdout(); let Output { packages, .. } = t!(serde_json::from_str(&metadata_output)); packages }; diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 78862ccb8cd..9995da3a1e5 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -23,7 +23,7 @@ use std::collections::HashSet; use crate::builder::Kind; use crate::core::config::Target; -use crate::utils::exec::BootstrapCommand; +use crate::utils::exec::command; use crate::Build; pub struct Finder { @@ -209,9 +209,7 @@ than building it. #[cfg(not(feature = "bootstrap-self-test"))] let stage0_supported_target_list: HashSet<String> = crate::utils::helpers::output( - &mut BootstrapCommand::new(&build.config.initial_rustc) - .args(["--print", "target-list"]) - .command, + &mut command(&build.config.initial_rustc).args(["--print", "target-list"]).command, ) .lines() .map(|s| s.to_string()) @@ -354,8 +352,7 @@ than building it. // There are three builds of cmake on windows: MSVC, MinGW, and // Cygwin. The Cygwin build does not have generators for Visual // Studio, so detect that here and error. - let out = - build.run(BootstrapCommand::new("cmake").capture_stdout().arg("--help")).stdout(); + let out = command("cmake").capture_stdout().arg("--help").run(build).stdout(); if !out.contains("Visual Studio") { panic!( " diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index ffdd9bc885a..f16afb29796 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -41,7 +41,7 @@ use crate::core::builder::Kind; use crate::core::config::{flags, LldMode}; use crate::core::config::{DryRun, Target}; use crate::core::config::{LlvmLibunwind, TargetSelection}; -use crate::utils::exec::{BehaviorOnFailure, BootstrapCommand, CommandOutput}; +use crate::utils::exec::{command, BehaviorOnFailure, BootstrapCommand, CommandOutput}; use crate::utils::helpers::{self, dir_is_empty, exe, libdir, mtime, output, symlink_dir}; mod core; @@ -510,9 +510,10 @@ impl Build { } println!("Updating submodule {}", relative_path.display()); - self.run( - helpers::git(Some(&self.src)).args(["submodule", "-q", "sync"]).arg(relative_path), - ); + helpers::git(Some(&self.src)) + .args(["submodule", "-q", "sync"]) + .arg(relative_path) + .run(self); // Try passing `--progress` to start, then run git again without if that fails. let update = |progress: bool| { @@ -548,23 +549,25 @@ impl Build { }; // NOTE: doesn't use `try_run` because this shouldn't print an error if it fails. if !update(true).command.status().map_or(false, |status| status.success()) { - self.run(update(false)); + update(false).run(self); } // Save any local changes, but avoid running `git stash pop` if there are none (since it will exit with an error). // diff-index reports the modifications through the exit status - let has_local_modifications = self - .run(submodule_git().allow_failure().args(["diff-index", "--quiet", "HEAD"])) + let has_local_modifications = submodule_git() + .allow_failure() + .args(["diff-index", "--quiet", "HEAD"]) + .run(self) .is_failure(); if has_local_modifications { - self.run(submodule_git().args(["stash", "push"])); + submodule_git().args(["stash", "push"]).run(self); } - self.run(submodule_git().args(["reset", "-q", "--hard"])); - self.run(submodule_git().args(["clean", "-qdfx"])); + submodule_git().args(["reset", "-q", "--hard"]).run(self); + submodule_git().args(["clean", "-qdfx"]).run(self); if has_local_modifications { - self.run(submodule_git().args(["stash", "pop"])); + submodule_git().args(["stash", "pop"]).run(self); } } @@ -575,14 +578,12 @@ impl Build { if !self.config.submodules(self.rust_info()) { return; } - let output = self - .run( - helpers::git(Some(&self.src)) - .capture() - .args(["config", "--file"]) - .arg(self.config.src.join(".gitmodules")) - .args(["--get-regexp", "path"]), - ) + let output = helpers::git(Some(&self.src)) + .capture() + .args(["config", "--file"]) + .arg(self.config.src.join(".gitmodules")) + .args(["--get-regexp", "path"]) + .run(self) .stdout(); for line in output.lines() { // Look for `submodule.$name.path = $path` @@ -860,16 +861,14 @@ impl Build { if let Some(s) = target_config.and_then(|c| c.llvm_filecheck.as_ref()) { s.to_path_buf() } else if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { - let llvm_bindir = - self.run(BootstrapCommand::new(s).capture_stdout().arg("--bindir")).stdout(); + let llvm_bindir = command(s).capture_stdout().arg("--bindir").run(self).stdout(); let filecheck = Path::new(llvm_bindir.trim()).join(exe("FileCheck", target)); if filecheck.exists() { filecheck } else { // On Fedora the system LLVM installs FileCheck in the // llvm subdirectory of the libdir. - let llvm_libdir = - self.run(BootstrapCommand::new(s).capture_stdout().arg("--libdir")).stdout(); + let llvm_libdir = command(s).capture_stdout().arg("--libdir").run(self).stdout(); let lib_filecheck = Path::new(llvm_libdir.trim()).join("llvm").join(exe("FileCheck", target)); if lib_filecheck.exists() { @@ -935,8 +934,7 @@ impl Build { /// Execute a command and return its output. /// This method should be used for all command executions in bootstrap. - fn run<C: AsMut<BootstrapCommand>>(&self, mut command: C) -> CommandOutput { - let command = command.as_mut(); + fn run(&self, command: &mut BootstrapCommand) -> CommandOutput { if self.config.dry_run() && !command.run_always { return CommandOutput::default(); } @@ -1496,18 +1494,17 @@ impl Build { // Figure out how many merge commits happened since we branched off master. // That's our beta number! // (Note that we use a `..` range, not the `...` symmetric difference.) - self.run( - helpers::git(Some(&self.src)) - .capture() - .arg("rev-list") - .arg("--count") - .arg("--merges") - .arg(format!( - "refs/remotes/origin/{}..HEAD", - self.config.stage0_metadata.config.nightly_branch - )), - ) - .stdout() + helpers::git(Some(&self.src)) + .capture() + .arg("rev-list") + .arg("--count") + .arg("--merges") + .arg(format!( + "refs/remotes/origin/{}..HEAD", + self.config.stage0_metadata.config.nightly_branch + )) + .run(self) + .stdout() }); let n = count.trim().parse().unwrap(); self.prerelease_version.set(Some(n)); diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs index b80df545202..d6fa7fc0bbe 100644 --- a/src/bootstrap/src/utils/cc_detect.rs +++ b/src/bootstrap/src/utils/cc_detect.rs @@ -26,7 +26,7 @@ use std::path::{Path, PathBuf}; use std::{env, iter}; use crate::core::config::TargetSelection; -use crate::utils::exec::BootstrapCommand; +use crate::utils::exec::{command, BootstrapCommand}; use crate::{Build, CLang, GitRepo}; // The `cc` crate doesn't provide a way to obtain a path to the detected archiver, @@ -183,14 +183,14 @@ fn default_compiler( } let cmd = BootstrapCommand::from(c.to_command()); - let output = build.run(cmd.capture_stdout().arg("--version")).stdout(); + let output = cmd.capture_stdout().arg("--version").run(build).stdout(); let i = output.find(" 4.")?; match output[i + 3..].chars().next().unwrap() { '0'..='6' => {} _ => return None, } let alternative = format!("e{gnu_compiler}"); - if build.run(BootstrapCommand::new(&alternative).capture()).is_success() { + if command(&alternative).capture().run(build).is_success() { Some(PathBuf::from(alternative)) } else { None diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index 086d10c6351..ba963f52dc2 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -1,3 +1,4 @@ +use crate::Build; use std::ffi::OsStr; use std::path::Path; use std::process::{Command, CommandArgs, CommandEnvs, ExitStatus, Output, Stdio}; @@ -108,14 +109,17 @@ impl BootstrapCommand { self } + #[must_use] pub fn delay_failure(self) -> Self { Self { failure_behavior: BehaviorOnFailure::DelayFail, ..self } } + #[must_use] pub fn fail_fast(self) -> Self { Self { failure_behavior: BehaviorOnFailure::Exit, ..self } } + #[must_use] pub fn allow_failure(self) -> Self { Self { failure_behavior: BehaviorOnFailure::Ignore, ..self } } @@ -126,21 +130,20 @@ impl BootstrapCommand { } /// Capture all output of the command, do not print it. + #[must_use] pub fn capture(self) -> Self { Self { stdout: OutputMode::Capture, stderr: OutputMode::Capture, ..self } } /// Capture stdout of the command, do not print it. + #[must_use] pub fn capture_stdout(self) -> Self { Self { stdout: OutputMode::Capture, ..self } } -} -/// This implementation exists to make it possible to pass both [BootstrapCommand] and -/// `&mut BootstrapCommand` to `Build.run()`. -impl AsMut<BootstrapCommand> for BootstrapCommand { - fn as_mut(&mut self) -> &mut BootstrapCommand { - self + /// Run the command, returning its output. + pub fn run(&mut self, builder: &Build) -> CommandOutput { + builder.run(self) } } @@ -164,6 +167,13 @@ enum CommandStatus { DidNotStart, } +/// Create a new BootstrapCommand. This is a helper function to make command creation +/// shorter than `BootstrapCommand::new`. +#[must_use] +pub fn command<S: AsRef<OsStr>>(program: S) -> BootstrapCommand { + BootstrapCommand::new(program) +} + /// Represents the output of an executed process. #[allow(unused)] pub struct CommandOutput { @@ -173,10 +183,12 @@ pub struct CommandOutput { } impl CommandOutput { + #[must_use] pub fn did_not_start() -> Self { Self { status: CommandStatus::DidNotStart, stdout: vec![], stderr: vec![] } } + #[must_use] pub fn is_success(&self) -> bool { match self.status { CommandStatus::Finished(status) => status.success(), @@ -184,10 +196,12 @@ impl CommandOutput { } } + #[must_use] pub fn is_failure(&self) -> bool { !self.is_success() } + #[must_use] pub fn status(&self) -> Option<ExitStatus> { match self.status { CommandStatus::Finished(status) => Some(status), @@ -195,14 +209,17 @@ impl CommandOutput { } } + #[must_use] pub fn stdout(&self) -> String { String::from_utf8(self.stdout.clone()).expect("Cannot parse process stdout as UTF-8") } + #[must_use] pub fn stdout_if_ok(&self) -> Option<String> { if self.is_success() { Some(self.stdout()) } else { None } } + #[must_use] pub fn stderr(&self) -> String { String::from_utf8(self.stderr.clone()).expect("Cannot parse process stderr as UTF-8") } diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 2575b7939b4..5dd3ba96786 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -47,7 +47,7 @@ macro_rules! t { } }; } -use crate::utils::exec::BootstrapCommand; +use crate::utils::exec::{command, BootstrapCommand}; pub use t; pub fn exe(name: &str, target: TargetSelection) -> String { @@ -369,9 +369,9 @@ fn lld_flag_no_threads(builder: &Builder<'_>, lld_mode: LldMode, is_windows: boo let (windows_flag, other_flag) = LLD_NO_THREADS.get_or_init(|| { let newer_version = match lld_mode { LldMode::External => { - let mut cmd = BootstrapCommand::new("lld").capture_stdout(); + let mut cmd = command("lld").capture_stdout(); cmd.arg("-flavor").arg("ld").arg("--version"); - let out = builder.run(cmd).stdout(); + let out = cmd.run(builder).stdout(); match (out.find(char::is_numeric), out.find('.')) { (Some(b), Some(e)) => out.as_str()[b..e].parse::<i32>().ok().unwrap_or(14) > 10, _ => true, @@ -499,10 +499,10 @@ pub fn check_cfg_arg(name: &str, values: Option<&[&str]>) -> String { /// Whenever a git invocation is needed, this function should be preferred over /// manually building a git `BootstrapCommand`. This approach allows us to manage /// bootstrap-specific needs/hacks from a single source, rather than applying them on next to every -/// `BootstrapCommand::new("git")`, which is painful to ensure that the required change is applied +/// git command creation, which is painful to ensure that the required change is applied /// on each one of them correctly. pub fn git(source_dir: Option<&Path>) -> BootstrapCommand { - let mut git = BootstrapCommand::new("git"); + let mut git = command("git"); if let Some(source_dir) = source_dir { git.current_dir(source_dir); diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs index 1a35dc1fd38..4f0104e4bba 100644 --- a/src/bootstrap/src/utils/tarball.rs +++ b/src/bootstrap/src/utils/tarball.rs @@ -379,7 +379,7 @@ impl<'a> Tarball<'a> { cmd.args(["--override-file-mtime", timestamp.trim()]); } - self.builder.run(cmd); + cmd.run(self.builder); // Ensure there are no symbolic links in the tarball. In particular, // rustup-toolchain-install-master and most versions of Windows can't handle symbolic links. diff --git a/src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md b/src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md index 2b3d15e93c8..c3eda26ca8e 100644 --- a/src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md +++ b/src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md @@ -107,7 +107,7 @@ flag, for example: Users need to install or built wasi-sdk since release 20.0 https://github.com/WebAssembly/wasi-sdk/releases/tag/wasi-sdk-20 -and specify path to *wasi-root* `.cargo/config.toml` +and specify path to *wasi-root* `config.toml` ```toml [target.wasm32-wasip1-threads] diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index a0ab262bf0b..86af38f3ee7 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -3293,10 +3293,9 @@ ${item.displayPath}<span class="${type}">${name}</span>\ } // call after consuming `{` decodeList() { - const cb = "}".charCodeAt(0); let c = this.string.charCodeAt(this.offset); const ret = []; - while (c !== cb) { + while (c !== 125) { // 125 = "}" ret.push(this.decode()); c = this.string.charCodeAt(this.offset); } @@ -3305,14 +3304,13 @@ ${item.displayPath}<span class="${type}">${name}</span>\ } // consumes and returns a list or integer decode() { - const [ob, la] = ["{", "`"].map(c => c.charCodeAt(0)); let n = 0; let c = this.string.charCodeAt(this.offset); - if (c === ob) { + if (c === 123) { // 123 = "{" this.offset += 1; return this.decodeList(); } - while (c < la) { + while (c < 96) { // 96 = "`" n = (n << 4) | (c & 0xF); this.offset += 1; c = this.string.charCodeAt(this.offset); @@ -3325,15 +3323,14 @@ ${item.displayPath}<span class="${type}">${name}</span>\ } next() { const c = this.string.charCodeAt(this.offset); - const [zero, ua, la] = ["0", "@", "`"].map(c => c.charCodeAt(0)); // sixteen characters after "0" are backref - if (c >= zero && c < ua) { + if (c >= 48 && c < 64) { // 48 = "0", 64 = "@" this.offset += 1; - return this.backrefQueue[c - zero]; + return this.backrefQueue[c - 48]; } // special exception: 0 doesn't use backref encoding // it's already one character, and it's always nullish - if (c === la) { + if (c === 96) { // 96 = "`" this.offset += 1; return this.cons(0); } @@ -3472,7 +3469,6 @@ ${item.displayPath}<span class="${type}">${name}</span>\ searchIndex = []; searchIndexDeprecated = new Map(); searchIndexEmptyDesc = new Map(); - const charA = "A".charCodeAt(0); let currentIndex = 0; let id = 0; @@ -3639,7 +3635,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\ // object defined above. const row = { crate, - ty: itemTypes.charCodeAt(i) - charA, + ty: itemTypes.charCodeAt(i) - 65, // 65 = "A" name: itemNames[i], path, descShard, diff --git a/src/tools/cargo b/src/tools/cargo -Subproject a515d463427b3912ec0365d106791f88c1c14e1 +Subproject 154fdac39ae9629954e19e9986fd2cf2cdd8d96 diff --git a/src/tools/run-make-support/src/diff/mod.rs b/src/tools/run-make-support/src/diff/mod.rs index 3e0bdc1c6f6..24fa88af82e 100644 --- a/src/tools/run-make-support/src/diff/mod.rs +++ b/src/tools/run-make-support/src/diff/mod.rs @@ -87,9 +87,7 @@ impl Diff { self } - #[track_caller] - pub fn run(&mut self) { - self.drop_bomb.defuse(); + fn run_common(&self) -> (&str, &str, String, String) { let expected = self.expected.as_ref().expect("expected text not set"); let mut actual = self.actual.as_ref().expect("actual text not set").to_string(); let expected_name = self.expected_name.as_ref().unwrap(); @@ -104,6 +102,14 @@ impl Diff { .header(expected_name, actual_name) .to_string(); + (expected_name, actual_name, output, actual) + } + + #[track_caller] + pub fn run(&mut self) { + self.drop_bomb.defuse(); + let (expected_name, actual_name, output, actual) = self.run_common(); + if !output.is_empty() { // If we can bless (meaning we have a file to write into and the `RUSTC_BLESS_TEST` // environment variable set), then we write into the file and return. @@ -120,4 +126,26 @@ impl Diff { ) } } + + #[track_caller] + pub fn run_fail(&mut self) { + self.drop_bomb.defuse(); + let (expected_name, actual_name, output, actual) = self.run_common(); + + if output.is_empty() { + // If we can bless (meaning we have a file to write into and the `RUSTC_BLESS_TEST` + // environment variable set), then we write into the file and return. + if let Some(ref expected_file) = self.expected_file { + if std::env::var("RUSTC_BLESS_TEST").is_ok() { + println!("Blessing `{}`", expected_file.display()); + fs_wrapper::write(expected_file, actual); + return; + } + } + panic!( + "test failed: `{}` is not different from `{}`\n\n{}", + expected_name, actual_name, output + ) + } + } } diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index ff98bd538db..31cb32d349a 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -23,8 +23,6 @@ run-make/dep-info-spaces/Makefile run-make/dep-info/Makefile run-make/dump-ice-to-disk/Makefile run-make/dump-mono-stats/Makefile -run-make/emit-path-unhashed/Makefile -run-make/emit-shared-files/Makefile run-make/emit-to-stdout/Makefile run-make/env-dep-info/Makefile run-make/export-executable-symbols/Makefile diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs index 7e5656926ab..2f8abc77566 100644 --- a/src/tools/tidy/src/pal.rs +++ b/src/tools/tidy/src/pal.rs @@ -45,6 +45,8 @@ const EXCEPTION_PATHS: &[&str] = &[ // pointer regardless of the target architecture. As a result, // we must use `#[cfg(windows)]` to conditionally compile the // correct `VaList` structure for windows. + "library/core/src/ffi/va_list.rs", + // We placed a linkage against Windows libraries here "library/core/src/ffi/mod.rs", "library/std/src/sys", // Platform-specific code for std lives here. "library/std/src/os", // Platform-specific public interfaces diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index e4d54d2a2b5..8e693c35adc 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -110,6 +110,7 @@ const ROOT_PROBLEMATIC_CONSTS: &[u32] = &[ 173390526, 721077, ]; +// Returns all permutations of problematic consts, over 2000 elements. fn generate_problematic_strings( consts: &[u32], letter_digit: &FxHashMap<char, char>, @@ -319,6 +320,8 @@ pub fn check(path: &Path, bad: &mut bool) { ROOT_PROBLEMATIC_CONSTS, &[('A', '4'), ('B', '8'), ('E', '3')].iter().cloned().collect(), ); + // This creates a RegexSet as regex contains performance optimizations to be able to deal with these over + // 2000 needles efficiently. This runs over the entire source code, so performance matters. let problematic_regex = RegexSet::new(problematic_consts_strings.as_slice()).unwrap(); walk(path, skip, &mut |entry, contents| { diff --git a/tests/crashes/125099.rs b/tests/crashes/125099.rs deleted file mode 100644 index bfc8c8fdcf6..00000000000 --- a/tests/crashes/125099.rs +++ /dev/null @@ -1,24 +0,0 @@ -//@ known-bug: rust-lang/rust#125099 - -pub trait ContFn<T>: Fn(T) -> Self::Future { - type Future; -} -impl<T, F> ContFn<T> for F -where - F: Fn(T), -{ - type Future = (); -} - -pub trait SeqHandler { - type Requires; - fn process<F: ContFn<Self::Requires>>() -> impl Sized; -} - -pub struct ConvertToU64; -impl SeqHandler for ConvertToU64 { - type Requires = u64; - fn process<F: ContFn<Self::Requires>>() -> impl Sized {} -} - -fn main() {} diff --git a/tests/crashes/127332.rs b/tests/crashes/127332.rs deleted file mode 100644 index 5c14af01cec..00000000000 --- a/tests/crashes/127332.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ known-bug: rust-lang/rust #127332 - -async fn fun() { - enum Foo { - A { x: u32 }, - } - let orig = Foo::A { x: 5 }; - Foo::A { x: 6, ..orig }; -} diff --git a/tests/run-make/emit-path-unhashed/Makefile b/tests/run-make/emit-path-unhashed/Makefile deleted file mode 100644 index 611f8578140..00000000000 --- a/tests/run-make/emit-path-unhashed/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -include ../tools.mk - -OUT=$(TMPDIR)/emit - -# --emit KIND=PATH should not affect crate hash vs --emit KIND -all: $(OUT)/a/libfoo.rlib $(OUT)/b/libfoo.rlib $(OUT)/c/libfoo.rlib \ - $(TMPDIR)/libfoo.rlib - $(RUSTC) -Zls=root $(TMPDIR)/libfoo.rlib > $(TMPDIR)/base.txt - $(RUSTC) -Zls=root $(OUT)/a/libfoo.rlib > $(TMPDIR)/a.txt - $(RUSTC) -Zls=root $(OUT)/b/libfoo.rlib > $(TMPDIR)/b.txt - $(RUSTC) -Zls=root $(OUT)/c/libfoo.rlib > $(TMPDIR)/c.txt - - diff $(TMPDIR)/base.txt $(TMPDIR)/a.txt - diff $(TMPDIR)/base.txt $(TMPDIR)/b.txt - - # Different KIND parameters do affect hash. - # diff exits 1 on difference, 2 on trouble - diff $(TMPDIR)/base.txt $(TMPDIR)/c.txt ; test "$$?" -eq 1 - -# Default output name -$(TMPDIR)/libfoo.rlib: foo.rs - $(RUSTC) --emit link foo.rs - -# Output named with -o -$(OUT)/a/libfoo.rlib: foo.rs - mkdir -p $(OUT)/a - $(RUSTC) --emit link -o $@ foo.rs - -# Output named with KIND=PATH -$(OUT)/b/libfoo.rlib: foo.rs - mkdir -p $(OUT)/b - $(RUSTC) --emit link=$@ foo.rs - -# Output multiple kinds -$(OUT)/c/libfoo.rlib: foo.rs - mkdir -p $(OUT)/c - $(RUSTC) --emit link=$@,metadata foo.rs diff --git a/tests/run-make/emit-path-unhashed/rmake.rs b/tests/run-make/emit-path-unhashed/rmake.rs new file mode 100644 index 00000000000..ce56c197588 --- /dev/null +++ b/tests/run-make/emit-path-unhashed/rmake.rs @@ -0,0 +1,34 @@ +// Specifying how rustc outputs a file can be done in different ways, such as +// the output flag or the KIND=NAME syntax. However, some of these methods used +// to result in different hashes on output files even though they yielded the +// exact same result otherwise. This was fixed in #86045, and this test checks +// that the hash is only modified when the output is made different, such as by +// adding a new output type (in this test, metadata). +// See https://github.com/rust-lang/rust/issues/86044 + +use run_make_support::{diff, fs_wrapper, rustc}; + +fn main() { + fs_wrapper::create_dir("emit"); + fs_wrapper::create_dir("emit/a"); + fs_wrapper::create_dir("emit/b"); + fs_wrapper::create_dir("emit/c"); + // The default output name. + rustc().emit("link").input("foo.rs").run(); + // The output is named with the output flag. + rustc().emit("link").output("emit/a/libfoo.rlib").input("foo.rs").run(); + // The output is named with link=NAME. + rustc().emit("link=emit/b/libfoo.rlib").input("foo.rs").run(); + // The output is named with link=NAME, with an additional kind tacked on. + rustc().emit("link=emit/c/libfoo.rlib,metadata").input("foo.rs").run(); + + let base = rustc().arg("-Zls=root").input("libfoo.rlib").run().stdout_utf8(); + let a = rustc().arg("-Zls=root").input("emit/a/libfoo.rlib").run().stdout_utf8(); + let b = rustc().arg("-Zls=root").input("emit/b/libfoo.rlib").run().stdout_utf8(); + let c = rustc().arg("-Zls=root").input("emit/c/libfoo.rlib").run().stdout_utf8(); + // Both the output flag and link=NAME methods do not modify the hash of the output file. + diff().expected_text("base", &base).actual_text("a", a).run(); + diff().expected_text("base", &base).actual_text("b", b).run(); + // However, having multiple types of outputs does modify the hash. + diff().expected_text("base", &base).actual_text("c", c).run_fail(); +} diff --git a/tests/run-make/emit-shared-files/Makefile b/tests/run-make/emit-shared-files/Makefile deleted file mode 100644 index 27c72b00368..00000000000 --- a/tests/run-make/emit-shared-files/Makefile +++ /dev/null @@ -1,46 +0,0 @@ -include ../tools.mk - -INVOCATION_ONLY = $(TMPDIR)/invocation-only -TOOLCHAIN_ONLY = $(TMPDIR)/toolchain-only -ALL_SHARED = $(TMPDIR)/all-shared - -all: invocation-only toolchain-only all-shared - -invocation-only: - $(RUSTDOC) -Z unstable-options --emit=invocation-specific --output $(INVOCATION_ONLY) --resource-suffix=-xxx --theme y.css --extend-css z.css x.rs - [ -e $(INVOCATION_ONLY)/search-index-xxx.js ] - [ -e $(INVOCATION_ONLY)/settings.html ] - [ -e $(INVOCATION_ONLY)/x/all.html ] - [ -e $(INVOCATION_ONLY)/x/index.html ] - [ -e $(INVOCATION_ONLY)/theme-xxx.css ] # generated from z.css - ! [ -e $(INVOCATION_ONLY)/storage-xxx.js ] - ! [ -e $(INVOCATION_ONLY)/SourceSerif4-It.ttf.woff2 ] - - # FIXME: this probably shouldn't have a suffix - [ -e $(INVOCATION_ONLY)/y-xxx.css ] - # FIXME: this is technically incorrect (see `write_shared`) - ! [ -e $(INVOCATION_ONLY)/main-xxx.js ] - -toolchain-only: - $(RUSTDOC) -Z unstable-options --emit=toolchain-shared-resources --output $(TOOLCHAIN_ONLY) --resource-suffix=-xxx --extend-css z.css x.rs - [ -e $(TOOLCHAIN_ONLY)/static.files/storage-*.js ] - [ -e $(TOOLCHAIN_ONLY)/static.files/SourceSerif4-It-*.ttf.woff2 ] - ! [ -e $(TOOLCHAIN_ONLY)/search-index-xxx.js ] - ! [ -e $(TOOLCHAIN_ONLY)/x/index.html ] - ! [ -e $(TOOLCHAIN_ONLY)/theme.css ] - - [ -e $(TOOLCHAIN_ONLY)/static.files/main-*.js ] - ! [ -e $(TOOLCHAIN_ONLY)/y-xxx.css ] - -all-shared: - $(RUSTDOC) -Z unstable-options --emit=toolchain-shared-resources,unversioned-shared-resources --output $(ALL_SHARED) --resource-suffix=-xxx --extend-css z.css x.rs - [ -e $(ALL_SHARED)/static.files/storage-*.js ] - [ -e $(ALL_SHARED)/static.files/SourceSerif4-It-*.ttf.woff2 ] - ! [ -e $(ALL_SHARED)/search-index-xxx.js ] - ! [ -e $(ALL_SHARED)/settings.html ] - ! [ -e $(ALL_SHARED)/x ] - ! [ -e $(ALL_SHARED)/src ] - ! [ -e $(ALL_SHARED)/theme.css ] - - [ -e $(ALL_SHARED)/static.files/main-*.js ] - ! [ -e $(ALL_SHARED)/y-xxx.css ] diff --git a/tests/run-make/emit-shared-files/rmake.rs b/tests/run-make/emit-shared-files/rmake.rs new file mode 100644 index 00000000000..33c12310246 --- /dev/null +++ b/tests/run-make/emit-shared-files/rmake.rs @@ -0,0 +1,102 @@ +// This test checks the functionality of one of rustdoc's unstable options, +// the ability to specify emit restrictions with `--emit`. +// `invocation-only` should only emit crate-specific files. +// `toolchain-only` should only emit toolchain-specific files. +// `all-shared` should only emit files that can be shared between crates. +// See https://github.com/rust-lang/rust/pull/83478 + +use run_make_support::{has_extension, has_prefix, rustdoc, shallow_find_files}; +use std::path::Path; + +fn main() { + rustdoc() + .arg("-Zunstable-options") + .arg("--emit=invocation-specific") + .output("invocation-only") + .arg("--resource-suffix=-xxx") + .args(&["--theme", "y.css"]) + .args(&["--extend-css", "z.css"]) + .input("x.rs") + .run(); + assert!(Path::new("invocation-only/search-index-xxx.js").exists()); + assert!(Path::new("invocation-only/settings.html").exists()); + assert!(Path::new("invocation-only/x/all.html").exists()); + assert!(Path::new("invocation-only/x/index.html").exists()); + assert!(Path::new("invocation-only/theme-xxx.css").exists()); // generated from z.css + assert!(!Path::new("invocation-only/storage-xxx.js").exists()); + assert!(!Path::new("invocation-only/SourceSerif4-It.ttf.woff2").exists()); + // FIXME: this probably shouldn't have a suffix + assert!(Path::new("invocation-only/y-xxx.css").exists()); + // FIXME: this is technically incorrect (see `write_shared`) + assert!(!Path::new("invocation-only/main-xxx.js").exists()); + + rustdoc() + .arg("-Zunstable-options") + .arg("--emit=toolchain-shared-resources") + .output("toolchain-only") + .arg("--resource-suffix=-xxx") + .args(&["--extend-css", "z.css"]) + .input("x.rs") + .run(); + assert_eq!( + shallow_find_files("toolchain-only/static.files", |path| { + has_prefix(path, "storage-") && has_extension(path, "js") + }) + .len(), + 1 + ); + assert_eq!( + shallow_find_files("toolchain-only/static.files", |path| { + has_prefix(path, "SourceSerif4-It-") && has_extension(path, "woff2") + }) + .len(), + 1 + ); + assert_eq!( + shallow_find_files("toolchain-only/static.files", |path| { + has_prefix(path, "main-") && has_extension(path, "js") + }) + .len(), + 1 + ); + assert!(!Path::new("toolchain-only/search-index-xxx.js").exists()); + assert!(!Path::new("toolchain-only/x/index.html").exists()); + assert!(!Path::new("toolchain-only/theme.css").exists()); + assert!(!Path::new("toolchain-only/y-xxx.css").exists()); + + rustdoc() + .arg("-Zunstable-options") + .arg("--emit=toolchain-shared-resources,unversioned-shared-resources") + .output("all-shared") + .arg("--resource-suffix=-xxx") + .args(&["--extend-css", "z.css"]) + .input("x.rs") + .run(); + assert_eq!( + shallow_find_files("all-shared/static.files", |path| { + has_prefix(path, "storage-") && has_extension(path, "js") + }) + .len(), + 1 + ); + assert_eq!( + shallow_find_files("all-shared/static.files", |path| { + has_prefix(path, "SourceSerif4-It-") && has_extension(path, "woff2") + }) + .len(), + 1 + ); + assert!(!Path::new("all-shared/search-index-xxx.js").exists()); + assert!(!Path::new("all-shared/settings.html").exists()); + assert!(!Path::new("all-shared/x").exists()); + assert!(!Path::new("all-shared/src").exists()); + assert!(!Path::new("all-shared/theme.css").exists()); + assert_eq!( + shallow_find_files("all-shared/static.files", |path| { + has_prefix(path, "main-") && has_extension(path, "js") + }) + .len(), + 1 + ); + assert!(!Path::new("all-shared/y-xxx.css").exists()); +} diff --git a/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr b/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr index 3cc35b21409..b547da7126a 100644 --- a/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr +++ b/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr @@ -1,29 +1,29 @@ -error[E0311]: the parameter type `U` may not live long enough +error[E0311]: the parameter type `T` may not live long enough --> $DIR/async-generics-and-bounds.rs:9:5 | LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; | ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | - | | the parameter type `U` must be valid for the anonymous lifetime as defined here... + | | the parameter type `T` must be valid for the anonymous lifetime as defined here... | ...so that the reference type `&(T, U)` does not outlive the data it points at | help: consider adding an explicit lifetime bound | -LL | async fn foo<'a>(&'a self) -> &'a (T, U) where T: Debug + Sized, U: Hash, U: 'a; +LL | async fn foo<'a>(&'a self) -> &'a (T, U) where T: Debug + Sized, U: Hash, T: 'a; | ++++ ++ ++ +++++++ -error[E0311]: the parameter type `T` may not live long enough +error[E0311]: the parameter type `U` may not live long enough --> $DIR/async-generics-and-bounds.rs:9:5 | LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; | ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | - | | the parameter type `T` must be valid for the anonymous lifetime as defined here... + | | the parameter type `U` must be valid for the anonymous lifetime as defined here... | ...so that the reference type `&(T, U)` does not outlive the data it points at | help: consider adding an explicit lifetime bound | -LL | async fn foo<'a>(&'a self) -> &'a (T, U) where T: Debug + Sized, U: Hash, T: 'a; +LL | async fn foo<'a>(&'a self) -> &'a (T, U) where T: Debug + Sized, U: Hash, U: 'a; | ++++ ++ ++ +++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/async-await/in-trait/async-generics.stderr b/tests/ui/async-await/in-trait/async-generics.stderr index 3b27f8fe2f0..2e29a9bcc77 100644 --- a/tests/ui/async-await/in-trait/async-generics.stderr +++ b/tests/ui/async-await/in-trait/async-generics.stderr @@ -1,29 +1,29 @@ -error[E0311]: the parameter type `U` may not live long enough +error[E0311]: the parameter type `T` may not live long enough --> $DIR/async-generics.rs:6:5 | LL | async fn foo(&self) -> &(T, U); | ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^ | | | - | | the parameter type `U` must be valid for the anonymous lifetime as defined here... + | | the parameter type `T` must be valid for the anonymous lifetime as defined here... | ...so that the reference type `&(T, U)` does not outlive the data it points at | help: consider adding an explicit lifetime bound | -LL | async fn foo<'a>(&'a self) -> &'a (T, U) where U: 'a; +LL | async fn foo<'a>(&'a self) -> &'a (T, U) where T: 'a; | ++++ ++ ++ +++++++++++ -error[E0311]: the parameter type `T` may not live long enough +error[E0311]: the parameter type `U` may not live long enough --> $DIR/async-generics.rs:6:5 | LL | async fn foo(&self) -> &(T, U); | ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^ | | | - | | the parameter type `T` must be valid for the anonymous lifetime as defined here... + | | the parameter type `U` must be valid for the anonymous lifetime as defined here... | ...so that the reference type `&(T, U)` does not outlive the data it points at | help: consider adding an explicit lifetime bound | -LL | async fn foo<'a>(&'a self) -> &'a (T, U) where T: 'a; +LL | async fn foo<'a>(&'a self) -> &'a (T, U) where U: 'a; | ++++ ++ ++ +++++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/compare-method/bad-self-type.stderr b/tests/ui/compare-method/bad-self-type.stderr index 29ebbc5dffb..a3a31f43447 100644 --- a/tests/ui/compare-method/bad-self-type.stderr +++ b/tests/ui/compare-method/bad-self-type.stderr @@ -41,7 +41,7 @@ note: type in trait LL | fn bar(self) -> Option<()>; | ^^^^^^^^^^ = note: expected signature `fn(MyFuture) -> Option<()>` - found signature `fn(MyFuture)` + found signature `fn(MyFuture) -> ()` help: change the output type to match the trait | LL | fn bar(self) -> Option<()> {} diff --git a/tests/ui/consts/offset_from_ub.rs b/tests/ui/consts/offset_from_ub.rs index 57767e96596..e71f88b8d5f 100644 --- a/tests/ui/consts/offset_from_ub.rs +++ b/tests/ui/consts/offset_from_ub.rs @@ -92,6 +92,14 @@ pub const TOO_FAR_APART2: isize = { unsafe { ptr_offset_from(ptr1, ptr2) } //~ERROR evaluation of constant value failed //~| too far before }; +pub const TOO_FAR_APART3: isize = { + let ptr1 = &0u8 as *const u8; + let ptr2 = ptr1.wrapping_offset(isize::MIN); + // The result of this would be `isize::MIN`, which *does* fit in an `isize`, but its + // absolute value does not. (Also anyway there cannot be an allocation of that size.) + unsafe { ptr_offset_from(ptr1, ptr2) } //~ERROR evaluation of constant value failed + //~| too far before +}; const WRONG_ORDER_UNSIGNED: usize = { let a = ['a', 'b', 'c']; diff --git a/tests/ui/consts/offset_from_ub.stderr b/tests/ui/consts/offset_from_ub.stderr index 65f75a6e058..7caf6247b9e 100644 --- a/tests/ui/consts/offset_from_ub.stderr +++ b/tests/ui/consts/offset_from_ub.stderr @@ -60,13 +60,19 @@ LL | unsafe { ptr_offset_from(ptr1, ptr2) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far before second error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:99:14 + --> $DIR/offset_from_ub.rs:100:14 + | +LL | unsafe { ptr_offset_from(ptr1, ptr2) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far before second + +error[E0080]: evaluation of constant value failed + --> $DIR/offset_from_ub.rs:107:14 | LL | unsafe { ptr_offset_from_unsigned(p, p.add(2) ) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer has smaller offset than second: 0 < 8 error[E0080]: evaluation of constant value failed - --> $DIR/offset_from_ub.rs:106:14 + --> $DIR/offset_from_ub.rs:114:14 | LL | unsafe { ptr_offset_from_unsigned(ptr2, ptr1) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer is too far ahead of second @@ -79,7 +85,7 @@ error[E0080]: evaluation of constant value failed note: inside `std::ptr::const_ptr::<impl *const u8>::offset_from` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `OFFSET_VERY_FAR1` - --> $DIR/offset_from_ub.rs:115:14 + --> $DIR/offset_from_ub.rs:123:14 | LL | unsafe { ptr2.offset_from(ptr1) } | ^^^^^^^^^^^^^^^^^^^^^^ @@ -92,11 +98,11 @@ error[E0080]: evaluation of constant value failed note: inside `std::ptr::const_ptr::<impl *const u8>::offset_from` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `OFFSET_VERY_FAR2` - --> $DIR/offset_from_ub.rs:121:14 + --> $DIR/offset_from_ub.rs:129:14 | LL | unsafe { ptr1.offset_from(ptr2.wrapping_offset(1)) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 13 previous errors +error: aborting due to 14 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/error-codes/E0308.stderr b/tests/ui/error-codes/E0308.stderr index bc6c5a632a1..709b3119276 100644 --- a/tests/ui/error-codes/E0308.stderr +++ b/tests/ui/error-codes/E0308.stderr @@ -5,7 +5,7 @@ LL | fn size_of<T>(); | ^ expected `usize`, found `()` | = note: expected signature `extern "rust-intrinsic" fn() -> usize` - found signature `extern "rust-intrinsic" fn()` + found signature `extern "rust-intrinsic" fn() -> ()` error: aborting due to 1 previous error diff --git a/tests/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr b/tests/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr index 06a606b09dc..584724dfe59 100644 --- a/tests/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr +++ b/tests/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr @@ -92,7 +92,7 @@ LL | extern "rust-call" fn call(self, args: ()) -> () {} | ^^^^ expected `&Foo`, found `Foo` | = note: expected signature `extern "rust-call" fn(&Foo, ()) -> _` - found signature `extern "rust-call" fn(Foo, ())` + found signature `extern "rust-call" fn(Foo, ()) -> ()` help: change the self-receiver type to match the trait | LL | extern "rust-call" fn call(&self, args: ()) -> () {} @@ -162,7 +162,7 @@ LL | extern "rust-call" fn call_mut(&self, args: ()) -> () {} | ^^^^^ types differ in mutability | = note: expected signature `extern "rust-call" fn(&mut Bar, ()) -> _` - found signature `extern "rust-call" fn(&Bar, ())` + found signature `extern "rust-call" fn(&Bar, ()) -> ()` help: change the self-receiver type to match the trait | LL | extern "rust-call" fn call_mut(&mut self, args: ()) -> () {} diff --git a/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.stderr b/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.stderr index 0b3331b040d..5000601e90f 100644 --- a/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.stderr +++ b/tests/ui/fn/fn_def_opaque_coercion_to_fn_ptr.stderr @@ -10,7 +10,7 @@ LL | x = foo::<()>; | ^^^^^^^^^ expected fn item, found a different fn item | = note: expected fn item `fn(F) -> F {bar::<F>}` - found fn item `fn(()) {foo::<()>}` + found fn item `fn(()) -> () {foo::<()>}` error[E0308]: mismatched types --> $DIR/fn_def_opaque_coercion_to_fn_ptr.rs:27:9 @@ -26,7 +26,7 @@ LL | let mut x = bar::<()>; LL | x = foo::<I>; | ^^^^^^^^ expected fn item, found a different fn item | - = note: expected fn item `fn(()) {bar::<()>}` + = note: expected fn item `fn(()) -> () {bar::<()>}` found fn item `fn(I) -> I {foo::<I>}` help: use parentheses to call this function | diff --git a/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.next.stderr b/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.next.stderr index 9b5d84b5b09..c5c4f2c4d23 100644 --- a/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.next.stderr +++ b/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.next.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `i32: Baz<Self>` is not satisfied +error[E0277]: the trait bound `<Self as Foo>::Bar<()>: Eq<i32>` is not satisfied --> $DIR/assume-gat-normalization-for-nested-goals.rs:9:30 | LL | type Bar<T>: Baz<Self> = i32; diff --git a/tests/ui/impl-trait/in-assoc-type-unconstrained.stderr b/tests/ui/impl-trait/in-assoc-type-unconstrained.stderr index e32c59a75c6..75cbe43eeb4 100644 --- a/tests/ui/impl-trait/in-assoc-type-unconstrained.stderr +++ b/tests/ui/impl-trait/in-assoc-type-unconstrained.stderr @@ -35,7 +35,7 @@ note: type in trait LL | fn method() -> Self::Ty; | ^^^^^^^^ = note: expected signature `fn() -> <() as compare_method::Trait>::Ty` - found signature `fn()` + found signature `fn() -> ()` note: this item must have the opaque type in its signature in order to be able to register hidden types --> $DIR/in-assoc-type-unconstrained.rs:22:12 | diff --git a/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr b/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr new file mode 100644 index 00000000000..d71c1768a6a --- /dev/null +++ b/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr @@ -0,0 +1,173 @@ +error[E0277]: the trait bound `F: MyFn<i32>` is not satisfied + --> $DIR/false-positive-predicate-entailment-error.rs:36:5 + | +LL | / fn autobatch<F>(self) -> impl Trait +LL | | +LL | | +LL | | +... | +LL | | where +LL | | F: Callback<Self::CallbackArg>, + | |_______________________________________^ the trait `MyFn<i32>` is not implemented for `F`, which is required by `F: Callback<i32>` + | +note: required for `F` to implement `Callback<i32>` + --> $DIR/false-positive-predicate-entailment-error.rs:14:21 + | +LL | impl<A, F: MyFn<A>> Callback<A> for F { + | ------- ^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here +help: consider further restricting this bound + | +LL | F: Callback<Self::CallbackArg> + MyFn<i32>, + | +++++++++++ + +error[E0277]: the trait bound `F: MyFn<i32>` is not satisfied + --> $DIR/false-positive-predicate-entailment-error.rs:36:30 + | +LL | fn autobatch<F>(self) -> impl Trait + | ^^^^^^^^^^ the trait `MyFn<i32>` is not implemented for `F`, which is required by `F: Callback<i32>` + | +note: required for `F` to implement `Callback<i32>` + --> $DIR/false-positive-predicate-entailment-error.rs:14:21 + | +LL | impl<A, F: MyFn<A>> Callback<A> for F { + | ------- ^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here +note: required by a bound in `<Sender as ChannelSender>::autobatch` + --> $DIR/false-positive-predicate-entailment-error.rs:43:12 + | +LL | fn autobatch<F>(self) -> impl Trait + | --------- required by a bound in this associated function +... +LL | F: Callback<Self::CallbackArg>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `<Sender as ChannelSender>::autobatch` +help: consider further restricting this bound + | +LL | F: Callback<Self::CallbackArg> + MyFn<i32>, + | +++++++++++ + +error[E0277]: the trait bound `F: MyFn<i32>` is not satisfied + --> $DIR/false-positive-predicate-entailment-error.rs:36:5 + | +LL | / fn autobatch<F>(self) -> impl Trait +LL | | +LL | | +LL | | +... | +LL | | where +LL | | F: Callback<Self::CallbackArg>, + | |_______________________________________^ the trait `MyFn<i32>` is not implemented for `F`, which is required by `F: Callback<i32>` + | +note: required for `F` to implement `Callback<i32>` + --> $DIR/false-positive-predicate-entailment-error.rs:14:21 + | +LL | impl<A, F: MyFn<A>> Callback<A> for F { + | ------- ^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider further restricting this bound + | +LL | F: Callback<Self::CallbackArg> + MyFn<i32>, + | +++++++++++ + +error[E0277]: the trait bound `F: Callback<i32>` is not satisfied + --> $DIR/false-positive-predicate-entailment-error.rs:43:12 + | +LL | F: Callback<Self::CallbackArg>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MyFn<i32>` is not implemented for `F`, which is required by `F: Callback<i32>` + | +note: required for `F` to implement `Callback<i32>` + --> $DIR/false-positive-predicate-entailment-error.rs:14:21 + | +LL | impl<A, F: MyFn<A>> Callback<A> for F { + | ------- ^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here +note: the requirement `F: Callback<i32>` appears on the `impl`'s method `autobatch` but not on the corresponding trait's method + --> $DIR/false-positive-predicate-entailment-error.rs:25:8 + | +LL | trait ChannelSender { + | ------------- in this trait +... +LL | fn autobatch<F>(self) -> impl Trait + | ^^^^^^^^^ this trait's method doesn't have the requirement `F: Callback<i32>` +help: consider further restricting this bound + | +LL | F: Callback<Self::CallbackArg> + MyFn<i32>, + | +++++++++++ + +error[E0277]: the trait bound `F: MyFn<i32>` is not satisfied + --> $DIR/false-positive-predicate-entailment-error.rs:36:30 + | +LL | fn autobatch<F>(self) -> impl Trait + | ^^^^^^^^^^ the trait `MyFn<i32>` is not implemented for `F`, which is required by `F: Callback<i32>` + | +note: required for `F` to implement `Callback<i32>` + --> $DIR/false-positive-predicate-entailment-error.rs:14:21 + | +LL | impl<A, F: MyFn<A>> Callback<A> for F { + | ------- ^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + +error[E0277]: the trait bound `F: Callback<i32>` is not satisfied + --> $DIR/false-positive-predicate-entailment-error.rs:27:12 + | +LL | F: Callback<Self::CallbackArg>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MyFn<i32>` is not implemented for `F`, which is required by `F: Callback<i32>` + | +note: required for `F` to implement `Callback<i32>` + --> $DIR/false-positive-predicate-entailment-error.rs:14:21 + | +LL | impl<A, F: MyFn<A>> Callback<A> for F { + | ------- ^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + +error[E0277]: the trait bound `F: MyFn<i32>` is not satisfied + --> $DIR/false-positive-predicate-entailment-error.rs:36:5 + | +LL | / fn autobatch<F>(self) -> impl Trait +LL | | +LL | | +LL | | +... | +LL | | where +LL | | F: Callback<Self::CallbackArg>, + | |_______________________________________^ the trait `MyFn<i32>` is not implemented for `F`, which is required by `F: Callback<i32>` + | +note: required for `F` to implement `Callback<i32>` + --> $DIR/false-positive-predicate-entailment-error.rs:14:21 + | +LL | impl<A, F: MyFn<A>> Callback<A> for F { + | ------- ^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider further restricting this bound + | +LL | F: Callback<Self::CallbackArg> + MyFn<i32>, + | +++++++++++ + +error[E0277]: the trait bound `F: MyFn<i32>` is not satisfied + --> $DIR/false-positive-predicate-entailment-error.rs:43:12 + | +LL | F: Callback<Self::CallbackArg>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MyFn<i32>` is not implemented for `F` + | +note: required by a bound in `Callback` + --> $DIR/false-positive-predicate-entailment-error.rs:10:20 + | +LL | trait Callback<A>: MyFn<A, Output = Self::Ret> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Callback` +help: consider further restricting this bound + | +LL | F: Callback<Self::CallbackArg> + MyFn<i32>, + | +++++++++++ + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.rs b/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.rs new file mode 100644 index 00000000000..59fdeab9e0a --- /dev/null +++ b/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.rs @@ -0,0 +1,51 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@[next] check-pass + +trait MyFn<T> { + type Output; +} + +trait Callback<A>: MyFn<A, Output = Self::Ret> { + type Ret; +} + +impl<A, F: MyFn<A>> Callback<A> for F { + type Ret = F::Output; +} + +struct Thing; +trait Trait {} +impl Trait for Thing {} + +trait ChannelSender { + type CallbackArg; + + fn autobatch<F>(self) -> impl Trait + where + F: Callback<Self::CallbackArg>; + //[current]~^ ERROR the trait bound `F: Callback<i32>` is not satisfied +} + +struct Sender; + +impl ChannelSender for Sender { + type CallbackArg = i32; + + fn autobatch<F>(self) -> impl Trait + //[current]~^ ERROR the trait bound `F: MyFn<i32>` is not satisfied + //[current]~| ERROR the trait bound `F: MyFn<i32>` is not satisfied + //[current]~| ERROR the trait bound `F: MyFn<i32>` is not satisfied + //[current]~| ERROR the trait bound `F: MyFn<i32>` is not satisfied + //[current]~| ERROR the trait bound `F: MyFn<i32>` is not satisfied + where + F: Callback<Self::CallbackArg>, + //[current]~^ ERROR the trait bound `F: Callback<i32>` is not satisfied + //[current]~| ERROR the trait bound `F: MyFn<i32>` is not satisfied + { + Thing + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/nested_impl_trait.rs b/tests/ui/impl-trait/nested_impl_trait.rs index 502b2af2bc6..760102794c3 100644 --- a/tests/ui/impl-trait/nested_impl_trait.rs +++ b/tests/ui/impl-trait/nested_impl_trait.rs @@ -5,7 +5,7 @@ fn fine(x: impl Into<u32>) -> impl Into<u32> { x } fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x } //~^ ERROR nested `impl Trait` is not allowed -//~| ERROR the trait bound `impl Into<u32>: Into<impl Debug>` is not satisfied +//~| ERROR the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {} //~^ ERROR nested `impl Trait` is not allowed @@ -18,7 +18,7 @@ struct X; impl X { fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x } //~^ ERROR nested `impl Trait` is not allowed - //~| ERROR the trait bound `impl Into<u32>: Into<impl Debug>` is not satisfied + //~| ERROR the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied } fn allowed_in_assoc_type() -> impl Iterator<Item=impl Fn()> { diff --git a/tests/ui/impl-trait/nested_impl_trait.stderr b/tests/ui/impl-trait/nested_impl_trait.stderr index a53312e5c0b..83d1347aff4 100644 --- a/tests/ui/impl-trait/nested_impl_trait.stderr +++ b/tests/ui/impl-trait/nested_impl_trait.stderr @@ -42,7 +42,7 @@ LL | fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {} | = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0277]: the trait bound `impl Into<u32>: Into<impl Debug>` is not satisfied +error[E0277]: the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied --> $DIR/nested_impl_trait.rs:6:46 | LL | fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x } @@ -51,7 +51,7 @@ LL | fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x } = help: the trait `Into<U>` is implemented for `T` = note: required for `impl Into<u32>` to implement `Into<impl Debug>` -error[E0277]: the trait bound `impl Into<u32>: Into<impl Debug>` is not satisfied +error[E0277]: the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied --> $DIR/nested_impl_trait.rs:19:34 | LL | fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x } diff --git a/tests/ui/impl-trait/trait_type.stderr b/tests/ui/impl-trait/trait_type.stderr index 0eb132c7a19..989779a6178 100644 --- a/tests/ui/impl-trait/trait_type.stderr +++ b/tests/ui/impl-trait/trait_type.stderr @@ -5,7 +5,7 @@ LL | fn fmt(&self, x: &str) -> () { } | ^^^^ types differ in mutability | = note: expected signature `fn(&MyType, &mut Formatter<'_>) -> Result<(), std::fmt::Error>` - found signature `fn(&MyType, &str)` + found signature `fn(&MyType, &str) -> ()` help: change the parameter type to match the trait | LL | fn fmt(&self, x: &mut Formatter<'_>) -> () { } diff --git a/tests/ui/lang-items/start_lang_item_args.missing_ret.stderr b/tests/ui/lang-items/start_lang_item_args.missing_ret.stderr index aa1b1b73bae..2672efe51c9 100644 --- a/tests/ui/lang-items/start_lang_item_args.missing_ret.stderr +++ b/tests/ui/lang-items/start_lang_item_args.missing_ret.stderr @@ -5,7 +5,7 @@ LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpi | ^ expected `isize`, found `()` | = note: expected signature `fn(fn() -> _, _, _, _) -> isize` - found signature `fn(fn() -> _, _, _, _)` + found signature `fn(fn() -> _, _, _, _) -> ()` error: aborting due to 1 previous error diff --git a/tests/ui/macros/macro-metavar-expr-concat/allowed-operations.rs b/tests/ui/macros/macro-metavar-expr-concat/allowed-operations.rs index e44eeffb01b..1acefa314aa 100644 --- a/tests/ui/macros/macro-metavar-expr-concat/allowed-operations.rs +++ b/tests/ui/macros/macro-metavar-expr-concat/allowed-operations.rs @@ -37,6 +37,16 @@ macro_rules! without_dollar_sign_is_an_ident { }; } +macro_rules! literals { + ($ident:ident) => {{ + let ${concat(_a, "_b")}: () = (); + let ${concat("_b", _a)}: () = (); + + let ${concat($ident, "_b")}: () = (); + let ${concat("_b", $ident)}: () = (); + }}; +} + fn main() { create_things!(behold); behold_separated_idents_in_a_fn(); @@ -55,4 +65,6 @@ fn main() { without_dollar_sign_is_an_ident!(_123); assert_eq!(VARident, 1); assert_eq!(VAR_123, 2); + + literals!(_hello); } diff --git a/tests/ui/macros/macro-metavar-expr-concat/raw-identifiers.rs b/tests/ui/macros/macro-metavar-expr-concat/raw-identifiers.rs index f72b9baca89..b1cb2141cc4 100644 --- a/tests/ui/macros/macro-metavar-expr-concat/raw-identifiers.rs +++ b/tests/ui/macros/macro-metavar-expr-concat/raw-identifiers.rs @@ -26,14 +26,14 @@ macro_rules! idents_11 { macro_rules! no_params { () => { let ${concat(r#abc, abc)}: () = (); - //~^ ERROR `${concat(..)}` currently does not support raw identifiers + //~^ ERROR expected identifier or string literal //~| ERROR expected pattern, found `$` let ${concat(abc, r#abc)}: () = (); - //~^ ERROR `${concat(..)}` currently does not support raw identifiers + //~^ ERROR expected identifier or string literal let ${concat(r#abc, r#abc)}: () = (); - //~^ ERROR `${concat(..)}` currently does not support raw identifiers + //~^ ERROR expected identifier or string literal }; } diff --git a/tests/ui/macros/macro-metavar-expr-concat/raw-identifiers.stderr b/tests/ui/macros/macro-metavar-expr-concat/raw-identifiers.stderr index dd525cf0801..4e11e20acc5 100644 --- a/tests/ui/macros/macro-metavar-expr-concat/raw-identifiers.stderr +++ b/tests/ui/macros/macro-metavar-expr-concat/raw-identifiers.stderr @@ -1,16 +1,16 @@ -error: `${concat(..)}` currently does not support raw identifiers +error: expected identifier or string literal --> $DIR/raw-identifiers.rs:28:22 | LL | let ${concat(r#abc, abc)}: () = (); | ^^^^^ -error: `${concat(..)}` currently does not support raw identifiers +error: expected identifier or string literal --> $DIR/raw-identifiers.rs:32:27 | LL | let ${concat(abc, r#abc)}: () = (); | ^^^^^ -error: `${concat(..)}` currently does not support raw identifiers +error: expected identifier or string literal --> $DIR/raw-identifiers.rs:35:22 | LL | let ${concat(r#abc, r#abc)}: () = (); diff --git a/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.rs b/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.rs index bf47442ea76..b2845c8d1c1 100644 --- a/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.rs +++ b/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.rs @@ -11,9 +11,6 @@ macro_rules! wrong_concat_declarations { ${concat(aaaa,)} //~^ ERROR expected identifier - ${concat(aaaa, 1)} - //~^ ERROR expected identifier - ${concat(_, aaaa)} ${concat(aaaa aaaa)} @@ -30,9 +27,6 @@ macro_rules! wrong_concat_declarations { ${concat($ex, aaaa,)} //~^ ERROR expected identifier - - ${concat($ex, aaaa, 123)} - //~^ ERROR expected identifier }; } @@ -43,8 +37,80 @@ macro_rules! dollar_sign_without_referenced_ident { }; } +macro_rules! starting_number { + ($ident:ident) => {{ + let ${concat("1", $ident)}: () = (); + //~^ ERROR `${concat(..)}` is not generating a valid identifier + }}; +} + +macro_rules! starting_valid_unicode { + ($ident:ident) => {{ + let ${concat("Ý", $ident)}: () = (); + }}; +} + +macro_rules! starting_invalid_unicode { + ($ident:ident) => {{ + let ${concat("\u{00BD}", $ident)}: () = (); + //~^ ERROR `${concat(..)}` is not generating a valid identifier + }}; +} + +macro_rules! ending_number { + ($ident:ident) => {{ + let ${concat($ident, "1")}: () = (); + }}; +} + +macro_rules! ending_valid_unicode { + ($ident:ident) => {{ + let ${concat($ident, "Ý")}: () = (); + }}; +} + +macro_rules! ending_invalid_unicode { + ($ident:ident) => {{ + let ${concat($ident, "\u{00BD}")}: () = (); + //~^ ERROR `${concat(..)}` is not generating a valid identifier + }}; +} + +macro_rules! empty { + () => {{ + let ${concat("", "")}: () = (); + //~^ ERROR `${concat(..)}` is not generating a valid identifier + }}; +} + +macro_rules! unsupported_literals { + ($ident:ident) => {{ + let ${concat(_a, 'b')}: () = (); + //~^ ERROR expected identifier or string literal + //~| ERROR expected pattern + let ${concat(_a, 1)}: () = (); + //~^ ERROR expected identifier or string literal + + let ${concat($ident, 'b')}: () = (); + //~^ ERROR expected identifier or string literal + let ${concat($ident, 1)}: () = (); + //~^ ERROR expected identifier or string literal + }}; +} + fn main() { wrong_concat_declarations!(1); dollar_sign_without_referenced_ident!(VAR); + + starting_number!(_abc); + starting_valid_unicode!(_abc); + starting_invalid_unicode!(_abc); + + ending_number!(_abc); + ending_valid_unicode!(_abc); + ending_invalid_unicode!(_abc); + unsupported_literals!(_abc); + + empty!(); } diff --git a/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.stderr b/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.stderr index b216a86d59a..2fe5842b39e 100644 --- a/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.stderr +++ b/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.stderr @@ -1,4 +1,4 @@ -error: expected identifier +error: expected identifier or string literal --> $DIR/syntax-errors.rs:5:10 | LL | ${concat()} @@ -10,59 +10,126 @@ error: `concat` must have at least two elements LL | ${concat(aaaa)} | ^^^^^^ -error: expected identifier +error: expected identifier or string literal --> $DIR/syntax-errors.rs:11:10 | LL | ${concat(aaaa,)} | ^^^^^^^^^^^^^^^ -error: expected identifier, found `1` - --> $DIR/syntax-errors.rs:14:24 - | -LL | ${concat(aaaa, 1)} - | ^ help: try removing `1` - error: expected comma - --> $DIR/syntax-errors.rs:19:10 + --> $DIR/syntax-errors.rs:16:10 | LL | ${concat(aaaa aaaa)} | ^^^^^^^^^^^^^^^^^^^ error: `concat` must have at least two elements - --> $DIR/syntax-errors.rs:22:11 + --> $DIR/syntax-errors.rs:19:11 | LL | ${concat($ex)} | ^^^^^^ error: expected comma - --> $DIR/syntax-errors.rs:28:10 + --> $DIR/syntax-errors.rs:25:10 | LL | ${concat($ex, aaaa 123)} | ^^^^^^^^^^^^^^^^^^^^^^^ -error: expected identifier - --> $DIR/syntax-errors.rs:31:10 +error: expected identifier or string literal + --> $DIR/syntax-errors.rs:28:10 | LL | ${concat($ex, aaaa,)} | ^^^^^^^^^^^^^^^^^^^^ -error: expected identifier, found `123` - --> $DIR/syntax-errors.rs:34:29 +error: expected identifier or string literal + --> $DIR/syntax-errors.rs:88:26 | -LL | ${concat($ex, aaaa, 123)} - | ^^^ help: try removing `123` +LL | let ${concat(_a, 'b')}: () = (); + | ^^^ + +error: expected identifier or string literal + --> $DIR/syntax-errors.rs:91:26 + | +LL | let ${concat(_a, 1)}: () = (); + | ^ + +error: expected identifier or string literal + --> $DIR/syntax-errors.rs:94:30 + | +LL | let ${concat($ident, 'b')}: () = (); + | ^^^ + +error: expected identifier or string literal + --> $DIR/syntax-errors.rs:96:30 + | +LL | let ${concat($ident, 1)}: () = (); + | ^ error: `${concat(..)}` currently only accepts identifiers or meta-variables as parameters - --> $DIR/syntax-errors.rs:25:19 + --> $DIR/syntax-errors.rs:22:19 | LL | ${concat($ex, aaaa)} | ^^ error: variable `foo` is not recognized in meta-variable expression - --> $DIR/syntax-errors.rs:41:30 + --> $DIR/syntax-errors.rs:35:30 | LL | const ${concat(FOO, $foo)}: i32 = 2; | ^^^ -error: aborting due to 11 previous errors +error: `${concat(..)}` is not generating a valid identifier + --> $DIR/syntax-errors.rs:42:14 + | +LL | let ${concat("1", $ident)}: () = (); + | ^^^^^^^^^^^^^^^^^^^^^ +... +LL | starting_number!(_abc); + | ---------------------- in this macro invocation + | + = note: this error originates in the macro `starting_number` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `${concat(..)}` is not generating a valid identifier + --> $DIR/syntax-errors.rs:55:14 + | +LL | let ${concat("\u{00BD}", $ident)}: () = (); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | starting_invalid_unicode!(_abc); + | ------------------------------- in this macro invocation + | + = note: this error originates in the macro `starting_invalid_unicode` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `${concat(..)}` is not generating a valid identifier + --> $DIR/syntax-errors.rs:74:14 + | +LL | let ${concat($ident, "\u{00BD}")}: () = (); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | ending_invalid_unicode!(_abc); + | ----------------------------- in this macro invocation + | + = note: this error originates in the macro `ending_invalid_unicode` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: expected pattern, found `$` + --> $DIR/syntax-errors.rs:88:13 + | +LL | let ${concat(_a, 'b')}: () = (); + | ^ expected pattern +... +LL | unsupported_literals!(_abc); + | --------------------------- in this macro invocation + | + = note: this error originates in the macro `unsupported_literals` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `${concat(..)}` is not generating a valid identifier + --> $DIR/syntax-errors.rs:81:14 + | +LL | let ${concat("", "")}: () = (); + | ^^^^^^^^^^^^^^^^ +... +LL | empty!(); + | -------- in this macro invocation + | + = note: this error originates in the macro `empty` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 18 previous errors diff --git a/tests/ui/macros/macro-metavar-expr-concat/unicode-expansion.rs b/tests/ui/macros/macro-metavar-expr-concat/unicode-expansion.rs new file mode 100644 index 00000000000..b2cfb211e2d --- /dev/null +++ b/tests/ui/macros/macro-metavar-expr-concat/unicode-expansion.rs @@ -0,0 +1,14 @@ +//@ run-pass + +#![feature(macro_metavar_expr_concat)] + +macro_rules! turn_to_page { + ($ident:ident) => { + const ${concat("Ḧ", $ident)}: i32 = 394; + }; +} + +fn main() { + turn_to_page!(P); + assert_eq!(ḦP, 394); +} diff --git a/tests/ui/macros/out-of-scope-calls-false-positives.rs b/tests/ui/macros/out-of-scope-calls-false-positives.rs new file mode 100644 index 00000000000..8d696c177e4 --- /dev/null +++ b/tests/ui/macros/out-of-scope-calls-false-positives.rs @@ -0,0 +1,10 @@ +//@ check-pass +//@ needs-asm-support + +macro_rules! mac { () => { "" } } +macro_rules! mac2 { () => { "auxiliary/issue-40469.rs" } } + +std::arch::global_asm!(mac!()); // OK +include!(mac2!()); // OK + +fn main() {} diff --git a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr index 8e4ba192d79..2c44ad2e0a4 100644 --- a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr +++ b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr @@ -190,7 +190,7 @@ error: unrecognized meta-variable expression LL | ( $( $i:ident ),* ) => { ${ aaaaaaaaaaaaaa(i) } }; | ^^^^^^^^^^^^^^ help: supported expressions are count, ignore, index and len -error: expected identifier +error: expected identifier or string literal --> $DIR/syntax-errors.rs:118:33 | LL | ( $( $i:ident ),* ) => { ${ {} } }; diff --git a/tests/ui/method-output-diff-issue-127263.rs b/tests/ui/method-output-diff-issue-127263.rs new file mode 100644 index 00000000000..85a903e2453 --- /dev/null +++ b/tests/ui/method-output-diff-issue-127263.rs @@ -0,0 +1,8 @@ +fn bar() {} +fn foo(x: i32) -> u32 { + 0 +} +fn main() { + let b: fn() -> u32 = bar; //~ ERROR mismatched types [E0308] + let f: fn(i32) = foo; //~ ERROR mismatched types [E0308] +} diff --git a/tests/ui/method-output-diff-issue-127263.stderr b/tests/ui/method-output-diff-issue-127263.stderr new file mode 100644 index 00000000000..35b86114f16 --- /dev/null +++ b/tests/ui/method-output-diff-issue-127263.stderr @@ -0,0 +1,25 @@ +error[E0308]: mismatched types + --> $DIR/method-output-diff-issue-127263.rs:6:26 + | +LL | let b: fn() -> u32 = bar; + | ----------- ^^^ expected fn pointer, found fn item + | | + | expected due to this + | + = note: expected fn pointer `fn() -> u32` + found fn item `fn() -> () {bar}` + +error[E0308]: mismatched types + --> $DIR/method-output-diff-issue-127263.rs:7:22 + | +LL | let f: fn(i32) = foo; + | ------- ^^^ expected fn pointer, found fn item + | | + | expected due to this + | + = note: expected fn pointer `fn(_) -> ()` + found fn item `fn(_) -> u32 {foo}` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.stderr b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr index fbd92f8f662..a75039b8237 100644 --- a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.stderr +++ b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2015.stderr @@ -1,5 +1,5 @@ warning: never type fallback affects this call to an `unsafe` function - --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:8:18 + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:13:18 | LL | unsafe { mem::zeroed() } | ^^^^^^^^^^^^^ @@ -10,7 +10,7 @@ LL | unsafe { mem::zeroed() } = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default warning: never type fallback affects this call to an `unsafe` function - --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:23:13 + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:30:13 | LL | core::mem::transmute(Zst) | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL | core::mem::transmute(Zst) = help: specify the type explicitly warning: never type fallback affects this union access - --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:39:18 + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:47:18 | LL | unsafe { Union { a: () }.b } | ^^^^^^^^^^^^^^^^^ @@ -30,7 +30,7 @@ LL | unsafe { Union { a: () }.b } = help: specify the type explicitly warning: never type fallback affects this raw pointer dereference - --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:49:18 + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:58:18 | LL | unsafe { *ptr::from_ref(&()).cast() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | unsafe { *ptr::from_ref(&()).cast() } = help: specify the type explicitly warning: never type fallback affects this call to an `unsafe` function - --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:67:18 + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:79:18 | LL | unsafe { internally_create(x) } | ^^^^^^^^^^^^^^^^^^^^ @@ -50,7 +50,7 @@ LL | unsafe { internally_create(x) } = help: specify the type explicitly warning: never type fallback affects this call to an `unsafe` function - --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:83:18 + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:97:18 | LL | unsafe { zeroed() } | ^^^^^^^^ @@ -60,7 +60,7 @@ LL | unsafe { zeroed() } = help: specify the type explicitly warning: never type fallback affects this `unsafe` function - --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:79:22 + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:92:22 | LL | let zeroed = mem::zeroed; | ^^^^^^^^^^^ @@ -70,7 +70,7 @@ LL | let zeroed = mem::zeroed; = help: specify the type explicitly warning: never type fallback affects this `unsafe` function - --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:98:17 + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:115:17 | LL | let f = internally_create; | ^^^^^^^^^^^^^^^^^ @@ -80,7 +80,7 @@ LL | let f = internally_create; = help: specify the type explicitly warning: never type fallback affects this call to an `unsafe` method - --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:122:13 + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:140:13 | LL | S(marker::PhantomData).create_out_of_thin_air() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -90,7 +90,7 @@ LL | S(marker::PhantomData).create_out_of_thin_air() = help: specify the type explicitly warning: never type fallback affects this call to an `unsafe` function - --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:139:19 + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:158:19 | LL | match send_message::<_ /* ?0 */>() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr new file mode 100644 index 00000000000..4138e9f8c86 --- /dev/null +++ b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.e2024.stderr @@ -0,0 +1,116 @@ +error: never type fallback affects this call to an `unsafe` function + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:13:18 + | +LL | unsafe { mem::zeroed() } + | ^^^^^^^^^^^^^ + | + = warning: this will change its meaning in a future release! + = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> + = help: specify the type explicitly + = note: `#[deny(never_type_fallback_flowing_into_unsafe)]` on by default + +error: never type fallback affects this call to an `unsafe` function + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:30:13 + | +LL | core::mem::transmute(Zst) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this will change its meaning in a future release! + = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> + = help: specify the type explicitly + +error: never type fallback affects this union access + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:47:18 + | +LL | unsafe { Union { a: () }.b } + | ^^^^^^^^^^^^^^^^^ + | + = warning: this will change its meaning in a future release! + = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> + = help: specify the type explicitly + +error: never type fallback affects this raw pointer dereference + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:58:18 + | +LL | unsafe { *ptr::from_ref(&()).cast() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this will change its meaning in a future release! + = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> + = help: specify the type explicitly + +error: never type fallback affects this call to an `unsafe` function + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:79:18 + | +LL | unsafe { internally_create(x) } + | ^^^^^^^^^^^^^^^^^^^^ + | + = warning: this will change its meaning in a future release! + = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> + = help: specify the type explicitly + +error: never type fallback affects this call to an `unsafe` function + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:97:18 + | +LL | unsafe { zeroed() } + | ^^^^^^^^ + | + = warning: this will change its meaning in a future release! + = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> + = help: specify the type explicitly + +error: never type fallback affects this `unsafe` function + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:92:22 + | +LL | let zeroed = mem::zeroed; + | ^^^^^^^^^^^ + | + = warning: this will change its meaning in a future release! + = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> + = help: specify the type explicitly + +error: never type fallback affects this `unsafe` function + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:115:17 + | +LL | let f = internally_create; + | ^^^^^^^^^^^^^^^^^ + | + = warning: this will change its meaning in a future release! + = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> + = help: specify the type explicitly + +error: never type fallback affects this call to an `unsafe` method + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:140:13 + | +LL | S(marker::PhantomData).create_out_of_thin_air() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this will change its meaning in a future release! + = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> + = help: specify the type explicitly + +error: never type fallback affects this call to an `unsafe` function + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:158:19 + | +LL | match send_message::<_ /* ?0 */>() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | msg_send!(); + | ----------- in this macro invocation + | + = warning: this will change its meaning in a future release! + = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748> + = help: specify the type explicitly + = note: this error originates in the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: the type `!` does not permit zero-initialization + --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:13:18 + | +LL | unsafe { mem::zeroed() } + | ^^^^^^^^^^^^^ this code causes undefined behavior when executed + | + = note: the `!` type has no valid value + = note: `#[warn(invalid_value)]` on by default + +error: aborting due to 10 previous errors; 1 warning emitted + diff --git a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.rs b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.rs index d65bfee843e..c96f4dda3f8 100644 --- a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.rs +++ b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.rs @@ -1,4 +1,9 @@ -//@ check-pass +//@ revisions: e2015 e2024 +//@[e2015] check-pass +//@[e2024] check-fail +//@[e2024] edition:2024 +//@[e2024] compile-flags: -Zunstable-options + use std::{marker, mem, ptr}; fn main() {} @@ -6,8 +11,10 @@ fn main() {} fn _zero() { if false { unsafe { mem::zeroed() } - //~^ warn: never type fallback affects this call to an `unsafe` function + //[e2015]~^ warn: never type fallback affects this call to an `unsafe` function + //[e2024]~^^ error: never type fallback affects this call to an `unsafe` function //~| warn: this will change its meaning in a future release! + //[e2024]~| warning: the type `!` does not permit zero-initialization } else { return; }; @@ -21,7 +28,8 @@ fn _trans() { unsafe { struct Zst; core::mem::transmute(Zst) - //~^ warn: never type fallback affects this call to an `unsafe` function + //[e2015]~^ warn: never type fallback affects this call to an `unsafe` function + //[e2024]~^^ error: never type fallback affects this call to an `unsafe` function //~| warn: this will change its meaning in a future release! } } else { @@ -37,7 +45,8 @@ fn _union() { } unsafe { Union { a: () }.b } - //~^ warn: never type fallback affects this union access + //[e2015]~^ warn: never type fallback affects this union access + //[e2024]~^^ error: never type fallback affects this union access //~| warn: this will change its meaning in a future release! } else { return; @@ -47,7 +56,8 @@ fn _union() { fn _deref() { if false { unsafe { *ptr::from_ref(&()).cast() } - //~^ warn: never type fallback affects this raw pointer dereference + //[e2015]~^ warn: never type fallback affects this raw pointer dereference + //[e2024]~^^ error: never type fallback affects this raw pointer dereference //~| warn: this will change its meaning in a future release! } else { return; @@ -57,7 +67,9 @@ fn _deref() { fn _only_generics() { if false { unsafe fn internally_create<T>(_: Option<T>) { - let _ = mem::zeroed::<T>(); + unsafe { + let _ = mem::zeroed::<T>(); + } } // We need the option (and unwrap later) to call a function in a way, @@ -65,7 +77,8 @@ fn _only_generics() { let x = None; unsafe { internally_create(x) } - //~^ warn: never type fallback affects this call to an `unsafe` function + //[e2015]~^ warn: never type fallback affects this call to an `unsafe` function + //[e2024]~^^ error: never type fallback affects this call to an `unsafe` function //~| warn: this will change its meaning in a future release! x.unwrap() @@ -77,11 +90,13 @@ fn _only_generics() { fn _stored_function() { if false { let zeroed = mem::zeroed; - //~^ warn: never type fallback affects this `unsafe` function + //[e2015]~^ warn: never type fallback affects this `unsafe` function + //[e2024]~^^ error: never type fallback affects this `unsafe` function //~| warn: this will change its meaning in a future release! unsafe { zeroed() } - //~^ warn: never type fallback affects this call to an `unsafe` function + //[e2015]~^ warn: never type fallback affects this call to an `unsafe` function + //[e2024]~^^ error: never type fallback affects this call to an `unsafe` function //~| warn: this will change its meaning in a future release! } else { return; @@ -91,12 +106,15 @@ fn _stored_function() { fn _only_generics_stored_function() { if false { unsafe fn internally_create<T>(_: Option<T>) { - let _ = mem::zeroed::<T>(); + unsafe { + let _ = mem::zeroed::<T>(); + } } let x = None; let f = internally_create; - //~^ warn: never type fallback affects this `unsafe` function + //[e2015]~^ warn: never type fallback affects this `unsafe` function + //[e2024]~^^ error: never type fallback affects this `unsafe` function //~| warn: this will change its meaning in a future release! unsafe { f(x) } @@ -120,7 +138,8 @@ fn _method() { if false { unsafe { S(marker::PhantomData).create_out_of_thin_air() - //~^ warn: never type fallback affects this call to an `unsafe` method + //[e2015]~^ warn: never type fallback affects this call to an `unsafe` method + //[e2024]~^^ error: never type fallback affects this call to an `unsafe` method //~| warn: this will change its meaning in a future release! } } else { @@ -137,7 +156,8 @@ fn _objc() { macro_rules! msg_send { () => { match send_message::<_ /* ?0 */>() { - //~^ warn: never type fallback affects this call to an `unsafe` function + //[e2015]~^ warn: never type fallback affects this call to an `unsafe` function + //[e2024]~^^ error: never type fallback affects this call to an `unsafe` function //~| warn: this will change its meaning in a future release! Ok(x) => x, Err(_) => loop {}, diff --git a/tests/ui/panic-handler/panic-handler-bad-signature-1.stderr b/tests/ui/panic-handler/panic-handler-bad-signature-1.stderr index 812f7a0692f..4fea52fec6e 100644 --- a/tests/ui/panic-handler/panic-handler-bad-signature-1.stderr +++ b/tests/ui/panic-handler/panic-handler-bad-signature-1.stderr @@ -5,7 +5,7 @@ LL | fn panic(info: PanicInfo) -> () {} | ^^^^^^^^^ expected `&PanicInfo<'_>`, found `PanicInfo<'_>` | = note: expected signature `for<'a, 'b> fn(&'a PanicInfo<'b>) -> !` - found signature `for<'a> fn(PanicInfo<'a>)` + found signature `for<'a> fn(PanicInfo<'a>) -> ()` error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.nn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.nn.stderr deleted file mode 100644 index 03536dca1e8..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.nn.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0271]: type mismatch resolving `<() as Index>::Output == &mut <() as Index>::Output` - --> $DIR/issue-100222.rs:34:12 - | -LL | fn foo(&mut self, x: <Self as Index>::Output) -> <Self as Index>::Output - | ^^^^^^^^^ expected `()`, found `&mut <() as Index>::Output` - | - = note: expected unit type `()` - found mutable reference `&mut <() as Index>::Output` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.ny.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.ny.stderr deleted file mode 100644 index 6a70a503606..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.ny.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0271]: type mismatch resolving `<() as Index>::Output == &mut <() as Index>::Output` - --> $DIR/issue-100222.rs:25:12 - | -LL | fn foo(&mut self, x: <Self as Index>::Output) -> <Self as Index>::Output - | ^^^^^^^^^ expected `()`, found `&mut <() as Index>::Output` - | - = note: expected unit type `()` - found mutable reference `&mut <() as Index>::Output` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.rs index 7949772a2b4..47f9fc664ce 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.rs @@ -1,6 +1,7 @@ //@ revisions: nn ny yn yy -//@ known-bug: #110395 //@ compile-flags: -Znext-solver +//@ check-pass + #![allow(incomplete_features)] #![feature(const_trait_impl, effects, associated_type_defaults, const_mut_refs)] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.yn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.yn.stderr deleted file mode 100644 index 03536dca1e8..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.yn.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0271]: type mismatch resolving `<() as Index>::Output == &mut <() as Index>::Output` - --> $DIR/issue-100222.rs:34:12 - | -LL | fn foo(&mut self, x: <Self as Index>::Output) -> <Self as Index>::Output - | ^^^^^^^^^ expected `()`, found `&mut <() as Index>::Output` - | - = note: expected unit type `()` - found mutable reference `&mut <() as Index>::Output` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.yy.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.yy.stderr deleted file mode 100644 index 6a70a503606..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.yy.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0271]: type mismatch resolving `<() as Index>::Output == &mut <() as Index>::Output` - --> $DIR/issue-100222.rs:25:12 - | -LL | fn foo(&mut self, x: <Self as Index>::Output) -> <Self as Index>::Output - | ^^^^^^^^^ expected `()`, found `&mut <() as Index>::Output` - | - = note: expected unit type `()` - found mutable reference `&mut <() as Index>::Output` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/traits/impl-method-mismatch.stderr b/tests/ui/traits/impl-method-mismatch.stderr index 77d542c729a..db457b77a23 100644 --- a/tests/ui/traits/impl-method-mismatch.stderr +++ b/tests/ui/traits/impl-method-mismatch.stderr @@ -10,7 +10,7 @@ note: type in trait LL | fn jumbo(&self, x: &usize) -> usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: expected signature `fn(&_, &_) -> usize` - found signature `unsafe fn(&_, &_)` + found signature `unsafe fn(&_, &_) -> ()` error: aborting due to 1 previous error diff --git a/tests/ui/traits/next-solver/auto-with-drop_tracking_mir.fail.stderr b/tests/ui/traits/next-solver/auto-with-drop_tracking_mir.fail.stderr index e0b23bd8110..c2029a5a1c8 100644 --- a/tests/ui/traits/next-solver/auto-with-drop_tracking_mir.fail.stderr +++ b/tests/ui/traits/next-solver/auto-with-drop_tracking_mir.fail.stderr @@ -17,10 +17,6 @@ note: required by a bound in `is_send` | LL | fn is_send(_: impl Send) {} | ^^^^ required by this bound in `is_send` -help: consider dereferencing here - | -LL | is_send(*foo()); - | + error: aborting due to 1 previous error diff --git a/tests/ui/traits/next-solver/typeck/receiver-self-ty-check-eq.rs b/tests/ui/traits/next-solver/typeck/receiver-self-ty-check-eq.rs new file mode 100644 index 00000000000..f8c8a17b7e5 --- /dev/null +++ b/tests/ui/traits/next-solver/typeck/receiver-self-ty-check-eq.rs @@ -0,0 +1,23 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +// Fixes a regression in `receiver_is_valid` in wfcheck where we were using +// `InferCtxt::can_eq` instead of processing alias-relate goals, leading to false +// positives, not deref'ing enough steps to check the receiver is valid. + +trait Mirror { + type Mirror: ?Sized; +} +impl<T: ?Sized> Mirror for T { + type Mirror = T; +} + +trait Foo { + fn foo(&self) {} +} + +impl Foo for <() as Mirror>::Mirror { + fn foo(&self) {} +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/method_resolution3.current.stderr b/tests/ui/type-alias-impl-trait/method_resolution3.current.stderr index e992d059daf..09efd7a9e7e 100644 --- a/tests/ui/type-alias-impl-trait/method_resolution3.current.stderr +++ b/tests/ui/type-alias-impl-trait/method_resolution3.current.stderr @@ -8,7 +8,7 @@ LL | fn bar(self: Bar<u32>) { = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) error[E0307]: invalid `self` parameter type: `&Bar<u32>` - --> $DIR/method_resolution3.rs:21:18 + --> $DIR/method_resolution3.rs:20:18 | LL | fn baz(self: &Bar<u32>) { | ^^^^^^^^^ diff --git a/tests/ui/type-alias-impl-trait/method_resolution3.next.stderr b/tests/ui/type-alias-impl-trait/method_resolution3.next.stderr index 9272017cdf5..09efd7a9e7e 100644 --- a/tests/ui/type-alias-impl-trait/method_resolution3.next.stderr +++ b/tests/ui/type-alias-impl-trait/method_resolution3.next.stderr @@ -1,15 +1,21 @@ -error[E0271]: type mismatch resolving `Foo == u32` +error[E0307]: invalid `self` parameter type: `Bar<u32>` --> $DIR/method_resolution3.rs:16:18 | LL | fn bar(self: Bar<u32>) { - | ^^^^^^^^ types differ + | ^^^^^^^^ + | + = note: type of `self` must be `Self` or a type that dereferences to it + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) -error[E0271]: type mismatch resolving `Foo == u32` - --> $DIR/method_resolution3.rs:21:18 +error[E0307]: invalid `self` parameter type: `&Bar<u32>` + --> $DIR/method_resolution3.rs:20:18 | LL | fn baz(self: &Bar<u32>) { - | ^^^^^^^^^ types differ + | ^^^^^^^^^ + | + = note: type of `self` must be `Self` or a type that dereferences to it + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0307`. diff --git a/tests/ui/type-alias-impl-trait/method_resolution3.rs b/tests/ui/type-alias-impl-trait/method_resolution3.rs index 447f3144b82..0e6176bfe03 100644 --- a/tests/ui/type-alias-impl-trait/method_resolution3.rs +++ b/tests/ui/type-alias-impl-trait/method_resolution3.rs @@ -14,13 +14,11 @@ struct Bar<T>(T); impl Bar<Foo> { fn bar(self: Bar<u32>) { - //[current]~^ ERROR: invalid `self` parameter - //[next]~^^ ERROR: type mismatch resolving `Foo == u32` + //~^ ERROR: invalid `self` parameter self.foo() } fn baz(self: &Bar<u32>) { - //[current]~^ ERROR: invalid `self` parameter - //[next]~^^ ERROR: type mismatch resolving `Foo == u32` + //~^ ERROR: invalid `self` parameter self.foo() } } diff --git a/tests/ui/type-alias-impl-trait/method_resolution4.current.stderr b/tests/ui/type-alias-impl-trait/method_resolution4.current.stderr index 3a2ca18f890..8ffdb21f251 100644 --- a/tests/ui/type-alias-impl-trait/method_resolution4.current.stderr +++ b/tests/ui/type-alias-impl-trait/method_resolution4.current.stderr @@ -8,7 +8,7 @@ LL | fn foo(self: Bar<Foo>) { = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) error[E0307]: invalid `self` parameter type: `&Bar<Foo>` - --> $DIR/method_resolution4.rs:32:20 + --> $DIR/method_resolution4.rs:31:20 | LL | fn foomp(self: &Bar<Foo>) { | ^^^^^^^^^ diff --git a/tests/ui/type-alias-impl-trait/method_resolution4.next.stderr b/tests/ui/type-alias-impl-trait/method_resolution4.next.stderr index 33ed2800ebe..8ffdb21f251 100644 --- a/tests/ui/type-alias-impl-trait/method_resolution4.next.stderr +++ b/tests/ui/type-alias-impl-trait/method_resolution4.next.stderr @@ -1,15 +1,21 @@ -error[E0271]: type mismatch resolving `u32 == Foo` +error[E0307]: invalid `self` parameter type: `Bar<Foo>` --> $DIR/method_resolution4.rs:27:18 | LL | fn foo(self: Bar<Foo>) { - | ^^^^^^^^ types differ + | ^^^^^^^^ + | + = note: type of `self` must be `Self` or a type that dereferences to it + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) -error[E0271]: type mismatch resolving `u32 == Foo` - --> $DIR/method_resolution4.rs:32:20 +error[E0307]: invalid `self` parameter type: `&Bar<Foo>` + --> $DIR/method_resolution4.rs:31:20 | LL | fn foomp(self: &Bar<Foo>) { - | ^^^^^^^^^ types differ + | ^^^^^^^^^ + | + = note: type of `self` must be `Self` or a type that dereferences to it + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0307`. diff --git a/tests/ui/type-alias-impl-trait/method_resolution4.rs b/tests/ui/type-alias-impl-trait/method_resolution4.rs index 42ed04b3c30..f33b4e473ae 100644 --- a/tests/ui/type-alias-impl-trait/method_resolution4.rs +++ b/tests/ui/type-alias-impl-trait/method_resolution4.rs @@ -25,13 +25,11 @@ impl Bar<Foo> { impl Bar<u32> { fn foo(self: Bar<Foo>) { - //[current]~^ ERROR: invalid `self` parameter - //[next]~^^ ERROR: type mismatch resolving `u32 == Foo` + //~^ ERROR: invalid `self` parameter self.bar() } fn foomp(self: &Bar<Foo>) { - //[current]~^ ERROR: invalid `self` parameter - //[next]~^^ ERROR: type mismatch resolving `u32 == Foo` + //~^ ERROR: invalid `self` parameter self.bar() } } diff --git a/tests/ui/typeck/ice-with-expr-not-struct-127332.rs b/tests/ui/typeck/ice-with-expr-not-struct-127332.rs new file mode 100644 index 00000000000..f3ea360e7e9 --- /dev/null +++ b/tests/ui/typeck/ice-with-expr-not-struct-127332.rs @@ -0,0 +1,15 @@ +// Regression test for ICE #127332 + +// Tests that we do not ICE when a with expr is +// not a struct but something else like an enum + +fn main() { + let x = || { + enum Foo { + A { x: u32 }, + } + let orig = Foo::A { x: 5 }; + Foo::A { x: 6, ..orig }; + //~^ ERROR functional record update syntax requires a struct + }; +} diff --git a/tests/ui/typeck/ice-with-expr-not-struct-127332.stderr b/tests/ui/typeck/ice-with-expr-not-struct-127332.stderr new file mode 100644 index 00000000000..446f49e8639 --- /dev/null +++ b/tests/ui/typeck/ice-with-expr-not-struct-127332.stderr @@ -0,0 +1,9 @@ +error[E0436]: functional record update syntax requires a struct + --> $DIR/ice-with-expr-not-struct-127332.rs:12:26 + | +LL | Foo::A { x: 6, ..orig }; + | ^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0436`. diff --git a/tests/ui/typeck/ptr-null-mutability-suggestions.stderr b/tests/ui/typeck/ptr-null-mutability-suggestions.stderr index b615d9fb45c..2912977a461 100644 --- a/tests/ui/typeck/ptr-null-mutability-suggestions.stderr +++ b/tests/ui/typeck/ptr-null-mutability-suggestions.stderr @@ -2,10 +2,8 @@ error[E0308]: mismatched types --> $DIR/ptr-null-mutability-suggestions.rs:9:24 | LL | expecting_null_mut(ptr::null()); - | ------------------ ^^^^^^^^^^^ - | | | - | | types differ in mutability - | | help: consider using `core::ptr::null_mut` instead: `core::ptr::null_mut()` + | ------------------ ^^^^^^^^^^^ types differ in mutability + | | | arguments to this function are incorrect | = note: expected raw pointer `*mut u8` @@ -15,6 +13,10 @@ note: function defined here | LL | fn expecting_null_mut(_: *mut u8) {} | ^^^^^^^^^^^^^^^^^^ ---------- +help: consider using `core::ptr::null_mut` instead + | +LL | expecting_null_mut(core::ptr::null_mut()); + | ~~~~~~~~~~~~~~~~~~~~~ error: aborting due to 1 previous error |
