diff options
315 files changed, 3272 insertions, 1650 deletions
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 6a0ace04d4b..b94b8c87216 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -230,7 +230,7 @@ impl AttrItem { } pub fn meta_kind(&self) -> Option<MetaItemKind> { - Some(MetaItemKind::from_mac_args(&self.args)?) + MetaItemKind::from_mac_args(&self.args) } } diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 5a85356d96d..18fcc99ffba 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -129,13 +129,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { .operands .iter() .map(|(op, op_sp)| { - let lower_reg = |reg| match reg { + let lower_reg = |reg, is_clobber| match reg { InlineAsmRegOrRegClass::Reg(s) => { asm::InlineAsmRegOrRegClass::Reg(if let Some(asm_arch) = asm_arch { asm::InlineAsmReg::parse( asm_arch, &sess.target_features, &sess.target, + is_clobber, s, ) .unwrap_or_else(|e| { @@ -162,24 +163,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let op = match *op { InlineAsmOperand::In { reg, ref expr } => hir::InlineAsmOperand::In { - reg: lower_reg(reg), + reg: lower_reg(reg, false), expr: self.lower_expr_mut(expr), }, InlineAsmOperand::Out { reg, late, ref expr } => hir::InlineAsmOperand::Out { - reg: lower_reg(reg), + reg: lower_reg(reg, expr.is_none()), late, expr: expr.as_ref().map(|expr| self.lower_expr_mut(expr)), }, InlineAsmOperand::InOut { reg, late, ref expr } => { hir::InlineAsmOperand::InOut { - reg: lower_reg(reg), + reg: lower_reg(reg, false), late, expr: self.lower_expr_mut(expr), } } InlineAsmOperand::SplitInOut { reg, late, ref in_expr, ref out_expr } => { hir::InlineAsmOperand::SplitInOut { - reg: lower_reg(reg), + reg: lower_reg(reg, false), late, in_expr: self.lower_expr_mut(in_expr), out_expr: out_expr.as_ref().map(|expr| self.lower_expr_mut(expr)), diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index 082c5bb7833..3a7e0a70585 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -97,7 +97,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let ty = l .ty .as_ref() - .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Binding))); + .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Variable))); let init = l.kind.init().map(|init| self.lower_expr(init)); let hir_id = self.lower_node_id(l.id); let pat = self.lower_pat(&l.pat); @@ -127,7 +127,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let ty = local .ty .as_ref() - .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Binding))); + .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Variable))); let span = self.lower_span(local.span); let span = self.mark_span_with_reason(DesugaringKind::LetElse, span, None); let init = self.lower_expr(init); diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 17bc8d7591b..d48ff10b97d 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1,3 +1,5 @@ +use crate::{FnDeclKind, ImplTraitPosition}; + use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs}; use rustc_ast::attr; @@ -53,7 +55,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ParamMode::Optional, 0, ParenthesizedGenericArgs::Err, - ImplTraitContext::disallowed(), + ImplTraitContext::Disallowed(ImplTraitPosition::Path), )); let args = self.lower_exprs(args); hir::ExprKind::MethodCall(hir_seg, args, self.lower_span(span)) @@ -74,12 +76,14 @@ impl<'hir> LoweringContext<'_, 'hir> { } ExprKind::Cast(ref expr, ref ty) => { let expr = self.lower_expr(expr); - let ty = self.lower_ty(ty, ImplTraitContext::disallowed()); + let ty = + self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)); hir::ExprKind::Cast(expr, ty) } ExprKind::Type(ref expr, ref ty) => { let expr = self.lower_expr(expr); - let ty = self.lower_ty(ty, ImplTraitContext::disallowed()); + let ty = + self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)); hir::ExprKind::Type(expr, ty) } ExprKind::AddrOf(k, m, ref ohs) => { @@ -203,7 +207,7 @@ impl<'hir> LoweringContext<'_, 'hir> { qself, path, ParamMode::Optional, - ImplTraitContext::disallowed(), + ImplTraitContext::Disallowed(ImplTraitPosition::Path), ); hir::ExprKind::Path(qpath) } @@ -239,7 +243,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &se.qself, &se.path, ParamMode::Optional, - ImplTraitContext::disallowed(), + ImplTraitContext::Disallowed(ImplTraitPosition::Path), )), self.arena .alloc_from_iter(se.fields.iter().map(|x| self.lower_expr_field(x))), @@ -538,7 +542,9 @@ impl<'hir> LoweringContext<'_, 'hir> { body: impl FnOnce(&mut Self) -> hir::Expr<'hir>, ) -> hir::ExprKind<'hir> { let output = match ret_ty { - Some(ty) => hir::FnRetTy::Return(self.lower_ty(&ty, ImplTraitContext::disallowed())), + Some(ty) => hir::FnRetTy::Return( + self.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock)), + ), None => hir::FnRetTy::DefaultReturn(self.lower_span(span)), }; @@ -827,7 +833,7 @@ impl<'hir> LoweringContext<'_, 'hir> { }); // Lower outside new scope to preserve `is_in_loop_condition`. - let fn_decl = self.lower_fn_decl(decl, None, false, None); + let fn_decl = self.lower_fn_decl(decl, None, FnDeclKind::Closure, None); hir::ExprKind::Closure( capture_clause, @@ -919,7 +925,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // We need to lower the declaration outside the new scope, because we // have to conserve the state of being inside a loop condition for the // closure argument types. - let fn_decl = self.lower_fn_decl(&outer_decl, None, false, None); + let fn_decl = self.lower_fn_decl(&outer_decl, None, FnDeclKind::Closure, None); hir::ExprKind::Closure( capture_clause, @@ -1064,7 +1070,7 @@ impl<'hir> LoweringContext<'_, 'hir> { qself, path, ParamMode::Optional, - ImplTraitContext::disallowed(), + ImplTraitContext::Disallowed(ImplTraitPosition::Path), ); // Destructure like a tuple struct. let tuple_struct_pat = @@ -1089,7 +1095,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &se.qself, &se.path, ParamMode::Optional, - ImplTraitContext::disallowed(), + ImplTraitContext::Disallowed(ImplTraitPosition::Path), ); let fields_omitted = match &se.rest { StructRest::Base(e) => { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index f48cf212a98..6489c729cfe 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1,6 +1,6 @@ use super::{AnonymousLifetimeMode, LoweringContext, ParamMode}; use super::{ImplTraitContext, ImplTraitPosition}; -use crate::Arena; +use crate::{Arena, FnDeclKind}; use rustc_ast::ptr::P; use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; @@ -246,7 +246,12 @@ impl<'hir> LoweringContext<'_, 'hir> { AnonymousLifetimeMode::PassThrough, |this, idty| { let ret_id = asyncness.opt_return_id(); - this.lower_fn_decl(&decl, Some((fn_def_id, idty)), true, ret_id) + this.lower_fn_decl( + &decl, + Some((fn_def_id, idty)), + FnDeclKind::Fn, + ret_id, + ) }, ); let sig = hir::FnSig { @@ -287,12 +292,18 @@ impl<'hir> LoweringContext<'_, 'hir> { capturable_lifetimes: &mut FxHashSet::default(), }, ); - let generics = self.lower_generics(generics, ImplTraitContext::disallowed()); + let generics = self.lower_generics( + generics, + ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + ); hir::ItemKind::TyAlias(ty, generics) } ItemKind::TyAlias(box TyAlias { ref generics, ty: None, .. }) => { let ty = self.arena.alloc(self.ty(span, hir::TyKind::Err)); - let generics = self.lower_generics(generics, ImplTraitContext::disallowed()); + let generics = self.lower_generics( + generics, + ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + ); hir::ItemKind::TyAlias(ty, generics) } ItemKind::Enum(ref enum_definition, ref generics) => hir::ItemKind::Enum( @@ -301,20 +312,29 @@ impl<'hir> LoweringContext<'_, 'hir> { enum_definition.variants.iter().map(|x| self.lower_variant(x)), ), }, - self.lower_generics(generics, ImplTraitContext::disallowed()), + self.lower_generics( + generics, + ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + ), ), ItemKind::Struct(ref struct_def, ref generics) => { let struct_def = self.lower_variant_data(hir_id, struct_def); hir::ItemKind::Struct( struct_def, - self.lower_generics(generics, ImplTraitContext::disallowed()), + self.lower_generics( + generics, + ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + ), ) } ItemKind::Union(ref vdata, ref generics) => { let vdata = self.lower_variant_data(hir_id, vdata); hir::ItemKind::Union( vdata, - self.lower_generics(generics, ImplTraitContext::disallowed()), + self.lower_generics( + generics, + ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + ), ) } ItemKind::Impl(box Impl { @@ -347,10 +367,14 @@ impl<'hir> LoweringContext<'_, 'hir> { AnonymousLifetimeMode::CreateParameter, |this, _| { let trait_ref = trait_ref.as_ref().map(|trait_ref| { - this.lower_trait_ref(trait_ref, ImplTraitContext::disallowed()) + this.lower_trait_ref( + trait_ref, + ImplTraitContext::Disallowed(ImplTraitPosition::Trait), + ) }); - let lowered_ty = this.lower_ty(ty, ImplTraitContext::disallowed()); + let lowered_ty = this + .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)); (trait_ref, lowered_ty) }, @@ -390,21 +414,33 @@ impl<'hir> LoweringContext<'_, 'hir> { ref bounds, ref items, }) => { - let bounds = self.lower_param_bounds(bounds, ImplTraitContext::disallowed()); + let bounds = self.lower_param_bounds( + bounds, + ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + ); let items = self .arena .alloc_from_iter(items.iter().map(|item| self.lower_trait_item_ref(item))); hir::ItemKind::Trait( is_auto, self.lower_unsafety(unsafety), - self.lower_generics(generics, ImplTraitContext::disallowed()), + self.lower_generics( + generics, + ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + ), bounds, items, ) } ItemKind::TraitAlias(ref generics, ref bounds) => hir::ItemKind::TraitAlias( - self.lower_generics(generics, ImplTraitContext::disallowed()), - self.lower_param_bounds(bounds, ImplTraitContext::disallowed()), + self.lower_generics( + generics, + ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + ), + self.lower_param_bounds( + bounds, + ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + ), ), ItemKind::MacroDef(MacroDef { ref body, macro_rules }) => { let body = P(self.lower_mac_args(body)); @@ -423,7 +459,7 @@ impl<'hir> LoweringContext<'_, 'hir> { span: Span, body: Option<&Expr>, ) -> (&'hir hir::Ty<'hir>, hir::BodyId) { - let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Binding)); + let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)); (ty, self.lower_const_body(span, body)) } @@ -667,7 +703,7 @@ impl<'hir> LoweringContext<'_, 'hir> { |this, _| { ( // Disallow `impl Trait` in foreign items. - this.lower_fn_decl(fdec, None, false, None), + this.lower_fn_decl(fdec, None, FnDeclKind::ExternFn, None), this.lower_fn_params_to_names(fdec), ) }, @@ -676,7 +712,8 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ForeignItemKind::Fn(fn_dec, fn_args, generics) } ForeignItemKind::Static(ref t, m, _) => { - let ty = self.lower_ty(t, ImplTraitContext::disallowed()); + let ty = + self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Type)); hir::ForeignItemKind::Static(ty, m) } ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type, @@ -744,11 +781,11 @@ impl<'hir> LoweringContext<'_, 'hir> { qself, path, ParamMode::ExplicitNamed, // no `'_` in declarations (Issue #61124) - ImplTraitContext::disallowed(), + ImplTraitContext::Disallowed(ImplTraitPosition::Path), ); self.arena.alloc(t) } else { - self.lower_ty(&f.ty, ImplTraitContext::disallowed()) + self.lower_ty(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)) }; let hir_id = self.lower_node_id(f.id); self.lower_attrs(hir_id, &f.attrs); @@ -771,14 +808,19 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, kind) = match i.kind { AssocItemKind::Const(_, ref ty, ref default) => { - let ty = self.lower_ty(ty, ImplTraitContext::disallowed()); + let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)); let body = default.as_ref().map(|x| self.lower_const_body(i.span, Some(x))); (hir::Generics::empty(), hir::TraitItemKind::Const(ty, body)) } AssocItemKind::Fn(box Fn { ref sig, ref generics, body: None, .. }) => { let names = self.lower_fn_params_to_names(&sig.decl); - let (generics, sig) = - self.lower_method_sig(generics, sig, trait_item_def_id, false, None); + let (generics, sig) = self.lower_method_sig( + generics, + sig, + trait_item_def_id, + FnDeclKind::Trait, + None, + ); (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names))) } AssocItemKind::Fn(box Fn { ref sig, ref generics, body: Some(ref body), .. }) => { @@ -789,16 +831,24 @@ impl<'hir> LoweringContext<'_, 'hir> { generics, sig, trait_item_def_id, - false, + FnDeclKind::Trait, asyncness.opt_return_id(), ); (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id))) } AssocItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. }) => { - let ty = ty.as_ref().map(|x| self.lower_ty(x, ImplTraitContext::disallowed())); - let generics = self.lower_generics(generics, ImplTraitContext::disallowed()); + let ty = ty.as_ref().map(|x| { + self.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Type)) + }); + let generics = self.lower_generics( + generics, + ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + ); let kind = hir::TraitItemKind::Type( - self.lower_param_bounds(bounds, ImplTraitContext::disallowed()), + self.lower_param_bounds( + bounds, + ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + ), ty, ); @@ -850,7 +900,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, kind) = match &i.kind { AssocItemKind::Const(_, ty, expr) => { - let ty = self.lower_ty(ty, ImplTraitContext::disallowed()); + let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)); ( hir::Generics::empty(), hir::ImplItemKind::Const(ty, self.lower_const_body(i.span, expr.as_deref())), @@ -861,19 +911,21 @@ impl<'hir> LoweringContext<'_, 'hir> { let asyncness = sig.header.asyncness; let body_id = self.lower_maybe_async_body(i.span, &sig.decl, asyncness, body.as_deref()); - let impl_trait_return_allow = !self.is_in_trait_impl; let (generics, sig) = self.lower_method_sig( generics, sig, impl_item_def_id, - impl_trait_return_allow, + if self.is_in_trait_impl { FnDeclKind::Impl } else { FnDeclKind::Inherent }, asyncness.opt_return_id(), ); (generics, hir::ImplItemKind::Fn(sig, body_id)) } AssocItemKind::TyAlias(box TyAlias { generics, ty, .. }) => { - let generics = self.lower_generics(generics, ImplTraitContext::disallowed()); + let generics = self.lower_generics( + generics, + ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + ); let kind = match ty { None => { let ty = self.arena.alloc(self.ty(i.span, hir::TyKind::Err)); @@ -1248,7 +1300,7 @@ impl<'hir> LoweringContext<'_, 'hir> { generics: &Generics, sig: &FnSig, fn_def_id: LocalDefId, - impl_trait_return_allow: bool, + kind: FnDeclKind, is_async: Option<NodeId>, ) -> (hir::Generics<'hir>, hir::FnSig<'hir>) { let header = self.lower_fn_header(sig.header); @@ -1256,14 +1308,7 @@ impl<'hir> LoweringContext<'_, 'hir> { generics, fn_def_id, AnonymousLifetimeMode::PassThrough, - |this, idty| { - this.lower_fn_decl( - &sig.decl, - Some((fn_def_id, idty)), - impl_trait_return_allow, - is_async, - ) - }, + |this, idty| this.lower_fn_decl(&sig.decl, Some((fn_def_id, idty)), kind, is_async), ); (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) }) } @@ -1409,11 +1454,19 @@ impl<'hir> LoweringContext<'_, 'hir> { span, }) => self.with_in_scope_lifetime_defs(&bound_generic_params, |this| { hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { - bound_generic_params: this - .lower_generic_params(bound_generic_params, ImplTraitContext::disallowed()), - bounded_ty: this.lower_ty(bounded_ty, ImplTraitContext::disallowed()), + bound_generic_params: this.lower_generic_params( + bound_generic_params, + ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + ), + bounded_ty: this.lower_ty( + bounded_ty, + ImplTraitContext::Disallowed(ImplTraitPosition::Type), + ), bounds: this.arena.alloc_from_iter(bounds.iter().map(|bound| { - this.lower_param_bound(bound, ImplTraitContext::disallowed()) + this.lower_param_bound( + bound, + ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + ) })), span: this.lower_span(span), }) @@ -1425,13 +1478,18 @@ impl<'hir> LoweringContext<'_, 'hir> { }) => hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate { span: self.lower_span(span), lifetime: self.lower_lifetime(lifetime), - bounds: self.lower_param_bounds(bounds, ImplTraitContext::disallowed()), + bounds: self.lower_param_bounds( + bounds, + ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + ), }), WherePredicate::EqPredicate(WhereEqPredicate { id, ref lhs_ty, ref rhs_ty, span }) => { hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { hir_id: self.lower_node_id(id), - lhs_ty: self.lower_ty(lhs_ty, ImplTraitContext::disallowed()), - rhs_ty: self.lower_ty(rhs_ty, ImplTraitContext::disallowed()), + lhs_ty: self + .lower_ty(lhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)), + rhs_ty: self + .lower_ty(rhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)), span: self.lower_span(span), }) } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 60b5aeb52b1..ae7f22923df 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -256,19 +256,28 @@ enum ImplTraitContext<'b, 'a> { /// Position in which `impl Trait` is disallowed. #[derive(Debug, Copy, Clone, PartialEq, Eq)] enum ImplTraitPosition { - /// Disallowed in `let` / `const` / `static` bindings. - Binding, - - /// All other positions. - Other, + Path, + Variable, + Type, + Trait, + AsyncBlock, + Bound, + Generic, + ExternFnParam, + ClosureParam, + PointerParam, + FnTraitParam, + TraitParam, + ImplParam, + ExternFnReturn, + ClosureReturn, + PointerReturn, + FnTraitReturn, + TraitReturn, + ImplReturn, } impl<'a> ImplTraitContext<'_, 'a> { - #[inline] - fn disallowed() -> Self { - ImplTraitContext::Disallowed(ImplTraitPosition::Other) - } - fn reborrow<'this>(&'this mut self) -> ImplTraitContext<'this, 'a> { use self::ImplTraitContext::*; match self { @@ -284,6 +293,54 @@ impl<'a> ImplTraitContext<'_, 'a> { } } +impl std::fmt::Display for ImplTraitPosition { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let name = match self { + ImplTraitPosition::Path => "path", + ImplTraitPosition::Variable => "variable binding", + ImplTraitPosition::Type => "type", + ImplTraitPosition::Trait => "trait", + ImplTraitPosition::AsyncBlock => "async block", + ImplTraitPosition::Bound => "bound", + ImplTraitPosition::Generic => "generic", + ImplTraitPosition::ExternFnParam => "`extern fn` param", + ImplTraitPosition::ClosureParam => "closure param", + ImplTraitPosition::PointerParam => "`fn` pointer param", + ImplTraitPosition::FnTraitParam => "`Fn` trait param", + ImplTraitPosition::TraitParam => "trait method param", + ImplTraitPosition::ImplParam => "`impl` method param", + ImplTraitPosition::ExternFnReturn => "`extern fn` return", + ImplTraitPosition::ClosureReturn => "closure return", + ImplTraitPosition::PointerReturn => "`fn` pointer return", + ImplTraitPosition::FnTraitReturn => "`Fn` trait return", + ImplTraitPosition::TraitReturn => "trait method return", + ImplTraitPosition::ImplReturn => "`impl` method return", + }; + + write!(f, "{}", name) + } +} + +#[derive(Debug)] +enum FnDeclKind { + Fn, + Inherent, + ExternFn, + Closure, + Pointer, + Trait, + Impl, +} + +impl FnDeclKind { + fn impl_trait_return_allowed(&self) -> bool { + match self { + FnDeclKind::Fn | FnDeclKind::Inherent => true, + _ => false, + } + } +} + pub fn lower_crate<'a, 'hir>( sess: &'a Session, krate: &'a Crate, @@ -1232,11 +1289,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy { generic_params: this.lower_generic_params( &f.generic_params, - ImplTraitContext::disallowed(), + ImplTraitContext::Disallowed(ImplTraitPosition::Generic), ), unsafety: this.lower_unsafety(f.unsafety), abi: this.lower_extern(f.ext), - decl: this.lower_fn_decl(&f.decl, None, false, None), + decl: this.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None), param_names: this.lower_fn_params_to_names(&f.decl), })) }) @@ -1357,13 +1414,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }), )) } - ImplTraitContext::Disallowed(_) => { + ImplTraitContext::Disallowed(position) => { let mut err = struct_span_err!( self.sess, t.span, E0562, - "`impl Trait` not allowed outside of {}", - "function and method return types", + "`impl Trait` only allowed in function and inherent method return types, not in {}", + position ); err.emit(); hir::TyKind::Err @@ -1528,16 +1585,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, decl: &FnDecl, mut in_band_ty_params: Option<(LocalDefId, &mut Vec<hir::GenericParam<'hir>>)>, - impl_trait_return_allow: bool, + kind: FnDeclKind, make_ret_async: Option<NodeId>, ) -> &'hir hir::FnDecl<'hir> { debug!( "lower_fn_decl(\ fn_decl: {:?}, \ in_band_ty_params: {:?}, \ - impl_trait_return_allow: {}, \ + kind: {:?}, \ make_ret_async: {:?})", - decl, in_band_ty_params, impl_trait_return_allow, make_ret_async, + decl, in_band_ty_params, kind, make_ret_async, ); let lt_mode = if make_ret_async.is_some() { // In `async fn`, argument-position elided lifetimes @@ -1567,7 +1624,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ImplTraitContext::Universal(ibty, this.current_hir_id_owner), ) } else { - this.lower_ty_direct(¶m.ty, ImplTraitContext::disallowed()) + this.lower_ty_direct( + ¶m.ty, + ImplTraitContext::Disallowed(match kind { + FnDeclKind::Fn | FnDeclKind::Inherent => { + unreachable!("fn should allow in-band lifetimes") + } + FnDeclKind::ExternFn => ImplTraitPosition::ExternFnParam, + FnDeclKind::Closure => ImplTraitPosition::ClosureParam, + FnDeclKind::Pointer => ImplTraitPosition::PointerParam, + FnDeclKind::Trait => ImplTraitPosition::TraitParam, + FnDeclKind::Impl => ImplTraitPosition::ImplParam, + }), + ) } })) }); @@ -1582,13 +1651,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { match decl.output { FnRetTy::Ty(ref ty) => { let context = match in_band_ty_params { - Some((def_id, _)) if impl_trait_return_allow => { + Some((def_id, _)) if kind.impl_trait_return_allowed() => { ImplTraitContext::ReturnPositionOpaqueTy { fn_def_id: def_id, origin: hir::OpaqueTyOrigin::FnReturn(def_id), } } - _ => ImplTraitContext::disallowed(), + _ => ImplTraitContext::Disallowed(match kind { + FnDeclKind::Fn | FnDeclKind::Inherent => { + unreachable!("fn should allow in-band lifetimes") + } + FnDeclKind::ExternFn => ImplTraitPosition::ExternFnReturn, + FnDeclKind::Closure => ImplTraitPosition::ClosureReturn, + FnDeclKind::Pointer => ImplTraitPosition::PointerReturn, + FnDeclKind::Trait => ImplTraitPosition::TraitReturn, + FnDeclKind::Impl => ImplTraitPosition::ImplReturn, + }), }; hir::FnRetTy::Return(self.lower_ty(ty, context)) } @@ -1659,12 +1737,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // When we create the opaque type for this async fn, it is going to have // to capture all the lifetimes involved in the signature (including in the - // return type). This is done by: + // return type). This is done by introducing lifetime parameters for: // - // - making the opaque type inherit all lifetime parameters from its parent; - // - make all the elided lifetimes in the fn arguments into parameters; - // - manually introducing parameters on the opaque type for elided - // lifetimes in the return type. + // - all the explicitly declared lifetimes from the impl and function itself; + // - all the elided lifetimes in the fn arguments; + // - all the elided lifetimes in the return type. // // So for example in this snippet: // @@ -1680,14 +1757,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // we would create an opaque type like: // // ``` - // type Foo<'a>::bar<'b, '0, '1>::Bar<'2> = impl Future<Output = &'2 u32>; + // type Bar<'a, 'b, '0, '1, '2> = impl Future<Output = &'2 u32>; // ``` // // and we would then desugar `bar` to the equivalent of: // // ```rust // impl<'a> Foo<'a> { - // fn bar<'b, '0, '1>(&'0 self, x: &'b Vec<f64>, y: &'1 str) -> Bar<'_> + // fn bar<'b, '0, '1>(&'0 self, x: &'b Vec<f64>, y: &'1 str) -> Bar<'a, 'b, '0, '1, '_> // } // ``` // @@ -1695,7 +1772,29 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // this is because the elided lifetimes from the return type // should be figured out using the ordinary elision rules, and // this desugaring achieves that. - let mut lifetime_params = Vec::new(); + + debug!("lower_async_fn_ret_ty: in_scope_lifetimes={:#?}", self.in_scope_lifetimes); + debug!("lower_async_fn_ret_ty: lifetimes_to_define={:#?}", self.lifetimes_to_define); + + // Calculate all the lifetimes that should be captured + // by the opaque type. This should include all in-scope + // lifetime parameters, including those defined in-band. + // + // `lifetime_params` is a vector of tuple (span, parameter name, lifetime name). + + // Input lifetime like `'a` or `'1`: + let mut lifetime_params: Vec<_> = self + .in_scope_lifetimes + .iter() + .cloned() + .map(|name| (name.ident().span, name, hir::LifetimeName::Param(name))) + .chain( + self.lifetimes_to_define + .iter() + .map(|&(span, name)| (span, name, hir::LifetimeName::Param(name))), + ) + .collect(); + self.with_hir_id_owner(opaque_ty_node_id, |this| { // We have to be careful to get elision right here. The // idea is that we create a lifetime parameter for each @@ -1714,12 +1813,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { debug!("lower_async_fn_ret_ty: future_bound={:#?}", future_bound); debug!("lower_async_fn_ret_ty: lifetimes_to_define={:#?}", lifetimes_to_define); - // Output lifetime like `'_`: - lifetime_params = lifetimes_to_define; + lifetime_params.extend( + // Output lifetime like `'_`: + lifetimes_to_define + .into_iter() + .map(|(span, name)| (span, name, hir::LifetimeName::Implicit(false))), + ); debug!("lower_async_fn_ret_ty: lifetime_params={:#?}", lifetime_params); let generic_params = - this.arena.alloc_from_iter(lifetime_params.iter().map(|&(span, hir_name)| { + this.arena.alloc_from_iter(lifetime_params.iter().map(|&(span, hir_name, _)| { this.lifetime_to_generic_param(span, hir_name, opaque_ty_def_id) })); @@ -1737,22 +1840,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { this.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span) }); - // We need to create the lifetime arguments to our opaque type. - // Continuing with our example, we're creating the type arguments - // for the return type: + // As documented above on the variable + // `input_lifetimes_count`, we need to create the lifetime + // arguments to our opaque type. Continuing with our example, + // we're creating the type arguments for the return type: // // ``` - // For<'a>::bar<'b, '0, '1>::Bar<'_> + // Bar<'a, 'b, '0, '1, '_> // ``` // - // For the "input" lifetime parameters are inherited automatically. - // For the "output" lifetime parameters, we just want to generate `'_`. + // For the "input" lifetime parameters, we wish to create + // references to the parameters themselves, including the + // "implicit" ones created from parameter types (`'a`, `'b`, + // '`0`, `'1`). + // + // For the "output" lifetime parameters, we just want to + // generate `'_`. let generic_args = - self.arena.alloc_from_iter(lifetime_params.into_iter().map(|(span, _)| { + self.arena.alloc_from_iter(lifetime_params.into_iter().map(|(span, _, name)| { GenericArg::Lifetime(hir::Lifetime { hir_id: self.next_id(), span: self.lower_span(span), - name: hir::LifetimeName::Implicit(false), + name, }) })); @@ -1915,7 +2024,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { GenericParamKind::Type { ref default, .. } => { let kind = hir::GenericParamKind::Type { default: default.as_ref().map(|x| { - self.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Other)) + self.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Type)) }), synthetic: false, }; @@ -1923,9 +2032,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { (hir::ParamName::Plain(self.lower_ident(param.ident)), kind) } GenericParamKind::Const { ref ty, kw_span: _, ref default } => { - let ty = self - .with_anonymous_lifetime_mode(AnonymousLifetimeMode::ReportError, |this| { - this.lower_ty(&ty, ImplTraitContext::disallowed()) + let ty = + self.with_anonymous_lifetime_mode(AnonymousLifetimeMode::ReportError, |this| { + this.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)) }); let default = default.as_ref().map(|def| self.lower_anon_const(def)); ( diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index ebae7798433..2c331767b89 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -1,3 +1,5 @@ +use crate::ImplTraitPosition; + use super::{ImplTraitContext, LoweringContext, ParamMode}; use rustc_ast::ptr::P; @@ -33,7 +35,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself, path, ParamMode::Optional, - ImplTraitContext::disallowed(), + ImplTraitContext::Disallowed(ImplTraitPosition::Path), ); let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct"); break hir::PatKind::TupleStruct(qpath, pats, ddpos); @@ -49,7 +51,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself, path, ParamMode::Optional, - ImplTraitContext::disallowed(), + ImplTraitContext::Disallowed(ImplTraitPosition::Path), ); break hir::PatKind::Path(qpath); } @@ -59,7 +61,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself, path, ParamMode::Optional, - ImplTraitContext::disallowed(), + ImplTraitContext::Disallowed(ImplTraitPosition::Path), ); let fs = self.arena.alloc_from_iter(fields.iter().map(|f| hir::PatField { diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 79262235cd9..b35e3a07161 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -1,3 +1,5 @@ +use crate::ImplTraitPosition; + use super::{AnonymousLifetimeMode, ImplTraitContext, LoweringContext, ParamMode}; use super::{GenericArgsCtor, ParenthesizedGenericArgs}; @@ -184,7 +186,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { param_mode, 0, ParenthesizedGenericArgs::Err, - ImplTraitContext::disallowed(), + ImplTraitContext::Disallowed(ImplTraitPosition::Path), ) })), span: self.lower_span(p.span), @@ -392,11 +394,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // we generally don't permit such things (see #51008). self.with_anonymous_lifetime_mode(AnonymousLifetimeMode::PassThrough, |this| { let ParenthesizedArgs { span, inputs, inputs_span, output } = data; - let inputs = this.arena.alloc_from_iter( - inputs.iter().map(|ty| this.lower_ty_direct(ty, ImplTraitContext::disallowed())), - ); + let inputs = this.arena.alloc_from_iter(inputs.iter().map(|ty| { + this.lower_ty_direct( + ty, + ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam), + ) + })); let output_ty = match output { - FnRetTy::Ty(ty) => this.lower_ty(&ty, ImplTraitContext::disallowed()), + FnRetTy::Ty(ty) => this + .lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn)), FnRetTy::Default(_) => this.arena.alloc(this.ty_tup(*span, &[])), }; let args = smallvec![GenericArg::Type(this.ty_tup(*inputs_span, inputs))]; diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 0a96e60d4d3..6c44fb0df23 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -823,7 +823,7 @@ fn maybe_stage_features(sess: &Session, krate: &ast::Crate) { ); let mut all_stable = true; for ident in - attr.meta_item_list().into_iter().flatten().map(|nested| nested.ident()).flatten() + attr.meta_item_list().into_iter().flatten().flat_map(|nested| nested.ident()) { let name = ident.name; let stable_since = lang_features diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index dca7f5dd487..49043e9f5f9 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -1,10 +1,13 @@ //! Parsing and validation of builtin attributes -use rustc_ast::{self as ast, Attribute, Lit, LitKind, MetaItem, MetaItemKind, NestedMetaItem}; +use rustc_ast as ast; +use rustc_ast::node_id::CRATE_NODE_ID; +use rustc_ast::{Attribute, Lit, LitKind, MetaItem, MetaItemKind, NestedMetaItem}; use rustc_ast_pretty::pprust; use rustc_errors::{struct_span_err, Applicability}; use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg}; use rustc_macros::HashStable_Generic; +use rustc_session::lint::builtin::UNEXPECTED_CFGS; use rustc_session::parse::{feature_err, ParseSess}; use rustc_session::Session; use rustc_span::hygiene::Transparency; @@ -458,8 +461,30 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat true } MetaItemKind::NameValue(..) | MetaItemKind::Word => { - let ident = cfg.ident().expect("multi-segment cfg predicate"); - sess.config.contains(&(ident.name, cfg.value_str())) + let name = cfg.ident().expect("multi-segment cfg predicate").name; + let value = cfg.value_str(); + if sess.check_config.names_checked && !sess.check_config.names_valid.contains(&name) + { + sess.buffer_lint( + UNEXPECTED_CFGS, + cfg.span, + CRATE_NODE_ID, + "unexpected `cfg` condition name", + ); + } + if let Some(val) = value { + if sess.check_config.values_checked.contains(&name) + && !sess.check_config.values_valid.contains(&(name, val)) + { + sess.buffer_lint( + UNEXPECTED_CFGS, + cfg.span, + CRATE_NODE_ID, + "unexpected `cfg` condition value", + ); + } + } + sess.config.contains(&(name, value)) } } }) diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 904a8a22e01..2a906e41b8c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -142,11 +142,9 @@ trait TypeOpInfo<'tcx> { let tcx = mbcx.infcx.tcx; let base_universe = self.base_universe(); - let adjusted_universe = if let Some(adjusted) = + let Some(adjusted_universe) = placeholder.universe.as_u32().checked_sub(base_universe.as_u32()) - { - adjusted - } else { + else { mbcx.buffer_error(self.fallback_error(tcx, cause.span)); return; }; diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 5da2021e711..73b0d398285 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -867,15 +867,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { kind: TerminatorKind::Call { fn_span, from_hir_call, .. }, .. }) = &self.body[location.block].terminator { - let (method_did, method_substs) = if let Some(info) = + let Some((method_did, method_substs)) = rustc_const_eval::util::find_self_call( self.infcx.tcx, &self.body, target_temp, location.block, - ) { - info - } else { + ) + else { return normal_ret; }; diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 5963904aa0b..7d0dde53c2b 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -639,11 +639,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let hir_map = self.infcx.tcx.hir(); let my_def = self.body.source.def_id(); let my_hir = hir_map.local_def_id_to_hir_id(my_def.as_local().unwrap()); - let td = if let Some(a) = + let Some(td) = self.infcx.tcx.impl_of_method(my_def).and_then(|x| self.infcx.tcx.trait_id_of_impl(x)) - { - a - } else { + else { return (false, None); }; ( diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index ca1e77ff8fd..e6a323d676e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -5,6 +5,7 @@ use rustc_infer::infer::{ error_reporting::nice_region_error::NiceRegionError, error_reporting::unexpected_hidden_region_diagnostic, NllRegionVariableOrigin, }; +use rustc_middle::hir::place::PlaceBase; use rustc_middle::mir::{ConstraintCategory, ReturnConstraint}; use rustc_middle::ty::subst::{InternalSubsts, Subst}; use rustc_middle::ty::{self, RegionVid, Ty}; @@ -421,17 +422,26 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { diag.span_label(*span, message); - // FIXME(project-rfc-2229#48): This should store a captured_place not a hir id - if let ReturnConstraint::ClosureUpvar(upvar) = kind { + if let ReturnConstraint::ClosureUpvar(upvar_field) = kind { let def_id = match self.regioncx.universal_regions().defining_ty { DefiningTy::Closure(def_id, _) => def_id, ty => bug!("unexpected DefiningTy {:?}", ty), }; - let upvar_def_span = self.infcx.tcx.hir().span(upvar); - let upvar_span = self.infcx.tcx.upvars_mentioned(def_id).unwrap()[&upvar].span; - diag.span_label(upvar_def_span, "variable defined here"); - diag.span_label(upvar_span, "variable captured here"); + let captured_place = &self.upvars[upvar_field.index()].place; + let defined_hir = match captured_place.place.base { + PlaceBase::Local(hirid) => Some(hirid), + PlaceBase::Upvar(upvar) => Some(upvar.var_path.hir_id), + _ => None, + }; + + if defined_hir.is_some() { + let upvars_map = self.infcx.tcx.upvars_mentioned(def_id).unwrap(); + let upvar_def_span = self.infcx.tcx.hir().span(defined_hir.unwrap()); + let upvar_span = upvars_map.get(&defined_hir.unwrap()).unwrap().span; + diag.span_label(upvar_def_span, "variable defined here"); + diag.span_label(upvar_span, "variable captured here"); + } } if let Some(fr_span) = self.give_region_a_name(*outlived_fr).unwrap().span() { diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index dee47a3e440..abd6a15334c 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -2156,24 +2156,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } - // When in async fn, prefer errors that come from inside the closure. - if !categorized_path[i].from_closure { - let span = categorized_path.iter().find_map(|p| { - if p.from_closure - && p.category == categorized_path[i].category - && categorized_path[i].cause.span.contains(p.cause.span) - { - Some(p.cause.span) - } else { - None - } - }); - - if let Some(span) = span { - categorized_path[i].cause.span = span; - } - } - return categorized_path[i].clone(); } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 46924f50d2e..a5824090096 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -2530,9 +2530,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { body, ); let category = if let Some(field) = field { - let var_hir_id = self.borrowck_context.upvars[field.index()].place.get_root_variable(); - // FIXME(project-rfc-2229#8): Use Place for better diagnostics - ConstraintCategory::ClosureUpvar(var_hir_id) + ConstraintCategory::ClosureUpvar(field) } else { ConstraintCategory::Boring }; diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs index eb08170959b..c06af5206d5 100644 --- a/compiler/rustc_builtin_macros/src/concat_bytes.rs +++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs @@ -6,9 +6,7 @@ use rustc_expand::base::{self, DummyResult}; /// Emits errors for literal expressions that are invalid inside and outside of an array. fn invalid_type_err(cx: &mut base::ExtCtxt<'_>, expr: &P<rustc_ast::Expr>, is_nested: bool) { - let lit = if let ast::ExprKind::Lit(lit) = &expr.kind { - lit - } else { + let ast::ExprKind::Lit(lit) = &expr.kind else { unreachable!(); }; match lit.kind { diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 0289acac606..38877399943 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -9,6 +9,7 @@ #![feature(decl_macro)] #![feature(is_sorted)] #![feature(nll)] +#![feature(let_else)] #![feature(proc_macro_internals)] #![feature(proc_macro_quote)] #![recursion_limit = "256"] diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index 6f61e4cba07..c9dd114047b 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -56,7 +56,6 @@ pub fn inject( is_proc_macro_crate: bool, has_proc_macro_decls: bool, is_test_crate: bool, - num_crate_types: usize, handler: &rustc_errors::Handler, ) -> ast::Crate { let ecfg = ExpansionConfig::default("proc_macro".to_string()); @@ -81,10 +80,6 @@ pub fn inject( return krate; } - if num_crate_types > 1 { - handler.err("cannot mix `proc-macro` crate type with others"); - } - if is_test_crate { return krate; } diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 9459bb7047f..69087962405 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -6,6 +6,7 @@ use rustc_ast as ast; use rustc_ast::attr; use rustc_ast::ptr::P; use rustc_ast_pretty::pprust; +use rustc_errors::Applicability; use rustc_expand::base::*; use rustc_session::Session; use rustc_span::symbol::{sym, Ident, Symbol}; @@ -102,11 +103,20 @@ pub fn expand_test_or_bench( } }; - if let ast::ItemKind::MacCall(_) = item.kind { - cx.sess.parse_sess.span_diagnostic.span_warn( - item.span, - "`#[test]` attribute should not be used on macros. Use `#[cfg(test)]` instead.", - ); + // Note: non-associated fn items are already handled by `expand_test_or_bench` + if !matches!(item.kind, ast::ItemKind::Fn(_)) { + cx.sess + .parse_sess + .span_diagnostic + .struct_span_err( + attr_sp, + "the `#[test]` attribute may only be used on a non-associated function", + ) + .note("the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions") + .span_label(item.span, format!("expected a non-associated function, found {} {}", item.kind.article(), item.kind.descr())) + .span_suggestion(attr_sp, "replace with conditional compilation to make the item only exist when tests are being run", String::from("#[cfg(test)]"), Applicability::MaybeIncorrect) + .emit(); + return vec![Annotatable::Item(item)]; } @@ -466,7 +476,7 @@ fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool { (false, _) => true, } } else { - sd.span_err(i.span, "only functions may be used as tests"); + // should be unreachable because `is_test_fn_item` should catch all non-fn items false } } diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 30a52d6bd67..f6d7221d4e9 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -55,6 +55,19 @@ pub fn sanitize<'ll>(cx: &CodegenCx<'ll, '_>, no_sanitize: SanitizerSet, llfn: & if enabled.contains(SanitizerSet::HWADDRESS) { llvm::Attribute::SanitizeHWAddress.apply_llfn(Function, llfn); } + if enabled.contains(SanitizerSet::MEMTAG) { + // Check to make sure the mte target feature is actually enabled. + let sess = cx.tcx.sess; + let features = llvm_util::llvm_global_features(sess).join(","); + let mte_feature_enabled = features.rfind("+mte"); + let mte_feature_disabled = features.rfind("-mte"); + + if mte_feature_enabled.is_none() || (mte_feature_disabled > mte_feature_enabled) { + sess.err("`-Zsanitizer=memtag` requires `-Ctarget-feature=+mte`"); + } + + llvm::Attribute::SanitizeMemTag.apply_llfn(Function, llfn); + } } /// Tell LLVM to emit or not emit the information necessary to unwind the stack for the function. diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index ec68f6eb0f8..90ddf791450 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -292,7 +292,7 @@ pub unsafe fn create_module<'ll>( "sign-return-address-all\0".as_ptr().cast(), pac_opts.leaf.into(), ); - let is_bkey = if pac_opts.key == PAuthKey::A { false } else { true }; + let is_bkey: bool = pac_opts.key != PAuthKey::A; llvm::LLVMRustAddModuleFlag( llmod, llvm::LLVMModFlagBehavior::Error, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs index 6dd0d58efe3..acd032a7dc6 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs @@ -6,7 +6,7 @@ use super::CrateDebugContext; use rustc_hir::def_id::DefId; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, DefIdTree, Ty}; -use rustc_target::abi::VariantIdx; +use rustc_target::abi::Variants; use crate::common::CodegenCx; use crate::llvm; @@ -72,20 +72,15 @@ pub(crate) fn fat_pointer_kind<'ll, 'tcx>( match *pointee_ty.kind() { ty::Str | ty::Slice(_) => Some(FatPtrKind::Slice), ty::Dynamic(..) => Some(FatPtrKind::Dyn), - ty::Adt(adt_def, _) => { - assert!(adt_def.is_struct()); - assert!(adt_def.variants.len() == 1); - let variant = &adt_def.variants[VariantIdx::from_usize(0)]; - assert!(!variant.fields.is_empty()); - let last_field_index = variant.fields.len() - 1; - + ty::Adt(..) | ty::Tuple(..) if matches!(layout.variants, Variants::Single { .. }) => { + let last_field_index = layout.fields.count() - 1; debug_assert!( (0..last_field_index) .all(|field_index| { !layout.field(cx, field_index).is_unsized() }) ); let unsized_field = layout.field(cx, last_field_index); - assert!(unsized_field.is_unsized()); + debug_assert!(unsized_field.is_unsized()); fat_pointer_kind(cx, unsized_field.ty) } ty::Foreign(_) => { diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 90d4367a280..657f1fcf31e 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -190,6 +190,7 @@ pub enum Attribute { StackProtectStrong = 31, StackProtect = 32, NoUndef = 33, + SanitizeMemTag = 34, } /// LLVMIntPredicate diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index 81d0603bc52..fafb9a6dbde 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -330,7 +330,9 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { ty::Ref(..) | ty::RawPtr(_) => { return self.field(cx, index).llvm_type(cx); } - ty::Adt(def, _) if def.is_box() => { + // only wide pointer boxes are handled as pointers + // thin pointer boxes with scalar allocators are handled by the general logic below + ty::Adt(def, substs) if def.is_box() && cx.layout_of(substs.type_at(1)).is_zst() => { let ptr_ty = cx.tcx.mk_mut_ptr(self.ty.boxed_ty()); return cx.layout_of(ptr_ty).scalar_pair_element_llvm_type(cx, index, immediate); } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index e53c9842117..58e0667d678 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -216,17 +216,18 @@ pub fn each_linked_rlib( } let name = &info.crate_name[&cnum]; let used_crate_source = &info.used_crate_source[&cnum]; - let path = if let Some((path, _)) = &used_crate_source.rlib { - path - } else if used_crate_source.rmeta.is_some() { - return Err(format!( - "could not find rlib for: `{}`, found rmeta (metadata) file", - name - )); + if let Some((path, _)) = &used_crate_source.rlib { + f(cnum, &path); } else { - return Err(format!("could not find rlib for: `{}`", name)); - }; - f(cnum, &path); + if used_crate_source.rmeta.is_some() { + return Err(format!( + "could not find rlib for: `{}`, found rmeta (metadata) file", + name + )); + } else { + return Err(format!("could not find rlib for: `{}`", name)); + } + } } Ok(()) } diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 6849533abc0..9ebbcac76a2 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -200,9 +200,7 @@ fn create_object_file(sess: &Session) -> Option<write::Object<'static>> { // `SHF_EXCLUDE` flag we can set on sections in an object file to get // automatically removed from the final output. pub fn create_rmeta_file(sess: &Session, metadata: &[u8]) -> Vec<u8> { - let mut file = if let Some(file) = create_object_file(sess) { - file - } else { + let Some(mut file) = create_object_file(sess) else { // This is used to handle all "other" targets. This includes targets // in two categories: // @@ -262,9 +260,7 @@ pub fn create_compressed_metadata_file( ) -> Vec<u8> { let mut compressed = rustc_metadata::METADATA_HEADER.to_vec(); FrameEncoder::new(&mut compressed).write_all(metadata.raw_data()).unwrap(); - let mut file = if let Some(file) = create_object_file(sess) { - file - } else { + let Some(mut file) = create_object_file(sess) else { return compressed.to_vec(); }; let section = file.add_section( diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index c21d19a6227..6976999c0e4 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -476,7 +476,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::ProjectionElem::Subslice { from, to, from_end } => { let mut subslice = cg_base.project_index(bx, bx.cx().const_usize(from as u64)); let projected_ty = - PlaceTy::from_ty(cg_base.layout.ty).projection_ty(tcx, elem.clone()).ty; + PlaceTy::from_ty(cg_base.layout.ty).projection_ty(tcx, *elem).ty; subslice.layout = bx.cx().layout_of(self.monomorphize(projected_ty)); if subslice.layout.is_unsized() { diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 3601169528b..85826cfbf01 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -216,10 +216,12 @@ fn run_compiler( } let cfg = interface::parse_cfgspecs(matches.opt_strs("cfg")); + let check_cfg = interface::parse_check_cfg(matches.opt_strs("check-cfg")); let (odir, ofile) = make_output(&matches); let mut config = interface::Config { opts: sopts, crate_cfg: cfg, + crate_check_cfg: check_cfg, input: Input::File(PathBuf::new()), input_path: None, output_file: ofile, diff --git a/compiler/rustc_error_codes/src/error_codes/E0760.md b/compiler/rustc_error_codes/src/error_codes/E0760.md index 65acd4fabdf..e1dcfefebcd 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0760.md +++ b/compiler/rustc_error_codes/src/error_codes/E0760.md @@ -1,4 +1,4 @@ -`impl trait` return type cannot contain a projection +`async fn`/`impl trait` return type cannot contain a projection or `Self` that references lifetimes from a parent scope. Erroneous code example: @@ -7,7 +7,7 @@ Erroneous code example: struct S<'a>(&'a i32); impl<'a> S<'a> { - fn new(i: &'a i32) -> impl Into<Self> { + async fn new(i: &'a i32) -> Self { S(&22) } } @@ -19,7 +19,7 @@ To fix this error we need to spell out `Self` to `S<'a>`: struct S<'a>(&'a i32); impl<'a> S<'a> { - fn new(i: &'a i32) -> impl Into<S<'a>> { + async fn new(i: &'a i32) -> S<'a> { S(&22) } } diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 8065911afb9..f71fb58cf6b 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -1039,7 +1039,7 @@ fn check_matcher_core( )); err.span_suggestion( span, - &format!("try a `pat_param` fragment specifier instead"), + "try a `pat_param` fragment specifier instead", suggestion, Applicability::MaybeIncorrect, ); diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 32a9d081ed8..d43f926d0a5 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -70,6 +70,8 @@ declare_features! ( (accepted, cfg_attr_multi, "1.33.0", Some(54881), None), /// Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests. (accepted, cfg_doctest, "1.40.0", Some(62210), None), + /// Enables `#[cfg(panic = "...")]` config key. + (accepted, cfg_panic, "1.60.0", Some(77443), None), /// Allows `cfg(target_feature = "...")`. (accepted, cfg_target_feature, "1.27.0", Some(29717), None), /// Allows `cfg(target_vendor = "...")`. diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 3c85ff77cfb..5545abc6024 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -285,13 +285,13 @@ declare_features! ( /// Allows trait methods with arbitrary self types. (active, arbitrary_self_types, "1.23.0", Some(44874), None), /// Allows using `const` operands in inline assembly. - (active, asm_const, "1.58.0", Some(72016), None), + (active, asm_const, "1.58.0", Some(93332), None), /// Enables experimental inline assembly support for additional architectures. - (active, asm_experimental_arch, "1.58.0", Some(72016), None), + (active, asm_experimental_arch, "1.58.0", Some(93335), None), /// Allows using `sym` operands in inline assembly. - (active, asm_sym, "1.58.0", Some(72016), None), + (active, asm_sym, "1.58.0", Some(93333), None), /// Allows the `may_unwind` option in inline assembly. - (active, asm_unwind, "1.58.0", Some(72016), None), + (active, asm_unwind, "1.58.0", Some(93334), None), /// Allows users to enforce equality of associated constants `TraitImpl<AssocConst=3>`. (active, associated_const_equality, "1.58.0", Some(92827), None), /// Allows the user of associated type bounds. @@ -306,8 +306,6 @@ declare_features! ( (active, c_variadic, "1.34.0", Some(44930), None), /// Allows capturing disjoint fields in a closure/generator (RFC 2229). (incomplete, capture_disjoint_fields, "1.49.0", Some(53488), None), - /// Enables `#[cfg(panic = "...")]` config key. - (active, cfg_panic, "1.49.0", Some(77443), None), /// Allows the use of `#[cfg(sanitize = "option")]`; set when -Zsanitizer is used. (active, cfg_sanitize, "1.41.0", Some(39699), None), /// Allows `cfg(target_abi = "...")`. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index d9a986aba7d..1fb1a38a927 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -34,7 +34,6 @@ const GATED_CFGS: &[GatedCfg] = &[ (sym::target_has_atomic_load_store, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), (sym::sanitize, sym::cfg_sanitize, cfg_fn!(cfg_sanitize)), (sym::version, sym::cfg_version, cfg_fn!(cfg_version)), - (sym::panic, sym::cfg_panic, cfg_fn!(cfg_panic)), ]; /// Find a gated cfg determined by the `pred`icate which is given the cfg's name. diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index cf86c450a5b..7f376c5fbe5 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -852,11 +852,7 @@ impl<T: Idx> HybridBitSet<T> { Bound::Excluded(end) => end.index(), Bound::Unbounded => self.domain_size() - 1, }; - let len = if let Some(l) = end.checked_sub(start) { - l - } else { - return; - }; + let Some(len) = end.checked_sub(start) else { return }; match self { HybridBitSet::Sparse(sparse) if sparse.len() + len < SPARSE_MAX => { // The set is sparse and has space for `elems`. diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index aba5666b58c..205ad044554 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -497,16 +497,32 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let ty_to_string = |ty: Ty<'tcx>| -> String { let mut s = String::new(); let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS); - let mut inner = self.inner.borrow_mut(); - let ty_vars = inner.type_variables(); - let getter = move |ty_vid| { - let var_origin = ty_vars.var_origin(ty_vid); - if let TypeVariableOriginKind::TypeParameterDefinition(name, _) = var_origin.kind { + let ty_getter = move |ty_vid| { + if let TypeVariableOriginKind::TypeParameterDefinition(name, _) = + self.inner.borrow_mut().type_variables().var_origin(ty_vid).kind + { + Some(name.to_string()) + } else { + None + } + }; + printer.ty_infer_name_resolver = Some(Box::new(ty_getter)); + let const_getter = move |ct_vid| { + if let ConstVariableOriginKind::ConstParameterDefinition(name, _) = self + .inner + .borrow_mut() + .const_unification_table() + .probe_value(ct_vid) + .origin + .kind + { return Some(name.to_string()); + } else { + None } - None }; - printer.name_resolver = Some(Box::new(&getter)); + printer.const_infer_name_resolver = Some(Box::new(const_getter)); + let _ = if let ty::FnDef(..) = ty.kind() { // We don't want the regular output for `fn`s because it includes its path in // invalid pseudo-syntax, we want the `fn`-pointer output instead. @@ -553,8 +569,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let ty_msg = match (local_visitor.found_node_ty, local_visitor.found_exact_method_call) { (_, Some(_)) => String::new(), (Some(ty), _) if ty.is_closure() => { - let substs = - if let ty::Closure(_, substs) = *ty.kind() { substs } else { unreachable!() }; + let ty::Closure(_, substs) = *ty.kind() else { unreachable!() }; let fn_sig = substs.as_closure().sig(); let args = closure_args(&fn_sig); let ret = fn_sig.output().skip_binder().to_string(); @@ -597,8 +612,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let param_type = arg_data.kind.descr(); let suffix = match local_visitor.found_node_ty { Some(ty) if ty.is_closure() => { - let substs = - if let ty::Closure(_, substs) = *ty.kind() { substs } else { unreachable!() }; + let ty::Closure(_, substs) = *ty.kind() else { unreachable!() }; let fn_sig = substs.as_closure().sig(); let ret = fn_sig.output().skip_binder().to_string(); diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs index 8512597cb91..f44e6e04346 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs @@ -64,7 +64,7 @@ impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> { .or_else(|| self.try_report_mismatched_static_lifetime()) } - pub fn regions(&self) -> Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)> { + pub(super) fn regions(&self) -> Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)> { match (&self.error, self.regions) { (Some(ConcreteFailure(origin, sub, sup)), None) => Some((origin.span(), *sub, *sup)), (Some(SubSupConflict(_, _, origin, sub, _, sup, _)), None) => { diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index 8e5efa12ac6..8671ecba6e9 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -102,6 +102,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "...so that the definition in impl matches the definition from the trait", ); } + infer::CheckAssociatedTypeBounds { ref parent, .. } => { + self.note_region_origin(err, &parent); + } } } @@ -345,6 +348,55 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { trait_item_def_id, &format!("`{}: {}`", sup, sub), ), + infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => { + let mut err = self.report_concrete_failure(*parent, sub, sup); + + let trait_item_span = self.tcx.def_span(trait_item_def_id); + let item_name = self.tcx.item_name(impl_item_def_id); + err.span_label( + trait_item_span, + format!("definition of `{}` from trait", item_name), + ); + + let trait_predicates = self.tcx.explicit_predicates_of(trait_item_def_id); + let impl_predicates = self.tcx.explicit_predicates_of(impl_item_def_id); + + let impl_predicates: rustc_data_structures::stable_set::FxHashSet<_> = + impl_predicates.predicates.into_iter().map(|(pred, _)| pred).collect(); + let clauses: Vec<_> = trait_predicates + .predicates + .into_iter() + .filter(|&(pred, _)| !impl_predicates.contains(pred)) + .map(|(pred, _)| format!("{}", pred)) + .collect(); + + if !clauses.is_empty() { + let where_clause_span = self + .tcx + .hir() + .get_generics(impl_item_def_id.expect_local()) + .unwrap() + .where_clause + .tail_span_for_suggestion(); + + let suggestion = format!( + "{} {}", + if !impl_predicates.is_empty() { "," } else { " where" }, + clauses.join(", "), + ); + err.span_suggestion( + where_clause_span, + &format!( + "try copying {} from the trait", + if clauses.len() > 1 { "these clauses" } else { "this clause" } + ), + suggestion, + rustc_errors::Applicability::MaybeIncorrect, + ); + } + + err + } } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index f0a4ec81313..57ac98ca897 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -438,6 +438,13 @@ pub enum SubregionOrigin<'tcx> { /// Comparing the signature and requirements of an impl associated type /// against the containing trait CompareImplTypeObligation { span: Span, impl_item_def_id: DefId, trait_item_def_id: DefId }, + + /// Checking that the bounds of a trait's associated type hold for a given impl + CheckAssociatedTypeBounds { + parent: Box<SubregionOrigin<'tcx>>, + impl_item_def_id: DefId, + trait_item_def_id: DefId, + }, } // `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger. @@ -1832,6 +1839,7 @@ impl<'tcx> SubregionOrigin<'tcx> { ReferenceOutlivesReferent(_, a) => a, CompareImplMethodObligation { span, .. } => span, CompareImplTypeObligation { span, .. } => span, + CheckAssociatedTypeBounds { ref parent, .. } => parent.span(), } } @@ -1862,6 +1870,15 @@ impl<'tcx> SubregionOrigin<'tcx> { trait_item_def_id, }, + traits::ObligationCauseCode::CheckAssociatedTypeBounds { + impl_item_def_id, + trait_item_def_id, + } => SubregionOrigin::CheckAssociatedTypeBounds { + impl_item_def_id, + trait_item_def_id, + parent: Box::new(default()), + }, + _ => default(), } } diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index e79ece9a4a4..e7dca94806c 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -276,7 +276,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { debug!(?concrete_ty); let first_own_region = match opaque_defn.origin { - hir::OpaqueTyOrigin::FnReturn(..) => { + hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => { // We lower // // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm> @@ -291,7 +291,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } // These opaque type inherit all lifetime parameters from their // parent, so we have to check them all. - hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::TyAlias => 0, + hir::OpaqueTyOrigin::TyAlias => 0, }; // For a case like `impl Foo<'a, 'b>`, we would generate a constraint diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs index 0864edf4451..74c44089045 100644 --- a/compiler/rustc_infer/src/infer/type_variable.rs +++ b/compiler/rustc_infer/src/infer/type_variable.rs @@ -263,7 +263,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { let index = self.values().push(TypeVariableData { origin }); assert_eq!(eq_key.vid.as_u32(), index as u32); - debug!("new_var(index={:?}, universe={:?}, origin={:?}", eq_key.vid, universe, origin,); + debug!("new_var(index={:?}, universe={:?}, origin={:?})", eq_key.vid, universe, origin); eq_key.vid } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 9a588b55393..609fc4b78c0 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -2,7 +2,7 @@ pub use crate::passes::BoxedResolver; use crate::util; use rustc_ast::token; -use rustc_ast::{self as ast, MetaItemKind}; +use rustc_ast::{self as ast, LitKind, MetaItemKind}; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; @@ -13,12 +13,13 @@ use rustc_lint::LintStore; use rustc_middle::ty; use rustc_parse::maybe_new_parser_from_source_str; use rustc_query_impl::QueryCtxt; -use rustc_session::config::{self, ErrorOutputType, Input, OutputFilenames}; +use rustc_session::config::{self, CheckCfg, ErrorOutputType, Input, OutputFilenames}; use rustc_session::early_error; use rustc_session::lint; use rustc_session::parse::{CrateConfig, ParseSess}; use rustc_session::{DiagnosticOutput, Session}; use rustc_span::source_map::{FileLoader, FileName}; +use rustc_span::symbol::sym; use std::path::PathBuf; use std::result; @@ -139,6 +140,90 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String }) } +/// Converts strings provided as `--check-cfg [specs]` into a `CheckCfg`. +pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg { + rustc_span::create_default_session_if_not_set_then(move |_| { + let mut cfg = CheckCfg::default(); + + 'specs: for s in specs { + let sess = ParseSess::with_silent_emitter(Some(format!( + "this error occurred on the command line: `--check-cfg={}`", + s + ))); + let filename = FileName::cfg_spec_source_code(&s); + + macro_rules! error { + ($reason: expr) => { + early_error( + ErrorOutputType::default(), + &format!( + concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"), + s + ), + ); + }; + } + + match maybe_new_parser_from_source_str(&sess, filename, s.to_string()) { + Ok(mut parser) => match &mut parser.parse_meta_item() { + Ok(meta_item) if parser.token == token::Eof => { + if let Some(args) = meta_item.meta_item_list() { + if meta_item.has_name(sym::names) { + cfg.names_checked = true; + for arg in args { + if arg.is_word() && arg.ident().is_some() { + let ident = arg.ident().expect("multi-segment cfg key"); + cfg.names_valid.insert(ident.name.to_string()); + } else { + error!("`names()` arguments must be simple identifers"); + } + } + continue 'specs; + } else if meta_item.has_name(sym::values) { + if let Some((name, values)) = args.split_first() { + if name.is_word() && name.ident().is_some() { + let ident = name.ident().expect("multi-segment cfg key"); + cfg.values_checked.insert(ident.to_string()); + for val in values { + if let Some(LitKind::Str(s, _)) = + val.literal().map(|lit| &lit.kind) + { + cfg.values_valid + .insert((ident.to_string(), s.to_string())); + } else { + error!( + "`values()` arguments must be string literals" + ); + } + } + + continue 'specs; + } else { + error!( + "`values()` first argument must be a simple identifer" + ); + } + } + } + } + } + Ok(..) => {} + Err(err) => err.cancel(), + }, + Err(errs) => errs.into_iter().for_each(|mut err| err.cancel()), + } + + error!( + "expected `names(name1, name2, ... nameN)` or \ + `values(name, \"value1\", \"value2\", ... \"valueN\")`" + ); + } + + cfg.names_valid.extend(cfg.values_checked.iter().cloned()); + cfg + }) +} + /// The compiler configuration pub struct Config { /// Command line options @@ -146,6 +231,7 @@ pub struct Config { /// cfg! configuration in addition to the default ones pub crate_cfg: FxHashSet<(String, Option<String>)>, + pub crate_check_cfg: CheckCfg, pub input: Input, pub input_path: Option<PathBuf>, @@ -188,6 +274,7 @@ pub fn create_compiler_and_run<R>(config: Config, f: impl FnOnce(&Compiler) -> R let (mut sess, codegen_backend) = util::create_session( config.opts, config.crate_cfg, + config.crate_check_cfg, config.diagnostic_output, config.file_loader, config.input_path.clone(), diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 66e1e78b285..c0552fd200b 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -393,8 +393,18 @@ pub fn configure_and_expand( }); let crate_types = sess.crate_types(); + let is_executable_crate = crate_types.contains(&CrateType::Executable); let is_proc_macro_crate = crate_types.contains(&CrateType::ProcMacro); + if crate_types.len() > 1 { + if is_executable_crate { + sess.err("cannot mix `bin` crate type with others"); + } + if is_proc_macro_crate { + sess.err("cannot mix `proc-macro` crate type with others"); + } + } + // For backwards compatibility, we don't try to run proc macro injection // if rustdoc is run on a proc macro crate without '--crate-type proc-macro' being // specified. This should only affect users who manually invoke 'rustdoc', as @@ -411,7 +421,6 @@ pub fn configure_and_expand( msg.emit() } else { krate = sess.time("maybe_create_a_macro_crate", || { - let num_crate_types = crate_types.len(); let is_test_crate = sess.opts.test; rustc_builtin_macros::proc_macro_harness::inject( sess, @@ -420,7 +429,6 @@ pub fn configure_and_expand( is_proc_macro_crate, has_proc_macro_decls, is_test_crate, - num_crate_types, sess.diagnostic(), ) }); diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 700710c82c9..46964f52685 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -15,6 +15,7 @@ use rustc_parse::validate_attr; use rustc_query_impl::QueryCtxt; use rustc_resolve::{self, Resolver}; use rustc_session as session; +use rustc_session::config::CheckCfg; use rustc_session::config::{self, CrateType}; use rustc_session::config::{ErrorOutputType, Input, OutputFilenames}; use rustc_session::lint::{self, BuiltinLintDiagnostics, LintBuffer}; @@ -65,6 +66,7 @@ pub fn add_configuration( pub fn create_session( sopts: config::Options, cfg: FxHashSet<(String, Option<String>)>, + check_cfg: CheckCfg, diagnostic_output: DiagnosticOutput, file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>, input_path: Option<PathBuf>, @@ -100,7 +102,13 @@ pub fn create_session( let mut cfg = config::build_configuration(&sess, config::to_crate_config(cfg)); add_configuration(&mut cfg, &mut sess, &*codegen_backend); + + let mut check_cfg = config::to_crate_check_config(check_cfg); + check_cfg.fill_well_known(); + check_cfg.fill_actual(&cfg); + sess.parse_sess.config = cfg; + sess.parse_sess.check_config = check_cfg; (Lrc::new(sess), Lrc::new(codegen_backend)) } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index f4eba25475e..adec1a3ab00 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -2957,6 +2957,43 @@ declare_lint! { }; } +declare_lint! { + /// The `unexpected_cfgs` lint detects unexpected conditional compilation conditions. + /// + /// ### Example + /// + /// ```text + /// rustc --check-cfg 'names()' + /// ``` + /// + /// ```rust,ignore (needs command line option) + /// #[cfg(widnows)] + /// fn foo() {} + /// ``` + /// + /// This will produce: + /// + /// ```text + /// warning: unknown condition name used + /// --> lint_example.rs:1:7 + /// | + /// 1 | #[cfg(widnows)] + /// | ^^^^^^^ + /// | + /// = note: `#[warn(unexpected_cfgs)]` on by default + /// ``` + /// + /// ### Explanation + /// + /// This lint is only active when a `--check-cfg='names(...)'` option has been passed + /// to the compiler and triggers whenever an unknown condition name or value is used. + /// The known condition include names or values passed in `--check-cfg`, `--cfg`, and some + /// well-knows names and values built into the compiler. + pub UNEXPECTED_CFGS, + Warn, + "detects unexpected names and values in `#[cfg]` conditions", +} + declare_lint_pass! { /// Does nothing as a lint pass, but registers some `Lint`s /// that are used by other parts of the compiler. @@ -3055,6 +3092,7 @@ declare_lint_pass! { DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME, DUPLICATE_MACRO_ATTRIBUTES, SUSPICIOUS_AUTO_TRAIT_IMPLS, + UNEXPECTED_CFGS, ] } diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h index 9e0a9b354e1..a2b0e9b4d29 100644 --- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h +++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h @@ -83,6 +83,7 @@ enum LLVMRustAttribute { StackProtectStrong = 31, StackProtect = 32, NoUndef = 33, + SanitizeMemTag = 34, }; typedef struct OpaqueRustString *RustStringRef; diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 23333199506..c8f31adbfd9 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -226,6 +226,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) { return Attribute::StackProtect; case NoUndef: return Attribute::NoUndef; + case SanitizeMemTag: + return Attribute::SanitizeMemTag; } report_fatal_error("bad AttributeKind"); } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 87a88fbac71..66968c9ba54 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1032,13 +1032,11 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } /// Iterates over the language items in the given crate. - fn get_lang_items(self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, usize)] { - tcx.arena.alloc_from_iter( - self.root - .lang_items - .decode(self) - .map(|(def_index, index)| (self.local_def_id(def_index), index)), - ) + fn get_lang_items(self) -> impl Iterator<Item = (DefId, usize)> + 'a { + self.root + .lang_items + .decode(self) + .map(move |(def_index, index)| (self.local_def_id(def_index), index)) } /// Iterates over the diagnostic items in the given crate. diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 9b0272e7fd3..7708b5193f4 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -200,7 +200,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, tcx.arena.alloc_slice(&result) } defined_lib_features => { cdata.get_lib_features(tcx) } - defined_lang_items => { cdata.get_lang_items(tcx) } + defined_lang_items => { tcx.arena.alloc_from_iter(cdata.get_lang_items()) } diagnostic_items => { cdata.get_diagnostic_items() } missing_lang_items => { cdata.get_missing_lang_items(tcx) } @@ -501,6 +501,11 @@ impl CStore { ) -> impl Iterator<Item = (DefId, DefId)> + '_ { self.get_crate_data(cnum).get_inherent_impls() } + + /// Decodes all lang items in the crate (for rustdoc). + pub fn lang_items_untracked(&self, cnum: CrateNum) -> impl Iterator<Item = DefId> + '_ { + self.get_crate_data(cnum).get_lang_items().map(|(def_id, _)| def_id) + } } impl CrateStore for CStore { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 4d6b97eff24..4dea04e62ff 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -982,7 +982,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { for local_id in hir.iter_local_def_id() { let def_id = local_id.to_def_id(); let def_kind = tcx.opt_def_kind(local_id); - let def_kind = if let Some(def_kind) = def_kind { def_kind } else { continue }; + let Some(def_kind) = def_kind else { continue }; record!(self.tables.def_kind[def_id] <- match def_kind { // Replace Ctor by the enclosing object to avoid leaking details in children crates. DefKind::Ctor(CtorOf::Struct, _) => DefKind::Struct, diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index cf50378ad60..6bfd1b7ffab 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -61,7 +61,7 @@ impl rustc_query_system::dep_graph::DepKind for DepKind { OP: for<'a> FnOnce(TaskDepsRef<'a>), { ty::tls::with_context_opt(|icx| { - let icx = if let Some(icx) = icx { icx } else { return }; + let Some(icx) = icx else { return }; op(icx.task_deps) }) } diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 03cca51dc0b..fedf456ccc8 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -198,7 +198,7 @@ fn deprecation_message( } else { let since = since.as_ref().map(Symbol::as_str); - if since.as_deref() == Some("TBD") { + if since == Some("TBD") { format!("use of {} `{}` that will be deprecated in a future Rust version", kind, path) } else { format!( diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 5c616425957..fbd5a2d08a5 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -341,7 +341,7 @@ pub enum ConstraintCategory { /// like `Foo { field: my_val }`) Usage, OpaqueType, - ClosureUpvar(hir::HirId), + ClosureUpvar(Field), /// A constraint from a user-written predicate /// with the provided span, written on the item @@ -363,7 +363,7 @@ pub enum ConstraintCategory { #[derive(TyEncodable, TyDecodable, HashStable)] pub enum ReturnConstraint { Normal, - ClosureUpvar(hir::HirId), + ClosureUpvar(Field), } /// The subject of a `ClosureOutlivesRequirement` -- that is, the thing diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 1123cab8076..b54418e5201 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -285,6 +285,12 @@ pub enum ObligationCauseCode<'tcx> { trait_item_def_id: DefId, }, + /// Checking that the bounds of a trait's associated type hold for a given impl + CheckAssociatedTypeBounds { + impl_item_def_id: DefId, + trait_item_def_id: DefId, + }, + /// Checking that this expression can be assigned where it needs to be // FIXME(eddyb) #11161 is the original Expr required? ExprAssignable, diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index b3006672e22..4922d07ae1c 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -1,38 +1,56 @@ -//! Generalized type folding mechanism. The setup is a bit convoluted -//! but allows for convenient usage. Let T be an instance of some -//! "foldable type" (one which implements `TypeFoldable`) and F be an -//! instance of a "folder" (a type which implements `TypeFolder`). Then -//! the setup is intended to be: +//! A generalized traversal mechanism for complex data structures that contain +//! type information. //! -//! T.fold_with(F) --calls--> F.fold_T(T) --calls--> T.super_fold_with(F) +//! There are two types of traversal. +//! - Folding. This is a modifying traversal. It consumes the data structure, +//! producing a (possibly) modified version of it. Both fallible and +//! infallible versions are available. The name is potentially +//! confusing, because this traversal is more like `Iterator::map` than +//! `Iterator::fold`. +//! - Visiting. This is a read-only traversal of the data structure. //! -//! This way, when you define a new folder F, you can override -//! `fold_T()` to customize the behavior, and invoke `T.super_fold_with()` -//! to get the original behavior. Meanwhile, to actually fold -//! something, you can just write `T.fold_with(F)`, which is -//! convenient. (Note that `fold_with` will also transparently handle -//! things like a `Vec<T>` where T is foldable and so on.) +//! These traversals have limited flexibility. Only a small number of "types of +//! interest" within the complex data structures can receive custom +//! modification (when folding) or custom visitation (when visiting). These are +//! the ones containing the most important type-related information, such as +//! `Ty`, `Predicate`, `Region`, and `Const`. //! -//! In this ideal setup, the only function that actually *does* -//! anything is `T.super_fold_with()`, which traverses the type `T`. -//! Moreover, `T.super_fold_with()` should only ever call `T.fold_with()`. +//! There are two traits involved in each traversal type. +//! - The first trait is `TypeFoldable`, which is implemented once for many +//! types. This includes both (a) types of interest, and (b) all other +//! relevant types, including generic containers like `Vec` and `Option`. It +//! defines a "skeleton" of how they should be traversed, for both folding +//! and visiting. +//! - The second trait is `TypeFolder`/`FallibleTypeFolder` (for +//! infallible/fallible folding traversals) or `TypeVisitor` (for visiting +//! traversals). One of these is implemented for each folder/visitor. This +//! defines how types of interest are handled. //! -//! In some cases, we follow a degenerate pattern where we do not have -//! a `fold_T` method. Instead, `T.fold_with` traverses the structure directly. -//! This is suboptimal because the behavior cannot be overridden, but it's -//! much less work to implement. If you ever *do* need an override that -//! doesn't exist, it's not hard to convert the degenerate pattern into the -//! proper thing. +//! This means each traversal is a mixture of (a) generic traversal operations, +//! and (b) custom fold/visit operations that are specific to the +//! folder/visitor. +//! - The `TypeFoldable` impls handle most of the traversal, and call into +//! `TypeFolder`/`FallibleTypeFolder`/`TypeVisitor` when they encounter a +//! type of interest. +//! - A `TypeFolder`/`FallibleTypeFolder`/`TypeVisitor` may also call back into +//! a `TypeFoldable` impl, because (a) the types of interest are recursive +//! and can contain other types of interest, and (b) each folder/visitor +//! might provide custom handling only for some types of interest, or only +//! for some variants of each type of interest, and then use default +//! traversal for the remaining cases. //! -//! A `TypeFoldable` T can also be visited by a `TypeVisitor` V using similar setup: -//! -//! T.visit_with(V) --calls--> V.visit_T(T) --calls--> T.super_visit_with(V). -//! -//! These methods return true to indicate that the visitor has found what it is -//! looking for, and does not need to visit anything else. +//! For example, if you have `struct S(Ty, U)` where `S: TypeFoldable` and `U: +//! TypeFoldable`, and an instance `S(ty, u)`, it would be visited like so: +//! ``` +//! s.visit_with(visitor) calls +//! - s.super_visit_with(visitor) calls +//! - ty.visit_with(visitor) calls +//! - visitor.visit_ty(ty) may call +//! - ty.super_visit_with(visitor) +//! - u.visit_with(visitor) +//! ``` use crate::mir; use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags}; -use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_data_structures::fx::FxHashSet; @@ -41,42 +59,67 @@ use std::collections::BTreeMap; use std::fmt; use std::ops::ControlFlow; -/// This trait is implemented for every type that can be folded. -/// Basically, every type that has a corresponding method in `TypeFolder`. +/// This trait is implemented for every type that can be folded/visited, +/// providing the skeleton of the traversal. /// -/// To implement this conveniently, use the derive macro located in `rustc_macros`. +/// To implement this conveniently, use the derive macro located in +/// `rustc_macros`. pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { - /// Consumers may find this more convenient to use with infallible folders than - /// [`try_super_fold_with`][`TypeFoldable::try_super_fold_with`], to which the - /// provided default definition delegates. Implementors **should not** override - /// this provided default definition, to ensure that the two methods are coherent - /// (provide a definition of `try_super_fold_with` instead). - fn super_fold_with<F: TypeFolder<'tcx, Error = !>>(self, folder: &mut F) -> Self { - self.try_super_fold_with(folder).into_ok() + /// The main entry point for folding. To fold a value `t` with a folder `f` + /// call: `t.try_fold_with(f)`. + /// + /// For types of interest (such as `Ty`), this default is overridden with a + /// method that calls a folder method specifically for that type (such as + /// `F::try_fold_ty`). This is where control transfers from `TypeFoldable` + /// to `TypeFolder`. + /// + /// For other types, this default is used. + fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { + self.try_super_fold_with(folder) } - /// Consumers may find this more convenient to use with infallible folders than - /// [`try_fold_with`][`TypeFoldable::try_fold_with`], to which the provided - /// default definition delegates. Implementors **should not** override this - /// provided default definition, to ensure that the two methods are coherent - /// (provide a definition of `try_fold_with` instead). + + /// A convenient alternative to `try_fold_with` for use with infallible + /// folders. Do not override this method, to ensure coherence with + /// `try_fold_with`. fn fold_with<F: TypeFolder<'tcx, Error = !>>(self, folder: &mut F) -> Self { self.try_fold_with(folder).into_ok() } + /// Traverses the type in question, typically by calling `try_fold_with` on + /// each field/element. This is true even for types of interest such as + /// `Ty`. This should only be called within `TypeFolder` methods, when + /// non-custom traversals are desired for types of interest. fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>( self, folder: &mut F, ) -> Result<Self, F::Error>; - fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> { - self.try_super_fold_with(folder) + /// A convenient alternative to `try_super_fold_with` for use with + /// infallible folders. Do not override this method, to ensure coherence + /// with `try_super_fold_with`. + fn super_fold_with<F: TypeFolder<'tcx, Error = !>>(self, folder: &mut F) -> Self { + self.try_super_fold_with(folder).into_ok() } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>; + /// The entry point for visiting. To visit a value `t` with a visitor `v` + /// call: `t.visit_with(v)`. + /// + /// For types of interest (such as `Ty`), this default is overridden with a + /// method that calls a visitor method specifically for that type (such as + /// `V::visit_ty`). This is where control transfers from `TypeFoldable` to + /// `TypeVisitor`. + /// + /// For other types, this default is used. fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { self.super_visit_with(visitor) } + /// Traverses the type in question, typically by calling `visit_with` on + /// each field/element. This is true even for types of interest such as + /// `Ty`. This should only be called within `TypeVisitor` methods, when + /// non-custom traversals are desired for types of interest. + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>; + /// Returns `true` if `self` has any late-bound regions that are either /// bound by `binder` or bound by some binder outside of `binder`. /// If `binder` is `ty::INNERMOST`, this indicates whether @@ -168,24 +211,13 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { } } -impl<'tcx> TypeFoldable<'tcx> for hir::Constness { - fn try_super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> { - Ok(self) - } - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> { - ControlFlow::CONTINUE - } -} - -/// The `TypeFolder` trait defines the actual *folding*. There is a -/// method defined for every foldable type. Each of these has a -/// default implementation that does an "identity" fold. Within each -/// identity fold, it should invoke `foo.fold_with(self)` to fold each -/// sub-item. +/// This trait is implemented for every folding traversal. There is a fold +/// method defined for every type of interest. Each such method has a default +/// that does an "identity" fold. /// /// If this folder is fallible (and therefore its [`Error`][`TypeFolder::Error`] -/// associated type is something other than the default, never), -/// [`FallibleTypeFolder`] should be implemented manually; otherwise, +/// associated type is something other than the default `!`) then +/// [`FallibleTypeFolder`] should be implemented manually. Otherwise, /// a blanket implementation of [`FallibleTypeFolder`] will defer to /// the infallible methods of this trait to ensure that the two APIs /// are coherent. @@ -238,11 +270,9 @@ pub trait TypeFolder<'tcx>: Sized { } } -/// The `FallibleTypeFolder` trait defines the actual *folding*. There is a -/// method defined for every foldable type. Each of these has a -/// default implementation that does an "identity" fold. Within each -/// identity fold, it should invoke `foo.try_fold_with(self)` to fold each -/// sub-item. +/// This trait is implemented for every folding traversal. There is a fold +/// method defined for every type of interest. Each such method has a default +/// that does an "identity" fold. /// /// A blanket implementation of this trait (that defers to the relevant /// method of [`TypeFolder`]) is provided for all infallible folders in @@ -282,8 +312,8 @@ pub trait FallibleTypeFolder<'tcx>: TypeFolder<'tcx> { } } -// Blanket implementation of fallible trait for infallible folders -// delegates to infallible methods to prevent incoherence +// This blanket implementation of the fallible trait for infallible folders +// delegates to infallible methods to ensure coherence. impl<'tcx, F> FallibleTypeFolder<'tcx> for F where F: TypeFolder<'tcx, Error = !>, @@ -322,6 +352,9 @@ where } } +/// This trait is implemented for every visiting traversal. There is a visit +/// method defined for every type of interest. Each such method has a default +/// that recurses into the type's fields in a non-custom fashion. pub trait TypeVisitor<'tcx>: Sized { type BreakTy = !; diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index ae838a46157..bf7370c9e0e 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -606,7 +606,7 @@ pub trait PrettyPrinter<'tcx>: ty::Infer(infer_ty) => { let verbose = self.tcx().sess.verbose(); if let ty::TyVar(ty_vid) = infer_ty { - if let Some(name) = self.infer_ty_name(ty_vid) { + if let Some(name) = self.ty_infer_name(ty_vid) { p!(write("{}", name)) } else { if verbose { @@ -1015,7 +1015,11 @@ pub trait PrettyPrinter<'tcx>: } } - fn infer_ty_name(&self, _: ty::TyVid) -> Option<String> { + fn ty_infer_name(&self, _: ty::TyVid) -> Option<String> { + None + } + + fn const_infer_name(&self, _: ty::ConstVid<'tcx>) -> Option<String> { None } @@ -1203,7 +1207,14 @@ pub trait PrettyPrinter<'tcx>: } } } - ty::ConstKind::Infer(..) => print_underscore!(), + ty::ConstKind::Infer(infer_ct) => { + match infer_ct { + ty::InferConst::Var(ct_vid) + if let Some(name) = self.const_infer_name(ct_vid) => + p!(write("{}", name)), + _ => print_underscore!(), + } + } ty::ConstKind::Param(ParamConst { name, .. }) => p!(write("{}", name)), ty::ConstKind::Value(value) => { return self.pretty_print_const_value(value, ct.ty(), print_ty); @@ -1559,7 +1570,8 @@ pub struct FmtPrinterData<'a, 'tcx, F> { pub region_highlight_mode: RegionHighlightMode<'tcx>, - pub name_resolver: Option<Box<&'a dyn Fn(ty::TyVid) -> Option<String>>>, + pub ty_infer_name_resolver: Option<Box<dyn Fn(ty::TyVid) -> Option<String> + 'a>>, + pub const_infer_name_resolver: Option<Box<dyn Fn(ty::ConstVid<'tcx>) -> Option<String> + 'a>>, } impl<'a, 'tcx, F> Deref for FmtPrinter<'a, 'tcx, F> { @@ -1588,7 +1600,8 @@ impl<'a, 'tcx, F> FmtPrinter<'a, 'tcx, F> { binder_depth: 0, printed_type_count: 0, region_highlight_mode: RegionHighlightMode::new(tcx), - name_resolver: None, + ty_infer_name_resolver: None, + const_infer_name_resolver: None, })) } } @@ -1843,8 +1856,12 @@ impl<'tcx, F: fmt::Write> Printer<'tcx> for FmtPrinter<'_, 'tcx, F> { } impl<'tcx, F: fmt::Write> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx, F> { - fn infer_ty_name(&self, id: ty::TyVid) -> Option<String> { - self.0.name_resolver.as_ref().and_then(|func| func(id)) + fn ty_infer_name(&self, id: ty::TyVid) -> Option<String> { + self.0.ty_infer_name_resolver.as_ref().and_then(|func| func(id)) + } + + fn const_infer_name(&self, id: ty::ConstVid<'tcx>) -> Option<String> { + self.0.const_infer_name_resolver.as_ref().and_then(|func| func(id)) } fn print_value_path( diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index b59fb6afe6f..7c57d42631a 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -855,7 +855,7 @@ impl<'tcx> Relate<'tcx> for ty::ProjectionPredicate<'tcx> { ) -> RelateResult<'tcx, ty::ProjectionPredicate<'tcx>> { Ok(ty::ProjectionPredicate { projection_ty: relation.relate(a.projection_ty, b.projection_ty)?, - term: relation.relate(a.term, b.term)?.into(), + term: relation.relate(a.term, b.term)?, }) } } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index c1d714ed8d6..e4691dee779 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -8,6 +8,7 @@ use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeVisitor}; use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer}; use crate::ty::{self, InferConst, Lift, Term, Ty, TyCtxt}; use rustc_data_structures::functor::IdFunctor; +use rustc_hir as hir; use rustc_hir::def::Namespace; use rustc_hir::def_id::CRATE_DEF_INDEX; use rustc_index::vec::{Idx, IndexVec}; @@ -663,14 +664,6 @@ impl<'a, 'tcx> Lift<'tcx> for ty::InstanceDef<'a> { /////////////////////////////////////////////////////////////////////////// // TypeFoldable implementations. -// -// Ideally, each type should invoke `folder.fold_foo(self)` and -// nothing else. In some cases, though, we haven't gotten around to -// adding methods on the `folder` yet, and thus the folding is -// hard-coded here. This is less-flexible, because folders cannot -// override the behavior, but there are a lot of random types and one -// can easily refactor the folding into the TypeFolder trait as -// needed. /// AdtDefs are basically the same as a DefId. impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::AdtDef { @@ -1270,3 +1263,13 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx, ()> { self.substs.visit_with(visitor) } } + +impl<'tcx> TypeFoldable<'tcx> for hir::Constness { + fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> { + Ok(self) + } + + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> { + ControlFlow::CONTINUE + } +} diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 9835211a748..7c6d6ea1cb6 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -8,7 +8,9 @@ use crate::infer::canonical::Canonical; use crate::ty::fold::ValidateBoundVars; use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef}; use crate::ty::InferTy::{self, *}; -use crate::ty::{self, AdtDef, DefIdTree, Discr, Term, Ty, TyCtxt, TypeFlags, TypeFoldable}; +use crate::ty::{ + self, AdtDef, DefIdTree, Discr, Term, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeVisitor, +}; use crate::ty::{DelaySpanBugEmitted, List, ParamEnv}; use polonius_engine::Atom; use rustc_data_structures::captures::Captures; @@ -24,7 +26,7 @@ use std::borrow::Cow; use std::cmp::Ordering; use std::fmt; use std::marker::PhantomData; -use std::ops::{Deref, Range}; +use std::ops::{ControlFlow, Deref, Range}; use ty::util::IntTypeExt; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] @@ -2072,6 +2074,24 @@ impl<'tcx> Ty<'tcx> { !matches!(self.kind(), Param(_) | Infer(_) | Error(_)) } + /// Checks whether a type recursively contains another type + /// + /// Example: `Option<()>` contains `()` + pub fn contains(self, other: Ty<'tcx>) -> bool { + struct ContainsTyVisitor<'tcx>(Ty<'tcx>); + + impl<'tcx> TypeVisitor<'tcx> for ContainsTyVisitor<'tcx> { + type BreakTy = (); + + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { + if self.0 == t { ControlFlow::BREAK } else { t.super_visit_with(self) } + } + } + + let cf = self.visit_with(&mut ContainsTyVisitor(other)); + cf.is_break() + } + /// Returns the type and mutability of `*ty`. /// /// The parameter `explicit` indicates if this is an *explicit* dereference. diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index 597f7dd95a2..8f4cc182e7f 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -210,7 +210,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn all_impls(self, def_id: DefId) -> impl Iterator<Item = DefId> + 'tcx { let TraitImpls { blanket_impls, non_blanket_impls } = self.trait_impls_of(def_id); - blanket_impls.iter().chain(non_blanket_impls.iter().map(|(_, v)| v).flatten()).cloned() + blanket_impls.iter().chain(non_blanket_impls.iter().flat_map(|(_, v)| v)).cloned() } } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index c2a4cea2b1a..92d9cb2fc1b 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -17,7 +17,7 @@ use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_errors::ErrorReported; use rustc_hir as hir; -use rustc_hir::def::DefKind; +use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; use rustc_query_system::ich::NodeIdHashingMode; @@ -146,6 +146,37 @@ impl<'tcx> TyCtxt<'tcx> { hasher.finish() } + pub fn res_generics_def_id(self, res: Res) -> Option<DefId> { + match res { + Res::Def(DefKind::Ctor(CtorOf::Variant, _), def_id) => { + Some(self.parent(def_id).and_then(|def_id| self.parent(def_id)).unwrap()) + } + Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Struct, _), def_id) => { + Some(self.parent(def_id).unwrap()) + } + // Other `DefKind`s don't have generics and would ICE when calling + // `generics_of`. + Res::Def( + DefKind::Struct + | DefKind::Union + | DefKind::Enum + | DefKind::Trait + | DefKind::OpaqueTy + | DefKind::TyAlias + | DefKind::ForeignTy + | DefKind::TraitAlias + | DefKind::AssocTy + | DefKind::Fn + | DefKind::AssocFn + | DefKind::AssocConst + | DefKind::Impl, + def_id, + ) => Some(def_id), + Res::Err => None, + _ => None, + } + } + pub fn has_error_field(self, ty: Ty<'tcx>) -> bool { if let ty::Adt(def, substs) = *ty.kind() { for field in def.all_fields() { diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs index 46de6d939a1..da921904523 100644 --- a/compiler/rustc_mir_transform/src/coverage/query.rs +++ b/compiler/rustc_mir_transform/src/coverage/query.rs @@ -140,7 +140,7 @@ fn covered_code_regions<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Vec<&'tcx Cod let body = mir_body(tcx, def_id); body.basic_blocks() .iter() - .map(|data| { + .flat_map(|data| { data.statements.iter().filter_map(|statement| match statement.kind { StatementKind::Coverage(box ref coverage) => { if is_inlined(body, statement) { @@ -152,7 +152,6 @@ fn covered_code_regions<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Vec<&'tcx Cod _ => None, }) }) - .flatten() .collect() } diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index 433a1c6ad67..05de52458ad 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -1241,9 +1241,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform { } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let yield_ty = if let Some(yield_ty) = body.yield_ty() { - yield_ty - } else { + let Some(yield_ty) = body.yield_ty() else { // This only applies to generators return; }; diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index f0e4129b002..55ce5910c81 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -7,6 +7,7 @@ use rustc_index::vec::Idx; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::visit::*; use rustc_middle::mir::*; +use rustc_middle::traits::ObligationCause; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{self, ConstKind, Instance, InstanceDef, ParamEnv, Ty, TyCtxt}; use rustc_span::{hygiene::ExpnKind, ExpnData, Span}; @@ -75,10 +76,18 @@ fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool { return false; } + let param_env = tcx.param_env_reveal_all_normalized(def_id); + let param_env = rustc_trait_selection::traits::normalize_param_env_or_error( + tcx, + def_id, + param_env, + ObligationCause::misc(body.span, hir_id), + ); + let mut this = Inliner { tcx, - param_env: tcx.param_env_reveal_all_normalized(body.source.def_id()), - codegen_fn_attrs: tcx.codegen_fn_attrs(body.source.def_id()), + param_env, + codegen_fn_attrs: tcx.codegen_fn_attrs(def_id), hir_id, history: Vec::new(), changed: false, diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs index 0392c5a5468..cdfd49ef478 100644 --- a/compiler/rustc_mir_transform/src/normalize_array_len.rs +++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs @@ -212,12 +212,7 @@ fn normalize_array_len_call<'tcx>( let Some(local) = place.as_local() else { return }; match operand { Operand::Copy(place) | Operand::Move(place) => { - let operand_local = - if let Some(local) = place.local_or_deref_local() { - local - } else { - return; - }; + let Some(operand_local) = place.local_or_deref_local() else { return; }; if !interesting_locals.contains(operand_local) { return; } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 8a1fe6e91cb..72c1b3fa6e9 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -947,9 +947,7 @@ fn visit_instance_use<'tcx>( /// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we /// can just link to the upstream crate and therefore don't need a mono item. fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> bool { - let def_id = if let Some(def_id) = instance.def.def_id_if_not_guaranteed_local_codegen() { - def_id - } else { + let Some(def_id) = instance.def.def_id_if_not_guaranteed_local_codegen() else { return true; }; diff --git a/compiler/rustc_monomorphize/src/partitioning/mod.rs b/compiler/rustc_monomorphize/src/partitioning/mod.rs index 67597a0d7b4..b8684a09fd7 100644 --- a/compiler/rustc_monomorphize/src/partitioning/mod.rs +++ b/compiler/rustc_monomorphize/src/partitioning/mod.rs @@ -220,18 +220,16 @@ pub fn partition<'tcx>( let mut cgus: Vec<_> = post_inlining.codegen_units.iter_mut().collect(); cgus.sort_by_key(|cgu| cgu.size_estimate()); - let dead_code_cgu = if let Some(cgu) = cgus - .into_iter() - .rev() - .filter(|cgu| cgu.items().iter().any(|(_, (linkage, _))| *linkage == Linkage::External)) - .next() - { - cgu - } else { - // If there are no CGUs that have externally linked items, - // then we just pick the first CGU as a fallback. - &mut post_inlining.codegen_units[0] - }; + let dead_code_cgu = + if let Some(cgu) = cgus.into_iter().rev().find(|cgu| { + cgu.items().iter().any(|(_, (linkage, _))| *linkage == Linkage::External) + }) { + cgu + } else { + // If there are no CGUs that have externally linked items, + // then we just pick the first CGU as a fallback. + &mut post_inlining.codegen_units[0] + }; dead_code_cgu.make_code_coverage_dead_code_cgu(); } diff --git a/compiler/rustc_monomorphize/src/util.rs b/compiler/rustc_monomorphize/src/util.rs index 27540395c07..04baa01832b 100644 --- a/compiler/rustc_monomorphize/src/util.rs +++ b/compiler/rustc_monomorphize/src/util.rs @@ -8,13 +8,11 @@ use std::io::prelude::*; /// During the same compile all closures dump the information in the same file /// "closure_profile_XXXXX.csv", which is created in the directory where the compiler is invoked. crate fn dump_closure_profile<'tcx>(tcx: TyCtxt<'tcx>, closure_instance: Instance<'tcx>) { - let mut file = if let Ok(file) = OpenOptions::new() + let Ok(mut file) = OpenOptions::new() .create(true) .append(true) .open(&format!("closure_profile_{}.csv", std::process::id())) - { - file - } else { + else { eprintln!("Cound't open file for writing closure profile"); return; }; diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 1a620968d56..4cdd83c0acd 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -158,9 +158,7 @@ impl<'a> StringReader<'a> { Some(match token { rustc_lexer::TokenKind::LineComment { doc_style } => { // Skip non-doc comments - let doc_style = if let Some(doc_style) = doc_style { - doc_style - } else { + let Some(doc_style) = doc_style else { self.lint_unicode_text_flow(start); return None; }; @@ -185,9 +183,7 @@ impl<'a> StringReader<'a> { } // Skip non-doc comments - let doc_style = if let Some(doc_style) = doc_style { - doc_style - } else { + let Some(doc_style) = doc_style else { self.lint_unicode_text_flow(start); return None; }; diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 2b1b2f3fce4..eb0d1a12c77 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -4,6 +4,7 @@ #![feature(crate_visibility_modifier)] #![feature(if_let_guard)] #![feature(box_patterns)] +#![feature(let_else)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 7b74b137d21..def23005fbe 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -2156,7 +2156,7 @@ impl<'a> Parser<'a> { | PatKind::TupleStruct(qself @ None, path, _) | PatKind::Path(qself @ None, path) => match &first_pat.kind { PatKind::Ident(_, ident, _) => { - path.segments.insert(0, PathSegment::from_ident(ident.clone())); + path.segments.insert(0, PathSegment::from_ident(*ident)); path.span = new_span; show_sugg = true; first_pat = pat; @@ -2183,8 +2183,8 @@ impl<'a> Parser<'a> { Path { span: new_span, segments: vec![ - PathSegment::from_ident(old_ident.clone()), - PathSegment::from_ident(ident.clone()), + PathSegment::from_ident(*old_ident), + PathSegment::from_ident(*ident), ], tokens: None, }, @@ -2194,7 +2194,7 @@ impl<'a> Parser<'a> { } PatKind::Path(old_qself, old_path) => { let mut segments = old_path.segments.clone(); - segments.push(PathSegment::from_ident(ident.clone())); + segments.push(PathSegment::from_ident(*ident)); let path = PatKind::Path( old_qself.clone(), Path { span: new_span, segments, tokens: None }, diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index 62ed104aef3..4b57aa1f24a 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -260,7 +260,7 @@ impl<'a> Parser<'a> { let ate_comma = self.eat(&token::Comma); if self.eat_keyword_noexpect(kw::Where) { - let msg = &format!("cannot define duplicate `where` clauses on an item"); + let msg = "cannot define duplicate `where` clauses on an item"; let mut err = self.struct_span_err(self.token.span, msg); err.span_label(lo, "previous `where` clause starts here"); err.span_suggestion_verbose( diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 4b85531557c..9a2fb3b86e2 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1362,8 +1362,7 @@ impl<'a> Resolver<'a> { .filter(|(_, module)| { current_module.is_ancestor_of(module) && !ptr::eq(current_module, *module) }) - .map(|(_, module)| module.kind.name()) - .flatten(), + .flat_map(|(_, module)| module.kind.name()), ) .filter(|c| !c.to_string().is_empty()) .collect::<Vec<_>>(); @@ -1859,7 +1858,7 @@ crate fn show_candidates( let instead = if instead { " instead" } else { "" }; let mut msg = format!("consider importing {} {}{}", determiner, kind, instead); - for note in accessible_path_strings.iter().map(|cand| cand.3.as_ref()).flatten() { + for note in accessible_path_strings.iter().flat_map(|cand| cand.3.as_ref()) { err.note(note); } @@ -1942,7 +1941,7 @@ crate fn show_candidates( multi_span.push_span_label(span, format!("`{}`: not accessible", name)); } - for note in inaccessible_path_strings.iter().map(|cand| cand.3.as_ref()).flatten() { + for note in inaccessible_path_strings.iter().flat_map(|cand| cand.3.as_ref()) { err.note(note); } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 5d843b46ee2..129db038f4a 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -704,7 +704,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { ) = &bounded_ty.kind { // use this to verify that ident is a type param. - let partial_res = if let Ok(Some(partial_res)) = self.resolve_qpath_anywhere( + let Ok(Some(partial_res)) = self.resolve_qpath_anywhere( bounded_ty.id, None, &Segment::from_path(path), @@ -712,9 +712,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { span, true, CrateLint::No, - ) { - partial_res - } else { + ) else { return false; }; if !(matches!( @@ -731,7 +729,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { if let ast::TyKind::Path(None, type_param_path) = &ty.peel_refs().kind { // Confirm that the `SelfTy` is a type parameter. - let partial_res = if let Ok(Some(partial_res)) = self.resolve_qpath_anywhere( + let Ok(Some(partial_res)) = self.resolve_qpath_anywhere( bounded_ty.id, None, &Segment::from_path(type_param_path), @@ -739,9 +737,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { span, true, CrateLint::No, - ) { - partial_res - } else { + ) else { return false; }; if !(matches!( @@ -1167,7 +1163,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { err.span_suggestion( span, &"use this syntax instead", - format!("{path_str}"), + path_str.to_string(), Applicability::MaybeIncorrect, ); } diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 1ce70f5dcf7..3bea95fa1d5 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -729,16 +729,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { match item.kind { hir::ItemKind::Fn(ref sig, ref generics, _) => { self.missing_named_lifetime_spots.push(generics.into()); - self.visit_early_late( - None, - item.hir_id(), - &sig.decl, - generics, - sig.header.asyncness, - |this| { - intravisit::walk_item(this, item); - }, - ); + self.visit_early_late(None, item.hir_id(), &sig.decl, generics, |this| { + intravisit::walk_item(this, item); + }); self.missing_named_lifetime_spots.pop(); } @@ -856,16 +849,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { match item.kind { - hir::ForeignItemKind::Fn(ref decl, _, ref generics) => self.visit_early_late( - None, - item.hir_id(), - decl, - generics, - hir::IsAsync::NotAsync, - |this| { + hir::ForeignItemKind::Fn(ref decl, _, ref generics) => { + self.visit_early_late(None, item.hir_id(), decl, generics, |this| { intravisit::walk_foreign_item(this, item); - }, - ), + }) + } hir::ForeignItemKind::Static(..) => { intravisit::walk_foreign_item(self, item); } @@ -1142,7 +1130,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { trait_item.hir_id(), &sig.decl, &trait_item.generics, - sig.header.asyncness, |this| intravisit::walk_trait_item(this, trait_item), ); self.missing_named_lifetime_spots.pop(); @@ -1212,7 +1199,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { impl_item.hir_id(), &sig.decl, &impl_item.generics, - sig.header.asyncness, |this| intravisit::walk_impl_item(this, impl_item), ); self.missing_named_lifetime_spots.pop(); @@ -2173,15 +2159,11 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { hir_id: hir::HirId, decl: &'tcx hir::FnDecl<'tcx>, generics: &'tcx hir::Generics<'tcx>, - asyncness: hir::IsAsync, walk: F, ) where F: for<'b, 'c> FnOnce(&'b mut LifetimeContext<'c, 'tcx>), { - // Async fns need all their lifetime parameters to be early bound. - if asyncness != hir::IsAsync::Async { - insert_late_bound_lifetimes(self.map, decl, generics); - } + insert_late_bound_lifetimes(self.map, decl, generics); // Find the start of nested early scopes, e.g., in methods. let mut next_early_index = 0; diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 68e7cc3dc98..7a0d9a212c9 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -16,7 +16,7 @@ use rustc_target::spec::{LinkerFlavor, SplitDebuginfo, Target, TargetTriple, Tar use rustc_serialize::json; -use crate::parse::CrateConfig; +use crate::parse::{CrateCheckConfig, CrateConfig}; use rustc_feature::UnstableFeatures; use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION}; use rustc_span::source_map::{FileName, FilePathMapping}; @@ -936,6 +936,7 @@ pub const fn default_lib_output() -> CrateType { } fn default_configuration(sess: &Session) -> CrateConfig { + // NOTE: This should be kept in sync with `CrateCheckConfig::fill_well_known` below. let end = &sess.target.endian; let arch = &sess.target.arch; let wordsz = sess.target.pointer_width.to_string(); @@ -1020,6 +1021,91 @@ pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect() } +/// The parsed `--check-cfg` options +pub struct CheckCfg<T = String> { + /// Set if `names()` checking is enabled + pub names_checked: bool, + /// The union of all `names()` + pub names_valid: FxHashSet<T>, + /// The set of names for which `values()` was used + pub values_checked: FxHashSet<T>, + /// The set of all (name, value) pairs passed in `values()` + pub values_valid: FxHashSet<(T, T)>, +} + +impl<T> Default for CheckCfg<T> { + fn default() -> Self { + CheckCfg { + names_checked: false, + names_valid: FxHashSet::default(), + values_checked: FxHashSet::default(), + values_valid: FxHashSet::default(), + } + } +} + +impl<T> CheckCfg<T> { + fn map_data<O: Eq + Hash>(&self, f: impl Fn(&T) -> O) -> CheckCfg<O> { + CheckCfg { + names_checked: self.names_checked, + names_valid: self.names_valid.iter().map(|a| f(a)).collect(), + values_checked: self.values_checked.iter().map(|a| f(a)).collect(), + values_valid: self.values_valid.iter().map(|(a, b)| (f(a), f(b))).collect(), + } + } +} + +/// Converts the crate `--check-cfg` options from `String` to `Symbol`. +/// `rustc_interface::interface::Config` accepts this in the compiler configuration, +/// but the symbol interner is not yet set up then, so we must convert it later. +pub fn to_crate_check_config(cfg: CheckCfg) -> CrateCheckConfig { + cfg.map_data(|s| Symbol::intern(s)) +} + +impl CrateCheckConfig { + /// Fills a `CrateCheckConfig` with well-known configuration names. + pub fn fill_well_known(&mut self) { + // NOTE: This should be kept in sync with `default_configuration` + const WELL_KNOWN_NAMES: &[Symbol] = &[ + sym::unix, + sym::windows, + sym::target_os, + sym::target_family, + sym::target_arch, + sym::target_endian, + sym::target_pointer_width, + sym::target_env, + sym::target_abi, + sym::target_vendor, + sym::target_thread_local, + sym::target_has_atomic_load_store, + sym::target_has_atomic, + sym::target_has_atomic_equal_alignment, + sym::panic, + sym::sanitize, + sym::debug_assertions, + sym::proc_macro, + sym::test, + sym::doc, + sym::doctest, + sym::feature, + ]; + for &name in WELL_KNOWN_NAMES { + self.names_valid.insert(name); + } + } + + /// Fills a `CrateCheckConfig` with configuration names and values that are actually active. + pub fn fill_actual(&mut self, cfg: &CrateConfig) { + for &(k, v) in cfg { + self.names_valid.insert(k); + if let Some(v) = v { + self.values_valid.insert((k, v)); + } + } + } +} + pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig { // Combine the configuration requested by the session (command line) with // some default and generated configuration items. @@ -1163,6 +1249,7 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> { vec![ opt::flag_s("h", "help", "Display this message"), opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"), + opt::multi("", "check-cfg", "Provide list of valid cfg options for checking", "SPEC"), opt::multi_s( "L", "", diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index c069144fa9f..0a4bd23937d 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -376,7 +376,7 @@ mod desc { pub const parse_panic_strategy: &str = "either `unwind` or `abort`"; pub const parse_opt_panic_strategy: &str = parse_panic_strategy; pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`"; - pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `leak`, `memory` or `thread`"; + pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `leak`, `memory`, `memtag`, or `thread`"; pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2"; pub const parse_cfguard: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`"; @@ -639,6 +639,7 @@ mod parse { "cfi" => SanitizerSet::CFI, "leak" => SanitizerSet::LEAK, "memory" => SanitizerSet::MEMORY, + "memtag" => SanitizerSet::MEMTAG, "thread" => SanitizerSet::THREAD, "hwaddress" => SanitizerSet::HWADDRESS, _ => return false, diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index d5b520325e5..7113f9b0a2f 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -1,6 +1,7 @@ //! Contains `ParseSess` which holds state living beyond what one `Parser` might. //! It also serves as an input to the parser itself. +use crate::config::CheckCfg; use crate::lint::{BufferedEarlyLint, BuiltinLintDiagnostics, Lint, LintId}; use rustc_ast::node_id::NodeId; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -18,6 +19,7 @@ use std::str; /// The set of keys (and, optionally, values) that define the compilation /// environment of the crate, used to drive conditional compilation. pub type CrateConfig = FxHashSet<(Symbol, Option<Symbol>)>; +pub type CrateCheckConfig = CheckCfg<Symbol>; /// Collected spans during parsing for places where a certain feature was /// used and should be feature gated accordingly in `check_crate`. @@ -117,6 +119,7 @@ pub struct ParseSess { pub span_diagnostic: Handler, pub unstable_features: UnstableFeatures, pub config: CrateConfig, + pub check_config: CrateCheckConfig, pub edition: Edition, pub missing_fragment_specifiers: Lock<FxHashMap<Span, NodeId>>, /// Places where raw identifiers were used. This is used to avoid complaining about idents @@ -162,6 +165,7 @@ impl ParseSess { span_diagnostic: handler, unstable_features: UnstableFeatures::from_environment(None), config: FxHashSet::default(), + check_config: CrateCheckConfig::default(), edition: ExpnId::root().expn_data().edition, missing_fragment_specifiers: Default::default(), raw_identifier_spans: Lock::new(Vec::new()), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 33140911f91..c746255e95e 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -876,6 +876,7 @@ symbols! { mem_zeroed, member_constraints, memory, + memtag, message, meta, metadata_type, @@ -910,6 +911,7 @@ symbols! { naked, naked_functions, name, + names, native_link_modifiers, native_link_modifiers_as_needed, native_link_modifiers_bundle, @@ -1481,6 +1483,7 @@ symbols! { va_list, va_start, val, + values, var, variant_count, vec, diff --git a/compiler/rustc_target/src/asm/aarch64.rs b/compiler/rustc_target/src/asm/aarch64.rs index da875508676..d184ad4e78a 100644 --- a/compiler/rustc_target/src/asm/aarch64.rs +++ b/compiler/rustc_target/src/asm/aarch64.rs @@ -77,6 +77,7 @@ pub fn reserved_x18( _arch: InlineAsmArch, _target_features: &FxHashSet<Symbol>, target: &Target, + _is_clobber: bool, ) -> Result<(), &'static str> { if target.os == "android" || target.is_like_fuchsia diff --git a/compiler/rustc_target/src/asm/arm.rs b/compiler/rustc_target/src/asm/arm.rs index e3615b43c70..b2d5bb3736a 100644 --- a/compiler/rustc_target/src/asm/arm.rs +++ b/compiler/rustc_target/src/asm/arm.rs @@ -66,10 +66,13 @@ fn frame_pointer_is_r7(target_features: &FxHashSet<Symbol>, target: &Target) -> } fn frame_pointer_r11( - _arch: InlineAsmArch, + arch: InlineAsmArch, target_features: &FxHashSet<Symbol>, target: &Target, + is_clobber: bool, ) -> Result<(), &'static str> { + not_thumb1(arch, target_features, target, is_clobber)?; + if !frame_pointer_is_r7(target_features, target) { Err("the frame pointer (r11) cannot be used as an operand for inline asm") } else { @@ -81,6 +84,7 @@ fn frame_pointer_r7( _arch: InlineAsmArch, target_features: &FxHashSet<Symbol>, target: &Target, + _is_clobber: bool, ) -> Result<(), &'static str> { if frame_pointer_is_r7(target_features, target) { Err("the frame pointer (r7) cannot be used as an operand for inline asm") @@ -93,9 +97,13 @@ fn not_thumb1( _arch: InlineAsmArch, target_features: &FxHashSet<Symbol>, _target: &Target, + is_clobber: bool, ) -> Result<(), &'static str> { - if target_features.contains(&sym::thumb_mode) && !target_features.contains(&sym::thumb2) { - Err("high registers (r8+) cannot be used in Thumb-1 code") + if !is_clobber + && target_features.contains(&sym::thumb_mode) + && !target_features.contains(&sym::thumb2) + { + Err("high registers (r8+) can only be used as clobbers in Thumb-1 code") } else { Ok(()) } @@ -105,8 +113,9 @@ fn reserved_r9( arch: InlineAsmArch, target_features: &FxHashSet<Symbol>, target: &Target, + is_clobber: bool, ) -> Result<(), &'static str> { - not_thumb1(arch, target_features, target)?; + not_thumb1(arch, target_features, target, is_clobber)?; // We detect this using the reserved-r9 feature instead of using the target // because the relocation model can be changed with compiler options. diff --git a/compiler/rustc_target/src/asm/bpf.rs b/compiler/rustc_target/src/asm/bpf.rs index d94fcb53e24..b4d982f3836 100644 --- a/compiler/rustc_target/src/asm/bpf.rs +++ b/compiler/rustc_target/src/asm/bpf.rs @@ -47,6 +47,7 @@ fn only_alu32( _arch: InlineAsmArch, target_features: &FxHashSet<Symbol>, _target: &Target, + _is_clobber: bool, ) -> Result<(), &'static str> { if !target_features.contains(&sym::alu32) { Err("register can't be used without the `alu32` target feature") diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index a84410d0f3c..fd95b0338a6 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -83,12 +83,13 @@ macro_rules! def_regs { _arch: super::InlineAsmArch, _target_features: &rustc_data_structures::fx::FxHashSet<Symbol>, _target: &crate::spec::Target, + _is_clobber: bool, name: &str, ) -> Result<Self, &'static str> { match name { $( $($alias)|* | $reg_name => { - $($filter(_arch, _target_features, _target)?;)? + $($filter(_arch, _target_features, _target, _is_clobber)?;)? Ok(Self::$reg) } )* @@ -112,7 +113,7 @@ macro_rules! def_regs { #[allow(unused_imports)] use super::{InlineAsmReg, InlineAsmRegClass}; $( - if $($filter(_arch, _target_features, _target).is_ok() &&)? true { + if $($filter(_arch, _target_features, _target, false).is_ok() &&)? true { if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) { set.insert(InlineAsmReg::$arch($arch_reg::$reg)); } @@ -298,6 +299,7 @@ impl InlineAsmReg { arch: InlineAsmArch, target_features: &FxHashSet<Symbol>, target: &Target, + is_clobber: bool, name: Symbol, ) -> Result<Self, &'static str> { // FIXME: use direct symbol comparison for register names @@ -305,47 +307,79 @@ impl InlineAsmReg { let name = name.as_str(); Ok(match arch { InlineAsmArch::X86 | InlineAsmArch::X86_64 => { - Self::X86(X86InlineAsmReg::parse(arch, target_features, target, name)?) + Self::X86(X86InlineAsmReg::parse(arch, target_features, target, is_clobber, name)?) } InlineAsmArch::Arm => { - Self::Arm(ArmInlineAsmReg::parse(arch, target_features, target, name)?) - } - InlineAsmArch::AArch64 => { - Self::AArch64(AArch64InlineAsmReg::parse(arch, target_features, target, name)?) - } - InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => { - Self::RiscV(RiscVInlineAsmReg::parse(arch, target_features, target, name)?) - } - InlineAsmArch::Nvptx64 => { - Self::Nvptx(NvptxInlineAsmReg::parse(arch, target_features, target, name)?) - } - InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => { - Self::PowerPC(PowerPCInlineAsmReg::parse(arch, target_features, target, name)?) - } - InlineAsmArch::Hexagon => { - Self::Hexagon(HexagonInlineAsmReg::parse(arch, target_features, target, name)?) - } - InlineAsmArch::Mips | InlineAsmArch::Mips64 => { - Self::Mips(MipsInlineAsmReg::parse(arch, target_features, target, name)?) - } - InlineAsmArch::S390x => { - Self::S390x(S390xInlineAsmReg::parse(arch, target_features, target, name)?) - } - InlineAsmArch::SpirV => { - Self::SpirV(SpirVInlineAsmReg::parse(arch, target_features, target, name)?) - } - InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => { - Self::Wasm(WasmInlineAsmReg::parse(arch, target_features, target, name)?) + Self::Arm(ArmInlineAsmReg::parse(arch, target_features, target, is_clobber, name)?) } + InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmReg::parse( + arch, + target_features, + target, + is_clobber, + name, + )?), + InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => Self::RiscV( + RiscVInlineAsmReg::parse(arch, target_features, target, is_clobber, name)?, + ), + InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmReg::parse( + arch, + target_features, + target, + is_clobber, + name, + )?), + InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => Self::PowerPC( + PowerPCInlineAsmReg::parse(arch, target_features, target, is_clobber, name)?, + ), + InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmReg::parse( + arch, + target_features, + target, + is_clobber, + name, + )?), + InlineAsmArch::Mips | InlineAsmArch::Mips64 => Self::Mips(MipsInlineAsmReg::parse( + arch, + target_features, + target, + is_clobber, + name, + )?), + InlineAsmArch::S390x => Self::S390x(S390xInlineAsmReg::parse( + arch, + target_features, + target, + is_clobber, + name, + )?), + InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmReg::parse( + arch, + target_features, + target, + is_clobber, + name, + )?), + InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => Self::Wasm(WasmInlineAsmReg::parse( + arch, + target_features, + target, + is_clobber, + name, + )?), InlineAsmArch::Bpf => { - Self::Bpf(BpfInlineAsmReg::parse(arch, target_features, target, name)?) + Self::Bpf(BpfInlineAsmReg::parse(arch, target_features, target, is_clobber, name)?) } InlineAsmArch::Avr => { - Self::Avr(AvrInlineAsmReg::parse(arch, target_features, target, name)?) - } - InlineAsmArch::Msp430 => { - Self::Msp430(Msp430InlineAsmReg::parse(arch, target_features, target, name)?) + Self::Avr(AvrInlineAsmReg::parse(arch, target_features, target, is_clobber, name)?) } + InlineAsmArch::Msp430 => Self::Msp430(Msp430InlineAsmReg::parse( + arch, + target_features, + target, + is_clobber, + name, + )?), }) } @@ -844,7 +878,7 @@ impl InlineAsmClobberAbi { }, InlineAsmArch::AArch64 => match name { "C" | "system" | "efiapi" => { - Ok(if aarch64::reserved_x18(arch, target_features, target).is_err() { + Ok(if aarch64::reserved_x18(arch, target_features, target, true).is_err() { InlineAsmClobberAbi::AArch64NoX18 } else { InlineAsmClobberAbi::AArch64 diff --git a/compiler/rustc_target/src/asm/riscv.rs b/compiler/rustc_target/src/asm/riscv.rs index 39644d232ba..e145ba8a16e 100644 --- a/compiler/rustc_target/src/asm/riscv.rs +++ b/compiler/rustc_target/src/asm/riscv.rs @@ -56,6 +56,7 @@ fn not_e( _arch: InlineAsmArch, target_features: &FxHashSet<Symbol>, _target: &Target, + _is_clobber: bool, ) -> Result<(), &'static str> { if target_features.contains(&sym::e) { Err("register can't be used with the `e` target feature") diff --git a/compiler/rustc_target/src/asm/x86.rs b/compiler/rustc_target/src/asm/x86.rs index 01d32570f78..a8ee80ec4ea 100644 --- a/compiler/rustc_target/src/asm/x86.rs +++ b/compiler/rustc_target/src/asm/x86.rs @@ -141,6 +141,7 @@ fn x86_64_only( arch: InlineAsmArch, _target_features: &FxHashSet<Symbol>, _target: &Target, + _is_clobber: bool, ) -> Result<(), &'static str> { match arch { InlineAsmArch::X86 => Err("register is only available on x86_64"), @@ -153,6 +154,7 @@ fn high_byte( arch: InlineAsmArch, _target_features: &FxHashSet<Symbol>, _target: &Target, + _is_clobber: bool, ) -> Result<(), &'static str> { match arch { InlineAsmArch::X86_64 => Err("high byte registers cannot be used as an operand on x86_64"), @@ -164,6 +166,7 @@ fn rbx_reserved( arch: InlineAsmArch, _target_features: &FxHashSet<Symbol>, _target: &Target, + _is_clobber: bool, ) -> Result<(), &'static str> { match arch { InlineAsmArch::X86 => Ok(()), @@ -178,6 +181,7 @@ fn esi_reserved( arch: InlineAsmArch, _target_features: &FxHashSet<Symbol>, _target: &Target, + _is_clobber: bool, ) -> Result<(), &'static str> { match arch { InlineAsmArch::X86 => { diff --git a/compiler/rustc_target/src/spec/aarch64_linux_android.rs b/compiler/rustc_target/src/spec/aarch64_linux_android.rs index 1e9abbbe1e7..5692925f63b 100644 --- a/compiler/rustc_target/src/spec/aarch64_linux_android.rs +++ b/compiler/rustc_target/src/spec/aarch64_linux_android.rs @@ -14,7 +14,9 @@ pub fn target() -> Target { // As documented in https://developer.android.com/ndk/guides/cpu-features.html // the neon (ASIMD) and FP must exist on all android aarch64 targets. features: "+neon,+fp-armv8".to_string(), - supported_sanitizers: SanitizerSet::CFI | SanitizerSet::HWADDRESS, + supported_sanitizers: SanitizerSet::CFI + | SanitizerSet::HWADDRESS + | SanitizerSet::MEMTAG, ..super::android_base::opts() }, } diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs index 850381f7fb0..974a5b84d1d 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs @@ -14,6 +14,7 @@ pub fn target() -> Target { | SanitizerSet::CFI | SanitizerSet::LEAK | SanitizerSet::MEMORY + | SanitizerSet::MEMTAG | SanitizerSet::THREAD | SanitizerSet::HWADDRESS, ..super::linux_gnu_base::opts() diff --git a/compiler/rustc_target/src/spec/mips64_openwrt_linux_musl.rs b/compiler/rustc_target/src/spec/mips64_openwrt_linux_musl.rs index 1199ed44202..5991cd8bfa9 100644 --- a/compiler/rustc_target/src/spec/mips64_openwrt_linux_musl.rs +++ b/compiler/rustc_target/src/spec/mips64_openwrt_linux_musl.rs @@ -6,7 +6,7 @@ use crate::spec::{Target, TargetOptions}; pub fn target() -> Target { let mut base = super::linux_musl_base::opts(); base.cpu = "mips64r2".to_string(); - base.features = "+mips64r2".to_string(); + base.features = "+mips64r2,+soft-float".to_string(); base.max_atomic_width = Some(64); base.crt_static_default = false; diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index bfafe2d83d7..92678aed5b1 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -606,6 +606,7 @@ bitflags::bitflags! { const THREAD = 1 << 3; const HWADDRESS = 1 << 4; const CFI = 1 << 5; + const MEMTAG = 1 << 6; } } @@ -619,6 +620,7 @@ impl SanitizerSet { SanitizerSet::CFI => "cfi", SanitizerSet::LEAK => "leak", SanitizerSet::MEMORY => "memory", + SanitizerSet::MEMTAG => "memtag", SanitizerSet::THREAD => "thread", SanitizerSet::HWADDRESS => "hwaddress", _ => return None, @@ -652,6 +654,7 @@ impl IntoIterator for SanitizerSet { SanitizerSet::CFI, SanitizerSet::LEAK, SanitizerSet::MEMORY, + SanitizerSet::MEMTAG, SanitizerSet::THREAD, SanitizerSet::HWADDRESS, ] @@ -1883,6 +1886,7 @@ impl Target { Some("cfi") => SanitizerSet::CFI, Some("leak") => SanitizerSet::LEAK, Some("memory") => SanitizerSet::MEMORY, + Some("memtag") => SanitizerSet::MEMTAG, Some("thread") => SanitizerSet::THREAD, Some("hwaddress") => SanitizerSet::HWADDRESS, Some(s) => return Err(format!("unknown sanitizer {}", s)), diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs index 603ab0622f0..bf6e6a4fcbb 100644 --- a/compiler/rustc_trait_selection/src/traits/codegen.rs +++ b/compiler/rustc_trait_selection/src/traits/codegen.rs @@ -64,6 +64,8 @@ pub fn codegen_fulfill_obligation<'tcx>( Err(Unimplemented) => { // This can trigger when we probe for the source of a `'static` lifetime requirement // on a trait object: `impl Foo for dyn Trait {}` has an implicit `'static` bound. + // This can also trigger when we have a global bound that is not actually satisfied, + // but was included during typeck due to the trivial_bounds feature. infcx.tcx.sess.delay_span_bug( rustc_span::DUMMY_SP, &format!( diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index f22b4e8d072..c3df17c83bb 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1437,8 +1437,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { self.tcx .associated_items(did) .in_definition_order() - .filter(|assoc| assoc.ident(self.tcx) == trait_assoc_ident) - .next() + .find(|assoc| assoc.ident(self.tcx) == trait_assoc_ident) }, ) }) 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 40cb9647a35..7df880a7cc0 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1099,9 +1099,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { _ => return false, }; - let ret_ty = if let hir::FnRetTy::Return(ret_ty) = sig.decl.output { - ret_ty - } else { + let hir::FnRetTy::Return(ret_ty) = sig.decl.output else { return false; }; @@ -1168,7 +1166,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }; let sm = self.tcx.sess.source_map(); - let snippet = if let (true, hir::TyKind::TraitObject(..), Ok(snippet), true) = ( + let (true, hir::TyKind::TraitObject(..), Ok(snippet), true) = ( // Verify that we're dealing with a return `dyn Trait` ret_ty.span.overlaps(span), &ret_ty.kind, @@ -1176,9 +1174,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // If any of the return types does not conform to the trait, then we can't // suggest `impl Trait` nor trait objects: it is a type mismatch error. all_returns_conform_to_trait, - ) { - snippet - } else { + ) else { return false; }; err.code(error_code!(E0746)); @@ -1932,7 +1928,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { | ObligationCauseCode::AwaitableExpr(_) | ObligationCauseCode::ForLoopIterator | ObligationCauseCode::QuestionMark - | ObligationCauseCode::LetElse => {} + | ObligationCauseCode::LetElse + | ObligationCauseCode::CheckAssociatedTypeBounds { .. } => {} ObligationCauseCode::SliceOrArrayElem => { err.note("slice and array elements must have `Sized` type"); } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 5f338664c9a..dba24fb2f31 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -19,6 +19,7 @@ use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey}; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; use crate::traits::error_reporting::InferCtxtExt as _; +use crate::traits::select::ProjectionMatchesProjection; use rustc_data_structures::sso::SsoHashSet; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::ErrorReported; @@ -959,7 +960,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone()); } obligations.extend(result.obligations); - Ok(Some(result.value.into())) + Ok(Some(result.value)) } Ok(Projected::NoProgress(projected_ty)) => { let result = Normalized { value: projected_ty, obligations: vec![] }; @@ -1075,16 +1076,6 @@ fn project<'cx, 'tcx>( return Ok(Projected::Progress(Progress::error(selcx.tcx()))); } - // If the obligation contains any inference types or consts in associated - // type substs, then we don't assemble any candidates. - // This isn't really correct, but otherwise we can end up in a case where - // we constrain inference variables by selecting a single predicate, when - // we need to stay general. See issue #91762. - let (_, predicate_own_substs) = obligation.predicate.trait_ref_and_own_substs(selcx.tcx()); - if predicate_own_substs.iter().any(|g| g.has_infer_types_or_consts()) { - return Err(ProjectionError::TooManyCandidates); - } - let mut candidates = ProjectionCandidateSet::None; // Make sure that the following procedures are kept in order. ParamEnv @@ -1182,7 +1173,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( ProjectionCandidate::TraitDef, bounds.iter(), true, - ) + ); } /// In the case of a trait object like @@ -1247,28 +1238,35 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>( let bound_predicate = predicate.kind(); if let ty::PredicateKind::Projection(data) = predicate.kind().skip_binder() { let data = bound_predicate.rebind(data); - let same_def_id = data.projection_def_id() == obligation.predicate.item_def_id; - - let is_match = same_def_id - && infcx.probe(|_| { - selcx.match_projection_projections( - obligation, - data, - potentially_unnormalized_candidates, - ) - }); + if data.projection_def_id() != obligation.predicate.item_def_id { + continue; + } - if is_match { - candidate_set.push_candidate(ctor(data)); + let is_match = infcx.probe(|_| { + selcx.match_projection_projections( + obligation, + data, + potentially_unnormalized_candidates, + ) + }); - if potentially_unnormalized_candidates - && !obligation.predicate.has_infer_types_or_consts() - { - // HACK: Pick the first trait def candidate for a fully - // inferred predicate. This is to allow duplicates that - // differ only in normalization. - return; + match is_match { + ProjectionMatchesProjection::Yes => { + candidate_set.push_candidate(ctor(data)); + + if potentially_unnormalized_candidates + && !obligation.predicate.has_infer_types_or_consts() + { + // HACK: Pick the first trait def candidate for a fully + // inferred predicate. This is to allow duplicates that + // differ only in normalization. + return; + } + } + ProjectionMatchesProjection::Ambiguous => { + candidate_set.mark_ambiguous(); } + ProjectionMatchesProjection::No => {} } } } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 64af875dd22..3b69700530b 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1494,12 +1494,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }) } + /// Return `Yes` if the obligation's predicate type applies to the env_predicate, and + /// `No` if it does not. Return `Ambiguous` in the case that the projection type is a GAT, + /// and applying this env_predicate constrains any of the obligation's GAT substitutions. + /// + /// This behavior is a somewhat of a hack to prevent overconstraining inference variables + /// in cases like #91762. pub(super) fn match_projection_projections( &mut self, obligation: &ProjectionTyObligation<'tcx>, env_predicate: PolyProjectionPredicate<'tcx>, potentially_unnormalized_candidates: bool, - ) -> bool { + ) -> ProjectionMatchesProjection { let mut nested_obligations = Vec::new(); let (infer_predicate, _) = self.infcx.replace_bound_vars_with_fresh_vars( obligation.cause.span, @@ -1521,7 +1527,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { infer_predicate.projection_ty }; - self.infcx + let is_match = self + .infcx .at(&obligation.cause, obligation.param_env) .sup(obligation.predicate, infer_projection) .map_or(false, |InferOk { obligations, value: () }| { @@ -1530,7 +1537,26 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { nested_obligations.into_iter().chain(obligations), ) .map_or(false, |res| res.may_apply()) - }) + }); + + if is_match { + let generics = self.tcx().generics_of(obligation.predicate.item_def_id); + // FIXME(generic-associated-types): Addresses aggressive inference in #92917. + // If this type is a GAT, and of the GAT substs resolve to something new, + // that means that we must have newly inferred something about the GAT. + // We should give up in that case. + if !generics.params.is_empty() + && obligation.predicate.substs[generics.parent_count..] + .iter() + .any(|&p| p.has_infer_types_or_consts() && self.infcx.shallow_resolve(p) != p) + { + ProjectionMatchesProjection::Ambiguous + } else { + ProjectionMatchesProjection::Yes + } + } else { + ProjectionMatchesProjection::No + } } /////////////////////////////////////////////////////////////////////////// @@ -2709,3 +2735,9 @@ impl<'o, 'tcx> fmt::Debug for TraitObligationStack<'o, 'tcx> { write!(f, "TraitObligationStack({:?})", self.obligation) } } + +pub enum ProjectionMatchesProjection { + Yes, + Ambiguous, + No, +} diff --git a/compiler/rustc_typeck/src/astconv/errors.rs b/compiler/rustc_typeck/src/astconv/errors.rs index a49d6e24f26..7e9abe3a250 100644 --- a/compiler/rustc_typeck/src/astconv/errors.rs +++ b/compiler/rustc_typeck/src/astconv/errors.rs @@ -211,8 +211,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ); let all_candidate_names: Vec<_> = all_candidates() - .map(|r| self.tcx().associated_items(r.def_id()).in_definition_order()) - .flatten() + .flat_map(|r| self.tcx().associated_items(r.def_id()).in_definition_order()) .filter_map( |item| if item.kind == ty::AssocKind::Type { Some(item.name) } else { None }, ) diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 845f03183c3..96f92049983 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -2409,11 +2409,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let def_id = item_id.def_id.to_def_id(); match opaque_ty.kind { - hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => { - let replace_parent_lifetimes = - matches!(origin, hir::OpaqueTyOrigin::FnReturn(..)); - self.impl_trait_ty_to_ty(def_id, lifetimes, replace_parent_lifetimes) - } + hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => self + .impl_trait_ty_to_ty( + def_id, + lifetimes, + matches!( + origin, + hir::OpaqueTyOrigin::FnReturn(..) + | hir::OpaqueTyOrigin::AsyncFn(..) + ), + ), ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i), } } diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 6dbda1005dd..1650a62f79f 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -392,7 +392,7 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b "when the type does not implement `Copy`, \ wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped", vec![ - (ty_span.shrink_to_lo(), format!("std::mem::ManuallyDrop<")), + (ty_span.shrink_to_lo(), "std::mem::ManuallyDrop<".into()), (ty_span.shrink_to_hi(), ">".into()), ], Applicability::MaybeIncorrect, @@ -545,8 +545,10 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>( } } - if let ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(..), .. }) = - item.kind + if let ItemKind::OpaqueTy(hir::OpaqueTy { + origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..), + .. + }) = item.kind { let mut visitor = ProhibitOpaqueVisitor { opaque_identity_ty: tcx.mk_opaque( @@ -568,13 +570,20 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>( if let Some(ty) = prohibit_opaque.break_value() { visitor.visit_item(&item); + let is_async = match item.kind { + ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => { + matches!(origin, hir::OpaqueTyOrigin::AsyncFn(..)) + } + _ => unreachable!(), + }; let mut err = struct_span_err!( tcx.sess, span, E0760, - "`impl Trait` return type cannot contain a projection or `Self` that references lifetimes from \ + "`{}` return type cannot contain a projection or `Self` that references lifetimes from \ a parent scope", + if is_async { "async fn" } else { "impl Trait" }, ); for (span, name) in visitor.selftys { diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index 457e9cf1ea5..38449c2a76a 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -1378,7 +1378,14 @@ pub fn check_type_bounds<'tcx>( let mut selcx = traits::SelectionContext::new(&infcx); let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local()); - let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id); + let normalize_cause = ObligationCause::new( + impl_ty_span, + impl_ty_hir_id, + ObligationCauseCode::CheckAssociatedTypeBounds { + impl_item_def_id: impl_ty.def_id, + trait_item_def_id: trait_ty.def_id, + }, + ); let mk_cause = |span: Span| { let code = if span.is_dummy() { traits::MiscObligation diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index d0e96e7538c..e7eadb760c7 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -340,7 +340,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) { Some(ident) => format!("{}: ", ident), - None => format!(""), + None => String::new(), }; match &compatible_variants[..] { @@ -683,7 +683,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) { Some(ident) => format!("{}: ", ident), - None => format!(""), + None => String::new(), }; if let Some(hir::Node::Expr(hir::Expr { @@ -875,7 +875,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) { Some(ident) => format!("{}: ", ident), - None => format!(""), + None => String::new(), }; let (span, suggestion) = if self.is_else_if_block(expr) { // Don't suggest nonsense like `else *if` diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index b5f13703edf..4869d193d80 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -1318,10 +1318,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { base_expr: &'tcx Option<&'tcx hir::Expr<'tcx>>, ) -> Ty<'tcx> { // Find the relevant variant - let (variant, adt_ty) = if let Some(variant_ty) = self.check_struct_path(qpath, expr.hir_id) - { - variant_ty - } else { + let Some((variant, adt_ty)) = self.check_struct_path(qpath, expr.hir_id) else { self.check_struct_fields_on_error(fields, base_expr); return self.tcx.ty_error(); }; diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index 86cf850d723..f9c482713f1 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -8,8 +8,12 @@ use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind}; use rustc_hir::lang_items::LangItem; -use rustc_hir::{Expr, ExprKind, ItemKind, Node, Path, QPath, Stmt, StmtKind, TyKind}; +use rustc_hir::{ + Expr, ExprKind, GenericBound, ItemKind, Node, Path, QPath, Stmt, StmtKind, TyKind, + WherePredicate, +}; use rustc_infer::infer::{self, TyCtxtInferExt}; + use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Binder, Ty}; use rustc_span::symbol::{kw, sym}; @@ -559,6 +563,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = self.tcx.erase_late_bound_regions(ty); if self.can_coerce(expected, ty) { err.span_label(sp, format!("expected `{}` because of return type", expected)); + self.try_suggest_return_impl_trait(err, expected, ty, fn_id); return true; } false @@ -566,6 +571,115 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + /// check whether the return type is a generic type with a trait bound + /// only suggest this if the generic param is not present in the arguments + /// if this is true, hint them towards changing the return type to `impl Trait` + /// ``` + /// fn cant_name_it<T: Fn() -> u32>() -> T { + /// || 3 + /// } + /// ``` + fn try_suggest_return_impl_trait( + &self, + err: &mut DiagnosticBuilder<'_>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + fn_id: hir::HirId, + ) { + // Only apply the suggestion if: + // - the return type is a generic parameter + // - the generic param is not used as a fn param + // - the generic param has at least one bound + // - the generic param doesn't appear in any other bounds where it's not the Self type + // Suggest: + // - Changing the return type to be `impl <all bounds>` + + debug!("try_suggest_return_impl_trait, expected = {:?}, found = {:?}", expected, found); + + let ty::Param(expected_ty_as_param) = expected.kind() else { return }; + + let fn_node = self.tcx.hir().find(fn_id); + + let Some(hir::Node::Item(hir::Item { + kind: + hir::ItemKind::Fn( + hir::FnSig { decl: hir::FnDecl { inputs: fn_parameters, output: fn_return, .. }, .. }, + hir::Generics { params, where_clause, .. }, + _body_id, + ), + .. + })) = fn_node else { return }; + + let Some(expected_generic_param) = params.get(expected_ty_as_param.index as usize) else { return }; + + // get all where BoundPredicates here, because they are used in to cases below + let where_predicates = where_clause + .predicates + .iter() + .filter_map(|p| match p { + WherePredicate::BoundPredicate(hir::WhereBoundPredicate { + bounds, + bounded_ty, + .. + }) => { + // FIXME: Maybe these calls to `ast_ty_to_ty` can be removed (and the ones below) + let ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, bounded_ty); + Some((ty, bounds)) + } + _ => None, + }) + .map(|(ty, bounds)| match ty.kind() { + ty::Param(param_ty) if param_ty == expected_ty_as_param => Ok(Some(bounds)), + // check whether there is any predicate that contains our `T`, like `Option<T>: Send` + _ => match ty.contains(expected) { + true => Err(()), + false => Ok(None), + }, + }) + .collect::<Result<Vec<_>, _>>(); + + let Ok(where_predicates) = where_predicates else { return }; + + // now get all predicates in the same types as the where bounds, so we can chain them + let predicates_from_where = + where_predicates.iter().flatten().map(|bounds| bounds.iter()).flatten(); + + // extract all bounds from the source code using their spans + let all_matching_bounds_strs = expected_generic_param + .bounds + .iter() + .chain(predicates_from_where) + .filter_map(|bound| match bound { + GenericBound::Trait(_, _) => { + self.tcx.sess.source_map().span_to_snippet(bound.span()).ok() + } + _ => None, + }) + .collect::<Vec<String>>(); + + if all_matching_bounds_strs.len() == 0 { + return; + } + + let all_bounds_str = all_matching_bounds_strs.join(" + "); + + let ty_param_used_in_fn_params = fn_parameters.iter().any(|param| { + let ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, param); + matches!(ty.kind(), ty::Param(fn_param_ty_param) if expected_ty_as_param == fn_param_ty_param) + }); + + if ty_param_used_in_fn_params { + return; + } + + err.span_suggestion( + fn_return.span(), + "consider using an impl return type", + format!("impl {}", all_bounds_str), + Applicability::MaybeIncorrect, + ); + } + pub(in super::super) fn suggest_missing_break_or_return_expr( &self, err: &mut DiagnosticBuilder<'_>, diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs index c4e7d6a199e..972dd622d6e 100644 --- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs +++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs @@ -246,7 +246,7 @@ impl DropRangesBuilder { fn add_control_edge(&mut self, from: PostOrderId, to: PostOrderId) { trace!("adding control edge from {:?} to {:?}", from, to); - self.node_mut(from.into()).successors.push(to.into()); + self.node_mut(from).successors.push(to); } } diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs index e2a4d9c1b3a..cfed784ea72 100644 --- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs +++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs @@ -527,7 +527,7 @@ impl DropRangesBuilder { fn drop_at(&mut self, value: TrackedValue, location: PostOrderId) { let value = self.tracked_value_index(value); - self.node_mut(location.into()).drops.push(value); + self.node_mut(location).drops.push(value); } fn reinit_at(&mut self, value: TrackedValue, location: PostOrderId) { @@ -537,7 +537,7 @@ impl DropRangesBuilder { // ignore this. None => return, }; - self.node_mut(location.into()).reinits.push(value); + self.node_mut(location).reinits.push(value); } /// Looks up PostOrderId for any control edges added by HirId and adds a proper edge for them. diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 88dc90dd3e7..18f54eb2246 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -2157,7 +2157,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP generics } ItemKind::OpaqueTy(OpaqueTy { - origin: hir::OpaqueTyOrigin::FnReturn(..), .. + origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..), + .. }) => { // return-position impl trait // @@ -2177,7 +2178,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP } ItemKind::OpaqueTy(OpaqueTy { ref generics, - origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::TyAlias, + origin: hir::OpaqueTyOrigin::TyAlias, .. }) => { // type-alias impl trait @@ -3008,6 +3009,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI; } else if item.has_name(sym::memory) { codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY; + } else if item.has_name(sym::memtag) { + codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG; } else if item.has_name(sym::thread) { codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD; } else if item.has_name(sym::hwaddress) { @@ -3015,7 +3018,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { } else { tcx.sess .struct_span_err(item.span(), "invalid argument for `no_sanitize`") - .note("expected one of: `address`, `hwaddress`, `memory` or `thread`") + .note("expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, or `thread`") .emit(); } } diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index 90555b213c1..39da7c82c4e 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -1,7 +1,6 @@ use rustc_errors::{Applicability, ErrorReported, StashKey}; use rustc_hir as hir; -use rustc_hir::def::CtorOf; -use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def::Res; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit; use rustc_hir::intravisit::Visitor; @@ -9,7 +8,7 @@ use rustc_hir::{HirId, Node}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::util::IntTypeExt; -use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable, TypeFolder}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder}; use rustc_span::symbol::Ident; use rustc_span::{Span, DUMMY_SP}; @@ -198,38 +197,9 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< // Try to use the segment resolution if it is valid, otherwise we // default to the path resolution. let res = segment.res.filter(|&r| r != Res::Err).unwrap_or(path.res); - let generics = match res { - Res::Def(DefKind::Ctor(CtorOf::Variant, _), def_id) => tcx - .generics_of(tcx.parent(def_id).and_then(|def_id| tcx.parent(def_id)).unwrap()), - Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Struct, _), def_id) => { - tcx.generics_of(tcx.parent(def_id).unwrap()) - } - // Other `DefKind`s don't have generics and would ICE when calling - // `generics_of`. - Res::Def( - DefKind::Struct - | DefKind::Union - | DefKind::Enum - | DefKind::Trait - | DefKind::OpaqueTy - | DefKind::TyAlias - | DefKind::ForeignTy - | DefKind::TraitAlias - | DefKind::AssocTy - | DefKind::Fn - | DefKind::AssocFn - | DefKind::AssocConst - | DefKind::Impl, - def_id, - ) => tcx.generics_of(def_id), - Res::Err => { - tcx.sess.delay_span_bug(tcx.def_span(def_id), "anon const with Res::Err"); - return None; - } - _ => { - // If the user tries to specify generics on a type that does not take them, - // e.g. `usize<T>`, we may hit this branch, in which case we treat it as if - // no arguments have been passed. An error should already have been emitted. + let generics = match tcx.res_generics_def_id(res) { + Some(def_id) => tcx.generics_of(def_id), + None => { tcx.sess.delay_span_bug( tcx.def_span(def_id), &format!("unexpected anon const res {:?} in path: {:?}", res, path), @@ -527,7 +497,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { // FIXME(associated_const_equality): add a useful error message here. tcx.ty_error_with_message( DUMMY_SP, - &format!("Could not find associated const on trait"), + "Could not find associated const on trait", ) } } diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index aa7344ba405..68bf59a01b3 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -133,6 +133,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use core::any::Any; +use core::async_iter::AsyncIterator; use core::borrow; use core::cmp::Ordering; use core::convert::{From, TryFrom}; @@ -149,7 +150,6 @@ use core::ops::{ }; use core::pin::Pin; use core::ptr::{self, Unique}; -use core::stream::Stream; use core::task::{Context, Poll}; #[cfg(not(no_global_oom_handling))] @@ -1992,8 +1992,8 @@ where } } -#[unstable(feature = "async_stream", issue = "79024")] -impl<S: ?Sized + Stream + Unpin> Stream for Box<S> { +#[unstable(feature = "async_iterator", issue = "79024")] +impl<S: ?Sized + AsyncIterator + Unpin> AsyncIterator for Box<S> { type Item = S::Item; fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs index 56a47001811..e18cd8cd464 100644 --- a/library/alloc/src/collections/binary_heap.rs +++ b/library/alloc/src/collections/binary_heap.rs @@ -746,9 +746,12 @@ impl<T: Ord> BinaryHeap<T> { self.rebuild_tail(start); } - /// Returns an iterator which retrieves elements in heap order. - /// The retrieved elements are removed from the original heap. - /// The remaining elements will be removed on drop in heap order. + /// Clears the binary heap, returning an iterator over the removed elements + /// in heap order. If the iterator is dropped before being fully consumed, + /// it drops the remaining elements in heap order. + /// + /// The returned iterator keeps a mutable borrow on the heap to optimize + /// its implementation. /// /// Note: /// * `.drain_sorted()` is *O*(*n* \* log(*n*)); much slower than `.drain()`. @@ -1158,9 +1161,12 @@ impl<T> BinaryHeap<T> { self.len() == 0 } - /// Clears the binary heap, returning an iterator over the removed elements. + /// Clears the binary heap, returning an iterator over the removed elements + /// in arbitrary order. If the iterator is dropped before being fully + /// consumed, it drops the remaining elements in arbitrary order. /// - /// The elements are removed in arbitrary order. + /// The returned iterator keeps a mutable borrow on the heap to optimize + /// its implementation. /// /// # Examples /// diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 763175fc045..7139a0fb94d 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -1215,21 +1215,25 @@ impl<T, A: Allocator> VecDeque<T, A> { unsafe { IterMut::new(ring, tail, head, PhantomData) } } - /// Creates a draining iterator that removes the specified range in the - /// deque and yields the removed items. + /// Removes the specified range from the deque in bulk, returning all + /// removed elements as an iterator. If the iterator is dropped before + /// being fully consumed, it drops the remaining removed elements. /// - /// Note 1: The element range is removed even if the iterator is not - /// consumed until the end. + /// The returned iterator keeps a mutable borrow on the queue to optimize + /// its implementation. /// - /// Note 2: It is unspecified how many elements are removed from the deque, - /// if the `Drain` value is not dropped, but the borrow it holds expires - /// (e.g., due to `mem::forget`). /// /// # Panics /// /// Panics if the starting point is greater than the end point or if /// the end point is greater than the length of the deque. /// + /// # Leaking + /// + /// If the returned iterator goes out of scope without being dropped (due to + /// [`mem::forget`], for example), the deque may have lost and leaked + /// elements arbitrarily, including elements outside the range. + /// /// # Examples /// /// ``` @@ -1240,7 +1244,7 @@ impl<T, A: Allocator> VecDeque<T, A> { /// assert_eq!(drained, [3]); /// assert_eq!(deque, [1, 2]); /// - /// // A full range clears all contents + /// // A full range clears all contents, like `clear()` does /// deque.drain(..); /// assert!(deque.is_empty()); /// ``` diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index ce75859f963..6da32df57ef 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -91,7 +91,7 @@ #![feature(array_chunks)] #![feature(array_methods)] #![feature(array_windows)] -#![feature(async_stream)] +#![feature(async_iterator)] #![feature(coerce_unsized)] #![cfg_attr(not(no_global_oom_handling), feature(const_alloc_error))] #![feature(const_box)] diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 7c0faf0659a..716bb4983a6 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1628,17 +1628,24 @@ impl String { self.vec.clear() } - /// Creates a draining iterator that removes the specified range in the `String` - /// and yields the removed `chars`. + /// Removes the specified range from the string in bulk, returning all + /// removed characters as an iterator. /// - /// Note: The element range is removed even if the iterator is not - /// consumed until the end. + /// The returned iterator keeps a mutable borrow on the string to optimize + /// its implementation. /// /// # Panics /// /// Panics if the starting point or end point do not lie on a [`char`] /// boundary, or if they're out of bounds. /// + /// # Leaking + /// + /// If the returned iterator goes out of scope without being dropped (due to + /// [`core::mem::forget`], for example), the string may still contain a copy + /// of any drained characters, or may have lost characters arbitrarily, + /// including characters outside the range. + /// /// # Examples /// /// Basic usage: @@ -1652,7 +1659,7 @@ impl String { /// assert_eq!(t, "α is alpha, "); /// assert_eq!(s, "β is beta"); /// - /// // A full range clears the string + /// // A full range clears the string, like `clear()` does /// s.drain(..); /// assert_eq!(s, ""); /// ``` diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 3dc3eee4133..c29aa0fec5b 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1799,19 +1799,24 @@ impl<T, A: Allocator> Vec<T, A> { self.len += count; } - /// Creates a draining iterator that removes the specified range in the vector - /// and yields the removed items. + /// Removes the specified range from the vector in bulk, returning all + /// removed elements as an iterator. If the iterator is dropped before + /// being fully consumed, it drops the remaining removed elements. /// - /// When the iterator **is** dropped, all elements in the range are removed - /// from the vector, even if the iterator was not fully consumed. If the - /// iterator **is not** dropped (with [`mem::forget`] for example), it is - /// unspecified how many elements are removed. + /// The returned iterator keeps a mutable borrow on the vector to optimize + /// its implementation. /// /// # Panics /// /// Panics if the starting point is greater than the end point or if /// the end point is greater than the length of the vector. /// + /// # Leaking + /// + /// If the returned iterator goes out of scope without being dropped (due to + /// [`mem::forget`], for example), the vector may have lost and leaked + /// elements arbitrarily, including elements outside the range. + /// /// # Examples /// /// ``` @@ -1820,7 +1825,7 @@ impl<T, A: Allocator> Vec<T, A> { /// assert_eq!(v, &[1]); /// assert_eq!(u, &[2, 3]); /// - /// // A full range clears the vector + /// // A full range clears the vector, like `clear()` does /// v.drain(..); /// assert_eq!(v, &[]); /// ``` diff --git a/library/core/src/stream/stream.rs b/library/core/src/async_iter/async_iter.rs index 2cfddf9ad01..f29de31171a 100644 --- a/library/core/src/stream/stream.rs +++ b/library/core/src/async_iter/async_iter.rs @@ -4,50 +4,50 @@ use crate::task::{Context, Poll}; /// An interface for dealing with asynchronous iterators. /// -/// This is the main stream trait. For more about the concept of streams +/// This is the main async iterator trait. For more about the concept of async iterators /// generally, please see the [module-level documentation]. In particular, you -/// may want to know how to [implement `Stream`][impl]. +/// may want to know how to [implement `AsyncIterator`][impl]. /// /// [module-level documentation]: index.html -/// [impl]: index.html#implementing-stream -#[unstable(feature = "async_stream", issue = "79024")] -#[must_use = "streams do nothing unless polled"] -pub trait Stream { - /// The type of items yielded by the stream. +/// [impl]: index.html#implementing-async-iterator +#[unstable(feature = "async_iterator", issue = "79024")] +#[must_use = "async iterators do nothing unless polled"] +pub trait AsyncIterator { + /// The type of items yielded by the async iterator. type Item; - /// Attempt to pull out the next value of this stream, registering the + /// Attempt to pull out the next value of this async iterator, registering the /// current task for wakeup if the value is not yet available, and returning - /// `None` if the stream is exhausted. + /// `None` if the async iterator is exhausted. /// /// # Return value /// /// There are several possible return values, each indicating a distinct - /// stream state: + /// async iterator state: /// - /// - `Poll::Pending` means that this stream's next value is not ready + /// - `Poll::Pending` means that this async iterator's next value is not ready /// yet. Implementations will ensure that the current task will be notified /// when the next value may be ready. /// - /// - `Poll::Ready(Some(val))` means that the stream has successfully + /// - `Poll::Ready(Some(val))` means that the async iterator has successfully /// produced a value, `val`, and may produce further values on subsequent /// `poll_next` calls. /// - /// - `Poll::Ready(None)` means that the stream has terminated, and + /// - `Poll::Ready(None)` means that the async iterator has terminated, and /// `poll_next` should not be invoked again. /// /// # Panics /// - /// Once a stream has finished (returned `Ready(None)` from `poll_next`), calling its + /// Once an async iterator has finished (returned `Ready(None)` from `poll_next`), calling its /// `poll_next` method again may panic, block forever, or cause other kinds of - /// problems; the `Stream` trait places no requirements on the effects of + /// problems; the `AsyncIterator` trait places no requirements on the effects of /// such a call. However, as the `poll_next` method is not marked `unsafe`, /// Rust's usual rules apply: calls must never cause undefined behavior /// (memory corruption, incorrect use of `unsafe` functions, or the like), - /// regardless of the stream's state. + /// regardless of the async iterator's state. fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>; - /// Returns the bounds on the remaining length of the stream. + /// Returns the bounds on the remaining length of the async iterator. /// /// Specifically, `size_hint()` returns a tuple where the first element /// is the lower bound, and the second element is the upper bound. @@ -58,12 +58,12 @@ pub trait Stream { /// /// # Implementation notes /// - /// It is not enforced that a stream implementation yields the declared - /// number of elements. A buggy stream may yield less than the lower bound + /// It is not enforced that an async iterator implementation yields the declared + /// number of elements. A buggy async iterator may yield less than the lower bound /// or more than the upper bound of elements. /// /// `size_hint()` is primarily intended to be used for optimizations such as - /// reserving space for the elements of the stream, but must not be + /// reserving space for the elements of the async iterator, but must not be /// trusted to e.g., omit bounds checks in unsafe code. An incorrect /// implementation of `size_hint()` should not lead to memory safety /// violations. @@ -72,15 +72,15 @@ pub trait Stream { /// because otherwise it would be a violation of the trait's protocol. /// /// The default implementation returns <code>(0, [None])</code> which is correct for any - /// stream. + /// async iterator. #[inline] fn size_hint(&self) -> (usize, Option<usize>) { (0, None) } } -#[unstable(feature = "async_stream", issue = "79024")] -impl<S: ?Sized + Stream + Unpin> Stream for &mut S { +#[unstable(feature = "async_iterator", issue = "79024")] +impl<S: ?Sized + AsyncIterator + Unpin> AsyncIterator for &mut S { type Item = S::Item; fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { @@ -92,16 +92,16 @@ impl<S: ?Sized + Stream + Unpin> Stream for &mut S { } } -#[unstable(feature = "async_stream", issue = "79024")] -impl<P> Stream for Pin<P> +#[unstable(feature = "async_iterator", issue = "79024")] +impl<P> AsyncIterator for Pin<P> where P: DerefMut, - P::Target: Stream, + P::Target: AsyncIterator, { - type Item = <P::Target as Stream>::Item; + type Item = <P::Target as AsyncIterator>::Item; fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { - <P::Target as Stream>::poll_next(self.as_deref_mut(), cx) + <P::Target as AsyncIterator>::poll_next(self.as_deref_mut(), cx) } fn size_hint(&self) -> (usize, Option<usize>) { diff --git a/library/core/src/stream/from_iter.rs b/library/core/src/async_iter/from_iter.rs index eb9a0fd2842..3180187afc8 100644 --- a/library/core/src/stream/from_iter.rs +++ b/library/core/src/async_iter/from_iter.rs @@ -1,31 +1,31 @@ use crate::pin::Pin; -use crate::stream::Stream; +use crate::async_iter::AsyncIterator; use crate::task::{Context, Poll}; -/// A stream that was created from iterator. +/// An async iterator that was created from iterator. /// -/// This stream is created by the [`from_iter`] function. +/// This async iterator is created by the [`from_iter`] function. /// See it documentation for more. /// /// [`from_iter`]: fn.from_iter.html -#[unstable(feature = "stream_from_iter", issue = "81798")] +#[unstable(feature = "async_iter_from_iter", issue = "81798")] #[derive(Clone, Debug)] pub struct FromIter<I> { iter: I, } -#[unstable(feature = "stream_from_iter", issue = "81798")] +#[unstable(feature = "async_iter_from_iter", issue = "81798")] impl<I> Unpin for FromIter<I> {} -/// Converts an iterator into a stream. -#[unstable(feature = "stream_from_iter", issue = "81798")] +/// Converts an iterator into an async iterator. +#[unstable(feature = "async_iter_from_iter", issue = "81798")] pub fn from_iter<I: IntoIterator>(iter: I) -> FromIter<I::IntoIter> { FromIter { iter: iter.into_iter() } } -#[unstable(feature = "stream_from_iter", issue = "81798")] -impl<I: Iterator> Stream for FromIter<I> { +#[unstable(feature = "async_iter_from_iter", issue = "81798")] +impl<I: Iterator> AsyncIterator for FromIter<I> { type Item = I::Item; fn poll_next(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { diff --git a/library/core/src/stream/mod.rs b/library/core/src/async_iter/mod.rs index b59a46d5f3a..0c6f637711b 100644 --- a/library/core/src/stream/mod.rs +++ b/library/core/src/async_iter/mod.rs @@ -1,10 +1,9 @@ //! Composable asynchronous iteration. //! -//! If futures are asynchronous values, then streams are asynchronous -//! iterators. If you've found yourself with an asynchronous collection of some kind, +//! If you've found yourself with an asynchronous collection of some kind, //! and needed to perform an operation on the elements of said collection, -//! you'll quickly run into 'streams'. Streams are heavily used in idiomatic -//! asynchronous Rust code, so it's worth becoming familiar with them. +//! you'll quickly run into 'async iterators'. Async Iterators are heavily used in +//! idiomatic asynchronous Rust code, so it's worth becoming familiar with them. //! //! Before explaining more, let's talk about how this module is structured: //! @@ -12,71 +11,71 @@ //! //! This module is largely organized by type: //! -//! * [Traits] are the core portion: these traits define what kind of streams +//! * [Traits] are the core portion: these traits define what kind of async iterators //! exist and what you can do with them. The methods of these traits are worth //! putting some extra study time into. -//! * Functions provide some helpful ways to create some basic streams. +//! * Functions provide some helpful ways to create some basic async iterators. //! * Structs are often the return types of the various methods on this //! module's traits. You'll usually want to look at the method that creates //! the `struct`, rather than the `struct` itself. For more detail about why, -//! see '[Implementing Stream](#implementing-stream)'. +//! see '[Implementing Async Iterator](#implementing-async-iterator)'. //! //! [Traits]: #traits //! -//! That's it! Let's dig into streams. +//! That's it! Let's dig into async iterators. //! -//! # Stream +//! # Async Iterators //! -//! The heart and soul of this module is the [`Stream`] trait. The core of -//! [`Stream`] looks like this: +//! The heart and soul of this module is the [`AsyncIterator`] trait. The core of +//! [`AsyncIterator`] looks like this: //! //! ``` //! # use core::task::{Context, Poll}; //! # use core::pin::Pin; -//! trait Stream { +//! trait AsyncIterator { //! type Item; //! fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>; //! } //! ``` //! -//! Unlike `Iterator`, `Stream` makes a distinction between the [`poll_next`] -//! method which is used when implementing a `Stream`, and a (to-be-implemented) -//! `next` method which is used when consuming a stream. Consumers of `Stream` +//! Unlike `Iterator`, `AsyncIterator` makes a distinction between the [`poll_next`] +//! method which is used when implementing an `AsyncIterator`, and a (to-be-implemented) +//! `next` method which is used when consuming an async iterator. Consumers of `AsyncIterator` //! only need to consider `next`, which when called, returns a future which -//! yields `Option<Stream::Item>`. +//! yields `Option<AsyncIterator::Item>`. //! //! The future returned by `next` will yield `Some(Item)` as long as there are //! elements, and once they've all been exhausted, will yield `None` to indicate //! that iteration is finished. If we're waiting on something asynchronous to -//! resolve, the future will wait until the stream is ready to yield again. +//! resolve, the future will wait until the async iterator is ready to yield again. //! -//! Individual streams may choose to resume iteration, and so calling `next` +//! Individual async iterators may choose to resume iteration, and so calling `next` //! again may or may not eventually yield `Some(Item)` again at some point. //! -//! [`Stream`]'s full definition includes a number of other methods as well, +//! [`AsyncIterator`]'s full definition includes a number of other methods as well, //! but they are default methods, built on top of [`poll_next`], and so you get //! them for free. //! //! [`Poll`]: super::task::Poll -//! [`poll_next`]: Stream::poll_next +//! [`poll_next`]: AsyncIterator::poll_next //! -//! # Implementing Stream +//! # Implementing Async Iterator //! -//! Creating a stream of your own involves two steps: creating a `struct` to -//! hold the stream's state, and then implementing [`Stream`] for that +//! Creating an async iterator of your own involves two steps: creating a `struct` to +//! hold the async iterator's state, and then implementing [`AsyncIterator`] for that //! `struct`. //! -//! Let's make a stream named `Counter` which counts from `1` to `5`: +//! Let's make an async iterator named `Counter` which counts from `1` to `5`: //! //! ```no_run -//! #![feature(async_stream)] -//! # use core::stream::Stream; +//! #![feature(async_iterator)] +//! # use core::async_iter::AsyncIterator; //! # use core::task::{Context, Poll}; //! # use core::pin::Pin; //! //! // First, the struct: //! -//! /// A stream which counts from one to five +//! /// An async iterator which counts from one to five //! struct Counter { //! count: usize, //! } @@ -90,9 +89,9 @@ //! } //! } //! -//! // Then, we implement `Stream` for our `Counter`: +//! // Then, we implement `AsyncIterator` for our `Counter`: //! -//! impl Stream for Counter { +//! impl AsyncIterator for Counter { //! // we will be counting with usize //! type Item = usize; //! @@ -113,17 +112,17 @@ //! //! # Laziness //! -//! Streams are *lazy*. This means that just creating a stream doesn't _do_ a -//! whole lot. Nothing really happens until you call `poll_next`. This is -//! sometimes a source of confusion when creating a stream solely for its side +//! Async iterators are *lazy*. This means that just creating an async iterator doesn't +//! _do_ a whole lot. Nothing really happens until you call `poll_next`. This is +//! sometimes a source of confusion when creating an async iterator solely for its side //! effects. The compiler will warn us about this kind of behavior: //! //! ```text -//! warning: unused result that must be used: streams do nothing unless polled +//! warning: unused result that must be used: async iterators do nothing unless polled //! ``` +mod async_iter; mod from_iter; -mod stream; +pub use async_iter::AsyncIterator; pub use from_iter::{from_iter, FromIter}; -pub use stream::Stream; diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index a8fe5f59bae..5a361edecd9 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1,6 +1,7 @@ use crate::cmp::{self, Ordering}; use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try}; +use super::super::try_process; use super::super::TrustedRandomAccessNoCoerce; use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse}; use super::super::{FlatMap, Flatten}; @@ -1777,6 +1778,87 @@ pub trait Iterator { FromIterator::from_iter(self) } + /// Fallibly transforms an iterator into a collection, short circuiting if + /// a failure is encountered. + /// + /// `try_collect()` is a variation of [`collect()`][`collect`] that allows fallible + /// conversions during collection. Its main use case is simplifying conversions from + /// iterators yielding [`Option<T>`][`Option`] into `Option<Collection<T>>`, or similarly for other [`Try`] + /// types (e.g. [`Result`]). + /// + /// Importantly, `try_collect()` doesn't require that the outer [`Try`] type also implements [`FromIterator`]; + /// only the inner type produced on `Try::Output` must implement it. Concretely, + /// this means that collecting into `ControlFlow<_, Vec<i32>>` is valid because `Vec<i32>` implements + /// [`FromIterator`], even though [`ControlFlow`] doesn't. + /// + /// Also, if a failure is encountered during `try_collect()`, the iterator is still valid and + /// may continue to be used, in which case it will continue iterating starting after the element that + /// triggered the failure. See the last example below for an example of how this works. + /// + /// # Examples + /// Successfully collecting an iterator of `Option<i32>` into `Option<Vec<i32>>`: + /// ``` + /// #![feature(iterator_try_collect)] + /// + /// let u = vec![Some(1), Some(2), Some(3)]; + /// let v = u.into_iter().try_collect::<Vec<i32>>(); + /// assert_eq!(v, Some(vec![1, 2, 3])); + /// ``` + /// + /// Failing to collect in the same way: + /// ``` + /// #![feature(iterator_try_collect)] + /// + /// let u = vec![Some(1), Some(2), None, Some(3)]; + /// let v = u.into_iter().try_collect::<Vec<i32>>(); + /// assert_eq!(v, None); + /// ``` + /// + /// A similar example, but with `Result`: + /// ``` + /// #![feature(iterator_try_collect)] + /// + /// let u: Vec<Result<i32, ()>> = vec![Ok(1), Ok(2), Ok(3)]; + /// let v = u.into_iter().try_collect::<Vec<i32>>(); + /// assert_eq!(v, Ok(vec![1, 2, 3])); + /// + /// let u = vec![Ok(1), Ok(2), Err(()), Ok(3)]; + /// let v = u.into_iter().try_collect::<Vec<i32>>(); + /// assert_eq!(v, Err(())); + /// ``` + /// + /// Finally, even [`ControlFlow`] works, despite the fact that it + /// doesn't implement [`FromIterator`]. Note also that the iterator can + /// continue to be used, even if a failure is encountered: + /// + /// ``` + /// #![feature(iterator_try_collect)] + /// + /// use core::ops::ControlFlow::{Break, Continue}; + /// + /// let u = [Continue(1), Continue(2), Break(3), Continue(4), Continue(5)]; + /// let mut it = u.into_iter(); + /// + /// let v = it.try_collect::<Vec<_>>(); + /// assert_eq!(v, Break(3)); + /// + /// let v = it.try_collect::<Vec<_>>(); + /// assert_eq!(v, Continue(vec![4, 5])); + /// ``` + /// + /// [`collect`]: Iterator::collect + #[inline] + #[unstable(feature = "iterator_try_collect", issue = "94047")] + fn try_collect<B>(&mut self) -> ChangeOutputType<Self::Item, B> + where + Self: Sized, + <Self as Iterator>::Item: Try, + <<Self as Iterator>::Item as Try>::Residual: Residual<B>, + B: FromIterator<<Self::Item as Try>::Output>, + { + try_process(self, |i| i.collect()) + } + /// Consumes an iterator, creating two collections from it. /// /// The predicate passed to `partition()` can return `true`, or `false`. diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index afef129303e..aa1ad9362a9 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -305,6 +305,8 @@ pub mod ops; pub mod any; pub mod array; pub mod ascii; +#[unstable(feature = "async_iterator", issue = "79024")] +pub mod async_iter; pub mod cell; pub mod char; pub mod ffi; @@ -316,8 +318,6 @@ pub mod panic; pub mod panicking; pub mod pin; pub mod result; -#[unstable(feature = "async_stream", issue = "79024")] -pub mod stream; pub mod sync; pub mod fmt; diff --git a/library/core/src/panic/unwind_safe.rs b/library/core/src/panic/unwind_safe.rs index 092b7cf0f2c..95be879e319 100644 --- a/library/core/src/panic/unwind_safe.rs +++ b/library/core/src/panic/unwind_safe.rs @@ -1,10 +1,10 @@ +use crate::async_iter::AsyncIterator; use crate::cell::UnsafeCell; use crate::fmt; use crate::future::Future; use crate::ops::{Deref, DerefMut}; use crate::pin::Pin; use crate::ptr::{NonNull, Unique}; -use crate::stream::Stream; use crate::task::{Context, Poll}; /// A marker trait which represents "panic safe" types in Rust. @@ -290,8 +290,8 @@ impl<F: Future> Future for AssertUnwindSafe<F> { } } -#[unstable(feature = "async_stream", issue = "79024")] -impl<S: Stream> Stream for AssertUnwindSafe<S> { +#[unstable(feature = "async_iterator", issue = "79024")] +impl<S: AsyncIterator> AsyncIterator for AssertUnwindSafe<S> { type Item = S::Item; fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<S::Item>> { diff --git a/library/core/tests/iter/traits/iterator.rs b/library/core/tests/iter/traits/iterator.rs index 972d61ba909..cf69f0a7a4d 100644 --- a/library/core/tests/iter/traits/iterator.rs +++ b/library/core/tests/iter/traits/iterator.rs @@ -497,6 +497,52 @@ fn test_collect() { assert!(a == b); } +#[test] +fn test_try_collect() { + use core::ops::ControlFlow::{Break, Continue}; + + let u = vec![Some(1), Some(2), Some(3)]; + let v = u.into_iter().try_collect::<Vec<i32>>(); + assert_eq!(v, Some(vec![1, 2, 3])); + + let u = vec![Some(1), Some(2), None, Some(3)]; + let mut it = u.into_iter(); + let v = it.try_collect::<Vec<i32>>(); + assert_eq!(v, None); + let v = it.try_collect::<Vec<i32>>(); + assert_eq!(v, Some(vec![3])); + + let u: Vec<Result<i32, ()>> = vec![Ok(1), Ok(2), Ok(3)]; + let v = u.into_iter().try_collect::<Vec<i32>>(); + assert_eq!(v, Ok(vec![1, 2, 3])); + + let u = vec![Ok(1), Ok(2), Err(()), Ok(3)]; + let v = u.into_iter().try_collect::<Vec<i32>>(); + assert_eq!(v, Err(())); + + let numbers = vec![1, 2, 3, 4, 5]; + let all_positive = numbers + .iter() + .cloned() + .map(|n| if n > 0 { Some(n) } else { None }) + .try_collect::<Vec<i32>>(); + assert_eq!(all_positive, Some(numbers)); + + let numbers = vec![-2, -1, 0, 1, 2]; + let all_positive = + numbers.into_iter().map(|n| if n > 0 { Some(n) } else { None }).try_collect::<Vec<i32>>(); + assert_eq!(all_positive, None); + + let u = [Continue(1), Continue(2), Break(3), Continue(4), Continue(5)]; + let mut it = u.into_iter(); + + let v = it.try_collect::<Vec<_>>(); + assert_eq!(v, Break(3)); + + let v = it.try_collect::<Vec<_>>(); + assert_eq!(v, Continue(vec![4, 5])); +} + // just tests by whether or not this compiles fn _empty_impl_all_auto_traits<T>() { use std::panic::{RefUnwindSafe, UnwindSafe}; diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 65be0c320c2..06c7be054a0 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -6,7 +6,7 @@ #![feature(bool_to_option)] #![feature(box_syntax)] #![feature(cell_update)] -#![feature(cfg_panic)] +#![cfg_attr(bootstrap, feature(cfg_panic))] #![cfg_attr(bootstrap, feature(cfg_target_has_atomic))] #![feature(const_assume)] #![feature(const_black_box)] @@ -67,6 +67,7 @@ #![feature(iter_intersperse)] #![feature(iter_is_partitioned)] #![feature(iter_order_by)] +#![feature(iterator_try_collect)] #![feature(iterator_try_reduce)] #![feature(const_mut_refs)] #![feature(const_pin)] diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 9e61defc31e..c9d91d2c03b 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -547,6 +547,10 @@ impl<K, V, S> HashMap<K, V, S> { /// Clears the map, returning all key-value pairs as an iterator. Keeps the /// allocated memory for reuse. /// + /// If the returned iterator is dropped before being fully consumed, it + /// drops the remaining key-value pairs. The returned iterator keeps a + /// mutable borrow on the vector to optimize its implementation. + /// /// # Examples /// /// ``` diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index d1450987e73..200667ae390 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -227,7 +227,12 @@ impl<T, S> HashSet<T, S> { self.base.is_empty() } - /// Clears the set, returning all elements in an iterator. + /// Clears the set, returning all elements as an iterator. Keeps the + /// allocated memory for reuse. + /// + /// If the returned iterator is dropped before being fully consumed, it + /// drops the remaining elements. The returned iterator keeps a mutable + /// borrow on the vector to optimize its implementation. /// /// # Examples /// diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs index 6e70d5ca02d..1678367290e 100644 --- a/library/std/src/ffi/c_str.rs +++ b/library/std/src/ffi/c_str.rs @@ -382,7 +382,7 @@ impl CString { let bytes: Vec<u8> = self.into(); match memchr::memchr(0, &bytes) { Some(i) => Err(NulError(i, bytes)), - None => Ok(unsafe { CString::from_vec_unchecked(bytes) }), + None => Ok(unsafe { CString::_from_vec_unchecked(bytes) }), } } } @@ -405,7 +405,7 @@ impl CString { // This allows better optimizations if lto enabled. match memchr::memchr(0, bytes) { Some(i) => Err(NulError(i, buffer)), - None => Ok(unsafe { CString::from_vec_unchecked(buffer) }), + None => Ok(unsafe { CString::_from_vec_unchecked(buffer) }), } } @@ -451,10 +451,15 @@ impl CString { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - pub unsafe fn from_vec_unchecked(mut v: Vec<u8>) -> CString { + pub unsafe fn from_vec_unchecked(v: Vec<u8>) -> Self { + debug_assert!(memchr::memchr(0, &v).is_none()); + unsafe { Self::_from_vec_unchecked(v) } + } + + unsafe fn _from_vec_unchecked(mut v: Vec<u8>) -> Self { v.reserve_exact(1); v.push(0); - CString { inner: v.into_boxed_slice() } + Self { inner: v.into_boxed_slice() } } /// Retakes ownership of a `CString` that was transferred to C via @@ -578,7 +583,7 @@ impl CString { pub fn into_string(self) -> Result<String, IntoStringError> { String::from_utf8(self.into_bytes()).map_err(|e| IntoStringError { error: e.utf8_error(), - inner: unsafe { CString::from_vec_unchecked(e.into_bytes()) }, + inner: unsafe { Self::_from_vec_unchecked(e.into_bytes()) }, }) } @@ -735,6 +740,11 @@ impl CString { #[must_use] #[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")] pub unsafe fn from_vec_with_nul_unchecked(v: Vec<u8>) -> Self { + debug_assert!(memchr::memchr(0, &v).unwrap() + 1 == v.len()); + unsafe { Self::_from_vec_with_nul_unchecked(v) } + } + + unsafe fn _from_vec_with_nul_unchecked(v: Vec<u8>) -> Self { Self { inner: v.into_boxed_slice() } } @@ -778,7 +788,7 @@ impl CString { Some(nul_pos) if nul_pos + 1 == v.len() => { // SAFETY: We know there is only one nul byte, at the end // of the vec. - Ok(unsafe { Self::from_vec_with_nul_unchecked(v) }) + Ok(unsafe { Self::_from_vec_with_nul_unchecked(v) }) } Some(nul_pos) => Err(FromVecWithNulError { error_kind: FromBytesWithNulErrorKind::InteriorNul(nul_pos), @@ -811,7 +821,7 @@ impl ops::Deref for CString { #[inline] fn deref(&self) -> &CStr { - unsafe { CStr::from_bytes_with_nul_unchecked(self.as_bytes_with_nul()) } + unsafe { CStr::_from_bytes_with_nul_unchecked(self.as_bytes_with_nul()) } } } @@ -928,7 +938,7 @@ impl From<Vec<NonZeroU8>> for CString { }; // SAFETY: `v` cannot contain null bytes, given the type-level // invariant of `NonZeroU8`. - CString::from_vec_unchecked(v) + Self::_from_vec_unchecked(v) } } } @@ -1225,7 +1235,7 @@ impl CStr { unsafe { let len = sys::strlen(ptr); let ptr = ptr as *const u8; - CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1)) + Self::_from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1)) } } @@ -1268,7 +1278,7 @@ impl CStr { Some(nul_pos) if nul_pos + 1 == bytes.len() => { // SAFETY: We know there is only one nul byte, at the end // of the byte slice. - Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) }) + Ok(unsafe { Self::_from_bytes_with_nul_unchecked(bytes) }) } Some(nul_pos) => Err(FromBytesWithNulError::interior_nul(nul_pos)), None => Err(FromBytesWithNulError::not_nul_terminated()), @@ -1297,12 +1307,19 @@ impl CStr { #[stable(feature = "cstr_from_bytes", since = "1.10.0")] #[rustc_const_stable(feature = "const_cstr_unchecked", since = "1.59.0")] pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr { + // We're in a const fn, so this is the best we can do + debug_assert!(!bytes.is_empty() && bytes[bytes.len() - 1] == 0); + unsafe { Self::_from_bytes_with_nul_unchecked(bytes) } + } + + #[inline] + const unsafe fn _from_bytes_with_nul_unchecked(bytes: &[u8]) -> &Self { // SAFETY: Casting to CStr is safe because its internal representation // is a [u8] too (safe only inside std). // Dereferencing the obtained pointer is safe because it comes from a // reference. Making a reference is then safe because its lifetime // is bound by the lifetime of the given `bytes`. - unsafe { &*(bytes as *const [u8] as *const CStr) } + unsafe { &*(bytes as *const [u8] as *const Self) } } /// Returns the inner pointer to this C string. @@ -1566,7 +1583,7 @@ impl ops::Index<ops::RangeFrom<usize>> for CStr { // byte, since otherwise we could get an empty string that doesn't end // in a null. if index.start < bytes.len() { - unsafe { CStr::from_bytes_with_nul_unchecked(&bytes[index.start..]) } + unsafe { CStr::_from_bytes_with_nul_unchecked(&bytes[index.start..]) } } else { panic!( "index out of bounds: the len is {} but the index is {}", diff --git a/library/std/src/ffi/c_str/tests.rs b/library/std/src/ffi/c_str/tests.rs index 4f7ba9ad437..00ba5460821 100644 --- a/library/std/src/ffi/c_str/tests.rs +++ b/library/std/src/ffi/c_str/tests.rs @@ -33,14 +33,6 @@ fn build_with_zero2() { } #[test] -fn build_with_zero3() { - unsafe { - let s = CString::from_vec_unchecked(vec![0]); - assert_eq!(s.as_bytes(), b"\0"); - } -} - -#[test] fn formatted() { let s = CString::new(&b"abc\x01\x02\n\xE2\x80\xA6\xFF"[..]).unwrap(); assert_eq!(format!("{:?}", s), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#); diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index a03da0682a5..8c38db9b62c 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -233,7 +233,7 @@ #![feature(array_error_internals)] #![feature(assert_matches)] #![feature(associated_type_bounds)] -#![feature(async_stream)] +#![feature(async_iterator)] #![feature(atomic_mut_ptr)] #![feature(auto_traits)] #![feature(bench_black_box)] @@ -404,6 +404,8 @@ pub use alloc_crate::vec; pub use core::any; #[stable(feature = "core_array", since = "1.36.0")] pub use core::array; +#[unstable(feature = "async_iterator", issue = "79024")] +pub use core::async_iter; #[stable(feature = "rust1", since = "1.0.0")] pub use core::cell; #[stable(feature = "rust1", since = "1.0.0")] @@ -458,8 +460,6 @@ pub use core::pin; pub use core::ptr; #[stable(feature = "rust1", since = "1.0.0")] pub use core::result; -#[unstable(feature = "async_stream", issue = "79024")] -pub use core::stream; #[stable(feature = "i128", since = "1.26.0")] #[allow(deprecated, deprecated_in_future)] pub use core::u128; diff --git a/library/std/src/path.rs b/library/std/src/path.rs index adb8b30ec08..e544608f83c 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -268,6 +268,12 @@ pub fn is_separator(c: char) -> bool { #[stable(feature = "rust1", since = "1.0.0")] pub const MAIN_SEPARATOR: char = crate::sys::path::MAIN_SEP; +/// The primary separator of path components for the current platform. +/// +/// For example, `/` on Unix and `\` on Windows. +#[unstable(feature = "main_separator_str", issue = "94071")] +pub const MAIN_SEPARATOR_STR: &str = crate::sys::path::MAIN_SEP_STR; + //////////////////////////////////////////////////////////////////////////////// // Misc helpers //////////////////////////////////////////////////////////////////////////////// diff --git a/library/std/src/sys/solid/fs.rs b/library/std/src/sys/solid/fs.rs index a6ed10f7789..a2cbee4dcf0 100644 --- a/library/std/src/sys/solid/fs.rs +++ b/library/std/src/sys/solid/fs.rs @@ -289,7 +289,26 @@ impl OpenOptions { } fn cstr(path: &Path) -> io::Result<CString> { - Ok(CString::new(path.as_os_str().as_bytes())?) + let path = path.as_os_str().as_bytes(); + + if !path.starts_with(br"\") { + // Relative paths aren't supported + return Err(crate::io::const_io_error!( + crate::io::ErrorKind::Unsupported, + "relative path is not supported on this platform", + )); + } + + // Apply the thread-safety wrapper + const SAFE_PREFIX: &[u8] = br"\TS"; + let wrapped_path = [SAFE_PREFIX, &path, &[0]].concat(); + + CString::from_vec_with_nul(wrapped_path).map_err(|_| { + crate::io::const_io_error!( + io::ErrorKind::InvalidInput, + "path provided contains a nul byte", + ) + }) } impl File { diff --git a/library/stdarch b/library/stdarch -Subproject 863d31b8e1314e15d124384e5eaa9ab21e12bd7 +Subproject b4a0e07552cf90ef8f1a5b775bf70e4db94b3d6 diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 013687ce377..029049d5434 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1877,12 +1877,6 @@ fn add_env(builder: &Builder<'_>, cmd: &mut Command, target: TargetSelection) { } else { cmd.env("CFG_MINGW", "0").env("CFG_ABI", "MSVC"); } - - if target.contains("x86_64") { - cmd.env("CFG_PLATFORM", "x64"); - } else { - cmd.env("CFG_PLATFORM", "x86"); - } } /// Maybe add LLVM object files to the given destination lib-dir. Allows either static or dynamic linking. diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index d60be193bda..c7fd5ed6fcb 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -509,3 +509,6 @@ reverse-dependency like `examples/ex.rs` is given to rustdoc with the target crate being documented (`foobar`) and a path to output the calls (`output.calls`). Then, the generated calls file can be passed via `--with-examples` to the subsequent documentation of `foobar`. + +To scrape examples from test code, e.g. functions marked `#[test]`, then +add the `--scrape-tests` flag. diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md index d630f4ecb7b..457851b0cc7 100644 --- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md +++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md @@ -16,11 +16,13 @@ This feature allows for use of one of following sanitizers: AddressSanitizer, but based on partial hardware assistance. * [LeakSanitizer][clang-lsan] a run-time memory leak detector. * [MemorySanitizer][clang-msan] a detector of uninitialized reads. +* [MemTagSanitizer][clang-memtag] fast memory error detector based on + Armv8.5-A Memory Tagging Extension. * [ThreadSanitizer][clang-tsan] a fast data race detector. To enable a sanitizer compile with `-Zsanitizer=address`,`-Zsanitizer=cfi`, -`-Zsanitizer=hwaddress`, `-Zsanitizer=leak`, `-Zsanitizer=memory` or -`-Zsanitizer=thread`. +`-Zsanitizer=hwaddress`, `-Zsanitizer=leak`, `-Zsanitizer=memory`, +`-Zsanitizer=memtag`, or `-Zsanitizer=thread`. # AddressSanitizer @@ -494,6 +496,20 @@ $ cargo run -Zbuild-std --target x86_64-unknown-linux-gnu #0 0x560c04b2bc50 in memory::main::hd2333c1899d997f5 $CWD/src/main.rs:3 ``` +# MemTagSanitizer + +MemTagSanitizer detects a similar class of errors as AddressSanitizer and HardwareAddressSanitizer, but with lower overhead suitable for use as hardening for production binaries. + +MemTagSanitizer is supported on the following targets: + +* `aarch64-linux-android` +* `aarch64-unknown-linux-gnu` + +MemTagSanitizer requires hardware support and the `mte` target feature. +To enable this target feature compile with `-C target-feature="+mte"`. + +More information can be found in the associated [LLVM documentation](https://llvm.org/docs/MemTagSanitizer.html). + # ThreadSanitizer ThreadSanitizer is a data race detection tool. It is supported on the following diff --git a/src/doc/unstable-book/src/language-features/asm-const.md b/src/doc/unstable-book/src/language-features/asm-const.md index 1063c23b6df..670c4df414f 100644 --- a/src/doc/unstable-book/src/language-features/asm-const.md +++ b/src/doc/unstable-book/src/language-features/asm-const.md @@ -1,8 +1,8 @@ # `asm_const` -The tracking issue for this feature is: [#72016] +The tracking issue for this feature is: [#93332] -[#72016]: https://github.com/rust-lang/rust/issues/72016 +[#93332]: https://github.com/rust-lang/rust/issues/93332 ------------------------ diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md index 37fd67447c1..0a48eb4f81a 100644 --- a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md +++ b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md @@ -1,8 +1,8 @@ # `asm_experimental_arch` -The tracking issue for this feature is: [#72016] +The tracking issue for this feature is: [#93335] -[#72016]: https://github.com/rust-lang/rust/issues/72016 +[#93335]: https://github.com/rust-lang/rust/issues/93335 ------------------------ diff --git a/src/doc/unstable-book/src/language-features/asm-sym.md b/src/doc/unstable-book/src/language-features/asm-sym.md index 7544e20807e..103d91caf4c 100644 --- a/src/doc/unstable-book/src/language-features/asm-sym.md +++ b/src/doc/unstable-book/src/language-features/asm-sym.md @@ -1,8 +1,8 @@ # `asm_sym` -The tracking issue for this feature is: [#72016] +The tracking issue for this feature is: [#93333] -[#72016]: https://github.com/rust-lang/rust/issues/72016 +[#93333]: https://github.com/rust-lang/rust/issues/93333 ------------------------ diff --git a/src/doc/unstable-book/src/language-features/asm-unwind.md b/src/doc/unstable-book/src/language-features/asm-unwind.md index 414193fe801..809e6d75b35 100644 --- a/src/doc/unstable-book/src/language-features/asm-unwind.md +++ b/src/doc/unstable-book/src/language-features/asm-unwind.md @@ -1,8 +1,8 @@ # `asm_unwind` -The tracking issue for this feature is: [#72016] +The tracking issue for this feature is: [#93334] -[#72016]: https://github.com/rust-lang/rust/issues/72016 +[#93334]: https://github.com/rust-lang/rust/issues/93334 ------------------------ diff --git a/src/doc/unstable-book/src/language-features/cfg-panic.md b/src/doc/unstable-book/src/language-features/cfg-panic.md deleted file mode 100644 index f5b73128ad6..00000000000 --- a/src/doc/unstable-book/src/language-features/cfg-panic.md +++ /dev/null @@ -1,38 +0,0 @@ -# `cfg_panic` - -The tracking issue for this feature is: [#77443] - -[#77443]: https://github.com/rust-lang/rust/issues/77443 - ------------------------- - -The `cfg_panic` feature makes it possible to execute different code -depending on the panic strategy. - -Possible values at the moment are `"unwind"` or `"abort"`, although -it is possible that new panic strategies may be added to Rust in the -future. - -## Examples - -```rust -#![feature(cfg_panic)] - -#[cfg(panic = "unwind")] -fn a() { - // ... -} - -#[cfg(not(panic = "unwind"))] -fn a() { - // ... -} - -fn b() { - if cfg!(panic = "abort") { - // ... - } else { - // ... - } -} -``` diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index bcbde428e7c..187bc13357a 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -585,12 +585,7 @@ fn clean_ty_generics( .params .iter() .filter_map(|param| match param.kind { - ty::GenericParamDefKind::Lifetime => { - if param.name == kw::UnderscoreLifetime { - return None; - } - Some(param.clean(cx)) - } + ty::GenericParamDefKind::Lifetime => Some(param.clean(cx)), ty::GenericParamDefKind::Type { synthetic, .. } => { if param.name == kw::SelfUpper { assert_eq!(param.index, 0); diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 0bad1532808..ea18d915deb 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -51,9 +51,7 @@ crate fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> Vec<WP> { // Look for equality predicates on associated types that can be merged into // general bound predicates equalities.retain(|&(ref lhs, ref rhs)| { - let (self_, trait_did, name) = if let Some(p) = lhs.projection() { - p - } else { + let Some((self_, trait_did, name)) = lhs.projection() else { return true; }; let generic = match self_ { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 893e126283b..c2f6f7aea75 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -200,6 +200,7 @@ crate fn create_config( lint_opts, describe_lints, lint_cap, + scrape_examples_options, .. }: RustdocOptions, ) -> rustc_interface::Config { @@ -227,6 +228,7 @@ crate fn create_config( let crate_types = if proc_macro_crate { vec![CrateType::ProcMacro] } else { vec![CrateType::Rlib] }; + let test = scrape_examples_options.map(|opts| opts.scrape_tests).unwrap_or(false); // plays with error output here! let sessopts = config::Options { maybe_sysroot, @@ -244,12 +246,14 @@ crate fn create_config( edition, describe_lints, crate_name, + test, ..Options::default() }; interface::Config { opts: sessopts, crate_cfg: interface::parse_cfgspecs(cfgs), + crate_check_cfg: interface::parse_check_cfg(vec![]), input, input_path: cpath, output_file: None, diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 3a9fb6d1420..696397c5f67 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -91,6 +91,7 @@ crate fn run(options: RustdocOptions) -> Result<(), ErrorReported> { let config = interface::Config { opts: sessopts, crate_cfg: interface::parse_cfgspecs(cfgs), + crate_check_cfg: interface::parse_check_cfg(vec![]), input, input_path: None, output_file: None, diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 1c0448828a2..7061a9674e4 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -236,9 +236,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> { let should_panic; let ignore; let edition; - let kind = if let Some(Event::Start(Tag::CodeBlock(kind))) = event { - kind - } else { + let Some(Event::Start(Tag::CodeBlock(kind))) = event else { return event; }; diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 1c3f9b56b47..3e3302f8f4d 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1963,16 +1963,12 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) { // We want links' order to be reproducible so we don't use unstable sort. assoc_consts.sort(); - out.push_str( - "<h3 class=\"sidebar-title\">\ - <a href=\"#implementations\">Associated Constants</a>\ - </h3>\ - <div class=\"sidebar-links\">", + print_sidebar_block( + out, + "implementations", + "Associated Constants", + assoc_consts.iter(), ); - for line in assoc_consts { - write!(out, "{}", line); - } - out.push_str("</div>"); } let mut methods = v .iter() @@ -1983,14 +1979,7 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) { // We want links' order to be reproducible so we don't use unstable sort. methods.sort(); - out.push_str( - "<h3 class=\"sidebar-title\"><a href=\"#implementations\">Methods</a></h3>\ - <div class=\"sidebar-links\">", - ); - for line in methods { - write!(out, "{}", line); - } - out.push_str("</div>"); + print_sidebar_block(out, "implementations", "Methods", methods.iter()); } } @@ -2029,14 +2018,6 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) { ret }; - let write_sidebar_links = |out: &mut Buffer, links: Vec<String>| { - out.push_str("<div class=\"sidebar-links\">"); - for link in links { - out.push_str(&link); - } - out.push_str("</div>"); - }; - let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) = v.iter().partition::<Vec<_>, _>(|i| i.inner_impl().kind.is_auto()); let (blanket_impl, concrete): (Vec<&Impl>, Vec<&Impl>) = @@ -2047,27 +2028,30 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) { let blanket_format = format_impls(blanket_impl); if !concrete_format.is_empty() { - out.push_str( - "<h3 class=\"sidebar-title\"><a href=\"#trait-implementations\">\ - Trait Implementations</a></h3>", + print_sidebar_block( + out, + "trait-implementations", + "Trait Implementations", + concrete_format.iter(), ); - write_sidebar_links(out, concrete_format); } if !synthetic_format.is_empty() { - out.push_str( - "<h3 class=\"sidebar-title\"><a href=\"#synthetic-implementations\">\ - Auto Trait Implementations</a></h3>", + print_sidebar_block( + out, + "synthetic-implementations", + "Auto Trait Implementations", + synthetic_format.iter(), ); - write_sidebar_links(out, synthetic_format); } if !blanket_format.is_empty() { - out.push_str( - "<h3 class=\"sidebar-title\"><a href=\"#blanket-implementations\">\ - Blanket Implementations</a></h3>", + print_sidebar_block( + out, + "blanket-implementations", + "Blanket Implementations", + blanket_format.iter(), ); - write_sidebar_links(out, blanket_format); } } } @@ -2127,20 +2111,14 @@ fn sidebar_deref_methods( } else { "deref-methods" }; - write!( - out, - "<h3 class=\"sidebar-title\"><a href=\"#{}\">Methods from {}<Target={}></a></h3>", - id, + let title = format!( + "Methods from {}<Target={}>", Escape(&format!("{:#}", impl_.inner_impl().trait_.as_ref().unwrap().print(cx))), Escape(&format!("{:#}", real_target.print(cx))), ); // We want links' order to be reproducible so we don't use unstable sort. ret.sort(); - out.push_str("<div class=\"sidebar-links\">"); - for link in ret { - write!(out, "{}", link); - } - out.push_str("</div>"); + print_sidebar_block(out, id, &title, ret.iter()); } } @@ -2166,27 +2144,19 @@ fn sidebar_struct(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, s: &clea let fields = get_struct_fields_name(&s.fields); if !fields.is_empty() { - if let CtorKind::Fictive = s.struct_type { - sidebar.push_str( - "<h3 class=\"sidebar-title\"><a href=\"#fields\">Fields</a></h3>\ - <div class=\"sidebar-links\">", - ); - - for field in fields { - sidebar.push_str(&field); + match s.struct_type { + CtorKind::Fictive => { + print_sidebar_block(&mut sidebar, "fields", "Fields", fields.iter()); } - - sidebar.push_str("</div>"); - } else if let CtorKind::Fn = s.struct_type { - sidebar - .push_str("<h3 class=\"sidebar-title\"><a href=\"#fields\">Tuple Fields</a></h3>"); + CtorKind::Fn => print_sidebar_title(&mut sidebar, "fields", "Tuple Fields"), + CtorKind::Const => {} } } sidebar_assoc_items(cx, &mut sidebar, it); if !sidebar.is_empty() { - write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner()); + write!(buf, "<section>{}</section>", sidebar.into_inner()); } } @@ -2214,18 +2184,50 @@ fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String } } +/// Don't call this function directly!!! Use `print_sidebar_title` or `print_sidebar_block` instead! +fn print_sidebar_title_inner(buf: &mut Buffer, id: &str, title: &str) { + write!( + buf, + "<h3 class=\"sidebar-title\">\ + <a href=\"#{}\">{}</a>\ + </h3>", + id, title + ); +} + +fn print_sidebar_title(buf: &mut Buffer, id: &str, title: &str) { + buf.push_str("<div class=\"block\">"); + print_sidebar_title_inner(buf, id, title); + buf.push_str("</div>"); +} + +fn print_sidebar_block( + buf: &mut Buffer, + id: &str, + title: &str, + items: impl Iterator<Item = impl fmt::Display>, +) { + buf.push_str("<div class=\"block\">"); + print_sidebar_title_inner(buf, id, title); + buf.push_str("<ul>"); + for item in items { + write!(buf, "<li>{}</li>", item); + } + buf.push_str("</ul></div>"); +} + fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean::Trait) { - buf.write_str("<div class=\"block items\">"); + buf.write_str("<section>"); fn print_sidebar_section( out: &mut Buffer, items: &[clean::Item], - before: &str, + id: &str, + title: &str, filter: impl Fn(&clean::Item) -> bool, - write: impl Fn(&mut Buffer, &str), - after: &str, + mapper: impl Fn(&str) -> String, ) { - let mut items = items + let mut items: Vec<&str> = items .iter() .filter_map(|m| match m.name { Some(ref name) if filter(m) => Some(name.as_str()), @@ -2235,52 +2237,44 @@ fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean if !items.is_empty() { items.sort_unstable(); - out.push_str(before); - for item in items.into_iter() { - write(out, &item); - } - out.push_str(after); + print_sidebar_block(out, id, title, items.into_iter().map(mapper)); } } print_sidebar_section( buf, &t.items, - "<h3 class=\"sidebar-title\"><a href=\"#associated-types\">\ - Associated Types</a></h3><div class=\"sidebar-links\">", + "associated-types", + "Associated Types", |m| m.is_associated_type(), - |out, sym| write!(out, "<a href=\"#associatedtype.{0}\">{0}</a>", sym), - "</div>", + |sym| format!("<a href=\"#associatedtype.{0}\">{0}</a>", sym), ); print_sidebar_section( buf, &t.items, - "<h3 class=\"sidebar-title\"><a href=\"#associated-const\">\ - Associated Constants</a></h3><div class=\"sidebar-links\">", + "associated-const", + "Associated Constants", |m| m.is_associated_const(), - |out, sym| write!(out, "<a href=\"#associatedconstant.{0}\">{0}</a>", sym), - "</div>", + |sym| format!("<a href=\"#associatedconstant.{0}\">{0}</a>", sym), ); print_sidebar_section( buf, &t.items, - "<h3 class=\"sidebar-title\"><a href=\"#required-methods\">\ - Required Methods</a></h3><div class=\"sidebar-links\">", + "required-methods", + "Required Methods", |m| m.is_ty_method(), - |out, sym| write!(out, "<a href=\"#tymethod.{0}\">{0}</a>", sym), - "</div>", + |sym| format!("<a href=\"#tymethod.{0}\">{0}</a>", sym), ); print_sidebar_section( buf, &t.items, - "<h3 class=\"sidebar-title\"><a href=\"#provided-methods\">\ - Provided Methods</a></h3><div class=\"sidebar-links\">", + "provided-methods", + "Provided Methods", |m| m.is_method(), - |out, sym| write!(out, "<a href=\"#method.{0}\">{0}</a>", sym), - "</div>", + |sym| format!("<a href=\"#method.{0}\">{0}</a>", sym), ); let cache = cx.cache(); @@ -2295,29 +2289,23 @@ fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean if !res.is_empty() { res.sort(); - buf.push_str( - "<h3 class=\"sidebar-title\"><a href=\"#foreign-impls\">\ - Implementations on Foreign Types</a></h3>\ - <div class=\"sidebar-links\">", + print_sidebar_block( + buf, + "foreign-impls", + "Implementations on Foreign Types", + res.iter().map(|(name, id)| format!("<a href=\"#{}\">{}</a>", id, Escape(&name))), ); - for (name, id) in res.into_iter() { - write!(buf, "<a href=\"#{}\">{}</a>", id, Escape(&name)); - } - buf.push_str("</div>"); } } sidebar_assoc_items(cx, buf, it); - buf.push_str("<h3 class=\"sidebar-title\"><a href=\"#implementors\">Implementors</a></h3>"); + print_sidebar_title(buf, "implementors", "Implementors"); if t.is_auto { - buf.push_str( - "<h3 class=\"sidebar-title\"><a \ - href=\"#synthetic-implementors\">Auto Implementors</a></h3>", - ); + print_sidebar_title(buf, "synthetic-implementors", "Auto Implementors"); } - buf.push_str("</div>") + buf.push_str("</section>") } fn sidebar_primitive(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) { @@ -2325,7 +2313,7 @@ fn sidebar_primitive(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) { sidebar_assoc_items(cx, &mut sidebar, it); if !sidebar.is_empty() { - write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner()); + write!(buf, "<section>{}</section>", sidebar.into_inner()); } } @@ -2334,7 +2322,7 @@ fn sidebar_typedef(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) { sidebar_assoc_items(cx, &mut sidebar, it); if !sidebar.is_empty() { - write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner()); + write!(buf, "<section>{}</section>", sidebar.into_inner()); } } @@ -2355,22 +2343,13 @@ fn sidebar_union(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, u: &clean let fields = get_struct_fields_name(&u.fields); if !fields.is_empty() { - sidebar.push_str( - "<h3 class=\"sidebar-title\"><a href=\"#fields\">Fields</a></h3>\ - <div class=\"sidebar-links\">", - ); - - for field in fields { - sidebar.push_str(&field); - } - - sidebar.push_str("</div>"); + print_sidebar_block(&mut sidebar, "fields", "Fields", fields.iter()); } sidebar_assoc_items(cx, &mut sidebar, it); if !sidebar.is_empty() { - write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner()); + write!(buf, "<section>{}</section>", sidebar.into_inner()); } } @@ -2388,17 +2367,13 @@ fn sidebar_enum(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, e: &clean: .collect::<Vec<_>>(); if !variants.is_empty() { variants.sort_unstable(); - sidebar.push_str(&format!( - "<h3 class=\"sidebar-title\"><a href=\"#variants\">Variants</a></h3>\ - <div class=\"sidebar-links\">{}</div>", - variants.join(""), - )); + print_sidebar_block(&mut sidebar, "variants", "Variants", variants.iter()); } sidebar_assoc_items(cx, &mut sidebar, it); if !sidebar.is_empty() { - write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner()); + write!(buf, "<section>{}</section>", sidebar.into_inner()); } } @@ -2569,7 +2544,15 @@ fn sidebar_module(buf: &mut Buffer, items: &[clean::Item]) { } if !sidebar.is_empty() { - write!(buf, "<div class=\"block items\"><ul>{}</ul></div>", sidebar); + write!( + buf, + "<section>\ + <div class=\"block\">\ + <ul>{}</ul>\ + </div>\ + </section>", + sidebar + ); } } @@ -2578,7 +2561,7 @@ fn sidebar_foreign_type(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) { sidebar_assoc_items(cx, &mut sidebar, it); if !sidebar.is_empty() { - write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner()); + write!(buf, "<section>{}</section>", sidebar.into_inner()); } } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 2ae7626b886..e84dc6c7240 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1752,9 +1752,7 @@ fn document_type_layout(w: &mut Buffer, cx: &Context<'_>, ty_def_id: DefId) { <ul>", ); - let adt = if let Adt(adt, _) = ty_layout.ty.kind() { - adt - } else { + let Adt(adt, _) = ty_layout.ty.kind() else { span_bug!(tcx.def_span(ty_def_id), "not an adt") }; diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 662221ae773..f1e0a89883a 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -484,10 +484,6 @@ h2.location a { overflow: hidden; } -.sidebar-links a { - white-space: nowrap; -} - .sidebar h2 { border-bottom: none; font-weight: 500; @@ -504,11 +500,14 @@ h2.location a { margin: 0; } -.sidebar-links, -.block { +.sidebar-elems .block { margin-bottom: 2em; } +.sidebar-elems .block li a { + white-space: nowrap; +} + .mobile-topbar { display: none; } diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index f9e9fe0d3cf..52980e07b8c 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -8,6 +8,7 @@ mod conversions; use std::cell::RefCell; use std::fs::{create_dir_all, File}; +use std::io::{BufWriter, Write}; use std::path::PathBuf; use std::rc::Rc; @@ -213,7 +214,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { let mut index = (*self.index).clone().into_inner(); index.extend(self.get_trait_items()); // This needs to be the default HashMap for compatibility with the public interface for - // rustdoc-json + // rustdoc-json-types #[allow(rustc::default_hash_types)] let output = types::Crate { root: types::Id(String::from("0:0")), @@ -263,8 +264,10 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { let mut p = out_dir; p.push(output.index.get(&output.root).unwrap().name.clone().unwrap()); p.set_extension("json"); - let file = try_err!(File::create(&p), p); - serde_json::ser::to_writer(&file, &output).unwrap(); + let mut file = BufWriter::new(try_err!(File::create(&p), p)); + serde_json::ser::to_writer(&mut file, &output).unwrap(); + try_err!(file.flush(), p); + Ok(()) } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 170f166db50..7eff725989c 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -596,6 +596,9 @@ fn opts() -> Vec<RustcOptGroup> { "collect function call information for functions from the target crate", ) }), + unstable("scrape-tests", |o| { + o.optflag("", "scrape-tests", "Include test code when scraping examples") + }), unstable("with-examples", |o| { o.optmulti( "", diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 8621fe6ba1b..33a1530d588 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1226,9 +1226,7 @@ impl LinkCollector<'_, '_> { let base_node = if item.is_mod() && inner_docs { self.mod_ids.last().copied() } else { parent_node }; - let mut module_id = if let Some(id) = base_node { - id - } else { + let Some(mut module_id) = base_node else { // This is a bug. debug!("attempting to resolve item without parent module: {}", path_str); resolution_failure( @@ -1977,9 +1975,7 @@ fn resolution_failure( // If so, report it and say the first which failed; if not, say the first path segment didn't resolve. let mut name = path_str; 'outer: loop { - let (start, end) = if let Some(x) = split(name) { - x - } else { + let Some((start, end)) = split(name) else { // avoid bug that marked [Quux::Z] as missing Z, not Quux if partial_res.is_none() { *unresolved = name.into(); diff --git a/src/librustdoc/passes/collect_intra_doc_links/early.rs b/src/librustdoc/passes/collect_intra_doc_links/early.rs index e28034b2b0d..5c11ab1d3be 100644 --- a/src/librustdoc/passes/collect_intra_doc_links/early.rs +++ b/src/librustdoc/passes/collect_intra_doc_links/early.rs @@ -118,6 +118,7 @@ impl IntraLinkCrateLoader<'_, '_> { Vec::from_iter(self.resolver.cstore().trait_impls_in_crate_untracked(cnum)); let all_inherent_impls = Vec::from_iter(self.resolver.cstore().inherent_impls_in_crate_untracked(cnum)); + let all_lang_items = Vec::from_iter(self.resolver.cstore().lang_items_untracked(cnum)); // Querying traits in scope is expensive so we try to prune the impl and traits lists // using privacy, private traits and impls from other crates are never documented in @@ -141,6 +142,9 @@ impl IntraLinkCrateLoader<'_, '_> { self.add_traits_in_parent_scope(impl_def_id); } } + for def_id in all_lang_items { + self.add_traits_in_parent_scope(def_id); + } self.all_traits.extend(all_traits); self.all_trait_impls.extend(all_trait_impls.into_iter().map(|(_, def_id, _)| def_id)); diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs index 16882cf83d0..7cf0ea9e84e 100644 --- a/src/librustdoc/scrape_examples.rs +++ b/src/librustdoc/scrape_examples.rs @@ -34,6 +34,7 @@ use std::path::PathBuf; crate struct ScrapeExamplesOptions { output_path: PathBuf, target_crates: Vec<String>, + crate scrape_tests: bool, } impl ScrapeExamplesOptions { @@ -43,16 +44,22 @@ impl ScrapeExamplesOptions { ) -> Result<Option<Self>, i32> { let output_path = matches.opt_str("scrape-examples-output-path"); let target_crates = matches.opt_strs("scrape-examples-target-crate"); - match (output_path, !target_crates.is_empty()) { - (Some(output_path), true) => Ok(Some(ScrapeExamplesOptions { + let scrape_tests = matches.opt_present("scrape-tests"); + match (output_path, !target_crates.is_empty(), scrape_tests) { + (Some(output_path), true, _) => Ok(Some(ScrapeExamplesOptions { output_path: PathBuf::from(output_path), target_crates, + scrape_tests, })), - (Some(_), false) | (None, true) => { + (Some(_), false, _) | (None, true, _) => { diag.err("must use --scrape-examples-output-path and --scrape-examples-target-crate together"); Err(1) } - (None, false) => Ok(None), + (None, false, true) => { + diag.err("must use --scrape-examples-output-path and --scrape-examples-target-crate with --scrape-tests"); + Err(1) + } + (None, false, false) => Ok(None), } } } @@ -152,9 +159,7 @@ where } hir::ExprKind::MethodCall(_, _, span) => { let types = tcx.typeck(ex.hir_id.owner); - let def_id = if let Some(def_id) = types.type_dependent_def_id(ex.hir_id) { - def_id - } else { + let Some(def_id) = types.type_dependent_def_id(ex.hir_id) else { trace!("type_dependent_def_id({}) = None", ex.hir_id); return; }; diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 2cbb3324a5e..e8b3a0929db 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -188,9 +188,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { debug!("maybe_inline_local res: {:?}", res); let tcx = self.cx.tcx; - let res_did = if let Some(did) = res.opt_def_id() { - did - } else { + let Some(res_did) = res.opt_def_id() else { return false; }; diff --git a/src/test/codegen/sanitizer_memtag_attr_check.rs b/src/test/codegen/sanitizer_memtag_attr_check.rs new file mode 100644 index 00000000000..2fd362656d4 --- /dev/null +++ b/src/test/codegen/sanitizer_memtag_attr_check.rs @@ -0,0 +1,12 @@ +// This tests that the sanitize_memtag attribute is +// applied when enabling the memtag sanitizer. +// +// needs-sanitizer-memtag +// compile-flags: -Zsanitizer=memtag -Ctarget-feature=+mte + +#![crate_type = "lib"] + +// CHECK: ; Function Attrs:{{.*}}sanitize_memtag +pub fn tagged() {} + +// CHECK: attributes #0 = {{.*}}sanitize_memtag diff --git a/src/test/debuginfo/unsized.rs b/src/test/debuginfo/unsized.rs index ebd40f9dda2..7ccc88ef940 100644 --- a/src/test/debuginfo/unsized.rs +++ b/src/test/debuginfo/unsized.rs @@ -16,6 +16,14 @@ // gdbg-check:$3 = {pointer = [...], vtable = [...]} // gdbr-check:$3 = &unsized::Foo<dyn core::fmt::Debug> {pointer: [...], vtable: [...]} +// gdb-command:print tuple_slice +// gdbg-check:$4 = {data_ptr = [...], length = 2} +// gdbr-check:$4 = &(i32, i32, [i32]) {data_ptr: [...], length: 2} + +// gdb-command:print tuple_dyn +// gdbg-check:$5 = {pointer = [...], vtable = [...]} +// gdbr-check:$5 = &(i32, i32, dyn core::fmt::Debug) {pointer: [...], vtable: [...]} + // === CDB TESTS =================================================================================== // cdb-command: g @@ -34,6 +42,17 @@ // cdb-check: [+0x000] pointer : 0x[...] [Type: unsized::Foo<dyn$<core::fmt::Debug> > *] // cdb-check: [...] vtable : 0x[...] [Type: unsigned [...]int[...] (*)[3]] +// cdb-command:dx tuple_slice +// cdb-check:tuple_slice [Type: ref$<tuple$<i32,i32,slice$<i32> > >] +// cdb-check: [+0x000] data_ptr : 0x[...] [Type: tuple$<i32,i32,slice$<i32> > *] +// cdb-check: [...] length : 0x2 [Type: unsigned [...]int[...] + +// cdb-command:dx tuple_dyn +// cdb-check:tuple_dyn [Type: ref$<tuple$<i32,i32,dyn$<core::fmt::Debug> > >] +// cdb-check: [+0x000] pointer : 0x[...] [Type: tuple$<i32,i32,dyn$<core::fmt::Debug> > *] +// cdb-check: [...] vtable : 0x[...] [Type: unsigned [...]int[...] (*)[3]] + +#![feature(unsized_tuple_coercion)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -51,6 +70,10 @@ fn main() { let b: &Foo<Foo<[u8]>> = &foo; let c: &Foo<dyn std::fmt::Debug> = &Foo { value: 7i32 }; + // Also check unsized tuples + let tuple_slice: &(i32, i32, [i32]) = &(0, 1, [2, 3]); + let tuple_dyn: &(i32, i32, dyn std::fmt::Debug) = &(0, 1, &3u64); + zzz(); // #break } diff --git a/src/test/run-make-fulldeps/issue-19371/foo.rs b/src/test/run-make-fulldeps/issue-19371/foo.rs index 9172d08eff9..fd294b018af 100644 --- a/src/test/run-make-fulldeps/issue-19371/foo.rs +++ b/src/test/run-make-fulldeps/issue-19371/foo.rs @@ -49,6 +49,7 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) { let config = interface::Config { opts, crate_cfg: Default::default(), + crate_check_cfg: Default::default(), input, input_path: None, output_file: Some(output), diff --git a/src/test/run-make-fulldeps/libs-and-bins/Makefile b/src/test/run-make-fulldeps/libs-and-bins/Makefile deleted file mode 100644 index cc3b257a5c5..00000000000 --- a/src/test/run-make-fulldeps/libs-and-bins/Makefile +++ /dev/null @@ -1,6 +0,0 @@ --include ../tools.mk - -all: - $(RUSTC) foo.rs - $(call RUN,foo) - rm $(TMPDIR)/$(call DYLIB_GLOB,foo) diff --git a/src/test/run-make-fulldeps/libs-and-bins/foo.rs b/src/test/run-make-fulldeps/libs-and-bins/foo.rs deleted file mode 100644 index ae166b17840..00000000000 --- a/src/test/run-make-fulldeps/libs-and-bins/foo.rs +++ /dev/null @@ -1,4 +0,0 @@ -#![crate_type = "dylib"] -#![crate_type = "bin"] - -fn main() {} diff --git a/src/test/run-make-fulldeps/output-with-hyphens/Makefile b/src/test/run-make-fulldeps/output-with-hyphens/Makefile index 783d826a53d..69a286f0b74 100644 --- a/src/test/run-make-fulldeps/output-with-hyphens/Makefile +++ b/src/test/run-make-fulldeps/output-with-hyphens/Makefile @@ -1,6 +1,7 @@ -include ../tools.mk all: - $(RUSTC) foo-bar.rs + $(RUSTC) foo-bar.rs --crate-type bin [ -f $(TMPDIR)/$(call BIN,foo-bar) ] + $(RUSTC) foo-bar.rs --crate-type lib [ -f $(TMPDIR)/libfoo_bar.rlib ] diff --git a/src/test/run-make-fulldeps/output-with-hyphens/foo-bar.rs b/src/test/run-make-fulldeps/output-with-hyphens/foo-bar.rs index 3f1a70458e3..f328e4d9d04 100644 --- a/src/test/run-make-fulldeps/output-with-hyphens/foo-bar.rs +++ b/src/test/run-make-fulldeps/output-with-hyphens/foo-bar.rs @@ -1,4 +1 @@ -#![crate_type = "lib"] -#![crate_type = "bin"] - fn main() {} diff --git a/src/test/run-make/rustdoc-scrape-examples-multiple/scrape.mk b/src/test/run-make/rustdoc-scrape-examples-multiple/scrape.mk index 1fa1fae1a0b..d49b6c1f290 100644 --- a/src/test/run-make/rustdoc-scrape-examples-multiple/scrape.mk +++ b/src/test/run-make/rustdoc-scrape-examples-multiple/scrape.mk @@ -7,7 +7,8 @@ $(TMPDIR)/%.calls: $(TMPDIR)/libfoobar.rmeta --extern foobar=$(TMPDIR)/libfoobar.rmeta \ -Z unstable-options \ --scrape-examples-output-path $@ \ - --scrape-examples-target-crate foobar + --scrape-examples-target-crate foobar \ + $(extra_flags) $(TMPDIR)/lib%.rmeta: src/lib.rs $(RUSTC) src/lib.rs --crate-name $* --crate-type lib --emit=metadata diff --git a/src/test/run-make/rustdoc-scrape-examples-test/Makefile b/src/test/run-make/rustdoc-scrape-examples-test/Makefile new file mode 100644 index 00000000000..9f80a8d9602 --- /dev/null +++ b/src/test/run-make/rustdoc-scrape-examples-test/Makefile @@ -0,0 +1,6 @@ +extra_flags := --scrape-tests +deps := ex + +-include ../rustdoc-scrape-examples-multiple/scrape.mk + +all: scrape diff --git a/src/test/run-make/rustdoc-scrape-examples-test/examples/ex.rs b/src/test/run-make/rustdoc-scrape-examples-test/examples/ex.rs new file mode 100644 index 00000000000..d1a9a74e782 --- /dev/null +++ b/src/test/run-make/rustdoc-scrape-examples-test/examples/ex.rs @@ -0,0 +1,6 @@ +fn main() {} + +#[test] +fn a_test() { + foobar::ok(); +} diff --git a/src/test/run-make/rustdoc-scrape-examples-test/src/lib.rs b/src/test/run-make/rustdoc-scrape-examples-test/src/lib.rs new file mode 100644 index 00000000000..22be1ad4101 --- /dev/null +++ b/src/test/run-make/rustdoc-scrape-examples-test/src/lib.rs @@ -0,0 +1,3 @@ +// @has foobar/fn.ok.html '//*[@class="docblock scraped-example-list"]' '' + +pub fn ok() {} diff --git a/src/test/rustdoc-gui/hash-item-expansion.goml b/src/test/rustdoc-gui/hash-item-expansion.goml index 2885978ce1f..a680635ef8a 100644 --- a/src/test/rustdoc-gui/hash-item-expansion.goml +++ b/src/test/rustdoc-gui/hash-item-expansion.goml @@ -5,7 +5,7 @@ assert-attribute: ("#blanket-implementations-list > details:nth-child(2)", {"ope // We first check that the impl block is open by default. assert-attribute: ("#implementations + details", {"open": ""}) // To ensure that we will click on the currently hidden method. -assert-text: (".sidebar-links > a", "must_use") -click: ".sidebar-links > a" +assert-text: (".sidebar-elems section .block li > a", "must_use") +click: ".sidebar-elems section .block li > a" // We check that the impl block was opened as expected so that we can see the method. assert-attribute: ("#implementations + details", {"open": ""}) diff --git a/src/test/rustdoc-gui/sidebar-mobile.goml b/src/test/rustdoc-gui/sidebar-mobile.goml index 9581aa74b0f..79f18db8fc7 100644 --- a/src/test/rustdoc-gui/sidebar-mobile.goml +++ b/src/test/rustdoc-gui/sidebar-mobile.goml @@ -33,7 +33,7 @@ assert-property: (".mobile-topbar", {"clientHeight": "45"}) // Check that clicking an element from the sidebar scrolls to the right place // so the target is not obscured by the topbar. click: ".sidebar-menu-toggle" -click: ".sidebar-links a" +click: ".sidebar-elems section .block li > a" assert-position: ("#method\.must_use", {"y": 45}) // Check that the bottom-most item on the sidebar menu can be scrolled fully into view. diff --git a/src/test/rustdoc-gui/sidebar.goml b/src/test/rustdoc-gui/sidebar.goml index 9505e00512f..6b79b00d3f7 100644 --- a/src/test/rustdoc-gui/sidebar.goml +++ b/src/test/rustdoc-gui/sidebar.goml @@ -13,15 +13,15 @@ assert-css: ("#all-types", {"color": "rgb(53, 109, 164)"}) // We check that we have the crates list and that the "current" on is "test_docs". assert-text: (".sidebar-elems .crate > ul > li > a.current", "test_docs") // And we're also supposed to have the list of items in the current module. -assert-text: (".sidebar-elems .items > ul > li:nth-child(1)", "Modules") -assert-text: (".sidebar-elems .items > ul > li:nth-child(2)", "Macros") -assert-text: (".sidebar-elems .items > ul > li:nth-child(3)", "Structs") -assert-text: (".sidebar-elems .items > ul > li:nth-child(4)", "Enums") -assert-text: (".sidebar-elems .items > ul > li:nth-child(5)", "Traits") -assert-text: (".sidebar-elems .items > ul > li:nth-child(6)", "Functions") -assert-text: (".sidebar-elems .items > ul > li:nth-child(7)", "Type Definitions") -assert-text: (".sidebar-elems .items > ul > li:nth-child(8)", "Unions") -assert-text: (".sidebar-elems .items > ul > li:nth-child(9)", "Keywords") +assert-text: (".sidebar-elems section ul > li:nth-child(1)", "Modules") +assert-text: (".sidebar-elems section ul > li:nth-child(2)", "Macros") +assert-text: (".sidebar-elems section ul > li:nth-child(3)", "Structs") +assert-text: (".sidebar-elems section ul > li:nth-child(4)", "Enums") +assert-text: (".sidebar-elems section ul > li:nth-child(5)", "Traits") +assert-text: (".sidebar-elems section ul > li:nth-child(6)", "Functions") +assert-text: (".sidebar-elems section ul > li:nth-child(7)", "Type Definitions") +assert-text: (".sidebar-elems section ul > li:nth-child(8)", "Unions") +assert-text: (".sidebar-elems section ul > li:nth-child(9)", "Keywords") assert-text: ("#structs + .item-table .item-left > a", "Foo") click: "#structs + .item-table .item-left > a" @@ -30,7 +30,7 @@ assert-count: (".sidebar .location", 2) // We check that there is no crate listed outside of the top level. assert-false: ".sidebar-elems > .crate" -click: ".sidebar-links a" +click: ".sidebar-elems section .block li > a" assert-property-false: ("html", {"scrollTop": "0"}) click: ".sidebar h2.location a" @@ -47,11 +47,11 @@ assert-text: (".sidebar > .location", "Crate lib2") // We check that we have the crates list and that the "current" on is now "lib2". assert-text: (".sidebar-elems .crate > ul > li > a.current", "lib2") // We now go to the "foobar" function page. -assert-text: (".sidebar-elems > .items > ul > li:nth-child(1)", "Modules") -assert-text: (".sidebar-elems > .items > ul > li:nth-child(2)", "Structs") -assert-text: (".sidebar-elems > .items > ul > li:nth-child(3)", "Traits") -assert-text: (".sidebar-elems > .items > ul > li:nth-child(4)", "Functions") -assert-text: (".sidebar-elems > .items > ul > li:nth-child(5)", "Type Definitions") +assert-text: (".sidebar-elems > section .block ul > li:nth-child(1)", "Modules") +assert-text: (".sidebar-elems > section .block ul > li:nth-child(2)", "Structs") +assert-text: (".sidebar-elems > section .block ul > li:nth-child(3)", "Traits") +assert-text: (".sidebar-elems > section .block ul > li:nth-child(4)", "Functions") +assert-text: (".sidebar-elems > section .block ul > li:nth-child(5)", "Type Definitions") assert-text: ("#functions + .item-table .item-left > a", "foobar") click: "#functions + .item-table .item-left > a" @@ -72,12 +72,12 @@ goto: ./sub_module/sub_sub_module/index.html assert-text: (".sidebar > .location", "Module sub_sub_module") // We check that we don't have the crate list. assert-false: ".sidebar-elems .crate" -assert-text: (".sidebar-elems .items > ul > li:nth-child(1)", "Functions") +assert-text: (".sidebar-elems > section ul > li:nth-child(1)", "Functions") assert-text: ("#functions + .item-table .item-left > a", "foo") // Links to trait implementations in the sidebar should not wrap even if they are long. goto: file://|DOC_PATH|/lib2/struct.HasALongTraitWithParams.html -assert-property: (".sidebar-links a", {"offsetHeight": 29}) +assert-property: (".sidebar-elems section .block li > a", {"offsetHeight": 29}) // Test that clicking on of the "In <module>" headings in the sidebar links to the // appropriate anchor in index.html. diff --git a/src/test/rustdoc-gui/trait-sidebar-item-order.goml b/src/test/rustdoc-gui/trait-sidebar-item-order.goml index 38942baa0b5..d77d1dca483 100644 --- a/src/test/rustdoc-gui/trait-sidebar-item-order.goml +++ b/src/test/rustdoc-gui/trait-sidebar-item-order.goml @@ -1,8 +1,8 @@ // Checks that the elements in the sidebar are alphabetically sorted. goto: file://|DOC_PATH|/test_docs/trait.AnotherOne.html -assert-text: (".sidebar-links a:nth-of-type(1)", "another") -assert-text: (".sidebar-links a:nth-of-type(2)", "func1") -assert-text: (".sidebar-links a:nth-of-type(3)", "func2") -assert-text: (".sidebar-links a:nth-of-type(4)", "func3") -assert-text: (".sidebar-links a:nth-of-type(5)", "hello") -assert-text: (".sidebar-links a:nth-of-type(6)", "why_not") +assert-text: (".sidebar-elems section .block li:nth-of-type(1) > a", "another") +assert-text: (".sidebar-elems section .block li:nth-of-type(2) > a", "func1") +assert-text: (".sidebar-elems section .block li:nth-of-type(3) > a", "func2") +assert-text: (".sidebar-elems section .block li:nth-of-type(4) > a", "func3") +assert-text: (".sidebar-elems section .block li:nth-of-type(5) > a", "hello") +assert-text: (".sidebar-elems section .block li:nth-of-type(6) > a", "why_not") diff --git a/src/test/rustdoc/associated-consts.rs b/src/test/rustdoc/associated-consts.rs index 6ae5e20632e..da50fb86cd5 100644 --- a/src/test/rustdoc/associated-consts.rs +++ b/src/test/rustdoc/associated-consts.rs @@ -10,7 +10,7 @@ pub struct Bar; // @has 'foo/struct.Bar.html' // @has - '//h3[@class="sidebar-title"]' 'Associated Constants' -// @has - '//div[@class="sidebar-elems"]//div[@class="sidebar-links"]/a' 'FOO' +// @has - '//div[@class="sidebar-elems"]//a' 'FOO' impl Trait for Bar { const FOO: u32 = 1; @@ -23,7 +23,7 @@ pub enum Foo { // @has 'foo/enum.Foo.html' // @has - '//h3[@class="sidebar-title"]' 'Associated Constants' -// @has - '//div[@class="sidebar-elems"]//div[@class="sidebar-links"]/a' 'FOO' +// @has - '//div[@class="sidebar-elems"]//a' 'FOO' impl Trait for Foo { const FOO: u32 = 1; diff --git a/src/test/rustdoc/deref-mut-methods.rs b/src/test/rustdoc/deref-mut-methods.rs index 0e27fc90b69..fdf8434224f 100644 --- a/src/test/rustdoc/deref-mut-methods.rs +++ b/src/test/rustdoc/deref-mut-methods.rs @@ -9,7 +9,7 @@ impl Foo { } // @has foo/struct.Bar.html -// @has - '//div[@class="sidebar-links"]/a[@href="#method.foo"]' 'foo' +// @has - '//*[@class="sidebar-elems"]//*[@class="block"]//a[@href="#method.foo"]' 'foo' pub struct Bar { foo: Foo, } diff --git a/src/test/rustdoc/deref-recursive-pathbuf.rs b/src/test/rustdoc/deref-recursive-pathbuf.rs index 9ab338ca9b1..746df9c804e 100644 --- a/src/test/rustdoc/deref-recursive-pathbuf.rs +++ b/src/test/rustdoc/deref-recursive-pathbuf.rs @@ -8,9 +8,9 @@ // @has '-' '//*[@id="deref-methods-Path"]' 'Methods from Deref<Target = Path>' // @has '-' '//*[@class="impl-items"]//*[@id="method.exists"]' 'pub fn exists(&self)' // @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-PathBuf"]' 'Methods from Deref<Target=PathBuf>' -// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.as_path"]' 'as_path' +// @has '-' '//*[@class="sidebar-elems"]//*[@class="block"]//a[@href="#method.as_path"]' 'as_path' // @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Path"]' 'Methods from Deref<Target=Path>' -// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.exists"]' 'exists' +// @has '-' '//*[@class="sidebar-elems"]//*[@class="block"]//a[@href="#method.exists"]' 'exists' #![crate_name = "foo"] diff --git a/src/test/rustdoc/deref-recursive.rs b/src/test/rustdoc/deref-recursive.rs index c07e048b065..d5f8473f284 100644 --- a/src/test/rustdoc/deref-recursive.rs +++ b/src/test/rustdoc/deref-recursive.rs @@ -8,9 +8,9 @@ // @has '-' '//*[@id="deref-methods-Baz"]' 'Methods from Deref<Target = Baz>' // @has '-' '//*[@class="impl-items"]//*[@id="method.baz"]' 'pub fn baz(&self)' // @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Bar"]' 'Methods from Deref<Target=Bar>' -// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.bar"]' 'bar' +// @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.bar"]' 'bar' // @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Baz"]' 'Methods from Deref<Target=Baz>' -// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.baz"]' 'baz' +// @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.baz"]' 'baz' #![crate_name = "foo"] diff --git a/src/test/rustdoc/deref-typedef.rs b/src/test/rustdoc/deref-typedef.rs index ad7a96c5dad..28f977e315a 100644 --- a/src/test/rustdoc/deref-typedef.rs +++ b/src/test/rustdoc/deref-typedef.rs @@ -7,10 +7,10 @@ // @has '-' '//*[@class="impl-items"]//*[@id="method.foo_c"]' 'pub fn foo_c(&self)' // @has '-' '//*[@class="impl-items"]//*[@id="method.foo_j"]' 'pub fn foo_j(&self)' // @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-FooJ"]' 'Methods from Deref<Target=FooJ>' -// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_a"]' 'foo_a' -// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_b"]' 'foo_b' -// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_c"]' 'foo_c' -// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_j"]' 'foo_j' +// @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.foo_a"]' 'foo_a' +// @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.foo_b"]' 'foo_b' +// @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.foo_c"]' 'foo_c' +// @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.foo_j"]' 'foo_j' pub struct FooA; pub type FooB = FooA; diff --git a/src/test/rustdoc/double-quote-escape.rs b/src/test/rustdoc/double-quote-escape.rs index 546af2c121a..b7bbf140cfd 100644 --- a/src/test/rustdoc/double-quote-escape.rs +++ b/src/test/rustdoc/double-quote-escape.rs @@ -8,5 +8,5 @@ pub trait Foo<T> { pub struct Bar; // @has foo/struct.Bar.html -// @has - '//*[@class="sidebar-links"]/a[@href="#impl-Foo%3Cunsafe%20extern%20%22C%22%20fn()%3E"]' 'Foo<unsafe extern "C" fn()>' +// @has - '//*[@class="sidebar-elems"]//section//a[@href="#impl-Foo%3Cunsafe%20extern%20%22C%22%20fn()%3E"]' 'Foo<unsafe extern "C" fn()>' impl Foo<unsafe extern "C" fn()> for Bar {} diff --git a/src/test/rustdoc/generic-impl.rs b/src/test/rustdoc/generic-impl.rs index 0f6cba93f95..1268c9587f8 100644 --- a/src/test/rustdoc/generic-impl.rs +++ b/src/test/rustdoc/generic-impl.rs @@ -7,7 +7,7 @@ pub struct Bar; // @has foo/struct.Foo.html '//*[@id="impl-ToString"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T' pub struct Foo; -// @has foo/struct.Foo.html '//div[@class="sidebar-links"]/a[@href="#impl-ToString"]' 'ToString' +// @has foo/struct.Foo.html '//*[@class="sidebar-elems"]//section//a[@href="#impl-ToString"]' 'ToString' impl fmt::Display for Foo { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/src/test/rustdoc/intra-doc/auxiliary/extern-lang-item-impl-dep.rs b/src/test/rustdoc/intra-doc/auxiliary/extern-lang-item-impl-dep.rs new file mode 100644 index 00000000000..87ae2f096bb --- /dev/null +++ b/src/test/rustdoc/intra-doc/auxiliary/extern-lang-item-impl-dep.rs @@ -0,0 +1,29 @@ +// no-prefer-dynamic + +#![feature(lang_items)] + +#![crate_type = "rlib"] +#![no_std] + +pub struct DerefsToF64(f64); + +impl core::ops::Deref for DerefsToF64 { + type Target = f64; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +mod inner { + #[lang = "f64_runtime"] + impl f64 { + /// [f64::clone] + pub fn method() {} + } +} + +#[lang = "eh_personality"] +fn foo() {} + +#[panic_handler] +fn bar(_: &core::panic::PanicInfo) -> ! { loop {} } diff --git a/src/test/rustdoc/intra-doc/extern-lang-item-impl.rs b/src/test/rustdoc/intra-doc/extern-lang-item-impl.rs new file mode 100644 index 00000000000..f64f886f076 --- /dev/null +++ b/src/test/rustdoc/intra-doc/extern-lang-item-impl.rs @@ -0,0 +1,11 @@ +// Reexport of a structure that derefs to a type with lang item impls having doc links in their +// comments. The doc link points to an associated item, so we check that traits in scope for that +// link are populated. + +// aux-build:extern-lang-item-impl-dep.rs + +#![no_std] + +extern crate extern_lang_item_impl_dep; + +pub use extern_lang_item_impl_dep::DerefsToF64; diff --git a/src/test/rustdoc/method-list.rs b/src/test/rustdoc/method-list.rs index 9f24e817fd3..50f4af3aaaf 100644 --- a/src/test/rustdoc/method-list.rs +++ b/src/test/rustdoc/method-list.rs @@ -1,8 +1,8 @@ #![crate_name = "foo"] // @has foo/struct.Foo.html -// @has - '//*[@class="sidebar-links"]/a' 'super_long_name' -// @has - '//*[@class="sidebar-links"]/a' 'Disp' +// @has - '//*[@class="sidebar-elems"]//section//a' 'super_long_name' +// @has - '//*[@class="sidebar-elems"]//section//a' 'Disp' pub struct Foo(usize); impl Foo { diff --git a/src/test/rustdoc/negative-impl-sidebar.rs b/src/test/rustdoc/negative-impl-sidebar.rs index d63ab346045..b995fff1f9a 100644 --- a/src/test/rustdoc/negative-impl-sidebar.rs +++ b/src/test/rustdoc/negative-impl-sidebar.rs @@ -5,5 +5,5 @@ pub struct Foo; // @has foo/struct.Foo.html // @has - '//*[@class="sidebar-title"]/a[@href="#trait-implementations"]' 'Trait Implementations' -// @has - '//*[@class="sidebar-links"]/a' '!Sync' +// @has - '//*[@class="sidebar-elems"]//section//a' '!Sync' impl !Sync for Foo {} diff --git a/src/test/rustdoc/recursive-deref-sidebar.rs b/src/test/rustdoc/recursive-deref-sidebar.rs index 65a7debc253..619f40eff89 100644 --- a/src/test/rustdoc/recursive-deref-sidebar.rs +++ b/src/test/rustdoc/recursive-deref-sidebar.rs @@ -9,13 +9,13 @@ impl B { pub fn foo_b(&self) {} } pub struct C {} impl C { pub fn foo_c(&self) {} } -// @has recursive_deref_sidebar/struct.A.html '//div[@class="sidebar-links"]' 'foo_b' +// @has recursive_deref_sidebar/struct.A.html '//*[@class="sidebar-elems"]//section' 'foo_b' impl Deref for A { type Target = B; fn deref(&self) -> &B { todo!() } } -// @has recursive_deref_sidebar/struct.A.html '//div[@class="sidebar-links"]' 'foo_c' +// @has recursive_deref_sidebar/struct.A.html '//*[@class="sidebar-elems"]//section' 'foo_c' impl Deref for B { type Target = C; fn deref(&self) -> &C { todo!() } diff --git a/src/test/rustdoc/sidebar-items.rs b/src/test/rustdoc/sidebar-items.rs index ee670e88b5c..375cad9da7f 100644 --- a/src/test/rustdoc/sidebar-items.rs +++ b/src/test/rustdoc/sidebar-items.rs @@ -2,13 +2,13 @@ // @has foo/trait.Foo.html // @has - '//*[@class="sidebar-title"]/a[@href="#required-methods"]' 'Required Methods' -// @has - '//*[@class="sidebar-links"]/a' 'bar' +// @has - '//*[@class="sidebar-elems"]//section//a' 'bar' // @has - '//*[@class="sidebar-title"]/a[@href="#provided-methods"]' 'Provided Methods' -// @has - '//*[@class="sidebar-links"]/a' 'foo' +// @has - '//*[@class="sidebar-elems"]//section//a' 'foo' // @has - '//*[@class="sidebar-title"]/a[@href="#associated-const"]' 'Associated Constants' -// @has - '//*[@class="sidebar-links"]/a' 'BAR' +// @has - '//*[@class="sidebar-elems"]//section//a' 'BAR' // @has - '//*[@class="sidebar-title"]/a[@href="#associated-types"]' 'Associated Types' -// @has - '//*[@class="sidebar-links"]/a' 'Output' +// @has - '//*[@class="sidebar-elems"]//section//a' 'Output' pub trait Foo { const BAR: u32 = 0; type Output: ?Sized; @@ -19,9 +19,9 @@ pub trait Foo { // @has foo/struct.Bar.html // @has - '//*[@class="sidebar-title"]/a[@href="#fields"]' 'Fields' -// @has - '//*[@class="sidebar-links"]/a[@href="#structfield.f"]' 'f' -// @has - '//*[@class="sidebar-links"]/a[@href="#structfield.u"]' 'u' -// @!has - '//*[@class="sidebar-links"]/a' 'waza' +// @has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.f"]' 'f' +// @has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.u"]' 'u' +// @!has - '//*[@class="sidebar-elems"]//section//a' 'waza' pub struct Bar { pub f: u32, pub u: u32, @@ -30,8 +30,8 @@ pub struct Bar { // @has foo/enum.En.html // @has - '//*[@class="sidebar-title"]/a[@href="#variants"]' 'Variants' -// @has - '//*[@class="sidebar-links"]/a' 'Foo' -// @has - '//*[@class="sidebar-links"]/a' 'Bar' +// @has - '//*[@class="sidebar-elems"]//section//a' 'Foo' +// @has - '//*[@class="sidebar-elems"]//section//a' 'Bar' pub enum En { Foo, Bar, @@ -39,9 +39,9 @@ pub enum En { // @has foo/union.MyUnion.html // @has - '//*[@class="sidebar-title"]/a[@href="#fields"]' 'Fields' -// @has - '//*[@class="sidebar-links"]/a[@href="#structfield.f1"]' 'f1' -// @has - '//*[@class="sidebar-links"]/a[@href="#structfield.f2"]' 'f2' -// @!has - '//*[@class="sidebar-links"]/a' 'waza' +// @has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.f1"]' 'f1' +// @has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.f2"]' 'f2' +// @!has - '//*[@class="sidebar-elems"]//section//a' 'waza' pub union MyUnion { pub f1: u32, pub f2: f32, diff --git a/src/test/rustdoc/sidebar-link-generation.rs b/src/test/rustdoc/sidebar-link-generation.rs index 76b77b9bcbb..7858f35a261 100644 --- a/src/test/rustdoc/sidebar-link-generation.rs +++ b/src/test/rustdoc/sidebar-link-generation.rs @@ -1,6 +1,6 @@ #![crate_name = "foo"] -// @has foo/struct.SomeStruct.html '//*[@class="sidebar-links"]/a[@href="#method.some_fn-1"]' \ +// @has foo/struct.SomeStruct.html '//*[@class="sidebar-elems"]//section//li/a[@href="#method.some_fn-1"]' \ // "some_fn" pub struct SomeStruct<T> { _inner: T } diff --git a/src/test/rustdoc/sidebar-links-to-foreign-impl.rs b/src/test/rustdoc/sidebar-links-to-foreign-impl.rs index 63e486b8834..15515039659 100644 --- a/src/test/rustdoc/sidebar-links-to-foreign-impl.rs +++ b/src/test/rustdoc/sidebar-links-to-foreign-impl.rs @@ -5,9 +5,9 @@ // @has foo/trait.Foo.html // @has - '//*[@class="sidebar-title"]/a[@href="#foreign-impls"]' 'Implementations on Foreign Types' // @has - '//h2[@id="foreign-impls"]' 'Implementations on Foreign Types' -// @has - '//*[@class="sidebar-links"]/a[@href="#impl-Foo-for-u32"]' 'u32' +// @has - '//*[@class="sidebar-elems"]//section//a[@href="#impl-Foo-for-u32"]' 'u32' // @has - '//*[@id="impl-Foo-for-u32"]//h3[@class="code-header in-band"]' 'impl Foo for u32' -// @has - '//*[@class="sidebar-links"]/a[@href="#impl-Foo-for-%26%27a%20str"]' "&'a str" +// @has - '//*[@class="sidebar-elems"]//section//a[@href="#impl-Foo-for-%26%27a%20str"]' "&'a str" // @has - '//*[@id="impl-Foo-for-%26%27a%20str"]//h3[@class="code-header in-band"]' "impl<'a> Foo for &'a str" pub trait Foo {} diff --git a/src/test/ui/async-await/issue-61949-self-return-type.rs b/src/test/ui/async-await/issue-61949-self-return-type.rs index 42133d51041..43429ba2329 100644 --- a/src/test/ui/async-await/issue-61949-self-return-type.rs +++ b/src/test/ui/async-await/issue-61949-self-return-type.rs @@ -8,6 +8,7 @@ pub struct Foo<'a> { impl<'a> Foo<'a> { pub async fn new(_bar: &'a i32) -> Self { + //~^ ERROR `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope Foo { bar: &22 } @@ -18,7 +19,6 @@ async fn foo() { let x = { let bar = 22; Foo::new(&bar).await - //~^ ERROR `bar` does not live long enough [E0597] }; drop(x); } diff --git a/src/test/ui/async-await/issue-61949-self-return-type.stderr b/src/test/ui/async-await/issue-61949-self-return-type.stderr index f86844e1a9c..52b726e186e 100644 --- a/src/test/ui/async-await/issue-61949-self-return-type.stderr +++ b/src/test/ui/async-await/issue-61949-self-return-type.stderr @@ -1,15 +1,9 @@ -error[E0597]: `bar` does not live long enough - --> $DIR/issue-61949-self-return-type.rs:20:18 +error[E0760]: `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope + --> $DIR/issue-61949-self-return-type.rs:10:40 | -LL | let x = { - | - borrow later stored here -LL | let bar = 22; -LL | Foo::new(&bar).await - | ^^^^ borrowed value does not live long enough -LL | -LL | }; - | - `bar` dropped here while still borrowed +LL | pub async fn new(_bar: &'a i32) -> Self { + | ^^^^ help: consider spelling out the type instead: `Foo<'a>` error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0760`. diff --git a/src/test/ui/async-await/issue-74072-lifetime-name-annotations.stderr b/src/test/ui/async-await/issue-74072-lifetime-name-annotations.stderr index 80504613eb4..b96cab9f0f5 100644 --- a/src/test/ui/async-await/issue-74072-lifetime-name-annotations.stderr +++ b/src/test/ui/async-await/issue-74072-lifetime-name-annotations.stderr @@ -1,10 +1,14 @@ error[E0506]: cannot assign to `*x` because it is borrowed --> $DIR/issue-74072-lifetime-name-annotations.rs:9:5 | +LL | pub async fn async_fn(x: &mut i32) -> &i32 { + | - let's call the lifetime of this reference `'1` LL | let y = &*x; | --- borrow of `*x` occurs here LL | *x += 1; | ^^^^^^^ assignment to borrowed `*x` occurs here +LL | y + | - returning this value requires that `*x` is borrowed for `'1` error[E0506]: cannot assign to `*x` because it is borrowed --> $DIR/issue-74072-lifetime-name-annotations.rs:16:9 diff --git a/src/test/ui/async-await/issue-75785-confusing-named-region.stderr b/src/test/ui/async-await/issue-75785-confusing-named-region.stderr index 06660b7c182..3b731d9c60a 100644 --- a/src/test/ui/async-await/issue-75785-confusing-named-region.stderr +++ b/src/test/ui/async-await/issue-75785-confusing-named-region.stderr @@ -1,10 +1,14 @@ error[E0506]: cannot assign to `*x` because it is borrowed --> $DIR/issue-75785-confusing-named-region.rs:9:5 | +LL | pub async fn async_fn(x: &mut i32) -> (&i32, &i32) { + | - let's call the lifetime of this reference `'1` LL | let y = &*x; | --- borrow of `*x` occurs here LL | *x += 1; | ^^^^^^^ assignment to borrowed `*x` occurs here +LL | (&32, y) + | -------- returning this value requires that `*x` is borrowed for `'1` error: aborting due to previous error diff --git a/src/test/ui/async-await/issues/issue-63388-1.stderr b/src/test/ui/async-await/issues/issue-63388-1.stderr index ee270d36979..8f602a1492a 100644 --- a/src/test/ui/async-await/issues/issue-63388-1.stderr +++ b/src/test/ui/async-await/issues/issue-63388-1.stderr @@ -2,10 +2,12 @@ error[E0623]: lifetime mismatch --> $DIR/issue-63388-1.rs:14:9 | LL | &'a self, foo: &dyn Foo - | -------- -------- these two types are declared with different lifetimes... -... + | -------- this parameter and the return type are declared with different lifetimes... +LL | ) -> &dyn Foo + | -------- +LL | { LL | foo - | ^^^ ...but data from `foo` flows into `self` here + | ^^^ ...but data from `foo` is returned here error: aborting due to previous error diff --git a/src/test/ui/async-await/issues/issue-78600.rs b/src/test/ui/async-await/issues/issue-78600.rs index 4303fc7952f..8aaeaecf3e1 100644 --- a/src/test/ui/async-await/issues/issue-78600.rs +++ b/src/test/ui/async-await/issues/issue-78600.rs @@ -1,10 +1,10 @@ -// check-pass // edition:2018 struct S<'a>(&'a i32); impl<'a> S<'a> { async fn new(i: &'a i32) -> Result<Self, ()> { + //~^ ERROR: `async fn` Ok(S(&22)) } } diff --git a/src/test/ui/async-await/issues/issue-78600.stderr b/src/test/ui/async-await/issues/issue-78600.stderr new file mode 100644 index 00000000000..92b66147106 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-78600.stderr @@ -0,0 +1,11 @@ +error[E0760]: `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope + --> $DIR/issue-78600.rs:6:33 + | +LL | async fn new(i: &'a i32) -> Result<Self, ()> { + | ^^^^^^^----^^^^^ + | | + | help: consider spelling out the type instead: `S<'a>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0760`. diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.nll.stderr b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.nll.stderr index b0ea6af0050..2722c72c20a 100644 --- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.nll.stderr +++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.nll.stderr @@ -1,13 +1,15 @@ error: lifetime may not live long enough - --> $DIR/ret-impl-trait-one.rs:12:5 + --> $DIR/ret-impl-trait-one.rs:10:85 | -LL | async fn async_ret_impl_trait3<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b { - | -- -- lifetime `'b` defined here - | | - | lifetime `'a` defined here -LL | -LL | (a, b) - | ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` +LL | async fn async_ret_impl_trait3<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b { + | ________________________________--__--_______________________________________________^ + | | | | + | | | lifetime `'b` defined here + | | lifetime `'a` defined here +LL | | +LL | | (a, b) +LL | | } + | |_^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` | = help: consider adding the following bound: `'a: 'b` diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr index 6f79d9e9b5f..149692a2c69 100644 --- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr +++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr @@ -2,9 +2,10 @@ error[E0623]: lifetime mismatch --> $DIR/ret-impl-trait-one.rs:10:65 | LL | async fn async_ret_impl_trait3<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b { - | ------ ------ ^^^^^^^^^^^^^^^^^^^ ...but data from `a` flows into `b` here - | | - | these two types are declared with different lifetimes... + | ------ ^^^^^^^^^^^^^^^^^^^ + | | | + | | ...but data from `a` is returned here + | this parameter and the return type are declared with different lifetimes... error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds --> $DIR/ret-impl-trait-one.rs:16:65 diff --git a/src/test/ui/async-await/unused-lifetime.rs b/src/test/ui/async-await/unused-lifetime.rs index a0504927254..5bd6ae8d3a4 100644 --- a/src/test/ui/async-await/unused-lifetime.rs +++ b/src/test/ui/async-await/unused-lifetime.rs @@ -10,13 +10,10 @@ // Even wrong cases don't cause errors because async functions are desugared with all lifetimes // involved in the signature. So, we cannot predict what lifetimes are unused in async function. async fn async_wrong_without_args<'a>() {} -//~^ ERROR lifetime parameter `'a` never used [unused_lifetimes] async fn async_wrong_1_lifetime<'a>(_: &i32) {} -//~^ ERROR lifetime parameter `'a` never used [unused_lifetimes] async fn async_wrong_2_lifetimes<'a, 'b>(_: &'a i32, _: &i32) {} -//~^ ERROR lifetime parameter `'b` never used [unused_lifetimes] async fn async_right_1_lifetime<'a>(_: &'a i32) {} diff --git a/src/test/ui/async-await/unused-lifetime.stderr b/src/test/ui/async-await/unused-lifetime.stderr index 85304b9cb9e..4e90f43fdd0 100644 --- a/src/test/ui/async-await/unused-lifetime.stderr +++ b/src/test/ui/async-await/unused-lifetime.stderr @@ -1,8 +1,8 @@ error: lifetime parameter `'a` never used - --> $DIR/unused-lifetime.rs:12:35 + --> $DIR/unused-lifetime.rs:31:23 | -LL | async fn async_wrong_without_args<'a>() {} - | -^^- help: elide the unused lifetime +LL | fn wrong_without_args<'a>() {} + | -^^- help: elide the unused lifetime | note: the lint level is defined here --> $DIR/unused-lifetime.rs:5:9 @@ -11,40 +11,18 @@ LL | #![deny(unused_lifetimes)] | ^^^^^^^^^^^^^^^^ error: lifetime parameter `'a` never used - --> $DIR/unused-lifetime.rs:15:33 - | -LL | async fn async_wrong_1_lifetime<'a>(_: &i32) {} - | ^^----- - | | - | help: elide the unused lifetime - -error: lifetime parameter `'b` never used - --> $DIR/unused-lifetime.rs:18:38 - | -LL | async fn async_wrong_2_lifetimes<'a, 'b>(_: &'a i32, _: &i32) {} - | ^^----------------- - | | - | help: elide the unused lifetime - -error: lifetime parameter `'a` never used - --> $DIR/unused-lifetime.rs:34:23 - | -LL | fn wrong_without_args<'a>() {} - | -^^- help: elide the unused lifetime - -error: lifetime parameter `'a` never used - --> $DIR/unused-lifetime.rs:36:21 + --> $DIR/unused-lifetime.rs:33:21 | LL | fn wrong_1_lifetime<'a>(_: &i32) {} | -^^- help: elide the unused lifetime error: lifetime parameter `'b` never used - --> $DIR/unused-lifetime.rs:38:26 + --> $DIR/unused-lifetime.rs:35:26 | LL | fn wrong_2_lifetimes<'a, 'b>(_: &'a i32, _: &i32) {} | --^^ | | | help: elide the unused lifetime -error: aborting due to 6 previous errors +error: aborting due to 3 previous errors diff --git a/src/test/ui/box/issue-78459-ice.rs b/src/test/ui/box/issue-78459-ice.rs new file mode 100644 index 00000000000..89f75fea15b --- /dev/null +++ b/src/test/ui/box/issue-78459-ice.rs @@ -0,0 +1,6 @@ +// check-pass +#![feature(allocator_api)] + +fn main() { + Box::new_in((), &std::alloc::Global); +} diff --git a/src/test/ui/cfg/cfg-panic-abort.rs b/src/test/ui/cfg/cfg-panic-abort.rs index 9b88eff12ed..3853b598a7a 100644 --- a/src/test/ui/cfg/cfg-panic-abort.rs +++ b/src/test/ui/cfg/cfg-panic-abort.rs @@ -1,7 +1,7 @@ // build-pass // compile-flags: -C panic=abort // no-prefer-dynamic -#![feature(cfg_panic)] + #[cfg(panic = "unwind")] pub fn bad() -> i32 { } diff --git a/src/test/ui/cfg/cfg-panic.rs b/src/test/ui/cfg/cfg-panic.rs index d2113e4f5ec..fb3e5059c81 100644 --- a/src/test/ui/cfg/cfg-panic.rs +++ b/src/test/ui/cfg/cfg-panic.rs @@ -4,7 +4,7 @@ // ignore-emscripten no panic_unwind implementation // ignore-wasm32 no panic_unwind implementation // ignore-wasm64 no panic_unwind implementation -#![feature(cfg_panic)] + #[cfg(panic = "abort")] pub fn bad() -> i32 { } diff --git a/src/test/ui/check-cfg/empty-names.rs b/src/test/ui/check-cfg/empty-names.rs new file mode 100644 index 00000000000..046ff0364e2 --- /dev/null +++ b/src/test/ui/check-cfg/empty-names.rs @@ -0,0 +1,10 @@ +// Check warning for unexpected cfg +// +// check-pass +// compile-flags: --check-cfg=names() -Z unstable-options + +#[cfg(unknown_key = "value")] +//~^ WARNING unexpected `cfg` condition name +pub fn f() {} + +fn main() {} diff --git a/src/test/ui/check-cfg/empty-names.stderr b/src/test/ui/check-cfg/empty-names.stderr new file mode 100644 index 00000000000..f926d1133cc --- /dev/null +++ b/src/test/ui/check-cfg/empty-names.stderr @@ -0,0 +1,10 @@ +warning: unexpected `cfg` condition name + --> $DIR/empty-names.rs:6:7 + | +LL | #[cfg(unknown_key = "value")] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: 1 warning emitted + diff --git a/src/test/ui/check-cfg/empty-values.rs b/src/test/ui/check-cfg/empty-values.rs new file mode 100644 index 00000000000..38ef9e51c7a --- /dev/null +++ b/src/test/ui/check-cfg/empty-values.rs @@ -0,0 +1,6 @@ +// Check that a an empty values() is rejected +// +// check-fail +// compile-flags: --check-cfg=values() -Z unstable-options + +fn main() {} diff --git a/src/test/ui/check-cfg/empty-values.stderr b/src/test/ui/check-cfg/empty-values.stderr new file mode 100644 index 00000000000..106d5b7b47f --- /dev/null +++ b/src/test/ui/check-cfg/empty-values.stderr @@ -0,0 +1,2 @@ +error: invalid `--check-cfg` argument: `values()` (expected `names(name1, name2, ... nameN)` or `values(name, "value1", "value2", ... "valueN")`) + diff --git a/src/test/ui/check-cfg/invalid-arguments.anything_else.stderr b/src/test/ui/check-cfg/invalid-arguments.anything_else.stderr new file mode 100644 index 00000000000..850924d993a --- /dev/null +++ b/src/test/ui/check-cfg/invalid-arguments.anything_else.stderr @@ -0,0 +1,2 @@ +error: invalid `--check-cfg` argument: `anything_else(...)` (expected `names(name1, name2, ... nameN)` or `values(name, "value1", "value2", ... "valueN")`) + diff --git a/src/test/ui/check-cfg/invalid-arguments.names_simple_ident.stderr b/src/test/ui/check-cfg/invalid-arguments.names_simple_ident.stderr new file mode 100644 index 00000000000..bdfbc3d54a2 --- /dev/null +++ b/src/test/ui/check-cfg/invalid-arguments.names_simple_ident.stderr @@ -0,0 +1,2 @@ +error: invalid `--check-cfg` argument: `names("NOT_IDENT")` (`names()` arguments must be simple identifers) + diff --git a/src/test/ui/check-cfg/invalid-arguments.rs b/src/test/ui/check-cfg/invalid-arguments.rs new file mode 100644 index 00000000000..5090ce3e845 --- /dev/null +++ b/src/test/ui/check-cfg/invalid-arguments.rs @@ -0,0 +1,10 @@ +// Check that invalid --check-cfg are rejected +// +// check-fail +// revisions: anything_else names_simple_ident values_simple_ident values_string_literals +// [anything_else]compile-flags: -Z unstable-options --check-cfg=anything_else(...) +// [names_simple_ident]compile-flags: -Z unstable-options --check-cfg=names("NOT_IDENT") +// [values_simple_ident]compile-flags: -Z unstable-options --check-cfg=values("NOT_IDENT") +// [values_string_literals]compile-flags: -Z unstable-options --check-cfg=values(test,12) + +fn main() {} diff --git a/src/test/ui/check-cfg/invalid-arguments.values_simple_ident.stderr b/src/test/ui/check-cfg/invalid-arguments.values_simple_ident.stderr new file mode 100644 index 00000000000..b25882baaf3 --- /dev/null +++ b/src/test/ui/check-cfg/invalid-arguments.values_simple_ident.stderr @@ -0,0 +1,2 @@ +error: invalid `--check-cfg` argument: `values("NOT_IDENT")` (`values()` first argument must be a simple identifer) + diff --git a/src/test/ui/check-cfg/invalid-arguments.values_string_literals.stderr b/src/test/ui/check-cfg/invalid-arguments.values_string_literals.stderr new file mode 100644 index 00000000000..5853b4741a6 --- /dev/null +++ b/src/test/ui/check-cfg/invalid-arguments.values_string_literals.stderr @@ -0,0 +1,2 @@ +error: invalid `--check-cfg` argument: `values(test,12)` (`values()` arguments must be string literals) + diff --git a/src/test/ui/check-cfg/invalid-cfg-name.rs b/src/test/ui/check-cfg/invalid-cfg-name.rs new file mode 100644 index 00000000000..8499d3d4448 --- /dev/null +++ b/src/test/ui/check-cfg/invalid-cfg-name.rs @@ -0,0 +1,14 @@ +// Check warning for invalid configuration name +// +// edition:2018 +// check-pass +// compile-flags: --check-cfg=names() -Z unstable-options + +#[cfg(widnows)] +//~^ WARNING unexpected `cfg` condition name +pub fn f() {} + +#[cfg(windows)] +pub fn g() {} + +pub fn main() {} diff --git a/src/test/ui/check-cfg/invalid-cfg-name.stderr b/src/test/ui/check-cfg/invalid-cfg-name.stderr new file mode 100644 index 00000000000..2587685afa0 --- /dev/null +++ b/src/test/ui/check-cfg/invalid-cfg-name.stderr @@ -0,0 +1,10 @@ +warning: unexpected `cfg` condition name + --> $DIR/invalid-cfg-name.rs:7:7 + | +LL | #[cfg(widnows)] + | ^^^^^^^ + | + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: 1 warning emitted + diff --git a/src/test/ui/check-cfg/invalid-cfg-value.rs b/src/test/ui/check-cfg/invalid-cfg-value.rs new file mode 100644 index 00000000000..a60095a5aae --- /dev/null +++ b/src/test/ui/check-cfg/invalid-cfg-value.rs @@ -0,0 +1,17 @@ +// Check warning for invalid configuration value +// +// edition:2018 +// check-pass +// compile-flags: --check-cfg=values(feature,"serde","full") --cfg=feature="rand" -Z unstable-options + +#[cfg(feature = "sedre")] +//~^ WARNING unexpected `cfg` condition value +pub fn f() {} + +#[cfg(feature = "serde")] +pub fn g() {} + +#[cfg(feature = "rand")] +pub fn h() {} + +pub fn main() {} diff --git a/src/test/ui/check-cfg/invalid-cfg-value.stderr b/src/test/ui/check-cfg/invalid-cfg-value.stderr new file mode 100644 index 00000000000..c591d8474a2 --- /dev/null +++ b/src/test/ui/check-cfg/invalid-cfg-value.stderr @@ -0,0 +1,10 @@ +warning: unexpected `cfg` condition value + --> $DIR/invalid-cfg-value.rs:7:7 + | +LL | #[cfg(feature = "sedre")] + | ^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: 1 warning emitted + diff --git a/src/test/ui/const-generics/defaults/doesnt_infer.rs b/src/test/ui/const-generics/defaults/doesnt_infer.rs index cd533b57bc3..9c59e672d8e 100644 --- a/src/test/ui/const-generics/defaults/doesnt_infer.rs +++ b/src/test/ui/const-generics/defaults/doesnt_infer.rs @@ -9,5 +9,5 @@ impl<const N: u32> Foo<N> { fn main() { let foo = Foo::<1>::foo(); let foo = Foo::foo(); - //~^ error: type annotations needed for `Foo<{_: u32}>` + //~^ error: type annotations needed for `Foo<N>` } diff --git a/src/test/ui/const-generics/defaults/doesnt_infer.stderr b/src/test/ui/const-generics/defaults/doesnt_infer.stderr index 1551e81ea75..cccf433e328 100644 --- a/src/test/ui/const-generics/defaults/doesnt_infer.stderr +++ b/src/test/ui/const-generics/defaults/doesnt_infer.stderr @@ -1,4 +1,4 @@ -error[E0282]: type annotations needed for `Foo<{_: u32}>` +error[E0282]: type annotations needed for `Foo<N>` --> $DIR/doesnt_infer.rs:11:15 | LL | let foo = Foo::foo(); diff --git a/src/test/ui/const-generics/generic_arg_infer/issue-91614.rs b/src/test/ui/const-generics/generic_arg_infer/issue-91614.rs index 413cc153924..b45e2cbc737 100644 --- a/src/test/ui/const-generics/generic_arg_infer/issue-91614.rs +++ b/src/test/ui/const-generics/generic_arg_infer/issue-91614.rs @@ -4,5 +4,5 @@ use std::simd::Mask; fn main() { let y = Mask::<_, _>::splat(false); - //~^ error: type annotations needed for `Mask<_, {_: usize}>` + //~^ ERROR: type annotations needed for } diff --git a/src/test/ui/const-generics/generic_arg_infer/issue-91614.stderr b/src/test/ui/const-generics/generic_arg_infer/issue-91614.stderr index 71a5ff79280..347cd2364b2 100644 --- a/src/test/ui/const-generics/generic_arg_infer/issue-91614.stderr +++ b/src/test/ui/const-generics/generic_arg_infer/issue-91614.stderr @@ -1,4 +1,4 @@ -error[E0283]: type annotations needed for `Mask<_, {_: usize}>` +error[E0283]: type annotations needed for `Mask<_, LANES>` --> $DIR/issue-91614.rs:6:13 | LL | let y = Mask::<_, _>::splat(false); diff --git a/src/test/ui/dropck/drop-with-active-borrows-2.stderr b/src/test/ui/dropck/drop-with-active-borrows-2.stderr index d5b747d42fb..24650dfac02 100644 --- a/src/test/ui/dropck/drop-with-active-borrows-2.stderr +++ b/src/test/ui/dropck/drop-with-active-borrows-2.stderr @@ -1,9 +1,10 @@ error[E0515]: cannot return value referencing local variable `raw_lines` - --> $DIR/drop-with-active-borrows-2.rs:3:30 + --> $DIR/drop-with-active-borrows-2.rs:3:5 | LL | raw_lines.iter().map(|l| l.trim()).collect() - | ---------------- ^^^^^^^^ returns a value referencing data owned by the current function + | ----------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | + | returns a value referencing data owned by the current function | `raw_lines` is borrowed here error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-asm_const.stderr b/src/test/ui/feature-gates/feature-gate-asm_const.stderr index 2851a9b0ae6..0202ccbe5a2 100644 --- a/src/test/ui/feature-gates/feature-gate-asm_const.stderr +++ b/src/test/ui/feature-gates/feature-gate-asm_const.stderr @@ -4,7 +4,7 @@ error[E0658]: const operands for inline assembly are unstable LL | asm!("mov eax, {}", const 123); | ^^^^^^^^^ | - = note: see issue #72016 <https://github.com/rust-lang/rust/issues/72016> for more information + = note: see issue #93332 <https://github.com/rust-lang/rust/issues/93332> for more information = help: add `#![feature(asm_const)]` to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-asm_experimental_arch.stderr b/src/test/ui/feature-gates/feature-gate-asm_experimental_arch.stderr index 1b4188ae1ad..4a859430e04 100644 --- a/src/test/ui/feature-gates/feature-gate-asm_experimental_arch.stderr +++ b/src/test/ui/feature-gates/feature-gate-asm_experimental_arch.stderr @@ -4,7 +4,7 @@ error[E0658]: inline assembly is not stable yet on this architecture LL | asm!(""); | ^^^^^^^^ | - = note: see issue #72016 <https://github.com/rust-lang/rust/issues/72016> for more information + = note: see issue #93335 <https://github.com/rust-lang/rust/issues/93335> for more information = help: add `#![feature(asm_experimental_arch)]` to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-asm_sym.stderr b/src/test/ui/feature-gates/feature-gate-asm_sym.stderr index 99b61b829fb..68f2d0f6c18 100644 --- a/src/test/ui/feature-gates/feature-gate-asm_sym.stderr +++ b/src/test/ui/feature-gates/feature-gate-asm_sym.stderr @@ -4,7 +4,7 @@ error[E0658]: sym operands for inline assembly are unstable LL | asm!("mov eax, {}", sym main); | ^^^^^^^^ | - = note: see issue #72016 <https://github.com/rust-lang/rust/issues/72016> for more information + = note: see issue #93333 <https://github.com/rust-lang/rust/issues/93333> for more information = help: add `#![feature(asm_sym)]` to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-asm_unwind.stderr b/src/test/ui/feature-gates/feature-gate-asm_unwind.stderr index 6b5bf286e7b..05e66acb556 100644 --- a/src/test/ui/feature-gates/feature-gate-asm_unwind.stderr +++ b/src/test/ui/feature-gates/feature-gate-asm_unwind.stderr @@ -4,7 +4,7 @@ error[E0658]: the `may_unwind` option is unstable LL | asm!("", options(may_unwind)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #72016 <https://github.com/rust-lang/rust/issues/72016> for more information + = note: see issue #93334 <https://github.com/rust-lang/rust/issues/93334> for more information = help: add `#![feature(asm_unwind)]` to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs index 1e48996acb8..a93fb797713 100644 --- a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs +++ b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs @@ -57,20 +57,20 @@ fn _rpit_dyn() -> Box<dyn Tr1<As1: Copy>> { Box::new(S1) } const _cdef: impl Tr1<As1: Copy> = S1; //~^ ERROR associated type bounds are unstable -//~| ERROR `impl Trait` not allowed outside of function and method return types [E0562] +//~| ERROR `impl Trait` only allowed in function and inherent method return types // FIXME: uncomment when `impl_trait_in_bindings` feature is fixed. // const _cdef_dyn: &dyn Tr1<As1: Copy> = &S1; static _sdef: impl Tr1<As1: Copy> = S1; //~^ ERROR associated type bounds are unstable -//~| ERROR `impl Trait` not allowed outside of function and method return types [E0562] +//~| ERROR `impl Trait` only allowed in function and inherent method return types // FIXME: uncomment when `impl_trait_in_bindings` feature is fixed. // static _sdef_dyn: &dyn Tr1<As1: Copy> = &S1; fn main() { let _: impl Tr1<As1: Copy> = S1; //~^ ERROR associated type bounds are unstable - //~| ERROR `impl Trait` not allowed outside of function and method return types [E0562] + //~| ERROR `impl Trait` only allowed in function and inherent method return types // FIXME: uncomment when `impl_trait_in_bindings` feature is fixed. // let _: &dyn Tr1<As1: Copy> = &S1; } diff --git a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr index 8c5d72d7efe..5be1d97a059 100644 --- a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr +++ b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr @@ -115,19 +115,19 @@ LL | let _: impl Tr1<As1: Copy> = S1; = note: see issue #52662 <https://github.com/rust-lang/rust/issues/52662> for more information = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type --> $DIR/feature-gate-associated_type_bounds.rs:58:14 | LL | const _cdef: impl Tr1<As1: Copy> = S1; | ^^^^^^^^^^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type --> $DIR/feature-gate-associated_type_bounds.rs:64:15 | LL | static _sdef: impl Tr1<As1: Copy> = S1; | ^^^^^^^^^^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding --> $DIR/feature-gate-associated_type_bounds.rs:71:12 | LL | let _: impl Tr1<As1: Copy> = S1; diff --git a/src/test/ui/feature-gates/feature-gate-cfg-panic.rs b/src/test/ui/feature-gates/feature-gate-cfg-panic.rs deleted file mode 100644 index 1508374d942..00000000000 --- a/src/test/ui/feature-gates/feature-gate-cfg-panic.rs +++ /dev/null @@ -1,11 +0,0 @@ -#[cfg(panic = "unwind")] -//~^ ERROR `cfg(panic)` is experimental and subject to change -fn foo() -> bool { true } -#[cfg(not(panic = "unwind"))] -//~^ ERROR `cfg(panic)` is experimental and subject to change -fn foo() -> bool { false } - - -fn main() { - assert!(foo()); -} diff --git a/src/test/ui/feature-gates/feature-gate-cfg-panic.stderr b/src/test/ui/feature-gates/feature-gate-cfg-panic.stderr deleted file mode 100644 index ea5cd54fa90..00000000000 --- a/src/test/ui/feature-gates/feature-gate-cfg-panic.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0658]: `cfg(panic)` is experimental and subject to change - --> $DIR/feature-gate-cfg-panic.rs:1:7 - | -LL | #[cfg(panic = "unwind")] - | ^^^^^^^^^^^^^^^^ - | - = note: see issue #77443 <https://github.com/rust-lang/rust/issues/77443> for more information - = help: add `#![feature(cfg_panic)]` to the crate attributes to enable - -error[E0658]: `cfg(panic)` is experimental and subject to change - --> $DIR/feature-gate-cfg-panic.rs:4:11 - | -LL | #[cfg(not(panic = "unwind"))] - | ^^^^^^^^^^^^^^^^ - | - = note: see issue #77443 <https://github.com/rust-lang/rust/issues/77443> for more information - = help: add `#![feature(cfg_panic)]` to the crate attributes to enable - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-check-cfg.rs b/src/test/ui/feature-gates/feature-gate-check-cfg.rs new file mode 100644 index 00000000000..4012a3b04b5 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-check-cfg.rs @@ -0,0 +1,3 @@ +// compile-flags: --check-cfg "names()" + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-check-cfg.stderr b/src/test/ui/feature-gates/feature-gate-check-cfg.stderr new file mode 100644 index 00000000000..9b27c2bc058 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-check-cfg.stderr @@ -0,0 +1,2 @@ +error: the `-Z unstable-options` flag must also be passed to enable the flag `check-cfg` + diff --git a/src/test/ui/fmt/format-args-capture.rs b/src/test/ui/fmt/format-args-capture.rs index d31d2a6c336..560352b5cb9 100644 --- a/src/test/ui/fmt/format-args-capture.rs +++ b/src/test/ui/fmt/format-args-capture.rs @@ -1,5 +1,4 @@ // run-pass -#![feature(cfg_panic)] fn main() { named_argument_takes_precedence_to_captured(); diff --git a/src/test/ui/generic-associated-types/bugs/issue-80626.rs b/src/test/ui/generic-associated-types/bugs/issue-80626.rs index aea8aaf4bb3..a637da6cf6f 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-80626.rs +++ b/src/test/ui/generic-associated-types/bugs/issue-80626.rs @@ -1,4 +1,5 @@ // check-fail +// known-bug // This should pass, but it requires `Sized` to be coinductive. @@ -11,7 +12,6 @@ trait Allocator { enum LinkedList<A: Allocator> { Head, Next(A::Allocated<Self>) - //~^ overflow } fn main() {} diff --git a/src/test/ui/generic-associated-types/bugs/issue-80626.stderr b/src/test/ui/generic-associated-types/bugs/issue-80626.stderr index e18af9c257f..8b0cc78e999 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-80626.stderr +++ b/src/test/ui/generic-associated-types/bugs/issue-80626.stderr @@ -1,5 +1,5 @@ error[E0275]: overflow evaluating the requirement `LinkedList<A>: Sized` - --> $DIR/issue-80626.rs:13:10 + --> $DIR/issue-80626.rs:14:10 | LL | Next(A::Allocated<Self>) | ^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/generic-associated-types/bugs/issue-86218.rs b/src/test/ui/generic-associated-types/bugs/issue-86218.rs index 3f8776a3637..68cd0fd7efc 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-86218.rs +++ b/src/test/ui/generic-associated-types/bugs/issue-86218.rs @@ -1,4 +1,5 @@ // check-fail +// known-bug // This should pass, but seems to run into a TAIT issue. @@ -20,7 +21,6 @@ trait Yay<AdditionalValue> { impl<'a> Yay<&'a ()> for () { type InnerStream<'s> = impl Stream<Item = i32> + 's; - //~^ the type fn foo<'s>() -> Self::InnerStream<'s> { todo!() } } diff --git a/src/test/ui/generic-associated-types/bugs/issue-86218.stderr b/src/test/ui/generic-associated-types/bugs/issue-86218.stderr index 9f4efc0addb..98a5f4254bb 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-86218.stderr +++ b/src/test/ui/generic-associated-types/bugs/issue-86218.stderr @@ -1,11 +1,11 @@ error[E0477]: the type `impl Stream<Item = i32>` does not fulfill the required lifetime - --> $DIR/issue-86218.rs:22:28 + --> $DIR/issue-86218.rs:23:28 | LL | type InnerStream<'s> = impl Stream<Item = i32> + 's; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: type must outlive the lifetime `'s` as defined here as required by this binding - --> $DIR/issue-86218.rs:22:22 + --> $DIR/issue-86218.rs:23:22 | LL | type InnerStream<'s> = impl Stream<Item = i32> + 's; | ^^ diff --git a/src/test/ui/generic-associated-types/bugs/issue-87735.rs b/src/test/ui/generic-associated-types/bugs/issue-87735.rs index 5f7a42a740d..6d6063f8085 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-87735.rs +++ b/src/test/ui/generic-associated-types/bugs/issue-87735.rs @@ -1,4 +1,5 @@ // check-fail +// known-bug // This should pass, but we need an extension of implied bounds (probably). @@ -23,7 +24,7 @@ struct Foo<T>(T); #[derive(Debug)] struct FooRef<'a, U>(&'a [U]); -impl<'b, T, U> AsRef2 for Foo<T> //~ the type parameter +impl<'b, T, U> AsRef2 for Foo<T> where // * `for<'b, 'c> T: AsRef2<Output<'b> = &'c [U]>>` does not work // diff --git a/src/test/ui/generic-associated-types/bugs/issue-87735.stderr b/src/test/ui/generic-associated-types/bugs/issue-87735.stderr index 31b3a9619b6..0a18b5f0cbd 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-87735.stderr +++ b/src/test/ui/generic-associated-types/bugs/issue-87735.stderr @@ -1,5 +1,5 @@ error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates - --> $DIR/issue-87735.rs:26:13 + --> $DIR/issue-87735.rs:27:13 | LL | impl<'b, T, U> AsRef2 for Foo<T> | ^ unconstrained type parameter diff --git a/src/test/ui/generic-associated-types/bugs/issue-87748.rs b/src/test/ui/generic-associated-types/bugs/issue-87748.rs index 4dbaf429ead..ffcfd62cbb3 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-87748.rs +++ b/src/test/ui/generic-associated-types/bugs/issue-87748.rs @@ -1,4 +1,5 @@ // check-fail +// known-bug // This should pass, but unnormalized input args aren't treated as implied. @@ -14,7 +15,7 @@ struct Foo; impl MyTrait for Foo { type Assoc<'a, 'b> where 'b: 'a = u32; - fn do_sth(_: u32) {} //~ lifetime bound + fn do_sth(_: u32) {} // fn do_sth(_: Self::Assoc<'static, 'static>) {} // fn do_sth(_: Self::Assoc<'_, '_>) {} } diff --git a/src/test/ui/generic-associated-types/bugs/issue-87748.stderr b/src/test/ui/generic-associated-types/bugs/issue-87748.stderr index c38d4478592..60bb48efbc8 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-87748.stderr +++ b/src/test/ui/generic-associated-types/bugs/issue-87748.stderr @@ -1,16 +1,16 @@ error[E0478]: lifetime bound not satisfied - --> $DIR/issue-87748.rs:17:5 + --> $DIR/issue-87748.rs:18:5 | LL | fn do_sth(_: u32) {} | ^^^^^^^^^^^^^^^^^ | note: lifetime parameter instantiated with the anonymous lifetime #2 defined here - --> $DIR/issue-87748.rs:17:5 + --> $DIR/issue-87748.rs:18:5 | LL | fn do_sth(_: u32) {} | ^^^^^^^^^^^^^^^^^ note: but lifetime parameter must outlive the anonymous lifetime #1 defined here - --> $DIR/issue-87748.rs:17:5 + --> $DIR/issue-87748.rs:18:5 | LL | fn do_sth(_: u32) {} | ^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/generic-associated-types/bugs/issue-87755.rs b/src/test/ui/generic-associated-types/bugs/issue-87755.rs index 1cd3534ba77..31cea12a3e2 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-87755.rs +++ b/src/test/ui/generic-associated-types/bugs/issue-87755.rs @@ -1,4 +1,5 @@ // check-fail +// known-bug // This should pass. @@ -15,7 +16,6 @@ struct Bar; impl Foo for Bar { type Ass = Bar; - //~^ overflow } fn main() {} diff --git a/src/test/ui/generic-associated-types/bugs/issue-87755.stderr b/src/test/ui/generic-associated-types/bugs/issue-87755.stderr index d2dc991a2b6..5d1aff0117c 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-87755.stderr +++ b/src/test/ui/generic-associated-types/bugs/issue-87755.stderr @@ -1,5 +1,5 @@ error[E0275]: overflow evaluating the requirement `<Bar as Foo>::Ass == _` - --> $DIR/issue-87755.rs:17:16 + --> $DIR/issue-87755.rs:18:16 | LL | type Ass = Bar; | ^^^ diff --git a/src/test/ui/generic-associated-types/bugs/issue-87803.rs b/src/test/ui/generic-associated-types/bugs/issue-87803.rs index 3d2ff38ab04..57a4b028d93 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-87803.rs +++ b/src/test/ui/generic-associated-types/bugs/issue-87803.rs @@ -1,4 +1,5 @@ // check-fail +// known-bug // This should pass, but using a type alias vs a reference directly // changes late-bound -> early-bound. @@ -18,7 +19,7 @@ impl Scanner for IdScanner { type Input<'a> = &'a str; type Token<'a> = &'a str; - fn scan<'a>(&mut self, s : &'a str) -> &'a str { //~ lifetime parameters + fn scan<'a>(&mut self, s : &'a str) -> &'a str { s } } diff --git a/src/test/ui/generic-associated-types/bugs/issue-87803.stderr b/src/test/ui/generic-associated-types/bugs/issue-87803.stderr index 759c0440d07..c81c051d32a 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-87803.stderr +++ b/src/test/ui/generic-associated-types/bugs/issue-87803.stderr @@ -1,5 +1,5 @@ error[E0195]: lifetime parameters or bounds on method `scan` do not match the trait declaration - --> $DIR/issue-87803.rs:21:12 + --> $DIR/issue-87803.rs:22:12 | LL | fn scan<'a>(&mut self, i : Self::Input<'a>) -> Self::Token<'a>; | ---- lifetimes in impl do not match this method in trait diff --git a/src/test/ui/generic-associated-types/bugs/issue-88382.rs b/src/test/ui/generic-associated-types/bugs/issue-88382.rs index f4633ca5169..c9f34240527 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-88382.rs +++ b/src/test/ui/generic-associated-types/bugs/issue-88382.rs @@ -1,4 +1,5 @@ // check-fail +// known-bug // This should pass, but has a missed normalization due to HRTB. @@ -25,7 +26,6 @@ fn do_something<I: Iterable>(i: I, mut f: impl for<'a> Fn(&mut I::Iterator<'a>)) fn main() { do_something(SomeImplementation(), |_| ()); do_something(SomeImplementation(), test); - //~^ type mismatch } fn test<'a, I: Iterable>(_: &mut I::Iterator<'a>) {} diff --git a/src/test/ui/generic-associated-types/bugs/issue-88382.stderr b/src/test/ui/generic-associated-types/bugs/issue-88382.stderr index 05bc58cbba4..d06c3ec8de7 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-88382.stderr +++ b/src/test/ui/generic-associated-types/bugs/issue-88382.stderr @@ -1,5 +1,5 @@ error[E0631]: type mismatch in function arguments - --> $DIR/issue-88382.rs:27:40 + --> $DIR/issue-88382.rs:28:40 | LL | do_something(SomeImplementation(), test); | ------------ ^^^^ expected signature of `for<'a> fn(&mut <SomeImplementation as Iterable>::Iterator<'a>) -> _` @@ -10,7 +10,7 @@ LL | fn test<'a, I: Iterable>(_: &mut I::Iterator<'a>) {} | ------------------------------------------------- found signature of `for<'r> fn(&'r mut std::iter::Empty<usize>) -> _` | note: required by a bound in `do_something` - --> $DIR/issue-88382.rs:21:56 + --> $DIR/issue-88382.rs:22:56 | LL | fn do_something<I: Iterable>(i: I, mut f: impl for<'a> Fn(&mut I::Iterator<'a>)) { | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `do_something` diff --git a/src/test/ui/generic-associated-types/bugs/issue-88460.rs b/src/test/ui/generic-associated-types/bugs/issue-88460.rs index 7e62790cc50..b31d012d2fc 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-88460.rs +++ b/src/test/ui/generic-associated-types/bugs/issue-88460.rs @@ -1,4 +1,5 @@ // check-fail +// known-bug // This should pass, but has a missed normalization due to HRTB. @@ -27,5 +28,4 @@ impl Trait for Foo { fn main() { test(Foo); - //~^ the trait bound } diff --git a/src/test/ui/generic-associated-types/bugs/issue-88460.stderr b/src/test/ui/generic-associated-types/bugs/issue-88460.stderr index 604658da7d2..0b83e9da1ab 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-88460.stderr +++ b/src/test/ui/generic-associated-types/bugs/issue-88460.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `for<'a> <_ as Trait>::Assoc<'a>: Marker` is not satisfied - --> $DIR/issue-88460.rs:29:5 + --> $DIR/issue-88460.rs:30:5 | LL | test(Foo); | ^^^^ the trait `for<'a> Marker` is not implemented for `<_ as Trait>::Assoc<'a>` | note: required by a bound in `test` - --> $DIR/issue-88460.rs:16:27 + --> $DIR/issue-88460.rs:17:27 | LL | fn test<T>(value: T) | ---- required by a bound in this diff --git a/src/test/ui/generic-associated-types/bugs/issue-88526.rs b/src/test/ui/generic-associated-types/bugs/issue-88526.rs index 90568fcb401..c72a450b926 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-88526.rs +++ b/src/test/ui/generic-associated-types/bugs/issue-88526.rs @@ -1,4 +1,5 @@ // check-fail +// known-bug // This should pass, but requires more logic. @@ -23,7 +24,7 @@ struct TestB<Q, F> f: F, } -impl<'q, Q, I, F> A for TestB<Q, F> //~ the type parameter +impl<'q, Q, I, F> A for TestB<Q, F> where Q: A<I<'q> = &'q I>, F: Fn(I), diff --git a/src/test/ui/generic-associated-types/bugs/issue-88526.stderr b/src/test/ui/generic-associated-types/bugs/issue-88526.stderr index ccc5ae0b621..127c889bf71 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-88526.stderr +++ b/src/test/ui/generic-associated-types/bugs/issue-88526.stderr @@ -1,5 +1,5 @@ error[E0207]: the type parameter `I` is not constrained by the impl trait, self type, or predicates - --> $DIR/issue-88526.rs:26:13 + --> $DIR/issue-88526.rs:27:13 | LL | impl<'q, Q, I, F> A for TestB<Q, F> | ^ unconstrained type parameter diff --git a/src/test/ui/generic-associated-types/bugs/issue-89008.rs b/src/test/ui/generic-associated-types/bugs/issue-89008.rs index 5d850849fd2..1581b7105a8 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-89008.rs +++ b/src/test/ui/generic-associated-types/bugs/issue-89008.rs @@ -1,5 +1,6 @@ // check-fail // edition:2021 +// known-bug // This should pass, but seems to run into a TAIT bug. @@ -31,11 +32,11 @@ trait X { struct Y; impl X for Y { - type LineStream<'a, Repr> = impl Stream<Item = Repr>; //~ could not find + type LineStream<'a, Repr> = impl Stream<Item = Repr>; type LineStreamFut<'a, Repr> = impl Future<Output = Self::LineStream<'a, Repr>> ; - fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> { //~ type mismatch + fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> { async {empty()} } } diff --git a/src/test/ui/generic-associated-types/bugs/issue-89008.stderr b/src/test/ui/generic-associated-types/bugs/issue-89008.stderr index 48745fe0fbd..c2687ca5401 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-89008.stderr +++ b/src/test/ui/generic-associated-types/bugs/issue-89008.stderr @@ -1,5 +1,5 @@ error[E0271]: type mismatch resolving `<impl Future<Output = [async output]> as Future>::Output == impl Stream<Item = Repr>` - --> $DIR/issue-89008.rs:38:43 + --> $DIR/issue-89008.rs:39:43 | LL | type LineStream<'a, Repr> = impl Stream<Item = Repr>; | ------------------------ the expected opaque type @@ -11,7 +11,7 @@ LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> { found struct `Empty<_>` error: could not find defining uses - --> $DIR/issue-89008.rs:34:33 + --> $DIR/issue-89008.rs:35:33 | LL | type LineStream<'a, Repr> = impl Stream<Item = Repr>; | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/generic-associated-types/impl_bounds.stderr b/src/test/ui/generic-associated-types/impl_bounds.stderr index 5be431f2933..bd0dea37219 100644 --- a/src/test/ui/generic-associated-types/impl_bounds.stderr +++ b/src/test/ui/generic-associated-types/impl_bounds.stderr @@ -19,8 +19,13 @@ LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ()); error[E0478]: lifetime bound not satisfied --> $DIR/impl_bounds.rs:17:35 | +LL | type B<'a, 'b> where 'a: 'b; + | ---------------------------- definition of `B` from trait +... LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ()); - | ^^^^^^^^^^^^^^^ + | - ^^^^^^^^^^^^^^^ + | | + | help: try copying this clause from the trait: `, 'a: 'b` | note: lifetime parameter instantiated with the lifetime `'a` as defined here --> $DIR/impl_bounds.rs:17:12 diff --git a/src/test/ui/generic-associated-types/issue-74824.rs b/src/test/ui/generic-associated-types/issue-74824.rs index 01f99fa4487..1bbf7aac5cd 100644 --- a/src/test/ui/generic-associated-types/issue-74824.rs +++ b/src/test/ui/generic-associated-types/issue-74824.rs @@ -17,7 +17,6 @@ impl<T> UnsafeCopy for T {} fn main() { let b = Box::new(42usize); let copy = <()>::copy(&b); - //~^ type annotations needed let raw_b = Box::deref(&b) as *const _; let raw_copy = Box::deref(©) as *const _; diff --git a/src/test/ui/generic-associated-types/issue-74824.stderr b/src/test/ui/generic-associated-types/issue-74824.stderr index e7ebf5964ba..8517eb9fa21 100644 --- a/src/test/ui/generic-associated-types/issue-74824.stderr +++ b/src/test/ui/generic-associated-types/issue-74824.stderr @@ -27,13 +27,6 @@ help: consider restricting type parameter `T` LL | type Copy<T: std::clone::Clone>: Copy = Box<T>; | +++++++++++++++++++ -error[E0282]: type annotations needed - --> $DIR/issue-74824.rs:19:16 - | -LL | let copy = <()>::copy(&b); - | ^^^^^^^^^^ cannot infer type for type parameter `T` declared on the associated function `copy` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0277, E0282. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/generic-associated-types/issue-88595.rs b/src/test/ui/generic-associated-types/issue-88595.rs index e397390783f..c97d17811ba 100644 --- a/src/test/ui/generic-associated-types/issue-88595.rs +++ b/src/test/ui/generic-associated-types/issue-88595.rs @@ -8,7 +8,7 @@ trait A<'a> { // FIXME(generic_associated_types): Remove one of the below bounds // https://github.com/rust-lang/rust/pull/90678#discussion_r744976085 where - 'a: 'b, Self: 'a, Self: 'b; + Self: 'a, Self: 'b; fn a(&'a self) -> Self::B<'a>; } @@ -17,8 +17,7 @@ struct C; impl<'a> A<'a> for C { type B<'b> = impl Clone; - //~^ ERROR: lifetime bound not satisfied - //~| ERROR: could not find defining uses + //~^ ERROR: could not find defining uses fn a(&'a self) -> Self::B<'a> {} //~ ERROR: non-defining opaque type use in defining scope } diff --git a/src/test/ui/generic-associated-types/issue-88595.stderr b/src/test/ui/generic-associated-types/issue-88595.stderr index cb462871ccd..4e4f86bbac8 100644 --- a/src/test/ui/generic-associated-types/issue-88595.stderr +++ b/src/test/ui/generic-associated-types/issue-88595.stderr @@ -1,22 +1,5 @@ -error[E0478]: lifetime bound not satisfied - --> $DIR/issue-88595.rs:19:18 - | -LL | type B<'b> = impl Clone; - | ^^^^^^^^^^ - | -note: lifetime parameter instantiated with the lifetime `'a` as defined here - --> $DIR/issue-88595.rs:18:6 - | -LL | impl<'a> A<'a> for C { - | ^^ -note: but lifetime parameter must outlive the lifetime `'b` as defined here - --> $DIR/issue-88595.rs:19:12 - | -LL | type B<'b> = impl Clone; - | ^^ - error: non-defining opaque type use in defining scope - --> $DIR/issue-88595.rs:23:23 + --> $DIR/issue-88595.rs:22:23 | LL | fn a(&'a self) -> Self::B<'a> {} | ^^^^^^^^^^^ @@ -35,6 +18,5 @@ error: could not find defining uses LL | type B<'b> = impl Clone; | ^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0478`. diff --git a/src/test/ui/generic-associated-types/issue-90014.stderr b/src/test/ui/generic-associated-types/issue-90014.stderr index 23e8d08af34..f8fb71bbddb 100644 --- a/src/test/ui/generic-associated-types/issue-90014.stderr +++ b/src/test/ui/generic-associated-types/issue-90014.stderr @@ -1,8 +1,13 @@ error[E0477]: the type `&mut ()` does not fulfill the required lifetime --> $DIR/issue-90014.rs:14:20 | +LL | type Fut<'a> where Self: 'a; + | ---------------------------- definition of `Fut` from trait +... LL | type Fut<'a> = impl Future<Output = ()>; - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | - ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: try copying this clause from the trait: `where Self: 'a` | note: type must outlive the lifetime `'a` as defined here --> $DIR/issue-90014.rs:14:14 diff --git a/src/test/ui/generic-associated-types/issue-92033.rs b/src/test/ui/generic-associated-types/issue-92033.rs new file mode 100644 index 00000000000..1d5f7d5c009 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-92033.rs @@ -0,0 +1,39 @@ +#![feature(generic_associated_types)] + +struct Texture; + +trait Surface { + type TextureIter<'a>: Iterator<Item = &'a Texture> + where + Self: 'a; + + fn get_texture(&self) -> Self::TextureIter<'_>; +} + +trait Swapchain { + type Surface<'a>: Surface + where + Self: 'a; + + fn get_surface(&self) -> Self::Surface<'_>; +} + +impl<'s> Surface for &'s Texture { + type TextureIter<'a> = std::option::IntoIter<&'a Texture>; + //~^ ERROR the type + + fn get_texture(&self) -> Self::TextureIter<'_> { + let option: Option<&Texture> = Some(self); + option.into_iter() + } +} + +impl Swapchain for Texture { + type Surface<'a> = &'a Texture; + + fn get_surface(&self) -> Self::Surface<'_> { + self + } +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/issue-92033.stderr b/src/test/ui/generic-associated-types/issue-92033.stderr new file mode 100644 index 00000000000..caa6618f398 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-92033.stderr @@ -0,0 +1,22 @@ +error[E0477]: the type `&'s Texture` does not fulfill the required lifetime + --> $DIR/issue-92033.rs:22:28 + | +LL | / type TextureIter<'a>: Iterator<Item = &'a Texture> +LL | | where +LL | | Self: 'a; + | |_________________- definition of `TextureIter` from trait +... +LL | type TextureIter<'a> = std::option::IntoIter<&'a Texture>; + | - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: try copying this clause from the trait: `where Self: 'a` + | +note: type must outlive the lifetime `'a` as defined here + --> $DIR/issue-92033.rs:22:22 + | +LL | type TextureIter<'a> = std::option::IntoIter<&'a Texture>; + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0477`. diff --git a/src/test/ui/generic-associated-types/issue-93874.rs b/src/test/ui/generic-associated-types/issue-93874.rs new file mode 100644 index 00000000000..f403d75167d --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-93874.rs @@ -0,0 +1,35 @@ +// check-pass + +#![feature(generic_associated_types)] + +pub trait Build { + type Output<O>; + fn build<O>(self, input: O) -> Self::Output<O>; +} + +pub struct IdentityBuild; +impl Build for IdentityBuild { + type Output<O> = O; + fn build<O>(self, input: O) -> Self::Output<O> { + input + } +} + +fn a() { + let _x: u8 = IdentityBuild.build(10); +} + +fn b() { + let _x: Vec<u8> = IdentityBuild.build(Vec::new()); +} + +fn c() { + let mut f = IdentityBuild.build(|| ()); + (f)(); +} + +pub fn main() { + a(); + b(); + c(); +} diff --git a/src/test/ui/impl-trait/issues/issue-54600.rs b/src/test/ui/impl-trait/issues/issue-54600.rs index 7a647993023..3024fedf7b5 100644 --- a/src/test/ui/impl-trait/issues/issue-54600.rs +++ b/src/test/ui/impl-trait/issues/issue-54600.rs @@ -2,6 +2,6 @@ use std::fmt::Debug; fn main() { let x: Option<impl Debug> = Some(44_u32); - //~^ `impl Trait` not allowed outside of function and method return types + //~^ `impl Trait` only allowed in function and inherent method return types println!("{:?}", x); } diff --git a/src/test/ui/impl-trait/issues/issue-54600.stderr b/src/test/ui/impl-trait/issues/issue-54600.stderr index 4d0c32c6bb7..316566a57a8 100644 --- a/src/test/ui/impl-trait/issues/issue-54600.stderr +++ b/src/test/ui/impl-trait/issues/issue-54600.stderr @@ -1,4 +1,4 @@ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding --> $DIR/issue-54600.rs:4:19 | LL | let x: Option<impl Debug> = Some(44_u32); diff --git a/src/test/ui/impl-trait/issues/issue-54840.rs b/src/test/ui/impl-trait/issues/issue-54840.rs index 030d5715d57..8f1e0ece03a 100644 --- a/src/test/ui/impl-trait/issues/issue-54840.rs +++ b/src/test/ui/impl-trait/issues/issue-54840.rs @@ -3,5 +3,5 @@ use std::ops::Add; fn main() { let i: i32 = 0; let j: &impl Add = &i; - //~^ `impl Trait` not allowed outside of function and method return types + //~^ `impl Trait` only allowed in function and inherent method return types } diff --git a/src/test/ui/impl-trait/issues/issue-54840.stderr b/src/test/ui/impl-trait/issues/issue-54840.stderr index b8046b7482f..8d82133ac90 100644 --- a/src/test/ui/impl-trait/issues/issue-54840.stderr +++ b/src/test/ui/impl-trait/issues/issue-54840.stderr @@ -1,4 +1,4 @@ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding --> $DIR/issue-54840.rs:5:13 | LL | let j: &impl Add = &i; diff --git a/src/test/ui/impl-trait/issues/issue-58504.rs b/src/test/ui/impl-trait/issues/issue-58504.rs index aac33b3b3e5..e5865d0dfff 100644 --- a/src/test/ui/impl-trait/issues/issue-58504.rs +++ b/src/test/ui/impl-trait/issues/issue-58504.rs @@ -8,5 +8,5 @@ fn mk_gen() -> impl Generator<Return=!, Yield=()> { fn main() { let gens: [impl Generator<Return=!, Yield=()>;2] = [ mk_gen(), mk_gen() ]; - //~^ `impl Trait` not allowed outside of function and method return types + //~^ `impl Trait` only allowed in function and inherent method return types } diff --git a/src/test/ui/impl-trait/issues/issue-58504.stderr b/src/test/ui/impl-trait/issues/issue-58504.stderr index ff1010f0661..6656e9fc3fb 100644 --- a/src/test/ui/impl-trait/issues/issue-58504.stderr +++ b/src/test/ui/impl-trait/issues/issue-58504.stderr @@ -1,4 +1,4 @@ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding --> $DIR/issue-58504.rs:10:16 | LL | let gens: [impl Generator<Return=!, Yield=()>;2] = [ mk_gen(), mk_gen() ]; diff --git a/src/test/ui/impl-trait/issues/issue-58956.rs b/src/test/ui/impl-trait/issues/issue-58956.rs index 5fe18b6e9b5..68cfcd9ba4f 100644 --- a/src/test/ui/impl-trait/issues/issue-58956.rs +++ b/src/test/ui/impl-trait/issues/issue-58956.rs @@ -5,9 +5,9 @@ impl Lam for B {} pub struct Wrap<T>(T); const _A: impl Lam = { - //~^ `impl Trait` not allowed outside of function and method return types + //~^ `impl Trait` only allowed in function and inherent method return types let x: Wrap<impl Lam> = Wrap(B); - //~^ `impl Trait` not allowed outside of function and method return types + //~^ `impl Trait` only allowed in function and inherent method return types x.0 }; diff --git a/src/test/ui/impl-trait/issues/issue-58956.stderr b/src/test/ui/impl-trait/issues/issue-58956.stderr index 00ebf170ab2..123fb4df4b3 100644 --- a/src/test/ui/impl-trait/issues/issue-58956.stderr +++ b/src/test/ui/impl-trait/issues/issue-58956.stderr @@ -1,10 +1,10 @@ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type --> $DIR/issue-58956.rs:7:11 | LL | const _A: impl Lam = { | ^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding --> $DIR/issue-58956.rs:9:17 | LL | let x: Wrap<impl Lam> = Wrap(B); diff --git a/src/test/ui/impl-trait/issues/issue-70971.rs b/src/test/ui/impl-trait/issues/issue-70971.rs index d4dc2fd877b..f8ae18bacd6 100644 --- a/src/test/ui/impl-trait/issues/issue-70971.rs +++ b/src/test/ui/impl-trait/issues/issue-70971.rs @@ -1,4 +1,4 @@ fn main() { let x : (impl Copy,) = (true,); - //~^ `impl Trait` not allowed outside of function and method return types + //~^ `impl Trait` only allowed in function and inherent method return types } diff --git a/src/test/ui/impl-trait/issues/issue-70971.stderr b/src/test/ui/impl-trait/issues/issue-70971.stderr index 31993da3e32..4dda4c22aa2 100644 --- a/src/test/ui/impl-trait/issues/issue-70971.stderr +++ b/src/test/ui/impl-trait/issues/issue-70971.stderr @@ -1,4 +1,4 @@ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding --> $DIR/issue-70971.rs:2:14 | LL | let x : (impl Copy,) = (true,); diff --git a/src/test/ui/impl-trait/issues/issue-79099.rs b/src/test/ui/impl-trait/issues/issue-79099.rs index f72533d42e1..da53594f3d0 100644 --- a/src/test/ui/impl-trait/issues/issue-79099.rs +++ b/src/test/ui/impl-trait/issues/issue-79099.rs @@ -1,7 +1,7 @@ struct Bug { V1: [(); { let f: impl core::future::Future<Output = u8> = async { 1 }; - //~^ `impl Trait` not allowed outside of function and method return types + //~^ `impl Trait` only allowed in function and inherent method return types //~| expected identifier 1 }], diff --git a/src/test/ui/impl-trait/issues/issue-79099.stderr b/src/test/ui/impl-trait/issues/issue-79099.stderr index 394b697a250..4c9ec2a83ff 100644 --- a/src/test/ui/impl-trait/issues/issue-79099.stderr +++ b/src/test/ui/impl-trait/issues/issue-79099.stderr @@ -9,7 +9,7 @@ LL | let f: impl core::future::Future<Output = u8> = async { 1 }; = help: set `edition = "2021"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding --> $DIR/issue-79099.rs:3:16 | LL | let f: impl core::future::Future<Output = u8> = async { 1 }; diff --git a/src/test/ui/impl-trait/issues/issue-83929-impl-trait-in-generic-default.rs b/src/test/ui/impl-trait/issues/issue-83929-impl-trait-in-generic-default.rs index 773cd0b81cc..344f359529b 100644 --- a/src/test/ui/impl-trait/issues/issue-83929-impl-trait-in-generic-default.rs +++ b/src/test/ui/impl-trait/issues/issue-83929-impl-trait-in-generic-default.rs @@ -1,8 +1,8 @@ struct Foo<T = impl Copy>(T); -//~^ ERROR `impl Trait` not allowed outside of function and method return types +//~^ ERROR `impl Trait` only allowed in function and inherent method return types type Result<T, E = impl std::error::Error> = std::result::Result<T, E>; -//~^ ERROR `impl Trait` not allowed outside of function and method return types +//~^ ERROR `impl Trait` only allowed in function and inherent method return types // should not cause ICE fn x() -> Foo { diff --git a/src/test/ui/impl-trait/issues/issue-83929-impl-trait-in-generic-default.stderr b/src/test/ui/impl-trait/issues/issue-83929-impl-trait-in-generic-default.stderr index d44dcf1f7fa..e635e554e23 100644 --- a/src/test/ui/impl-trait/issues/issue-83929-impl-trait-in-generic-default.stderr +++ b/src/test/ui/impl-trait/issues/issue-83929-impl-trait-in-generic-default.stderr @@ -1,10 +1,10 @@ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type --> $DIR/issue-83929-impl-trait-in-generic-default.rs:1:16 | LL | struct Foo<T = impl Copy>(T); | ^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type --> $DIR/issue-83929-impl-trait-in-generic-default.rs:4:20 | LL | type Result<T, E = impl std::error::Error> = std::result::Result<T, E>; diff --git a/src/test/ui/impl-trait/issues/issue-84919.rs b/src/test/ui/impl-trait/issues/issue-84919.rs index 479bad97cdf..a0b73743a2b 100644 --- a/src/test/ui/impl-trait/issues/issue-84919.rs +++ b/src/test/ui/impl-trait/issues/issue-84919.rs @@ -3,7 +3,7 @@ impl Trait for () {} fn foo<'a: 'a>() { let _x: impl Trait = (); - //~^ `impl Trait` not allowed outside of function and method return types + //~^ `impl Trait` only allowed in function and inherent method return types } fn main() {} diff --git a/src/test/ui/impl-trait/issues/issue-84919.stderr b/src/test/ui/impl-trait/issues/issue-84919.stderr index bb1bcfefe64..5abe1bd8779 100644 --- a/src/test/ui/impl-trait/issues/issue-84919.stderr +++ b/src/test/ui/impl-trait/issues/issue-84919.stderr @@ -1,4 +1,4 @@ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding --> $DIR/issue-84919.rs:5:13 | LL | let _x: impl Trait = (); diff --git a/src/test/ui/impl-trait/issues/issue-86642.rs b/src/test/ui/impl-trait/issues/issue-86642.rs index 8953ff81581..e6e95771400 100644 --- a/src/test/ui/impl-trait/issues/issue-86642.rs +++ b/src/test/ui/impl-trait/issues/issue-86642.rs @@ -1,5 +1,5 @@ static x: impl Fn(&str) -> Result<&str, ()> = move |source| { - //~^ `impl Trait` not allowed outside of function and method return types + //~^ `impl Trait` only allowed in function and inherent method return types let res = (move |source| Ok(source))(source); let res = res.or((move |source| Ok(source))(source)); res diff --git a/src/test/ui/impl-trait/issues/issue-86642.stderr b/src/test/ui/impl-trait/issues/issue-86642.stderr index 2fc0a6fe1f5..0ec118d5be8 100644 --- a/src/test/ui/impl-trait/issues/issue-86642.stderr +++ b/src/test/ui/impl-trait/issues/issue-86642.stderr @@ -1,4 +1,4 @@ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type --> $DIR/issue-86642.rs:1:11 | LL | static x: impl Fn(&str) -> Result<&str, ()> = move |source| { diff --git a/src/test/ui/impl-trait/issues/issue-87295.rs b/src/test/ui/impl-trait/issues/issue-87295.rs index 2f2bfe147bd..aeb8f83326e 100644 --- a/src/test/ui/impl-trait/issues/issue-87295.rs +++ b/src/test/ui/impl-trait/issues/issue-87295.rs @@ -14,5 +14,5 @@ impl<F> Struct<F> { fn main() { let _do_not_waste: Struct<impl Trait<Output = i32>> = Struct::new(()); - //~^ `impl Trait` not allowed outside of function and method return types + //~^ `impl Trait` only allowed in function and inherent method return types } diff --git a/src/test/ui/impl-trait/issues/issue-87295.stderr b/src/test/ui/impl-trait/issues/issue-87295.stderr index f5c7603ce49..0b043056b84 100644 --- a/src/test/ui/impl-trait/issues/issue-87295.stderr +++ b/src/test/ui/impl-trait/issues/issue-87295.stderr @@ -1,4 +1,4 @@ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding --> $DIR/issue-87295.rs:16:31 | LL | let _do_not_waste: Struct<impl Trait<Output = i32>> = Struct::new(()); diff --git a/src/test/ui/impl-trait/nested_impl_trait.rs b/src/test/ui/impl-trait/nested_impl_trait.rs index be2c21a7743..06a2191a017 100644 --- a/src/test/ui/impl-trait/nested_impl_trait.rs +++ b/src/test/ui/impl-trait/nested_impl_trait.rs @@ -7,7 +7,7 @@ fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x } fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {} //~^ ERROR nested `impl Trait` is not allowed -//~^^ `impl Trait` not allowed +//~| `impl Trait` only allowed in function and inherent method return types fn bad_in_arg_position(_: impl Into<impl Debug>) { } //~^ ERROR nested `impl Trait` is not allowed @@ -23,7 +23,7 @@ fn allowed_in_assoc_type() -> impl Iterator<Item=impl Fn()> { } fn allowed_in_ret_type() -> impl Fn() -> impl Into<u32> { -//~^ `impl Trait` not allowed +//~^ `impl Trait` only allowed in function and inherent method return types || 5 } diff --git a/src/test/ui/impl-trait/nested_impl_trait.stderr b/src/test/ui/impl-trait/nested_impl_trait.stderr index 59c7e4d5f4e..4444e6a454f 100644 --- a/src/test/ui/impl-trait/nested_impl_trait.stderr +++ b/src/test/ui/impl-trait/nested_impl_trait.stderr @@ -34,13 +34,13 @@ LL | fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x } | | nested `impl Trait` here | outer `impl Trait` -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer return --> $DIR/nested_impl_trait.rs:8:32 | LL | fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {} | ^^^^^^^^^^^^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return --> $DIR/nested_impl_trait.rs:25:42 | LL | fn allowed_in_ret_type() -> impl Fn() -> impl Into<u32> { diff --git a/src/test/ui/impl-trait/where-allowed.rs b/src/test/ui/impl-trait/where-allowed.rs index 35fb42d6213..c1dd46c7ff7 100644 --- a/src/test/ui/impl-trait/where-allowed.rs +++ b/src/test/ui/impl-trait/where-allowed.rs @@ -13,61 +13,61 @@ fn in_adt_in_parameters(_: Vec<impl Debug>) { panic!() } // Disallowed fn in_fn_parameter_in_parameters(_: fn(impl Debug)) { panic!() } -//~^ ERROR `impl Trait` not allowed outside of function and method return types +//~^ ERROR `impl Trait` only allowed in function and inherent method return types // Disallowed fn in_fn_return_in_parameters(_: fn() -> impl Debug) { panic!() } -//~^ ERROR `impl Trait` not allowed outside of function and method return types +//~^ ERROR `impl Trait` only allowed in function and inherent method return types // Disallowed fn in_fn_parameter_in_return() -> fn(impl Debug) { panic!() } -//~^ ERROR `impl Trait` not allowed outside of function and method return types +//~^ ERROR `impl Trait` only allowed in function and inherent method return types // Disallowed fn in_fn_return_in_return() -> fn() -> impl Debug { panic!() } -//~^ ERROR `impl Trait` not allowed outside of function and method return types +//~^ ERROR `impl Trait` only allowed in function and inherent method return types // Disallowed fn in_dyn_Fn_parameter_in_parameters(_: &dyn Fn(impl Debug)) { panic!() } -//~^ ERROR `impl Trait` not allowed outside of function and method return types +//~^ ERROR `impl Trait` only allowed in function and inherent method return types // Disallowed fn in_dyn_Fn_return_in_parameters(_: &dyn Fn() -> impl Debug) { panic!() } -//~^ ERROR `impl Trait` not allowed outside of function and method return types +//~^ ERROR `impl Trait` only allowed in function and inherent method return types // Disallowed fn in_dyn_Fn_parameter_in_return() -> &'static dyn Fn(impl Debug) { panic!() } -//~^ ERROR `impl Trait` not allowed outside of function and method return types +//~^ ERROR `impl Trait` only allowed in function and inherent method return types // Disallowed fn in_dyn_Fn_return_in_return() -> &'static dyn Fn() -> impl Debug { panic!() } -//~^ ERROR `impl Trait` not allowed outside of function and method return types +//~^ ERROR `impl Trait` only allowed in function and inherent method return types // Disallowed fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() } -//~^ ERROR `impl Trait` not allowed outside of function and method return types +//~^ ERROR `impl Trait` only allowed in function and inherent method return types //~^^ ERROR nested `impl Trait` is not allowed // Disallowed fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() } -//~^ ERROR `impl Trait` not allowed outside of function and method return types +//~^ ERROR `impl Trait` only allowed in function and inherent method return types // Disallowed fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } -//~^ ERROR `impl Trait` not allowed outside of function and method return types +//~^ ERROR `impl Trait` only allowed in function and inherent method return types //~| ERROR nested `impl Trait` is not allowed // Disallowed fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() } -//~^ ERROR `impl Trait` not allowed outside of function and method return types +//~^ ERROR `impl Trait` only allowed in function and inherent method return types // Disallowed fn in_Fn_parameter_in_generics<F: Fn(impl Debug)> (_: F) { panic!() } -//~^ ERROR `impl Trait` not allowed outside of function and method return types +//~^ ERROR `impl Trait` only allowed in function and inherent method return types // Disallowed fn in_Fn_return_in_generics<F: Fn() -> impl Debug> (_: F) { panic!() } -//~^ ERROR `impl Trait` not allowed outside of function and method return types +//~^ ERROR `impl Trait` only allowed in function and inherent method return types // Allowed @@ -80,22 +80,22 @@ fn in_impl_Trait_in_return() -> impl IntoIterator<Item = impl IntoIterator> { // Disallowed struct InBraceStructField { x: impl Debug } -//~^ ERROR `impl Trait` not allowed outside of function and method return types +//~^ ERROR `impl Trait` only allowed in function and inherent method return types // Disallowed struct InAdtInBraceStructField { x: Vec<impl Debug> } -//~^ ERROR `impl Trait` not allowed outside of function and method return types +//~^ ERROR `impl Trait` only allowed in function and inherent method return types // Disallowed struct InTupleStructField(impl Debug); -//~^ ERROR `impl Trait` not allowed outside of function and method return types +//~^ ERROR `impl Trait` only allowed in function and inherent method return types // Disallowed enum InEnum { InBraceVariant { x: impl Debug }, - //~^ ERROR `impl Trait` not allowed outside of function and method return types + //~^ ERROR `impl Trait` only allowed in function and inherent method return types InTupleVariant(impl Debug), - //~^ ERROR `impl Trait` not allowed outside of function and method return types + //~^ ERROR `impl Trait` only allowed in function and inherent method return types } // Allowed @@ -106,7 +106,7 @@ trait InTraitDefnParameters { // Disallowed trait InTraitDefnReturn { fn in_return() -> impl Debug; - //~^ ERROR `impl Trait` not allowed outside of function and method return types + //~^ ERROR `impl Trait` only allowed in function and inherent method return types } // Allowed and disallowed in trait impls @@ -123,7 +123,7 @@ impl DummyTrait for () { // Allowed fn in_trait_impl_return() -> impl Debug { () } - //~^ ERROR `impl Trait` not allowed outside of function and method return types + //~^ ERROR `impl Trait` only allowed in function and inherent method return types } // Allowed @@ -136,10 +136,10 @@ impl DummyType { // Disallowed extern "C" { fn in_foreign_parameters(_: impl Debug); - //~^ ERROR `impl Trait` not allowed outside of function and method return types + //~^ ERROR `impl Trait` only allowed in function and inherent method return types fn in_foreign_return() -> impl Debug; - //~^ ERROR `impl Trait` not allowed outside of function and method return types + //~^ ERROR `impl Trait` only allowed in function and inherent method return types } // Allowed @@ -155,97 +155,97 @@ type InTypeAlias<R> = impl Debug; //~^ ERROR `impl Trait` in type aliases is unstable type InReturnInTypeAlias<R> = fn() -> impl Debug; -//~^ ERROR `impl Trait` not allowed outside of function and method return types +//~^ ERROR `impl Trait` only allowed in function and inherent method return types //~| ERROR `impl Trait` in type aliases is unstable // Disallowed in impl headers impl PartialEq<impl Debug> for () { - //~^ ERROR `impl Trait` not allowed outside of function and method return types + //~^ ERROR `impl Trait` only allowed in function and inherent method return types } // Disallowed in impl headers impl PartialEq<()> for impl Debug { - //~^ ERROR `impl Trait` not allowed outside of function and method return types + //~^ ERROR `impl Trait` only allowed in function and inherent method return types } // Disallowed in inherent impls impl impl Debug { - //~^ ERROR `impl Trait` not allowed outside of function and method return types + //~^ ERROR `impl Trait` only allowed in function and inherent method return types } // Disallowed in inherent impls struct InInherentImplAdt<T> { t: T } impl InInherentImplAdt<impl Debug> { - //~^ ERROR `impl Trait` not allowed outside of function and method return types + //~^ ERROR `impl Trait` only allowed in function and inherent method return types } // Disallowed in where clauses fn in_fn_where_clause() where impl Debug: Debug -//~^ ERROR `impl Trait` not allowed outside of function and method return types +//~^ ERROR `impl Trait` only allowed in function and inherent method return types { } // Disallowed in where clauses fn in_adt_in_fn_where_clause() where Vec<impl Debug>: Debug -//~^ ERROR `impl Trait` not allowed outside of function and method return types +//~^ ERROR `impl Trait` only allowed in function and inherent method return types { } // Disallowed fn in_trait_parameter_in_fn_where_clause<T>() where T: PartialEq<impl Debug> -//~^ ERROR `impl Trait` not allowed outside of function and method return types +//~^ ERROR `impl Trait` only allowed in function and inherent method return types { } // Disallowed fn in_Fn_parameter_in_fn_where_clause<T>() where T: Fn(impl Debug) -//~^ ERROR `impl Trait` not allowed outside of function and method return types +//~^ ERROR `impl Trait` only allowed in function and inherent method return types { } // Disallowed fn in_Fn_return_in_fn_where_clause<T>() where T: Fn() -> impl Debug -//~^ ERROR `impl Trait` not allowed outside of function and method return types +//~^ ERROR `impl Trait` only allowed in function and inherent method return types { } // Disallowed struct InStructGenericParamDefault<T = impl Debug>(T); -//~^ ERROR `impl Trait` not allowed outside of function and method return types +//~^ ERROR `impl Trait` only allowed in function and inherent method return types // Disallowed enum InEnumGenericParamDefault<T = impl Debug> { Variant(T) } -//~^ ERROR `impl Trait` not allowed outside of function and method return types +//~^ ERROR `impl Trait` only allowed in function and inherent method return types // Disallowed trait InTraitGenericParamDefault<T = impl Debug> {} -//~^ ERROR `impl Trait` not allowed outside of function and method return types +//~^ ERROR `impl Trait` only allowed in function and inherent method return types // Disallowed type InTypeAliasGenericParamDefault<T = impl Debug> = T; -//~^ ERROR `impl Trait` not allowed outside of function and method return types +//~^ ERROR `impl Trait` only allowed in function and inherent method return types // Disallowed impl <T = impl Debug> T {} //~^ ERROR defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions //~| WARNING this was previously accepted by the compiler but is being phased out -//~| ERROR `impl Trait` not allowed outside of function and method return types +//~| ERROR `impl Trait` only allowed in function and inherent method return types //~| ERROR no nominal type found // Disallowed fn in_method_generic_param_default<T = impl Debug>(_: T) {} //~^ ERROR defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions //~| WARNING this was previously accepted by the compiler but is being phased out -//~| ERROR `impl Trait` not allowed outside of function and method return types +//~| ERROR `impl Trait` only allowed in function and inherent method return types fn main() { let _in_local_variable: impl Fn() = || {}; - //~^ ERROR `impl Trait` not allowed outside of function and method return types + //~^ ERROR `impl Trait` only allowed in function and inherent method return types let _in_return_in_local_variable = || -> impl Fn() { || {} }; - //~^ ERROR `impl Trait` not allowed outside of function and method return types + //~^ ERROR `impl Trait` only allowed in function and inherent method return types } diff --git a/src/test/ui/impl-trait/where-allowed.stderr b/src/test/ui/impl-trait/where-allowed.stderr index 236cf449e85..eef20c2de94 100644 --- a/src/test/ui/impl-trait/where-allowed.stderr +++ b/src/test/ui/impl-trait/where-allowed.stderr @@ -43,247 +43,247 @@ LL | type InReturnInTypeAlias<R> = fn() -> impl Debug; = note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer param --> $DIR/where-allowed.rs:15:40 | LL | fn in_fn_parameter_in_parameters(_: fn(impl Debug)) { panic!() } | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer return --> $DIR/where-allowed.rs:19:42 | LL | fn in_fn_return_in_parameters(_: fn() -> impl Debug) { panic!() } | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer param --> $DIR/where-allowed.rs:23:38 | LL | fn in_fn_parameter_in_return() -> fn(impl Debug) { panic!() } | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer return --> $DIR/where-allowed.rs:27:40 | LL | fn in_fn_return_in_return() -> fn() -> impl Debug { panic!() } | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait param --> $DIR/where-allowed.rs:31:49 | LL | fn in_dyn_Fn_parameter_in_parameters(_: &dyn Fn(impl Debug)) { panic!() } | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return --> $DIR/where-allowed.rs:35:51 | LL | fn in_dyn_Fn_return_in_parameters(_: &dyn Fn() -> impl Debug) { panic!() } | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait param --> $DIR/where-allowed.rs:39:55 | LL | fn in_dyn_Fn_parameter_in_return() -> &'static dyn Fn(impl Debug) { panic!() } | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return --> $DIR/where-allowed.rs:43:57 | LL | fn in_dyn_Fn_return_in_return() -> &'static dyn Fn() -> impl Debug { panic!() } | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait param --> $DIR/where-allowed.rs:47:51 | LL | fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() } | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return --> $DIR/where-allowed.rs:52:53 | LL | fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() } | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait param --> $DIR/where-allowed.rs:56:57 | LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return --> $DIR/where-allowed.rs:61:59 | LL | fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() } | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait param --> $DIR/where-allowed.rs:65:38 | LL | fn in_Fn_parameter_in_generics<F: Fn(impl Debug)> (_: F) { panic!() } | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return --> $DIR/where-allowed.rs:69:40 | LL | fn in_Fn_return_in_generics<F: Fn() -> impl Debug> (_: F) { panic!() } | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type --> $DIR/where-allowed.rs:82:32 | LL | struct InBraceStructField { x: impl Debug } | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in path --> $DIR/where-allowed.rs:86:41 | LL | struct InAdtInBraceStructField { x: Vec<impl Debug> } | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type --> $DIR/where-allowed.rs:90:27 | LL | struct InTupleStructField(impl Debug); | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type --> $DIR/where-allowed.rs:95:25 | LL | InBraceVariant { x: impl Debug }, | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type --> $DIR/where-allowed.rs:97:20 | LL | InTupleVariant(impl Debug), | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in trait method return --> $DIR/where-allowed.rs:108:23 | LL | fn in_return() -> impl Debug; | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `impl` method return --> $DIR/where-allowed.rs:125:34 | LL | fn in_trait_impl_return() -> impl Debug { () } | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `extern fn` param --> $DIR/where-allowed.rs:138:33 | LL | fn in_foreign_parameters(_: impl Debug); | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `extern fn` return --> $DIR/where-allowed.rs:141:31 | LL | fn in_foreign_return() -> impl Debug; | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer return --> $DIR/where-allowed.rs:157:39 | LL | type InReturnInTypeAlias<R> = fn() -> impl Debug; | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in trait --> $DIR/where-allowed.rs:162:16 | LL | impl PartialEq<impl Debug> for () { | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type --> $DIR/where-allowed.rs:167:24 | LL | impl PartialEq<()> for impl Debug { | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type --> $DIR/where-allowed.rs:172:6 | LL | impl impl Debug { | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type --> $DIR/where-allowed.rs:178:24 | LL | impl InInherentImplAdt<impl Debug> { | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type --> $DIR/where-allowed.rs:184:11 | LL | where impl Debug: Debug | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type --> $DIR/where-allowed.rs:191:15 | LL | where Vec<impl Debug>: Debug | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in bound --> $DIR/where-allowed.rs:198:24 | LL | where T: PartialEq<impl Debug> | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait param --> $DIR/where-allowed.rs:205:17 | LL | where T: Fn(impl Debug) | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return --> $DIR/where-allowed.rs:212:22 | LL | where T: Fn() -> impl Debug | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type --> $DIR/where-allowed.rs:218:40 | LL | struct InStructGenericParamDefault<T = impl Debug>(T); | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type --> $DIR/where-allowed.rs:222:36 | LL | enum InEnumGenericParamDefault<T = impl Debug> { Variant(T) } | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type --> $DIR/where-allowed.rs:226:38 | LL | trait InTraitGenericParamDefault<T = impl Debug> {} | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type --> $DIR/where-allowed.rs:230:41 | LL | type InTypeAliasGenericParamDefault<T = impl Debug> = T; | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type --> $DIR/where-allowed.rs:234:11 | LL | impl <T = impl Debug> T {} | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type --> $DIR/where-allowed.rs:241:40 | LL | fn in_method_generic_param_default<T = impl Debug>(_: T) {} | ^^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding --> $DIR/where-allowed.rs:247:29 | LL | let _in_local_variable: impl Fn() = || {}; | ^^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in closure return --> $DIR/where-allowed.rs:249:46 | LL | let _in_return_in_local_variable = || -> impl Fn() { || {} }; diff --git a/src/test/ui/invalid/invalid-no-sanitize.stderr b/src/test/ui/invalid/invalid-no-sanitize.stderr index 4c0b17c7d37..5a92555eb32 100644 --- a/src/test/ui/invalid/invalid-no-sanitize.stderr +++ b/src/test/ui/invalid/invalid-no-sanitize.stderr @@ -4,7 +4,7 @@ error: invalid argument for `no_sanitize` LL | #[no_sanitize(brontosaurus)] | ^^^^^^^^^^^^ | - = note: expected one of: `address`, `hwaddress`, `memory` or `thread` + = note: expected one of: `address`, `cfi`, `hwaddress`, `memory`, `memtag`, or `thread` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-13497-2.rs b/src/test/ui/issues/issue-13497-2.rs index 32abe2b8543..c82da0f0096 100644 --- a/src/test/ui/issues/issue-13497-2.rs +++ b/src/test/ui/issues/issue-13497-2.rs @@ -1,7 +1,7 @@ fn read_lines_borrowed<'a>() -> Vec<&'a str> { let rawLines: Vec<String> = vec!["foo ".to_string(), " bar".to_string()]; - rawLines.iter().map(|l| l.trim()).collect() - //~^ ERROR cannot return value referencing local variable `rawLines` + rawLines //~ ERROR cannot return value referencing local variable `rawLines` + .iter().map(|l| l.trim()).collect() } fn main() {} diff --git a/src/test/ui/issues/issue-13497-2.stderr b/src/test/ui/issues/issue-13497-2.stderr index 1b78e7ec1c6..6f72b79f2a5 100644 --- a/src/test/ui/issues/issue-13497-2.stderr +++ b/src/test/ui/issues/issue-13497-2.stderr @@ -1,10 +1,14 @@ error[E0515]: cannot return value referencing local variable `rawLines` - --> $DIR/issue-13497-2.rs:3:29 + --> $DIR/issue-13497-2.rs:3:5 | -LL | rawLines.iter().map(|l| l.trim()).collect() - | --------------- ^^^^^^^^ returns a value referencing data owned by the current function - | | - | `rawLines` is borrowed here +LL | rawLines + | _____^ + | |_____| + | || +LL | || .iter().map(|l| l.trim()).collect() + | ||_______________-___________________________^ returns a value referencing data owned by the current function + | |________________| + | `rawLines` is borrowed here error: aborting due to previous error diff --git a/src/test/ui/issues/issue-14772.rs b/src/test/ui/issues/issue-14772.rs deleted file mode 100644 index 8f6745246fd..00000000000 --- a/src/test/ui/issues/issue-14772.rs +++ /dev/null @@ -1,6 +0,0 @@ -// compile-flags: --test - -#[test] -mod foo {} //~ ERROR only functions may be used as tests - -fn main() {} diff --git a/src/test/ui/issues/issue-14772.stderr b/src/test/ui/issues/issue-14772.stderr deleted file mode 100644 index 253fec5e578..00000000000 --- a/src/test/ui/issues/issue-14772.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: only functions may be used as tests - --> $DIR/issue-14772.rs:4:1 - | -LL | mod foo {} - | ^^^^^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/issues/issue-47715.rs b/src/test/ui/issues/issue-47715.rs index 478ac6a2e89..b8088c18dad 100644 --- a/src/test/ui/issues/issue-47715.rs +++ b/src/test/ui/issues/issue-47715.rs @@ -7,22 +7,22 @@ trait Iterable { } struct Container<T: Iterable<Item = impl Foo>> { - //~^ ERROR `impl Trait` not allowed + //~^ ERROR `impl Trait` only allowed in function and inherent method return types field: T } enum Enum<T: Iterable<Item = impl Foo>> { - //~^ ERROR `impl Trait` not allowed + //~^ ERROR `impl Trait` only allowed in function and inherent method return types A(T), } union Union<T: Iterable<Item = impl Foo> + Copy> { - //~^ ERROR `impl Trait` not allowed + //~^ ERROR `impl Trait` only allowed in function and inherent method return types x: T, } type Type<T: Iterable<Item = impl Foo>> = T; -//~^ ERROR `impl Trait` not allowed +//~^ ERROR `impl Trait` only allowed in function and inherent method return types fn main() { } diff --git a/src/test/ui/issues/issue-47715.stderr b/src/test/ui/issues/issue-47715.stderr index 63a28d997e1..0ee9388bf2b 100644 --- a/src/test/ui/issues/issue-47715.stderr +++ b/src/test/ui/issues/issue-47715.stderr @@ -1,22 +1,22 @@ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in generic --> $DIR/issue-47715.rs:9:37 | LL | struct Container<T: Iterable<Item = impl Foo>> { | ^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in generic --> $DIR/issue-47715.rs:14:30 | LL | enum Enum<T: Iterable<Item = impl Foo>> { | ^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in generic --> $DIR/issue-47715.rs:19:32 | LL | union Union<T: Iterable<Item = impl Foo> + Copy> { | ^^^^^^^^ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in generic --> $DIR/issue-47715.rs:24:30 | LL | type Type<T: Iterable<Item = impl Foo>> = T; diff --git a/src/test/ui/issues/issue-68696-catch-during-unwind.rs b/src/test/ui/issues/issue-68696-catch-during-unwind.rs index f25a78f59cd..2b12a62d0eb 100644 --- a/src/test/ui/issues/issue-68696-catch-during-unwind.rs +++ b/src/test/ui/issues/issue-68696-catch-during-unwind.rs @@ -4,7 +4,6 @@ // entering the catch_unwind. // // run-pass -#![feature(cfg_panic)] use std::panic::catch_unwind; diff --git a/src/test/ui/return/return-impl-trait-bad.rs b/src/test/ui/return/return-impl-trait-bad.rs new file mode 100644 index 00000000000..e3f6ddb9a14 --- /dev/null +++ b/src/test/ui/return/return-impl-trait-bad.rs @@ -0,0 +1,31 @@ +trait Trait {} +impl Trait for () {} + +fn bad_echo<T>(_t: T) -> T { + "this should not suggest impl Trait" //~ ERROR mismatched types +} + +fn bad_echo_2<T: Trait>(_t: T) -> T { + "this will not suggest it, because that would probably be wrong" //~ ERROR mismatched types +} + +fn other_bounds_bad<T>() -> T +where + T: Send, + Option<T>: Send, +{ + "don't suggest this, because Option<T> places additional constraints" //~ ERROR mismatched types +} + +// FIXME: implement this check +trait GenericTrait<T> {} + +fn used_in_trait<T>() -> T +where + T: Send, + (): GenericTrait<T>, +{ + "don't suggest this, because the generic param is used in the bound." //~ ERROR mismatched types +} + +fn main() {} diff --git a/src/test/ui/return/return-impl-trait-bad.stderr b/src/test/ui/return/return-impl-trait-bad.stderr new file mode 100644 index 00000000000..237b85ee66a --- /dev/null +++ b/src/test/ui/return/return-impl-trait-bad.stderr @@ -0,0 +1,59 @@ +error[E0308]: mismatched types + --> $DIR/return-impl-trait-bad.rs:5:5 + | +LL | fn bad_echo<T>(_t: T) -> T { + | - - expected `T` because of return type + | | + | this type parameter +LL | "this should not suggest impl Trait" + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `T`, found `&str` + | + = note: expected type parameter `T` + found reference `&'static str` + +error[E0308]: mismatched types + --> $DIR/return-impl-trait-bad.rs:9:5 + | +LL | fn bad_echo_2<T: Trait>(_t: T) -> T { + | - - expected `T` because of return type + | | + | this type parameter +LL | "this will not suggest it, because that would probably be wrong" + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `T`, found `&str` + | + = note: expected type parameter `T` + found reference `&'static str` + +error[E0308]: mismatched types + --> $DIR/return-impl-trait-bad.rs:17:5 + | +LL | fn other_bounds_bad<T>() -> T + | - - expected `T` because of return type + | | + | this type parameter +... +LL | "don't suggest this, because Option<T> places additional constraints" + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `T`, found `&str` + | + = note: expected type parameter `T` + found reference `&'static str` + +error[E0308]: mismatched types + --> $DIR/return-impl-trait-bad.rs:28:5 + | +LL | fn used_in_trait<T>() -> T + | - - + | | | + | | expected `T` because of return type + | | help: consider using an impl return type: `impl Send` + | this type parameter +... +LL | "don't suggest this, because the generic param is used in the bound." + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `T`, found `&str` + | + = note: expected type parameter `T` + found reference `&'static str` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/return/return-impl-trait.fixed b/src/test/ui/return/return-impl-trait.fixed new file mode 100644 index 00000000000..ff2b02f73ea --- /dev/null +++ b/src/test/ui/return/return-impl-trait.fixed @@ -0,0 +1,30 @@ +// run-rustfix + +trait Trait {} +impl Trait for () {} + +// this works +fn foo() -> impl Trait { + () +} + +fn bar<T: Trait + std::marker::Sync>() -> impl Trait + std::marker::Sync + Send +where + T: Send, +{ + () //~ ERROR mismatched types +} + +fn other_bounds<T>() -> impl Trait +where + T: Trait, + Vec<usize>: Clone, +{ + () //~ ERROR mismatched types +} + +fn main() { + foo(); + bar::<()>(); + other_bounds::<()>(); +} diff --git a/src/test/ui/return/return-impl-trait.rs b/src/test/ui/return/return-impl-trait.rs new file mode 100644 index 00000000000..e905d712f62 --- /dev/null +++ b/src/test/ui/return/return-impl-trait.rs @@ -0,0 +1,30 @@ +// run-rustfix + +trait Trait {} +impl Trait for () {} + +// this works +fn foo() -> impl Trait { + () +} + +fn bar<T: Trait + std::marker::Sync>() -> T +where + T: Send, +{ + () //~ ERROR mismatched types +} + +fn other_bounds<T>() -> T +where + T: Trait, + Vec<usize>: Clone, +{ + () //~ ERROR mismatched types +} + +fn main() { + foo(); + bar::<()>(); + other_bounds::<()>(); +} diff --git a/src/test/ui/return/return-impl-trait.stderr b/src/test/ui/return/return-impl-trait.stderr new file mode 100644 index 00000000000..43d40972fca --- /dev/null +++ b/src/test/ui/return/return-impl-trait.stderr @@ -0,0 +1,34 @@ +error[E0308]: mismatched types + --> $DIR/return-impl-trait.rs:15:5 + | +LL | fn bar<T: Trait + std::marker::Sync>() -> T + | - - + | | | + | | expected `T` because of return type + | this type parameter help: consider using an impl return type: `impl Trait + std::marker::Sync + Send` +... +LL | () + | ^^ expected type parameter `T`, found `()` + | + = note: expected type parameter `T` + found unit type `()` + +error[E0308]: mismatched types + --> $DIR/return-impl-trait.rs:23:5 + | +LL | fn other_bounds<T>() -> T + | - - + | | | + | | expected `T` because of return type + | | help: consider using an impl return type: `impl Trait` + | this type parameter +... +LL | () + | ^^ expected type parameter `T`, found `()` + | + = note: expected type parameter `T` + found unit type `()` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.nll.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.nll.stderr index aaed3665149..57374b7e3bb 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.nll.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.nll.stderr @@ -20,8 +20,9 @@ error: lifetime may not live long enough --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:17:64 | LL | async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg } - | -- ---- has type `Pin<&'1 Foo>` ^^^ associated function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a` - | | + | -- - ^^^ associated function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a` + | | | + | | let's call the lifetime of this reference `'1` | lifetime `'a` defined here error: aborting due to 3 previous errors diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr index 042ae53dba1..299a2d2f2d3 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr @@ -2,25 +2,25 @@ error[E0623]: lifetime mismatch --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:8:52 | LL | async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f } - | ---- ---- ^ ...but data from `f` flows into `self` here + | ---- ---- ^ ...but data from `f` is returned here | | - | these two types are declared with different lifetimes... + | this parameter and the return type are declared with different lifetimes... error[E0623]: lifetime mismatch --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:11:82 | LL | async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) } - | ----- ---- ^ ...but data from `f` flows into `self` here + | ---- ----------------- ^ ...but data from `f` is returned here | | - | these two types are declared with different lifetimes... + | this parameter and the return type are declared with different lifetimes... error[E0623]: lifetime mismatch --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:17:64 | LL | async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg } - | ----- ------ ^^^ ...but data from `arg` flows into `self` here + | ------ --- ^^^ ...but data from `arg` is returned here | | - | these two types are declared with different lifetimes... + | this parameter and the return type are declared with different lifetimes... error: aborting due to 3 previous errors diff --git a/src/test/ui/self/elision/lt-ref-self-async.stderr b/src/test/ui/self/elision/lt-ref-self-async.stderr index ae484670213..7448e8484b4 100644 --- a/src/test/ui/self/elision/lt-ref-self-async.stderr +++ b/src/test/ui/self/elision/lt-ref-self-async.stderr @@ -2,49 +2,61 @@ error[E0623]: lifetime mismatch --> $DIR/lt-ref-self-async.rs:13:9 | LL | async fn ref_self(&self, f: &u32) -> &u32 { - | ----- ---- these two types are declared with different lifetimes... + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` flows into `self` here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/lt-ref-self-async.rs:19:9 | LL | async fn ref_Self(self: &Self, f: &u32) -> &u32 { - | ----- ---- these two types are declared with different lifetimes... + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` flows into `self` here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/lt-ref-self-async.rs:23:9 | LL | async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 { - | ----- ---- these two types are declared with different lifetimes... + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` flows into `self` here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/lt-ref-self-async.rs:27:9 | LL | async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 { - | ----- ---- these two types are declared with different lifetimes... + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` flows into `self` here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/lt-ref-self-async.rs:31:9 | LL | async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 { - | ----- ---- these two types are declared with different lifetimes... + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` flows into `self` here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/lt-ref-self-async.rs:35:9 | LL | async fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 { - | ----- ---- these two types are declared with different lifetimes... + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` flows into `self` here + | ^ ...but data from `f` is returned here error: aborting due to 6 previous errors diff --git a/src/test/ui/self/elision/ref-mut-self-async.stderr b/src/test/ui/self/elision/ref-mut-self-async.stderr index 7b984b343d6..6056cc46d3d 100644 --- a/src/test/ui/self/elision/ref-mut-self-async.stderr +++ b/src/test/ui/self/elision/ref-mut-self-async.stderr @@ -2,49 +2,61 @@ error[E0623]: lifetime mismatch --> $DIR/ref-mut-self-async.rs:13:9 | LL | async fn ref_self(&mut self, f: &u32) -> &u32 { - | --------- ---- these two types are declared with different lifetimes... + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` flows into `self` here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-mut-self-async.rs:19:9 | LL | async fn ref_Self(self: &mut Self, f: &u32) -> &u32 { - | --------- ---- these two types are declared with different lifetimes... + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` flows into `self` here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-mut-self-async.rs:23:9 | LL | async fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 { - | --------- ---- these two types are declared with different lifetimes... + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` flows into `self` here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-mut-self-async.rs:27:9 | LL | async fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 { - | --------- ---- these two types are declared with different lifetimes... + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` flows into `self` here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-mut-self-async.rs:31:9 | LL | async fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 { - | --------- ---- these two types are declared with different lifetimes... + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` flows into `self` here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-mut-self-async.rs:35:9 | LL | async fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 { - | --------- ---- these two types are declared with different lifetimes... + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` flows into `self` here + | ^ ...but data from `f` is returned here error: aborting due to 6 previous errors diff --git a/src/test/ui/self/elision/ref-mut-struct-async.stderr b/src/test/ui/self/elision/ref-mut-struct-async.stderr index 87a144f62f6..61034ae4d47 100644 --- a/src/test/ui/self/elision/ref-mut-struct-async.stderr +++ b/src/test/ui/self/elision/ref-mut-struct-async.stderr @@ -2,41 +2,51 @@ error[E0623]: lifetime mismatch --> $DIR/ref-mut-struct-async.rs:13:9 | LL | async fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 { - | ----------- ---- these two types are declared with different lifetimes... + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` flows into `self` here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-mut-struct-async.rs:17:9 | LL | async fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 { - | ----------- ---- these two types are declared with different lifetimes... + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` flows into `self` here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-mut-struct-async.rs:21:9 | LL | async fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 { - | ----------- ---- these two types are declared with different lifetimes... + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` flows into `self` here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-mut-struct-async.rs:25:9 | LL | async fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 { - | ----------- ---- these two types are declared with different lifetimes... + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` flows into `self` here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-mut-struct-async.rs:29:9 | LL | async fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 { - | ----------- ---- these two types are declared with different lifetimes... + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` flows into `self` here + | ^ ...but data from `f` is returned here error: aborting due to 5 previous errors diff --git a/src/test/ui/self/elision/ref-self-async.stderr b/src/test/ui/self/elision/ref-self-async.stderr index 15c20c1bc4d..0eab16e685d 100644 --- a/src/test/ui/self/elision/ref-self-async.stderr +++ b/src/test/ui/self/elision/ref-self-async.stderr @@ -2,57 +2,71 @@ error[E0623]: lifetime mismatch --> $DIR/ref-self-async.rs:23:9 | LL | async fn ref_self(&self, f: &u32) -> &u32 { - | ----- ---- these two types are declared with different lifetimes... + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` flows into `self` here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-self-async.rs:29:9 | LL | async fn ref_Self(self: &Self, f: &u32) -> &u32 { - | ----- ---- these two types are declared with different lifetimes... + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` flows into `self` here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-self-async.rs:33:9 | LL | async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 { - | ----- ---- these two types are declared with different lifetimes... + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` flows into `self` here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-self-async.rs:37:9 | LL | async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 { - | ----- ---- these two types are declared with different lifetimes... + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` flows into `self` here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-self-async.rs:41:9 | LL | async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 { - | ----- ---- these two types are declared with different lifetimes... + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` flows into `self` here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-self-async.rs:45:9 | LL | async fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 { - | ----- ---- these two types are declared with different lifetimes... + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` flows into `self` here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-self-async.rs:49:9 | LL | async fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 { - | ----- --- these two types are declared with different lifetimes... + | --- --- + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` flows into `self` here + | ^ ...but data from `f` is returned here error: aborting due to 7 previous errors diff --git a/src/test/ui/self/elision/ref-struct-async.stderr b/src/test/ui/self/elision/ref-struct-async.stderr index f24be3b58a7..aa1d7453e83 100644 --- a/src/test/ui/self/elision/ref-struct-async.stderr +++ b/src/test/ui/self/elision/ref-struct-async.stderr @@ -2,41 +2,51 @@ error[E0623]: lifetime mismatch --> $DIR/ref-struct-async.rs:13:9 | LL | async fn ref_Struct(self: &Struct, f: &u32) -> &u32 { - | ------- ---- these two types are declared with different lifetimes... + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` flows into `self` here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-struct-async.rs:17:9 | LL | async fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 { - | ------- ---- these two types are declared with different lifetimes... + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` flows into `self` here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-struct-async.rs:21:9 | LL | async fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 { - | ------- ---- these two types are declared with different lifetimes... + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` flows into `self` here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-struct-async.rs:25:9 | LL | async fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 { - | ------- ---- these two types are declared with different lifetimes... + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` flows into `self` here + | ^ ...but data from `f` is returned here error[E0623]: lifetime mismatch --> $DIR/ref-struct-async.rs:29:9 | LL | async fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 { - | ------- ---- these two types are declared with different lifetimes... + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... LL | f - | ^ ...but data from `f` flows into `self` here + | ^ ...but data from `f` is returned here error: aborting due to 5 previous errors diff --git a/src/test/ui/test-attrs/test-on-macro.rs b/src/test/ui/test-attrs/test-on-macro.rs deleted file mode 100644 index 0667364d13c..00000000000 --- a/src/test/ui/test-attrs/test-on-macro.rs +++ /dev/null @@ -1,13 +0,0 @@ -// check-pass -// compile-flags:--test - -#![deny(warnings)] - -macro_rules! foo { - () => (fn foo(){}) -} - -#[test] -foo!(); //~ WARNING `#[test]` attribute should not be used on macros - -fn main(){} diff --git a/src/test/ui/test-attrs/test-on-macro.stderr b/src/test/ui/test-attrs/test-on-macro.stderr deleted file mode 100644 index 98190b060ce..00000000000 --- a/src/test/ui/test-attrs/test-on-macro.stderr +++ /dev/null @@ -1,8 +0,0 @@ -warning: `#[test]` attribute should not be used on macros. Use `#[cfg(test)]` instead. - --> $DIR/test-on-macro.rs:11:1 - | -LL | foo!(); - | ^^^^^^^ - -warning: 1 warning emitted - diff --git a/src/test/ui/test-attrs/test-on-not-fn.rs b/src/test/ui/test-attrs/test-on-not-fn.rs new file mode 100644 index 00000000000..b2f681c01d1 --- /dev/null +++ b/src/test/ui/test-attrs/test-on-not-fn.rs @@ -0,0 +1,80 @@ +// compile-flags: --test + +#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function +mod test {} + +#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function +mod loooooooooooooong_teeeeeeeeeest { + /* + this is a comment + this comment goes on for a very long time + this is to pad out the span for this module for a long time + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut + labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco + laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in + voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat + non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. + */ +} + +#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function +extern "C" {} + +#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function +trait Foo {} + +#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function +impl Foo for i32 {} + +#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function +const FOO: i32 = -1_i32; + +#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function +static BAR: u64 = 10_000_u64; + +#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function +enum MyUnit { + Unit, +} + +#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function +struct NewI32(i32); + +#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function +union Spooky { + x: i32, + y: u32, +} + +#[repr(C, align(64))] +#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function +#[derive(Copy, Clone, Debug)] +struct MoreAttrs { + a: i32, + b: u64, +} + +macro_rules! foo { + () => {}; +} + +#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function +foo!(); + +// make sure it doesn't erroneously trigger on a real test +#[test] +fn real_test() { + assert_eq!(42_i32, 42_i32); +} + +// make sure it works with cfg test +#[cfg(test)] +mod real_tests { + #[cfg(test)] + fn foo() {} + + #[test] + fn bar() { + foo(); + } +} diff --git a/src/test/ui/test-attrs/test-on-not-fn.stderr b/src/test/ui/test-attrs/test-on-not-fn.stderr new file mode 100644 index 00000000000..dd693cf316d --- /dev/null +++ b/src/test/ui/test-attrs/test-on-not-fn.stderr @@ -0,0 +1,185 @@ +error: the `#[test]` attribute may only be used on a non-associated function + --> $DIR/test-on-not-fn.rs:3:1 + | +LL | #[test] + | ^^^^^^^ +LL | mod test {} + | ----------- expected a non-associated function, found a module + | + = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions +help: replace with conditional compilation to make the item only exist when tests are being run + | +LL | #[cfg(test)] + | ~~~~~~~~~~~~ + +error: the `#[test]` attribute may only be used on a non-associated function + --> $DIR/test-on-not-fn.rs:6:1 + | +LL | #[test] + | ^^^^^^^ +LL | / mod loooooooooooooong_teeeeeeeeeest { +LL | | /* +LL | | this is a comment +LL | | this comment goes on for a very long time +... | +LL | | */ +LL | | } + | |_- expected a non-associated function, found a module + | + = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions +help: replace with conditional compilation to make the item only exist when tests are being run + | +LL | #[cfg(test)] + | ~~~~~~~~~~~~ + +error: the `#[test]` attribute may only be used on a non-associated function + --> $DIR/test-on-not-fn.rs:20:1 + | +LL | #[test] + | ^^^^^^^ +LL | extern "C" {} + | ------------- expected a non-associated function, found an extern block + | + = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions +help: replace with conditional compilation to make the item only exist when tests are being run + | +LL | #[cfg(test)] + | ~~~~~~~~~~~~ + +error: the `#[test]` attribute may only be used on a non-associated function + --> $DIR/test-on-not-fn.rs:23:1 + | +LL | #[test] + | ^^^^^^^ +LL | trait Foo {} + | ------------ expected a non-associated function, found a trait + | + = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions +help: replace with conditional compilation to make the item only exist when tests are being run + | +LL | #[cfg(test)] + | ~~~~~~~~~~~~ + +error: the `#[test]` attribute may only be used on a non-associated function + --> $DIR/test-on-not-fn.rs:26:1 + | +LL | #[test] + | ^^^^^^^ +LL | impl Foo for i32 {} + | ------------------- expected a non-associated function, found an implementation + | + = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions +help: replace with conditional compilation to make the item only exist when tests are being run + | +LL | #[cfg(test)] + | ~~~~~~~~~~~~ + +error: the `#[test]` attribute may only be used on a non-associated function + --> $DIR/test-on-not-fn.rs:29:1 + | +LL | #[test] + | ^^^^^^^ +LL | const FOO: i32 = -1_i32; + | ------------------------ expected a non-associated function, found a constant item + | + = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions +help: replace with conditional compilation to make the item only exist when tests are being run + | +LL | #[cfg(test)] + | ~~~~~~~~~~~~ + +error: the `#[test]` attribute may only be used on a non-associated function + --> $DIR/test-on-not-fn.rs:32:1 + | +LL | #[test] + | ^^^^^^^ +LL | static BAR: u64 = 10_000_u64; + | ----------------------------- expected a non-associated function, found a static item + | + = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions +help: replace with conditional compilation to make the item only exist when tests are being run + | +LL | #[cfg(test)] + | ~~~~~~~~~~~~ + +error: the `#[test]` attribute may only be used on a non-associated function + --> $DIR/test-on-not-fn.rs:35:1 + | +LL | #[test] + | ^^^^^^^ +LL | / enum MyUnit { +LL | | Unit, +LL | | } + | |_- expected a non-associated function, found an enum + | + = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions +help: replace with conditional compilation to make the item only exist when tests are being run + | +LL | #[cfg(test)] + | ~~~~~~~~~~~~ + +error: the `#[test]` attribute may only be used on a non-associated function + --> $DIR/test-on-not-fn.rs:40:1 + | +LL | #[test] + | ^^^^^^^ +LL | struct NewI32(i32); + | ------------------- expected a non-associated function, found a struct + | + = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions +help: replace with conditional compilation to make the item only exist when tests are being run + | +LL | #[cfg(test)] + | ~~~~~~~~~~~~ + +error: the `#[test]` attribute may only be used on a non-associated function + --> $DIR/test-on-not-fn.rs:43:1 + | +LL | #[test] + | ^^^^^^^ +LL | / union Spooky { +LL | | x: i32, +LL | | y: u32, +LL | | } + | |_- expected a non-associated function, found a union + | + = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions +help: replace with conditional compilation to make the item only exist when tests are being run + | +LL | #[cfg(test)] + | ~~~~~~~~~~~~ + +error: the `#[test]` attribute may only be used on a non-associated function + --> $DIR/test-on-not-fn.rs:50:1 + | +LL | #[test] + | ^^^^^^^ +LL | #[derive(Copy, Clone, Debug)] +LL | / struct MoreAttrs { +LL | | a: i32, +LL | | b: u64, +LL | | } + | |_- expected a non-associated function, found a struct + | + = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions +help: replace with conditional compilation to make the item only exist when tests are being run + | +LL | #[cfg(test)] + | ~~~~~~~~~~~~ + +error: the `#[test]` attribute may only be used on a non-associated function + --> $DIR/test-on-not-fn.rs:61:1 + | +LL | #[test] + | ^^^^^^^ +LL | foo!(); + | ------- expected a non-associated function, found an item macro invocation + | + = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions +help: replace with conditional compilation to make the item only exist when tests are being run + | +LL | #[cfg(test)] + | ~~~~~~~~~~~~ + +error: aborting due to 12 previous errors + diff --git a/src/test/ui/trait-bounds/issue-93008.rs b/src/test/ui/trait-bounds/issue-93008.rs new file mode 100644 index 00000000000..1b010566cbc --- /dev/null +++ b/src/test/ui/trait-bounds/issue-93008.rs @@ -0,0 +1,10 @@ +// compile-flags: -Zmir-opt-level=4 + +pub fn bar<T>(s: &'static mut ()) +where + &'static mut (): Clone, //~ ERROR the trait bound +{ + <&'static mut () as Clone>::clone(&s); +} + +fn main() {} diff --git a/src/test/ui/trait-bounds/issue-93008.stderr b/src/test/ui/trait-bounds/issue-93008.stderr new file mode 100644 index 00000000000..10f80f8de0c --- /dev/null +++ b/src/test/ui/trait-bounds/issue-93008.stderr @@ -0,0 +1,12 @@ +error[E0277]: the trait bound `&'static mut (): Clone` is not satisfied + --> $DIR/issue-93008.rs:5:5 + | +LL | &'static mut (): Clone, + | ^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `&'static mut ()` + | + = help: see issue #48214 + = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-fn-type.rs b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-fn-type.rs index 299bdf562dc..857066c78c9 100644 --- a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-fn-type.rs +++ b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-fn-type.rs @@ -4,7 +4,7 @@ // FIXME: this is ruled out for now but should work type Foo = fn() -> impl Send; -//~^ ERROR: `impl Trait` not allowed outside of function and method return types +//~^ ERROR: `impl Trait` only allowed in function and inherent method return types fn make_foo() -> Foo { || 15 diff --git a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-fn-type.stderr b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-fn-type.stderr index 1c5d57d4af7..a31cf1a51cc 100644 --- a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-fn-type.stderr +++ b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-fn-type.stderr @@ -1,4 +1,4 @@ -error[E0562]: `impl Trait` not allowed outside of function and method return types +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer return --> $DIR/type-alias-impl-trait-fn-type.rs:6:20 | LL | type Foo = fn() -> impl Send; diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index 6d0851d804c..fe391198342 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -528,7 +528,7 @@ fn is_auto_reborrow_position(parent: Option<Node<'_>>) -> bool { fn is_auto_borrow_position(parent: Option<Node<'_>>, child_id: HirId) -> bool { if let Some(Node::Expr(parent)) = parent { match parent.kind { - ExprKind::MethodCall(_, [self_arg, ..], _) => self_arg.hir_id == child_id, + // ExprKind::MethodCall(_, [self_arg, ..], _) => self_arg.hir_id == child_id, ExprKind::Field(..) => true, ExprKind::Call(f, _) => f.hir_id == child_id, _ => false, diff --git a/src/tools/clippy/tests/ui/manual_async_fn.fixed b/src/tools/clippy/tests/ui/manual_async_fn.fixed index e9ca66f125d..136cc96be70 100644 --- a/src/tools/clippy/tests/ui/manual_async_fn.fixed +++ b/src/tools/clippy/tests/ui/manual_async_fn.fixed @@ -80,7 +80,6 @@ fn elided_not_bound(_: &i32) -> impl Future<Output = i32> { async { 42 } } -#[allow(clippy::needless_lifetimes)] async fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> i32 { 42 } // should be ignored diff --git a/src/tools/clippy/tests/ui/manual_async_fn.rs b/src/tools/clippy/tests/ui/manual_async_fn.rs index c3fa846485b..ddc453ffdb7 100644 --- a/src/tools/clippy/tests/ui/manual_async_fn.rs +++ b/src/tools/clippy/tests/ui/manual_async_fn.rs @@ -98,7 +98,6 @@ fn elided_not_bound(_: &i32) -> impl Future<Output = i32> { async { 42 } } -#[allow(clippy::needless_lifetimes)] fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future<Output = i32> + 'a + 'b { async { 42 } } diff --git a/src/tools/clippy/tests/ui/manual_async_fn.stderr b/src/tools/clippy/tests/ui/manual_async_fn.stderr index b83abfccd4e..7435f46074c 100644 --- a/src/tools/clippy/tests/ui/manual_async_fn.stderr +++ b/src/tools/clippy/tests/ui/manual_async_fn.stderr @@ -140,7 +140,7 @@ LL | fn elided(_: &i32) -> impl Future<Output = i32> + '_ { 42 } | ~~~~~~ error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:102:1 + --> $DIR/manual_async_fn.rs:101:1 | LL | fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future<Output = i32> + 'a + 'b { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/needless_borrow.fixed b/src/tools/clippy/tests/ui/needless_borrow.fixed index b856f1375d3..efeb5cf5b2b 100644 --- a/src/tools/clippy/tests/ui/needless_borrow.fixed +++ b/src/tools/clippy/tests/ui/needless_borrow.fixed @@ -64,9 +64,9 @@ fn main() { *x = 5; let s = String::new(); - let _ = s.len(); - let _ = s.capacity(); - let _ = s.capacity(); + // let _ = (&s).len(); + // let _ = (&s).capacity(); + // let _ = (&&s).capacity(); let x = (1, 2); let _ = x.0; diff --git a/src/tools/clippy/tests/ui/needless_borrow.rs b/src/tools/clippy/tests/ui/needless_borrow.rs index 0bfe222a3dc..3e416a0eb84 100644 --- a/src/tools/clippy/tests/ui/needless_borrow.rs +++ b/src/tools/clippy/tests/ui/needless_borrow.rs @@ -64,9 +64,9 @@ fn main() { *x = 5; let s = String::new(); - let _ = (&s).len(); - let _ = (&s).capacity(); - let _ = (&&s).capacity(); + // let _ = (&s).len(); + // let _ = (&s).capacity(); + // let _ = (&&s).capacity(); let x = (1, 2); let _ = (&x).0; diff --git a/src/tools/clippy/tests/ui/needless_borrow.stderr b/src/tools/clippy/tests/ui/needless_borrow.stderr index b90e8448db0..05591ce4117 100644 --- a/src/tools/clippy/tests/ui/needless_borrow.stderr +++ b/src/tools/clippy/tests/ui/needless_borrow.stderr @@ -85,24 +85,6 @@ LL | let y: &mut i32 = &mut &mut x; | ^^^^^^^^^^^ help: change this to: `x` error: this expression borrows a value the compiler would automatically borrow - --> $DIR/needless_borrow.rs:67:13 - | -LL | let _ = (&s).len(); - | ^^^^ help: change this to: `s` - -error: this expression borrows a value the compiler would automatically borrow - --> $DIR/needless_borrow.rs:68:13 - | -LL | let _ = (&s).capacity(); - | ^^^^ help: change this to: `s` - -error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:69:13 - | -LL | let _ = (&&s).capacity(); - | ^^^^^ help: change this to: `s` - -error: this expression borrows a value the compiler would automatically borrow --> $DIR/needless_borrow.rs:72:13 | LL | let _ = (&x).0; @@ -114,5 +96,5 @@ error: this expression borrows a value the compiler would automatically borrow LL | let _ = unsafe { (&*x).0 }; | ^^^^^ help: change this to: `(*x)` -error: aborting due to 19 previous errors +error: aborting due to 16 previous errors diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.stderr b/src/tools/clippy/tests/ui/needless_lifetimes.stderr index 8df50d79ca5..ffa152427a9 100644 --- a/src/tools/clippy/tests/ui/needless_lifetimes.stderr +++ b/src/tools/clippy/tests/ui/needless_lifetimes.stderr @@ -19,12 +19,6 @@ LL | fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:37:1 - | -LL | async fn func<'a>(args: &[&'a str]) -> Option<&'a str> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) --> $DIR/needless_lifetimes.rs:56:1 | LL | fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> { @@ -198,5 +192,5 @@ error: explicit lifetimes given in parameter types where they could be elided (o LL | fn lifetime_elsewhere_provided<'a>(self: Box<Self>, here: &'a ()) -> &'a () { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 33 previous errors +error: aborting due to 32 previous errors diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index da7a19139c6..887d27fd6dc 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -41,12 +41,15 @@ impl EarlyProps { pub fn from_reader<R: Read>(config: &Config, testfile: &Path, rdr: R) -> Self { let mut props = EarlyProps::default(); iter_header(testfile, rdr, &mut |_, ln| { - if let Some(s) = config.parse_aux_build(ln) { - props.aux.push(s); - } - if let Some(ac) = config.parse_aux_crate(ln) { - props.aux_crate.push(ac); - } + config.push_name_value_directive(ln, directives::AUX_BUILD, &mut props.aux, |r| { + r.trim().to_string() + }); + config.push_name_value_directive( + ln, + directives::AUX_CRATE, + &mut props.aux_crate, + Config::parse_aux_crate, + ); config.parse_and_update_revisions(ln, &mut props.revisions); }); return props; @@ -126,6 +129,12 @@ pub struct TestProps { // empty before the test starts. Incremental mode tests will reuse the // incremental directory between passes in the same test. pub incremental: bool, + // If `true`, this test is a known bug. + // + // When set, some requirements are relaxed. Currently, this only means no + // error annotations are needed, but this may be updated in the future to + // include other relaxations. + pub known_bug: bool, // How far should the test proceed while still passing. pass_mode: Option<PassMode>, // Ignore `--pass` overrides from the command line for this test. @@ -150,6 +159,38 @@ pub struct TestProps { pub stderr_per_bitwidth: bool, } +mod directives { + pub const ERROR_PATTERN: &'static str = "error-pattern"; + pub const COMPILE_FLAGS: &'static str = "compile-flags"; + pub const RUN_FLAGS: &'static str = "run-flags"; + pub const SHOULD_ICE: &'static str = "should-ice"; + pub const BUILD_AUX_DOCS: &'static str = "build-aux-docs"; + pub const FORCE_HOST: &'static str = "force-host"; + pub const CHECK_STDOUT: &'static str = "check-stdout"; + pub const CHECK_RUN_RESULTS: &'static str = "check-run-results"; + pub const DONT_CHECK_COMPILER_STDOUT: &'static str = "dont-check-compiler-stdout"; + pub const DONT_CHECK_COMPILER_STDERR: &'static str = "dont-check-compiler-stderr"; + pub const NO_PREFER_DYNAMIC: &'static str = "no-prefer-dynamic"; + pub const PRETTY_EXPANDED: &'static str = "pretty-expanded"; + pub const PRETTY_MODE: &'static str = "pretty-mode"; + pub const PRETTY_COMPARE_ONLY: &'static str = "pretty-compare-only"; + pub const AUX_BUILD: &'static str = "aux-build"; + pub const AUX_CRATE: &'static str = "aux-crate"; + pub const EXEC_ENV: &'static str = "exec-env"; + pub const RUSTC_ENV: &'static str = "rustc-env"; + pub const UNSET_RUSTC_ENV: &'static str = "unset-rustc-env"; + pub const FORBID_OUTPUT: &'static str = "forbid-output"; + pub const CHECK_TEST_LINE_NUMBERS_MATCH: &'static str = "check-test-line-numbers-match"; + pub const IGNORE_PASS: &'static str = "ignore-pass"; + pub const FAILURE_STATUS: &'static str = "failure-status"; + pub const RUN_RUSTFIX: &'static str = "run-rustfix"; + pub const RUSTFIX_ONLY_MACHINE_APPLICABLE: &'static str = "rustfix-only-machine-applicable"; + pub const ASSEMBLY_OUTPUT: &'static str = "assembly-output"; + pub const STDERR_PER_BITWIDTH: &'static str = "stderr-per-bitwidth"; + pub const INCREMENTAL: &'static str = "incremental"; + pub const KNOWN_BUG: &'static str = "known-bug"; +} + impl TestProps { pub fn new() -> Self { TestProps { @@ -176,6 +217,7 @@ impl TestProps { forbid_output: vec![], incremental_dir: None, incremental: false, + known_bug: false, pass_mode: None, fail_mode: None, ignore_pass: false, @@ -228,11 +270,16 @@ impl TestProps { return; } - if let Some(ep) = config.parse_error_pattern(ln) { - self.error_patterns.push(ep); - } + use directives::*; - if let Some(flags) = config.parse_compile_flags(ln) { + config.push_name_value_directive( + ln, + ERROR_PATTERN, + &mut self.error_patterns, + |r| r, + ); + + if let Some(flags) = config.parse_name_value_directive(ln, COMPILE_FLAGS) { self.compile_flags.extend(flags.split_whitespace().map(|s| s.to_owned())); } @@ -243,93 +290,73 @@ impl TestProps { config.parse_and_update_revisions(ln, &mut self.revisions); - if self.run_flags.is_none() { - self.run_flags = config.parse_run_flags(ln); - } + config.set_name_value_directive(ln, RUN_FLAGS, &mut self.run_flags, |r| r); if self.pp_exact.is_none() { self.pp_exact = config.parse_pp_exact(ln, testfile); } - if !self.should_ice { - self.should_ice = config.parse_should_ice(ln); - } - - if !self.build_aux_docs { - self.build_aux_docs = config.parse_build_aux_docs(ln); - } - - if !self.force_host { - self.force_host = config.parse_force_host(ln); - } - - if !self.check_stdout { - self.check_stdout = config.parse_check_stdout(ln); - } - - if !self.check_run_results { - self.check_run_results = config.parse_check_run_results(ln); - } - - if !self.dont_check_compiler_stdout { - self.dont_check_compiler_stdout = config.parse_dont_check_compiler_stdout(ln); - } - - if !self.dont_check_compiler_stderr { - self.dont_check_compiler_stderr = config.parse_dont_check_compiler_stderr(ln); - } - - if !self.no_prefer_dynamic { - self.no_prefer_dynamic = config.parse_no_prefer_dynamic(ln); - } - - if !self.pretty_expanded { - self.pretty_expanded = config.parse_pretty_expanded(ln); - } - - if let Some(m) = config.parse_pretty_mode(ln) { + config.set_name_directive(ln, SHOULD_ICE, &mut self.should_ice); + config.set_name_directive(ln, BUILD_AUX_DOCS, &mut self.build_aux_docs); + config.set_name_directive(ln, FORCE_HOST, &mut self.force_host); + config.set_name_directive(ln, CHECK_STDOUT, &mut self.check_stdout); + config.set_name_directive(ln, CHECK_RUN_RESULTS, &mut self.check_run_results); + config.set_name_directive( + ln, + DONT_CHECK_COMPILER_STDOUT, + &mut self.dont_check_compiler_stdout, + ); + config.set_name_directive( + ln, + DONT_CHECK_COMPILER_STDERR, + &mut self.dont_check_compiler_stderr, + ); + config.set_name_directive(ln, NO_PREFER_DYNAMIC, &mut self.no_prefer_dynamic); + config.set_name_directive(ln, PRETTY_EXPANDED, &mut self.pretty_expanded); + + if let Some(m) = config.parse_name_value_directive(ln, PRETTY_MODE) { self.pretty_mode = m; } - if !self.pretty_compare_only { - self.pretty_compare_only = config.parse_pretty_compare_only(ln); - } - - if let Some(ab) = config.parse_aux_build(ln) { - self.aux_builds.push(ab); - } - - if let Some(ac) = config.parse_aux_crate(ln) { - self.aux_crates.push(ac); - } - - if let Some(ee) = config.parse_env(ln, "exec-env") { - self.exec_env.push(ee); - } - - if let Some(ee) = config.parse_env(ln, "rustc-env") { - self.rustc_env.push(ee); - } - - if let Some(ev) = config.parse_name_value_directive(ln, "unset-rustc-env") { - self.unset_rustc_env.push(ev); - } - - if let Some(of) = config.parse_forbid_output(ln) { - self.forbid_output.push(of); - } - - if !self.check_test_line_numbers_match { - self.check_test_line_numbers_match = - config.parse_check_test_line_numbers_match(ln); - } + config.set_name_directive(ln, PRETTY_COMPARE_ONLY, &mut self.pretty_compare_only); + config.push_name_value_directive(ln, AUX_BUILD, &mut self.aux_builds, |r| { + r.trim().to_string() + }); + config.push_name_value_directive( + ln, + AUX_CRATE, + &mut self.aux_crates, + Config::parse_aux_crate, + ); + config.push_name_value_directive( + ln, + EXEC_ENV, + &mut self.exec_env, + Config::parse_env, + ); + config.push_name_value_directive( + ln, + RUSTC_ENV, + &mut self.rustc_env, + Config::parse_env, + ); + config.push_name_value_directive( + ln, + UNSET_RUSTC_ENV, + &mut self.unset_rustc_env, + |r| r, + ); + config.push_name_value_directive(ln, FORBID_OUTPUT, &mut self.forbid_output, |r| r); + config.set_name_directive( + ln, + CHECK_TEST_LINE_NUMBERS_MATCH, + &mut self.check_test_line_numbers_match, + ); self.update_pass_mode(ln, cfg, config); self.update_fail_mode(ln, config); - if !self.ignore_pass { - self.ignore_pass = config.parse_ignore_pass(ln); - } + config.set_name_directive(ln, IGNORE_PASS, &mut self.ignore_pass); if let Some(rule) = config.parse_custom_normalization(ln, "normalize-stdout") { self.normalize_stdout.push(rule); @@ -338,30 +365,28 @@ impl TestProps { self.normalize_stderr.push(rule); } - if let Some(code) = config.parse_failure_status(ln) { + if let Some(code) = config + .parse_name_value_directive(ln, FAILURE_STATUS) + .and_then(|code| code.trim().parse::<i32>().ok()) + { self.failure_status = code; } - if !self.run_rustfix { - self.run_rustfix = config.parse_run_rustfix(ln); - } - - if !self.rustfix_only_machine_applicable { - self.rustfix_only_machine_applicable = - config.parse_rustfix_only_machine_applicable(ln); - } - - if self.assembly_output.is_none() { - self.assembly_output = config.parse_assembly_output(ln); - } - - if !self.stderr_per_bitwidth { - self.stderr_per_bitwidth = config.parse_stderr_per_bitwidth(ln); - } - - if !self.incremental { - self.incremental = config.parse_incremental(ln); - } + config.set_name_directive(ln, RUN_RUSTFIX, &mut self.run_rustfix); + config.set_name_directive( + ln, + RUSTFIX_ONLY_MACHINE_APPLICABLE, + &mut self.rustfix_only_machine_applicable, + ); + config.set_name_value_directive( + ln, + ASSEMBLY_OUTPUT, + &mut self.assembly_output, + |r| r.trim().to_string(), + ); + config.set_name_directive(ln, STDERR_PER_BITWIDTH, &mut self.stderr_per_bitwidth); + config.set_name_directive(ln, INCREMENTAL, &mut self.incremental); + config.set_name_directive(ln, KNOWN_BUG, &mut self.known_bug); }); } @@ -503,33 +528,12 @@ fn iter_header<R: Read>(testfile: &Path, rdr: R, it: &mut dyn FnMut(Option<&str> } impl Config { - fn parse_should_ice(&self, line: &str) -> bool { - self.parse_name_directive(line, "should-ice") - } - fn parse_error_pattern(&self, line: &str) -> Option<String> { - self.parse_name_value_directive(line, "error-pattern") - } - - fn parse_forbid_output(&self, line: &str) -> Option<String> { - self.parse_name_value_directive(line, "forbid-output") - } - - fn parse_aux_build(&self, line: &str) -> Option<String> { - self.parse_name_value_directive(line, "aux-build").map(|r| r.trim().to_string()) - } - - fn parse_aux_crate(&self, line: &str) -> Option<(String, String)> { - self.parse_name_value_directive(line, "aux-crate").map(|r| { - let mut parts = r.trim().splitn(2, '='); - ( - parts.next().expect("missing aux-crate name (e.g. log=log.rs)").to_string(), - parts.next().expect("missing aux-crate value (e.g. log=log.rs)").to_string(), - ) - }) - } - - fn parse_compile_flags(&self, line: &str) -> Option<String> { - self.parse_name_value_directive(line, "compile-flags") + fn parse_aux_crate(r: String) -> (String, String) { + let mut parts = r.trim().splitn(2, '='); + ( + parts.next().expect("missing aux-crate name (e.g. log=log.rs)").to_string(), + parts.next().expect("missing aux-crate value (e.g. log=log.rs)").to_string(), + ) } fn parse_and_update_revisions(&self, line: &str, existing: &mut Vec<String>) { @@ -544,87 +548,18 @@ impl Config { } } - fn parse_run_flags(&self, line: &str) -> Option<String> { - self.parse_name_value_directive(line, "run-flags") - } - - fn parse_force_host(&self, line: &str) -> bool { - self.parse_name_directive(line, "force-host") - } - - fn parse_build_aux_docs(&self, line: &str) -> bool { - self.parse_name_directive(line, "build-aux-docs") - } - - fn parse_check_stdout(&self, line: &str) -> bool { - self.parse_name_directive(line, "check-stdout") - } - - fn parse_check_run_results(&self, line: &str) -> bool { - self.parse_name_directive(line, "check-run-results") - } - - fn parse_dont_check_compiler_stdout(&self, line: &str) -> bool { - self.parse_name_directive(line, "dont-check-compiler-stdout") - } - - fn parse_dont_check_compiler_stderr(&self, line: &str) -> bool { - self.parse_name_directive(line, "dont-check-compiler-stderr") - } - - fn parse_no_prefer_dynamic(&self, line: &str) -> bool { - self.parse_name_directive(line, "no-prefer-dynamic") - } - - fn parse_pretty_expanded(&self, line: &str) -> bool { - self.parse_name_directive(line, "pretty-expanded") - } - - fn parse_pretty_mode(&self, line: &str) -> Option<String> { - self.parse_name_value_directive(line, "pretty-mode") - } - - fn parse_pretty_compare_only(&self, line: &str) -> bool { - self.parse_name_directive(line, "pretty-compare-only") - } - - fn parse_failure_status(&self, line: &str) -> Option<i32> { - match self.parse_name_value_directive(line, "failure-status") { - Some(code) => code.trim().parse::<i32>().ok(), - _ => None, - } - } - - fn parse_check_test_line_numbers_match(&self, line: &str) -> bool { - self.parse_name_directive(line, "check-test-line-numbers-match") - } - - fn parse_ignore_pass(&self, line: &str) -> bool { - self.parse_name_directive(line, "ignore-pass") - } - - fn parse_stderr_per_bitwidth(&self, line: &str) -> bool { - self.parse_name_directive(line, "stderr-per-bitwidth") - } - - fn parse_assembly_output(&self, line: &str) -> Option<String> { - self.parse_name_value_directive(line, "assembly-output").map(|r| r.trim().to_string()) - } - - fn parse_env(&self, line: &str, name: &str) -> Option<(String, String)> { - self.parse_name_value_directive(line, name).map(|nv| { - // nv is either FOO or FOO=BAR - let mut strs: Vec<String> = nv.splitn(2, '=').map(str::to_owned).collect(); + fn parse_env(nv: String) -> (String, String) { + // nv is either FOO or FOO=BAR + let mut strs: Vec<String> = nv.splitn(2, '=').map(str::to_owned).collect(); - match strs.len() { - 1 => (strs.pop().unwrap(), String::new()), - 2 => { - let end = strs.pop().unwrap(); - (strs.pop().unwrap(), end) - } - n => panic!("Expected 1 or 2 strings, not {}", n), + match strs.len() { + 1 => (strs.pop().unwrap(), String::new()), + 2 => { + let end = strs.pop().unwrap(); + (strs.pop().unwrap(), end) } - }) + n => panic!("Expected 1 or 2 strings, not {}", n), + } } fn parse_pp_exact(&self, line: &str, testfile: &Path) -> Option<PathBuf> { @@ -736,20 +671,38 @@ impl Config { None } - fn parse_run_rustfix(&self, line: &str) -> bool { - self.parse_name_directive(line, "run-rustfix") + fn parse_edition(&self, line: &str) -> Option<String> { + self.parse_name_value_directive(line, "edition") } - fn parse_rustfix_only_machine_applicable(&self, line: &str) -> bool { - self.parse_name_directive(line, "rustfix-only-machine-applicable") + fn set_name_directive(&self, line: &str, directive: &str, value: &mut bool) { + if !*value { + *value = self.parse_name_directive(line, directive) + } } - fn parse_edition(&self, line: &str) -> Option<String> { - self.parse_name_value_directive(line, "edition") + fn set_name_value_directive<T>( + &self, + line: &str, + directive: &str, + value: &mut Option<T>, + parse: impl FnOnce(String) -> T, + ) { + if value.is_none() { + *value = self.parse_name_value_directive(line, directive).map(parse); + } } - fn parse_incremental(&self, line: &str) -> bool { - self.parse_name_directive(line, "incremental") + fn push_name_value_directive<T>( + &self, + line: &str, + directive: &str, + values: &mut Vec<T>, + parse: impl FnOnce(String) -> T, + ) { + if let Some(value) = self.parse_name_value_directive(line, directive).map(parse) { + values.push(value); + } } } @@ -863,6 +816,7 @@ pub fn make_test_description<R: Read>( let has_msan = util::MSAN_SUPPORTED_TARGETS.contains(&&*config.target); let has_tsan = util::TSAN_SUPPORTED_TARGETS.contains(&&*config.target); let has_hwasan = util::HWASAN_SUPPORTED_TARGETS.contains(&&*config.target); + let has_memtag = util::MEMTAG_SUPPORTED_TARGETS.contains(&&*config.target); // for `-Z gcc-ld=lld` let has_rust_lld = config .compile_lib_path @@ -899,9 +853,11 @@ pub fn make_test_description<R: Read>( ignore |= !has_msan && config.parse_name_directive(ln, "needs-sanitizer-memory"); ignore |= !has_tsan && config.parse_name_directive(ln, "needs-sanitizer-thread"); ignore |= !has_hwasan && config.parse_name_directive(ln, "needs-sanitizer-hwaddress"); + ignore |= !has_memtag && config.parse_name_directive(ln, "needs-sanitizer-memtag"); ignore |= config.target_panic == PanicStrategy::Abort && config.parse_name_directive(ln, "needs-unwind"); - ignore |= config.target == "wasm32-unknown-unknown" && config.parse_check_run_results(ln); + ignore |= config.target == "wasm32-unknown-unknown" + && config.parse_name_directive(ln, directives::CHECK_RUN_RESULTS); ignore |= config.debugger == Some(Debugger::Cdb) && ignore_cdb(config, ln); ignore |= config.debugger == Some(Debugger::Gdb) && ignore_gdb(config, ln); ignore |= config.debugger == Some(Debugger::Lldb) && ignore_lldb(config, ln); diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index f6ddac3a65e..7fe7db0801b 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1274,6 +1274,16 @@ impl<'test> TestCx<'test> { self.fatal_proc_rec("process did not return an error status", proc_res); } + if self.props.known_bug { + if !expected_errors.is_empty() { + self.fatal_proc_rec( + "`known_bug` tests should not have an expected errors", + proc_res, + ); + } + return; + } + // On Windows, keep all '\' path separators to match the paths reported in the JSON output // from the compiler let os_file_name = self.testpaths.file.display().to_string(); @@ -1310,6 +1320,7 @@ impl<'test> TestCx<'test> { } None => { + // If the test is a known bug, don't require that the error is annotated if self.is_unexpected_compiler_message(actual_error, expect_help, expect_note) { self.error(&format!( "{}:{}: unexpected {}: '{}'", diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index 6ca145a58e9..bed509d77be 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -117,6 +117,9 @@ pub const TSAN_SUPPORTED_TARGETS: &[&str] = &[ pub const HWASAN_SUPPORTED_TARGETS: &[&str] = &["aarch64-linux-android", "aarch64-unknown-linux-gnu"]; +pub const MEMTAG_SUPPORTED_TARGETS: &[&str] = + &["aarch64-linux-android", "aarch64-unknown-linux-gnu"]; + const BIG_ENDIAN: &[&str] = &[ "aarch64_be", "armebv7r", diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 203e33e8b1f..95847dcd46b 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -7,7 +7,7 @@ use std::path::Path; const ENTRY_LIMIT: usize = 1000; // FIXME: The following limits should be reduced eventually. -const ROOT_ENTRY_LIMIT: usize = 982; +const ROOT_ENTRY_LIMIT: usize = 983; const ISSUES_ENTRY_LIMIT: usize = 2310; fn check_entries(path: &Path, bad: &mut bool) { |
