diff options
722 files changed, 7675 insertions, 4289 deletions
diff --git a/.gitmodules b/.gitmodules index c60a0dd2c7c..9f54ed5bdab 100644 --- a/.gitmodules +++ b/.gitmodules @@ -34,7 +34,7 @@ [submodule "src/llvm-project"] path = src/llvm-project url = https://github.com/rust-lang/llvm-project.git - branch = rustc/13.0-2021-09-30 + branch = rustc/14.0-2022-02-09 [submodule "src/doc/embedded-book"] path = src/doc/embedded-book url = https://github.com/rust-embedded/book.git diff --git a/Cargo.lock b/Cargo.lock index 47cc635b952..fd65ed8d4a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -194,9 +194,9 @@ dependencies = [ [[package]] name = "block-buffer" -version = "0.9.0" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" dependencies = [ "generic-array 0.14.4", ] @@ -740,9 +740,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.69" +version = "0.1.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac0d1d6b2307c15fd27af2bb41234b4ebddeae69f33714bfbdb44b3b5a6e3efe" +checksum = "80873f979f0a344a4ade87c2f70d9ccf5720b83b10c97ec7cd745895d021e85a" dependencies = [ "cc", "rustc-std-workspace-core", @@ -821,10 +821,13 @@ name = "coverage_test_macros" version = "0.0.0" [[package]] -name = "cpuid-bool" -version = "0.1.2" +name = "cpufeatures" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" +checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" +dependencies = [ + "libc", +] [[package]] name = "crates-io" @@ -892,6 +895,15 @@ dependencies = [ ] [[package]] +name = "crypto-common" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4600d695eb3f6ce1cd44e6e291adceb2cc3ab12f20a33777ecd0bf6eba34e06" +dependencies = [ + "generic-array 0.14.4", +] + +[[package]] name = "crypto-hash" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1005,11 +1017,12 @@ dependencies = [ [[package]] name = "digest" -version = "0.9.0" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +checksum = "8cb780dce4f9a8f5c087362b3a4595936b2019e7c8b30f2c3e9a7e94e6ae9837" dependencies = [ - "generic-array 0.14.4", + "block-buffer 0.10.2", + "crypto-common", ] [[package]] @@ -2173,13 +2186,11 @@ checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" [[package]] name = "md-5" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5a279bb9607f9f53c22d496eade00d138d1bdcccd07d74650387cf94942a15" +checksum = "e6a38fc55c8bbc10058782919516f88826e70320db6d206aebc49611d24216ae" dependencies = [ - "block-buffer 0.9.0", - "digest 0.9.0", - "opaque-debug 0.3.0", + "digest 0.10.2", ] [[package]] @@ -2436,12 +2447,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" [[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - -[[package]] name = "opener" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4253,7 +4258,7 @@ dependencies = [ "rustc_macros", "rustc_serialize", "scoped-tls", - "sha-1 0.9.1", + "sha-1 0.10.0", "sha2", "tracing", "unicode-width", @@ -4647,33 +4652,29 @@ dependencies = [ "block-buffer 0.7.3", "digest 0.8.1", "fake-simd", - "opaque-debug 0.2.3", + "opaque-debug", ] [[package]] name = "sha-1" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "170a36ea86c864a3f16dd2687712dd6646f7019f301e57537c7f4dc9f5916770" +checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" dependencies = [ - "block-buffer 0.9.0", - "cfg-if 0.1.10", - "cpuid-bool", - "digest 0.9.0", - "opaque-debug 0.3.0", + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.2", ] [[package]] name = "sha2" -version = "0.9.1" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2933378ddfeda7ea26f48c555bdad8bb446bf8a3d17832dc83e380d444cfb8c1" +checksum = "99c3bd8169c58782adad9290a9af5939994036b76187f7b4f0e6de91dbbfc0ec" dependencies = [ - "block-buffer 0.9.0", - "cfg-if 0.1.10", - "cpuid-bool", - "digest 0.9.0", - "opaque-debug 0.3.0", + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.2", ] [[package]] diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 7c19559ed91..e9135b71630 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -54,7 +54,7 @@ mod tests; /// ``` /// /// `'outer` is a label. -#[derive(Clone, Encodable, Decodable, Copy, HashStable_Generic)] +#[derive(Clone, Encodable, Decodable, Copy, HashStable_Generic, Eq, PartialEq)] pub struct Label { pub ident: Ident, } 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/constraint_generation.rs b/compiler/rustc_borrowck/src/constraint_generation.rs index a40f148cdf8..22edee33c5c 100644 --- a/compiler/rustc_borrowck/src/constraint_generation.rs +++ b/compiler/rustc_borrowck/src/constraint_generation.rs @@ -60,8 +60,8 @@ impl<'cg, 'cx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'tcx> { /// We sometimes have `region` within an rvalue, or within a /// call. Make them live at the location where they appear. - fn visit_region(&mut self, region: &ty::Region<'tcx>, location: Location) { - self.add_regular_live_constraint(*region, location); + fn visit_region(&mut self, region: ty::Region<'tcx>, location: Location) { + self.add_regular_live_constraint(region, location); self.super_region(region); } diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index ac9950241bf..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; }; @@ -356,8 +354,8 @@ fn try_extract_error_from_fulfill_cx<'tcx>( })?; debug!(?sub_region, "cause = {:#?}", cause); - let nice_error = match (error_region, sub_region) { - (Some(error_region), &ty::ReVar(vid)) => NiceRegionError::new( + let nice_error = match (error_region, *sub_region) { + (Some(error_region), ty::ReVar(vid)) => NiceRegionError::new( infcx, RegionResolutionError::SubSupConflict( vid, @@ -374,7 +372,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>( RegionResolutionError::ConcreteFailure(cause.clone(), error_region, placeholder_region), ), // Note universe here is wrong... - (None, &ty::ReVar(vid)) => NiceRegionError::new( + (None, ty::ReVar(vid)) => NiceRegionError::new( infcx, RegionResolutionError::UpperBoundUniverseConflict( vid, diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index f6d21f879ff..fce5ed0ef42 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -2324,7 +2324,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // This is also case 2 from above but for functions, return type is still an // anonymous reference so we select the first argument. let argument_span = fn_decl.inputs.first()?.span; - let argument_ty = sig.inputs().skip_binder().first()?; + let argument_ty = *sig.inputs().skip_binder().first()?; let return_span = fn_decl.output.span(); let return_ty = sig.output().skip_binder(); @@ -2379,27 +2379,27 @@ impl<'tcx> AnnotatedBorrowFnSignature<'tcx> { diag: &mut DiagnosticBuilder<'_>, ) -> String { match self { - AnnotatedBorrowFnSignature::Closure { argument_ty, argument_span } => { + &AnnotatedBorrowFnSignature::Closure { argument_ty, argument_span } => { diag.span_label( - *argument_span, + argument_span, format!("has type `{}`", cx.get_name_for_ty(argument_ty, 0)), ); cx.get_region_name_for_ty(argument_ty, 0) } - AnnotatedBorrowFnSignature::AnonymousFunction { + &AnnotatedBorrowFnSignature::AnonymousFunction { argument_ty, argument_span, return_ty, return_span, } => { let argument_ty_name = cx.get_name_for_ty(argument_ty, 0); - diag.span_label(*argument_span, format!("has type `{}`", argument_ty_name)); + diag.span_label(argument_span, format!("has type `{}`", argument_ty_name)); let return_ty_name = cx.get_name_for_ty(return_ty, 0); let types_equal = return_ty_name == argument_ty_name; diag.span_label( - *return_span, + return_span, format!( "{}has type `{}`", if types_equal { "also " } else { "" }, @@ -2419,7 +2419,7 @@ impl<'tcx> AnnotatedBorrowFnSignature<'tcx> { } AnnotatedBorrowFnSignature::NamedFunction { arguments, return_ty, return_span } => { // Region of return type and arguments checked to be the same earlier. - let region_name = cx.get_region_name_for_ty(return_ty, 0); + let region_name = cx.get_region_name_for_ty(*return_ty, 0); for (_, argument_span) in arguments { diag.span_label(*argument_span, format!("has lifetime `{}`", region_name)); } diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 4400fed13b7..73b0d398285 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -331,7 +331,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { match place { PlaceRef { local, projection: [] } => { let local = &self.body.local_decls[local]; - self.describe_field_from_ty(&local.ty, field, None) + self.describe_field_from_ty(local.ty, field, None) } PlaceRef { local, projection: [proj_base @ .., elem] } => match elem { ProjectionElem::Deref => { @@ -339,10 +339,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } ProjectionElem::Downcast(_, variant_index) => { let base_ty = place.ty(self.body, self.infcx.tcx).ty; - self.describe_field_from_ty(&base_ty, field, Some(*variant_index)) + self.describe_field_from_ty(base_ty, field, Some(*variant_index)) } ProjectionElem::Field(_, field_type) => { - self.describe_field_from_ty(&field_type, field, None) + self.describe_field_from_ty(*field_type, field, None) } ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } @@ -362,7 +362,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ) -> String { if ty.is_box() { // If the type is a box, the field is described from the boxed type - self.describe_field_from_ty(&ty.boxed_ty(), field, variant_index) + self.describe_field_from_ty(ty.boxed_ty(), field, variant_index) } else { match *ty.kind() { ty::Adt(def, _) => { @@ -376,10 +376,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } ty::Tuple(_) => field.index().to_string(), ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => { - self.describe_field_from_ty(&ty, field, variant_index) + self.describe_field_from_ty(ty, field, variant_index) } ty::Array(ty, _) | ty::Slice(ty) => { - self.describe_field_from_ty(&ty, field, variant_index) + self.describe_field_from_ty(ty, field, variant_index) } ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => { // We won't be borrowck'ing here if the closure came from another crate, @@ -497,14 +497,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // We need to add synthesized lifetimes where appropriate. We do // this by hooking into the pretty printer and telling it to label the // lifetimes without names with the value `'0`. - match ty.kind() { - ty::Ref( - ty::RegionKind::ReLateBound(_, ty::BoundRegion { kind: br, .. }) - | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }), - _, - _, - ) => printer.region_highlight_mode.highlighting_bound_region(*br, counter), - _ => {} + if let ty::Ref(region, ..) = ty.kind() { + match **region { + ty::ReLateBound(_, ty::BoundRegion { kind: br, .. }) + | ty::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => { + printer.region_highlight_mode.highlighting_bound_region(br, counter) + } + _ => {} + } } let _ = ty.print(printer); @@ -517,19 +517,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut s = String::new(); let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, &mut s, Namespace::TypeNS); - let region = match ty.kind() { - ty::Ref(region, _, _) => { - match region { - ty::RegionKind::ReLateBound(_, ty::BoundRegion { kind: br, .. }) - | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => { - printer.region_highlight_mode.highlighting_bound_region(*br, counter) - } - _ => {} + let region = if let ty::Ref(region, ..) = ty.kind() { + match **region { + ty::ReLateBound(_, ty::BoundRegion { kind: br, .. }) + | ty::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => { + printer.region_highlight_mode.highlighting_bound_region(br, counter) } - - region + _ => {} } - _ => bug!("ty for annotation of borrow region is not a reference"), + region + } else { + bug!("ty for annotation of borrow region is not a reference"); }; let _ = region.print(printer); @@ -869,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/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index b33b779edda..cc6566882ad 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -246,18 +246,18 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ); ( match kind { - IllegalMoveOriginKind::BorrowedContent { target_place } => self + &IllegalMoveOriginKind::BorrowedContent { target_place } => self .report_cannot_move_from_borrowed_content( original_path, - *target_place, + target_place, span, use_spans, ), - IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => { + &IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => { self.cannot_move_out_of_interior_of_drop(span, ty) } - IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } => { - self.cannot_move_out_of_interior_noncopy(span, ty, Some(*is_index)) + &IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } => { + self.cannot_move_out_of_interior_noncopy(span, ty, Some(is_index)) } }, span, 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 31c977cc78d..ca1e77ff8fd 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -139,7 +139,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { /// Returns `true` if a closure is inferred to be an `FnMut` closure. fn is_closure_fn_mut(&self, fr: RegionVid) -> bool { - if let Some(ty::ReFree(free_region)) = self.to_error_region(fr) { + if let Some(ty::ReFree(free_region)) = self.to_error_region(fr).as_deref() { if let ty::BoundRegionKind::BrEnv = free_region.bound_region { if let DefiningTy::Closure(_, substs) = self.regioncx.universal_regions().defining_ty @@ -628,8 +628,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { fr_name: RegionName, outlived_fr: RegionVid, ) { - if let (Some(f), Some(ty::RegionKind::ReStatic)) = - (self.to_error_region(fr), self.to_error_region(outlived_fr)) + if let (Some(f), Some(ty::ReStatic)) = + (self.to_error_region(fr), self.to_error_region(outlived_fr).as_deref()) { if let Some(&ty::Opaque(did, substs)) = self .infcx @@ -652,7 +652,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { bound.kind().skip_binder() { let r = r.subst(self.infcx.tcx, substs); - if let ty::RegionKind::ReStatic = r { + if r.is_static() { found = true; break; } else { diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 3409f14c98b..3bcc9f7be38 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -264,7 +264,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { let tcx = self.infcx.tcx; debug!("give_region_a_name: error_region = {:?}", error_region); - match error_region { + match *error_region { ty::ReEarlyBound(ebr) => { if ebr.has_name() { let span = tcx.hir().span_if_local(ebr.def_id).unwrap_or(DUMMY_SP); @@ -433,7 +433,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { span: Span, counter: usize, ) -> RegionNameHighlight { - let mut highlight = RegionHighlightMode::default(); + let mut highlight = RegionHighlightMode::new(self.infcx.tcx); highlight.highlighting_region_vid(needle_fr, counter); let type_name = self.infcx.extract_inference_diagnostics_data(ty.into(), Some(highlight)).name; @@ -500,7 +500,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { } // Otherwise, let's descend into the referent types. - search_stack.push((referent_ty, &referent_hir_ty.ty)); + search_stack.push((*referent_ty, &referent_hir_ty.ty)); } // Match up something like `Foo<'1>` @@ -539,7 +539,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { (ty::Slice(elem_ty), hir::TyKind::Slice(elem_hir_ty)) | (ty::Array(elem_ty, _), hir::TyKind::Array(elem_hir_ty, _)) => { - search_stack.push((elem_ty, elem_hir_ty)); + search_stack.push((*elem_ty, elem_hir_ty)); } (ty::RawPtr(mut_ty), hir::TyKind::Ptr(mut_hir_ty)) => { @@ -818,7 +818,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { return None; } - let mut highlight = RegionHighlightMode::default(); + let mut highlight = RegionHighlightMode::new(tcx); highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap()); let type_name = self.infcx.extract_inference_diagnostics_data(yield_ty.into(), Some(highlight)).name; diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 7fc1fe1130b..a16bdf28673 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -8,7 +8,7 @@ use rustc_middle::mir::{ BasicBlock, Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location, Promoted, }; -use rustc_middle::ty::{self, OpaqueTypeKey, RegionKind, RegionVid, Ty}; +use rustc_middle::ty::{self, OpaqueTypeKey, Region, RegionVid, Ty}; use rustc_span::symbol::sym; use std::env; use std::fmt::Debug; @@ -443,9 +443,9 @@ pub trait ToRegionVid { fn to_region_vid(self) -> RegionVid; } -impl<'tcx> ToRegionVid for &'tcx RegionKind { +impl<'tcx> ToRegionVid for Region<'tcx> { fn to_region_vid(self) -> RegionVid { - if let ty::ReVar(vid) = self { *vid } else { bug!("region is not an ReVar: {:?}", self) } + if let ty::ReVar(vid) = *self { vid } else { bug!("region is not an ReVar: {:?}", self) } } } diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 0f0d3eaa293..abd6a15334c 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -1169,7 +1169,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { match verify_bound { VerifyBound::IfEq(test_ty, verify_bound1) => { - self.eval_if_eq(tcx, body, generic_ty, lower_bound, test_ty, verify_bound1) + self.eval_if_eq(tcx, body, generic_ty, lower_bound, *test_ty, verify_bound1) } VerifyBound::IsEmpty => { @@ -1178,7 +1178,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } VerifyBound::OutlivedBy(r) => { - let r_vid = self.to_region_vid(r); + let r_vid = self.to_region_vid(*r); self.eval_outlives(r_vid, lower_bound) } @@ -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/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 76b3be7976c..60c48d8a764 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -133,7 +133,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { for vid in self.rev_scc_graph.as_ref().unwrap().upper_bounds(scc) { match self.definitions[vid].external_name { None => {} - Some(&ty::ReStatic) => {} + Some(region) if region.is_static() => {} Some(region) => return region, } } @@ -183,7 +183,7 @@ fn check_opaque_type_parameter_valid( for (i, arg) in opaque_type_key.substs.iter().enumerate() { let arg_is_param = match arg.unpack() { GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)), - GenericArgKind::Lifetime(ty::ReStatic) => { + GenericArgKind::Lifetime(lt) if lt.is_static() => { tcx.sess .struct_span_err(span, "non-defining opaque type use in defining scope") .span_label( @@ -196,9 +196,9 @@ fn check_opaque_type_parameter_valid( return false; } GenericArgKind::Lifetime(lt) => { - matches!(lt, ty::ReEarlyBound(_) | ty::ReFree(_)) + matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_)) } - GenericArgKind::Const(ct) => matches!(ct.val, ty::ConstKind::Param(_)), + GenericArgKind::Const(ct) => matches!(ct.val(), ty::ConstKind::Param(_)), }; if arg_is_param { diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs index 4b6cab24cdb..2876d60527f 100644 --- a/compiler/rustc_borrowck/src/renumber.rs +++ b/compiler/rustc_borrowck/src/renumber.rs @@ -57,7 +57,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> { #[instrument(skip(self), level = "debug")] fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) { - *ty = self.renumber_regions(ty); + *ty = self.renumber_regions(*ty); debug!(?ty); } @@ -72,12 +72,12 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> { #[instrument(skip(self), level = "debug")] fn visit_region(&mut self, region: &mut ty::Region<'tcx>, location: Location) { let old_region = *region; - *region = self.renumber_regions(&old_region); + *region = self.renumber_regions(old_region); debug!(?region); } - fn visit_const(&mut self, constant: &mut &'tcx ty::Const<'tcx>, _location: Location) { - *constant = self.renumber_regions(&*constant); + fn visit_const(&mut self, constant: &mut ty::Const<'tcx>, _location: Location) { + *constant = self.renumber_regions(*constant); } } diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index a3b39591f8d..5022cb98b82 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -105,8 +105,8 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { // create new region variables, which can't be done later when // verifying these bounds. if t1.has_placeholders() { - t1 = tcx.fold_regions(&t1, &mut false, |r, _| match *r { - ty::RegionKind::RePlaceholder(placeholder) => { + t1 = tcx.fold_regions(t1, &mut false, |r, _| match *r { + ty::RePlaceholder(placeholder) => { self.constraints.placeholder_region(self.infcx, placeholder) } _ => r, @@ -142,8 +142,8 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { } fn to_region_vid(&mut self, r: ty::Region<'tcx>) -> ty::RegionVid { - if let ty::RePlaceholder(placeholder) = r { - self.constraints.placeholder_region(self.infcx, *placeholder).to_region_vid() + if let ty::RePlaceholder(placeholder) = *r { + self.constraints.placeholder_region(self.infcx, placeholder).to_region_vid() } else { self.universal_regions.to_region_vid(r) } diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index fec6bdf314b..9a028147a4b 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -358,7 +358,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { // `where Type:` is lowered to `where Type: 'empty` so that // we check `Type` is well formed, but there's no use for // this bound here. - if let ty::ReEmpty(_) = r1 { + if r1.is_empty() { return; } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 73103643e3e..46924f50d2e 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -383,7 +383,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { } else { let tcx = self.tcx(); let maybe_uneval = match constant.literal { - ConstantKind::Ty(ct) => match ct.val { + ConstantKind::Ty(ct) => match ct.val() { ty::ConstKind::Unevaluated(uv) => Some(uv), _ => None, }, @@ -482,7 +482,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { // then remove the outermost reference so we can check the // type annotation for the remaining type. if let ty::Ref(_, rty, _) = local_decl.ty.kind() { - rty + *rty } else { bug!("{:?} with ref binding has wrong type {}", local, local_decl.ty); } @@ -716,7 +716,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { PlaceTy::from_ty(match base_ty.kind() { ty::Array(inner, _) => { assert!(!from_end, "array subslices should not use from_end"); - tcx.mk_array(inner, to - from) + tcx.mk_array(*inner, to - from) } ty::Slice(..) => { assert!(from_end, "slice subslices should use from_end"); @@ -1737,7 +1737,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ConstraintCategory::Boring }; if let Err(terr) = - self.sub_types(op_arg_ty, fn_arg, term_location.to_locations(), category) + self.sub_types(op_arg_ty, *fn_arg, term_location.to_locations(), category) { span_mirbug!( self, @@ -1956,7 +1956,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { fn check_operand(&mut self, op: &Operand<'tcx>, location: Location) { if let Operand::Constant(constant) = op { let maybe_uneval = match constant.literal { - ConstantKind::Ty(ct) => match ct.val { + ConstantKind::Ty(ct) => match ct.val() { ty::ConstKind::Unevaluated(uv) => Some(uv), _ => None, }, @@ -2048,7 +2048,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } - Rvalue::NullaryOp(_, ty) => { + &Rvalue::NullaryOp(_, ty) => { let trait_ref = ty::TraitRef { def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)), substs: tcx.mk_substs_trait(ty, &[]), @@ -2066,7 +2066,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let trait_ref = ty::TraitRef { def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)), - substs: tcx.mk_substs_trait(ty, &[]), + substs: tcx.mk_substs_trait(*ty, &[]), }; self.prove_trait_ref( @@ -2093,7 +2093,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let ty_fn_ptr_from = tcx.mk_fn_ptr(fn_sig); if let Err(terr) = self.eq_types( - ty, + *ty, ty_fn_ptr_from, location.to_locations(), ConstraintCategory::Cast, @@ -2117,7 +2117,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let ty_fn_ptr_from = tcx.mk_fn_ptr(tcx.signature_unclosure(sig, *unsafety)); if let Err(terr) = self.eq_types( - ty, + *ty, ty_fn_ptr_from, location.to_locations(), ConstraintCategory::Cast, @@ -2146,7 +2146,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let ty_fn_ptr_from = tcx.safe_to_unsafe_fn_ty(fn_sig); if let Err(terr) = self.eq_types( - ty, + *ty, ty_fn_ptr_from, location.to_locations(), ConstraintCategory::Cast, @@ -2209,8 +2209,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } }; if let Err(terr) = self.sub_types( - ty_from, - ty_to, + *ty_from, + *ty_to, location.to_locations(), ConstraintCategory::Cast, ) { @@ -2278,8 +2278,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } if let Err(terr) = self.sub_types( - ty_elem, - ty_to, + *ty_elem, + *ty_to, location.to_locations(), ConstraintCategory::Cast, ) { @@ -2297,7 +2297,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { CastKind::Misc => { let ty_from = op.ty(body, tcx); let cast_ty_from = CastTy::from_ty(ty_from); - let cast_ty_to = CastTy::from_ty(ty); + let cast_ty_to = CastTy::from_ty(*ty); match (cast_ty_from, cast_ty_to) { (None, _) | (_, None | Some(CastTy::FnPtr)) @@ -2318,7 +2318,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } Rvalue::Ref(region, _borrow_kind, borrowed_place) => { - self.add_reborrow_constraint(&body, location, region, borrowed_place); + self.add_reborrow_constraint(&body, location, *region, borrowed_place); } Rvalue::BinaryOp( diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index cc3fe0a123c..590a7a91641 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -117,7 +117,7 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> // We don't have to worry about the equality of consts during borrow checking // as consts always have a static lifetime. - fn const_equate(&mut self, _a: &'tcx Const<'tcx>, _b: &'tcx Const<'tcx>) {} + fn const_equate(&mut self, _a: Const<'tcx>, _b: Const<'tcx>) {} fn normalization() -> NormalizationStrategy { NormalizationStrategy::Eager diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 16a903d5e59..72de3805467 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -323,7 +323,7 @@ impl<'tcx> UniversalRegions<'tcx> { /// See `UniversalRegionIndices::to_region_vid`. pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid { - if let ty::ReEmpty(ty::UniverseIndex::ROOT) = r { + if let ty::ReEmpty(ty::UniverseIndex::ROOT) = *r { self.root_empty } else { self.indices.to_region_vid(r) @@ -512,7 +512,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { first_local_index, num_universals, defining_ty, - unnormalized_output_ty, + unnormalized_output_ty: *unnormalized_output_ty, unnormalized_input_tys, yield_ty, } @@ -805,7 +805,7 @@ impl<'tcx> UniversalRegionIndices<'tcx> { /// during initialization. Relies on the `indices` map having been /// fully initialized. pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid { - if let ty::ReVar(..) = r { + if let ty::ReVar(..) = *r { r.to_region_vid() } else { *self diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 1a6e5694791..ac37c4973d8 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -700,11 +700,11 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl Some(idx) } } - parse::ArgumentNamed(name) => match args.named_args.get(&name) { + parse::ArgumentNamed(name, span) => match args.named_args.get(&name) { Some(&idx) => Some(idx), None => { let msg = format!("there is no argument named `{}`", name); - ecx.struct_span_err(span, &msg).emit(); + ecx.struct_span_err(template_span.from_inner(span), &msg).emit(); None } }, 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/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 8c53094b624..1d1eee88a68 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -222,9 +222,6 @@ fn validate_default_attribute( "this method must only be called with a variant that has a `#[default]` attribute", ), [first, rest @ ..] => { - // FIXME(jhpratt) Do we want to perform this check? It doesn't exist - // for `#[inline]`, `#[non_exhaustive]`, and presumably others. - let suggestion_text = if rest.len() == 1 { "try removing this" } else { "try removing these" }; diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 584fbd1b605..6141d00f697 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -11,7 +11,7 @@ use rustc_errors::{pluralize, Applicability, DiagnosticBuilder}; use rustc_expand::base::{self, *}; use rustc_parse_format as parse; use rustc_span::symbol::{sym, Ident, Symbol}; -use rustc_span::{MultiSpan, Span}; +use rustc_span::{InnerSpan, MultiSpan, Span}; use smallvec::SmallVec; use std::borrow::Cow; @@ -26,7 +26,7 @@ enum ArgumentType { enum Position { Exact(usize), Capture(usize), - Named(Symbol), + Named(Symbol, InnerSpan), } struct Context<'a, 'b> { @@ -247,13 +247,13 @@ impl<'a, 'b> Context<'a, 'b> { match *p { parse::String(_) => {} parse::NextArgument(ref mut arg) => { - if let parse::ArgumentNamed(s) = arg.position { + if let parse::ArgumentNamed(s, _) = arg.position { arg.position = parse::ArgumentIs(lookup(s)); } - if let parse::CountIsName(s) = arg.format.width { + if let parse::CountIsName(s, _) = arg.format.width { arg.format.width = parse::CountIsParam(lookup(s)); } - if let parse::CountIsName(s) = arg.format.precision { + if let parse::CountIsName(s, _) = arg.format.precision { arg.format.precision = parse::CountIsParam(lookup(s)); } } @@ -276,7 +276,7 @@ impl<'a, 'b> Context<'a, 'b> { // it's written second, so it should come after width/precision. let pos = match arg.position { parse::ArgumentIs(i) | parse::ArgumentImplicitlyIs(i) => Exact(i), - parse::ArgumentNamed(s) => Named(s), + parse::ArgumentNamed(s, span) => Named(s, span), }; let ty = Placeholder(match arg.format.ty { @@ -346,8 +346,8 @@ impl<'a, 'b> Context<'a, 'b> { parse::CountIsParam(i) => { self.verify_arg_type(Exact(i), Count); } - parse::CountIsName(s) => { - self.verify_arg_type(Named(s), Count); + parse::CountIsName(s, span) => { + self.verify_arg_type(Named(s, span), Count); } } } @@ -533,7 +533,7 @@ impl<'a, 'b> Context<'a, 'b> { } } - Named(name) => { + Named(name, span) => { match self.names.get(&name) { Some(&idx) => { // Treat as positional arg. @@ -548,7 +548,7 @@ impl<'a, 'b> Context<'a, 'b> { self.arg_types.push(Vec::new()); self.arg_unique_types.push(Vec::new()); let span = if self.is_literal { - *self.arg_spans.get(self.curpiece).unwrap_or(&self.fmtsp) + self.fmtsp.from_inner(span) } else { self.fmtsp }; @@ -559,7 +559,7 @@ impl<'a, 'b> Context<'a, 'b> { } else { let msg = format!("there is no argument named `{}`", name); let sp = if self.is_literal { - *self.arg_spans.get(self.curpiece).unwrap_or(&self.fmtsp) + self.fmtsp.from_inner(span) } else { self.fmtsp }; @@ -629,7 +629,7 @@ impl<'a, 'b> Context<'a, 'b> { } parse::CountImplied => count(sym::Implied, None), // should never be the case, names are already resolved - parse::CountIsName(_) => panic!("should never happen"), + parse::CountIsName(..) => panic!("should never happen"), } } @@ -676,7 +676,7 @@ impl<'a, 'b> Context<'a, 'b> { // should never be the case, because names are already // resolved. - parse::ArgumentNamed(_) => panic!("should never happen"), + parse::ArgumentNamed(..) => panic!("should never happen"), } }; 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_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 72ebc84c1a3..a0550860fa5 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -544,7 +544,7 @@ pub(crate) fn codegen_drop<'tcx>( let arg_value = drop_place.place_ref( fx, fx.layout_of(fx.tcx.mk_ref( - &ty::RegionKind::ReErased, + fx.tcx.lifetimes.re_erased, TypeAndMut { ty, mutbl: crate::rustc_hir::Mutability::Mut }, )), ); diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 5a889734f21..917afa4eae0 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -79,7 +79,7 @@ pub(crate) fn codegen_fn<'tcx>( let arg_uninhabited = fx .mir .args_iter() - .any(|arg| fx.layout_of(fx.monomorphize(&fx.mir.local_decls[arg].ty)).abi.is_uninhabited()); + .any(|arg| fx.layout_of(fx.monomorphize(fx.mir.local_decls[arg].ty)).abi.is_uninhabited()); if !crate::constant::check_constants(&mut fx) { fx.bcx.append_block_params_for_function_params(fx.block_map[START_BLOCK]); @@ -668,7 +668,7 @@ fn codegen_stmt<'tcx>( let times = fx .monomorphize(times) .eval(fx.tcx, ParamEnv::reveal_all()) - .val + .val() .try_to_bits(fx.tcx.data_layout.pointer_size) .unwrap(); if operand.layout().size.bytes() == 0 { @@ -818,16 +818,16 @@ pub(crate) fn codegen_place<'tcx>( match cplace.layout().ty.kind() { ty::Array(elem_ty, _len) => { assert!(!from_end, "array subslices are never `from_end`"); - let elem_layout = fx.layout_of(elem_ty); + let elem_layout = fx.layout_of(*elem_ty); let ptr = cplace.to_ptr(); cplace = CPlace::for_ptr( ptr.offset_i64(fx, elem_layout.size.bytes() as i64 * (from as i64)), - fx.layout_of(fx.tcx.mk_array(elem_ty, to - from)), + fx.layout_of(fx.tcx.mk_array(*elem_ty, to - from)), ); } ty::Slice(elem_ty) => { assert!(from_end, "slice subslices should be `from_end`"); - let elem_layout = fx.layout_of(elem_ty); + let elem_layout = fx.layout_of(*elem_ty); let (ptr, len) = cplace.to_ptr_maybe_unsized(); let len = len.unwrap(); cplace = CPlace::for_ptr_with_extra( diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index 3b6025c73d1..50f98965ab5 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -61,7 +61,7 @@ fn clif_type_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<types::Typ }, ty::FnPtr(_) => pointer_ty(tcx), ty::RawPtr(TypeAndMut { ty: pointee_ty, mutbl: _ }) | ty::Ref(_, pointee_ty, _) => { - if has_ptr_meta(tcx, pointee_ty) { + if has_ptr_meta(tcx, *pointee_ty) { return None; } else { pointer_ty(tcx) @@ -100,7 +100,7 @@ fn clif_pair_type_from_ty<'tcx>( (a, b) } ty::RawPtr(TypeAndMut { ty: pointee_ty, mutbl: _ }) | ty::Ref(_, pointee_ty, _) => { - if has_ptr_meta(tcx, pointee_ty) { + if has_ptr_meta(tcx, *pointee_ty) { (pointer_ty(tcx), pointer_ty(tcx)) } else { return None; diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 74571817969..274fb211b7b 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -46,7 +46,7 @@ pub(crate) fn check_constants(fx: &mut FunctionCx<'_, '_, '_>) -> bool { ConstantKind::Ty(ct) => ct, ConstantKind::Val(..) => continue, }; - match const_.val { + match const_.val() { ConstKind::Value(_) => {} ConstKind::Unevaluated(unevaluated) => { if let Err(err) = @@ -127,7 +127,7 @@ pub(crate) fn codegen_constant<'tcx>( ConstantKind::Ty(ct) => ct, ConstantKind::Val(val, ty) => return codegen_const_value(fx, val, ty), }; - let const_val = match const_.val { + let const_val = match const_.val() { ConstKind::Value(const_val) => const_val, ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) if fx.tcx.is_static(def.did) => @@ -135,7 +135,7 @@ pub(crate) fn codegen_constant<'tcx>( assert!(substs.is_empty()); assert!(promoted.is_none()); - return codegen_static_ref(fx, def.did, fx.layout_of(const_.ty)).to_cvalue(fx); + return codegen_static_ref(fx, def.did, fx.layout_of(const_.ty())).to_cvalue(fx); } ConstKind::Unevaluated(unevaluated) => { match fx.tcx.const_eval_resolve(ParamEnv::reveal_all(), unevaluated, None) { @@ -152,7 +152,7 @@ pub(crate) fn codegen_constant<'tcx>( | ConstKind::Error(_) => unreachable!("{:?}", const_), }; - codegen_const_value(fx, const_val, const_.ty) + codegen_const_value(fx, const_val, const_.ty()) } pub(crate) fn codegen_const_value<'tcx>( @@ -465,7 +465,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( match operand { Operand::Constant(const_) => match const_.literal { ConstantKind::Ty(const_) => { - fx.monomorphize(const_).eval(fx.tcx, ParamEnv::reveal_all()).val.try_to_value() + fx.monomorphize(const_).eval(fx.tcx, ParamEnv::reveal_all()).val().try_to_value() } ConstantKind::Val(val, _) => Some(val), }, @@ -490,7 +490,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( return None; } let const_val = mir_operand_get_const_val(fx, operand)?; - if fx.layout_of(ty).size + if fx.layout_of(*ty).size != const_val.try_to_scalar_int()?.size() { return None; diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs index 8e203b8cfa0..693092ba543 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs @@ -114,7 +114,7 @@ impl<'tcx> DebugContext<'tcx> { } fn dwarf_ty(&mut self, ty: Ty<'tcx>) -> UnitEntryId { - if let Some(type_id) = self.types.get(ty) { + if let Some(type_id) = self.types.get(&ty) { return *type_id; } @@ -143,7 +143,7 @@ impl<'tcx> DebugContext<'tcx> { // Ensure that type is inserted before recursing to avoid duplicates self.types.insert(ty, type_id); - let pointee = self.dwarf_ty(pointee_ty); + let pointee = self.dwarf_ty(*pointee_ty); let type_entry = self.dwarf.unit.get_mut(type_id); diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs index fd96858010e..8cae506e0cb 100644 --- a/compiler/rustc_codegen_cranelift/src/unsize.rs +++ b/compiler/rustc_codegen_cranelift/src/unsize.rs @@ -66,7 +66,7 @@ fn unsize_ptr<'tcx>( (&ty::Ref(_, a, _), &ty::Ref(_, b, _)) | (&ty::Ref(_, a, _), &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) | (&ty::RawPtr(ty::TypeAndMut { ty: a, .. }), &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) => { - (src, unsized_info(fx, a, b, old_info)) + (src, unsized_info(fx, *a, *b, old_info)) } (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) if def_a.is_box() && def_b.is_box() => { let (a, b) = (src_layout.ty.boxed_ty(), dst_layout.ty.boxed_ty()); diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index f29d13ccabd..b016af5174e 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -514,7 +514,7 @@ impl<'tcx> CPlace<'tcx> { // Can only happen for vector types let len = u16::try_from(len.eval_usize(fx.tcx, ParamEnv::reveal_all())).unwrap(); - let vector_ty = fx.clif_type(element).unwrap().by(len).unwrap(); + let vector_ty = fx.clif_type(*element).unwrap().by(len).unwrap(); let data = match from.0 { CValueInner::ByRef(ptr, None) => { @@ -721,8 +721,8 @@ impl<'tcx> CPlace<'tcx> { index: Value, ) -> CPlace<'tcx> { let (elem_layout, ptr) = match self.layout().ty.kind() { - ty::Array(elem_ty, _) => (fx.layout_of(elem_ty), self.to_ptr()), - ty::Slice(elem_ty) => (fx.layout_of(elem_ty), self.to_ptr_maybe_unsized().0), + ty::Array(elem_ty, _) => (fx.layout_of(*elem_ty), self.to_ptr()), + ty::Slice(elem_ty) => (fx.layout_of(*elem_ty), self.to_ptr_maybe_unsized().0), _ => bug!("place_index({:?})", self.layout().ty), }; @@ -781,11 +781,11 @@ pub(crate) fn assert_assignable<'tcx>( ty::RawPtr(TypeAndMut { ty: a, mutbl: _ }), ty::RawPtr(TypeAndMut { ty: b, mutbl: _ }), ) => { - assert_assignable(fx, a, b); + assert_assignable(fx, *a, *b); } (ty::Ref(_, a, _), ty::RawPtr(TypeAndMut { ty: b, mutbl: _ })) | (ty::RawPtr(TypeAndMut { ty: a, mutbl: _ }), ty::Ref(_, b, _)) => { - assert_assignable(fx, a, b); + assert_assignable(fx, *a, *b); } (ty::FnPtr(_), ty::FnPtr(_)) => { let from_sig = fx.tcx.normalize_erasing_late_bound_regions( diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index 30d91b41a8e..7680d4fd233 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -64,7 +64,7 @@ pub(crate) unsafe fn codegen( llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); } if tcx.sess.must_emit_unwind_tables() { - attributes::emit_uwtable(llfn, true); + attributes::emit_uwtable(llfn); } let callee = kind.fn_name(method.name); @@ -111,7 +111,7 @@ pub(crate) unsafe fn codegen( llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); } if tcx.sess.must_emit_unwind_tables() { - attributes::emit_uwtable(llfn, true); + attributes::emit_uwtable(llfn); } let kind = if has_alloc_error_handler { AllocatorKind::Global } else { AllocatorKind::Default }; diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 2472789601e..f6d7221d4e9 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -55,12 +55,28 @@ 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. #[inline] -pub fn emit_uwtable(val: &Value, emit: bool) { - Attribute::UWTable.toggle_llfn(Function, val, emit); +pub fn emit_uwtable(val: &Value) { + // NOTE: We should determine if we even need async unwind tables, as they + // take have more overhead and if we can use sync unwind tables we + // probably should. + llvm::EmitUWTableAttr(val, true); } /// Tell LLVM if this function should be 'naked', i.e., skip the epilogue and prologue. @@ -275,7 +291,7 @@ pub fn from_fn_attrs<'ll, 'tcx>( // You can also find more info on why Windows always requires uwtables here: // https://bugzilla.mozilla.org/show_bug.cgi?id=1302078 if cx.sess().must_emit_unwind_tables() { - attributes::emit_uwtable(llfn, true); + attributes::emit_uwtable(llfn); } if cx.sess().opts.debugging_opts.profile_sample_use.is_some() { diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 8672459b5da..90ddf791450 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -21,7 +21,8 @@ use rustc_middle::ty::layout::{ }; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; -use rustc_session::config::{BranchProtection, CFGuard, CrateType, DebugInfo, PAuthKey, PacRet}; +use rustc_session::config::{BranchProtection, CFGuard, CFProtection}; +use rustc_session::config::{CrateType, DebugInfo, PAuthKey, PacRet}; use rustc_session::Session; use rustc_span::source_map::Span; use rustc_span::symbol::Symbol; @@ -134,7 +135,8 @@ pub unsafe fn create_module<'ll>( let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx); let mut target_data_layout = sess.target.data_layout.clone(); - if llvm_util::get_version() < (13, 0, 0) { + let llvm_version = llvm_util::get_version(); + if llvm_version < (13, 0, 0) { if sess.target.arch == "powerpc64" { target_data_layout = target_data_layout.replace("-S128", ""); } @@ -145,6 +147,18 @@ pub unsafe fn create_module<'ll>( target_data_layout = "e-m:e-p:64:64-i64:64-n32:64-S128".to_string(); } } + if llvm_version < (14, 0, 0) { + if sess.target.llvm_target == "i686-pc-windows-msvc" + || sess.target.llvm_target == "i586-pc-windows-msvc" + { + target_data_layout = + "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:32-n8:16:32-a:0:32-S32" + .to_string(); + } + if sess.target.arch == "wasm32" { + target_data_layout = target_data_layout.replace("-p10:8:8-p20:8:8", ""); + } + } // Ensure the data-layout values hardcoded remain the defaults. if sess.target.is_builtin { @@ -278,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, @@ -287,6 +301,24 @@ pub unsafe fn create_module<'ll>( ); } + // Pass on the control-flow protection flags to LLVM (equivalent to `-fcf-protection` in Clang). + if let CFProtection::Branch | CFProtection::Full = sess.opts.debugging_opts.cf_protection { + llvm::LLVMRustAddModuleFlag( + llmod, + llvm::LLVMModFlagBehavior::Override, + "cf-protection-branch\0".as_ptr().cast(), + 1, + ) + } + if let CFProtection::Return | CFProtection::Full = sess.opts.debugging_opts.cf_protection { + llvm::LLVMRustAddModuleFlag( + llmod, + llvm::LLVMModFlagBehavior::Override, + "cf-protection-return\0".as_ptr().cast(), + 1, + ) + } + llmod } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index da997dd9879..1abc3fb523d 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -185,9 +185,9 @@ impl<'ll, 'tcx> TypeMap<'ll, 'tcx> { /// /// This function is used to remove the temporary metadata /// mapping after we've computed the actual metadata. - fn remove_type(&mut self, type_: Ty<'tcx>) { - if self.type_to_metadata.remove(type_).is_none() { - bug!("type metadata `Ty` '{}' is not in the `TypeMap`!", type_); + fn remove_type(&mut self, ty: Ty<'tcx>) { + if self.type_to_metadata.remove(&ty).is_none() { + bug!("type metadata `Ty` '{}' is not in the `TypeMap`!", ty); } } @@ -397,7 +397,7 @@ fn fixed_size_array_metadata<'ll, 'tcx>( bug!("fixed_size_array_metadata() called with non-ty::Array type `{:?}`", array_type) }; - let element_type_metadata = type_metadata(cx, element_type); + let element_type_metadata = type_metadata(cx, *element_type); return_if_metadata_created_in_meantime!(cx, unique_type_id); @@ -546,7 +546,7 @@ fn subroutine_type_metadata<'ll, 'tcx>( ) .chain( // regular arguments - signature.inputs().iter().map(|argument_type| Some(type_metadata(cx, argument_type))), + signature.inputs().iter().map(|&argument_type| Some(type_metadata(cx, argument_type))), ) .collect(); @@ -601,7 +601,7 @@ fn slice_type_metadata<'ll, 'tcx>( unique_type_id: UniqueTypeId, ) -> MetadataCreationResult<'ll> { let element_type = match slice_type.kind() { - ty::Slice(element_type) => element_type, + ty::Slice(element_type) => *element_type, ty::Str => cx.tcx.types.u8, _ => { bug!( diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 6bc7d8518dc..247cb9ee6e8 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -430,9 +430,9 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { let t = arg.layout.ty; let t = match t.kind() { ty::Array(ct, _) - if (*ct == cx.tcx.types.u8) || cx.layout_of(ct).is_zst() => + if (*ct == cx.tcx.types.u8) || cx.layout_of(*ct).is_zst() => { - cx.tcx.mk_imm_ptr(ct) + cx.tcx.mk_imm_ptr(*ct) } _ => t, }; 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/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index f51d014bfb3..cfd23f5c24e 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1132,8 +1132,8 @@ fn generic_simd_intrinsic<'ll, 'tcx>( fn simd_simple_float_intrinsic<'ll, 'tcx>( name: Symbol, - in_elem: &::rustc_middle::ty::TyS<'_>, - in_ty: &::rustc_middle::ty::TyS<'_>, + in_elem: Ty<'_>, + in_ty: Ty<'_>, in_len: u64, bx: &mut Builder<'_, 'll, 'tcx>, span: Span, diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 4f62c685568..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 @@ -1182,6 +1183,7 @@ extern "C" { pub fn LLVMRustAddByValAttr(Fn: &Value, index: c_uint, ty: &Type); pub fn LLVMRustAddStructRetAttr(Fn: &Value, index: c_uint, ty: &Type); pub fn LLVMRustAddFunctionAttribute(Fn: &Value, index: c_uint, attr: Attribute); + pub fn LLVMRustEmitUWTableAttr(Fn: &Value, async_: bool); pub fn LLVMRustAddFunctionAttrStringValue( Fn: &Value, index: c_uint, diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index a1117a11fc7..8586b0466c8 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -31,6 +31,10 @@ impl LLVMRustResult { } } +pub fn EmitUWTableAttr(llfn: &Value, async_: bool) { + unsafe { LLVMRustEmitUWTableAttr(llfn, async_) } +} + pub fn AddFunctionAttrStringValue(llfn: &Value, idx: AttributePlace, attr: &CStr, value: &CStr) { unsafe { LLVMRustAddFunctionAttrStringValue(llfn, idx.as_uint(), attr.as_ptr(), value.as_ptr()) diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 727d079d83d..b1c14c7e44b 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -217,24 +217,32 @@ pub fn check_tied_features( pub fn target_features(sess: &Session) -> Vec<Symbol> { let target_machine = create_informational_target_machine(sess); - supported_target_features(sess) - .iter() - .filter_map( - |&(feature, gate)| { + let mut features: Vec<Symbol> = + supported_target_features(sess) + .iter() + .filter_map(|&(feature, gate)| { if sess.is_nightly_build() || gate.is_none() { Some(feature) } else { None } - }, - ) - .filter(|feature| { - for llvm_feature in to_llvm_feature(sess, feature) { - let cstr = CString::new(llvm_feature).unwrap(); - if unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) } { - return true; + }) + .filter(|feature| { + for llvm_feature in to_llvm_feature(sess, feature) { + let cstr = CString::new(llvm_feature).unwrap(); + if unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) } { + return true; + } } - } - false - }) - .map(|feature| Symbol::intern(feature)) - .collect() + false + }) + .map(|feature| Symbol::intern(feature)) + .collect(); + + // LLVM 14 changed the ABI for i128 arguments to __float/__fix builtins on Win64 + // (see https://reviews.llvm.org/D110413). This unstable target feature is intended for use + // by compiler-builtins, to export the builtins with the expected, LLVM-version-dependent ABI. + // The target feature can be dropped once we no longer support older LLVM versions. + if sess.is_nightly_build() && get_version() >= (14, 0, 0) { + features.push(Symbol::intern("llvm14-builtins-abi")); + } + features } pub fn print_version() { 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/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 3cb19c0eec6..b63851c195d 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -146,7 +146,7 @@ fn push_debuginfo_type_name<'tcx>( if cpp_like_debuginfo { output.push_str("array$<"); push_debuginfo_type_name(tcx, inner_type, true, output, visited); - match len.val { + match len.val() { ty::ConstKind::Param(param) => write!(output, ",{}>", param.name).unwrap(), _ => write!(output, ",{}>", len.eval_usize(tcx, ty::ParamEnv::reveal_all())) .unwrap(), @@ -154,7 +154,7 @@ fn push_debuginfo_type_name<'tcx>( } else { output.push('['); push_debuginfo_type_name(tcx, inner_type, true, output, visited); - match len.val { + match len.val() { ty::ConstKind::Param(param) => write!(output, "; {}]", param.name).unwrap(), _ => write!(output, "; {}]", len.eval_usize(tcx, ty::ParamEnv::reveal_all())) .unwrap(), @@ -343,7 +343,7 @@ fn push_debuginfo_type_name<'tcx>( // We only care about avoiding recursing // directly back to the type we're currently // processing - visited.remove(t); + visited.remove(&t); } ty::Closure(def_id, substs) | ty::Generator(def_id, substs, ..) => { // Name will be "{closure_env#0}<T1, T2, ...>", "{generator_env#0}<T1, T2, ...>", or @@ -645,19 +645,19 @@ fn push_generic_params_internal<'tcx>( true } -fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: &'tcx ty::Const<'tcx>, output: &mut String) { - match ct.val { +fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut String) { + match ct.val() { ty::ConstKind::Param(param) => { write!(output, "{}", param.name) } - _ => match ct.ty.kind() { + _ => match ct.ty().kind() { ty::Int(ity) => { - let bits = ct.eval_bits(tcx, ty::ParamEnv::reveal_all(), ct.ty); + let bits = ct.eval_bits(tcx, ty::ParamEnv::reveal_all(), ct.ty()); let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128; write!(output, "{}", val) } ty::Uint(_) => { - let val = ct.eval_bits(tcx, ty::ParamEnv::reveal_all(), ct.ty); + let val = ct.eval_bits(tcx, ty::ParamEnv::reveal_all(), ct.ty()); write!(output, "{}", val) } ty::Bool => { @@ -672,7 +672,7 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: &'tcx ty::Const<'tcx>, output: let mut hasher = StableHasher::new(); hcx.while_hashing_spans(false, |hcx| { hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { - ct.val.hash_stable(hcx, &mut hasher); + ct.val().hash_stable(hcx, &mut hasher); }); }); // Let's only emit 64 bits of the hash value. That should be plenty for diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index 93b39dc8e9e..5cdf131b0b6 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -29,7 +29,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::ConstantKind::Ty(ct) => ct, mir::ConstantKind::Val(val, _) => return Ok(val), }; - match ct.val { + match ct.val() { ty::ConstKind::Unevaluated(ct) => self .cx .tcx() @@ -61,11 +61,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let c = ty::Const::from_value(bx.tcx(), val, ty); let values: Vec<_> = bx .tcx() - .destructure_const(ty::ParamEnv::reveal_all().and(&c)) + .destructure_const(ty::ParamEnv::reveal_all().and(c)) .fields .iter() .map(|field| { - if let Some(prim) = field.val.try_to_scalar() { + if let Some(prim) = field.val().try_to_scalar() { let layout = bx.layout_of(field_ty); let scalar = match layout.abi { Abi::Scalar(x) => x, @@ -78,7 +78,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }) .collect(); let llval = bx.const_struct(&values, false); - (llval, c.ty) + (llval, c.ty()) }) .unwrap_or_else(|_| { bx.tcx().sess.span_err(span, "could not evaluate shuffle_indices at compile time"); 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_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index 91b17d1ac1e..ba1d5f45bbb 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -11,7 +11,8 @@ use rustc_middle::{ use rustc_span::{source_map::DUMMY_SP, symbol::Symbol}; use crate::interpret::{ - intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, MPlaceTy, MemPlaceMeta, Scalar, + intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MPlaceTy, + MemPlaceMeta, Scalar, }; mod error; @@ -132,49 +133,46 @@ fn const_to_valtree_inner<'tcx>( } } -/// This function uses `unwrap` copiously, because an already validated constant -/// must have valid fields and can thus never fail outside of compiler bugs. However, it is -/// invoked from the pretty printer, where it can receive enums with no variants and e.g. -/// `read_discriminant` needs to be able to handle that. -pub(crate) fn destructure_const<'tcx>( +/// This function should never fail for validated constants. However, it is also invoked from the +/// pretty printer which might attempt to format invalid constants and in that case it might fail. +pub(crate) fn try_destructure_const<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - val: &'tcx ty::Const<'tcx>, -) -> mir::DestructuredConst<'tcx> { + val: ty::Const<'tcx>, +) -> InterpResult<'tcx, mir::DestructuredConst<'tcx>> { trace!("destructure_const: {:?}", val); let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false); - let op = ecx.const_to_op(val, None).unwrap(); + let op = ecx.const_to_op(val, None)?; // We go to `usize` as we cannot allocate anything bigger anyway. - let (field_count, variant, down) = match val.ty.kind() { + let (field_count, variant, down) = match val.ty().kind() { ty::Array(_, len) => (usize::try_from(len.eval_usize(tcx, param_env)).unwrap(), None, op), - ty::Adt(def, _) if def.variants.is_empty() => { - return mir::DestructuredConst { variant: None, fields: &[] }; - } ty::Adt(def, _) => { - let variant = ecx.read_discriminant(&op).unwrap().1; - let down = ecx.operand_downcast(&op, variant).unwrap(); + let variant = ecx.read_discriminant(&op)?.1; + let down = ecx.operand_downcast(&op, variant)?; (def.variants[variant].fields.len(), Some(variant), down) } ty::Tuple(substs) => (substs.len(), None, op), _ => bug!("cannot destructure constant {:?}", val), }; - let fields_iter = (0..field_count).map(|i| { - let field_op = ecx.operand_field(&down, i).unwrap(); - let val = op_to_const(&ecx, &field_op); - ty::Const::from_value(tcx, val, field_op.layout.ty) - }); - let fields = tcx.arena.alloc_from_iter(fields_iter); + let fields = (0..field_count) + .map(|i| { + let field_op = ecx.operand_field(&down, i)?; + let val = op_to_const(&ecx, &field_op); + Ok(ty::Const::from_value(tcx, val, field_op.layout.ty)) + }) + .collect::<InterpResult<'tcx, Vec<_>>>()?; + let fields = tcx.arena.alloc_from_iter(fields); - mir::DestructuredConst { variant, fields } + Ok(mir::DestructuredConst { variant, fields }) } pub(crate) fn deref_const<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - val: &'tcx ty::Const<'tcx>, -) -> &'tcx ty::Const<'tcx> { + val: ty::Const<'tcx>, +) -> ty::Const<'tcx> { trace!("deref_const: {:?}", val); let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false); let op = ecx.const_to_op(val, None).unwrap(); @@ -194,7 +192,7 @@ pub(crate) fn deref_const<'tcx>( // In case of unsized types, figure out the real type behind. MemPlaceMeta::Meta(scalar) => match mplace.layout.ty.kind() { ty::Str => bug!("there's no sized equivalent of a `str`"), - ty::Slice(elem_ty) => tcx.mk_array(elem_ty, scalar.to_machine_usize(&tcx).unwrap()), + ty::Slice(elem_ty) => tcx.mk_array(*elem_ty, scalar.to_machine_usize(&tcx).unwrap()), _ => bug!( "type {} should not have metadata, but had {:?}", mplace.layout.ty, @@ -203,5 +201,5 @@ pub(crate) fn deref_const<'tcx>( }, }; - tcx.mk_const(ty::Const { val: ty::ConstKind::Value(op_to_const(&ecx, &mplace.into())), ty }) + tcx.mk_const(ty::ConstS { val: ty::ConstKind::Value(op_to_const(&ecx, &mplace.into())), ty }) } diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 4c4b0bd2d1f..e2c4eb1dadc 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -315,7 +315,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { match (&src.layout.ty.kind(), &cast_ty.ty.kind()) { (&ty::Ref(_, s, _), &ty::Ref(_, c, _) | &ty::RawPtr(TypeAndMut { ty: c, .. })) | (&ty::RawPtr(TypeAndMut { ty: s, .. }), &ty::RawPtr(TypeAndMut { ty: c, .. })) => { - self.unsize_into_ptr(src, dest, s, c) + self.unsize_into_ptr(src, dest, *s, *c) } (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => { assert_eq!(def_a, def_b); diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs index ca000f93eb6..e6f243e28db 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs @@ -68,7 +68,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { } } - fn print_const(self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> { + fn print_const(self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> { self.pretty_print_const(ct, false) } diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index e9c94c0cc43..ec5eafcd633 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -561,10 +561,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// "universe" (param_env). pub fn const_to_op( &self, - val: &ty::Const<'tcx>, + val: ty::Const<'tcx>, layout: Option<TyAndLayout<'tcx>>, ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { - match val.val { + match val.val() { ty::ConstKind::Param(_) | ty::ConstKind::Bound(..) => throw_inval!(TooGeneric), ty::ConstKind::Error(_) => throw_inval!(AlreadyReported(ErrorReported)), ty::ConstKind::Unevaluated(uv) => { @@ -574,7 +574,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty::ConstKind::Infer(..) | ty::ConstKind::Placeholder(..) => { span_bug!(self.cur_span(), "const_to_op: Unexpected ConstKind {:?}", val) } - ty::ConstKind::Value(val_val) => self.const_val_to_op(val_val, val.ty, layout), + ty::ConstKind::Value(val_val) => self.const_val_to_op(val_val, val.ty(), layout), } } @@ -584,8 +584,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { layout: Option<TyAndLayout<'tcx>>, ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { match val { - mir::ConstantKind::Ty(ct) => self.const_to_op(ct, layout), - mir::ConstantKind::Val(val, ty) => self.const_val_to_op(*val, ty, layout), + mir::ConstantKind::Ty(ct) => self.const_to_op(*ct, layout), + mir::ConstantKind::Val(val, ty) => self.const_val_to_op(*val, *ty, layout), } } diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 818b95b7fc4..7b06ffaf15d 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -462,7 +462,7 @@ where let (meta, ty) = match base.layout.ty.kind() { // It is not nice to match on the type, but that seems to be the only way to // implement this. - ty::Array(inner, _) => (MemPlaceMeta::None, self.tcx.mk_array(inner, inner_len)), + ty::Array(inner, _) => (MemPlaceMeta::None, self.tcx.mk_array(*inner, inner_len)), ty::Slice(..) => { let len = Scalar::from_machine_usize(inner_len, self); (MemPlaceMeta::Meta(len), base.layout.ty) diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index 6a3378a3896..e17bd9a8c08 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -55,7 +55,7 @@ where assert!(matches!(ty.kind(), ty::Param(_))) } ty::subst::GenericArgKind::Const(ct) => { - assert!(matches!(ct.val, ty::ConstKind::Param(_))) + assert!(matches!(ct.val(), ty::ConstKind::Param(_))) } ty::subst::GenericArgKind::Lifetime(..) => (), }, @@ -68,8 +68,8 @@ where } } - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { - match c.val { + fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { + match c.val() { ty::ConstKind::Param(..) => ControlFlow::Break(FoundParam), _ => c.super_visit_with(self), } diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 9dc7930fc51..4060bee7e05 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -553,7 +553,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' { // A mutable reference inside a const? That does not seem right (except if it is // a ZST). - let layout = self.ecx.layout_of(ty)?; + let layout = self.ecx.layout_of(*ty)?; if !layout.is_zst() { throw_validation_failure!(self.path, { "mutable reference in a `const`" }); } @@ -837,7 +837,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> // This is the length of the array/slice. let len = mplace.len(self.ecx)?; // This is the element type size. - let layout = self.ecx.layout_of(tys)?; + let layout = self.ecx.layout_of(*tys)?; // This is the size in bytes of the whole array. (This checks for overflow.) let size = layout.size * len; @@ -896,7 +896,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> // Fast path for arrays and slices of ZSTs. We only need to check a single ZST element // of an array and not all of them, because there's only a single value of a specific // ZST type, so either validation fails for all elements or none. - ty::Array(tys, ..) | ty::Slice(tys) if self.ecx.layout_of(tys)?.is_zst() => { + ty::Array(tys, ..) | ty::Slice(tys) if self.ecx.layout_of(*tys)?.is_zst() => { // Validate just the first element (if any). self.walk_aggregate(op, fields.take(1))? } diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 838484876c7..77d312f5851 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -41,9 +41,9 @@ pub fn provide(providers: &mut Providers) { providers.eval_to_const_value_raw = const_eval::eval_to_const_value_raw_provider; providers.eval_to_allocation_raw = const_eval::eval_to_allocation_raw_provider; providers.const_caller_location = const_eval::const_caller_location; - providers.destructure_const = |tcx, param_env_and_value| { + providers.try_destructure_const = |tcx, param_env_and_value| { let (param_env, value) = param_env_and_value.into_parts(); - const_eval::destructure_const(tcx, param_env, value) + const_eval::try_destructure_const(tcx, param_env, value).ok() }; providers.const_to_valtree = |tcx, param_env_and_value| { let (param_env, raw) = param_env_and_value.into_parts(); diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index 519b4c02b61..8c3f8e88164 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -233,7 +233,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { let mut tmp_ty = self_ty; while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() { num_refs += 1; - tmp_ty = inner_ty; + tmp_ty = *inner_ty; } let deref = "*".repeat(num_refs); diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index c3fa98b000f..639b798be54 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -355,7 +355,7 @@ where // Check the qualifs of the value of `const` items. if let Some(ct) = constant.literal.const_for_ty() { - if let ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs: _, promoted }) = ct.val { + if let ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs: _, promoted }) = ct.val() { // Use qualifs of the type for the promoted. Promoteds in MIR body should be possible // only for `NeedsNonConstDrop` with precise drop checking. This is the only const // check performed after the promotion. Verify that with an assertion. diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index 92d1f5bceef..cacc0018fe9 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -496,7 +496,7 @@ impl<'tcx> Validator<'_, 'tcx> { if matches!(kind, CastKind::Misc) { let operand_ty = operand.ty(self.body, self.tcx); let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast"); - let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); + let cast_out = CastTy::from_ty(*cast_ty).expect("bad output type for cast"); if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) { // ptr-to-int casts are not possible in consts and thus not promotable return Err(Unpromotable); @@ -839,7 +839,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { span, user_ty: None, literal: tcx - .mk_const(ty::Const { + .mk_const(ty::ConstS { ty, val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, diff --git a/compiler/rustc_data_structures/src/intern.rs b/compiler/rustc_data_structures/src/intern.rs new file mode 100644 index 00000000000..c79a5ebf093 --- /dev/null +++ b/compiler/rustc_data_structures/src/intern.rs @@ -0,0 +1,98 @@ +use std::cmp::Ordering; +use std::hash::{Hash, Hasher}; +use std::ops::Deref; +use std::ptr; + +mod private { + #[derive(Clone, Copy, Debug)] + pub struct PrivateZst; +} + +/// A reference to a value that is interned, and is known to be unique. +/// +/// Note that it is possible to have a `T` and a `Interned<T>` that are (or +/// refer to) equal but different values. But if you have two different +/// `Interned<T>`s, they both refer to the same value, at a single location in +/// memory. This means that equality and hashing can be done on the value's +/// address rather than the value's contents, which can improve performance. +/// +/// The `PrivateZst` field means you can pattern match with `Interned(v, _)` +/// but you can only construct a `Interned` with `new_unchecked`, and not +/// directly. +#[derive(Debug)] +#[cfg_attr(not(bootstrap), rustc_pass_by_value)] +pub struct Interned<'a, T>(pub &'a T, pub private::PrivateZst); + +impl<'a, T> Interned<'a, T> { + /// Create a new `Interned` value. The value referred to *must* be interned + /// and thus be unique, and it *must* remain unique in the future. This + /// function has `_unchecked` in the name but is not `unsafe`, because if + /// the uniqueness condition is violated condition it will cause incorrect + /// behaviour but will not affect memory safety. + #[inline] + pub const fn new_unchecked(t: &'a T) -> Self { + Interned(t, private::PrivateZst) + } +} + +impl<'a, T> Clone for Interned<'a, T> { + fn clone(&self) -> Self { + *self + } +} + +impl<'a, T> Copy for Interned<'a, T> {} + +impl<'a, T> Deref for Interned<'a, T> { + type Target = T; + + #[inline] + fn deref(&self) -> &T { + self.0 + } +} + +impl<'a, T> PartialEq for Interned<'a, T> { + #[inline] + fn eq(&self, other: &Self) -> bool { + // Pointer equality implies equality, due to the uniqueness constraint. + ptr::eq(self.0, other.0) + } +} + +impl<'a, T> Eq for Interned<'a, T> {} + +// In practice you can't intern any `T` that doesn't implement `Eq`, because +// that's needed for hashing. Therefore, we won't be interning any `T` that +// implements `PartialOrd` without also implementing `Ord`. So we can have the +// bound `T: Ord` here and avoid duplication with the `Ord` impl below. +impl<'a, T: Ord> PartialOrd for Interned<'a, T> { + fn partial_cmp(&self, other: &Interned<'a, T>) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + +impl<'a, T: Ord> Ord for Interned<'a, T> { + fn cmp(&self, other: &Interned<'a, T>) -> Ordering { + // Pointer equality implies equality, due to the uniqueness constraint, + // but the contents must be compared otherwise. + if ptr::eq(self.0, other.0) { + Ordering::Equal + } else { + let res = self.0.cmp(&other.0); + debug_assert_ne!(res, Ordering::Equal); + res + } + } +} + +impl<'a, T> Hash for Interned<'a, T> { + #[inline] + fn hash<H: Hasher>(&self, s: &mut H) { + // Pointer hashing is sufficient, due to the uniqueness constraint. + ptr::hash(self.0, s) + } +} + +#[cfg(test)] +mod tests; diff --git a/compiler/rustc_data_structures/src/intern/tests.rs b/compiler/rustc_data_structures/src/intern/tests.rs new file mode 100644 index 00000000000..09810a0850e --- /dev/null +++ b/compiler/rustc_data_structures/src/intern/tests.rs @@ -0,0 +1,59 @@ +use super::*; +use std::cmp::Ordering; + +#[derive(Debug)] +struct S(u32); + +impl PartialEq for S { + fn eq(&self, _other: &Self) -> bool { + panic!("shouldn't be called"); + } +} + +impl Eq for S {} + +impl PartialOrd for S { + fn partial_cmp(&self, other: &S) -> Option<Ordering> { + // The `==` case should be handled by `Interned`. + assert_ne!(self.0, other.0); + self.0.partial_cmp(&other.0) + } +} + +impl Ord for S { + fn cmp(&self, other: &S) -> Ordering { + // The `==` case should be handled by `Interned`. + assert_ne!(self.0, other.0); + self.0.cmp(&other.0) + } +} + +#[test] +fn test_uniq() { + let s1 = S(1); + let s2 = S(2); + let s3 = S(3); + let s4 = S(1); // violates uniqueness + + let v1 = Interned::new_unchecked(&s1); + let v2 = Interned::new_unchecked(&s2); + let v3a = Interned::new_unchecked(&s3); + let v3b = Interned::new_unchecked(&s3); + let v4 = Interned::new_unchecked(&s4); // violates uniqueness + + assert_ne!(v1, v2); + assert_ne!(v2, v3a); + assert_eq!(v1, v1); + assert_eq!(v3a, v3b); + assert_ne!(v1, v4); // same content but different addresses: not equal + + assert_eq!(v1.cmp(&v2), Ordering::Less); + assert_eq!(v3a.cmp(&v2), Ordering::Greater); + assert_eq!(v1.cmp(&v1), Ordering::Equal); // only uses Interned::eq, not S::cmp + assert_eq!(v3a.cmp(&v3b), Ordering::Equal); // only uses Interned::eq, not S::cmp + + assert_eq!(v1.partial_cmp(&v2), Some(Ordering::Less)); + assert_eq!(v3a.partial_cmp(&v2), Some(Ordering::Greater)); + assert_eq!(v1.partial_cmp(&v1), Some(Ordering::Equal)); // only uses Interned::eq, not S::cmp + assert_eq!(v3a.partial_cmp(&v3b), Some(Ordering::Equal)); // only uses Interned::eq, not S::cmp +} diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 205f1cd77c0..80f83140f4b 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -21,6 +21,7 @@ #![feature(type_alias_impl_trait)] #![feature(new_uninit)] #![feature(once_cell)] +#![feature(rustc_attrs)] #![feature(test)] #![feature(thread_id_value)] #![feature(vec_into_raw_parts)] @@ -68,12 +69,12 @@ pub mod flock; pub mod functor; pub mod fx; pub mod graph; +pub mod intern; pub mod jobserver; pub mod macros; pub mod map_in_place; pub mod obligation_forest; pub mod owning_ref; -pub mod ptr_key; pub mod sip128; pub mod small_c_str; pub mod snapshot_map; diff --git a/compiler/rustc_data_structures/src/ptr_key.rs b/compiler/rustc_data_structures/src/ptr_key.rs deleted file mode 100644 index 440ccb05d86..00000000000 --- a/compiler/rustc_data_structures/src/ptr_key.rs +++ /dev/null @@ -1,37 +0,0 @@ -use std::ops::Deref; -use std::{hash, ptr}; - -/// A wrapper around reference that compares and hashes like a pointer. -/// Can be used as a key in sets/maps indexed by pointers to avoid `unsafe`. -#[derive(Debug)] -pub struct PtrKey<'a, T>(pub &'a T); - -impl<'a, T> Clone for PtrKey<'a, T> { - fn clone(&self) -> Self { - *self - } -} - -impl<'a, T> Copy for PtrKey<'a, T> {} - -impl<'a, T> PartialEq for PtrKey<'a, T> { - fn eq(&self, rhs: &Self) -> bool { - ptr::eq(self.0, rhs.0) - } -} - -impl<'a, T> Eq for PtrKey<'a, T> {} - -impl<'a, T> hash::Hash for PtrKey<'a, T> { - fn hash<H: hash::Hasher>(&self, hasher: &mut H) { - (self.0 as *const T).hash(hasher) - } -} - -impl<'a, T> Deref for PtrKey<'a, T> { - type Target = T; - - fn deref(&self) -> &Self::Target { - self.0 - } -} diff --git a/compiler/rustc_data_structures/src/snapshot_map/mod.rs b/compiler/rustc_data_structures/src/snapshot_map/mod.rs index b4cc85293f7..8a50179cd3b 100644 --- a/compiler/rustc_data_structures/src/snapshot_map/mod.rs +++ b/compiler/rustc_data_structures/src/snapshot_map/mod.rs @@ -13,6 +13,7 @@ mod tests; pub type SnapshotMapStorage<K, V> = SnapshotMap<K, V, FxHashMap<K, V>, ()>; pub type SnapshotMapRef<'a, K, V, L> = SnapshotMap<K, V, &'a mut FxHashMap<K, V>, &'a mut L>; +#[derive(Clone)] pub struct SnapshotMap<K, V, M = FxHashMap<K, V>, L = VecLog<UndoLog<K, V>>> { map: M, undo_log: L, @@ -30,6 +31,7 @@ where } } +#[derive(Clone)] pub enum UndoLog<K, V> { Inserted(K), Overwrite(K, V), diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 7eeae66d709..85826cfbf01 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -216,17 +216,18 @@ 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, output_dir: odir, file_loader, diagnostic_output, - stderr: None, lint_caps: Default::default(), parse_sess_created: None, register_lints: None, 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 88edaec9169..d43f926d0a5 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -70,10 +70,10 @@ 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_has_atomic = "...")`. - (accepted, cfg_target_has_atomic, "1.60.0", Some(32976), None), /// Allows `cfg(target_vendor = "...")`. (accepted, cfg_target_vendor, "1.33.0", Some(29718), None), /// Allows implementing `Clone` for closures where possible (RFC 2132). diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index fab22e4e6cf..5545abc6024 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -161,6 +161,9 @@ declare_features! ( (active, staged_api, "1.0.0", None, None), /// Added for testing E0705; perma-unstable. (active, test_2018_feature, "1.31.0", None, Some(Edition::Edition2018)), + /// Allows non-`unsafe` —and thus, unsound— access to `Pin` constructions. + /// Marked `incomplete` since perma-unstable and unsound. + (incomplete, unsafe_pin_internals, "1.60.0", None, None), /// Use for stable + negative coherence and strict coherence depending on trait's /// rustc_strict_coherence value. (active, with_negative_coherence, "1.60.0", None, None), @@ -282,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. @@ -303,12 +306,12 @@ 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 = "...")`. (active, cfg_target_abi, "1.55.0", Some(80970), None), + /// Allows `cfg(target_has_atomic_load_store = "...")`. + (active, cfg_target_has_atomic, "1.60.0", Some(94039), None), /// Allows `cfg(target_has_atomic_equal_alignment = "...")`. (active, cfg_target_has_atomic_equal_alignment, "1.60.0", Some(93822), None), /// Allows `cfg(target_thread_local)`. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 69ce21d231f..1fb1a38a927 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -31,9 +31,9 @@ const GATED_CFGS: &[GatedCfg] = &[ sym::cfg_target_has_atomic_equal_alignment, cfg_fn!(cfg_target_has_atomic_equal_alignment), ), + (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_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index a43cb0203dd..e99f61d034f 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -266,59 +266,67 @@ pub enum Res<Id = hir::HirId> { /// /// **Belongs to the type namespace.** PrimTy(hir::PrimTy), - /// The `Self` type, optionally with the trait it is associated with - /// and optionally with the [`DefId`] of the impl it is associated with. + /// The `Self` type, optionally with the [`DefId`] of the trait it belongs to and + /// optionally with the [`DefId`] of the item introducing the `Self` type alias. /// /// **Belongs to the type namespace.** /// - /// For example, the `Self` in - /// + /// Examples: /// ``` + /// struct Bar(Box<Self>); + /// // `Res::SelfTy { trait_: None, alias_of: Some(Bar) }` + /// /// trait Foo { /// fn foo() -> Box<Self>; + /// // `Res::SelfTy { trait_: Some(Foo), alias_of: None }` /// } - /// ``` - /// - /// would have the [`DefId`] of `Foo` associated with it. The `Self` in - /// - /// ``` - /// struct Bar; /// /// impl Bar { - /// fn new() -> Self { Bar } + /// fn blah() { + /// let _: Self; + /// // `Res::SelfTy { trait_: None, alias_of: Some(::{impl#0}) }` + /// } /// } - /// ``` - /// - /// would have the [`DefId`] of the impl associated with it. Finally, the `Self` in /// - /// ``` /// impl Foo for Bar { - /// fn foo() -> Box<Self> { Box::new(Bar) } + /// fn foo() -> Box<Self> { + /// // `Res::SelfTy { trait_: Some(Foo), alias_of: Some(::{impl#1}) }` + /// let _: Self; + /// // `Res::SelfTy { trait_: Some(Foo), alias_of: Some(::{impl#1}) }` + /// + /// todo!() + /// } /// } /// ``` /// - /// would have both the [`DefId`] of `Foo` and the [`DefId`] of the impl - /// associated with it. - /// /// *See also [`Res::SelfCtor`].* /// /// ----- /// - /// HACK(min_const_generics): impl self types also have an optional requirement to **not** mention + /// HACK(min_const_generics): self types also have an optional requirement to **not** mention /// any generic parameters to allow the following with `min_const_generics`: /// ``` /// impl Foo { fn test() -> [u8; std::mem::size_of::<Self>()] { todo!() } } + /// + /// struct Bar([u8; baz::<Self>()]); + /// const fn baz<T>() -> usize { 10 } /// ``` /// We do however allow `Self` in repeat expression even if it is generic to not break code - /// which already works on stable while causing the `const_evaluatable_unchecked` future compat lint. - /// - /// FIXME(generic_const_exprs): Remove this bodge once that feature is stable. - SelfTy( - /// Optionally, the trait associated with this `Self` type. - Option<DefId>, - /// Optionally, the impl associated with this `Self` type. - Option<(DefId, bool)>, - ), + /// which already works on stable while causing the `const_evaluatable_unchecked` future compat lint: + /// ``` + /// fn foo<T>() { + /// let _bar = [1_u8; std::mem::size_of::<*mut T>()]; + /// } + /// ``` + // FIXME(generic_const_exprs): Remove this bodge once that feature is stable. + SelfTy { + /// The trait this `Self` is a generic arg for. + trait_: Option<DefId>, + /// The item introducing the `Self` type alias. Can be used in the `type_of` query + /// to get the underlying type. Additionally whether the `Self` type is disallowed + /// from mentioning generics (i.e. when used in an anonymous constant). + alias_to: Option<(DefId, bool)>, + }, /// A tool attribute module; e.g., the `rustfmt` in `#[rustfmt::skip]`. /// /// **Belongs to the type namespace.** @@ -550,7 +558,7 @@ impl<Id> Res<Id> { Res::Local(..) | Res::PrimTy(..) - | Res::SelfTy(..) + | Res::SelfTy { .. } | Res::SelfCtor(..) | Res::ToolMod | Res::NonMacroAttr(..) @@ -573,7 +581,7 @@ impl<Id> Res<Id> { Res::SelfCtor(..) => "self constructor", Res::PrimTy(..) => "builtin type", Res::Local(..) => "local variable", - Res::SelfTy(..) => "self type", + Res::SelfTy { .. } => "self type", Res::ToolMod => "tool module", Res::NonMacroAttr(attr_kind) => attr_kind.descr(), Res::Err => "unresolved item", @@ -596,7 +604,7 @@ impl<Id> Res<Id> { Res::SelfCtor(id) => Res::SelfCtor(id), Res::PrimTy(id) => Res::PrimTy(id), Res::Local(id) => Res::Local(map(id)), - Res::SelfTy(a, b) => Res::SelfTy(a, b), + Res::SelfTy { trait_, alias_to } => Res::SelfTy { trait_, alias_to }, Res::ToolMod => Res::ToolMod, Res::NonMacroAttr(attr_kind) => Res::NonMacroAttr(attr_kind), Res::Err => Res::Err, @@ -620,7 +628,7 @@ impl<Id> Res<Id> { pub fn ns(&self) -> Option<Namespace> { match self { Res::Def(kind, ..) => kind.ns(), - Res::PrimTy(..) | Res::SelfTy(..) | Res::ToolMod => Some(Namespace::TypeNS), + Res::PrimTy(..) | Res::SelfTy { .. } | Res::ToolMod => Some(Namespace::TypeNS), Res::SelfCtor(..) | Res::Local(..) => Some(Namespace::ValueNS), Res::NonMacroAttr(..) => Some(Namespace::MacroNS), Res::Err => None, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index f21f17439a4..0961d0131d0 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -640,9 +640,8 @@ impl<'hir> WhereBoundPredicate<'hir> { _ => return false, }; match path.res { - Res::Def(DefKind::TyParam, def_id) | Res::SelfTy(Some(def_id), None) => { - def_id == param_def_id - } + Res::Def(DefKind::TyParam, def_id) + | Res::SelfTy { trait_: Some(def_id), alias_to: None } => def_id == param_def_id, _ => false, } } 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/at.rs b/compiler/rustc_infer/src/infer/at.rs index c26ea4c9669..94991fdb201 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -51,6 +51,28 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ) -> At<'a, 'tcx> { At { infcx: self, cause, param_env } } + + /// Forks the inference context, creating a new inference context with the same inference + /// variables in the same state. This can be used to "branch off" many tests from the same + /// common state. Used in coherence. + pub fn fork(&self) -> Self { + Self { + tcx: self.tcx.clone(), + defining_use_anchor: self.defining_use_anchor.clone(), + in_progress_typeck_results: self.in_progress_typeck_results.clone(), + inner: self.inner.clone(), + skip_leak_check: self.skip_leak_check.clone(), + lexical_region_resolutions: self.lexical_region_resolutions.clone(), + selection_cache: self.selection_cache.clone(), + evaluation_cache: self.evaluation_cache.clone(), + reported_trait_errors: self.reported_trait_errors.clone(), + reported_closure_mismatch: self.reported_closure_mismatch.clone(), + tainted_by_errors_flag: self.tainted_by_errors_flag.clone(), + err_count_on_creation: self.err_count_on_creation, + in_snapshot: self.in_snapshot.clone(), + universe: self.universe.clone(), + } + } } pub trait ToTrace<'tcx>: Relate<'tcx> + Copy { @@ -277,7 +299,7 @@ impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> { } } -impl<'tcx> ToTrace<'tcx> for &'tcx Const<'tcx> { +impl<'tcx> ToTrace<'tcx> for Const<'tcx> { fn to_trace( _: TyCtxt<'tcx>, cause: &ObligationCause<'tcx>, diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index bd5892dba38..5e67c8cfa27 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -179,7 +179,7 @@ impl CanonicalizeMode for CanonicalizeQueryResponse { canonicalizer: &mut Canonicalizer<'_, 'tcx>, r: ty::Region<'tcx>, ) -> ty::Region<'tcx> { - match r { + match *r { ty::ReFree(_) | ty::ReErased | ty::ReStatic @@ -187,12 +187,12 @@ impl CanonicalizeMode for CanonicalizeQueryResponse { | ty::ReEarlyBound(..) => r, ty::RePlaceholder(placeholder) => canonicalizer.canonical_var_for_region( - CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderRegion(*placeholder) }, + CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderRegion(placeholder) }, r, ), ty::ReVar(vid) => { - let universe = canonicalizer.region_var_universe(*vid); + let universe = canonicalizer.region_var_universe(vid); canonicalizer.canonical_var_for_region( CanonicalVarInfo { kind: CanonicalVarKind::Region(universe) }, r, @@ -240,7 +240,7 @@ impl CanonicalizeMode for CanonicalizeUserTypeAnnotation { canonicalizer: &mut Canonicalizer<'_, 'tcx>, r: ty::Region<'tcx>, ) -> ty::Region<'tcx> { - match r { + match *r { ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReErased | ty::ReStatic => r, ty::ReVar(_) => canonicalizer.canonical_var_for_region_in_root_universe(r), _ => { @@ -311,11 +311,7 @@ impl CanonicalizeMode for CanonicalizeFreeRegionsOtherThanStatic { canonicalizer: &mut Canonicalizer<'_, 'tcx>, r: ty::Region<'tcx>, ) -> ty::Region<'tcx> { - if let ty::ReStatic = r { - r - } else { - canonicalizer.canonical_var_for_region_in_root_universe(r) - } + if r.is_static() { r } else { canonicalizer.canonical_var_for_region_in_root_universe(r) } } fn any(&self) -> bool { @@ -479,8 +475,8 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { } } - fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - match ct.val { + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + match ct.val() { ty::ConstKind::Infer(InferConst::Var(vid)) => { debug!("canonical: const var found with vid {:?}", vid); match self.infcx.probe_const_var(vid) { @@ -497,7 +493,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { ui = ty::UniverseIndex::ROOT; } return self.canonicalize_const_var( - CanonicalVarInfo { kind: CanonicalVarKind::Const(ui, ct.ty) }, + CanonicalVarInfo { kind: CanonicalVarKind::Const(ui, ct.ty()) }, ct, ); } @@ -773,17 +769,17 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { fn canonicalize_const_var( &mut self, info: CanonicalVarInfo<'tcx>, - const_var: &'tcx ty::Const<'tcx>, - ) -> &'tcx ty::Const<'tcx> { + const_var: ty::Const<'tcx>, + ) -> ty::Const<'tcx> { let infcx = self.infcx; let bound_to = infcx.shallow_resolve(const_var); if bound_to != const_var { self.fold_const(bound_to) } else { let var = self.canonical_var(info, const_var.into()); - self.tcx().mk_const(ty::Const { + self.tcx().mk_const(ty::ConstS { val: ty::ConstKind::Bound(self.binder_index, var), - ty: self.fold_ty(const_var.ty), + ty: self.fold_ty(const_var.ty()), }) } } diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index 2d2edb07d9e..79856867985 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -149,7 +149,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { let universe_mapped = universe_map(universe); let placeholder_mapped = ty::PlaceholderConst { universe: universe_mapped, name }; self.tcx - .mk_const(ty::Const { + .mk_const(ty::ConstS { val: ty::ConstKind::Placeholder(placeholder_mapped), ty: name.ty, }) diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 5b4a9d9dfad..48d5c21f9eb 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -237,10 +237,9 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { v.var_values[BoundVar::new(index)] }); match (original_value.unpack(), result_value.unpack()) { - ( - GenericArgKind::Lifetime(ty::ReErased), - GenericArgKind::Lifetime(ty::ReErased), - ) => { + (GenericArgKind::Lifetime(re1), GenericArgKind::Lifetime(re2)) + if re1.is_erased() && re2.is_erased() => + { // No action needed. } @@ -429,7 +428,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { } GenericArgKind::Lifetime(result_value) => { // e.g., here `result_value` might be `'?1` in the example above... - if let &ty::RegionKind::ReLateBound(debruijn, br) = result_value { + if let ty::ReLateBound(debruijn, br) = *result_value { // ... in which case we would set `canonical_vars[0]` to `Some('static)`. // We only allow a `ty::INNERMOST` index in substitutions. @@ -438,12 +437,12 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { } } GenericArgKind::Const(result_value) => { - if let ty::Const { val: ty::ConstKind::Bound(debrujin, b), .. } = result_value { + if let ty::ConstKind::Bound(debrujin, b) = result_value.val() { // ...in which case we would set `canonical_vars[0]` to `Some(const X)`. // We only allow a `ty::INNERMOST` index in substitutions. - assert_eq!(*debrujin, ty::INNERMOST); - opt_values[*b] = Some(*original_value); + assert_eq!(debrujin, ty::INNERMOST); + opt_values[b] = Some(*original_value); } } } @@ -558,10 +557,9 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { obligations .extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations()); } - ( - GenericArgKind::Lifetime(ty::ReErased), - GenericArgKind::Lifetime(ty::ReErased), - ) => { + (GenericArgKind::Lifetime(re1), GenericArgKind::Lifetime(re2)) + if re1.is_erased() && re2.is_erased() => + { // no action needed } (GenericArgKind::Lifetime(v1), GenericArgKind::Lifetime(v2)) => { @@ -672,7 +670,7 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> { }); } - fn const_equate(&mut self, _a: &'tcx Const<'tcx>, _b: &'tcx Const<'tcx>) { + fn const_equate(&mut self, _a: Const<'tcx>, _b: Const<'tcx>) { span_bug!( self.cause.span(self.infcx.tcx), "generic_const_exprs: unreachable `const_equate`" diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index a77fd8fae8d..e1b5d04ccfb 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -123,9 +123,9 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { pub fn super_combine_consts<R>( &self, relation: &mut R, - a: &'tcx ty::Const<'tcx>, - b: &'tcx ty::Const<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> + a: ty::Const<'tcx>, + b: ty::Const<'tcx>, + ) -> RelateResult<'tcx, ty::Const<'tcx>> where R: ConstEquateRelation<'tcx>, { @@ -139,7 +139,7 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { let a_is_expected = relation.a_is_expected(); - match (a.val, b.val) { + match (a.val(), b.val()) { ( ty::ConstKind::Infer(InferConst::Var(a_vid)), ty::ConstKind::Infer(InferConst::Var(b_vid)), @@ -226,9 +226,9 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { &self, param_env: ty::ParamEnv<'tcx>, target_vid: ty::ConstVid<'tcx>, - ct: &'tcx ty::Const<'tcx>, + ct: ty::Const<'tcx>, vid_is_expected: bool, - ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { + ) -> RelateResult<'tcx, ty::Const<'tcx>> { let (for_universe, span) = { let mut inner = self.inner.borrow_mut(); let variable_table = &mut inner.const_unification_table(); @@ -451,8 +451,8 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { pub fn add_const_equate_obligation( &mut self, a_is_expected: bool, - a: &'tcx ty::Const<'tcx>, - b: &'tcx ty::Const<'tcx>, + a: ty::Const<'tcx>, + b: ty::Const<'tcx>, ) { let predicate = if a_is_expected { ty::PredicateKind::ConstEquate(a, b) @@ -716,12 +716,12 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { fn consts( &mut self, - c: &'tcx ty::Const<'tcx>, - c2: &'tcx ty::Const<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { + c: ty::Const<'tcx>, + c2: ty::Const<'tcx>, + ) -> RelateResult<'tcx, ty::Const<'tcx>> { assert_eq!(c, c2); // we are abusing TypeRelation here; both LHS and RHS ought to be == - match c.val { + match c.val() { ty::ConstKind::Infer(InferConst::Var(vid)) => { let mut inner = self.infcx.inner.borrow_mut(); let variable_table = &mut inner.const_unification_table(); @@ -739,7 +739,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { origin: var_value.origin, val: ConstVariableValue::Unknown { universe: self.for_universe }, }); - Ok(self.tcx().mk_const_var(new_var_id, c.ty)) + Ok(self.tcx().mk_const_var(new_var_id, c.ty())) } } } @@ -754,8 +754,8 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { substs, substs, )?; - Ok(self.tcx().mk_const(ty::Const { - ty: c.ty, + Ok(self.tcx().mk_const(ty::ConstS { + ty: c.ty(), val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }), })) } @@ -768,7 +768,7 @@ pub trait ConstEquateRelation<'tcx>: TypeRelation<'tcx> { /// Register an obligation that both constants must be equal to each other. /// /// If they aren't equal then the relation doesn't hold. - fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>); + fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>); } pub trait RelateResultCompare<'tcx, T> { @@ -788,7 +788,7 @@ impl<'tcx, T: Clone + PartialEq> RelateResultCompare<'tcx, T> for RelateResult<' pub fn const_unification_error<'tcx>( a_is_expected: bool, - (a, b): (&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>), + (a, b): (ty::Const<'tcx>, ty::Const<'tcx>), ) -> TypeError<'tcx> { TypeError::ConstMismatch(ExpectedFound::new(a_is_expected, a, b)) } @@ -915,7 +915,7 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { debug_assert_eq!(r, _r); debug!("ConstInferUnifier: r={:?}", r); - match r { + match *r { // Never make variables for regions bound within the type itself, // nor for erased regions. ty::ReLateBound(..) | ty::ReErased => { @@ -945,13 +945,13 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { #[tracing::instrument(level = "debug", skip(self))] fn consts( &mut self, - c: &'tcx ty::Const<'tcx>, - _c: &'tcx ty::Const<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { + c: ty::Const<'tcx>, + _c: ty::Const<'tcx>, + ) -> RelateResult<'tcx, ty::Const<'tcx>> { debug_assert_eq!(c, _c); debug!("ConstInferUnifier: c={:?}", c); - match c.val { + match c.val() { ty::ConstKind::Infer(InferConst::Var(vid)) => { // Check if the current unification would end up // unifying `target_vid` with a const which contains @@ -985,7 +985,7 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { }, }, ); - Ok(self.tcx().mk_const_var(new_var_id, c.ty)) + Ok(self.tcx().mk_const_var(new_var_id, c.ty())) } } } @@ -1000,8 +1000,8 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { substs, substs, )?; - Ok(self.tcx().mk_const(ty::Const { - ty: c.ty, + Ok(self.tcx().mk_const(ty::ConstS { + ty: c.ty(), val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }), })) } diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs index 90c0ff9226f..5ac9ad6850c 100644 --- a/compiler/rustc_infer/src/infer/equate.rs +++ b/compiler/rustc_infer/src/infer/equate.rs @@ -117,9 +117,9 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> { fn consts( &mut self, - a: &'tcx ty::Const<'tcx>, - b: &'tcx ty::Const<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { + a: ty::Const<'tcx>, + b: ty::Const<'tcx>, + ) -> RelateResult<'tcx, ty::Const<'tcx>> { self.fields.infcx.super_combine_consts(self, a, b) } @@ -143,7 +143,7 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> { } impl<'tcx> ConstEquateRelation<'tcx> for Equate<'_, '_, 'tcx> { - fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) { + fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) { self.fields.add_const_equate_obligation(self.a_is_expected, a, b); } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index b2de440084c..d900379c44c 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -239,7 +239,7 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>( ); // Explain the region we are capturing. - match hidden_region { + match *hidden_region { ty::ReEmpty(ty::UniverseIndex::ROOT) => { // All lifetimes shorter than the function body are `empty` in // lexical region resolution. The default explanation of "an empty @@ -515,7 +515,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { Err(NonTrivialPath) } - fn print_const(self, _ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> { + fn print_const(self, _ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> { Err(NonTrivialPath) } @@ -915,13 +915,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ) -> Option<()> { for (i, ta) in sub.types().enumerate() { if ta == other_ty { - self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty); + self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, other_ty); return Some(()); } if let ty::Adt(def, _) = ta.kind() { let path_ = self.tcx.def_path_str(def.did); if path_ == other_path { - self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty); + self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, other_ty); return Some(()); } } @@ -1036,7 +1036,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let len2 = sig2.inputs().len(); if len1 == len2 { for (i, (l, r)) in iter::zip(sig1.inputs(), sig2.inputs()).enumerate() { - let (x1, x2) = self.cmp(l, r); + let (x1, x2) = self.cmp(*l, *r); (values.0).0.extend(x1.0); (values.1).0.extend(x2.0); self.push_comma(&mut values.0, &mut values.1, len1, i); @@ -1114,7 +1114,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } fn push_ty_ref<'tcx>( - region: &ty::Region<'tcx>, + region: ty::Region<'tcx>, ty: Ty<'tcx>, mutbl: hir::Mutability, s: &mut DiagnosticStyledString, @@ -1263,7 +1263,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { path1.clone(), sub_no_defaults_1, path2.clone(), - &t2, + t2, ) .is_some() { @@ -1281,7 +1281,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { path2, sub_no_defaults_2, path1, - &t1, + t1, ) .is_some() { @@ -1333,26 +1333,26 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } // When finding T != &T, highlight only the borrow - (&ty::Ref(r1, ref_ty1, mutbl1), _) if equals(&ref_ty1, &t2) => { + (&ty::Ref(r1, ref_ty1, mutbl1), _) if equals(ref_ty1, t2) => { let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new()); - push_ty_ref(&r1, ref_ty1, mutbl1, &mut values.0); + push_ty_ref(r1, ref_ty1, mutbl1, &mut values.0); values.1.push_normal(t2.to_string()); values } - (_, &ty::Ref(r2, ref_ty2, mutbl2)) if equals(&t1, &ref_ty2) => { + (_, &ty::Ref(r2, ref_ty2, mutbl2)) if equals(t1, ref_ty2) => { let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new()); values.0.push_normal(t1.to_string()); - push_ty_ref(&r2, ref_ty2, mutbl2, &mut values.1); + push_ty_ref(r2, ref_ty2, mutbl2, &mut values.1); values } // When encountering &T != &mut T, highlight only the borrow (&ty::Ref(r1, ref_ty1, mutbl1), &ty::Ref(r2, ref_ty2, mutbl2)) - if equals(&ref_ty1, &ref_ty2) => + if equals(ref_ty1, ref_ty2) => { let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new()); - push_ty_ref(&r1, ref_ty1, mutbl1, &mut values.0); - push_ty_ref(&r2, ref_ty2, mutbl2, &mut values.1); + push_ty_ref(r1, ref_ty1, mutbl1, &mut values.0); + push_ty_ref(r2, ref_ty2, mutbl2, &mut values.1); values } @@ -1923,7 +1923,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .iter() .filter(|field| field.vis.is_accessible_from(field.did, self.tcx)) .map(|field| (field.name, field.ty(self.tcx, expected_substs))) - .find(|(_, ty)| same_type_modulo_infer(ty, exp_found.found)) + .find(|(_, ty)| same_type_modulo_infer(*ty, exp_found.found)) { if let ObligationCauseCode::Pattern { span: Some(span), .. } = *cause.code() { if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { @@ -2116,7 +2116,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let [expected_tup_elem] = &expected.tuple_fields().collect::<Vec<_>>()[..] else { return }; - if !same_type_modulo_infer(expected_tup_elem, found) { + if !same_type_modulo_infer(*expected_tup_elem, found) { return; } 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 4c93ec7ab18..a61100d907b 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 @@ -369,7 +369,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn extract_inference_diagnostics_data( &self, arg: GenericArg<'tcx>, - highlight: Option<ty::print::RegionHighlightMode>, + highlight: Option<ty::print::RegionHighlightMode<'tcx>>, ) -> InferenceDiagnosticsData { match arg.unpack() { GenericArgKind::Type(ty) => { @@ -409,7 +409,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } GenericArgKind::Const(ct) => { - match ct.val { + match ct.val() { ty::ConstKind::Infer(InferConst::Var(vid)) => { let origin = self .inner @@ -459,7 +459,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } _ => {} }, - GenericArgKind::Const(c) => match c.val { + GenericArgKind::Const(c) => match c.val() { ty::ConstKind::Infer(InferConst::Var(_)) => { return self.extract_inference_diagnostics_data(s, None); } @@ -553,8 +553,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 +596,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(); @@ -935,9 +933,9 @@ impl<'tcx> ResolvedTypeParamEraser<'tcx> { } /// Replace not yet inferred const params with their def name. - fn replace_infers(&self, c: &'tcx Const<'tcx>, index: u32, name: Symbol) -> &'tcx Const<'tcx> { - match c.val { - ty::ConstKind::Infer(..) => self.tcx().mk_const_param(index, name, c.ty), + fn replace_infers(&self, c: Const<'tcx>, index: u32, name: Symbol) -> Const<'tcx> { + match c.val() { + ty::ConstKind::Infer(..) => self.tcx().mk_const_param(index, name, c.ty()), _ => c, } } @@ -962,7 +960,7 @@ impl<'tcx> TypeFolder<'tcx> for ResolvedTypeParamEraser<'tcx> { .map(|(subst, param)| match &(subst.unpack(), ¶m.kind) { (_, ty::GenericParamDefKind::Type { has_default: true, .. }) => subst, (crate::infer::GenericArgKind::Const(c), _) => { - self.replace_infers(c, param.index, param.name).into() + self.replace_infers(*c, param.index, param.name).into() } _ => subst.super_fold_with(self), }) @@ -985,7 +983,7 @@ impl<'tcx> TypeFolder<'tcx> for ResolvedTypeParamEraser<'tcx> { } } ty::Ref(_, ty, _) => { - let ty = self.fold_ty(ty); + let ty = self.fold_ty(*ty); match ty.kind() { // Avoid `&_`, these can be safely presented as `_`. ty::Error(_) => self.tcx().ty_error(), @@ -1002,7 +1000,7 @@ impl<'tcx> TypeFolder<'tcx> for ResolvedTypeParamEraser<'tcx> { | ty::Projection(_) | ty::Never => t.super_fold_with(self), ty::Array(ty, c) => { - self.tcx().mk_ty(ty::Array(self.fold_ty(ty), self.replace_infers(c, 0, sym::N))) + self.tcx().mk_ty(ty::Array(self.fold_ty(*ty), self.replace_infers(*c, 0, sym::N))) } // We don't want to hide type params that haven't been resolved yet. // This would be the type that will be written out with the type param diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs index d3b47e396ec..ef4c9c24f3e 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs @@ -10,7 +10,7 @@ use rustc_data_structures::stable_set::FxHashSet; use rustc_errors::{Applicability, ErrorReported}; use rustc_hir as hir; use rustc_hir::intravisit::Visitor; -use rustc_middle::ty::{self, TypeVisitor}; +use rustc_middle::ty::TypeVisitor; use rustc_span::MultiSpan; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { @@ -22,7 +22,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { RegionResolutionError::ConcreteFailure(origin, sub, sup) => (origin, sub, sup), _ => return None, }; - if *sub != ty::RegionKind::ReStatic { + if !sub.is_static() { return None; } let cause = match origin { 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 fd295b74342..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,11 +64,11 @@ 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(ConcreteFailure(origin, sub, sup)), None) => Some((origin.span(), *sub, *sup)), (Some(SubSupConflict(_, _, origin, sub, _, sup, _)), None) => { - Some((origin.span(), sub, sup)) + Some((origin.span(), *sub, *sup)) } (None, Some((span, sub, sup))) => Some((span, sub, sup)), _ => None, diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs index eb1c80ecb01..17ff5d45c89 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -48,7 +48,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // Suggesting to add a `'static` lifetime to a parameter is nearly always incorrect, // and can steer users down the wrong path. - if *named == ty::ReStatic { + if named.is_static() { return None; } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs index 7178bfa525b..7d82c60e6d3 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -3,13 +3,14 @@ use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::ValuePairs; use crate::infer::{SubregionOrigin, TypeTrace}; use crate::traits::{ObligationCause, ObligationCauseCode}; +use rustc_data_structures::intern::Interned; use rustc_errors::DiagnosticBuilder; use rustc_hir::def::Namespace; use rustc_hir::def_id::DefId; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::print::{FmtPrinter, Print, RegionHighlightMode}; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, RePlaceholder, ReVar, Region, TyCtxt}; use std::fmt::{self, Write}; @@ -31,15 +32,15 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { vid, _, SubregionOrigin::Subtype(box TypeTrace { cause, values }), - sub_placeholder @ ty::RePlaceholder(_), + sub_placeholder @ Region(Interned(RePlaceholder(_), _)), _, - sup_placeholder @ ty::RePlaceholder(_), + sup_placeholder @ Region(Interned(RePlaceholder(_), _)), _, )) => self.try_report_trait_placeholder_mismatch( - Some(self.tcx().mk_region(ty::ReVar(*vid))), + Some(self.tcx().mk_region(ReVar(*vid))), cause, - Some(sub_placeholder), - Some(sup_placeholder), + Some(*sub_placeholder), + Some(*sup_placeholder), values, ), @@ -47,14 +48,14 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { vid, _, SubregionOrigin::Subtype(box TypeTrace { cause, values }), - sub_placeholder @ ty::RePlaceholder(_), + sub_placeholder @ Region(Interned(RePlaceholder(_), _)), _, _, _, )) => self.try_report_trait_placeholder_mismatch( - Some(self.tcx().mk_region(ty::ReVar(*vid))), + Some(self.tcx().mk_region(ReVar(*vid))), cause, - Some(sub_placeholder), + Some(*sub_placeholder), None, values, ), @@ -65,10 +66,10 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { SubregionOrigin::Subtype(box TypeTrace { cause, values }), _, _, - sup_placeholder @ ty::RePlaceholder(_), + sup_placeholder @ Region(Interned(RePlaceholder(_), _)), _, )) => self.try_report_trait_placeholder_mismatch( - Some(self.tcx().mk_region(ty::ReVar(*vid))), + Some(self.tcx().mk_region(ReVar(*vid))), cause, None, Some(*sup_placeholder), @@ -81,10 +82,10 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { _, _, SubregionOrigin::Subtype(box TypeTrace { cause, values }), - sup_placeholder @ ty::RePlaceholder(_), + sup_placeholder @ Region(Interned(RePlaceholder(_), _)), _, )) => self.try_report_trait_placeholder_mismatch( - Some(self.tcx().mk_region(ty::ReVar(*vid))), + Some(self.tcx().mk_region(ReVar(*vid))), cause, None, Some(*sup_placeholder), @@ -96,9 +97,9 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { _, _, SubregionOrigin::Subtype(box TypeTrace { cause, values }), - sup_placeholder @ ty::RePlaceholder(_), + sup_placeholder @ Region(Interned(RePlaceholder(_), _)), )) => self.try_report_trait_placeholder_mismatch( - Some(self.tcx().mk_region(ty::ReVar(*vid))), + Some(self.tcx().mk_region(ReVar(*vid))), cause, None, Some(*sup_placeholder), @@ -107,8 +108,8 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { Some(RegionResolutionError::ConcreteFailure( SubregionOrigin::Subtype(box TypeTrace { cause, values }), - sub_region @ ty::RePlaceholder(_), - sup_region @ ty::RePlaceholder(_), + sub_region @ Region(Interned(RePlaceholder(_), _)), + sup_region @ Region(Interned(RePlaceholder(_), _)), )) => self.try_report_trait_placeholder_mismatch( None, cause, @@ -119,12 +120,12 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { Some(RegionResolutionError::ConcreteFailure( SubregionOrigin::Subtype(box TypeTrace { cause, values }), - sub_region @ ty::RePlaceholder(_), + sub_region @ Region(Interned(RePlaceholder(_), _)), sup_region, )) => self.try_report_trait_placeholder_mismatch( - (!sup_region.has_name()).then_some(sup_region), + (!sup_region.has_name()).then_some(*sup_region), cause, - Some(sub_region), + Some(*sub_region), None, values, ), @@ -132,12 +133,12 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { Some(RegionResolutionError::ConcreteFailure( SubregionOrigin::Subtype(box TypeTrace { cause, values }), sub_region, - sup_region @ ty::RePlaceholder(_), + sup_region @ Region(Interned(RePlaceholder(_), _)), )) => self.try_report_trait_placeholder_mismatch( - (!sub_region.has_name()).then_some(sub_region), + (!sub_region.has_name()).then_some(*sub_region), cause, None, - Some(sup_region), + Some(*sup_region), values, ), @@ -147,10 +148,10 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { fn try_report_trait_placeholder_mismatch( &self, - vid: Option<ty::Region<'tcx>>, + vid: Option<Region<'tcx>>, cause: &ObligationCause<'tcx>, - sub_placeholder: Option<ty::Region<'tcx>>, - sup_placeholder: Option<ty::Region<'tcx>>, + sub_placeholder: Option<Region<'tcx>>, + sup_placeholder: Option<Region<'tcx>>, value_pairs: &ValuePairs<'tcx>, ) -> Option<DiagnosticBuilder<'tcx>> { let (expected_substs, found_substs, trait_def_id) = match value_pairs { @@ -193,10 +194,10 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { #[instrument(level = "debug", skip(self))] fn report_trait_placeholder_mismatch( &self, - vid: Option<ty::Region<'tcx>>, + vid: Option<Region<'tcx>>, cause: &ObligationCause<'tcx>, - sub_placeholder: Option<ty::Region<'tcx>>, - sup_placeholder: Option<ty::Region<'tcx>>, + sub_placeholder: Option<Region<'tcx>>, + sup_placeholder: Option<Region<'tcx>>, trait_def_id: DefId, expected_substs: SubstsRef<'tcx>, actual_substs: SubstsRef<'tcx>, @@ -306,13 +307,13 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { fn explain_actual_impl_that_was_found( &self, err: &mut DiagnosticBuilder<'_>, - sub_placeholder: Option<ty::Region<'tcx>>, - sup_placeholder: Option<ty::Region<'tcx>>, + sub_placeholder: Option<Region<'tcx>>, + sup_placeholder: Option<Region<'tcx>>, has_sub: Option<usize>, has_sup: Option<usize>, expected_trait_ref: ty::TraitRef<'tcx>, actual_trait_ref: ty::TraitRef<'tcx>, - vid: Option<ty::Region<'tcx>>, + vid: Option<Region<'tcx>>, expected_has_vid: Option<usize>, actual_has_vid: Option<usize>, any_self_ty_has_vid: bool, @@ -322,7 +323,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { #[derive(Copy, Clone)] struct Highlighted<'tcx, T> { tcx: TyCtxt<'tcx>, - highlight: RegionHighlightMode, + highlight: RegionHighlightMode<'tcx>, value: T, } @@ -366,7 +367,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { let highlight_trait_ref = |trait_ref| Highlighted { tcx: self.tcx(), - highlight: RegionHighlightMode::default(), + highlight: RegionHighlightMode::new(self.tcx()), value: trait_ref, }; diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 0a9f59fbc97..625fd864218 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -10,8 +10,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{walk_ty, Visitor}; use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind}; use rustc_middle::ty::{ - self, AssocItemContainer, RegionKind, StaticLifetimeVisitor, Ty, TyCtxt, TypeFoldable, - TypeVisitor, + self, AssocItemContainer, StaticLifetimeVisitor, Ty, TyCtxt, TypeFoldable, TypeVisitor, }; use rustc_span::symbol::Ident; use rustc_span::{MultiSpan, Span}; @@ -33,25 +32,23 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { sup_origin, sup_r, spans, - ) if **sub_r == RegionKind::ReStatic => { - (var_origin, sub_origin, sub_r, sup_origin, sup_r, spans) - } + ) if sub_r.is_static() => (var_origin, sub_origin, sub_r, sup_origin, sup_r, spans), RegionResolutionError::ConcreteFailure( SubregionOrigin::Subtype(box TypeTrace { cause, .. }), sub_r, sup_r, - ) if **sub_r == RegionKind::ReStatic => { + ) if sub_r.is_static() => { // This is for an implicit `'static` requirement coming from `impl dyn Trait {}`. if let ObligationCauseCode::UnifyReceiver(ctxt) = cause.code() { // This may have a closure and it would cause ICE // through `find_param_with_region` (#78262). - let anon_reg_sup = tcx.is_suitable_region(sup_r)?; + let anon_reg_sup = tcx.is_suitable_region(*sup_r)?; let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id); if fn_returns.is_empty() { return None; } - let param = self.find_param_with_region(sup_r, sub_r)?; + let param = self.find_param_with_region(*sup_r, *sub_r)?; let lifetime = if sup_r.has_name() { format!("lifetime `{}`", sup_r) } else { @@ -101,11 +98,11 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})", var_origin, sub_origin, sub_r, sup_origin, sup_r ); - let anon_reg_sup = tcx.is_suitable_region(sup_r)?; + let anon_reg_sup = tcx.is_suitable_region(*sup_r)?; debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup); let sp = var_origin.span(); let return_sp = sub_origin.span(); - let param = self.find_param_with_region(sup_r, sub_r)?; + let param = self.find_param_with_region(*sup_r, *sub_r)?; let (lifetime_name, lifetime) = if sup_r.has_name() { (sup_r.to_string(), format!("lifetime `{}`", sup_r)) } else { @@ -560,7 +557,7 @@ pub(super) struct TraitObjectVisitor(pub(super) FxHashSet<DefId>); impl<'tcx> TypeVisitor<'tcx> for TraitObjectVisitor { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { match t.kind() { - ty::Dynamic(preds, RegionKind::ReStatic) => { + ty::Dynamic(preds, re) if re.is_static() => { if let Some(def_id) = preds.principal_def_id() { self.0.insert(def_id); } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs index a79ed20730b..9216fa3ca1d 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -42,8 +42,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { if sup_expected_found == sub_expected_found { self.emit_err( var_origin.span(), - sub_expected, - sub_found, + *sub_expected, + *sub_found, *trait_item_def_id, ); return Some(ErrorReported); @@ -81,21 +81,21 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // Mark all unnamed regions in the type with a number. // This diagnostic is called in response to lifetime errors, so be informative. - struct HighlightBuilder { - highlight: RegionHighlightMode, + struct HighlightBuilder<'tcx> { + highlight: RegionHighlightMode<'tcx>, counter: usize, } - impl HighlightBuilder { - fn build(ty: Ty<'_>) -> RegionHighlightMode { + impl<'tcx> HighlightBuilder<'tcx> { + fn build(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> RegionHighlightMode<'tcx> { let mut builder = - HighlightBuilder { highlight: RegionHighlightMode::default(), counter: 1 }; + HighlightBuilder { highlight: RegionHighlightMode::new(tcx), counter: 1 }; builder.visit_ty(ty); builder.highlight } } - impl<'tcx> ty::fold::TypeVisitor<'tcx> for HighlightBuilder { + impl<'tcx> ty::fold::TypeVisitor<'tcx> for HighlightBuilder<'tcx> { fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { if !r.has_name() && self.counter <= 3 { self.highlight.highlighting_region(r, self.counter); @@ -105,12 +105,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } } - let expected_highlight = HighlightBuilder::build(expected); + let expected_highlight = HighlightBuilder::build(self.tcx(), expected); let expected = self .infcx .extract_inference_diagnostics_data(expected.into(), Some(expected_highlight)) .name; - let found_highlight = HighlightBuilder::build(found); + let found_highlight = HighlightBuilder::build(self.tcx(), found); let found = self.infcx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name; @@ -203,7 +203,8 @@ impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> { .map(|res| { matches!( res, - Res::SelfTy(_, _) | Res::Def(hir::def::DefKind::TyParam, _) + Res::SelfTy { trait_: _, alias_to: _ } + | Res::Def(hir::def::DefKind::TyParam, _) ) }) .unwrap_or(false) => diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs index 6d71d702cc8..719f6b37a43 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs @@ -70,7 +70,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let ty = fn_sig.inputs()[index]; let mut found_anon_region = false; let new_param_ty = self.tcx().fold_regions(ty, &mut false, |r, _| { - if *r == *anon_region { + if r == anon_region { found_anon_region = true; replace_region } else { diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index 82bd8890dda..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); + } } } @@ -115,7 +118,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { infer::Subtype(box trace) => { let terr = TypeError::RegionsDoesNotOutlive(sup, sub); let mut err = self.report_and_explain_type_error(trace, &terr); - match (sub, sup) { + match (*sub, *sup) { (ty::RePlaceholder(_), ty::RePlaceholder(_)) => {} (ty::RePlaceholder(_), _) => { note_and_explain_region( @@ -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/free_regions.rs b/compiler/rustc_infer/src/infer/free_regions.rs index e93cdf79421..187c67df3eb 100644 --- a/compiler/rustc_infer/src/infer/free_regions.rs +++ b/compiler/rustc_infer/src/infer/free_regions.rs @@ -41,8 +41,8 @@ pub struct FreeRegionMap<'tcx> { } impl<'tcx> FreeRegionMap<'tcx> { - pub fn elements(&self) -> impl Iterator<Item = &Region<'tcx>> { - self.relation.elements() + pub fn elements(&self) -> impl Iterator<Item = Region<'tcx>> + '_ { + self.relation.elements().copied() } pub fn is_empty(&self) -> bool { @@ -91,7 +91,7 @@ impl<'tcx> FreeRegionMap<'tcx> { /// True for free regions other than `'static`. pub fn is_free(&self, r: Region<'_>) -> bool { - matches!(r, ty::ReEarlyBound(_) | ty::ReFree(_)) + matches!(*r, ty::ReEarlyBound(_) | ty::ReFree(_)) } /// True if `r` is a free region or static of the sort that this diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index 4af1bdf97a7..e9d3b6a8aa1 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -46,7 +46,7 @@ pub struct TypeFreshener<'a, 'tcx> { ty_freshen_count: u32, const_freshen_count: u32, ty_freshen_map: FxHashMap<ty::InferTy, Ty<'tcx>>, - const_freshen_map: FxHashMap<ty::InferConst<'tcx>, &'tcx ty::Const<'tcx>>, + const_freshen_map: FxHashMap<ty::InferConst<'tcx>, ty::Const<'tcx>>, keep_static: bool, } @@ -89,11 +89,11 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> { fn freshen_const<F>( &mut self, - opt_ct: Option<&'tcx ty::Const<'tcx>>, + opt_ct: Option<ty::Const<'tcx>>, key: ty::InferConst<'tcx>, freshener: F, ty: Ty<'tcx>, - ) -> &'tcx ty::Const<'tcx> + ) -> ty::Const<'tcx> where F: FnOnce(u32) -> ty::InferConst<'tcx>, { @@ -221,8 +221,8 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { } } - fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - match ct.val { + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + match ct.val() { ty::ConstKind::Infer(ty::InferConst::Var(v)) => { let opt_ct = self .infcx @@ -236,7 +236,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { opt_ct, ty::InferConst::Var(v), ty::InferConst::Fresh, - ct.ty, + ct.ty(), ); } ty::ConstKind::Infer(ty::InferConst::Fresh(i)) => { diff --git a/compiler/rustc_infer/src/infer/fudge.rs b/compiler/rustc_infer/src/infer/fudge.rs index 773753a0363..c5c131a5b79 100644 --- a/compiler/rustc_infer/src/infer/fudge.rs +++ b/compiler/rustc_infer/src/infer/fudge.rs @@ -230,14 +230,14 @@ impl<'a, 'tcx> TypeFolder<'tcx> for InferenceFudger<'a, 'tcx> { r } - fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - if let ty::Const { val: ty::ConstKind::Infer(ty::InferConst::Var(vid)), ty } = ct { + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.val() { if self.const_vars.0.contains(&vid) { // This variable was created during the fudging. // Recreate it with a fresh variable here. let idx = (vid.index - self.const_vars.0.start.index) as usize; let origin = self.const_vars.1[idx]; - self.infcx.next_const_var(ty, origin) + self.infcx.next_const_var(ct.ty(), origin) } else { ct } diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs index 862f5a5fbb8..381097344ec 100644 --- a/compiler/rustc_infer/src/infer/glb.rs +++ b/compiler/rustc_infer/src/infer/glb.rs @@ -78,9 +78,9 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> { fn consts( &mut self, - a: &'tcx ty::Const<'tcx>, - b: &'tcx ty::Const<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { + a: ty::Const<'tcx>, + b: ty::Const<'tcx>, + ) -> RelateResult<'tcx, ty::Const<'tcx>> { self.fields.infcx.super_combine_consts(self, a, b) } @@ -120,7 +120,7 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx, } impl<'tcx> ConstEquateRelation<'tcx> for Glb<'_, '_, 'tcx> { - fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) { + fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) { self.fields.add_const_equate_obligation(self.a_is_expected, a, b); } } diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs index ae85e55da6a..82454b89156 100644 --- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs +++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs @@ -94,7 +94,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }; let fld_c = |bound_var: ty::BoundVar, ty| { - self.tcx.mk_const(ty::Const { + self.tcx.mk_const(ty::ConstS { val: ty::ConstKind::Placeholder(ty::PlaceholderConst { universe: next_universe, name: ty::BoundConst { var: bound_var, ty }, diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index a5ec84a4f14..4e50585ff52 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -13,6 +13,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::graph::implementation::{ Direction, Graph, NodeIndex, INCOMING, OUTGOING, }; +use rustc_data_structures::intern::Interned; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -61,6 +62,7 @@ pub(crate) fn resolve<'tcx>( /// Contains the result of lexical region resolution. Offers methods /// to lookup up the final value of a region variable. +#[derive(Clone)] pub struct LexicalRegionResolutions<'tcx> { values: IndexVec<RegionVid, VarValue<'tcx>>, error_region: ty::Region<'tcx>, @@ -249,8 +251,8 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { changes.push(b_vid); } if let Some(a_vid) = a_vid { - match *b_data { - VarValue::Value(ReStatic) | VarValue::ErrorValue => (), + match b_data { + VarValue::Value(Region(Interned(ReStatic, _))) | VarValue::ErrorValue => (), _ => { constraints[a_vid].push((a_vid, b_vid)); constraints[b_vid].push((a_vid, b_vid)); @@ -269,7 +271,10 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { if self.expand_node(a_region, b_vid, b_data) { changes.push(b_vid); } - !matches!(b_data, VarValue::Value(ReStatic) | VarValue::ErrorValue) + !matches!( + b_data, + VarValue::Value(Region(Interned(ReStatic, _))) | VarValue::ErrorValue + ) }); } } @@ -300,8 +305,8 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // check below for a common case, here purely as an // optimization. let b_universe = self.var_infos[b_vid].universe; - if let ReEmpty(a_universe) = a_region { - if *a_universe == b_universe { + if let ReEmpty(a_universe) = *a_region { + if a_universe == b_universe { return false; } } @@ -320,7 +325,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // tighter bound than `'static`. // // (This might e.g. arise from being asked to prove `for<'a> { 'b: 'a }`.) - if let ty::RePlaceholder(p) = lub { + if let ty::RePlaceholder(p) = *lub { if b_universe.cannot_name(p.universe) { lub = self.tcx().lifetimes.re_static; } @@ -371,12 +376,12 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { /// term "concrete regions"). #[instrument(level = "trace", skip(self))] fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> { - let r = match (a, b) { - (&ReLateBound(..), _) | (_, &ReLateBound(..)) | (&ReErased, _) | (_, &ReErased) => { + let r = match (*a, *b) { + (ReLateBound(..), _) | (_, ReLateBound(..)) | (ReErased, _) | (_, ReErased) => { bug!("cannot relate region: LUB({:?}, {:?})", a, b); } - (&ReVar(v_id), _) | (_, &ReVar(v_id)) => { + (ReVar(v_id), _) | (_, ReVar(v_id)) => { span_bug!( self.var_infos[v_id].origin.span(), "lub_concrete_regions invoked with non-concrete \ @@ -386,27 +391,32 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { ); } - (&ReStatic, _) | (_, &ReStatic) => { + (ReStatic, _) | (_, ReStatic) => { // nothing lives longer than `'static` self.tcx().lifetimes.re_static } - (&ReEmpty(_), r @ (ReEarlyBound(_) | ReFree(_))) - | (r @ (ReEarlyBound(_) | ReFree(_)), &ReEmpty(_)) => { + (ReEmpty(_), ReEarlyBound(_) | ReFree(_)) => { // All empty regions are less than early-bound, free, // and scope regions. - r + b } - (&ReEmpty(a_ui), &ReEmpty(b_ui)) => { + (ReEarlyBound(_) | ReFree(_), ReEmpty(_)) => { + // All empty regions are less than early-bound, free, + // and scope regions. + a + } + + (ReEmpty(a_ui), ReEmpty(b_ui)) => { // Empty regions are ordered according to the universe // they are associated with. let ui = a_ui.min(b_ui); self.tcx().mk_region(ReEmpty(ui)) } - (&ReEmpty(empty_ui), &RePlaceholder(placeholder)) - | (&RePlaceholder(placeholder), &ReEmpty(empty_ui)) => { + (ReEmpty(empty_ui), RePlaceholder(placeholder)) + | (RePlaceholder(placeholder), ReEmpty(empty_ui)) => { // If this empty region is from a universe that can // name the placeholder, then the placeholder is // larger; otherwise, the only ancestor is `'static`. @@ -417,13 +427,13 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } } - (&ReEarlyBound(_) | &ReFree(_), &ReEarlyBound(_) | &ReFree(_)) => { + (ReEarlyBound(_) | ReFree(_), ReEarlyBound(_) | ReFree(_)) => { self.region_rels.lub_free_regions(a, b) } // For these types, we cannot define any additional // relationship: - (&RePlaceholder(..), _) | (_, &RePlaceholder(..)) => { + (RePlaceholder(..), _) | (_, RePlaceholder(..)) => { if a == b { a } else { @@ -675,7 +685,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { let node_universe = self.var_infos[node_idx].universe; for lower_bound in &lower_bounds { - let effective_lower_bound = if let ty::RePlaceholder(p) = lower_bound.region { + let effective_lower_bound = if let ty::RePlaceholder(p) = *lower_bound.region { if node_universe.cannot_name(p.universe) { self.tcx().lifetimes.re_static } else { @@ -720,7 +730,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { .expect("lower_vid_bounds should at least include `node_idx`"); for upper_bound in &upper_bounds { - if let ty::RePlaceholder(p) = upper_bound.region { + if let ty::RePlaceholder(p) = *upper_bound.region { if min_universe.cannot_name(p.universe) { let origin = self.var_infos[node_idx].origin; errors.push(RegionResolutionError::UpperBoundUniverseConflict( @@ -854,11 +864,11 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } VerifyBound::OutlivedBy(r) => { - self.sub_concrete_regions(min, var_values.normalize(self.tcx(), r)) + self.sub_concrete_regions(min, var_values.normalize(self.tcx(), *r)) } VerifyBound::IsEmpty => { - matches!(min, ty::ReEmpty(_)) + matches!(*min, ty::ReEmpty(_)) } VerifyBound::AnyBound(bs) => { @@ -883,8 +893,8 @@ impl<'tcx> LexicalRegionResolutions<'tcx> { where T: TypeFoldable<'tcx>, { - tcx.fold_regions(value, &mut false, |r, _db| match r { - ty::ReVar(rid) => self.resolve_var(*rid), + tcx.fold_regions(value, &mut false, |r, _db| match *r { + ty::ReVar(rid) => self.resolve_var(rid), _ => r, }) } diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs index 5191d1c1cc1..57cbe2c54f7 100644 --- a/compiler/rustc_infer/src/infer/lub.rs +++ b/compiler/rustc_infer/src/infer/lub.rs @@ -78,9 +78,9 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> { fn consts( &mut self, - a: &'tcx ty::Const<'tcx>, - b: &'tcx ty::Const<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { + a: ty::Const<'tcx>, + b: ty::Const<'tcx>, + ) -> RelateResult<'tcx, ty::Const<'tcx>> { self.fields.infcx.super_combine_consts(self, a, b) } @@ -103,7 +103,7 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> { } impl<'tcx> ConstEquateRelation<'tcx> for Lub<'_, '_, 'tcx> { - fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) { + fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) { self.fields.add_const_equate_obligation(self.a_is_expected, a, b); } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index c18d36d1f74..57ac98ca897 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -130,6 +130,7 @@ impl RegionckMode { /// `RefCell` and are involved with taking/rolling back snapshots. Snapshot /// operations are hot enough that we want only one call to `borrow_mut` per /// call to `start_snapshot` and `rollback_to`. +#[derive(Clone)] pub struct InferCtxtInner<'tcx> { /// Cache for projections. This cache is snapshotted along with the infcx. /// @@ -381,7 +382,7 @@ impl<'tcx> ValuePairs<'tcx> { found: ty::Term::Ty(found), }) = self { - Some((expected, found)) + Some((*expected, *found)) } else { None } @@ -437,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. @@ -1078,11 +1086,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.tcx.mk_ty_var(vid) } - pub fn next_const_var( - &self, - ty: Ty<'tcx>, - origin: ConstVariableOrigin, - ) -> &'tcx ty::Const<'tcx> { + pub fn next_const_var(&self, ty: Ty<'tcx>, origin: ConstVariableOrigin) -> ty::Const<'tcx> { self.tcx.mk_const_var(self.next_const_var_id(origin), ty) } @@ -1091,7 +1095,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ty: Ty<'tcx>, origin: ConstVariableOrigin, universe: ty::UniverseIndex, - ) -> &'tcx ty::Const<'tcx> { + ) -> ty::Const<'tcx> { let vid = self .inner .borrow_mut() @@ -1434,7 +1438,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn probe_const_var( &self, vid: ty::ConstVid<'tcx>, - ) -> Result<&'tcx ty::Const<'tcx>, ty::UniverseIndex> { + ) -> Result<ty::Const<'tcx>, ty::UniverseIndex> { match self.inner.borrow_mut().const_unification_table().probe_value(vid).val { ConstVariableValue::Known { value } => Ok(value), ConstVariableValue::Unknown { universe } => Err(universe), @@ -1500,8 +1504,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn report_mismatched_consts( &self, cause: &ObligationCause<'tcx>, - expected: &'tcx ty::Const<'tcx>, - actual: &'tcx ty::Const<'tcx>, + expected: ty::Const<'tcx>, + actual: ty::Const<'tcx>, err: TypeError<'tcx>, ) -> DiagnosticBuilder<'tcx> { let trace = TypeTrace::consts(cause, true, expected, actual); @@ -1755,8 +1759,8 @@ impl<'tcx> TyOrConstInferVar<'tcx> { /// Tries to extract an inference variable from a constant, returns `None` /// for constants other than `ty::ConstKind::Infer(_)` (or `InferConst::Fresh`). - pub fn maybe_from_const(ct: &'tcx ty::Const<'tcx>) -> Option<Self> { - match ct.val { + pub fn maybe_from_const(ct: ty::Const<'tcx>) -> Option<Self> { + match ct.val() { ty::ConstKind::Infer(InferConst::Var(v)) => Some(TyOrConstInferVar::Const(v)), _ => None, } @@ -1776,13 +1780,13 @@ impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> { self.infcx.shallow_resolve_ty(ty) } - fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - if let ty::Const { val: ty::ConstKind::Infer(InferConst::Var(vid)), .. } = ct { + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val() { self.infcx .inner .borrow_mut() .const_unification_table() - .probe_value(*vid) + .probe_value(vid) .val .known() .unwrap_or(ct) @@ -1812,8 +1816,8 @@ impl<'tcx> TypeTrace<'tcx> { pub fn consts( cause: &ObligationCause<'tcx>, a_is_expected: bool, - a: &'tcx ty::Const<'tcx>, - b: &'tcx ty::Const<'tcx>, + a: ty::Const<'tcx>, + b: ty::Const<'tcx>, ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), @@ -1835,6 +1839,7 @@ impl<'tcx> SubregionOrigin<'tcx> { ReferenceOutlivesReferent(_, a) => a, CompareImplMethodObligation { span, .. } => span, CompareImplTypeObligation { span, .. } => span, + CheckAssociatedTypeBounds { ref parent, .. } => parent.span(), } } @@ -1865,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/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 0a210ed053c..60f776d8c1f 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -87,7 +87,7 @@ pub trait TypeRelatingDelegate<'tcx> { info: ty::VarianceDiagInfo<'tcx>, ); - fn const_equate(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>); + fn const_equate(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>); /// Creates a new universe index. Used when instantiating placeholders. fn create_next_universe(&mut self) -> ty::UniverseIndex; @@ -244,8 +244,8 @@ where scopes: &[BoundRegionScope<'tcx>], ) -> ty::Region<'tcx> { debug!("replace_bound_regions(scopes={:?})", scopes); - if let ty::ReLateBound(debruijn, br) = r { - Self::lookup_bound_region(*debruijn, br, first_free_index, scopes) + if let ty::ReLateBound(debruijn, br) = *r { + Self::lookup_bound_region(debruijn, &br, first_free_index, scopes) } else { r } @@ -450,7 +450,7 @@ impl<'tcx> VidValuePair<'tcx> for (ty::TyVid, Ty<'tcx>) { where D: TypeRelatingDelegate<'tcx>, { - relate.relate(&generalized_ty, &self.value_ty()) + relate.relate(generalized_ty, self.value_ty()) } } @@ -482,7 +482,7 @@ impl<'tcx> VidValuePair<'tcx> for (Ty<'tcx>, ty::TyVid) { where D: TypeRelatingDelegate<'tcx>, { - relate.relate(&self.value_ty(), &generalized_ty) + relate.relate(self.value_ty(), generalized_ty) } } @@ -609,16 +609,16 @@ where fn consts( &mut self, - a: &'tcx ty::Const<'tcx>, - mut b: &'tcx ty::Const<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { + a: ty::Const<'tcx>, + mut b: ty::Const<'tcx>, + ) -> RelateResult<'tcx, ty::Const<'tcx>> { let a = self.infcx.shallow_resolve(a); if !D::forbid_inference_vars() { b = self.infcx.shallow_resolve(b); } - match b.val { + match b.val() { ty::ConstKind::Infer(InferConst::Var(_)) if D::forbid_inference_vars() => { // Forbid inference variables in the RHS. bug!("unexpected inference var {:?}", b) @@ -745,7 +745,7 @@ impl<'tcx, D> ConstEquateRelation<'tcx> for TypeRelating<'_, 'tcx, D> where D: TypeRelatingDelegate<'tcx>, { - fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) { + fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) { self.delegate.const_equate(a, b); } } @@ -779,9 +779,9 @@ impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> { fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { let ScopeInstantiator { bound_region_scope, next_region, .. } = self; - match r { - ty::ReLateBound(debruijn, br) if *debruijn == self.target_index => { - bound_region_scope.map.entry(*br).or_insert_with(|| next_region(*br)); + match *r { + ty::ReLateBound(debruijn, br) if debruijn == self.target_index => { + bound_region_scope.map.entry(br).or_insert_with(|| next_region(br)); } _ => {} @@ -963,8 +963,8 @@ where ) -> RelateResult<'tcx, ty::Region<'tcx>> { debug!("TypeGeneralizer::regions(a={:?})", a); - if let ty::ReLateBound(debruijn, _) = a { - if *debruijn < self.first_free_index { + if let ty::ReLateBound(debruijn, _) = *a { + if debruijn < self.first_free_index { return Ok(a); } } @@ -992,10 +992,10 @@ where fn consts( &mut self, - a: &'tcx ty::Const<'tcx>, - _: &'tcx ty::Const<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { - match a.val { + a: ty::Const<'tcx>, + _: ty::Const<'tcx>, + ) -> RelateResult<'tcx, ty::Const<'tcx>> { + match a.val() { ty::ConstKind::Infer(InferConst::Var(_)) if D::forbid_inference_vars() => { bug!("unexpected inference variable encountered in NLL generalization: {:?}", a); } @@ -1010,7 +1010,7 @@ where origin: var_value.origin, val: ConstVariableValue::Unknown { universe: self.universe }, }); - Ok(self.tcx().mk_const_var(new_var_id, a.ty)) + Ok(self.tcx().mk_const_var(new_var_id, a.ty())) } } } 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/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs index 3947282aa62..bd8bb9e1fa9 100644 --- a/compiler/rustc_infer/src/infer/outlives/env.rs +++ b/compiler/rustc_infer/src/infer/outlives/env.rs @@ -2,8 +2,9 @@ use crate::infer::free_regions::FreeRegionMap; use crate::infer::{GenericKind, InferCtxt}; use crate::traits::query::OutlivesBound; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::intern::Interned; use rustc_hir as hir; -use rustc_middle::ty; +use rustc_middle::ty::{self, ReEarlyBound, ReFree, ReVar, Region}; use super::explicit_outlives_bounds; @@ -66,7 +67,7 @@ pub struct OutlivesEnvironment<'tcx> { /// "Region-bound pairs" tracks outlives relations that are known to /// be true, either because of explicit where-clauses like `T: 'a` or /// because of implied bounds. -pub type RegionBoundPairs<'tcx> = Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>; +pub type RegionBoundPairs<'tcx> = Vec<(Region<'tcx>, GenericKind<'tcx>)>; impl<'a, 'tcx> OutlivesEnvironment<'tcx> { pub fn new(param_env: ty::ParamEnv<'tcx>) -> Self { @@ -164,10 +165,10 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> { debug!("add_outlives_bounds: outlives_bound={:?}", outlives_bound); match outlives_bound { OutlivesBound::RegionSubRegion( - r_a @ (&ty::ReEarlyBound(_) | &ty::ReFree(_)), - &ty::ReVar(vid_b), + r_a @ (Region(Interned(ReEarlyBound(_), _)) | Region(Interned(ReFree(_), _))), + Region(Interned(ReVar(vid_b), _)), ) => { - infcx.expect("no infcx provided but region vars found").add_given(r_a, vid_b); + infcx.expect("no infcx provided but region vars found").add_given(r_a, *vid_b); } OutlivesBound::RegionSubParam(r_a, param_b) => { self.region_bound_pairs_accum.push((r_a, GenericKind::Param(param_b))); diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index a5276afc5bf..0224aba01ef 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -285,7 +285,7 @@ where let origin = origin.clone(); match component { Component::Region(region1) => { - self.delegate.push_sub_region_constraint(origin, region, region1); + self.delegate.push_sub_region_constraint(origin, region, *region1); } Component::Param(param_ty) => { self.param_ty_must_outlive(origin, region, *param_ty); diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs index 2d4c1e5d050..36d18aebfe2 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs @@ -154,17 +154,17 @@ impl<'me, 'tcx> LeakCheck<'me, 'tcx> { let scc = self.mini_graph.sccs.scc(*leak_check_node); // Set the universe of each SCC to be the minimum of its constituent universes - let universe = self.rcc.universe(region); + let universe = self.rcc.universe(*region); debug!( "assign_placeholder_values: scc={:?} universe={:?} region={:?}", scc, universe, region ); - self.scc_universes[scc].take_min(universe, region); + self.scc_universes[scc].take_min(universe, *region); // Detect those SCCs that directly contain a placeholder - if let ty::RePlaceholder(placeholder) = region { + if let ty::RePlaceholder(placeholder) = **region { if self.universe_at_start_of_snapshot.cannot_name(placeholder.universe) { - self.assign_scc_value(scc, *placeholder)?; + self.assign_scc_value(scc, placeholder)?; } } } diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index 29775a96685..a5bd3b15c8d 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -8,6 +8,7 @@ use super::{ }; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::intern::Interned; use rustc_data_structures::sync::Lrc; use rustc_data_structures::undo_log::UndoLogs; use rustc_data_structures::unify as ut; @@ -28,7 +29,7 @@ mod leak_check; pub use rustc_middle::infer::MemberConstraint; -#[derive(Default)] +#[derive(Clone, Default)] pub struct RegionConstraintStorage<'tcx> { /// For each `RegionVid`, the corresponding `RegionVariableOrigin`. var_infos: IndexVec<RegionVid, RegionVariableInfo>, @@ -502,14 +503,15 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { self.make_subregion(origin, sup, sub); match (sub, sup) { - (&ty::ReVar(sub), &ty::ReVar(sup)) => { + (Region(Interned(ReVar(sub), _)), Region(Interned(ReVar(sup), _))) => { debug!("make_eqregion: unifying {:?} with {:?}", sub, sup); - self.unification_table().union(sub, sup); + self.unification_table().union(*sub, *sup); self.any_unifications = true; } - (&ty::ReVar(vid), value) | (value, &ty::ReVar(vid)) => { + (Region(Interned(ReVar(vid), _)), value) + | (value, Region(Interned(ReVar(vid), _))) => { debug!("make_eqregion: unifying {:?} with {:?}", vid, value); - self.unification_table().union_value(vid, UnifiedRegion(Some(value))); + self.unification_table().union_value(*vid, UnifiedRegion(Some(value))); self.any_unifications = true; } (_, _) => {} @@ -550,20 +552,20 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { // cannot add constraints once regions are resolved debug!("origin = {:#?}", origin); - match (sub, sup) { - (&ReLateBound(..), _) | (_, &ReLateBound(..)) => { + match (*sub, *sup) { + (ReLateBound(..), _) | (_, ReLateBound(..)) => { span_bug!(origin.span(), "cannot relate bound region: {:?} <= {:?}", sub, sup); } - (_, &ReStatic) => { + (_, ReStatic) => { // all regions are subregions of static, so we can ignore this } - (&ReVar(sub_id), &ReVar(sup_id)) => { + (ReVar(sub_id), ReVar(sup_id)) => { self.add_constraint(Constraint::VarSubVar(sub_id, sup_id), origin); } - (_, &ReVar(sup_id)) => { + (_, ReVar(sup_id)) => { self.add_constraint(Constraint::RegSubVar(sub, sup_id), origin); } - (&ReVar(sub_id), _) => { + (ReVar(sub_id), _) => { self.add_constraint(Constraint::VarSubReg(sub_id, sup), origin); } _ => { @@ -591,16 +593,12 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { ) -> Region<'tcx> { // cannot add constraints once regions are resolved debug!("RegionConstraintCollector: lub_regions({:?}, {:?})", a, b); - match (a, b) { - (r @ &ReStatic, _) | (_, r @ &ReStatic) => { - r // nothing lives longer than static - } - - _ if a == b => { - a // LUB(a,a) = a - } - - _ => self.combine_vars(tcx, Lub, a, b, origin), + if a.is_static() || b.is_static() { + a // nothing lives longer than static + } else if a == b { + a // LUB(a,a) = a + } else { + self.combine_vars(tcx, Lub, a, b, origin) } } @@ -613,16 +611,14 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { ) -> Region<'tcx> { // cannot add constraints once regions are resolved debug!("RegionConstraintCollector: glb_regions({:?}, {:?})", a, b); - match (a, b) { - (&ReStatic, r) | (r, &ReStatic) => { - r // static lives longer than everything else - } - - _ if a == b => { - a // GLB(a,a) = a - } - - _ => self.combine_vars(tcx, Glb, a, b, origin), + if a.is_static() { + b // static lives longer than everything else + } else if b.is_static() { + a // static lives longer than everything else + } else if a == b { + a // GLB(a,a) = a + } else { + self.combine_vars(tcx, Glb, a, b, origin) } } @@ -639,11 +635,11 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { tcx: TyCtxt<'tcx>, region: ty::Region<'tcx>, ) -> ty::Region<'tcx> { - match region { + match *region { ty::ReVar(rid) => { - let unified_region = self.unification_table().probe_value(*rid); + let unified_region = self.unification_table().probe_value(rid); unified_region.0.unwrap_or_else(|| { - let root = self.unification_table().find(*rid).vid; + let root = self.unification_table().find(rid).vid; tcx.reuse_or_mk_region(region, ty::ReVar(root)) }) } @@ -767,8 +763,7 @@ impl<'tcx> VerifyBound<'tcx> { pub fn must_hold(&self) -> bool { match self { VerifyBound::IfEq(..) => false, - VerifyBound::OutlivedBy(ty::ReStatic) => true, - VerifyBound::OutlivedBy(_) => false, + VerifyBound::OutlivedBy(re) => re.is_static(), VerifyBound::IsEmpty => false, VerifyBound::AnyBound(bs) => bs.iter().any(|b| b.must_hold()), VerifyBound::AllBounds(bs) => bs.iter().all(|b| b.must_hold()), diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 74459911384..08358bf5067 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -39,7 +39,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticVarResolver<'a, 'tcx> { } } - fn fold_const(&mut self, ct: &'tcx Const<'tcx>) -> &'tcx Const<'tcx> { + fn fold_const(&mut self, ct: Const<'tcx>) -> Const<'tcx> { if !ct.has_infer_types_or_consts() { ct // micro-optimize -- if there is nothing in this const that this fold affects... } else { @@ -98,7 +98,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticRegionResolver<'a, 'tcx> { } } - fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { if !ct.has_infer_regions() { ct // micro-optimize -- if there is nothing in this const that this fold affects... } else { @@ -218,15 +218,12 @@ impl<'a, 'tcx> FallibleTypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> { } } - fn try_fold_const( - &mut self, - c: &'tcx ty::Const<'tcx>, - ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> { + fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> { if !c.needs_infer() { Ok(c) // micro-optimize -- if there is nothing in this const that this fold affects... } else { let c = self.infcx.shallow_resolve(c); - match c.val { + match c.val() { ty::ConstKind::Infer(InferConst::Var(vid)) => { return Err(FixupError::UnresolvedConst(vid)); } diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index ccac0efd6c9..9ec1b3390d0 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -151,9 +151,9 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { fn consts( &mut self, - a: &'tcx ty::Const<'tcx>, - b: &'tcx ty::Const<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { + a: ty::Const<'tcx>, + b: ty::Const<'tcx>, + ) -> RelateResult<'tcx, ty::Const<'tcx>> { self.fields.infcx.super_combine_consts(self, a, b) } @@ -170,7 +170,7 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { } impl<'tcx> ConstEquateRelation<'tcx> for Sub<'_, '_, 'tcx> { - fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) { + fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) { self.fields.add_const_equate_obligation(self.a_is_expected, a, b); } } diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs index 82970f214fa..74c44089045 100644 --- a/compiler/rustc_infer/src/infer/type_variable.rs +++ b/compiler/rustc_infer/src/infer/type_variable.rs @@ -14,6 +14,7 @@ use std::ops::Range; use rustc_data_structures::undo_log::{Rollback, UndoLogs}; /// Represents a single undo-able action that affects a type inference variable. +#[derive(Clone)] pub(crate) enum UndoLog<'tcx> { EqRelation(sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>), SubRelation(sv::UndoLog<ut::Delegate<ty::TyVid>>), @@ -58,6 +59,7 @@ impl<'tcx> Rollback<UndoLog<'tcx>> for TypeVariableStorage<'tcx> { } } +#[derive(Clone)] pub struct TypeVariableStorage<'tcx> { values: sv::SnapshotVecStorage<Delegate>, @@ -137,6 +139,7 @@ pub enum TypeVariableOriginKind { LatticeVariable, } +#[derive(Clone)] pub(crate) struct TypeVariableData { origin: TypeVariableOrigin, } @@ -165,6 +168,7 @@ impl<'tcx> TypeVariableValue<'tcx> { } } +#[derive(Clone)] pub(crate) struct Instantiate; pub(crate) struct Delegate; @@ -259,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 } @@ -412,6 +416,7 @@ impl<'tcx> ut::UnifyKey for TyVidEqKey<'tcx> { fn index(&self) -> u32 { self.vid.as_u32() } + #[inline] fn from_index(i: u32) -> Self { TyVidEqKey::from(ty::TyVid::from_u32(i)) } diff --git a/compiler/rustc_infer/src/infer/undo_log.rs b/compiler/rustc_infer/src/infer/undo_log.rs index 89db8f464b4..ecd886b5478 100644 --- a/compiler/rustc_infer/src/infer/undo_log.rs +++ b/compiler/rustc_infer/src/infer/undo_log.rs @@ -17,6 +17,7 @@ pub struct Snapshot<'tcx> { } /// Records the "undo" data for a single operation that affects some form of inference variable. +#[derive(Clone)] pub(crate) enum UndoLog<'tcx> { TypeVariables(type_variable::UndoLog<'tcx>), ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>), @@ -84,6 +85,7 @@ impl<'tcx> Rollback<UndoLog<'tcx>> for InferCtxtInner<'tcx> { /// The combined undo log for all the various unification tables. For each change to the storage /// for any kind of inference variable, we record an UndoLog entry in the vector here. +#[derive(Clone)] pub(crate) struct InferCtxtUndoLogs<'tcx> { logs: Vec<UndoLog<'tcx>>, num_open_snapshots: usize, diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index e1f3b548e97..85bb727a6c8 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -101,7 +101,7 @@ pub enum FulfillmentErrorCode<'tcx> { CodeSelectionError(SelectionError<'tcx>), CodeProjectionError(MismatchedProjectionTypes<'tcx>), CodeSubtypeError(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate - CodeConstEquateError(ExpectedFound<&'tcx Const<'tcx>>, TypeError<'tcx>), + CodeConstEquateError(ExpectedFound<Const<'tcx>>, TypeError<'tcx>), CodeAmbiguity, } diff --git a/compiler/rustc_infer/src/traits/project.rs b/compiler/rustc_infer/src/traits/project.rs index a1a1168a21d..b84ed3dc689 100644 --- a/compiler/rustc_infer/src/traits/project.rs +++ b/compiler/rustc_infer/src/traits/project.rs @@ -70,7 +70,7 @@ pub struct ProjectionCache<'a, 'tcx> { undo_log: &'a mut InferCtxtUndoLogs<'tcx>, } -#[derive(Default)] +#[derive(Clone, Default)] pub struct ProjectionCacheStorage<'tcx> { map: SnapshotMapStorage<ProjectionCacheKey<'tcx>, ProjectionCacheEntry<'tcx>>, } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 8bd24487b78..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,15 +13,15 @@ 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; -use std::sync::{Arc, Mutex}; pub type Result<T> = result::Result<T, ErrorReported>; @@ -140,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 @@ -147,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>, @@ -155,9 +240,6 @@ pub struct Config { pub file_loader: Option<Box<dyn FileLoader + Send + Sync>>, pub diagnostic_output: DiagnosticOutput, - /// Set to capture stderr output during compiler execution - pub stderr: Option<Arc<Mutex<Vec<u8>>>>, - pub lint_caps: FxHashMap<lint::LintId, lint::Level>, /// This is a callback from the driver that is called when [`ParseSess`] is created. @@ -192,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(), @@ -237,13 +320,11 @@ pub fn create_compiler_and_run<R>(config: Config, f: impl FnOnce(&Compiler) -> R }) } -pub fn run_compiler<R: Send>(mut config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R { +pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R { tracing::trace!("run_compiler"); - let stderr = config.stderr.take(); util::run_in_thread_pool_with_globals( config.opts.edition, config.opts.debugging_opts.threads, - &stderr, || create_compiler_and_run(config, f), ) } 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 d206f2644e0..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}; @@ -27,7 +28,6 @@ use rustc_span::symbol::{sym, Symbol}; use smallvec::SmallVec; use std::env; use std::env::consts::{DLL_PREFIX, DLL_SUFFIX}; -use std::io; use std::lazy::SyncOnceCell; use std::mem; use std::ops::DerefMut; @@ -35,7 +35,6 @@ use std::ops::DerefMut; use std::panic; use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::{Arc, Mutex}; use std::thread; use tracing::info; @@ -67,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>, @@ -102,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)) } @@ -131,7 +137,6 @@ fn scoped_thread<F: FnOnce() -> R + Send, R: Send>(cfg: thread::Builder, f: F) - pub fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>( edition: Edition, _threads: usize, - stderr: &Option<Arc<Mutex<Vec<u8>>>>, f: F, ) -> R { let mut cfg = thread::Builder::new().name("rustc".to_string()); @@ -140,12 +145,7 @@ pub fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>( cfg = cfg.stack_size(size); } - let main_handler = move || { - rustc_span::create_session_globals_then(edition, || { - io::set_output_capture(stderr.clone()); - f() - }) - }; + let main_handler = move || rustc_span::create_session_globals_then(edition, f); scoped_thread(cfg, main_handler) } @@ -177,7 +177,6 @@ unsafe fn handle_deadlock() { pub fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>( edition: Edition, threads: usize, - stderr: &Option<Arc<Mutex<Vec<u8>>>>, f: F, ) -> R { let mut config = rayon::ThreadPoolBuilder::new() @@ -199,10 +198,7 @@ pub fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>( // the thread local rustc uses. `session_globals` is captured and set // on the new threads. let main_handler = move |thread: rayon::ThreadBuilder| { - rustc_span::set_session_globals_then(session_globals, || { - io::set_output_capture(stderr.clone()); - thread.run() - }) + rustc_span::set_session_globals_then(session_globals, || thread.run()) }; config.build_scoped(main_handler, with_pool).unwrap() @@ -339,6 +335,7 @@ fn sysroot_candidates() -> Vec<PathBuf> { #[cfg(windows)] fn current_dll_path() -> Option<PathBuf> { use std::ffi::OsString; + use std::io; use std::os::windows::prelude::*; use std::ptr; diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 734b32bb92f..a397db7f329 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2050,7 +2050,7 @@ impl ExplicitOutlivesRequirements { inferred_outlives .iter() .filter_map(|(pred, _)| match pred.kind().skip_binder() { - ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match a { + ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match *a { ty::ReEarlyBound(ebr) if ebr.index == index => Some(b), _ => None, }, @@ -2111,10 +2111,10 @@ impl ExplicitOutlivesRequirements { if let hir::GenericBound::Outlives(lifetime) = bound { let is_inferred = match tcx.named_region(lifetime.hir_id) { Some(Region::Static) if infer_static => { - inferred_outlives.iter().any(|r| matches!(r, ty::ReStatic)) + inferred_outlives.iter().any(|r| matches!(**r, ty::ReStatic)) } Some(Region::EarlyBound(index, ..)) => inferred_outlives.iter().any(|r| { - if let ty::ReEarlyBound(ebr) = r { ebr.index == index } else { false } + if let ty::ReEarlyBound(ebr) = **r { ebr.index == index } else { false } }), _ => false, }; @@ -2895,26 +2895,22 @@ impl ClashingExternDeclarations { } (Array(a_ty, a_const), Array(b_ty, b_const)) => { // For arrays, we also check the constness of the type. - a_const.val == b_const.val - && structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind) + a_const.val() == b_const.val() + && structurally_same_type_impl(seen_types, cx, *a_ty, *b_ty, ckind) } (Slice(a_ty), Slice(b_ty)) => { - structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind) + structurally_same_type_impl(seen_types, cx, *a_ty, *b_ty, ckind) } (RawPtr(a_tymut), RawPtr(b_tymut)) => { a_tymut.mutbl == b_tymut.mutbl && structurally_same_type_impl( - seen_types, - cx, - &a_tymut.ty, - &b_tymut.ty, - ckind, + seen_types, cx, a_tymut.ty, b_tymut.ty, ckind, ) } (Ref(_a_region, a_ty, a_mut), Ref(_b_region, b_ty, b_mut)) => { // For structural sameness, we don't need the region to be same. a_mut == b_mut - && structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind) + && structurally_same_type_impl(seen_types, cx, *a_ty, *b_ty, ckind) } (FnDef(..), FnDef(..)) => { let a_poly_sig = a.fn_sig(tcx); @@ -2927,7 +2923,7 @@ impl ClashingExternDeclarations { (a_sig.abi, a_sig.unsafety, a_sig.c_variadic) == (b_sig.abi, b_sig.unsafety, b_sig.c_variadic) && a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| { - structurally_same_type_impl(seen_types, cx, a, b, ckind) + structurally_same_type_impl(seen_types, cx, *a, *b, ckind) }) && structurally_same_type_impl( seen_types, diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 5da77b9f946..d2d853efda2 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -974,7 +974,7 @@ impl<'tcx> LateContext<'tcx> { Ok(()) } - fn print_const(self, _ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> { + fn print_const(self, _ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> { Ok(()) } diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index fa8cbeaaf51..944a0996427 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -202,7 +202,7 @@ fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, ty: &Ty<'_>) -> Option<String> { } } // Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait. - Res::SelfTy(None, Some((did, _))) => { + Res::SelfTy { trait_: None, alias_to: Some((did, _)) } => { if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() { if let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(adt.did) diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs index 2caf929788f..c47fdc063a9 100644 --- a/compiler/rustc_lint/src/pass_by_value.rs +++ b/compiler/rustc_lint/src/pass_by_value.rs @@ -7,9 +7,10 @@ use rustc_middle::ty; use rustc_span::symbol::sym; declare_tool_lint! { - /// The `rustc_pass_by_value` lint marks a type with `#[rustc_pass_by_value]` requiring it to always be passed by value. - /// This is usually used for types that are thin wrappers around references, so there is no benefit to an extra - /// layer of indirection. (Example: `Ty` which is a reference to a `TyS`) + /// The `rustc_pass_by_value` lint marks a type with `#[rustc_pass_by_value]` requiring it to + /// always be passed by value. This is usually used for types that are thin wrappers around + /// references, so there is no benefit to an extra layer of indirection. (Example: `Ty` which + /// is a reference to an `Interned<TyS>`) pub rustc::PASS_BY_VALUE, Warn, "pass by reference of a type flagged as `#[rustc_pass_by_value]`", @@ -54,7 +55,7 @@ fn path_for_pass_by_value(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Option<Stri let path_segment = path.segments.last().unwrap(); return Some(format!("{}{}", name, gen_args(cx, path_segment))); } - Res::SelfTy(None, Some((did, _))) => { + Res::SelfTy { trait_: None, alias_to: Some((did, _)) } => { if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() { if cx.tcx.has_attr(adt.did, sym::rustc_pass_by_value) { return Some(cx.tcx.def_path_str_with_substs(adt.did, substs)); diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index bceb5e536e7..fc88e8cd912 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -249,7 +249,7 @@ fn report_bin_hex_error( )); } if let Some(sugg_ty) = - get_type_suggestion(&cx.typeck_results().node_type(expr.hir_id), val, negative) + get_type_suggestion(cx.typeck_results().node_type(expr.hir_id), val, negative) { if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') { let (sans_suffix, _) = repr_str.split_at(pos); @@ -367,7 +367,7 @@ fn lint_int_literal<'tcx>( max, )); if let Some(sugg_ty) = - get_type_suggestion(&cx.typeck_results().node_type(e.hir_id), v, negative) + get_type_suggestion(cx.typeck_results().node_type(e.hir_id), v, negative) { err.help(&format!("consider using the type `{}` instead", sugg_ty)); } @@ -1095,7 +1095,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } } for arg in sig.inputs() { - let r = self.check_type_for_ffi(cache, arg); + let r = self.check_type_for_ffi(cache, *arg); match r { FfiSafe => {} _ => { @@ -1257,7 +1257,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { let sig = self.cx.tcx.erase_late_bound_regions(sig); for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) { - self.check_type_for_ffi_and_report_errors(input_hir.span, input_ty, false, false); + self.check_type_for_ffi_and_report_errors(input_hir.span, *input_ty, false, false); } if let hir::FnRetTy::Return(ref ret_hir) = decl.output { 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 fb9c5e6a527..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"); } @@ -334,6 +336,17 @@ extern "C" void LLVMRustAddStructRetAttr(LLVMValueRef Fn, unsigned Index, AddAttribute(F, Index, Attr); } +extern "C" void LLVMRustEmitUWTableAttr(LLVMValueRef Fn, bool Async) { + Function *F = unwrap<Function>(Fn); +#if LLVM_VERSION_LT(15, 0) + Attribute Attr = Attribute::get(F->getContext(), Attribute::UWTable); +#else + Attribute Attr = Attribute::getWithUWTableKind( + F->getContext(), Async ? UWTableKind::Async : UWTableKind::Sync); +#endif + AddAttribute(F, AttributeList::AttrIndex::FunctionIndex, Attr); +} + extern "C" void LLVMRustAddFunctionAttrStringValue(LLVMValueRef Fn, unsigned Index, const char *Name, 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 ad82165ebd4..7708b5193f4 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -117,7 +117,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, promoted_mir => { tcx.arena.alloc(cdata.get_promoted_mir(tcx, def_id.index)) } thir_abstract_const => { cdata.get_thir_abstract_const(tcx, def_id.index) } unused_generic_params => { cdata.get_unused_generic_params(def_id.index) } - const_param_default => { tcx.mk_const(cdata.get_const_param_default(tcx, def_id.index)) } + const_param_default => { cdata.get_const_param_default(tcx, def_id.index) } mir_const_qualif => { cdata.mir_const_qualif(def_id.index) } fn_sig => { cdata.fn_sig(def_id.index, tcx) } inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) } @@ -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 c92b3b9434c..4dea04e62ff 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -26,7 +26,7 @@ use rustc_middle::mir::interpret; use rustc_middle::thir; use rustc_middle::traits::specialization_graph; use rustc_middle::ty::codec::TyEncoder; -use rustc_middle::ty::fast_reject::{self, SimplifiedType, SimplifyParams, StripReferences}; +use rustc_middle::ty::fast_reject::{self, SimplifiedType, SimplifyParams}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt}; use rustc_serialize::{opaque, Encodable, Encoder}; @@ -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, @@ -2066,7 +2066,6 @@ impl<'tcx, 'v> ItemLikeVisitor<'v> for ImplsVisitor<'tcx> { self.tcx, trait_ref.self_ty(), SimplifyParams::No, - StripReferences::No, ); self.impls diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 9caf77532a9..c4e6734aa0f 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -88,7 +88,8 @@ macro_rules! arena_types { // Interned types [] tys: rustc_middle::ty::TyS<'tcx>, - [] predicates: rustc_middle::ty::PredicateInner<'tcx>, + [] predicates: rustc_middle::ty::PredicateS<'tcx>, + [] consts: rustc_middle::ty::ConstS<'tcx>, // Note that this deliberately duplicates items in the `rustc_hir::arena`, // since we need to allocate this type on both the `rustc_hir` arena 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/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 4efe3640dfa..419ed429246 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -328,8 +328,8 @@ impl<'tcx> CanonicalVarValues<'tcx> { tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into() } GenericArgKind::Const(ct) => tcx - .mk_const(ty::Const { - ty: ct.ty, + .mk_const(ty::ConstS { + ty: ct.ty(), val: ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i)), }) .into(), diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs index dcc49a53572..dd303aaada9 100644 --- a/compiler/rustc_middle/src/infer/unify_key.rs +++ b/compiler/rustc_middle/src/infer/unify_key.rs @@ -32,9 +32,11 @@ impl<'tcx> From<ty::RegionVid> for RegionVidKey<'tcx> { impl<'tcx> UnifyKey for RegionVidKey<'tcx> { type Value = UnifiedRegion<'tcx>; + #[inline] fn index(&self) -> u32 { self.vid.as_u32() } + #[inline] fn from_index(i: u32) -> Self { RegionVidKey::from(ty::RegionVid::from_u32(i)) } @@ -95,14 +97,14 @@ pub enum ConstVariableOriginKind { #[derive(Copy, Clone, Debug)] pub enum ConstVariableValue<'tcx> { - Known { value: &'tcx ty::Const<'tcx> }, + Known { value: ty::Const<'tcx> }, Unknown { universe: ty::UniverseIndex }, } impl<'tcx> ConstVariableValue<'tcx> { /// If this value is known, returns the const it is known to be. /// Otherwise, `None`. - pub fn known(&self) -> Option<&'tcx ty::Const<'tcx>> { + pub fn known(&self) -> Option<ty::Const<'tcx>> { match *self { ConstVariableValue::Unknown { .. } => None, ConstVariableValue::Known { value } => Some(value), @@ -118,9 +120,11 @@ pub struct ConstVarValue<'tcx> { impl<'tcx> UnifyKey for ty::ConstVid<'tcx> { type Value = ConstVarValue<'tcx>; + #[inline] fn index(&self) -> u32 { self.index } + #[inline] fn from_index(i: u32) -> Self { ty::ConstVid { index: i, phantom: PhantomData } } @@ -130,7 +134,7 @@ impl<'tcx> UnifyKey for ty::ConstVid<'tcx> { } impl<'tcx> UnifyValue for ConstVarValue<'tcx> { - type Error = (&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>); + type Error = (ty::Const<'tcx>, ty::Const<'tcx>); fn unify_values(&value1: &Self, &value2: &Self) -> Result<Self, Self::Error> { Ok(match (value1.val, value2.val) { @@ -162,18 +166,18 @@ impl<'tcx> UnifyValue for ConstVarValue<'tcx> { } } -impl<'tcx> EqUnifyValue for &'tcx ty::Const<'tcx> {} +impl<'tcx> EqUnifyValue for ty::Const<'tcx> {} pub fn replace_if_possible<'tcx, V, L>( table: &mut UnificationTable<InPlace<ty::ConstVid<'tcx>, V, L>>, - c: &'tcx ty::Const<'tcx>, -) -> &'tcx ty::Const<'tcx> + c: ty::Const<'tcx>, +) -> ty::Const<'tcx> where V: snapshot_vec::VecLike<unify::Delegate<ty::ConstVid<'tcx>>>, L: UndoLogs<snapshot_vec::UndoLog<unify::Delegate<ty::ConstVid<'tcx>>>>, { - if let ty::Const { val: ty::ConstKind::Infer(InferConst::Var(vid)), .. } = c { - match table.probe_value(*vid).val.known() { + if let ty::ConstKind::Infer(InferConst::Var(vid)) = c.val() { + match table.probe_value(vid).val.known() { Some(c) => c, None => c, } 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/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index ec0f5b7d059..4a57f483c70 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -98,4 +98,12 @@ impl<'tcx> TyCtxt<'tcx> { let raw_const = self.eval_to_allocation_raw(param_env.and(gid))?; Ok(self.global_alloc(raw_const.alloc_id).unwrap_memory()) } + + /// Destructure a constant ADT or array into its variant index and its field values. + pub fn destructure_const( + self, + param_env_and_val: ty::ParamEnvAnd<'tcx, ty::Const<'tcx>>, + ) -> mir::DestructuredConst<'tcx> { + self.try_destructure_const(param_env_and_val).unwrap() + } } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 0688d7d2569..7e5f8018dfc 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2185,7 +2185,7 @@ pub enum Rvalue<'tcx> { Use(Operand<'tcx>), /// [x; 32] - Repeat(Operand<'tcx>, &'tcx ty::Const<'tcx>), + Repeat(Operand<'tcx>, ty::Const<'tcx>), /// &x or &mut x Ref(Region<'tcx>, BorrowKind, Place<'tcx>), @@ -2270,11 +2270,13 @@ pub enum BinOp { Mul, /// The `/` operator (division) /// - /// Division by zero is UB. + /// Division by zero is UB, because the compiler should have inserted checks + /// prior to this. Div, /// The `%` operator (modulus) /// - /// Using zero as the modulus (second operand) is UB. + /// Using zero as the modulus (second operand) is UB, because the compiler + /// should have inserted checks prior to this. Rem, /// The `^` operator (bitwise xor) BitXor, @@ -2335,7 +2337,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { match *self { Use(ref place) => write!(fmt, "{:?}", place), - Repeat(ref a, ref b) => { + Repeat(ref a, b) => { write!(fmt, "[{:?}; ", a)?; pretty_print_const(b, fmt, false)?; write!(fmt, "]") @@ -2514,7 +2516,7 @@ pub struct Constant<'tcx> { #[derive(Lift)] pub enum ConstantKind<'tcx> { /// This constant came from the type system - Ty(&'tcx ty::Const<'tcx>), + Ty(ty::Const<'tcx>), /// This constant cannot go back into the type system, as it represents /// something the type system cannot handle (e.g. pointers). Val(interpret::ConstValue<'tcx>, Ty<'tcx>), @@ -2522,7 +2524,7 @@ pub enum ConstantKind<'tcx> { impl<'tcx> Constant<'tcx> { pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option<DefId> { - match self.literal.const_for_ty()?.val.try_to_scalar() { + match self.literal.try_to_scalar() { Some(Scalar::Ptr(ptr, _size)) => match tcx.global_alloc(ptr.provenance) { GlobalAlloc::Static(def_id) => { assert!(!tcx.is_thread_local_static(def_id)); @@ -2539,33 +2541,33 @@ impl<'tcx> Constant<'tcx> { } } -impl<'tcx> From<&'tcx ty::Const<'tcx>> for ConstantKind<'tcx> { +impl<'tcx> From<ty::Const<'tcx>> for ConstantKind<'tcx> { #[inline] - fn from(ct: &'tcx ty::Const<'tcx>) -> Self { + fn from(ct: ty::Const<'tcx>) -> Self { Self::Ty(ct) } } impl<'tcx> ConstantKind<'tcx> { /// Returns `None` if the constant is not trivially safe for use in the type system. - pub fn const_for_ty(&self) -> Option<&'tcx ty::Const<'tcx>> { + pub fn const_for_ty(&self) -> Option<ty::Const<'tcx>> { match self { - ConstantKind::Ty(c) => Some(c), + ConstantKind::Ty(c) => Some(*c), ConstantKind::Val(..) => None, } } pub fn ty(&self) -> Ty<'tcx> { match self { - ConstantKind::Ty(c) => c.ty, - ConstantKind::Val(_, ty) => ty, + ConstantKind::Ty(c) => c.ty(), + ConstantKind::Val(_, ty) => *ty, } } #[inline] pub fn try_to_value(self) -> Option<interpret::ConstValue<'tcx>> { match self { - ConstantKind::Ty(c) => c.val.try_to_value(), + ConstantKind::Ty(c) => c.val().try_to_value(), ConstantKind::Val(val, _) => Some(val), } } @@ -2829,7 +2831,7 @@ impl<'tcx> Display for ConstantKind<'tcx> { } fn pretty_print_const<'tcx>( - c: &ty::Const<'tcx>, + c: ty::Const<'tcx>, fmt: &mut Formatter<'_>, print_types: bool, ) -> fmt::Result { diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index f2ad5910711..784babffeff 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -17,9 +17,8 @@ use rustc_middle::mir::interpret::{ use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::MirSource; use rustc_middle::mir::*; -use rustc_middle::ty::{self, TyCtxt, TyS, TypeFoldable, TypeVisitor}; +use rustc_middle::ty::{self, TyCtxt}; use rustc_target::abi::Size; -use std::ops::ControlFlow; const INDENT: &str = " "; /// Alignment for lining up comments following MIR statements @@ -427,12 +426,12 @@ impl<'tcx> ExtraComments<'tcx> { } } -fn use_verbose<'tcx>(ty: &&TyS<'tcx>, fn_def: bool) -> bool { - match ty.kind() { +fn use_verbose<'tcx>(ty: Ty<'tcx>, fn_def: bool) -> bool { + match *ty.kind() { ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_) => false, // Unit type ty::Tuple(g_args) if g_args.is_empty() => false, - ty::Tuple(g_args) => g_args.iter().any(|g_arg| use_verbose(&g_arg.expect_ty(), fn_def)), + ty::Tuple(g_args) => g_args.iter().any(|g_arg| use_verbose(g_arg.expect_ty(), fn_def)), ty::Array(ty, _) => use_verbose(ty, fn_def), ty::FnDef(..) => fn_def, _ => true, @@ -443,7 +442,7 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> { fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { self.super_constant(constant, location); let Constant { span, user_ty, literal } = constant; - if use_verbose(&literal.ty(), true) { + if use_verbose(literal.ty(), true) { self.push("mir::Constant"); self.push(&format!( "+ span: {}", @@ -462,9 +461,10 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> { } } - fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, _: Location) { + fn visit_const(&mut self, constant: ty::Const<'tcx>, _: Location) { self.super_const(constant); - let ty::Const { ty, val, .. } = constant; + let ty = constant.ty(); + let val = constant.val(); if use_verbose(ty, false) { self.push("ty::Const"); self.push(&format!("+ ty: {:?}", ty)); @@ -668,6 +668,7 @@ pub fn write_allocations<'tcx>( fn alloc_ids_from_alloc(alloc: &Allocation) -> impl DoubleEndedIterator<Item = AllocId> + '_ { alloc.relocations().values().map(|id| *id) } + fn alloc_ids_from_const(val: ConstValue<'_>) -> impl Iterator<Item = AllocId> + '_ { match val { ConstValue::Scalar(interpret::Scalar::Ptr(ptr, _size)) => { @@ -681,17 +682,29 @@ pub fn write_allocations<'tcx>( } } } + struct CollectAllocIds(BTreeSet<AllocId>); - impl<'tcx> TypeVisitor<'tcx> for CollectAllocIds { - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { - if let ty::ConstKind::Value(val) = c.val { + + impl<'tcx> Visitor<'tcx> for CollectAllocIds { + fn visit_const(&mut self, c: ty::Const<'tcx>, _loc: Location) { + if let ty::ConstKind::Value(val) = c.val() { self.0.extend(alloc_ids_from_const(val)); } - c.super_visit_with(self) + } + + fn visit_constant(&mut self, c: &Constant<'tcx>, loc: Location) { + match c.literal { + ConstantKind::Ty(c) => self.visit_const(c, loc), + ConstantKind::Val(val, _) => { + self.0.extend(alloc_ids_from_const(val)); + } + } } } + let mut visitor = CollectAllocIds(Default::default()); - body.visit_with(&mut visitor); + visitor.visit_body(body); + // `seen` contains all seen allocations, including the ones we have *not* printed yet. // The protocol is to first `insert` into `seen`, and only if that returns `true` // then push to `todo`. diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 6e2b060e7dd..5c616425957 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -387,7 +387,7 @@ pub enum ClosureOutlivesSubject<'tcx> { #[derive(Copy, Clone, Debug, HashStable)] pub struct DestructuredConst<'tcx> { pub variant: Option<VariantIdx>, - pub fields: &'tcx [&'tcx ty::Const<'tcx>], + pub fields: &'tcx [ty::Const<'tcx>], } /// Coverage information summarized from a MIR if instrumented for source code coverage (see diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index dc53dc8de9d..302921cc4aa 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -57,7 +57,7 @@ impl<'tcx> PlaceTy<'tcx> { /// `PlaceElem`, where we can just use the `Ty` that is already /// stored inline on field projection elems. pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: PlaceElem<'tcx>) -> PlaceTy<'tcx> { - self.projection_ty_core(tcx, ty::ParamEnv::empty(), &elem, |_, _, ty| ty) + self.projection_ty_core(tcx, ty::ParamEnv::empty(), &elem, |_, _, &ty| ty) } /// `place_ty.projection_ty_core(tcx, elem, |...| { ... })` @@ -93,11 +93,11 @@ impl<'tcx> PlaceTy<'tcx> { ProjectionElem::Subslice { from, to, from_end } => { PlaceTy::from_ty(match self.ty.kind() { ty::Slice(..) => self.ty, - ty::Array(inner, _) if !from_end => tcx.mk_array(inner, (to - from) as u64), + ty::Array(inner, _) if !from_end => tcx.mk_array(*inner, (to - from) as u64), ty::Array(inner, size) if from_end => { let size = size.eval_usize(tcx, param_env); let len = size - (from as u64) - (to as u64); - tcx.mk_array(inner, len) + tcx.mk_array(*inner, len) } _ => bug!("cannot subslice non-array type: `{:?}`", self), }) diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index fafd847a1cb..ae94bd121f9 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -430,7 +430,7 @@ impl<'tcx> TerminatorKind<'tcx> { pub fn as_switch(&self) -> Option<(&Operand<'tcx>, Ty<'tcx>, &SwitchTargets)> { match self { TerminatorKind::SwitchInt { discr, switch_ty, targets } => { - Some((discr, switch_ty, targets)) + Some((discr, *switch_ty, targets)) } _ => None, } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 4452ac5e3e0..a618800cc1b 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -194,13 +194,13 @@ macro_rules! make_mir_visitor { } fn visit_region(&mut self, - region: & $($mutability)? ty::Region<'tcx>, + region: $(& $mutability)? ty::Region<'tcx>, _: Location) { self.super_region(region); } fn visit_const(&mut self, - constant: & $($mutability)? &'tcx ty::Const<'tcx>, + constant: $(& $mutability)? ty::Const<'tcx>, _: Location) { self.super_const(constant); } @@ -242,7 +242,7 @@ macro_rules! make_mir_visitor { ) { let span = body.span; if let Some(gen) = &$($mutability)? body.generator { - if let Some(yield_ty) = &$($mutability)? gen.yield_ty { + if let Some(yield_ty) = $(& $mutability)? gen.yield_ty { self.visit_ty( yield_ty, TyContext::YieldTy(SourceInfo::outermost(span)) @@ -266,7 +266,7 @@ macro_rules! make_mir_visitor { } self.visit_ty( - &$($mutability)? body.return_ty(), + $(& $mutability)? body.return_ty(), TyContext::ReturnTy(SourceInfo::outermost(body.span)) ); @@ -355,7 +355,7 @@ macro_rules! make_mir_visitor { ty::InstanceDef::DropGlue(_def_id, Some(ty)) | ty::InstanceDef::CloneShim(_def_id, ty) => { // FIXME(eddyb) use a better `TyContext` here. - self.visit_ty(ty, TyContext::Location(location)); + self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); } } self.visit_substs(callee_substs, location); @@ -487,7 +487,7 @@ macro_rules! make_mir_visitor { targets: _ } => { self.visit_operand(discr, location); - self.visit_ty(switch_ty, TyContext::Location(location)); + self.visit_ty($(& $mutability)? *switch_ty, TyContext::Location(location)); } TerminatorKind::Drop { @@ -641,7 +641,7 @@ macro_rules! make_mir_visitor { Rvalue::ThreadLocalRef(_) => {} Rvalue::Ref(r, bk, path) => { - self.visit_region(r, location); + self.visit_region($(& $mutability)? *r, location); let ctx = match bk { BorrowKind::Shared => PlaceContext::NonMutatingUse( NonMutatingUseContext::SharedBorrow @@ -680,7 +680,7 @@ macro_rules! make_mir_visitor { Rvalue::Cast(_cast_kind, operand, ty) => { self.visit_operand(operand, location); - self.visit_ty(ty, TyContext::Location(location)); + self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); } Rvalue::BinaryOp(_bin_op, box(lhs, rhs)) @@ -702,14 +702,14 @@ macro_rules! make_mir_visitor { } Rvalue::NullaryOp(_op, ty) => { - self.visit_ty(ty, TyContext::Location(location)); + self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); } Rvalue::Aggregate(kind, operands) => { let kind = &$($mutability)? **kind; match kind { AggregateKind::Array(ty) => { - self.visit_ty(ty, TyContext::Location(location)); + self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); } AggregateKind::Tuple => { } @@ -744,7 +744,7 @@ macro_rules! make_mir_visitor { Rvalue::ShallowInitBox(operand, ty) => { self.visit_operand(operand, location); - self.visit_ty(ty, TyContext::Location(location)); + self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); } } } @@ -815,7 +815,7 @@ macro_rules! make_mir_visitor { is_block_tail: _, } = local_decl; - self.visit_ty(ty, TyContext::LocalDecl { + self.visit_ty($(& $mutability)? *ty, TyContext::LocalDecl { local, source_info: *source_info, }); @@ -864,8 +864,8 @@ macro_rules! make_mir_visitor { self.visit_span(span); drop(user_ty); // no visit method for this match literal { - ConstantKind::Ty(ct) => self.visit_const(ct, location), - ConstantKind::Val(_, t) => self.visit_ty(t, TyContext::Location(location)), + ConstantKind::Ty(ct) => self.visit_const($(& $mutability)? *ct, location), + ConstantKind::Val(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)), } } @@ -894,16 +894,16 @@ macro_rules! make_mir_visitor { ty: & $($mutability)? CanonicalUserTypeAnnotation<'tcx>, ) { self.visit_span(& $($mutability)? ty.span); - self.visit_ty(& $($mutability)? ty.inferred_ty, TyContext::UserTy(ty.span)); + self.visit_ty($(& $mutability)? ty.inferred_ty, TyContext::UserTy(ty.span)); } fn super_ty(&mut self, _ty: $(& $mutability)? Ty<'tcx>) { } - fn super_region(&mut self, _region: & $($mutability)? ty::Region<'tcx>) { + fn super_region(&mut self, _region: $(& $mutability)? ty::Region<'tcx>) { } - fn super_const(&mut self, _const: & $($mutability)? &'tcx ty::Const<'tcx>) { + fn super_const(&mut self, _const: $(& $mutability)? ty::Const<'tcx>) { } fn super_substs(&mut self, _substs: & $($mutability)? SubstsRef<'tcx>) { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index fc2750d2303..43cfe6f3b8a 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -113,7 +113,7 @@ rustc_queries! { /// Given the def_id of a const-generic parameter, computes the associated default const /// parameter. e.g. `fn example<const N: usize=3>` called on `N` would return `3`. - query const_param_default(param: DefId) -> &'tcx ty::Const<'tcx> { + query const_param_default(param: DefId) -> ty::Const<'tcx> { desc { |tcx| "compute const default for a given parameter `{}`", tcx.def_path_str(param) } separate_provide_extern } @@ -924,10 +924,12 @@ rustc_queries! { } /// Destructure a constant ADT or array into its variant index and its - /// field values. - query destructure_const( - key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>> - ) -> mir::DestructuredConst<'tcx> { + /// field values or return `None` if constant is invalid. + /// + /// Use infallible `TyCtxt::destructure_const` when you know that constant is valid. + query try_destructure_const( + key: ty::ParamEnvAnd<'tcx, ty::Const<'tcx>> + ) -> Option<mir::DestructuredConst<'tcx>> { desc { "destructure constant" } remap_env_constness } @@ -935,8 +937,8 @@ rustc_queries! { /// Dereference a constant reference or raw pointer and turn the result into a constant /// again. query deref_const( - key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>> - ) -> &'tcx ty::Const<'tcx> { + key: ty::ParamEnvAnd<'tcx, ty::Const<'tcx>> + ) -> ty::Const<'tcx> { desc { "deref constant" } remap_env_constness } @@ -947,7 +949,7 @@ rustc_queries! { query lit_to_const( key: LitToConstInput<'tcx> - ) -> Result<&'tcx ty::Const<'tcx>, LitToConstError> { + ) -> Result<ty::Const<'tcx>, LitToConstError> { desc { "converting literal to const" } } @@ -1146,33 +1148,33 @@ rustc_queries! { desc { "computing whether `{}` is `Copy`", env.value } remap_env_constness } - /// Query backing `TyS::is_sized`. + /// Query backing `Ty::is_sized`. query is_sized_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` is `Sized`", env.value } remap_env_constness } - /// Query backing `TyS::is_freeze`. + /// Query backing `Ty::is_freeze`. query is_freeze_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` is freeze", env.value } remap_env_constness } - /// Query backing `TyS::is_unpin`. + /// Query backing `Ty::is_unpin`. query is_unpin_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` is `Unpin`", env.value } remap_env_constness } - /// Query backing `TyS::needs_drop`. + /// Query backing `Ty::needs_drop`. query needs_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` needs drop", env.value } remap_env_constness } - /// Query backing `TyS::has_significant_drop_raw`. + /// Query backing `Ty::has_significant_drop_raw`. query has_significant_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` has a significant drop", env.value } remap_env_constness } - /// Query backing `TyS::is_structural_eq_shallow`. + /// Query backing `Ty::is_structural_eq_shallow`. /// /// This is only correct for ADTs. Call `is_structural_eq_shallow` to handle all types /// correctly. diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 11dc69ab715..04bc0c8b521 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -17,6 +17,7 @@ use rustc_index::newtype_index; use rustc_index::vec::IndexVec; use rustc_middle::infer::canonical::Canonical; use rustc_middle::middle::region; +use rustc_middle::mir::interpret::AllocId; use rustc_middle::mir::{ BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp, UserTypeProjection, }; @@ -368,12 +369,12 @@ pub enum ExprKind<'tcx> { }, /// An inline `const` block, e.g. `const {}`. ConstBlock { - value: &'tcx Const<'tcx>, + value: Const<'tcx>, }, /// An array literal constructed from one repeated element, e.g. `[1; 5]`. Repeat { value: ExprId, - count: &'tcx Const<'tcx>, + count: Const<'tcx>, }, /// An array, e.g. `[a, b, c, d]`. Array { @@ -407,7 +408,7 @@ pub enum ExprKind<'tcx> { }, /// A literal. Literal { - literal: &'tcx Const<'tcx>, + literal: Const<'tcx>, user_ty: Option<Canonical<'tcx, UserType<'tcx>>>, /// The `DefId` of the `const` item this literal /// was produced from, if this is not a user-written @@ -419,7 +420,8 @@ pub enum ExprKind<'tcx> { /// This is only distinguished from `Literal` so that we can register some /// info for diagnostics. StaticRef { - literal: &'tcx Const<'tcx>, + alloc_id: AllocId, + ty: Ty<'tcx>, def_id: DefId, }, /// Inline assembly, i.e. `asm!()`. @@ -501,7 +503,7 @@ pub enum InlineAsmOperand<'tcx> { out_expr: Option<ExprId>, }, Const { - value: &'tcx Const<'tcx>, + value: Const<'tcx>, span: Span, }, SymFn { @@ -640,7 +642,7 @@ pub enum PatKind<'tcx> { /// * Opaque constants, that must not be matched structurally. So anything that does not derive /// `PartialEq` and `Eq`. Constant { - value: &'tcx ty::Const<'tcx>, + value: ty::Const<'tcx>, }, Range(PatRange<'tcx>), @@ -670,8 +672,8 @@ pub enum PatKind<'tcx> { #[derive(Copy, Clone, Debug, PartialEq, HashStable)] pub struct PatRange<'tcx> { - pub lo: &'tcx ty::Const<'tcx>, - pub hi: &'tcx ty::Const<'tcx>, + pub lo: ty::Const<'tcx>, + pub hi: ty::Const<'tcx>, pub end: RangeEnd, } diff --git a/compiler/rustc_middle/src/thir/abstract_const.rs b/compiler/rustc_middle/src/thir/abstract_const.rs index f80beadd6e5..e3d004ed133 100644 --- a/compiler/rustc_middle/src/thir/abstract_const.rs +++ b/compiler/rustc_middle/src/thir/abstract_const.rs @@ -22,7 +22,7 @@ pub enum CastKind { /// A node of an `AbstractConst`. #[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] pub enum Node<'tcx> { - Leaf(&'tcx ty::Const<'tcx>), + Leaf(ty::Const<'tcx>), Binop(mir::BinOp, NodeId, NodeId), UnaryOp(mir::UnOp, NodeId), FunctionCall(NodeId, &'tcx [NodeId]), diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 9f9947341c5..b3e2cb132a2 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -26,7 +26,7 @@ pub trait Visitor<'a, 'tcx: 'a>: Sized { walk_pat(self, pat); } - fn visit_const(&mut self, _cnst: &'tcx Const<'tcx>) {} + fn visit_const(&mut self, _cnst: Const<'tcx>) {} } pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Expr<'tcx>) { @@ -123,7 +123,7 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp } Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {} Literal { literal, user_ty: _, const_id: _ } => visitor.visit_const(literal), - StaticRef { literal, def_id: _ } => visitor.visit_const(literal), + StaticRef { .. } => {} InlineAsm { ref operands, template: _, options: _, line_spans: _ } => { for op in &**operands { use InlineAsmOperand::*; @@ -209,7 +209,7 @@ pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<' visitor.visit_pat(&subpattern.pattern); } } - Constant { value } => visitor.visit_const(value), + Constant { value } => visitor.visit_const(*value), Range(range) => { visitor.visit_const(range.lo); visitor.visit_const(range.hi); 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/_match.rs b/compiler/rustc_middle/src/ty/_match.rs index e0e3febe6b3..738c48dbb5c 100644 --- a/compiler/rustc_middle/src/ty/_match.rs +++ b/compiler/rustc_middle/src/ty/_match.rs @@ -77,7 +77,7 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { ) => Ok(a), (&ty::Infer(_), _) | (_, &ty::Infer(_)) => { - Err(TypeError::Sorts(relate::expected_found(self, &a, &b))) + Err(TypeError::Sorts(relate::expected_found(self, a, b))) } (&ty::Error(_), _) | (_, &ty::Error(_)) => Ok(self.tcx().ty_error()), @@ -88,21 +88,21 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { fn consts( &mut self, - a: &'tcx ty::Const<'tcx>, - b: &'tcx ty::Const<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { + a: ty::Const<'tcx>, + b: ty::Const<'tcx>, + ) -> RelateResult<'tcx, ty::Const<'tcx>> { debug!("{}.consts({:?}, {:?})", self.tag(), a, b); if a == b { return Ok(a); } - match (a.val, b.val) { + match (a.val(), b.val()) { (_, ty::ConstKind::Infer(InferConst::Fresh(_))) => { return Ok(a); } (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => { - return Err(TypeError::ConstMismatch(relate::expected_found(self, &a, &b))); + return Err(TypeError::ConstMismatch(relate::expected_found(self, a, b))); } _ => {} diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index aa264c26de8..40fbea7c3d9 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -395,7 +395,7 @@ impl<'tcx> AdtDef { | Res::Def(DefKind::Union, _) | Res::Def(DefKind::TyAlias, _) | Res::Def(DefKind::AssocTy, _) - | Res::SelfTy(..) + | Res::SelfTy { .. } | Res::SelfCtor(..) => self.non_enum_variant(), _ => bug!("unexpected res {:?} in variant_of_res", res), } diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index 0ac2ea4db5e..8ba6c1f67c9 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -116,7 +116,7 @@ impl<'tcx> ClosureKind { } /// Returns the representative scalar type for this closure kind. - /// See `TyS::to_opt_closure_kind` for more details. + /// See `Ty::to_opt_closure_kind` for more details. pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match self { ty::ClosureKind::Fn => tcx.types.i8, diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 69b116166e0..ecd30ba441f 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -138,6 +138,18 @@ impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ty::Predicate<'tcx> { } } +impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ty::Region<'tcx> { + fn encode(&self, e: &mut E) -> Result<(), E::Error> { + self.kind().encode(e) + } +} + +impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ty::Const<'tcx> { + fn encode(&self, e: &mut E) -> Result<(), E::Error> { + self.0.0.encode(e) + } +} + impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for AllocId { fn encode(&self, e: &mut E) -> Result<(), E::Error> { e.encode_alloc_id(self) @@ -156,7 +168,6 @@ macro_rules! encodable_via_deref { encodable_via_deref! { &'tcx ty::TypeckResults<'tcx>, - ty::Region<'tcx>, &'tcx traits::ImplSource<'tcx, ()>, &'tcx mir::Body<'tcx>, &'tcx mir::UnsafetyCheckResult, @@ -330,8 +341,8 @@ impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> } } -impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::Const<'tcx> { - fn decode(decoder: &mut D) -> &'tcx Self { +impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Const<'tcx> { + fn decode(decoder: &mut D) -> Self { decoder.tcx().mk_const(Decodable::decode(decoder)) } } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 19a73732fca..a794a8c0e08 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -4,10 +4,12 @@ use crate::ty::{ self, InlineConstSubsts, InlineConstSubstsParts, InternalSubsts, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeFoldable, }; +use rustc_data_structures::intern::Interned; use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_macros::HashStable; +use std::fmt; mod int; mod kind; @@ -17,22 +19,42 @@ pub use int::*; pub use kind::*; pub use valtree::*; +/// Use this rather than `ConstS`, whenever possible. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)] +#[cfg_attr(not(bootstrap), rustc_pass_by_value)] +pub struct Const<'tcx>(pub Interned<'tcx, ConstS<'tcx>>); + +impl<'tcx> fmt::Debug for Const<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // This reflects what `Const` looked liked before `Interned` was + // introduced. We print it like this to avoid having to update expected + // output in a lot of tests. + write!(f, "Const {{ ty: {:?}, val: {:?} }}", self.ty(), self.val()) + } +} + /// Typed constant value. -#[derive(Copy, Clone, Debug, Hash, TyEncodable, TyDecodable, Eq, PartialEq, Ord, PartialOrd)] -#[derive(HashStable)] -pub struct Const<'tcx> { +#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, HashStable, TyEncodable, TyDecodable)] +pub struct ConstS<'tcx> { pub ty: Ty<'tcx>, - pub val: ConstKind<'tcx>, } #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(Const<'_>, 48); +static_assert_size!(ConstS<'_>, 48); impl<'tcx> Const<'tcx> { + pub fn ty(self) -> Ty<'tcx> { + self.0.ty + } + + pub fn val(self) -> ConstKind<'tcx> { + self.0.val + } + /// Literals and const generic parameters are eagerly converted to a constant, everything else /// becomes `Unevaluated`. - pub fn from_anon_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx Self { + pub fn from_anon_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { Self::from_opt_const_arg_anon_const(tcx, ty::WithOptConstParam::unknown(def_id)) } @@ -40,7 +62,7 @@ impl<'tcx> Const<'tcx> { pub fn from_opt_const_arg_anon_const( tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalDefId>, - ) -> &'tcx Self { + ) -> Self { debug!("Const::from_anon_const(def={:?})", def); let body_id = match tcx.hir().get_by_def_id(def.did) { @@ -58,7 +80,7 @@ impl<'tcx> Const<'tcx> { match Self::try_eval_lit_or_param(tcx, ty, expr) { Some(v) => v, - None => tcx.mk_const(ty::Const { + None => tcx.mk_const(ty::ConstS { val: ty::ConstKind::Unevaluated(ty::Unevaluated { def: def.to_global(), substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()), @@ -74,7 +96,7 @@ impl<'tcx> Const<'tcx> { tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, expr: &'tcx hir::Expr<'tcx>, - ) -> Option<&'tcx Self> { + ) -> Option<Self> { // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments // currently have to be wrapped in curly brackets, so it's necessary to special-case. let expr = match &expr.kind { @@ -120,7 +142,7 @@ impl<'tcx> Const<'tcx> { let generics = tcx.generics_of(item_def_id.to_def_id()); let index = generics.param_def_id_to_index[&def_id]; let name = tcx.hir().name(hir_id); - Some(tcx.mk_const(ty::Const { + Some(tcx.mk_const(ty::ConstS { val: ty::ConstKind::Param(ty::ParamConst::new(index, name)), ty, })) @@ -129,7 +151,7 @@ impl<'tcx> Const<'tcx> { } } - pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx Self { + pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { debug!("Const::from_inline_const(def_id={:?})", def_id); let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); @@ -155,7 +177,7 @@ impl<'tcx> Const<'tcx> { let substs = InlineConstSubsts::new(tcx, InlineConstSubstsParts { parent_substs, ty }) .substs; - tcx.mk_const(ty::Const { + tcx.mk_const(ty::ConstS { val: ty::ConstKind::Unevaluated(ty::Unevaluated { def: ty::WithOptConstParam::unknown(def_id).to_global(), substs, @@ -171,19 +193,19 @@ impl<'tcx> Const<'tcx> { /// Interns the given value as a constant. #[inline] - pub fn from_value(tcx: TyCtxt<'tcx>, val: ConstValue<'tcx>, ty: Ty<'tcx>) -> &'tcx Self { - tcx.mk_const(Self { val: ConstKind::Value(val), ty }) + pub fn from_value(tcx: TyCtxt<'tcx>, val: ConstValue<'tcx>, ty: Ty<'tcx>) -> Self { + tcx.mk_const(ConstS { val: ConstKind::Value(val), ty }) } #[inline] /// Interns the given scalar as a constant. - pub fn from_scalar(tcx: TyCtxt<'tcx>, val: Scalar, ty: Ty<'tcx>) -> &'tcx Self { + pub fn from_scalar(tcx: TyCtxt<'tcx>, val: Scalar, ty: Ty<'tcx>) -> Self { Self::from_value(tcx, ConstValue::Scalar(val), ty) } #[inline] /// Creates a constant with the given integer value and interns it. - pub fn from_bits(tcx: TyCtxt<'tcx>, bits: u128, ty: ParamEnvAnd<'tcx, Ty<'tcx>>) -> &'tcx Self { + pub fn from_bits(tcx: TyCtxt<'tcx>, bits: u128, ty: ParamEnvAnd<'tcx, Ty<'tcx>>) -> Self { let size = tcx .layout_of(ty) .unwrap_or_else(|e| panic!("could not compute layout for {:?}: {:?}", ty, e)) @@ -193,19 +215,19 @@ impl<'tcx> Const<'tcx> { #[inline] /// Creates an interned zst constant. - pub fn zero_sized(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx Self { + pub fn zero_sized(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self { Self::from_scalar(tcx, Scalar::ZST, ty) } #[inline] /// Creates an interned bool constant. - pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> &'tcx Self { + pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> Self { Self::from_bits(tcx, v as u128, ParamEnv::empty().and(tcx.types.bool)) } #[inline] /// Creates an interned usize constant. - pub fn from_usize(tcx: TyCtxt<'tcx>, n: u64) -> &'tcx Self { + pub fn from_usize(tcx: TyCtxt<'tcx>, n: u64) -> Self { Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.usize)) } @@ -214,35 +236,35 @@ impl<'tcx> Const<'tcx> { /// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it /// contains const generic parameters or pointers). pub fn try_eval_bits( - &self, + self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>, ) -> Option<u128> { - assert_eq!(self.ty, ty); + assert_eq!(self.ty(), ty); let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size; // if `ty` does not depend on generic parameters, use an empty param_env - self.val.eval(tcx, param_env).try_to_bits(size) + self.val().eval(tcx, param_env).try_to_bits(size) } #[inline] - pub fn try_eval_bool(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> { - self.val.eval(tcx, param_env).try_to_bool() + pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> { + self.val().eval(tcx, param_env).try_to_bool() } #[inline] - pub fn try_eval_usize(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<u64> { - self.val.eval(tcx, param_env).try_to_machine_usize(tcx) + pub fn try_eval_usize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<u64> { + self.val().eval(tcx, param_env).try_to_machine_usize(tcx) } #[inline] /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the /// unevaluated constant. - pub fn eval(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> &Const<'tcx> { - if let Some(val) = self.val.try_eval(tcx, param_env) { + pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Const<'tcx> { + if let Some(val) = self.val().try_eval(tcx, param_env) { match val { - Ok(val) => Const::from_value(tcx, val, self.ty), - Err(ErrorReported) => tcx.const_error(self.ty), + Ok(val) => Const::from_value(tcx, val, self.ty()), + Err(ErrorReported) => tcx.const_error(self.ty()), } } else { self @@ -251,20 +273,20 @@ impl<'tcx> Const<'tcx> { #[inline] /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type. - pub fn eval_bits(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 { + pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 { self.try_eval_bits(tcx, param_env, ty) .unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self)) } #[inline] /// Panics if the value cannot be evaluated or doesn't contain a valid `usize`. - pub fn eval_usize(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u64 { + pub fn eval_usize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u64 { self.try_eval_usize(tcx, param_env) .unwrap_or_else(|| bug!("expected usize, got {:#?}", self)) } } -pub fn const_param_default<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx Const<'tcx> { +pub fn const_param_default<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Const<'tcx> { let default_def_id = match tcx.hir().get_by_def_id(def_id.expect_local()) { hir::Node::GenericParam(hir::GenericParam { kind: hir::GenericParamKind::Const { ty: _, default: Some(ac) }, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 4a3efb5c1b8..41145d25017 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -18,14 +18,15 @@ use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, Substs use crate::ty::TyKind::*; use crate::ty::{ self, AdtDef, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig, - ClosureSizeProfileData, Const, ConstVid, DefIdTree, ExistentialPredicate, FloatTy, FloatVar, - FloatVid, GenericParamDefKind, InferConst, InferTy, IntTy, IntVar, IntVid, List, ParamConst, - ParamTy, PolyFnSig, Predicate, PredicateInner, PredicateKind, ProjectionTy, Region, RegionKind, - ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, UintTy, + ClosureSizeProfileData, Const, ConstS, ConstVid, DefIdTree, ExistentialPredicate, FloatTy, + FloatVar, FloatVid, GenericParamDefKind, InferConst, InferTy, IntTy, IntVar, IntVid, List, + ParamConst, ParamTy, PolyFnSig, Predicate, PredicateKind, PredicateS, ProjectionTy, Region, + RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, UintTy, }; use rustc_ast as ast; use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::intern::Interned; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap}; @@ -91,7 +92,7 @@ pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync { #[derive(TyEncodable, TyDecodable, HashStable)] pub struct DelaySpanBugEmitted(()); -type InternedSet<'tcx, T> = ShardedHashMap<Interned<'tcx, T>, ()>; +type InternedSet<'tcx, T> = ShardedHashMap<InternedInSet<'tcx, T>, ()>; pub struct CtxtInterners<'tcx> { /// The arena that types, regions, etc. are allocated from. @@ -106,11 +107,11 @@ pub struct CtxtInterners<'tcx> { region: InternedSet<'tcx, RegionKind>, poly_existential_predicates: InternedSet<'tcx, List<ty::Binder<'tcx, ExistentialPredicate<'tcx>>>>, - predicate: InternedSet<'tcx, PredicateInner<'tcx>>, + predicate: InternedSet<'tcx, PredicateS<'tcx>>, predicates: InternedSet<'tcx, List<Predicate<'tcx>>>, projs: InternedSet<'tcx, List<ProjectionKind>>, place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>, - const_: InternedSet<'tcx, Const<'tcx>>, + const_: InternedSet<'tcx, ConstS<'tcx>>, const_allocation: InternedSet<'tcx, Allocation>, bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>, layout: InternedSet<'tcx, Layout>, @@ -151,39 +152,40 @@ impl<'tcx> CtxtInterners<'tcx> { #[allow(rustc::usage_of_ty_tykind)] #[inline(never)] fn intern_ty(&self, kind: TyKind<'tcx>) -> Ty<'tcx> { - self.type_ - .intern(kind, |kind| { - let flags = super::flags::FlagComputation::for_kind(&kind); - - let ty_struct = TyS { - kind, - flags: flags.flags, - outer_exclusive_binder: flags.outer_exclusive_binder, - }; + Ty(Interned::new_unchecked( + self.type_ + .intern(kind, |kind| { + let flags = super::flags::FlagComputation::for_kind(&kind); + + let ty_struct = TyS { + kind, + flags: flags.flags, + outer_exclusive_binder: flags.outer_exclusive_binder, + }; - Interned(self.arena.alloc(ty_struct)) - }) - .0 + InternedInSet(self.arena.alloc(ty_struct)) + }) + .0, + )) } #[inline(never)] - fn intern_predicate( - &self, - kind: Binder<'tcx, PredicateKind<'tcx>>, - ) -> &'tcx PredicateInner<'tcx> { - self.predicate - .intern(kind, |kind| { - let flags = super::flags::FlagComputation::for_predicate(kind); - - let predicate_struct = PredicateInner { - kind, - flags: flags.flags, - outer_exclusive_binder: flags.outer_exclusive_binder, - }; + fn intern_predicate(&self, kind: Binder<'tcx, PredicateKind<'tcx>>) -> Predicate<'tcx> { + Predicate(Interned::new_unchecked( + self.predicate + .intern(kind, |kind| { + let flags = super::flags::FlagComputation::for_predicate(kind); + + let predicate_struct = PredicateS { + kind, + flags: flags.flags, + outer_exclusive_binder: flags.outer_exclusive_binder, + }; - Interned(self.arena.alloc(predicate_struct)) - }) - .0 + InternedInSet(self.arena.alloc(predicate_struct)) + }) + .0, + )) } } @@ -227,7 +229,7 @@ pub struct CommonLifetimes<'tcx> { } pub struct CommonConsts<'tcx> { - pub unit: &'tcx Const<'tcx>, + pub unit: Const<'tcx>, } pub struct LocalTableInContext<'a, V> { @@ -858,16 +860,16 @@ impl<'tcx> CanonicalUserType<'tcx> { _ => false, }, - GenericArgKind::Lifetime(r) => match r { + GenericArgKind::Lifetime(r) => match *r { ty::ReLateBound(debruijn, br) => { // We only allow a `ty::INNERMOST` index in substitutions. - assert_eq!(*debruijn, ty::INNERMOST); + assert_eq!(debruijn, ty::INNERMOST); cvar == br.var } _ => false, }, - GenericArgKind::Const(ct) => match ct.val { + GenericArgKind::Const(ct) => match ct.val() { ty::ConstKind::Bound(debruijn, b) => { // We only allow a `ty::INNERMOST` index in substitutions. assert_eq!(debruijn, ty::INNERMOST); @@ -928,22 +930,30 @@ impl<'tcx> CommonTypes<'tcx> { impl<'tcx> CommonLifetimes<'tcx> { fn new(interners: &CtxtInterners<'tcx>) -> CommonLifetimes<'tcx> { - let mk = |r| interners.region.intern(r, |r| Interned(interners.arena.alloc(r))).0; + let mk = |r| { + Region(Interned::new_unchecked( + interners.region.intern(r, |r| InternedInSet(interners.arena.alloc(r))).0, + )) + }; CommonLifetimes { - re_root_empty: mk(RegionKind::ReEmpty(ty::UniverseIndex::ROOT)), - re_static: mk(RegionKind::ReStatic), - re_erased: mk(RegionKind::ReErased), + re_root_empty: mk(ty::ReEmpty(ty::UniverseIndex::ROOT)), + re_static: mk(ty::ReStatic), + re_erased: mk(ty::ReErased), } } } impl<'tcx> CommonConsts<'tcx> { fn new(interners: &CtxtInterners<'tcx>, types: &CommonTypes<'tcx>) -> CommonConsts<'tcx> { - let mk_const = |c| interners.const_.intern(c, |c| Interned(interners.arena.alloc(c))).0; + let mk_const = |c| { + Const(Interned::new_unchecked( + interners.const_.intern(c, |c| InternedInSet(interners.arena.alloc(c))).0, + )) + }; CommonConsts { - unit: mk_const(ty::Const { + unit: mk_const(ty::ConstS { val: ty::ConstKind::Value(ConstValue::Scalar(Scalar::ZST)), ty: types.unit, }), @@ -1215,7 +1225,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Like [TyCtxt::ty_error] but for constants. #[track_caller] - pub fn const_error(self, ty: Ty<'tcx>) -> &'tcx Const<'tcx> { + pub fn const_error(self, ty: Ty<'tcx>) -> Const<'tcx> { self.const_error_with_message( ty, DUMMY_SP, @@ -1230,9 +1240,9 @@ impl<'tcx> TyCtxt<'tcx> { ty: Ty<'tcx>, span: S, msg: &str, - ) -> &'tcx Const<'tcx> { + ) -> Const<'tcx> { self.sess.delay_span_bug(span, msg); - self.mk_const(ty::Const { val: ty::ConstKind::Error(DelaySpanBugEmitted(())), ty }) + self.mk_const(ty::ConstS { val: ty::ConstKind::Error(DelaySpanBugEmitted(())), ty }) } pub fn consider_optimizing<T: Fn() -> String>(self, msg: T) -> bool { @@ -1627,12 +1637,28 @@ pub trait Lift<'tcx>: fmt::Debug { fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted>; } +// Deprecated: we are in the process of converting all uses to `nop_lift`. +macro_rules! nop_lift_old { + ($set:ident; $ty:ty => $lifted:ty) => { + impl<'a, 'tcx> Lift<'tcx> for $ty { + type Lifted = $lifted; + fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { + if tcx.interners.$set.contains_pointer_to(&InternedInSet(self)) { + Some(unsafe { mem::transmute(self) }) + } else { + None + } + } + } + }; +} + macro_rules! nop_lift { ($set:ident; $ty:ty => $lifted:ty) => { impl<'a, 'tcx> Lift<'tcx> for $ty { type Lifted = $lifted; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - if tcx.interners.$set.contains_pointer_to(&Interned(self)) { + if tcx.interners.$set.contains_pointer_to(&InternedInSet(self.0.0)) { Some(unsafe { mem::transmute(self) }) } else { None @@ -1650,7 +1676,7 @@ macro_rules! nop_list_lift { if self.is_empty() { return Some(List::empty()); } - if tcx.interners.$set.contains_pointer_to(&Interned(self)) { + if tcx.interners.$set.contains_pointer_to(&InternedInSet(self)) { Some(unsafe { mem::transmute(self) }) } else { None @@ -1662,9 +1688,9 @@ macro_rules! nop_list_lift { nop_lift! {type_; Ty<'a> => Ty<'tcx>} nop_lift! {region; Region<'a> => Region<'tcx>} -nop_lift! {const_; &'a Const<'a> => &'tcx Const<'tcx>} -nop_lift! {const_allocation; &'a Allocation => &'tcx Allocation} -nop_lift! {predicate; &'a PredicateInner<'a> => &'tcx PredicateInner<'tcx>} +nop_lift! {const_; Const<'a> => Const<'tcx>} +nop_lift_old! {const_allocation; &'a Allocation => &'tcx Allocation} +nop_lift! {predicate; Predicate<'a> => Predicate<'tcx>} nop_list_lift! {type_list; Ty<'a> => Ty<'tcx>} nop_list_lift! {poly_existential_predicates; ty::Binder<'a, ExistentialPredicate<'a>> => ty::Binder<'tcx, ExistentialPredicate<'tcx>>} @@ -1857,7 +1883,7 @@ macro_rules! sty_debug_print { #[allow(non_snake_case)] mod inner { use crate::ty::{self, TyCtxt}; - use crate::ty::context::Interned; + use crate::ty::context::InternedInSet; #[derive(Copy, Clone)] struct DebugStat { @@ -1880,16 +1906,16 @@ macro_rules! sty_debug_print { let shards = tcx.interners.type_.lock_shards(); let types = shards.iter().flat_map(|shard| shard.keys()); - for &Interned(t) in types { - let variant = match t.kind() { + for &InternedInSet(t) in types { + let variant = match t.kind { ty::Bool | ty::Char | ty::Int(..) | ty::Uint(..) | ty::Float(..) | ty::Str | ty::Never => continue, ty::Error(_) => /* unimportant */ continue, $(ty::$variant(..) => &mut $variant,)* }; - let lt = t.flags().intersects(ty::TypeFlags::HAS_RE_INFER); - let ty = t.flags().intersects(ty::TypeFlags::HAS_TY_INFER); - let ct = t.flags().intersects(ty::TypeFlags::HAS_CT_INFER); + let lt = t.flags.intersects(ty::TypeFlags::HAS_RE_INFER); + let ty = t.flags.intersects(ty::TypeFlags::HAS_TY_INFER); + let ct = t.flags.intersects(ty::TypeFlags::HAS_CT_INFER); variant.total += 1; total.total += 1; @@ -1980,86 +2006,86 @@ impl<'tcx> TyCtxt<'tcx> { // this type just holds a pointer to it, but it still effectively owns it. It // impls `Borrow` so that it can be looked up using the original // (non-arena-memory-owning) types. -struct Interned<'tcx, T: ?Sized>(&'tcx T); +struct InternedInSet<'tcx, T: ?Sized>(&'tcx T); -impl<'tcx, T: 'tcx + ?Sized> Clone for Interned<'tcx, T> { +impl<'tcx, T: 'tcx + ?Sized> Clone for InternedInSet<'tcx, T> { fn clone(&self) -> Self { - Interned(self.0) + InternedInSet(self.0) } } -impl<'tcx, T: 'tcx + ?Sized> Copy for Interned<'tcx, T> {} +impl<'tcx, T: 'tcx + ?Sized> Copy for InternedInSet<'tcx, T> {} -impl<'tcx, T: 'tcx + ?Sized> IntoPointer for Interned<'tcx, T> { +impl<'tcx, T: 'tcx + ?Sized> IntoPointer for InternedInSet<'tcx, T> { fn into_pointer(&self) -> *const () { self.0 as *const _ as *const () } } #[allow(rustc::usage_of_ty_tykind)] -impl<'tcx> Borrow<TyKind<'tcx>> for Interned<'tcx, TyS<'tcx>> { +impl<'tcx> Borrow<TyKind<'tcx>> for InternedInSet<'tcx, TyS<'tcx>> { fn borrow<'a>(&'a self) -> &'a TyKind<'tcx> { - &self.0.kind() + &self.0.kind } } -impl<'tcx> PartialEq for Interned<'tcx, TyS<'tcx>> { - fn eq(&self, other: &Interned<'tcx, TyS<'tcx>>) -> bool { +impl<'tcx> PartialEq for InternedInSet<'tcx, TyS<'tcx>> { + fn eq(&self, other: &InternedInSet<'tcx, TyS<'tcx>>) -> bool { // The `Borrow` trait requires that `x.borrow() == y.borrow()` equals // `x == y`. - self.0.kind() == other.0.kind() + self.0.kind == other.0.kind } } -impl<'tcx> Eq for Interned<'tcx, TyS<'tcx>> {} +impl<'tcx> Eq for InternedInSet<'tcx, TyS<'tcx>> {} -impl<'tcx> Hash for Interned<'tcx, TyS<'tcx>> { +impl<'tcx> Hash for InternedInSet<'tcx, TyS<'tcx>> { fn hash<H: Hasher>(&self, s: &mut H) { // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`. - self.0.kind().hash(s) + self.0.kind.hash(s) } } -impl<'tcx> Borrow<Binder<'tcx, PredicateKind<'tcx>>> for Interned<'tcx, PredicateInner<'tcx>> { +impl<'tcx> Borrow<Binder<'tcx, PredicateKind<'tcx>>> for InternedInSet<'tcx, PredicateS<'tcx>> { fn borrow<'a>(&'a self) -> &'a Binder<'tcx, PredicateKind<'tcx>> { &self.0.kind } } -impl<'tcx> PartialEq for Interned<'tcx, PredicateInner<'tcx>> { - fn eq(&self, other: &Interned<'tcx, PredicateInner<'tcx>>) -> bool { +impl<'tcx> PartialEq for InternedInSet<'tcx, PredicateS<'tcx>> { + fn eq(&self, other: &InternedInSet<'tcx, PredicateS<'tcx>>) -> bool { // The `Borrow` trait requires that `x.borrow() == y.borrow()` equals // `x == y`. self.0.kind == other.0.kind } } -impl<'tcx> Eq for Interned<'tcx, PredicateInner<'tcx>> {} +impl<'tcx> Eq for InternedInSet<'tcx, PredicateS<'tcx>> {} -impl<'tcx> Hash for Interned<'tcx, PredicateInner<'tcx>> { +impl<'tcx> Hash for InternedInSet<'tcx, PredicateS<'tcx>> { fn hash<H: Hasher>(&self, s: &mut H) { // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`. self.0.kind.hash(s) } } -impl<'tcx, T> Borrow<[T]> for Interned<'tcx, List<T>> { +impl<'tcx, T> Borrow<[T]> for InternedInSet<'tcx, List<T>> { fn borrow<'a>(&'a self) -> &'a [T] { &self.0[..] } } -impl<'tcx, T: PartialEq> PartialEq for Interned<'tcx, List<T>> { - fn eq(&self, other: &Interned<'tcx, List<T>>) -> bool { +impl<'tcx, T: PartialEq> PartialEq for InternedInSet<'tcx, List<T>> { + fn eq(&self, other: &InternedInSet<'tcx, List<T>>) -> bool { // The `Borrow` trait requires that `x.borrow() == y.borrow()` equals // `x == y`. self.0[..] == other.0[..] } } -impl<'tcx, T: Eq> Eq for Interned<'tcx, List<T>> {} +impl<'tcx, T: Eq> Eq for InternedInSet<'tcx, List<T>> {} -impl<'tcx, T: Hash> Hash for Interned<'tcx, List<T>> { +impl<'tcx, T: Hash> Hash for InternedInSet<'tcx, List<T>> { fn hash<H: Hasher>(&self, s: &mut H) { // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`. self.0[..].hash(s) @@ -2067,14 +2093,55 @@ impl<'tcx, T: Hash> Hash for Interned<'tcx, List<T>> { } macro_rules! direct_interners { + ($($name:ident: $method:ident($ty:ty): $ret_ctor:ident -> $ret_ty:ty,)+) => { + $(impl<'tcx> Borrow<$ty> for InternedInSet<'tcx, $ty> { + fn borrow<'a>(&'a self) -> &'a $ty { + &self.0 + } + } + + impl<'tcx> PartialEq for InternedInSet<'tcx, $ty> { + fn eq(&self, other: &Self) -> bool { + // The `Borrow` trait requires that `x.borrow() == y.borrow()` + // equals `x == y`. + self.0 == other.0 + } + } + + impl<'tcx> Eq for InternedInSet<'tcx, $ty> {} + + impl<'tcx> Hash for InternedInSet<'tcx, $ty> { + fn hash<H: Hasher>(&self, s: &mut H) { + // The `Borrow` trait requires that `x.borrow().hash(s) == + // x.hash(s)`. + self.0.hash(s) + } + } + + impl<'tcx> TyCtxt<'tcx> { + pub fn $method(self, v: $ty) -> $ret_ty { + $ret_ctor(Interned::new_unchecked(self.interners.$name.intern(v, |v| { + InternedInSet(self.interners.arena.alloc(v)) + }).0)) + } + })+ + } +} + +direct_interners! { + region: mk_region(RegionKind): Region -> Region<'tcx>, + const_: mk_const(ConstS<'tcx>): Const -> Const<'tcx>, +} + +macro_rules! direct_interners_old { ($($name:ident: $method:ident($ty:ty),)+) => { - $(impl<'tcx> Borrow<$ty> for Interned<'tcx, $ty> { + $(impl<'tcx> Borrow<$ty> for InternedInSet<'tcx, $ty> { fn borrow<'a>(&'a self) -> &'a $ty { &self.0 } } - impl<'tcx> PartialEq for Interned<'tcx, $ty> { + impl<'tcx> PartialEq for InternedInSet<'tcx, $ty> { fn eq(&self, other: &Self) -> bool { // The `Borrow` trait requires that `x.borrow() == y.borrow()` // equals `x == y`. @@ -2082,9 +2149,9 @@ macro_rules! direct_interners { } } - impl<'tcx> Eq for Interned<'tcx, $ty> {} + impl<'tcx> Eq for InternedInSet<'tcx, $ty> {} - impl<'tcx> Hash for Interned<'tcx, $ty> { + impl<'tcx> Hash for InternedInSet<'tcx, $ty> { fn hash<H: Hasher>(&self, s: &mut H) { // The `Borrow` trait requires that `x.borrow().hash(s) == // x.hash(s)`. @@ -2095,16 +2162,15 @@ macro_rules! direct_interners { impl<'tcx> TyCtxt<'tcx> { pub fn $method(self, v: $ty) -> &'tcx $ty { self.interners.$name.intern(v, |v| { - Interned(self.interners.arena.alloc(v)) + InternedInSet(self.interners.arena.alloc(v)) }).0 } })+ } } -direct_interners! { - region: mk_region(RegionKind), - const_: mk_const(Const<'tcx>), +// FIXME: eventually these should all be converted to `direct_interners`. +direct_interners_old! { const_allocation: intern_const_alloc(Allocation), layout: intern_layout(Layout), adt_def: intern_adt_def(AdtDef), @@ -2117,7 +2183,7 @@ macro_rules! slice_interners { impl<'tcx> TyCtxt<'tcx> { $(pub fn $method(self, v: &[$ty]) -> &'tcx List<$ty> { self.interners.$field.intern_ref(v, || { - Interned(List::from_arena(&*self.arena, v)) + InternedInSet(List::from_arena(&*self.arena, v)) }).0 })+ } @@ -2217,8 +2283,7 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn mk_predicate(self, binder: Binder<'tcx, PredicateKind<'tcx>>) -> Predicate<'tcx> { - let inner = self.interners.intern_predicate(binder); - Predicate { inner } + self.interners.intern_predicate(binder) } #[inline] @@ -2429,8 +2494,8 @@ impl<'tcx> TyCtxt<'tcx> { } #[inline] - pub fn mk_const_var(self, v: ConstVid<'tcx>, ty: Ty<'tcx>) -> &'tcx Const<'tcx> { - self.mk_const(ty::Const { val: ty::ConstKind::Infer(InferConst::Var(v)), ty }) + pub fn mk_const_var(self, v: ConstVid<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { + self.mk_const(ty::ConstS { val: ty::ConstKind::Infer(InferConst::Var(v)), ty }) } #[inline] @@ -2449,8 +2514,8 @@ impl<'tcx> TyCtxt<'tcx> { } #[inline] - pub fn mk_const_infer(self, ic: InferConst<'tcx>, ty: Ty<'tcx>) -> &'tcx ty::Const<'tcx> { - self.mk_const(ty::Const { val: ty::ConstKind::Infer(ic), ty }) + pub fn mk_const_infer(self, ic: InferConst<'tcx>, ty: Ty<'tcx>) -> ty::Const<'tcx> { + self.mk_const(ty::ConstS { val: ty::ConstKind::Infer(ic), ty }) } #[inline] @@ -2459,8 +2524,8 @@ impl<'tcx> TyCtxt<'tcx> { } #[inline] - pub fn mk_const_param(self, index: u32, name: Symbol, ty: Ty<'tcx>) -> &'tcx Const<'tcx> { - self.mk_const(ty::Const { val: ty::ConstKind::Param(ParamConst { index, name }), ty }) + pub fn mk_const_param(self, index: u32, name: Symbol, ty: Ty<'tcx>) -> Const<'tcx> { + self.mk_const(ty::ConstS { val: ty::ConstKind::Param(ParamConst { index, name }), ty }) } pub fn mk_param_from_def(self, param: &ty::GenericParamDef) -> GenericArg<'tcx> { diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index d68c5514821..64b2edd2c3f 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -1,10 +1,10 @@ -//! Diagnostics related methods for `TyS`. +//! Diagnostics related methods for `Ty`. use crate::ty::subst::{GenericArg, GenericArgKind}; use crate::ty::TyKind::*; use crate::ty::{ ConstKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, InferTy, - ProjectionTy, Term, TyCtxt, TyS, TypeAndMut, + ProjectionTy, Term, Ty, TyCtxt, TypeAndMut, }; use rustc_errors::{Applicability, DiagnosticBuilder}; @@ -13,9 +13,9 @@ use rustc_hir::def_id::DefId; use rustc_hir::{QPath, TyKind, WhereBoundPredicate, WherePredicate}; use rustc_span::Span; -impl<'tcx> TyS<'tcx> { - /// Similar to `TyS::is_primitive`, but also considers inferred numeric values to be primitive. - pub fn is_primitive_ty(&self) -> bool { +impl<'tcx> Ty<'tcx> { + /// Similar to `Ty::is_primitive`, but also considers inferred numeric values to be primitive. + pub fn is_primitive_ty(self) -> bool { matches!( self.kind(), Bool | Char @@ -34,7 +34,7 @@ impl<'tcx> TyS<'tcx> { /// Whether the type is succinctly representable as a type instead of just referred to with a /// description in error messages. This is used in the main error message. - pub fn is_simple_ty(&self) -> bool { + pub fn is_simple_ty(self) -> bool { match self.kind() { Bool | Char @@ -58,7 +58,7 @@ impl<'tcx> TyS<'tcx> { /// description in error messages. This is used in the primary span label. Beyond what /// `is_simple_ty` includes, it also accepts ADTs with no type arguments and references to /// ADTs with no type arguments. - pub fn is_simple_text(&self) -> bool { + pub fn is_simple_text(self) -> bool { match self.kind() { Adt(_, substs) => substs.non_erasable_generics().next().is_none(), Ref(_, ty, _) => ty.is_simple_text(), @@ -67,11 +67,11 @@ impl<'tcx> TyS<'tcx> { } /// Whether the type can be safely suggested during error recovery. - pub fn is_suggestable(&self) -> bool { + pub fn is_suggestable(self) -> bool { fn generic_arg_is_suggestible(arg: GenericArg<'_>) -> bool { match arg.unpack() { GenericArgKind::Type(ty) => ty.is_suggestable(), - GenericArgKind::Const(c) => const_is_suggestable(c.val), + GenericArgKind::Const(c) => const_is_suggestable(c.val()), _ => true, } } @@ -110,7 +110,7 @@ impl<'tcx> TyS<'tcx> { }) => { let term_is_suggestable = match term { Term::Ty(ty) => ty.is_suggestable(), - Term::Const(c) => const_is_suggestable(c.val), + Term::Const(c) => const_is_suggestable(c.val()), }; term_is_suggestable && substs.iter().all(generic_arg_is_suggestible) } @@ -120,7 +120,7 @@ impl<'tcx> TyS<'tcx> { args.iter().all(generic_arg_is_suggestible) } Slice(ty) | RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => ty.is_suggestable(), - Array(ty, c) => ty.is_suggestable() && const_is_suggestable(c.val), + Array(ty, c) => ty.is_suggestable() && const_is_suggestable(c.val()), _ => true, } } diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 5c4a4cdde25..2ccfeba2b66 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -60,13 +60,13 @@ pub enum TypeError<'tcx> { /// created a cycle (because it appears somewhere within that /// type). CyclicTy(Ty<'tcx>), - CyclicConst(&'tcx ty::Const<'tcx>), + CyclicConst(ty::Const<'tcx>), ProjectionMismatched(ExpectedFound<DefId>), ExistentialMismatch( ExpectedFound<&'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>>, ), ObjectUnsafeCoercion(DefId), - ConstMismatch(ExpectedFound<&'tcx ty::Const<'tcx>>), + ConstMismatch(ExpectedFound<ty::Const<'tcx>>), IntrinsicCast, /// Safe `#[target_feature]` functions are not assignable to safe function pointers. @@ -239,8 +239,8 @@ impl<'tcx> TypeError<'tcx> { } } -impl<'tcx> ty::TyS<'tcx> { - pub fn sort_string(&self, tcx: TyCtxt<'_>) -> Cow<'static, str> { +impl<'tcx> Ty<'tcx> { + pub fn sort_string(self, tcx: TyCtxt<'_>) -> Cow<'static, str> { match *self.kind() { ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => { format!("`{}`", self).into() @@ -255,7 +255,7 @@ impl<'tcx> ty::TyS<'tcx> { } let n = tcx.lift(n).unwrap(); - if let ty::ConstKind::Value(v) = n.val { + if let ty::ConstKind::Value(v) = n.val() { if let Some(n) = v.try_to_machine_usize(tcx) { return format!("array of {} element{}", n, pluralize!(n)).into(); } @@ -306,7 +306,7 @@ impl<'tcx> ty::TyS<'tcx> { } } - pub fn prefix_string(&self, tcx: TyCtxt<'_>) -> Cow<'static, str> { + pub fn prefix_string(self, tcx: TyCtxt<'_>) -> Cow<'static, str> { match *self.kind() { ty::Infer(_) | ty::Error(_) diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index daf9156a15f..983057bff95 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -54,12 +54,6 @@ pub enum SimplifyParams { No, } -#[derive(PartialEq, Eq, Debug, Clone, Copy)] -pub enum StripReferences { - Yes, - No, -} - /// Tries to simplify a type by only returning the outermost injective¹ layer, if one exists. /// /// The idea is to get something simple that we can use to quickly decide if two types could unify, @@ -73,8 +67,6 @@ pub enum StripReferences { /// When using `SimplifyParams::Yes`, we still return a simplified type for params and projections², /// the reasoning for this can be seen at the places doing this. /// -/// For diagnostics we strip references with `StripReferences::Yes`. This is currently the best -/// way to skip some unhelpful suggestions. /// /// ¹ meaning that if two outermost layers are different, then the whole types are also different. /// ² FIXME(@lcnr): this seems like it can actually end up being unsound with the way it's used during @@ -87,7 +79,6 @@ pub fn simplify_type( tcx: TyCtxt<'_>, ty: Ty<'_>, can_simplify_params: SimplifyParams, - strip_references: StripReferences, ) -> Option<SimplifiedType> { match *ty.kind() { ty::Bool => Some(BoolSimplifiedType), @@ -106,16 +97,7 @@ pub fn simplify_type( } _ => Some(MarkerTraitObjectSimplifiedType), }, - ty::Ref(_, ty, mutbl) => { - if strip_references == StripReferences::Yes { - // For diagnostics, when recommending similar impls we want to - // recommend impls even when there is a reference mismatch, - // so we treat &T and T equivalently in that case. - simplify_type(tcx, ty, can_simplify_params, strip_references) - } else { - Some(RefSimplifiedType(mutbl)) - } - } + ty::Ref(_, _, mutbl) => Some(RefSimplifiedType(mutbl)), ty::FnDef(def_id, _) | ty::Closure(def_id, _) => Some(ClosureSimplifiedType(def_id)), ty::Generator(def_id, _, _) => Some(GeneratorSimplifiedType(def_id)), ty::GeneratorWitness(ref tys) => { diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index f06a1b09cd8..948a48c0826 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -6,7 +6,7 @@ use std::slice; pub struct FlagComputation { pub flags: TypeFlags, - // see `TyS::outer_exclusive_binder` for details + // see `Ty::outer_exclusive_binder` for details pub outer_exclusive_binder: ty::DebruijnIndex, } @@ -28,7 +28,7 @@ impl FlagComputation { result } - pub fn for_const(c: &ty::Const<'_>) -> TypeFlags { + pub fn for_const(c: ty::Const<'_>) -> TypeFlags { let mut result = FlagComputation::new(); result.add_const(c); result.flags @@ -270,7 +270,7 @@ impl FlagComputation { fn add_ty(&mut self, ty: Ty<'_>) { self.add_flags(ty.flags()); - self.add_exclusive_binder(ty.outer_exclusive_binder); + self.add_exclusive_binder(ty.outer_exclusive_binder()); } fn add_tys(&mut self, tys: &[Ty<'_>]) { @@ -286,9 +286,9 @@ impl FlagComputation { } } - fn add_const(&mut self, c: &ty::Const<'_>) { - self.add_ty(c.ty); - match c.val { + fn add_const(&mut self, c: ty::Const<'_>) { + self.add_ty(c.ty()); + match c.val() { ty::ConstKind::Unevaluated(unevaluated) => self.add_unevaluated_const(unevaluated), ty::ConstKind::Infer(infer) => { self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 3133cdfdd7a..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. @@ -216,7 +248,7 @@ pub trait TypeFolder<'tcx>: Sized { r.super_fold_with(self) } - fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> + fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> where Self: TypeFolder<'tcx, Error = !>, { @@ -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 @@ -263,10 +293,7 @@ pub trait FallibleTypeFolder<'tcx>: TypeFolder<'tcx> { r.try_super_fold_with(self) } - fn try_fold_const( - &mut self, - c: &'tcx ty::Const<'tcx>, - ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> { + fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> { c.try_super_fold_with(self) } @@ -285,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 = !>, @@ -306,10 +333,7 @@ where Ok(self.fold_region(r)) } - fn try_fold_const( - &mut self, - c: &'tcx ty::Const<'tcx>, - ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> { + fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> { Ok(self.fold_const(c)) } @@ -328,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 = !; @@ -346,7 +373,7 @@ pub trait TypeVisitor<'tcx>: Sized { r.super_visit_with(self) } - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { + fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { c.super_visit_with(self) } @@ -366,7 +393,7 @@ pub struct BottomUpFolder<'tcx, F, G, H> where F: FnMut(Ty<'tcx>) -> Ty<'tcx>, G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>, - H: FnMut(&'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx>, + H: FnMut(ty::Const<'tcx>) -> ty::Const<'tcx>, { pub tcx: TyCtxt<'tcx>, pub ty_op: F, @@ -378,7 +405,7 @@ impl<'tcx, F, G, H> TypeFolder<'tcx> for BottomUpFolder<'tcx, F, G, H> where F: FnMut(Ty<'tcx>) -> Ty<'tcx>, G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>, - H: FnMut(&'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx>, + H: FnMut(ty::Const<'tcx>) -> ty::Const<'tcx>, { fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { self.tcx @@ -394,7 +421,7 @@ where (self.lt_op)(r) } - fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { let ct = ct.super_fold_with(self); (self.ct_op)(ct) } @@ -593,7 +620,7 @@ struct BoundVarReplacer<'a, 'tcx> { fld_r: Option<&'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a)>, fld_t: Option<&'a mut (dyn FnMut(ty::BoundTy) -> Ty<'tcx> + 'a)>, - fld_c: Option<&'a mut (dyn FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::Const<'tcx> + 'a)>, + fld_c: Option<&'a mut (dyn FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx> + 'a)>, } impl<'a, 'tcx> BoundVarReplacer<'a, 'tcx> { @@ -601,7 +628,7 @@ impl<'a, 'tcx> BoundVarReplacer<'a, 'tcx> { tcx: TyCtxt<'tcx>, fld_r: Option<&'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a)>, fld_t: Option<&'a mut (dyn FnMut(ty::BoundTy) -> Ty<'tcx> + 'a)>, - fld_c: Option<&'a mut (dyn FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::Const<'tcx> + 'a)>, + fld_c: Option<&'a mut (dyn FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx> + 'a)>, ) -> Self { BoundVarReplacer { tcx, current_index: ty::INNERMOST, fld_r, fld_t, fld_c } } @@ -627,7 +654,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for BoundVarReplacer<'a, 'tcx> { ty::Bound(debruijn, bound_ty) if debruijn == self.current_index => { if let Some(fld_t) = self.fld_t.as_mut() { let ty = fld_t(bound_ty); - return ty::fold::shift_vars(self.tcx, &ty, self.current_index.as_u32()); + return ty::fold::shift_vars(self.tcx, ty, self.current_index.as_u32()); } } _ if t.has_vars_bound_at_or_above(self.current_index) => { @@ -660,14 +687,12 @@ impl<'a, 'tcx> TypeFolder<'tcx> for BoundVarReplacer<'a, 'tcx> { r } - fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - match *ct { - ty::Const { val: ty::ConstKind::Bound(debruijn, bound_const), ty } - if debruijn == self.current_index => - { + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + match ct.val() { + ty::ConstKind::Bound(debruijn, bound_const) if debruijn == self.current_index => { if let Some(fld_c) = self.fld_c.as_mut() { - let ct = fld_c(bound_const, ty); - return ty::fold::shift_vars(self.tcx, &ct, self.current_index.as_u32()); + let ct = fld_c(bound_const, ct.ty()); + return ty::fold::shift_vars(self.tcx, ct, self.current_index.as_u32()); } } _ if ct.has_vars_bound_at_or_above(self.current_index) => { @@ -726,7 +751,7 @@ impl<'tcx> TyCtxt<'tcx> { where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>, G: FnMut(ty::BoundTy) -> Ty<'tcx>, - H: FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::Const<'tcx>, + H: FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx>, T: TypeFoldable<'tcx>, { if !value.has_escaping_bound_vars() { @@ -751,7 +776,7 @@ impl<'tcx> TyCtxt<'tcx> { where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>, G: FnMut(ty::BoundTy) -> Ty<'tcx>, - H: FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::Const<'tcx>, + H: FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx>, T: TypeFoldable<'tcx>, { let mut region_map = BTreeMap::new(); @@ -804,7 +829,7 @@ impl<'tcx> TyCtxt<'tcx> { )) }, |c, ty| { - self.mk_const(ty::Const { + self.mk_const(ty::ConstS { val: ty::ConstKind::Bound( ty::INNERMOST, ty::BoundVar::from_usize(c.as_usize() + bound_vars), @@ -926,7 +951,7 @@ impl<'tcx> TypeVisitor<'tcx> for ValidateBoundVars<'tcx> { } fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { - if t.outer_exclusive_binder < self.binder_index + if t.outer_exclusive_binder() < self.binder_index || !self.visited.insert((self.binder_index, t)) { return ControlFlow::BREAK; @@ -960,10 +985,10 @@ impl<'tcx> TypeVisitor<'tcx> for ValidateBoundVars<'tcx> { } fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { - match r { - ty::ReLateBound(index, br) if *index == self.binder_index => { + match *r { + ty::ReLateBound(index, br) if index == self.binder_index => { if self.bound_vars.len() <= br.var.as_usize() { - bug!("Not enough bound vars: {:?} not found in {:?}", *br, self.bound_vars); + bug!("Not enough bound vars: {:?} not found in {:?}", br, self.bound_vars); } let list_var = self.bound_vars[br.var.as_usize()]; match list_var { @@ -1057,13 +1082,16 @@ impl<'tcx> TypeFolder<'tcx> for Shifter<'tcx> { } } - fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - if let ty::Const { val: ty::ConstKind::Bound(debruijn, bound_ct), ty } = *ct { + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + if let ty::ConstKind::Bound(debruijn, bound_ct) = ct.val() { if self.amount == 0 || debruijn < self.current_index { ct } else { let debruijn = debruijn.shifted_in(self.amount); - self.tcx.mk_const(ty::Const { val: ty::ConstKind::Bound(debruijn, bound_ct), ty }) + self.tcx.mk_const(ty::ConstS { + val: ty::ConstKind::Bound(debruijn, bound_ct), + ty: ct.ty(), + }) } } else { ct.super_fold_with(self) @@ -1076,9 +1104,9 @@ pub fn shift_region<'tcx>( region: ty::Region<'tcx>, amount: u32, ) -> ty::Region<'tcx> { - match region { + match *region { ty::ReLateBound(debruijn, br) if amount > 0 => { - tcx.mk_region(ty::ReLateBound(debruijn.shifted_in(amount), *br)) + tcx.mk_region(ty::ReLateBound(debruijn.shifted_in(amount), br)) } _ => region, } @@ -1146,7 +1174,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { // bound at `outer_index` or above (because // `outer_exclusive_binder` is always 1 higher than the // content in `t`). Therefore, `t` has some escaping vars. - if t.outer_exclusive_binder > self.outer_index { + if t.outer_exclusive_binder() > self.outer_index { ControlFlow::Break(FoundEscapingVars) } else { ControlFlow::CONTINUE @@ -1165,13 +1193,13 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { } } - fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { + fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { // we don't have a `visit_infer_const` callback, so we have to // hook in here to catch this case (annoying...), but // otherwise we do want to remember to visit the rest of the // const, as it has types/regions embedded in a lot of other // places. - match ct.val { + match ct.val() { ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => { ControlFlow::Break(FoundEscapingVars) } @@ -1181,7 +1209,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { #[inline] fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> { - if predicate.inner.outer_exclusive_binder > self.outer_index { + if predicate.outer_exclusive_binder() > self.outer_index { ControlFlow::Break(FoundEscapingVars) } else { ControlFlow::CONTINUE @@ -1236,7 +1264,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { #[inline] #[instrument(level = "trace")] - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { + fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { let flags = FlagComputation::for_const(c); trace!(r.flags=?flags); if flags.intersects(self.flags) { @@ -1263,9 +1291,11 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> { debug!( "HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}", - predicate, predicate.inner.flags, self.flags + predicate, + predicate.flags(), + self.flags ); - if predicate.inner.flags.intersects(self.flags) { + if predicate.flags().intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { ControlFlow::CONTINUE @@ -1323,12 +1353,12 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { t.super_visit_with(self) } - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { + fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { // if we are only looking for "constrained" region, we have to // ignore the inputs of an unevaluated const, as they may not appear // in the normalized form if self.just_constrained { - if let ty::ConstKind::Unevaluated(..) = c.val { + if let ty::ConstKind::Unevaluated(..) = c.val() { return ControlFlow::CONTINUE; } } diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index 14ddccbfd83..f2682b8bcd8 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -3,7 +3,7 @@ pub use self::def_id_forest::DefIdForest; use crate::ty; use crate::ty::context::TyCtxt; use crate::ty::TyKind::*; -use crate::ty::{AdtDef, FieldDef, Ty, TyS, VariantDef}; +use crate::ty::{AdtDef, FieldDef, Ty, VariantDef}; use crate::ty::{AdtKind, Visibility}; use crate::ty::{DefId, SubstsRef}; @@ -184,10 +184,10 @@ impl<'tcx> FieldDef { } } -impl<'tcx> TyS<'tcx> { +impl<'tcx> Ty<'tcx> { /// Calculates the forest of `DefId`s from which this type is visibly uninhabited. fn uninhabited_from( - &'tcx self, + self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> DefIdForest<'tcx> { diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index eaa7ee84b7b..99c595fcdf1 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -101,7 +101,7 @@ impl<'tcx> Instance<'tcx> { /// lifetimes erased, allowing a `ParamEnv` to be specified for use during normalization. pub fn ty(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Ty<'tcx> { let ty = tcx.type_of(self.def.def_id()); - tcx.subst_and_normalize_erasing_regions(self.substs, param_env, &ty) + tcx.subst_and_normalize_erasing_regions(self.substs, param_env, ty) } /// Finds a crate that contains a monomorphization of this instance that @@ -642,7 +642,7 @@ fn polymorphize<'tcx>( fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { debug!("fold_ty: ty={:?}", ty); - match ty.kind { + match *ty.kind() { ty::Closure(def_id, substs) => { let polymorphized_substs = polymorphize( self.tcx, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 8eb2793cc34..f0b7f2a653f 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -29,6 +29,7 @@ use crate::ty::util::Discr; use rustc_ast as ast; use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; +use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::tagged_ptr::CopyTaggedPtr; use rustc_hir as hir; @@ -42,10 +43,9 @@ use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::{sym, Span}; use rustc_target::abi::Align; -use std::cmp::Ordering; -use std::hash::{Hash, Hasher}; +use std::hash::Hash; use std::ops::ControlFlow; -use std::{fmt, ptr, str}; +use std::{fmt, str}; pub use crate::ty::diagnostics::*; pub use rustc_type_ir::InferTy::*; @@ -59,7 +59,9 @@ pub use self::closure::{ RootVariableMinCaptureList, UpvarCapture, UpvarCaptureMap, UpvarId, UpvarListMap, UpvarPath, CAPTURE_STRUCT_LOCAL, }; -pub use self::consts::{Const, ConstInt, ConstKind, InferConst, ScalarInt, Unevaluated, ValTree}; +pub use self::consts::{ + Const, ConstInt, ConstKind, ConstS, InferConst, ScalarInt, Unevaluated, ValTree, +}; pub use self::context::{ tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, CtxtInterners, DelaySpanBugEmitted, FreeRegionInfo, GeneratorInteriorTypeCause, GlobalCtxt, @@ -380,21 +382,25 @@ pub struct CReaderCacheKey { /// Represents a type. /// -/// IMPORTANT: Every `TyS` is *required* to have unique contents. The type's -/// correctness relies on this, *but it does not enforce it*. Therefore, any -/// code that creates a `TyS` must ensure uniqueness itself. In practice this -/// is achieved by interning. +/// IMPORTANT: +/// - This is a very "dumb" struct (with no derives and no `impls`). +/// - Values of this type are always interned and thus unique, and are stored +/// as an `Interned<TyS>`. +/// - `Ty` (which contains a reference to a `Interned<TyS>`) or `Interned<TyS>` +/// should be used everywhere instead of `TyS`. In particular, `Ty` has most +/// of the relevant methods. +#[derive(PartialEq, Eq, PartialOrd, Ord)] #[allow(rustc::usage_of_ty_tykind)] -pub struct TyS<'tcx> { +crate struct TyS<'tcx> { /// This field shouldn't be used directly and may be removed in the future. - /// Use `TyS::kind()` instead. + /// Use `Ty::kind()` instead. kind: TyKind<'tcx>, /// This field provides fast access to information that is also contained /// in `kind`. /// /// This field shouldn't be used directly and may be removed in the future. - /// Use `TyS::flags()` instead. + /// Use `Ty::flags()` instead. flags: TypeFlags, /// This field provides fast access to information that is also contained @@ -420,55 +426,27 @@ pub struct TyS<'tcx> { outer_exclusive_binder: ty::DebruijnIndex, } -impl<'tcx> TyS<'tcx> { - /// A constructor used only for internal testing. - #[allow(rustc::usage_of_ty_tykind)] - pub fn make_for_test( - kind: TyKind<'tcx>, - flags: TypeFlags, - outer_exclusive_binder: ty::DebruijnIndex, - ) -> TyS<'tcx> { - TyS { kind, flags, outer_exclusive_binder } - } -} - // `TyS` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] static_assert_size!(TyS<'_>, 40); -impl<'tcx> Ord for TyS<'tcx> { - fn cmp(&self, other: &TyS<'tcx>) -> Ordering { - self.kind().cmp(other.kind()) - } -} - -impl<'tcx> PartialOrd for TyS<'tcx> { - fn partial_cmp(&self, other: &TyS<'tcx>) -> Option<Ordering> { - Some(self.kind().cmp(other.kind())) - } -} - -impl<'tcx> PartialEq for TyS<'tcx> { - #[inline] - fn eq(&self, other: &TyS<'tcx>) -> bool { - // Pointer equality implies equality (due to the unique contents - // assumption). - ptr::eq(self, other) - } -} -impl<'tcx> Eq for TyS<'tcx> {} - -impl<'tcx> Hash for TyS<'tcx> { - fn hash<H: Hasher>(&self, s: &mut H) { - // Pointer hashing is sufficient (due to the unique contents - // assumption). - (self as *const TyS<'_>).hash(s) - } -} +/// Use this rather than `TyS`, whenever possible. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[rustc_diagnostic_item = "Ty"] +#[cfg_attr(not(bootstrap), rustc_pass_by_value)] +pub struct Ty<'tcx>(Interned<'tcx, TyS<'tcx>>); + +// Statics only used for internal testing. +pub static BOOL_TY: Ty<'static> = Ty(Interned::new_unchecked(&BOOL_TYS)); +static BOOL_TYS: TyS<'static> = TyS { + kind: ty::Bool, + flags: TypeFlags::empty(), + outer_exclusive_binder: DebruijnIndex::from_usize(0), +}; -impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TyS<'tcx> { +impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Ty<'tcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let ty::TyS { + let TyS { ref kind, // The other fields just provide fast access to information that is @@ -476,16 +454,12 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TyS<'tcx> { flags: _, outer_exclusive_binder: _, - } = *self; + } = self.0.0; kind.hash_stable(hcx, hasher); } } -#[rustc_diagnostic_item = "Ty"] -#[cfg_attr(not(bootstrap), rustc_pass_by_value)] -pub type Ty<'tcx> = &'tcx TyS<'tcx>; - impl ty::EarlyBoundRegion { /// Does this early bound region have a name? Early bound regions normally /// always have names except when using anonymous lifetimes (`'_`). @@ -494,51 +468,50 @@ impl ty::EarlyBoundRegion { } } +/// Represents a predicate. +/// +/// See comments on `TyS`, which apply here too (albeit for +/// `PredicateS`/`Predicate` rather than `TyS`/`Ty`). #[derive(Debug)] -crate struct PredicateInner<'tcx> { +crate struct PredicateS<'tcx> { kind: Binder<'tcx, PredicateKind<'tcx>>, flags: TypeFlags, /// See the comment for the corresponding field of [TyS]. outer_exclusive_binder: ty::DebruijnIndex, } +// This type is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(PredicateInner<'_>, 56); - -#[derive(Clone, Copy, Lift)] -pub struct Predicate<'tcx> { - inner: &'tcx PredicateInner<'tcx>, -} +static_assert_size!(PredicateS<'_>, 56); -impl<'tcx> PartialEq for Predicate<'tcx> { - fn eq(&self, other: &Self) -> bool { - // `self.kind` is always interned. - ptr::eq(self.inner, other.inner) - } -} - -impl Hash for Predicate<'_> { - fn hash<H: Hasher>(&self, s: &mut H) { - (self.inner as *const PredicateInner<'_>).hash(s) - } -} - -impl<'tcx> Eq for Predicate<'tcx> {} +/// Use this rather than `PredicateS`, whenever possible. +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(not(bootstrap), rustc_pass_by_value)] +pub struct Predicate<'tcx>(Interned<'tcx, PredicateS<'tcx>>); impl<'tcx> Predicate<'tcx> { /// Gets the inner `Binder<'tcx, PredicateKind<'tcx>>`. #[inline] pub fn kind(self) -> Binder<'tcx, PredicateKind<'tcx>> { - self.inner.kind + self.0.kind + } + + #[inline(always)] + pub fn flags(self) -> TypeFlags { + self.0.flags + } + + #[inline(always)] + pub fn outer_exclusive_binder(self) -> DebruijnIndex { + self.0.outer_exclusive_binder } /// Flips the polarity of a Predicate. /// /// Given `T: Trait` predicate it returns `T: !Trait` and given `T: !Trait` returns `T: Trait`. - pub fn flip_polarity(&self, tcx: TyCtxt<'tcx>) -> Option<Predicate<'tcx>> { + pub fn flip_polarity(self, tcx: TyCtxt<'tcx>) -> Option<Predicate<'tcx>> { let kind = self - .inner - .kind + .kind() .map_bound(|kind| match kind { PredicateKind::Trait(TraitPredicate { trait_ref, constness, polarity }) => { Some(PredicateKind::Trait(TraitPredicate { @@ -558,14 +531,14 @@ impl<'tcx> Predicate<'tcx> { impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Predicate<'tcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let PredicateInner { + let PredicateS { ref kind, // The other fields just provide fast access to information that is // also contained in `kind`, so no need to hash them. flags: _, outer_exclusive_binder: _, - } = self.inner; + } = self.0.0; kind.hash_stable(hcx, hasher); } @@ -621,7 +594,7 @@ pub enum PredicateKind<'tcx> { ConstEvaluatable(ty::Unevaluated<'tcx, ()>), /// Constants must be equal. The first component is the const that is expected. - ConstEquate(&'tcx Const<'tcx>, &'tcx Const<'tcx>), + ConstEquate(Const<'tcx>, Const<'tcx>), /// Represents a type found in the environment that we can use for implied bounds. /// @@ -847,7 +820,7 @@ pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>; #[derive(HashStable, TypeFoldable)] pub enum Term<'tcx> { Ty(Ty<'tcx>), - Const(&'tcx Const<'tcx>), + Const(Const<'tcx>), } impl<'tcx> From<Ty<'tcx>> for Term<'tcx> { @@ -856,18 +829,18 @@ impl<'tcx> From<Ty<'tcx>> for Term<'tcx> { } } -impl<'tcx> From<&'tcx Const<'tcx>> for Term<'tcx> { - fn from(c: &'tcx Const<'tcx>) -> Self { +impl<'tcx> From<Const<'tcx>> for Term<'tcx> { + fn from(c: Const<'tcx>) -> Self { Term::Const(c) } } impl<'tcx> Term<'tcx> { pub fn ty(&self) -> Option<Ty<'tcx>> { - if let Term::Ty(ty) = self { Some(ty) } else { None } + if let Term::Ty(ty) = self { Some(*ty) } else { None } } - pub fn ct(&self) -> Option<&'tcx Const<'tcx>> { - if let Term::Const(c) = self { Some(c) } else { None } + pub fn ct(&self) -> Option<Const<'tcx>> { + if let Term::Const(c) = self { Some(*c) } else { None } } } diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index b3b2bb4459f..808be446b2a 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -192,7 +192,7 @@ impl<'tcx> TypeFolder<'tcx> for NormalizeAfterErasingRegionsFolder<'tcx> { self.normalize_generic_arg_after_erasing_regions(ty.into()).expect_ty() } - fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { + fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> { self.normalize_generic_arg_after_erasing_regions(c.into()).expect_const() } @@ -244,13 +244,10 @@ impl<'tcx> FallibleTypeFolder<'tcx> for TryNormalizeAfterErasingRegionsFolder<'t } } - fn try_fold_const( - &mut self, - c: &'tcx ty::Const<'tcx>, - ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> { + fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> { match self.try_normalize_generic_arg_after_erasing_regions(c.into()) { Ok(t) => Ok(t.expect_const()), - Err(_) => Err(NormalizationError::Const(*c)), + Err(_) => Err(NormalizationError::Const(c)), } } diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 7b5905fddc9..94cea505c32 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -66,7 +66,7 @@ pub trait Printer<'tcx>: Sized { predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>, ) -> Result<Self::DynExistential, Self::Error>; - fn print_const(self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error>; + fn print_const(self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error>; fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error>; @@ -188,11 +188,6 @@ pub trait Printer<'tcx>: Sized { own_params.start = 1; } - // If we're in verbose mode, then print default-equal args too - if self.tcx().sess.verbose() { - return &substs[own_params]; - } - // Don't print args that are the defaults of their respective parameters. own_params.end -= generics .params @@ -326,19 +321,11 @@ pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> { characteristic_def_id_of_type_cached(ty, &mut SsoHashSet::new()) } -impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::RegionKind { - type Output = P::Region; - type Error = P::Error; - fn print(&self, cx: P) -> Result<Self::Output, Self::Error> { - cx.print_region(self) - } -} - impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Region<'_> { type Output = P::Region; type Error = P::Error; fn print(&self, cx: P) -> Result<Self::Output, Self::Error> { - cx.print_region(self) + cx.print_region(*self) } } @@ -346,7 +333,7 @@ impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for Ty<'tcx> { type Output = P::Type; type Error = P::Error; fn print(&self, cx: P) -> Result<Self::Output, Self::Error> { - cx.print_type(self) + cx.print_type(*self) } } @@ -360,10 +347,10 @@ impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> } } -impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for &'tcx ty::Const<'tcx> { +impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Const<'tcx> { type Output = P::Const; type Error = P::Error; fn print(&self, cx: P) -> Result<Self::Output, Self::Error> { - cx.print_const(self) + cx.print_const(*self) } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index ddcc8680d83..ae838a46157 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -3,6 +3,7 @@ use crate::ty::subst::{GenericArg, GenericArgKind, Subst}; use crate::ty::{self, ConstInt, DefIdTree, ParamConst, ScalarInt, Term, Ty, TyCtxt, TypeFoldable}; use rustc_apfloat::ieee::{Double, Single}; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::intern::Interned; use rustc_data_structures::sso::SsoHashSet; use rustc_hir as hir; use rustc_hir::def::{self, CtorKind, DefKind, Namespace}; @@ -130,11 +131,13 @@ pub fn with_no_visible_paths<F: FnOnce() -> R, R>(f: F) -> R { /// /// Regions not selected by the region highlight mode are presently /// unaffected. -#[derive(Copy, Clone, Default)] -pub struct RegionHighlightMode { +#[derive(Copy, Clone)] +pub struct RegionHighlightMode<'tcx> { + tcx: TyCtxt<'tcx>, + /// If enabled, when we see the selected region, use "`'N`" /// instead of the ordinary behavior. - highlight_regions: [Option<(ty::RegionKind, usize)>; 3], + highlight_regions: [Option<(ty::Region<'tcx>, usize)>; 3], /// If enabled, when printing a "free region" that originated from /// the given `ty::BoundRegionKind`, print it as "`'1`". Free regions that would ordinarily @@ -146,12 +149,20 @@ pub struct RegionHighlightMode { highlight_bound_region: Option<(ty::BoundRegionKind, usize)>, } -impl RegionHighlightMode { +impl<'tcx> RegionHighlightMode<'tcx> { + pub fn new(tcx: TyCtxt<'tcx>) -> Self { + Self { + tcx, + highlight_regions: Default::default(), + highlight_bound_region: Default::default(), + } + } + /// If `region` and `number` are both `Some`, invokes /// `highlighting_region`. pub fn maybe_highlighting_region( &mut self, - region: Option<ty::Region<'_>>, + region: Option<ty::Region<'tcx>>, number: Option<usize>, ) { if let Some(k) = region { @@ -162,24 +173,24 @@ impl RegionHighlightMode { } /// Highlights the region inference variable `vid` as `'N`. - pub fn highlighting_region(&mut self, region: ty::Region<'_>, number: usize) { + pub fn highlighting_region(&mut self, region: ty::Region<'tcx>, number: usize) { let num_slots = self.highlight_regions.len(); let first_avail_slot = self.highlight_regions.iter_mut().find(|s| s.is_none()).unwrap_or_else(|| { bug!("can only highlight {} placeholders at a time", num_slots,) }); - *first_avail_slot = Some((*region, number)); + *first_avail_slot = Some((region, number)); } /// Convenience wrapper for `highlighting_region`. pub fn highlighting_region_vid(&mut self, vid: ty::RegionVid, number: usize) { - self.highlighting_region(&ty::ReVar(vid), number) + self.highlighting_region(self.tcx.mk_region(ty::ReVar(vid)), number) } /// Returns `Some(n)` with the number to use for the given region, if any. fn region_highlighted(&self, region: ty::Region<'_>) -> Option<usize> { self.highlight_regions.iter().find_map(|h| match h { - Some((r, n)) if r == region => Some(*n), + Some((r, n)) if *r == region => Some(*n), _ => None, }) } @@ -743,14 +754,14 @@ pub trait PrettyPrinter<'tcx>: p!("[", print(ty), "; "); if self.tcx().sess.verbose() { p!(write("{:?}", sz)); - } else if let ty::ConstKind::Unevaluated(..) = sz.val { + } else if let ty::ConstKind::Unevaluated(..) = sz.val() { // Do not try to evaluate unevaluated constants. If we are const evaluating an // array length anon const, rustc will (with debug assertions) print the // constant's path. Which will end up here again. p!("_"); - } else if let Some(n) = sz.val.try_to_bits(self.tcx().data_layout.pointer_size) { + } else if let Some(n) = sz.val().try_to_bits(self.tcx().data_layout.pointer_size) { p!(write("{}", n)); - } else if let ty::ConstKind::Param(param) = sz.val { + } else if let ty::ConstKind::Param(param) = sz.val() { p!(write("{}", param)); } else { p!("_"); @@ -1053,7 +1064,7 @@ pub trait PrettyPrinter<'tcx>: // Don't print `'_` if there's no unerased regions. let print_regions = args.iter().any(|arg| match arg.unpack() { - GenericArgKind::Lifetime(r) => *r != ty::ReErased, + GenericArgKind::Lifetime(r) => !r.is_erased(), _ => false, }); let mut args = args.iter().cloned().filter(|arg| match arg.unpack() { @@ -1137,13 +1148,13 @@ pub trait PrettyPrinter<'tcx>: fn pretty_print_const( mut self, - ct: &'tcx ty::Const<'tcx>, + ct: ty::Const<'tcx>, print_ty: bool, ) -> Result<Self::Const, Self::Error> { define_scoped_cx!(self); if self.tcx().sess.verbose() { - p!(write("Const({:?}: {:?})", ct.val, ct.ty)); + p!(write("Const({:?}: {:?})", ct.val(), ct.ty())); return Ok(self); } @@ -1155,7 +1166,7 @@ pub trait PrettyPrinter<'tcx>: write!(this, "_")?; Ok(this) }, - |this| this.print_type(ct.ty), + |this| this.print_type(ct.ty()), ": ", )?; } else { @@ -1164,7 +1175,7 @@ pub trait PrettyPrinter<'tcx>: }}; } - match ct.val { + match ct.val() { ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, @@ -1195,7 +1206,7 @@ pub trait PrettyPrinter<'tcx>: ty::ConstKind::Infer(..) => 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); + return self.pretty_print_const_value(value, ct.ty(), print_ty); } ty::ConstKind::Bound(debruijn, bound_var) => { @@ -1232,16 +1243,23 @@ pub trait PrettyPrinter<'tcx>: // Byte strings (&[u8; N]) ty::Ref( _, - ty::TyS { - kind: - ty::Array( - ty::TyS { kind: ty::Uint(ty::UintTy::U8), .. }, - ty::Const { - val: ty::ConstKind::Value(ConstValue::Scalar(int)), .. - }, - ), - .. - }, + Ty(Interned( + ty::TyS { + kind: + ty::Array( + Ty(Interned(ty::TyS { kind: ty::Uint(ty::UintTy::U8), .. }, _)), + ty::Const(Interned( + ty::ConstS { + val: ty::ConstKind::Value(ConstValue::Scalar(int)), + .. + }, + _, + )), + ), + .. + }, + _, + )), _, ) => match self.tcx().get_global_alloc(alloc_id) { Some(GlobalAlloc::Memory(alloc)) => { @@ -1399,7 +1417,7 @@ pub trait PrettyPrinter<'tcx>: // Byte/string slices, printed as (byte) string literals. ( ConstValue::Slice { data, start, end }, - ty::Ref(_, ty::TyS { kind: ty::Slice(t), .. }, _), + ty::Ref(_, Ty(Interned(ty::TyS { kind: ty::Slice(t), .. }, _)), _), ) if *t == u8_type => { // The `inspect` here is okay since we checked the bounds, and there are // no relocations (we have an active slice reference here). We don't use @@ -1409,7 +1427,7 @@ pub trait PrettyPrinter<'tcx>: } ( ConstValue::Slice { data, start, end }, - ty::Ref(_, ty::TyS { kind: ty::Str, .. }, _), + ty::Ref(_, Ty(Interned(ty::TyS { kind: ty::Str, .. }, _)), _), ) => { // The `inspect` here is okay since we checked the bounds, and there are no // relocations (we have an active `str` reference here). We don't use this @@ -1420,7 +1438,7 @@ pub trait PrettyPrinter<'tcx>: Ok(self) } (ConstValue::ByRef { alloc, offset }, ty::Array(t, n)) if *t == u8_type => { - let n = n.val.try_to_bits(self.tcx().data_layout.pointer_size).unwrap(); + let n = n.val().try_to_bits(self.tcx().data_layout.pointer_size).unwrap(); // cast is ok because we already checked for pointer size (32 or 64 bit) above let range = AllocRange { start: offset, size: Size::from_bytes(n) }; @@ -1441,10 +1459,18 @@ pub trait PrettyPrinter<'tcx>: // FIXME(eddyb) for `--emit=mir`/`-Z dump-mir`, we should provide the // correct `ty::ParamEnv` to allow printing *all* constant values. (_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) if !ty.has_param_types_or_consts() => { - let contents = self.tcx().destructure_const( + let Some(contents) = self.tcx().try_destructure_const( ty::ParamEnv::reveal_all() - .and(self.tcx().mk_const(ty::Const { val: ty::ConstKind::Value(ct), ty })), - ); + .and(self.tcx().mk_const(ty::ConstS { val: ty::ConstKind::Value(ct), ty })), + ) else { + // Fall back to debug pretty printing for invalid constants. + p!(write("{:?}", ct)); + if print_ty { + p!(": ", print(ty)); + } + return Ok(self); + }; + let fields = contents.fields.iter().copied(); match *ty.kind() { @@ -1531,7 +1557,7 @@ pub struct FmtPrinterData<'a, 'tcx, F> { binder_depth: usize, printed_type_count: usize, - pub region_highlight_mode: RegionHighlightMode, + pub region_highlight_mode: RegionHighlightMode<'tcx>, pub name_resolver: Option<Box<&'a dyn Fn(ty::TyVid) -> Option<String>>>, } @@ -1561,7 +1587,7 @@ impl<'a, 'tcx, F> FmtPrinter<'a, 'tcx, F> { region_index: 0, binder_depth: 0, printed_type_count: 0, - region_highlight_mode: RegionHighlightMode::default(), + region_highlight_mode: RegionHighlightMode::new(tcx), name_resolver: None, })) } @@ -1702,7 +1728,7 @@ impl<'tcx, F: fmt::Write> Printer<'tcx> for FmtPrinter<'_, 'tcx, F> { self.pretty_print_dyn_existential(predicates) } - fn print_const(self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> { + fn print_const(self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> { self.pretty_print_const(ct, true) } @@ -1797,7 +1823,7 @@ impl<'tcx, F: fmt::Write> Printer<'tcx> for FmtPrinter<'_, 'tcx, F> { // Don't print `'_` if there's no unerased regions. let print_regions = self.tcx.sess.verbose() || args.iter().any(|arg| match arg.unpack() { - GenericArgKind::Lifetime(r) => *r != ty::ReErased, + GenericArgKind::Lifetime(r) => !r.is_erased(), _ => false, }); let args = args.iter().cloned().filter(|arg| match arg.unpack() { @@ -2056,7 +2082,7 @@ impl<'a, 'tcx> ty::TypeFolder<'tcx> for RegionFolder<'a, 'tcx> { fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { let name = &mut self.name; let region = match *r { - ty::ReLateBound(_, br) => self.region_map.entry(br).or_insert_with(|| name(br)), + ty::ReLateBound(_, br) => *self.region_map.entry(br).or_insert_with(|| name(br)), ty::RePlaceholder(ty::PlaceholderRegion { name: kind, .. }) => { // If this is an anonymous placeholder, don't rename. Otherwise, in some // async fns, we get a `for<'r> Send` bound @@ -2065,7 +2091,7 @@ impl<'a, 'tcx> ty::TypeFolder<'tcx> for RegionFolder<'a, 'tcx> { _ => { // Index doesn't matter, since this is just for naming and these never get bound let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind }; - self.region_map.entry(br).or_insert_with(|| name(br)) + *self.region_map.entry(br).or_insert_with(|| name(br)) } } } @@ -2267,7 +2293,7 @@ impl<'tcx, F: fmt::Write> FmtPrinter<'_, 'tcx, F> { #[instrument(skip(self), level = "trace")] fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { - trace!("address: {:p}", r); + trace!("address: {:p}", r.0.0); if let ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) = *r { self.used_region_names.insert(name); } else if let ty::RePlaceholder(ty::PlaceholderRegion { @@ -2364,7 +2390,7 @@ macro_rules! define_print_and_forward_display { } // HACK(eddyb) this is separate because `ty::RegionKind` doesn't need lifting. -impl fmt::Display for ty::RegionKind { +impl<'tcx> fmt::Display for ty::Region<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ty::tls::with(|tcx| { self.print(FmtPrinter::new(tcx, f, Namespace::TypeNS))?; @@ -2439,7 +2465,7 @@ impl<'tcx> ty::PolyTraitPredicate<'tcx> { forward_display_to_print! { Ty<'tcx>, &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>, - &'tcx ty::Const<'tcx>, + ty::Const<'tcx>, // HACK(eddyb) these are exhaustive instead of generic, // because `for<'tcx>` isn't possible yet. diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index bb040acd270..7c57d42631a 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -89,9 +89,9 @@ pub trait TypeRelation<'tcx>: Sized { fn consts( &mut self, - a: &'tcx ty::Const<'tcx>, - b: &'tcx ty::Const<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>>; + a: ty::Const<'tcx>, + b: ty::Const<'tcx>, + ) -> RelateResult<'tcx, ty::Const<'tcx>>; fn binders<T>( &mut self, @@ -149,8 +149,8 @@ pub fn relate_substs<'tcx, R: TypeRelation<'tcx>>( Some((ty_def_id, variances)) => { let variance = variances[i]; let variance_info = if variance == ty::Invariant { - let ty = - cached_ty.get_or_insert_with(|| tcx.type_of(ty_def_id).subst(tcx, a_subst)); + let ty = *cached_ty + .get_or_insert_with(|| tcx.type_of(ty_def_id).subst(tcx, a_subst)); ty::VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() } } else { ty::VarianceDiagInfo::default() @@ -545,16 +545,16 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>( /// it. pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>( relation: &mut R, - a: &'tcx ty::Const<'tcx>, - b: &'tcx ty::Const<'tcx>, -) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { + a: ty::Const<'tcx>, + b: ty::Const<'tcx>, +) -> RelateResult<'tcx, ty::Const<'tcx>> { debug!("{}.super_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b); let tcx = relation.tcx(); // FIXME(oli-obk): once const generics can have generic types, this assertion // will likely get triggered. Move to `normalize_erasing_regions` at that point. - let a_ty = tcx.erase_regions(a.ty); - let b_ty = tcx.erase_regions(b.ty); + let a_ty = tcx.erase_regions(a.ty()); + let b_ty = tcx.erase_regions(b.ty()); if a_ty != b_ty { relation.tcx().sess.delay_span_bug( DUMMY_SP, @@ -562,14 +562,14 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>( ); } - let eagerly_eval = |x: &'tcx ty::Const<'tcx>| x.eval(tcx, relation.param_env()); + let eagerly_eval = |x: ty::Const<'tcx>| x.eval(tcx, relation.param_env()); let a = eagerly_eval(a); let b = eagerly_eval(b); // Currently, the values that can be unified are primitive types, // and those that derive both `PartialEq` and `Eq`, corresponding // to structural-match types. - let is_match = match (a.val, b.val) { + let is_match = match (a.val(), b.val()) { (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => { // The caller should handle these cases! bug!("var types encountered in super_relate_consts: {:?} {:?}", a, b) @@ -602,13 +602,13 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>( au.substs, bu.substs, )?; - return Ok(tcx.mk_const(ty::Const { + return Ok(tcx.mk_const(ty::ConstS { val: ty::ConstKind::Unevaluated(ty::Unevaluated { def: au.def, substs, promoted: au.promoted, }), - ty: a.ty, + ty: a.ty(), })); } _ => false, @@ -621,8 +621,8 @@ fn check_const_value_eq<'tcx, R: TypeRelation<'tcx>>( a_val: ConstValue<'tcx>, b_val: ConstValue<'tcx>, // FIXME(oli-obk): these arguments should go away with valtrees - a: &'tcx ty::Const<'tcx>, - b: &'tcx ty::Const<'tcx>, + a: ty::Const<'tcx>, + b: ty::Const<'tcx>, // FIXME(oli-obk): this should just be `bool` with valtrees ) -> RelateResult<'tcx, bool> { let tcx = relation.tcx(); @@ -648,9 +648,9 @@ fn check_const_value_eq<'tcx, R: TypeRelation<'tcx>>( } (ConstValue::ByRef { alloc: alloc_a, .. }, ConstValue::ByRef { alloc: alloc_b, .. }) - if a.ty.is_ref() || b.ty.is_ref() => + if a.ty().is_ref() || b.ty().is_ref() => { - if a.ty.is_ref() && b.ty.is_ref() { + if a.ty().is_ref() && b.ty().is_ref() { alloc_a == alloc_b } else { false @@ -663,7 +663,7 @@ fn check_const_value_eq<'tcx, R: TypeRelation<'tcx>>( // Both the variant and each field have to be equal. if a_destructured.variant == b_destructured.variant { for (a_field, b_field) in iter::zip(a_destructured.fields, b_destructured.fields) { - relation.consts(a_field, b_field)?; + relation.consts(*a_field, *b_field)?; } true @@ -756,12 +756,12 @@ impl<'tcx> Relate<'tcx> for ty::Region<'tcx> { } } -impl<'tcx> Relate<'tcx> for &'tcx ty::Const<'tcx> { +impl<'tcx> Relate<'tcx> for ty::Const<'tcx> { fn relate<R: TypeRelation<'tcx>>( relation: &mut R, - a: &'tcx ty::Const<'tcx>, - b: &'tcx ty::Const<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { + a: ty::Const<'tcx>, + b: ty::Const<'tcx>, + ) -> RelateResult<'tcx, ty::Const<'tcx>> { relation.consts(a, b) } } @@ -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 39efc006d9d..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 { @@ -1078,7 +1071,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { } fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { - visitor.visit_ty(self) + visitor.visit_ty(*self) } } @@ -1112,12 +1105,12 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { self, folder: &mut F, ) -> Result<Self, F::Error> { - let new = self.inner.kind.try_fold_with(folder)?; + let new = self.kind().try_fold_with(folder)?; Ok(folder.tcx().reuse_or_mk_predicate(self, new)) } fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { - self.inner.kind.visit_with(visitor) + self.kind().visit_with(visitor) } fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { @@ -1125,11 +1118,11 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { } fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool { - self.inner.outer_exclusive_binder > binder + self.outer_exclusive_binder() > binder } fn has_type_flags(&self, flags: ty::TypeFlags) -> bool { - self.inner.flags.intersects(flags) + self.flags().intersects(flags) } } @@ -1159,15 +1152,15 @@ impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec<I, T> } } -impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Const<'tcx> { +impl<'tcx> TypeFoldable<'tcx> for ty::Const<'tcx> { fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>( self, folder: &mut F, ) -> Result<Self, F::Error> { - let ty = self.ty.try_fold_with(folder)?; - let val = self.val.try_fold_with(folder)?; - if ty != self.ty || val != self.val { - Ok(folder.tcx().mk_const(ty::Const { ty, val })) + let ty = self.ty().try_fold_with(folder)?; + let val = self.val().try_fold_with(folder)?; + if ty != self.ty() || val != self.val() { + Ok(folder.tcx().mk_const(ty::ConstS { ty, val })) } else { Ok(self) } @@ -1178,12 +1171,12 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Const<'tcx> { } fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { - self.ty.visit_with(visitor)?; - self.val.visit_with(visitor) + self.ty().visit_with(visitor)?; + self.val().visit_with(visitor) } fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { - visitor.visit_const(self) + visitor.visit_const(*self) } } @@ -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 786cf4fb251..7c6d6ea1cb6 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -8,10 +8,13 @@ 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::{DelaySpanBugEmitted, List, ParamEnv, TyS}; +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; +use rustc_data_structures::intern::Interned; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_index::vec::Idx; @@ -21,8 +24,9 @@ use rustc_target::abi::VariantIdx; use rustc_target::spec::abi; use std::borrow::Cow; use std::cmp::Ordering; +use std::fmt; use std::marker::PhantomData; -use std::ops::Range; +use std::ops::{ControlFlow, Deref, Range}; use ty::util::IntTypeExt; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] @@ -114,7 +118,7 @@ pub enum TyKind<'tcx> { Str, /// An array with the given length. Written as `[T; N]`. - Array(Ty<'tcx>, &'tcx ty::Const<'tcx>), + Array(Ty<'tcx>, ty::Const<'tcx>), /// The pointee of an array slice. Written as `[T]`. Slice(Ty<'tcx>), @@ -196,7 +200,7 @@ pub enum TyKind<'tcx> { Never, /// A tuple type. For example, `(i32, bool)`. - /// Use `TyS::tuple_fields` to iterate over the field types. + /// Use `Ty::tuple_fields` to iterate over the field types. Tuple(SubstsRef<'tcx>), /// The projection of an associated type. For example, @@ -282,7 +286,7 @@ static_assert_size!(TyKind<'_>, 32); /// in scope on the function that defined the closure, /// - CK represents the *closure kind* (Fn vs FnMut vs FnOnce). This /// is rather hackily encoded via a scalar type. See -/// `TyS::to_opt_closure_kind` for details. +/// `Ty::to_opt_closure_kind` for details. /// - CS represents the *closure signature*, representing as a `fn()` /// type. For example, `fn(u32, u32) -> u32` would mean that the closure /// implements `CK<(u32, u32), Output = u32>`, where `CK` is the trait @@ -1391,7 +1395,24 @@ impl ParamConst { } } -pub type Region<'tcx> = &'tcx RegionKind; +/// Use this rather than `TyKind`, whenever possible. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)] +#[cfg_attr(not(bootstrap), rustc_pass_by_value)] +pub struct Region<'tcx>(pub Interned<'tcx, RegionKind>); + +impl<'tcx> Deref for Region<'tcx> { + type Target = RegionKind; + + fn deref(&self) -> &RegionKind { + &self.0.0 + } +} + +impl<'tcx> fmt::Debug for Region<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self.kind()) + } +} /// Representation of regions. Note that the NLL checker uses a distinct /// representation of regions. For this reason, it internally replaces all the @@ -1399,6 +1420,9 @@ pub type Region<'tcx> = &'tcx RegionKind; /// to index into internal NLL data structures. See `rustc_const_eval::borrow_check` /// module for more information. /// +/// Note: operations are on the wrapper `Region` type, which is interned, +/// rather than this type. +/// /// ## The Region lattice within a given function /// /// In general, the region lattice looks like @@ -1655,40 +1679,59 @@ impl<'tcx> PolyExistentialProjection<'tcx> { } /// Region utilities -impl RegionKind { +impl<'tcx> Region<'tcx> { + pub fn kind(self) -> RegionKind { + *self.0.0 + } + /// Is this region named by the user? - pub fn has_name(&self) -> bool { + pub fn has_name(self) -> bool { match *self { - RegionKind::ReEarlyBound(ebr) => ebr.has_name(), - RegionKind::ReLateBound(_, br) => br.kind.is_named(), - RegionKind::ReFree(fr) => fr.bound_region.is_named(), - RegionKind::ReStatic => true, - RegionKind::ReVar(..) => false, - RegionKind::RePlaceholder(placeholder) => placeholder.name.is_named(), - RegionKind::ReEmpty(_) => false, - RegionKind::ReErased => false, + ty::ReEarlyBound(ebr) => ebr.has_name(), + ty::ReLateBound(_, br) => br.kind.is_named(), + ty::ReFree(fr) => fr.bound_region.is_named(), + ty::ReStatic => true, + ty::ReVar(..) => false, + ty::RePlaceholder(placeholder) => placeholder.name.is_named(), + ty::ReEmpty(_) => false, + ty::ReErased => false, } } #[inline] - pub fn is_late_bound(&self) -> bool { + pub fn is_static(self) -> bool { + matches!(*self, ty::ReStatic) + } + + #[inline] + pub fn is_erased(self) -> bool { + matches!(*self, ty::ReErased) + } + + #[inline] + pub fn is_late_bound(self) -> bool { matches!(*self, ty::ReLateBound(..)) } #[inline] - pub fn is_placeholder(&self) -> bool { + pub fn is_placeholder(self) -> bool { matches!(*self, ty::RePlaceholder(..)) } #[inline] - pub fn bound_at_or_above_binder(&self, index: ty::DebruijnIndex) -> bool { + pub fn is_empty(self) -> bool { + matches!(*self, ty::ReEmpty(..)) + } + + #[inline] + pub fn bound_at_or_above_binder(self, index: ty::DebruijnIndex) -> bool { match *self { ty::ReLateBound(debruijn, _) => debruijn >= index, _ => false, } } - pub fn type_flags(&self) -> TypeFlags { + pub fn type_flags(self) -> TypeFlags { let mut flags = TypeFlags::empty(); match *self { @@ -1746,8 +1789,8 @@ impl RegionKind { /// of the impl, and for all the other highlighted regions, it /// would return the `DefId` of the function. In other cases (not shown), this /// function might return the `DefId` of a closure. - pub fn free_region_binding_scope(&self, tcx: TyCtxt<'_>) -> DefId { - match self { + pub fn free_region_binding_scope(self, tcx: TyCtxt<'_>) -> DefId { + match *self { ty::ReEarlyBound(br) => tcx.parent(br.def_id).unwrap(), ty::ReFree(fr) => fr.scope, _ => bug!("free_region_binding_scope invoked on inappropriate region: {:?}", self), @@ -1756,19 +1799,19 @@ impl RegionKind { } /// Type utilities -impl<'tcx> TyS<'tcx> { +impl<'tcx> Ty<'tcx> { #[inline(always)] - pub fn kind(&self) -> &TyKind<'tcx> { - &self.kind + pub fn kind(self) -> &'tcx TyKind<'tcx> { + &self.0.0.kind } #[inline(always)] - pub fn flags(&self) -> TypeFlags { - self.flags + pub fn flags(self) -> TypeFlags { + self.0.0.flags } #[inline] - pub fn is_unit(&self) -> bool { + pub fn is_unit(self) -> bool { match self.kind() { Tuple(ref tys) => tys.is_empty(), _ => false, @@ -1776,32 +1819,32 @@ impl<'tcx> TyS<'tcx> { } #[inline] - pub fn is_never(&self) -> bool { + pub fn is_never(self) -> bool { matches!(self.kind(), Never) } #[inline] - pub fn is_primitive(&self) -> bool { + pub fn is_primitive(self) -> bool { self.kind().is_primitive() } #[inline] - pub fn is_adt(&self) -> bool { + pub fn is_adt(self) -> bool { matches!(self.kind(), Adt(..)) } #[inline] - pub fn is_ref(&self) -> bool { + pub fn is_ref(self) -> bool { matches!(self.kind(), Ref(..)) } #[inline] - pub fn is_ty_var(&self) -> bool { + pub fn is_ty_var(self) -> bool { matches!(self.kind(), Infer(TyVar(_))) } #[inline] - pub fn ty_vid(&self) -> Option<ty::TyVid> { + pub fn ty_vid(self) -> Option<ty::TyVid> { match self.kind() { &Infer(TyVar(vid)) => Some(vid), _ => None, @@ -1809,28 +1852,28 @@ impl<'tcx> TyS<'tcx> { } #[inline] - pub fn is_ty_infer(&self) -> bool { + pub fn is_ty_infer(self) -> bool { matches!(self.kind(), Infer(_)) } #[inline] - pub fn is_phantom_data(&self) -> bool { + pub fn is_phantom_data(self) -> bool { if let Adt(def, _) = self.kind() { def.is_phantom_data() } else { false } } #[inline] - pub fn is_bool(&self) -> bool { + pub fn is_bool(self) -> bool { *self.kind() == Bool } /// Returns `true` if this type is a `str`. #[inline] - pub fn is_str(&self) -> bool { + pub fn is_str(self) -> bool { *self.kind() == Str } #[inline] - pub fn is_param(&self, index: u32) -> bool { + pub fn is_param(self, index: u32) -> bool { match self.kind() { ty::Param(ref data) => data.index == index, _ => false, @@ -1838,7 +1881,7 @@ impl<'tcx> TyS<'tcx> { } #[inline] - pub fn is_slice(&self) -> bool { + pub fn is_slice(self) -> bool { match self.kind() { RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => matches!(ty.kind(), Slice(_) | Str), _ => false, @@ -1846,27 +1889,27 @@ impl<'tcx> TyS<'tcx> { } #[inline] - pub fn is_array(&self) -> bool { + pub fn is_array(self) -> bool { matches!(self.kind(), Array(..)) } #[inline] - pub fn is_simd(&self) -> bool { + pub fn is_simd(self) -> bool { match self.kind() { Adt(def, _) => def.repr.simd(), _ => false, } } - pub fn sequence_element_type(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + pub fn sequence_element_type(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match self.kind() { - Array(ty, _) | Slice(ty) => ty, + Array(ty, _) | Slice(ty) => *ty, Str => tcx.types.u8, _ => bug!("`sequence_element_type` called on non-sequence value: {}", self), } } - pub fn simd_size_and_type(&self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) { + pub fn simd_size_and_type(self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) { match self.kind() { Adt(def, substs) => { assert!(def.repr.simd(), "`simd_size_and_type` called on non-SIMD type"); @@ -1881,7 +1924,7 @@ impl<'tcx> TyS<'tcx> { // The way we evaluate the `N` in `[T; N]` here only works since we use // `simd_size_and_type` post-monomorphization. It will probably start to ICE // if we use it in generic code. See the `simd-array-trait` ui test. - (f0_len.eval_usize(tcx, ParamEnv::empty()) as u64, f0_elem_ty) + (f0_len.eval_usize(tcx, ParamEnv::empty()) as u64, *f0_elem_ty) } // Otherwise, the fields of this Adt are the SIMD components (and we assume they // all have the same type). @@ -1893,12 +1936,12 @@ impl<'tcx> TyS<'tcx> { } #[inline] - pub fn is_region_ptr(&self) -> bool { + pub fn is_region_ptr(self) -> bool { matches!(self.kind(), Ref(..)) } #[inline] - pub fn is_mutable_ptr(&self) -> bool { + pub fn is_mutable_ptr(self) -> bool { matches!( self.kind(), RawPtr(TypeAndMut { mutbl: hir::Mutability::Mut, .. }) @@ -1908,7 +1951,7 @@ impl<'tcx> TyS<'tcx> { /// Get the mutability of the reference or `None` when not a reference #[inline] - pub fn ref_mutability(&self) -> Option<hir::Mutability> { + pub fn ref_mutability(self) -> Option<hir::Mutability> { match self.kind() { Ref(_, _, mutability) => Some(*mutability), _ => None, @@ -1916,18 +1959,18 @@ impl<'tcx> TyS<'tcx> { } #[inline] - pub fn is_unsafe_ptr(&self) -> bool { + pub fn is_unsafe_ptr(self) -> bool { matches!(self.kind(), RawPtr(_)) } /// Tests if this is any kind of primitive pointer type (reference, raw pointer, fn pointer). #[inline] - pub fn is_any_ptr(&self) -> bool { + pub fn is_any_ptr(self) -> bool { self.is_region_ptr() || self.is_unsafe_ptr() || self.is_fn_ptr() } #[inline] - pub fn is_box(&self) -> bool { + pub fn is_box(self) -> bool { match self.kind() { Adt(def, _) => def.is_box(), _ => false, @@ -1935,7 +1978,7 @@ impl<'tcx> TyS<'tcx> { } /// Panics if called on any type other than `Box<T>`. - pub fn boxed_ty(&self) -> Ty<'tcx> { + pub fn boxed_ty(self) -> Ty<'tcx> { match self.kind() { Adt(def, substs) if def.is_box() => substs.type_at(0), _ => bug!("`boxed_ty` is called on non-box type {:?}", self), @@ -1946,7 +1989,7 @@ impl<'tcx> TyS<'tcx> { /// (A RawPtr is scalar because it represents a non-managed pointer, so its /// contents are abstract to rustc.) #[inline] - pub fn is_scalar(&self) -> bool { + pub fn is_scalar(self) -> bool { matches!( self.kind(), Bool | Char @@ -1962,99 +2005,117 @@ impl<'tcx> TyS<'tcx> { /// Returns `true` if this type is a floating point type. #[inline] - pub fn is_floating_point(&self) -> bool { + pub fn is_floating_point(self) -> bool { matches!(self.kind(), Float(_) | Infer(FloatVar(_))) } #[inline] - pub fn is_trait(&self) -> bool { + pub fn is_trait(self) -> bool { matches!(self.kind(), Dynamic(..)) } #[inline] - pub fn is_enum(&self) -> bool { + pub fn is_enum(self) -> bool { matches!(self.kind(), Adt(adt_def, _) if adt_def.is_enum()) } #[inline] - pub fn is_union(&self) -> bool { + pub fn is_union(self) -> bool { matches!(self.kind(), Adt(adt_def, _) if adt_def.is_union()) } #[inline] - pub fn is_closure(&self) -> bool { + pub fn is_closure(self) -> bool { matches!(self.kind(), Closure(..)) } #[inline] - pub fn is_generator(&self) -> bool { + pub fn is_generator(self) -> bool { matches!(self.kind(), Generator(..)) } #[inline] - pub fn is_integral(&self) -> bool { + pub fn is_integral(self) -> bool { matches!(self.kind(), Infer(IntVar(_)) | Int(_) | Uint(_)) } #[inline] - pub fn is_fresh_ty(&self) -> bool { + pub fn is_fresh_ty(self) -> bool { matches!(self.kind(), Infer(FreshTy(_))) } #[inline] - pub fn is_fresh(&self) -> bool { + pub fn is_fresh(self) -> bool { matches!(self.kind(), Infer(FreshTy(_) | FreshIntTy(_) | FreshFloatTy(_))) } #[inline] - pub fn is_char(&self) -> bool { + pub fn is_char(self) -> bool { matches!(self.kind(), Char) } #[inline] - pub fn is_numeric(&self) -> bool { + pub fn is_numeric(self) -> bool { self.is_integral() || self.is_floating_point() } #[inline] - pub fn is_signed(&self) -> bool { + pub fn is_signed(self) -> bool { matches!(self.kind(), Int(_)) } #[inline] - pub fn is_ptr_sized_integral(&self) -> bool { + pub fn is_ptr_sized_integral(self) -> bool { matches!(self.kind(), Int(ty::IntTy::Isize) | Uint(ty::UintTy::Usize)) } #[inline] - pub fn has_concrete_skeleton(&self) -> bool { + pub fn has_concrete_skeleton(self) -> bool { !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. /// Some types -- notably unsafe ptrs -- can only be dereferenced explicitly. - pub fn builtin_deref(&self, explicit: bool) -> Option<TypeAndMut<'tcx>> { + pub fn builtin_deref(self, explicit: bool) -> Option<TypeAndMut<'tcx>> { match self.kind() { Adt(def, _) if def.is_box() => { Some(TypeAndMut { ty: self.boxed_ty(), mutbl: hir::Mutability::Not }) } - Ref(_, ty, mutbl) => Some(TypeAndMut { ty, mutbl: *mutbl }), + Ref(_, ty, mutbl) => Some(TypeAndMut { ty: *ty, mutbl: *mutbl }), RawPtr(mt) if explicit => Some(*mt), _ => None, } } /// Returns the type of `ty[i]`. - pub fn builtin_index(&self) -> Option<Ty<'tcx>> { + pub fn builtin_index(self) -> Option<Ty<'tcx>> { match self.kind() { - Array(ty, _) | Slice(ty) => Some(ty), + Array(ty, _) | Slice(ty) => Some(*ty), _ => None, } } - pub fn fn_sig(&self, tcx: TyCtxt<'tcx>) -> PolyFnSig<'tcx> { + pub fn fn_sig(self, tcx: TyCtxt<'tcx>) -> PolyFnSig<'tcx> { match self.kind() { FnDef(def_id, substs) => tcx.fn_sig(*def_id).subst(tcx, substs), FnPtr(f) => *f, @@ -2070,22 +2131,22 @@ impl<'tcx> TyS<'tcx> { } #[inline] - pub fn is_fn(&self) -> bool { + pub fn is_fn(self) -> bool { matches!(self.kind(), FnDef(..) | FnPtr(_)) } #[inline] - pub fn is_fn_ptr(&self) -> bool { + pub fn is_fn_ptr(self) -> bool { matches!(self.kind(), FnPtr(_)) } #[inline] - pub fn is_impl_trait(&self) -> bool { + pub fn is_impl_trait(self) -> bool { matches!(self.kind(), Opaque(..)) } #[inline] - pub fn ty_adt_def(&self) -> Option<&'tcx AdtDef> { + pub fn ty_adt_def(self) -> Option<&'tcx AdtDef> { match self.kind() { Adt(adt, _) => Some(adt), _ => None, @@ -2094,7 +2155,7 @@ impl<'tcx> TyS<'tcx> { /// Iterates over tuple fields. /// Panics when called on anything but a tuple. - pub fn tuple_fields(&self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> { + pub fn tuple_fields(self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> { match self.kind() { Tuple(substs) => substs.iter().map(|field| field.expect_ty()), _ => bug!("tuple_fields called on non-tuple"), @@ -2103,7 +2164,7 @@ impl<'tcx> TyS<'tcx> { /// Get the `i`-th element of a tuple. /// Panics when called on anything but a tuple. - pub fn tuple_element_ty(&self, i: usize) -> Option<Ty<'tcx>> { + pub fn tuple_element_ty(self, i: usize) -> Option<Ty<'tcx>> { match self.kind() { Tuple(substs) => substs.iter().nth(i).map(|field| field.expect_ty()), _ => bug!("tuple_fields called on non-tuple"), @@ -2114,7 +2175,7 @@ impl<'tcx> TyS<'tcx> { // // FIXME: This requires the optimized MIR in the case of generators. #[inline] - pub fn variant_range(&self, tcx: TyCtxt<'tcx>) -> Option<Range<VariantIdx>> { + pub fn variant_range(self, tcx: TyCtxt<'tcx>) -> Option<Range<VariantIdx>> { match self.kind() { TyKind::Adt(adt, _) => Some(adt.variant_range()), TyKind::Generator(def_id, substs, _) => { @@ -2130,7 +2191,7 @@ impl<'tcx> TyS<'tcx> { // FIXME: This requires the optimized MIR in the case of generators. #[inline] pub fn discriminant_for_variant( - &self, + self, tcx: TyCtxt<'tcx>, variant_index: VariantIdx, ) -> Option<Discr<'tcx>> { @@ -2151,7 +2212,7 @@ impl<'tcx> TyS<'tcx> { } /// Returns the type of the discriminant of this type. - pub fn discriminant_ty(&'tcx self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + pub fn discriminant_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match self.kind() { ty::Adt(adt, _) if adt.is_enum() => adt.repr.discr_type().to_ty(tcx), ty::Generator(_, substs, _) => substs.as_generator().discr_ty(tcx), @@ -2195,7 +2256,7 @@ impl<'tcx> TyS<'tcx> { /// Returns the type of metadata for (potentially fat) pointers to this type. pub fn ptr_metadata_ty( - &'tcx self, + self, tcx: TyCtxt<'tcx>, normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>, ) -> Ty<'tcx> { @@ -2256,7 +2317,7 @@ impl<'tcx> TyS<'tcx> { /// to represent the closure kind, because it has not yet been /// inferred. Once upvar inference (in `rustc_typeck/src/check/upvar.rs`) /// is complete, that type variable will be unified. - pub fn to_opt_closure_kind(&self) -> Option<ty::ClosureKind> { + pub fn to_opt_closure_kind(self) -> Option<ty::ClosureKind> { match self.kind() { Int(int_ty) => match int_ty { ty::IntTy::I8 => Some(ty::ClosureKind::Fn), @@ -2285,7 +2346,7 @@ impl<'tcx> TyS<'tcx> { /// bound such as `[_]: Copy`. A function with such a bound obviously never /// can be called, but that doesn't mean it shouldn't typecheck. This is why /// this method doesn't return `Option<bool>`. - pub fn is_trivially_sized(&self, tcx: TyCtxt<'tcx>) -> bool { + pub fn is_trivially_sized(self, tcx: TyCtxt<'tcx>) -> bool { match self.kind() { ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Uint(_) diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index c723df83905..7dccef5e3ef 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -6,6 +6,7 @@ use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeVisitor} use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts}; use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt}; +use rustc_data_structures::intern::Interned; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; use rustc_serialize::{self, Decodable, Encodable}; @@ -25,10 +26,13 @@ use std::ops::ControlFlow; /// To reduce memory usage, a `GenericArg` is an interned pointer, /// with the lowest 2 bits being reserved for a tag to /// indicate the type (`Ty`, `Region`, or `Const`) it points to. +/// +/// Note: the `PartialEq`, `Eq` and `Hash` derives are only valid because `Ty`, +/// `Region` and `Const` are all interned. #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct GenericArg<'tcx> { ptr: NonZeroUsize, - marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>, &'tcx ty::Const<'tcx>)>, + marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>)>, } const TAG_MASK: usize = 0b11; @@ -40,26 +44,27 @@ const CONST_TAG: usize = 0b10; pub enum GenericArgKind<'tcx> { Lifetime(ty::Region<'tcx>), Type(Ty<'tcx>), - Const(&'tcx ty::Const<'tcx>), + Const(ty::Const<'tcx>), } impl<'tcx> GenericArgKind<'tcx> { + #[inline] fn pack(self) -> GenericArg<'tcx> { let (tag, ptr) = match self { GenericArgKind::Lifetime(lt) => { // Ensure we can use the tag bits. - assert_eq!(mem::align_of_val(lt) & TAG_MASK, 0); - (REGION_TAG, lt as *const _ as usize) + assert_eq!(mem::align_of_val(lt.0.0) & TAG_MASK, 0); + (REGION_TAG, lt.0.0 as *const ty::RegionKind as usize) } GenericArgKind::Type(ty) => { // Ensure we can use the tag bits. - assert_eq!(mem::align_of_val(ty) & TAG_MASK, 0); - (TYPE_TAG, ty as *const _ as usize) + assert_eq!(mem::align_of_val(ty.0.0) & TAG_MASK, 0); + (TYPE_TAG, ty.0.0 as *const ty::TyS<'tcx> as usize) } GenericArgKind::Const(ct) => { // Ensure we can use the tag bits. - assert_eq!(mem::align_of_val(ct) & TAG_MASK, 0); - (CONST_TAG, ct as *const _ as usize) + assert_eq!(mem::align_of_val(ct.0.0) & TAG_MASK, 0); + (CONST_TAG, ct.0.0 as *const ty::ConstS<'tcx> as usize) } }; @@ -90,19 +95,22 @@ impl<'tcx> PartialOrd for GenericArg<'tcx> { } impl<'tcx> From<ty::Region<'tcx>> for GenericArg<'tcx> { + #[inline] fn from(r: ty::Region<'tcx>) -> GenericArg<'tcx> { GenericArgKind::Lifetime(r).pack() } } impl<'tcx> From<Ty<'tcx>> for GenericArg<'tcx> { + #[inline] fn from(ty: Ty<'tcx>) -> GenericArg<'tcx> { GenericArgKind::Type(ty).pack() } } -impl<'tcx> From<&'tcx ty::Const<'tcx>> for GenericArg<'tcx> { - fn from(c: &'tcx ty::Const<'tcx>) -> GenericArg<'tcx> { +impl<'tcx> From<ty::Const<'tcx>> for GenericArg<'tcx> { + #[inline] + fn from(c: ty::Const<'tcx>) -> GenericArg<'tcx> { GenericArgKind::Const(c).pack() } } @@ -111,11 +119,20 @@ impl<'tcx> GenericArg<'tcx> { #[inline] pub fn unpack(self) -> GenericArgKind<'tcx> { let ptr = self.ptr.get(); + // SAFETY: use of `Interned::new_unchecked` here is ok because these + // pointers were originally created from `Interned` types in `pack()`, + // and this is just going in the other direction. unsafe { match ptr & TAG_MASK { - REGION_TAG => GenericArgKind::Lifetime(&*((ptr & !TAG_MASK) as *const _)), - TYPE_TAG => GenericArgKind::Type(&*((ptr & !TAG_MASK) as *const _)), - CONST_TAG => GenericArgKind::Const(&*((ptr & !TAG_MASK) as *const _)), + REGION_TAG => GenericArgKind::Lifetime(ty::Region(Interned::new_unchecked( + &*((ptr & !TAG_MASK) as *const ty::RegionKind), + ))), + TYPE_TAG => GenericArgKind::Type(Ty(Interned::new_unchecked( + &*((ptr & !TAG_MASK) as *const ty::TyS<'tcx>), + ))), + CONST_TAG => GenericArgKind::Const(ty::Const(Interned::new_unchecked( + &*((ptr & !TAG_MASK) as *const ty::ConstS<'tcx>), + ))), _ => intrinsics::unreachable(), } } @@ -132,7 +149,7 @@ impl<'tcx> GenericArg<'tcx> { } /// Unpack the `GenericArg` as a const when it is known certainly to be a const. - pub fn expect_const(self) -> &'tcx ty::Const<'tcx> { + pub fn expect_const(self) -> ty::Const<'tcx> { match self.unpack() { GenericArgKind::Const(c) => c, _ => bug!("expected a const, but found another kind"), @@ -289,7 +306,7 @@ impl<'a, 'tcx> InternalSubsts<'tcx> { } #[inline] - pub fn consts(&'a self) -> impl DoubleEndedIterator<Item = &'tcx ty::Const<'tcx>> + 'a { + pub fn consts(&'a self) -> impl DoubleEndedIterator<Item = ty::Const<'tcx>> + 'a { self.iter().filter_map(|k| { if let GenericArgKind::Const(ct) = k.unpack() { Some(ct) } else { None } }) @@ -324,7 +341,7 @@ impl<'a, 'tcx> InternalSubsts<'tcx> { } #[inline] - pub fn const_at(&self, i: usize) -> &'tcx ty::Const<'tcx> { + pub fn const_at(&self, i: usize) -> ty::Const<'tcx> { if let GenericArgKind::Const(ct) = self[i].unpack() { ct } else { @@ -503,8 +520,8 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { } } - fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - if let ty::ConstKind::Param(p) = c.val { + fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> { + if let ty::ConstKind::Param(p) = c.val() { self.const_for_param(p, c) } else { c.super_fold_with(self) @@ -553,11 +570,7 @@ impl<'a, 'tcx> SubstFolder<'a, 'tcx> { self.shift_vars_through_binders(ty) } - fn const_for_param( - &self, - p: ParamConst, - source_ct: &'tcx ty::Const<'tcx>, - ) -> &'tcx ty::Const<'tcx> { + fn const_for_param(&self, p: ParamConst, source_ct: ty::Const<'tcx>) -> ty::Const<'tcx> { // Look up the const in the substitutions. It really should be in there. let opt_ct = self.substs.get(p.index as usize).map(|k| k.unpack()); let ct = match opt_ct { diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index 9e32c0162e6..8f4cc182e7f 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -1,5 +1,5 @@ use crate::traits::specialization_graph; -use crate::ty::fast_reject::{self, SimplifiedType, SimplifyParams, StripReferences}; +use crate::ty::fast_reject::{self, SimplifiedType, SimplifyParams}; use crate::ty::fold::TypeFoldable; use crate::ty::{Ident, Ty, TyCtxt}; use rustc_hir as hir; @@ -150,9 +150,7 @@ impl<'tcx> TyCtxt<'tcx> { self_ty: Ty<'tcx>, ) -> impl Iterator<Item = DefId> + 'tcx { let impls = self.trait_impls_of(def_id); - if let Some(simp) = - fast_reject::simplify_type(self, self_ty, SimplifyParams::No, StripReferences::No) - { + if let Some(simp) = fast_reject::simplify_type(self, self_ty, SimplifyParams::No) { if let Some(impls) = impls.non_blanket_impls.get(&simp) { return impls.iter().copied(); } @@ -189,9 +187,7 @@ impl<'tcx> TyCtxt<'tcx> { // whose outer level is not a parameter or projection. Especially for things like // `T: Clone` this is incredibly useful as we would otherwise look at all the impls // of `Clone` for `Option<T>`, `Vec<T>`, `ConcreteType` and so on. - if let Some(simp) = - fast_reject::simplify_type(self, self_ty, SimplifyParams::Yes, StripReferences::No) - { + if let Some(simp) = fast_reject::simplify_type(self, self_ty, SimplifyParams::Yes) { if let Some(impls) = impls.non_blanket_impls.get(&simp) { for &impl_def_id in impls { if let result @ Some(_) = f(impl_def_id) { @@ -214,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() } } @@ -251,7 +247,7 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait } if let Some(simplified_self_ty) = - fast_reject::simplify_type(tcx, impl_self_ty, SimplifyParams::No, StripReferences::No) + fast_reject::simplify_type(tcx, impl_self_ty, SimplifyParams::No) { impls.non_blanket_impls.entry(simplified_self_ty).or_default().push(impl_def_id); } else { diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 3e3473bea0e..c2a4cea2b1a 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -5,12 +5,15 @@ use crate::ty::fold::{FallibleTypeFolder, TypeFolder}; use crate::ty::layout::IntegerExt; use crate::ty::query::TyCtxtAt; use crate::ty::subst::{GenericArgKind, Subst, SubstsRef}; -use crate::ty::TyKind::*; -use crate::ty::{self, DebruijnIndex, DefIdTree, List, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{ + self, Const, DebruijnIndex, DefIdTree, List, ReEarlyBound, Region, Ty, TyCtxt, TyKind::*, + TypeFoldable, +}; use rustc_apfloat::Float as _; use rustc_ast as ast; use rustc_attr::{self as attr, SignedInt, UnsignedInt}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_errors::ErrorReported; use rustc_hir as hir; @@ -389,15 +392,17 @@ impl<'tcx> TyCtxt<'tcx> { let result = iter::zip(item_substs, impl_substs) .filter(|&(_, k)| { match k.unpack() { - GenericArgKind::Lifetime(&ty::RegionKind::ReEarlyBound(ref ebr)) => { + GenericArgKind::Lifetime(Region(Interned(ReEarlyBound(ref ebr), _))) => { !impl_generics.region_param(ebr, self).pure_wrt_drop } - GenericArgKind::Type(&ty::TyS { kind: ty::Param(ref pt), .. }) => { - !impl_generics.type_param(pt, self).pure_wrt_drop - } - GenericArgKind::Const(&ty::Const { - val: ty::ConstKind::Param(ref pc), .. - }) => !impl_generics.const_param(pc, self).pure_wrt_drop, + GenericArgKind::Type(Ty(Interned( + ty::TyS { kind: ty::Param(ref pt), .. }, + _, + ))) => !impl_generics.type_param(pt, self).pure_wrt_drop, + GenericArgKind::Const(Const(Interned( + ty::ConstS { val: ty::ConstKind::Param(ref pc), .. }, + _, + ))) => !impl_generics.const_param(pc, self).pure_wrt_drop, GenericArgKind::Lifetime(_) | GenericArgKind::Type(_) | GenericArgKind::Const(_) => { @@ -577,7 +582,7 @@ impl<'tcx> OpaqueTypeExpander<'tcx> { let substs = substs.fold_with(self); if !self.check_recursion || self.seen_opaque_tys.insert(def_id) { let expanded_ty = match self.expanded_cache.get(&(def_id, substs)) { - Some(expanded_ty) => expanded_ty, + Some(expanded_ty) => *expanded_ty, None => { let generic_ty = self.tcx.type_of(def_id); let concrete_ty = generic_ty.subst(self.tcx, substs); @@ -606,7 +611,7 @@ impl<'tcx> TypeFolder<'tcx> for OpaqueTypeExpander<'tcx> { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if let ty::Opaque(def_id, substs) = t.kind { + if let ty::Opaque(def_id, substs) = *t.kind() { self.expand_opaque_ty(def_id, substs).unwrap_or(t) } else if t.has_opaque_types() { t.super_fold_with(self) @@ -616,10 +621,10 @@ impl<'tcx> TypeFolder<'tcx> for OpaqueTypeExpander<'tcx> { } } -impl<'tcx> ty::TyS<'tcx> { +impl<'tcx> Ty<'tcx> { /// Returns the maximum value for the given numeric type (including `char`s) /// or returns `None` if the type is not numeric. - pub fn numeric_max_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ty::Const<'tcx>> { + pub fn numeric_max_val(self, tcx: TyCtxt<'tcx>) -> Option<Const<'tcx>> { let val = match self.kind() { ty::Int(_) | ty::Uint(_) => { let (size, signed) = int_size_and_signed(tcx, self); @@ -634,12 +639,12 @@ impl<'tcx> ty::TyS<'tcx> { }), _ => None, }; - val.map(|v| ty::Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self))) + val.map(|v| Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self))) } /// Returns the minimum value for the given numeric type (including `char`s) /// or returns `None` if the type is not numeric. - pub fn numeric_min_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ty::Const<'tcx>> { + pub fn numeric_min_val(self, tcx: TyCtxt<'tcx>) -> Option<Const<'tcx>> { let val = match self.kind() { ty::Int(_) | ty::Uint(_) => { let (size, signed) = int_size_and_signed(tcx, self); @@ -653,7 +658,7 @@ impl<'tcx> ty::TyS<'tcx> { }), _ => None, }; - val.map(|v| ty::Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self))) + val.map(|v| Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self))) } /// Checks whether values of this type `T` are *moved* or *copied* @@ -664,7 +669,7 @@ impl<'tcx> ty::TyS<'tcx> { /// full requirements for the `Copy` trait (cc #29149) -- this /// winds up being reported as an error during NLL borrow check. pub fn is_copy_modulo_regions( - &'tcx self, + self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> bool { @@ -677,7 +682,7 @@ impl<'tcx> ty::TyS<'tcx> { /// over-approximation in generic contexts, where one can have /// strange rules like `<T as Foo<'static>>::Bar: Sized` that /// actually carry lifetime requirements. - pub fn is_sized(&'tcx self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { + pub fn is_sized(self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { self.is_trivially_sized(tcx_at.tcx) || tcx_at.is_sized_raw(param_env.and(self)) } @@ -688,7 +693,7 @@ impl<'tcx> ty::TyS<'tcx> { /// optimization as well as the rules around static values. Note /// that the `Freeze` trait is not exposed to end users and is /// effectively an implementation detail. - pub fn is_freeze(&'tcx self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { + pub fn is_freeze(self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { self.is_trivially_freeze() || tcx_at.is_freeze_raw(param_env.and(self)) } @@ -696,7 +701,7 @@ impl<'tcx> ty::TyS<'tcx> { /// /// Returning true means the type is known to be `Freeze`. Returning /// `false` means nothing -- could be `Freeze`, might not be. - fn is_trivially_freeze(&self) -> bool { + fn is_trivially_freeze(self) -> bool { match self.kind() { ty::Int(_) | ty::Uint(_) @@ -710,7 +715,7 @@ impl<'tcx> ty::TyS<'tcx> { | ty::FnDef(..) | ty::Error(_) | ty::FnPtr(_) => true, - ty::Tuple(_) => self.tuple_fields().all(Self::is_trivially_freeze), + ty::Tuple(_) => self.tuple_fields().all(|f| Self::is_trivially_freeze(f)), ty::Slice(elem_ty) | ty::Array(elem_ty, _) => elem_ty.is_trivially_freeze(), ty::Adt(..) | ty::Bound(..) @@ -728,7 +733,7 @@ impl<'tcx> ty::TyS<'tcx> { } /// Checks whether values of this type `T` implement the `Unpin` trait. - pub fn is_unpin(&'tcx self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { + pub fn is_unpin(self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { self.is_trivially_unpin() || tcx_at.is_unpin_raw(param_env.and(self)) } @@ -736,7 +741,7 @@ impl<'tcx> ty::TyS<'tcx> { /// /// Returning true means the type is known to be `Unpin`. Returning /// `false` means nothing -- could be `Unpin`, might not be. - fn is_trivially_unpin(&self) -> bool { + fn is_trivially_unpin(self) -> bool { match self.kind() { ty::Int(_) | ty::Uint(_) @@ -750,7 +755,7 @@ impl<'tcx> ty::TyS<'tcx> { | ty::FnDef(..) | ty::Error(_) | ty::FnPtr(_) => true, - ty::Tuple(_) => self.tuple_fields().all(Self::is_trivially_unpin), + ty::Tuple(_) => self.tuple_fields().all(|f| Self::is_trivially_unpin(f)), ty::Slice(elem_ty) | ty::Array(elem_ty, _) => elem_ty.is_trivially_unpin(), ty::Adt(..) | ty::Bound(..) @@ -776,7 +781,7 @@ impl<'tcx> ty::TyS<'tcx> { /// /// Note that this method is used to check eligible types in unions. #[inline] - pub fn needs_drop(&'tcx self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { + pub fn needs_drop(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { // Avoid querying in simple cases. match needs_drop_components(self, &tcx.data_layout) { Err(AlwaysRequiresDrop) => true, @@ -809,11 +814,7 @@ impl<'tcx> ty::TyS<'tcx> { /// Note that this method is used to check for change in drop order for /// 2229 drop reorder migration analysis. #[inline] - pub fn has_significant_drop( - &'tcx self, - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> bool { + pub fn has_significant_drop(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { // Avoid querying in simple cases. match needs_drop_components(self, &tcx.data_layout) { Err(AlwaysRequiresDrop) => true, @@ -858,7 +859,7 @@ impl<'tcx> ty::TyS<'tcx> { /// want to know whether a given call to `PartialEq::eq` will proceed structurally all the way /// down, you will need to use a type visitor. #[inline] - pub fn is_structural_eq_shallow(&'tcx self, tcx: TyCtxt<'tcx>) -> bool { + pub fn is_structural_eq_shallow(self, tcx: TyCtxt<'tcx>) -> bool { match self.kind() { // Look for an impl of both `PartialStructuralEq` and `StructuralEq`. Adt(..) => tcx.has_structural_eq_impls(self), @@ -903,16 +904,16 @@ impl<'tcx> ty::TyS<'tcx> { /// - `&'a mut u8` -> `u8` /// - `&'a &'b u8` -> `u8` /// - `&'a *const &'b u8 -> *const &'b u8` - pub fn peel_refs(&'tcx self) -> Ty<'tcx> { + pub fn peel_refs(self) -> Ty<'tcx> { let mut ty = self; while let Ref(_, inner_ty, _) = ty.kind() { - ty = inner_ty; + ty = *inner_ty; } ty } - pub fn outer_exclusive_binder(&'tcx self) -> DebruijnIndex { - self.outer_exclusive_binder + pub fn outer_exclusive_binder(self) -> DebruijnIndex { + self.0.outer_exclusive_binder } } @@ -993,11 +994,11 @@ pub fn needs_drop_components<'tcx>( ty::Dynamic(..) | ty::Error(_) => Err(AlwaysRequiresDrop), - ty::Slice(ty) => needs_drop_components(ty, target_layout), + ty::Slice(ty) => needs_drop_components(*ty, target_layout), ty::Array(elem_ty, size) => { - match needs_drop_components(elem_ty, target_layout) { + match needs_drop_components(*elem_ty, target_layout) { Ok(v) if v.is_empty() => Ok(v), - res => match size.val.try_to_bits(target_layout.pointer_size) { + res => match size.val().try_to_bits(target_layout.pointer_size) { // Arrays of size zero don't need drop, even if their element // type does. Some(0) => Ok(SmallVec::new()), diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index 38aa7633385..ab70c15160c 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -1,8 +1,8 @@ //! An iterator over the type substructure. //! WARNING: this does not keep track of the region depth. -use crate::ty; use crate::ty::subst::{GenericArg, GenericArgKind}; +use crate::ty::{self, Ty}; use rustc_data_structures::sso::SsoHashSet; use smallvec::{self, SmallVec}; @@ -96,7 +96,7 @@ impl<'tcx> GenericArg<'tcx> { } } -impl<'tcx> super::TyS<'tcx> { +impl<'tcx> Ty<'tcx> { /// Iterator that walks `self` and any types reachable from /// `self`, in depth-first order. Note that just walks the types /// that appear in `self`, it does not descend into the fields of @@ -107,7 +107,7 @@ impl<'tcx> super::TyS<'tcx> { /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize } /// [isize] => { [isize], isize } /// ``` - pub fn walk(&'tcx self) -> TypeWalker<'tcx> { + pub fn walk(self) -> TypeWalker<'tcx> { TypeWalker::new(self.into()) } } @@ -189,8 +189,8 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) }, GenericArgKind::Lifetime(_) => {} GenericArgKind::Const(parent_ct) => { - stack.push(parent_ct.ty.into()); - match parent_ct.val { + stack.push(parent_ct.ty().into()); + match parent_ct.val() { ty::ConstKind::Infer(_) | ty::ConstKind::Param(_) | ty::ConstKind::Placeholder(_) diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index 5e305ebba2f..0c0b0f2bd05 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -1,6 +1,7 @@ //! See docs in build/expr/mod.rs use crate::build::Builder; +use rustc_middle::mir::interpret::{ConstValue, Scalar}; use rustc_middle::mir::*; use rustc_middle::thir::*; use rustc_middle::ty::CanonicalUserTypeAnnotation; @@ -23,11 +24,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { inferred_ty: ty, }) }); - assert_eq!(literal.ty, ty); + assert_eq!(literal.ty(), ty); Constant { span, user_ty, literal: literal.into() } } - ExprKind::StaticRef { literal, .. } => { - Constant { span, user_ty: None, literal: literal.into() } + ExprKind::StaticRef { alloc_id, ty, .. } => { + let const_val = + ConstValue::Scalar(Scalar::from_pointer(alloc_id.into(), &this.tcx)); + let literal = ConstantKind::Val(const_val, ty); + + Constant { span, user_ty: None, literal } } ExprKind::ConstBlock { value } => { Constant { span: span, user_ty: None, literal: value.into() } diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index da8fbdbf3bc..c706e6ef1d4 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -348,7 +348,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let place_builder = place_builder.clone(); this.consume_by_copy_or_move( place_builder - .field(n, ty) + .field(n, *ty) .into_place(this.tcx, this.typeck_results), ) } diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index a4e100973b6..ec8cb30965d 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -964,13 +964,13 @@ enum TestKind<'tcx> { /// /// For `bool` we always generate two edges, one for `true` and one for /// `false`. - options: FxIndexMap<&'tcx ty::Const<'tcx>, u128>, + options: FxIndexMap<ty::Const<'tcx>, u128>, }, /// Test for equality with value, possibly after an unsizing coercion to /// `ty`, Eq { - value: &'tcx ty::Const<'tcx>, + value: ty::Const<'tcx>, // Integer types are handled by `SwitchInt`, and constants with ADT // types are converted back into patterns, so this can only be `&str`, // `&[T]`, `f32` or `f64`. diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index 4ce26cc8dff..4f9a2c0ce77 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -210,7 +210,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } PatKind::Range(PatRange { lo, hi, end }) => { - let (range, bias) = match *lo.ty.kind() { + let (range, bias) = match *lo.ty().kind() { ty::Char => { (Some(('\u{0000}' as u128, '\u{10FFFF}' as u128, Size::from_bits(32))), 0) } @@ -228,7 +228,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { _ => (None, 0), }; if let Some((min, max, sz)) = range { - if let (Some(lo), Some(hi)) = (lo.val.try_to_bits(sz), hi.val.try_to_bits(sz)) { + if let (Some(lo), Some(hi)) = + (lo.val().try_to_bits(sz), hi.val().try_to_bits(sz)) + { // We want to compare ranges numerically, but the order of the bitwise // representation of signed integers does not match their numeric order. // Thus, to correct the ordering, we need to shift the range of signed diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 49cd21c2137..ce848773b10 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -59,8 +59,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }, PatKind::Range(range) => { - assert_eq!(range.lo.ty, match_pair.pattern.ty); - assert_eq!(range.hi.ty, match_pair.pattern.ty); + assert_eq!(range.lo.ty(), match_pair.pattern.ty); + assert_eq!(range.hi.ty(), match_pair.pattern.ty); Test { span: match_pair.pattern.span, kind: TestKind::Range(range) } } @@ -86,7 +86,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { test_place: &PlaceBuilder<'tcx>, candidate: &Candidate<'pat, 'tcx>, switch_ty: Ty<'tcx>, - options: &mut FxIndexMap<&'tcx ty::Const<'tcx>, u128>, + options: &mut FxIndexMap<ty::Const<'tcx>, u128>, ) -> bool { let Some(match_pair) = candidate.match_pairs.iter().find(|mp| mp.place == *test_place) else { return false; @@ -266,7 +266,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ty, ); } else if let [success, fail] = *make_target_blocks(self) { - assert_eq!(value.ty, ty); + assert_eq!(value.ty(), ty); let expect = self.literal_operand(test.span, value); let val = Operand::Copy(place); self.compare(block, success, fail, source_info, BinOp::Eq, expect, val); @@ -275,7 +275,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - TestKind::Range(PatRange { ref lo, ref hi, ref end }) => { + TestKind::Range(PatRange { lo, hi, ref end }) => { let lower_bound_success = self.cfg.start_new_block(); let target_blocks = make_target_blocks(self); @@ -369,7 +369,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block: BasicBlock, make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>, source_info: SourceInfo, - value: &'tcx ty::Const<'tcx>, + value: ty::Const<'tcx>, place: Place<'tcx>, mut ty: Ty<'tcx>, ) { @@ -390,14 +390,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { _ => None, }; let opt_ref_ty = unsize(ty); - let opt_ref_test_ty = unsize(value.ty); + let opt_ref_test_ty = unsize(value.ty()); match (opt_ref_ty, opt_ref_test_ty) { // nothing to do, neither is an array (None, None) => {} (Some((region, elem_ty, _)), _) | (None, Some((region, elem_ty, _))) => { let tcx = self.tcx; // make both a slice - ty = tcx.mk_imm_ref(region, tcx.mk_slice(elem_ty)); + ty = tcx.mk_imm_ref(*region, tcx.mk_slice(*elem_ty)); if opt_ref_ty.is_some() { let temp = self.temp(ty, source_info.span); self.cfg.push_assign( @@ -646,7 +646,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let tcx = self.tcx; - let test_ty = test.lo.ty; + let test_ty = test.lo.ty(); let lo = compare_const_vals(tcx, test.lo, pat.hi, self.param_env, test_ty)?; let hi = compare_const_vals(tcx, test.hi, pat.lo, self.param_env, test_ty)?; @@ -764,17 +764,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { span_bug!(match_pair.pattern.span, "simplifyable pattern found: {:?}", match_pair.pattern) } - fn const_range_contains( - &self, - range: PatRange<'tcx>, - value: &'tcx ty::Const<'tcx>, - ) -> Option<bool> { + fn const_range_contains(&self, range: PatRange<'tcx>, value: ty::Const<'tcx>) -> Option<bool> { use std::cmp::Ordering::*; let tcx = self.tcx; - let a = compare_const_vals(tcx, range.lo, value, self.param_env, range.lo.ty)?; - let b = compare_const_vals(tcx, value, range.hi, self.param_env, range.lo.ty)?; + let a = compare_const_vals(tcx, range.lo, value, self.param_env, range.lo.ty())?; + let b = compare_const_vals(tcx, value, range.hi, self.param_env, range.lo.ty())?; match (b, range.end) { (Less, _) | (Equal, RangeEnd::Included) if a != Greater => Some(true), @@ -785,7 +781,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn values_not_contained_in_range( &self, range: PatRange<'tcx>, - options: &FxIndexMap<&'tcx ty::Const<'tcx>, u128>, + options: &FxIndexMap<ty::Const<'tcx>, u128>, ) -> Option<bool> { for &val in options.keys() { if self.const_range_contains(range, val)? { @@ -831,7 +827,7 @@ fn trait_method<'tcx>( method_name: Symbol, self_ty: Ty<'tcx>, params: &[GenericArg<'tcx>], -) -> &'tcx ty::Const<'tcx> { +) -> ty::Const<'tcx> { let substs = tcx.mk_substs_trait(self_ty, params); // The unhygienic comparison here is acceptable because this is only diff --git a/compiler/rustc_mir_build/src/build/misc.rs b/compiler/rustc_mir_build/src/build/misc.rs index 78047daf0ad..fd591446014 100644 --- a/compiler/rustc_mir_build/src/build/misc.rs +++ b/compiler/rustc_mir_build/src/build/misc.rs @@ -25,11 +25,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// Convenience function for creating a literal operand, one /// without any user type annotation. - crate fn literal_operand( - &mut self, - span: Span, - literal: &'tcx ty::Const<'tcx>, - ) -> Operand<'tcx> { + crate fn literal_operand(&mut self, span: Span, literal: ty::Const<'tcx>) -> Operand<'tcx> { let literal = literal.into(); let constant = Box::new(Constant { span, user_ty: None, literal }); Operand::Constant(constant) diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 10807d43276..fb403615e57 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -903,7 +903,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut closure_ty = self.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty; if let ty::Ref(_, ty, _) = closure_ty.kind() { closure_env_projs.push(ProjectionElem::Deref); - closure_ty = ty; + closure_ty = *ty; } let upvar_substs = match closure_ty.kind() { ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs), diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index 9b54db0d7de..ec2ff3c37ab 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -10,7 +10,7 @@ use rustc_target::abi::Size; crate fn lit_to_const<'tcx>( tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx>, -) -> Result<&'tcx ty::Const<'tcx>, LitToConstError> { +) -> Result<ty::Const<'tcx>, LitToConstError> { let LitToConstInput { lit, ty, neg } = lit_input; let trunc = |n| { diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 374e6ef87a7..829dec74803 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -8,7 +8,6 @@ use rustc_middle::hir::place::Place as HirPlace; use rustc_middle::hir::place::PlaceBase as HirPlaceBase; use rustc_middle::hir::place::ProjectionKind as HirProjectionKind; use rustc_middle::middle::region; -use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::{BinOp, BorrowKind, Field, UnOp}; use rustc_middle::thir::*; use rustc_middle::ty::adjustment::{ @@ -583,7 +582,7 @@ impl<'tcx> Cx<'tcx> { _ => span_bug!(expr.span, "unexpected repeat expr ty: {:?}", ty), }; - ExprKind::Repeat { value: self.mirror_expr(v), count } + ExprKind::Repeat { value: self.mirror_expr(v), count: *count } } hir::ExprKind::Ret(ref v) => { ExprKind::Return { value: v.as_ref().map(|v| self.mirror_expr(v)) } @@ -708,7 +707,7 @@ impl<'tcx> Cx<'tcx> { // in case we are offsetting from a computed discriminant // and not the beginning of discriminants (which is always `0`) let substs = InternalSubsts::identity_for_item(self.tcx(), did); - let lhs = ty::Const { + let lhs = ty::ConstS { val: ty::ConstKind::Unevaluated(ty::Unevaluated::new( ty::WithOptConstParam::unknown(did), substs, @@ -890,7 +889,7 @@ impl<'tcx> Cx<'tcx> { let name = self.tcx.hir().name(hir_id); let val = ty::ConstKind::Param(ty::ParamConst::new(index, name)); ExprKind::Literal { - literal: self.tcx.mk_const(ty::Const { + literal: self.tcx.mk_const(ty::ConstS { val, ty: self.typeck_results().node_type(expr.hir_id), }), @@ -903,7 +902,7 @@ impl<'tcx> Cx<'tcx> { let user_ty = self.user_substs_applied_to_res(expr.hir_id, res); debug!("convert_path_expr: (const) user_ty={:?}", user_ty); ExprKind::Literal { - literal: self.tcx.mk_const(ty::Const { + literal: self.tcx.mk_const(ty::ConstS { val: ty::ConstKind::Unevaluated(ty::Unevaluated::new( ty::WithOptConstParam::unknown(def_id), substs, @@ -943,15 +942,8 @@ impl<'tcx> Cx<'tcx> { let kind = if self.tcx.is_thread_local_static(id) { ExprKind::ThreadLocalRef(id) } else { - let ptr = self.tcx.create_static_alloc(id); - ExprKind::StaticRef { - literal: ty::Const::from_scalar( - self.tcx, - Scalar::from_pointer(ptr.into(), &self.tcx), - ty, - ), - def_id: id, - } + let alloc_id = self.tcx.create_static_alloc(id); + ExprKind::StaticRef { alloc_id, ty, def_id: id } }; ExprKind::Deref { arg: self.thir.exprs.push(Expr { ty, temp_lifetime, span: expr.span, kind }), diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index 38a4676bd15..a65a3ed31f6 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -79,7 +79,7 @@ impl<'tcx> Cx<'tcx> { ty: Ty<'tcx>, sp: Span, neg: bool, - ) -> &'tcx ty::Const<'tcx> { + ) -> ty::Const<'tcx> { trace!("const_eval_literal: {:#?}, {:?}, {:?}, {:?}", lit, ty, sp, neg); match self.tcx.at(sp).lit_to_const(LitToConstInput { lit, ty, neg }) { diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 34204c3852a..d357ac69302 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -556,7 +556,7 @@ fn non_exhaustive_match<'p, 'tcx>( } } if let ty::Ref(_, sub_ty, _) = scrut_ty.kind() { - if cx.tcx.is_ty_uninhabited_from(cx.module, sub_ty, cx.param_env) { + if cx.tcx.is_ty_uninhabited_from(cx.module, *sub_ty, cx.param_env) { err.note("references are always considered inhabited"); } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index d8c9a6fa3fe..7db71ed598d 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -22,7 +22,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { #[instrument(level = "debug", skip(self))] pub(super) fn const_to_pat( &self, - cv: &'tcx ty::Const<'tcx>, + cv: ty::Const<'tcx>, id: hir::HirId, span: Span, mir_structural_match_violation: bool, @@ -152,11 +152,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { ty.is_structural_eq_shallow(self.infcx.tcx) } - fn to_pat( - &mut self, - cv: &'tcx ty::Const<'tcx>, - mir_structural_match_violation: bool, - ) -> Pat<'tcx> { + fn to_pat(&mut self, cv: ty::Const<'tcx>, mir_structural_match_violation: bool) -> Pat<'tcx> { trace!(self.treat_byte_string_as_slice); // This method is just a wrapper handling a validity check; the heavy lifting is // performed by the recursive `recur` method, which is not meant to be @@ -171,10 +167,11 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // If we were able to successfully convert the const to some pat, // double-check that all types in the const implement `Structural`. - let structural = self.search_for_structural_match_violation(cv.ty); + let structural = self.search_for_structural_match_violation(cv.ty()); debug!( "search_for_structural_match_violation cv.ty: {:?} returned: {:?}", - cv.ty, structural + cv.ty(), + structural ); // This can occur because const qualification treats all associated constants as @@ -189,7 +186,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { } if let Some(msg) = structural { - if !self.type_may_have_partial_eq_impl(cv.ty) { + if !self.type_may_have_partial_eq_impl(cv.ty()) { // span_fatal avoids ICE from resolution of non-existent method (rare case). self.tcx().sess.span_fatal(self.span, &msg); } else if mir_structural_match_violation && !self.saw_const_match_lint.get() { @@ -247,7 +244,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { fn field_pats( &self, - vals: impl Iterator<Item = &'tcx ty::Const<'tcx>>, + vals: impl Iterator<Item = ty::Const<'tcx>>, ) -> Result<Vec<FieldPat<'tcx>>, FallbackToConstRef> { vals.enumerate() .map(|(idx, val)| { @@ -260,7 +257,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // Recursive helper for `to_pat`; invoke that (instead of calling this directly). fn recur( &self, - cv: &'tcx ty::Const<'tcx>, + cv: ty::Const<'tcx>, mir_structural_match_violation: bool, ) -> Result<Pat<'tcx>, FallbackToConstRef> { let id = self.id; @@ -268,7 +265,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { let tcx = self.tcx(); let param_env = self.param_env; - let kind = match cv.ty.kind() { + let kind = match cv.ty().kind() { ty::Float(_) => { if self.include_lint_checks { tcx.struct_span_lint_hir( @@ -292,14 +289,14 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { PatKind::Wild } ty::Adt(..) - if !self.type_may_have_partial_eq_impl(cv.ty) + if !self.type_may_have_partial_eq_impl(cv.ty()) // FIXME(#73448): Find a way to bring const qualification into parity with // `search_for_structural_match_violation` and then remove this condition. - && self.search_for_structural_match_violation(cv.ty).is_some() => + && self.search_for_structural_match_violation(cv.ty()).is_some() => { // Obtain the actual type that isn't annotated. If we just looked at `cv.ty` we // could get `Option<NonStructEq>`, even though `Option` is annotated with derive. - let msg = self.search_for_structural_match_violation(cv.ty).unwrap(); + let msg = self.search_for_structural_match_violation(cv.ty()).unwrap(); self.saw_const_match_error.set(true); if self.include_lint_checks { tcx.sess.span_err(self.span, &msg); @@ -317,7 +314,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // details. // Backwards compatibility hack because we can't cause hard errors on these // types, so we compare them via `PartialEq::eq` at runtime. - ty::Adt(..) if !self.type_marked_structural(cv.ty) && self.behind_reference.get() => { + ty::Adt(..) if !self.type_marked_structural(cv.ty()) && self.behind_reference.get() => { if self.include_lint_checks && !self.saw_const_match_error.get() && !self.saw_const_match_lint.get() @@ -331,7 +328,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { let msg = format!( "to use a constant of type `{}` in a pattern, \ `{}` must be annotated with `#[derive(PartialEq, Eq)]`", - cv.ty, cv.ty, + cv.ty(), + cv.ty(), ); lint.build(&msg).emit() }, @@ -342,8 +340,12 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // `PartialEq::eq` on it. return Err(fallback_to_const_ref(self)); } - ty::Adt(adt_def, _) if !self.type_marked_structural(cv.ty) => { - debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, cv.ty); + ty::Adt(adt_def, _) if !self.type_marked_structural(cv.ty()) => { + debug!( + "adt_def {:?} has !type_marked_structural for cv.ty: {:?}", + adt_def, + cv.ty() + ); let path = tcx.def_path_str(adt_def.did); let msg = format!( "to use a constant of type `{}` in a pattern, \ @@ -378,7 +380,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { .destructure_const(param_env.and(cv)) .fields .iter() - .map(|val| self.recur(val, false)) + .map(|val| self.recur(*val, false)) .collect::<Result<_, _>>()?, slice: None, suffix: Vec::new(), @@ -387,7 +389,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // These are not allowed and will error elsewhere anyway. ty::Dynamic(..) => { self.saw_const_match_error.set(true); - let msg = format!("`{}` cannot be used in patterns", cv.ty); + let msg = format!("`{}` cannot be used in patterns", cv.ty()); if self.include_lint_checks { tcx.sess.span_err(span, &msg); } else { @@ -414,13 +416,13 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { .destructure_const(param_env.and(array)) .fields .iter() - .map(|val| self.recur(val, false)) + .map(|val| self.recur(*val, false)) .collect::<Result<_, _>>()?, slice: None, suffix: vec![], }), span, - ty: pointee_ty, + ty: *pointee_ty, }, }; self.behind_reference.set(old); @@ -440,7 +442,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { .destructure_const(param_env.and(array)) .fields .iter() - .map(|val| self.recur(val, false)) + .map(|val| self.recur(*val, false)) .collect::<Result<_, _>>()?, slice: None, suffix: vec![], @@ -457,7 +459,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // this pattern to a `PartialEq::eq` comparison and `PartialEq::eq` takes a // reference. This makes the rest of the matching logic simpler as it doesn't have // to figure out how to get a reference again. - ty::Adt(adt_def, _) if !self.type_marked_structural(pointee_ty) => { + ty::Adt(adt_def, _) if !self.type_marked_structural(*pointee_ty) => { if self.behind_reference.get() { if self.include_lint_checks && !self.saw_const_match_error.get() @@ -544,7 +546,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { } _ => { self.saw_const_match_error.set(true); - let msg = format!("`{}` cannot be used in patterns", cv.ty); + let msg = format!("`{}` cannot be used in patterns", cv.ty()); if self.include_lint_checks { tcx.sess.span_err(span, &msg); } else { @@ -560,12 +562,12 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { && mir_structural_match_violation // FIXME(#73448): Find a way to bring const qualification into parity with // `search_for_structural_match_violation` and then remove this condition. - && self.search_for_structural_match_violation(cv.ty).is_some() + && self.search_for_structural_match_violation(cv.ty()).is_some() { self.saw_const_match_lint.set(true); // Obtain the actual type that isn't annotated. If we just looked at `cv.ty` we // could get `Option<NonStructEq>`, even though `Option` is annotated with derive. - let msg = self.search_for_structural_match_violation(cv.ty).unwrap().replace( + let msg = self.search_for_structural_match_violation(cv.ty()).unwrap().replace( "in a pattern,", "in a pattern, the constant's initializer must be trivial or", ); @@ -577,6 +579,6 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { ); } - Ok(Pat { span, ty: cv.ty, kind: Box::new(kind) }) + Ok(Pat { span, ty: cv.ty(), kind: Box::new(kind) }) } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 801c8778bff..e4d9bd9c237 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -136,12 +136,12 @@ impl IntRange { fn from_const<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - value: &Const<'tcx>, + value: Const<'tcx>, ) -> Option<IntRange> { - if let Some((target_size, bias)) = Self::integral_size_and_signed_bias(tcx, value.ty) { - let ty = value.ty; + let ty = value.ty(); + if let Some((target_size, bias)) = Self::integral_size_and_signed_bias(tcx, ty) { let val = (|| { - if let ty::ConstKind::Value(ConstValue::Scalar(scalar)) = value.val { + if let ty::ConstKind::Value(ConstValue::Scalar(scalar)) = value.val() { // For this specific pattern we can skip a lot of effort and go // straight to the result, after doing a bit of checking. (We // could remove this branch and just fall through, which @@ -630,9 +630,9 @@ pub(super) enum Constructor<'tcx> { /// Ranges of integer literal values (`2`, `2..=5` or `2..5`). IntRange(IntRange), /// Ranges of floating-point literal values (`2.0..=5.2`). - FloatRange(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>, RangeEnd), + FloatRange(ty::Const<'tcx>, ty::Const<'tcx>, RangeEnd), /// String literals. Strings are not quite the same as `&[u8]` so we treat them separately. - Str(&'tcx ty::Const<'tcx>), + Str(ty::Const<'tcx>), /// Array and slice patterns. Slice(Slice), /// Constants that must not be matched structurally. They are treated as black @@ -815,8 +815,14 @@ impl<'tcx> Constructor<'tcx> { FloatRange(other_from, other_to, other_end), ) => { match ( - compare_const_vals(pcx.cx.tcx, self_to, other_to, pcx.cx.param_env, pcx.ty), - compare_const_vals(pcx.cx.tcx, self_from, other_from, pcx.cx.param_env, pcx.ty), + compare_const_vals(pcx.cx.tcx, *self_to, *other_to, pcx.cx.param_env, pcx.ty), + compare_const_vals( + pcx.cx.tcx, + *self_from, + *other_from, + pcx.cx.param_env, + pcx.ty, + ), ) { (Some(to), Some(from)) => { (from == Ordering::Greater || from == Ordering::Equal) @@ -828,8 +834,13 @@ impl<'tcx> Constructor<'tcx> { } (Str(self_val), Str(other_val)) => { // FIXME: there's probably a more direct way of comparing for equality - match compare_const_vals(pcx.cx.tcx, self_val, other_val, pcx.cx.param_env, pcx.ty) - { + match compare_const_vals( + pcx.cx.tcx, + *self_val, + *other_val, + pcx.cx.param_env, + pcx.ty, + ) { Some(comparison) => comparison == Ordering::Equal, None => false, } @@ -929,7 +940,7 @@ impl<'tcx> SplitWildcard<'tcx> { ty::Bool => smallvec![make_range(0, 1)], ty::Array(sub_ty, len) if len.try_eval_usize(cx.tcx, cx.param_env).is_some() => { let len = len.eval_usize(cx.tcx, cx.param_env) as usize; - if len != 0 && cx.is_uninhabited(sub_ty) { + if len != 0 && cx.is_uninhabited(*sub_ty) { smallvec![] } else { smallvec![Slice(Slice::new(Some(len), VarLen(0, 0)))] @@ -937,7 +948,7 @@ impl<'tcx> SplitWildcard<'tcx> { } // Treat arrays of a constant but unknown length like slices. ty::Array(sub_ty, _) | ty::Slice(sub_ty) => { - let kind = if cx.is_uninhabited(sub_ty) { FixedLen(0) } else { VarLen(0, 0) }; + let kind = if cx.is_uninhabited(*sub_ty) { FixedLen(0) } else { VarLen(0, 0) }; smallvec![Slice(Slice::new(None, kind))] } ty::Adt(def, substs) if def.is_enum() => { @@ -1368,13 +1379,13 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { } } PatKind::Constant { value } => { - if let Some(int_range) = IntRange::from_const(cx.tcx, cx.param_env, value) { + if let Some(int_range) = IntRange::from_const(cx.tcx, cx.param_env, *value) { ctor = IntRange(int_range); fields = Fields::empty(); } else { match pat.ty.kind() { ty::Float(_) => { - ctor = FloatRange(value, value, RangeEnd::Included); + ctor = FloatRange(*value, *value, RangeEnd::Included); fields = Fields::empty(); } ty::Ref(_, t, _) if t.is_str() => { @@ -1386,7 +1397,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { // fields. // Note: `t` is `str`, not `&str`. let subpattern = - DeconstructedPat::new(Str(value), Fields::empty(), t, pat.span); + DeconstructedPat::new(Str(*value), Fields::empty(), *t, pat.span); ctor = Single; fields = Fields::singleton(cx, subpattern) } @@ -1401,11 +1412,11 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { } } &PatKind::Range(PatRange { lo, hi, end }) => { - let ty = lo.ty; + let ty = lo.ty(); ctor = if let Some(int_range) = IntRange::from_range( cx.tcx, - lo.eval_bits(cx.tcx, cx.param_env, lo.ty), - hi.eval_bits(cx.tcx, cx.param_env, hi.ty), + lo.eval_bits(cx.tcx, cx.param_env, lo.ty()), + hi.eval_bits(cx.tcx, cx.param_env, hi.ty()), ty, &end, ) { diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 55cf807172e..ddf39fb824c 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -99,7 +99,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { debug!("{:?}: wrapping pattern with type {:?}", pat, ref_ty); Pat { span: pat.span, - ty: ref_ty, + ty: *ref_ty, kind: Box::new(PatKind::Deref { subpattern: pat }), } }, @@ -121,13 +121,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { fn lower_pattern_range( &mut self, ty: Ty<'tcx>, - lo: &'tcx ty::Const<'tcx>, - hi: &'tcx ty::Const<'tcx>, + lo: ty::Const<'tcx>, + hi: ty::Const<'tcx>, end: RangeEnd, span: Span, ) -> PatKind<'tcx> { - assert_eq!(lo.ty, ty); - assert_eq!(hi.ty, ty); + assert_eq!(lo.ty(), ty); + assert_eq!(hi.ty(), ty); let cmp = compare_const_vals(self.tcx, lo, hi, self.param_env, ty); match (end, cmp) { // `x..y` where `x < y`. @@ -177,16 +177,16 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { ty: Ty<'tcx>, lo: Option<&PatKind<'tcx>>, hi: Option<&PatKind<'tcx>>, - ) -> Option<(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>)> { + ) -> Option<(ty::Const<'tcx>, ty::Const<'tcx>)> { match (lo, hi) { (Some(PatKind::Constant { value: lo }), Some(PatKind::Constant { value: hi })) => { - Some((lo, hi)) + Some((*lo, *hi)) } (Some(PatKind::Constant { value: lo }), None) => { - Some((lo, ty.numeric_max_val(self.tcx)?)) + Some((*lo, ty.numeric_max_val(self.tcx)?)) } (None, Some(PatKind::Constant { value: hi })) => { - Some((ty.numeric_min_val(self.tcx)?, hi)) + Some((ty.numeric_min_val(self.tcx)?, *hi)) } _ => None, } @@ -275,7 +275,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let var_ty = ty; if let ty::BindByReference(_) = bm { if let ty::Ref(_, rty, _) = ty.kind() { - ty = rty; + ty = *rty; } else { bug!("`ref {}` has wrong type {}", ident, ty); } @@ -417,7 +417,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { | DefKind::AssocTy, _, ) - | Res::SelfTy(..) + | Res::SelfTy { .. } | Res::SelfCtor(..) => PatKind::Leaf { subpatterns }, _ => { let pattern_error = match res { @@ -493,7 +493,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let const_ = ty::Const::from_value(self.tcx, value, self.typeck_results.node_type(id)); - let pattern = self.const_to_pat(&const_, id, span, mir_structural_match_violation); + let pattern = self.const_to_pat(const_, id, span, mir_structural_match_violation); if !is_associated_const { return pattern; @@ -514,7 +514,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { user_ty_span: span, }, }), - ty: const_.ty, + ty: const_.ty(), } } else { pattern @@ -546,7 +546,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // Evaluate early like we do in `lower_path`. let value = value.eval(self.tcx, self.param_env); - match value.val { + match value.val() { ConstKind::Param(_) => { self.errors.push(PatternError::ConstParamInPattern(span)); return PatKind::Wild; @@ -744,8 +744,8 @@ impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> { crate fn compare_const_vals<'tcx>( tcx: TyCtxt<'tcx>, - a: &'tcx ty::Const<'tcx>, - b: &'tcx ty::Const<'tcx>, + a: ty::Const<'tcx>, + b: ty::Const<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>, ) -> Option<Ordering> { @@ -756,13 +756,13 @@ crate fn compare_const_vals<'tcx>( let fallback = || from_bool(a == b); // Use the fallback if any type differs - if a.ty != b.ty || a.ty != ty { + if a.ty() != b.ty() || a.ty() != ty { return fallback(); } // Early return for equal constants (so e.g. references to ZSTs can be compared, even if they // are just integer addresses). - if a.val == b.val { + if a.val() == b.val() { return from_bool(true); } @@ -797,7 +797,7 @@ crate fn compare_const_vals<'tcx>( if let ( ty::ConstKind::Value(a_val @ ConstValue::Slice { .. }), ty::ConstKind::Value(b_val @ ConstValue::Slice { .. }), - ) = (a.val, b.val) + ) = (a.val(), b.val()) { let a_bytes = get_slice_bytes(&tcx, a_val); let b_bytes = get_slice_bytes(&tcx, b_val); diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index a3294672f54..3e1013b0351 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -880,9 +880,9 @@ where ty::Dynamic(..) => self.complete_drop(self.succ, self.unwind), ty::Array(ety, size) => { let size = size.try_eval_usize(self.tcx(), self.elaborator.param_env()); - self.open_drop_for_array(ety, size) + self.open_drop_for_array(*ety, size) } - ty::Slice(ety) => self.open_drop_for_array(ety, None), + ty::Slice(ety) => self.open_drop_for_array(*ety, None), _ => bug!("open drop from non-ADT `{:?}`", ty), } diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index 0d314a109ba..5810ce6edc9 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -484,7 +484,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let err = ConstEvalErr::new(&self.ecx, error, Some(c.span)); if let Some(lint_root) = self.lint_root(source_info) { let lint_only = match c.literal { - ConstantKind::Ty(ct) => match ct.val { + ConstantKind::Ty(ct) => match ct.val() { // Promoteds must lint and not error as the user didn't ask for them ConstKind::Unevaluated(ty::Unevaluated { def: _, @@ -801,7 +801,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { ) { if let Rvalue::Use(Operand::Constant(c)) = rval { match c.literal { - ConstantKind::Ty(c) if matches!(c.val, ConstKind::Unevaluated(..)) => {} + ConstantKind::Ty(c) if matches!(c.val(), ConstKind::Unevaluated(..)) => {} _ => { trace!("skipping replace of Rvalue::Use({:?} because it is already a const", c); return; @@ -841,7 +841,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // Found a value represented as a pair. For now only do const-prop if the type // of `rvalue` is also a tuple with two scalars. // FIXME: enable the general case stated above ^. - let ty = &value.layout.ty; + let ty = value.layout.ty; // Only do it for tuples if let ty::Tuple(substs) = ty.kind() { // Only do it if tuple is also a pair with two scalars @@ -875,7 +875,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { literal: self .ecx .tcx - .mk_const(ty::Const { + .mk_const(ty::ConstS { ty, val: ty::ConstKind::Value(ConstValue::ByRef { alloc, 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/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs index 62ea2538ff0..d787443f6aa 100644 --- a/compiler/rustc_mir_transform/src/coverage/tests.rs +++ b/compiler/rustc_mir_transform/src/coverage/tests.rs @@ -37,24 +37,12 @@ use rustc_data_structures::graph::WithSuccessors; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::mir::coverage::CoverageKind; use rustc_middle::mir::*; -use rustc_middle::ty::{self, DebruijnIndex, TyS, TypeFlags}; +use rustc_middle::ty::{self, BOOL_TY}; use rustc_span::{self, BytePos, Pos, Span, DUMMY_SP}; // All `TEMP_BLOCK` targets should be replaced before calling `to_body() -> mir::Body`. const TEMP_BLOCK: BasicBlock = BasicBlock::MAX; -fn dummy_ty() -> &'static TyS<'static> { - thread_local! { - static DUMMY_TYS: &'static TyS<'static> = Box::leak(Box::new(TyS::make_for_test( - ty::Bool, - TypeFlags::empty(), - DebruijnIndex::from_usize(0), - ))); - } - - &DUMMY_TYS.with(|tys| *tys) -} - struct MockBlocks<'tcx> { blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>, dummy_place: Place<'tcx>, @@ -166,7 +154,7 @@ impl<'tcx> MockBlocks<'tcx> { fn switchint(&mut self, some_from_block: Option<BasicBlock>) -> BasicBlock { let switchint_kind = TerminatorKind::SwitchInt { discr: Operand::Move(Place::from(self.new_temp())), - switch_ty: dummy_ty(), + switch_ty: BOOL_TY, // just a dummy value targets: SwitchTargets::static_if(0, TEMP_BLOCK, TEMP_BLOCK), }; self.add_block_from(some_from_block, switchint_kind) diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index d469be74641..237ead591a5 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -222,9 +222,11 @@ impl From<Local> for UnifyLocal { impl UnifyKey for UnifyLocal { type Value = (); + #[inline] fn index(&self) -> u32 { self.0.as_u32() } + #[inline] fn from_index(u: u32) -> Self { Self(Local::from_u32(u)) } diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs index 9a6b6532ce8..ba234dccaa6 100644 --- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs +++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs @@ -153,7 +153,7 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { // create temp to store inequality comparison between the two discriminants, `_t` in // example above let nequal = BinOp::Ne; - let comp_res_type = nequal.ty(tcx, parent_ty, opt_data.child_ty); + let comp_res_type = nequal.ty(tcx, *parent_ty, opt_data.child_ty); let comp_temp = patch.new_temp(comp_res_type, opt_data.child_source.span); patch.add_statement(parent_end, StatementKind::StorageLive(comp_temp)); @@ -343,7 +343,7 @@ fn evaluate_candidate<'tcx>( Some(OptimizationData { destination, child_place: *child_place, - child_ty, + child_ty: *child_ty, child_source: child_terminator.source_info, }) } 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 e1f30fef44f..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, @@ -625,7 +634,7 @@ impl<'tcx> Inliner<'tcx> { caller_body.required_consts.extend( callee_body.required_consts.iter().copied().filter(|&ct| { match ct.literal.const_for_ty() { - Some(ct) => matches!(ct.val, ConstKind::Unevaluated(_)), + Some(ct) => matches!(ct.val(), ConstKind::Unevaluated(_)), None => true, } }), diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs index e4ac57ac925..cdfd49ef478 100644 --- a/compiler/rustc_mir_transform/src/normalize_array_len.rs +++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs @@ -3,10 +3,11 @@ use crate::MirPass; use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::intern::Interned; use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; use rustc_middle::mir::*; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, ReErased, Region, TyCtxt}; const MAX_NUM_BLOCKS: usize = 800; const MAX_NUM_LOCALS: usize = 3000; @@ -211,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; } @@ -231,11 +227,15 @@ fn normalize_array_len_call<'tcx>( // current way of patching doesn't allow to work with `mut` ( ty::Ref( - ty::RegionKind::ReErased, + Region(Interned(ReErased, _)), operand_ty, Mutability::Not, ), - ty::Ref(ty::RegionKind::ReErased, cast_ty, Mutability::Not), + ty::Ref( + Region(Interned(ReErased, _)), + cast_ty, + Mutability::Not, + ), ) => { match (operand_ty.kind(), cast_ty.kind()) { // current way of patching doesn't allow to work with `mut` diff --git a/compiler/rustc_mir_transform/src/required_consts.rs b/compiler/rustc_mir_transform/src/required_consts.rs index 80c87cafea1..1c48efd8b42 100644 --- a/compiler/rustc_mir_transform/src/required_consts.rs +++ b/compiler/rustc_mir_transform/src/required_consts.rs @@ -15,7 +15,7 @@ impl<'a, 'tcx> RequiredConstsVisitor<'a, 'tcx> { impl<'tcx> Visitor<'tcx> for RequiredConstsVisitor<'_, 'tcx> { fn visit_constant(&mut self, constant: &Constant<'tcx>, _: Location) { if let Some(ct) = constant.literal.const_for_ty() { - if let ConstKind::Unevaluated(_) = ct.val { + if let ConstKind::Unevaluated(_) = ct.val() { self.required_consts.push(*constant); } } diff --git a/compiler/rustc_mir_transform/src/reveal_all.rs b/compiler/rustc_mir_transform/src/reveal_all.rs index ee661793a44..8ea550fa123 100644 --- a/compiler/rustc_mir_transform/src/reveal_all.rs +++ b/compiler/rustc_mir_transform/src/reveal_all.rs @@ -39,6 +39,6 @@ impl<'tcx> MutVisitor<'tcx> for RevealAllVisitor<'tcx> { // We have to use `try_normalize_erasing_regions` here, since it's // possible that we visit impossible-to-satisfy where clauses here, // see #91745 - *ty = self.tcx.try_normalize_erasing_regions(self.param_env, *ty).unwrap_or(ty); + *ty = self.tcx.try_normalize_erasing_regions(self.param_env, *ty).unwrap_or(*ty); } } diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index a4927c467cf..b8feeb993e7 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -68,7 +68,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' ty::InstanceDef::DropGlue(def_id, ty) => { // FIXME(#91576): Drop shims for generators aren't subject to the MIR passes at the end // of this function. Is this intentional? - if let Some(ty::Generator(gen_def_id, substs, _)) = ty.map(ty::TyS::kind) { + if let Some(ty::Generator(gen_def_id, substs, _)) = ty.map(Ty::kind) { let body = tcx.optimized_mir(*gen_def_id).generator_drop().unwrap(); let body = body.clone().subst(tcx, substs); debug!("make_shim({:?}) = {:?}", instance, body); @@ -137,7 +137,7 @@ fn local_decls_for_sig<'tcx>( span: Span, ) -> IndexVec<Local, LocalDecl<'tcx>> { iter::once(LocalDecl::new(sig.output(), span)) - .chain(sig.inputs().iter().map(|ity| LocalDecl::new(ity, span).immutable())) + .chain(sig.inputs().iter().map(|ity| LocalDecl::new(*ity, span).immutable())) .collect() } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 7f13da5d38f..72c1b3fa6e9 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -709,7 +709,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { let literal = self.monomorphize(constant.literal); let val = match literal { mir::ConstantKind::Val(val, _) => val, - mir::ConstantKind::Ty(ct) => match ct.val { + mir::ConstantKind::Ty(ct) => match ct.val() { ty::ConstKind::Value(val) => val, ty::ConstKind::Unevaluated(ct) => { let param_env = ty::ParamEnv::reveal_all(); @@ -731,13 +731,13 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { self.visit_ty(literal.ty(), TyContext::Location(location)); } - fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, location: Location) { - debug!("visiting const {:?} @ {:?}", *constant, location); + fn visit_const(&mut self, constant: ty::Const<'tcx>, location: Location) { + debug!("visiting const {:?} @ {:?}", constant, location); - let substituted_constant = self.monomorphize(*constant); + let substituted_constant = self.monomorphize(constant); let param_env = ty::ParamEnv::reveal_all(); - match substituted_constant.val { + match substituted_constant.val() { ty::ConstKind::Value(val) => collect_const_value(self.tcx, val, self.output), ty::ConstKind::Unevaluated(unevaluated) => { match self.tcx.const_eval_resolve(param_env, unevaluated, None) { @@ -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; }; @@ -1042,7 +1040,7 @@ fn find_vtable_types_for_unsizing<'tcx>( match (&source_ty.kind(), &target_ty.kind()) { (&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) | (&ty::RawPtr(ty::TypeAndMut { ty: a, .. }), &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) => { - ptr_vtable(a, b) + ptr_vtable(*a, *b) } (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) if def_a.is_box() && def_b.is_box() => { ptr_vtable(source_ty.boxed_ty(), target_ty.boxed_ty()) 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/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index 4b17c22a68c..48b6951f10e 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -267,7 +267,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { self.super_local_decl(local, local_decl); } - fn visit_const(&mut self, c: &&'tcx Const<'tcx>, _: Location) { + fn visit_const(&mut self, c: Const<'tcx>, _: Location) { c.visit_with(self); } @@ -278,12 +278,12 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { #[instrument(level = "debug", skip(self))] - fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> { + fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> { if !c.has_param_types_or_consts() { return ControlFlow::CONTINUE; } - match c.val { + match c.val() { ty::ConstKind::Param(param) => { debug!(?param); self.unused_parameters.clear(param.index); @@ -348,12 +348,12 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> { type BreakTy = (); #[instrument(level = "debug", skip(self))] - fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> { + fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> { if !c.has_param_types_or_consts() { return ControlFlow::CONTINUE; } - match c.val { + match c.val() { ty::ConstKind::Param(param) => { if self.unused_parameters.contains(param.index).unwrap_or(false) { ControlFlow::CONTINUE 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/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs index 7f68112a427..a41956c58f0 100644 --- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs +++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs @@ -185,6 +185,15 @@ pub(crate) fn emit_unescape_error( version control settings", ); } else { + if !mode.is_bytes() { + diag.span_suggestion( + span_with_quotes, + "if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal", + format!("r\"{}\"", lit), + Applicability::MaybeIncorrect, + ); + } + diag.help( "for more information, visit \ <https://static.rust-lang.org/doc/master/reference.html#literals>", 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_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 9d653de910f..a6a2cbc277c 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -95,7 +95,7 @@ pub enum Position { /// The argument is located at a specific index given in the format ArgumentIs(usize), /// The argument has a name. - ArgumentNamed(Symbol), + ArgumentNamed(Symbol, InnerSpan), } impl Position { @@ -147,7 +147,7 @@ pub enum Count { /// The count is specified explicitly. CountIs(usize), /// The count is specified by the argument with the given name. - CountIsName(Symbol), + CountIsName(Symbol, InnerSpan), /// The count is specified by the argument at the given index. CountIsParam(usize), /// The count is implied and cannot be explicitly specified. @@ -494,8 +494,11 @@ impl<'a> Parser<'a> { Some(ArgumentIs(i)) } else { match self.cur.peek() { - Some(&(_, c)) if rustc_lexer::is_id_start(c) => { - Some(ArgumentNamed(Symbol::intern(self.word()))) + Some(&(start, c)) if rustc_lexer::is_id_start(c) => { + let word = self.word(); + let end = start + word.len(); + let span = self.to_span_index(start).to(self.to_span_index(end)); + Some(ArgumentNamed(Symbol::intern(word), span)) } // This is an `ArgumentNext`. @@ -662,8 +665,9 @@ impl<'a> Parser<'a> { if word.is_empty() { self.cur = tmp; (CountImplied, None) - } else if self.consume('$') { - (CountIsName(Symbol::intern(word)), None) + } else if let Some(end) = self.consume_pos('$') { + let span = self.to_span_index(start + 1).to(self.to_span_index(end)); + (CountIsName(Symbol::intern(word), span), None) } else { self.cur = tmp; (CountImplied, None) diff --git a/compiler/rustc_parse_format/src/tests.rs b/compiler/rustc_parse_format/src/tests.rs index b7693a85ad9..6c960fdc72b 100644 --- a/compiler/rustc_parse_format/src/tests.rs +++ b/compiler/rustc_parse_format/src/tests.rs @@ -221,8 +221,8 @@ fn format_counts() { fill: None, align: AlignUnknown, flags: 0, - precision: CountIsName(Symbol::intern("b")), - width: CountIsName(Symbol::intern("a")), + precision: CountIsName(Symbol::intern("b"), InnerSpan::new(6, 7)), + width: CountIsName(Symbol::intern("a"), InnerSpan::new(4, 4)), precision_span: None, width_span: None, ty: "?", diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index dc3ce1afa33..e52fbc8ab92 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -104,7 +104,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { self.check_def_id(variant_id); } } - Res::SelfTy(t, i) => { + Res::SelfTy { trait_: t, alias_to: i } => { if let Some(t) = t { self.check_def_id(t); } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 7c511ccbd57..48594e73f5b 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -280,8 +280,8 @@ where } } - fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> { - self.visit_ty(c.ty)?; + fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> { + self.visit_ty(c.ty())?; let tcx = self.def_id_visitor.tcx(); if let Ok(Some(ct)) = AbstractConst::from_const(tcx, c) { self.visit_abstract_const_expr(tcx, ct)?; @@ -1350,7 +1350,7 @@ struct ObsoleteCheckTypeForPrivatenessVisitor<'a, 'b, 'tcx> { impl<'a, 'tcx> ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { fn path_is_private_type(&self, path: &hir::Path<'_>) -> bool { let did = match path.res { - Res::PrimTy(..) | Res::SelfTy(..) | Res::Err => return false, + Res::PrimTy(..) | Res::SelfTy { .. } | Res::Err => return false, res => res.def_id(), }; diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs index 581a2bce2e5..84de31a194d 100644 --- a/compiler/rustc_query_impl/src/keys.rs +++ b/compiler/rustc_query_impl/src/keys.rs @@ -275,7 +275,7 @@ impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) { } } -impl<'tcx> Key for (&'tcx ty::Const<'tcx>, mir::Field) { +impl<'tcx> Key for (ty::Const<'tcx>, mir::Field) { #[inline(always)] fn query_crate_is_local(&self) -> bool { true @@ -345,7 +345,7 @@ impl<'tcx> Key for mir::ConstantKind<'tcx> { } } -impl<'tcx> Key for &'tcx ty::Const<'tcx> { +impl<'tcx> Key for ty::Const<'tcx> { #[inline(always)] fn query_crate_is_local(&self) -> bool { true diff --git a/compiler/rustc_query_impl/src/values.rs b/compiler/rustc_query_impl/src/values.rs index 003867beeb7..718a2971c40 100644 --- a/compiler/rustc_query_impl/src/values.rs +++ b/compiler/rustc_query_impl/src/values.rs @@ -1,5 +1,5 @@ use super::QueryCtxt; -use rustc_middle::ty::{self, AdtSizedConstraint, Ty, TyS}; +use rustc_middle::ty::{self, AdtSizedConstraint, Ty}; pub(super) trait Value<'tcx>: Sized { fn from_cycle_error(tcx: QueryCtxt<'tcx>) -> Self; @@ -12,7 +12,7 @@ impl<'tcx, T> Value<'tcx> for T { } } -impl<'tcx> Value<'tcx> for &'_ TyS<'_> { +impl<'tcx> Value<'tcx> for Ty<'_> { fn from_cycle_error(tcx: QueryCtxt<'tcx>) -> Self { // SAFETY: This is never called when `Self` is not `Ty<'tcx>`. // FIXME: Represent the above fact in the trait system somehow. diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index e4d8b7d5283..3fa9343c399 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -991,7 +991,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { _, ) | Res::Local(..) - | Res::SelfTy(..) + | Res::SelfTy { .. } | Res::SelfCtor(..) | Res::Err => bug!("unexpected resolution: {:?}", res), } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 1f657218a64..9a2fb3b86e2 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -123,7 +123,7 @@ impl<'a> Resolver<'a> { let sm = self.session.source_map(); match outer_res { - Res::SelfTy(maybe_trait_defid, maybe_impl_defid) => { + Res::SelfTy { trait_: maybe_trait_defid, alias_to: maybe_impl_defid } => { if let Some(impl_span) = maybe_impl_defid.and_then(|(def_id, _)| self.opt_span(def_id)) { @@ -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/imports.rs b/compiler/rustc_resolve/src/imports.rs index e7f76a18ad3..a8c2a5e1424 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -11,7 +11,7 @@ use crate::{NameBinding, NameBindingKind, PathResult, PrivacyError, ToNameBindin use rustc_ast::NodeId; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::ptr_key::PtrKey; +use rustc_data_structures::intern::Interned; use rustc_errors::{pluralize, struct_span_err, Applicability}; use rustc_hir::def::{self, PartialRes}; use rustc_hir::def_id::DefId; @@ -134,7 +134,7 @@ impl<'a> Import<'a> { pub struct NameResolution<'a> { /// Single imports that may define the name in the namespace. /// Imports are arena-allocated, so it's ok to use pointers as keys. - single_imports: FxHashSet<PtrKey<'a, Import<'a>>>, + single_imports: FxHashSet<Interned<'a, Import<'a>>>, /// The least shadowable known binding for this name, or None if there are no known bindings. pub binding: Option<&'a NameBinding<'a>>, shadowed_glob: Option<&'a NameBinding<'a>>, @@ -153,7 +153,7 @@ impl<'a> NameResolution<'a> { } crate fn add_single_import(&mut self, import: &'a Import<'a>) { - self.single_imports.insert(PtrKey(import)); + self.single_imports.insert(Interned::new_unchecked(import)); } } @@ -850,7 +850,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { Err(Determined) => { let key = this.new_key(target, ns); this.update_resolution(parent, key, |_, resolution| { - resolution.single_imports.remove(&PtrKey(import)); + resolution.single_imports.remove(&Interned::new_unchecked(import)); }); } Ok(binding) if !binding.is_importable() => { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 6aed3223480..9ac3e6e22bd 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -289,7 +289,7 @@ impl<'a> PathSource<'a> { | DefKind::ForeignTy, _, ) | Res::PrimTy(..) - | Res::SelfTy(..) + | Res::SelfTy { .. } ), PathSource::Trait(AliasPossibility::No) => matches!(res, Res::Def(DefKind::Trait, _)), PathSource::Trait(AliasPossibility::Maybe) => { @@ -326,7 +326,7 @@ impl<'a> PathSource<'a> { | DefKind::TyAlias | DefKind::AssocTy, _, - ) | Res::SelfTy(..) + ) | Res::SelfTy { .. } ), PathSource::TraitItem(ns) => match res { Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) if ns == ValueNS => true, @@ -911,9 +911,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.with_current_self_item(item, |this| { this.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| { let item_def_id = this.r.local_def_id(item.id).to_def_id(); - this.with_self_rib(Res::SelfTy(None, Some((item_def_id, false))), |this| { - visit::walk_item(this, item); - }); + this.with_self_rib( + Res::SelfTy { trait_: None, alias_to: Some((item_def_id, false)) }, + |this| { + visit::walk_item(this, item); + }, + ); }); }); } @@ -999,8 +1002,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.compute_num_lifetime_params(item.id, generics); // Create a new rib for the trait-wide type parameters. self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| { - let local_def_id = this.r.local_def_id(item.id).to_def_id(); - this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| { + let def = this.r.local_def_id(item.id).to_def_id(); + this.with_self_rib(Res::SelfTy { trait_: Some(def), alias_to: None }, |this| { this.visit_generics(generics); walk_list!(this, visit_param_bound, bounds); @@ -1051,8 +1054,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.compute_num_lifetime_params(item.id, generics); // Create a new rib for the trait-wide type parameters. self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| { - let local_def_id = this.r.local_def_id(item.id).to_def_id(); - this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| { + let def = this.r.local_def_id(item.id).to_def_id(); + this.with_self_rib(Res::SelfTy { trait_: Some(def), alias_to: None }, |this| { this.visit_generics(generics); walk_list!(this, visit_param_bound, bounds); }); @@ -1296,7 +1299,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // If applicable, create a rib for the type parameters. self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| { // Dummy self type for better errors if `Self` is used in the trait path. - this.with_self_rib(Res::SelfTy(None, None), |this| { + this.with_self_rib(Res::SelfTy { trait_: None, alias_to: None }, |this| { // Resolve the trait reference, if necessary. this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| { let item_def_id = this.r.local_def_id(item_id); @@ -1307,7 +1310,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } let item_def_id = item_def_id.to_def_id(); - this.with_self_rib(Res::SelfTy(trait_id, Some((item_def_id, false))), |this| { + let res = + Res::SelfTy { trait_: trait_id, alias_to: Some((item_def_id, false)) }; + this.with_self_rib(res, |this| { if let Some(trait_ref) = opt_trait_reference.as_ref() { // Resolve type arguments in the trait path. visit::walk_trait_ref(this, trait_ref); diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index d05f139e3bf..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, ); } @@ -1189,7 +1185,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { Applicability::HasPlaceholders, ); } - (Res::SelfTy(..), _) if ns == ValueNS => { + (Res::SelfTy { .. }, _) if ns == ValueNS => { err.span_label(span, fallback_label); err.note("can't use `Self` as a constructor, you must use the implemented struct"); } diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index d25bee67d4e..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; @@ -2811,7 +2793,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { // Look for `self: &'a Self` - also desugared from `&'a self`, // and if that matches, use it for elision and return early. fn is_self_ty(&self, res: Res) -> bool { - if let Res::SelfTy(..) = res { + if let Res::SelfTy { .. } = res { return true; } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 28f06ed3a26..28d8d9247ac 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -38,7 +38,7 @@ use rustc_ast::{ItemKind, ModKind, Path}; use rustc_ast_lowering::ResolverAstLowering; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; -use rustc_data_structures::ptr_key::PtrKey; +use rustc_data_structures::intern::Interned; use rustc_data_structures::sync::Lrc; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_expand::base::{DeriveResolutions, SyntaxExtension, SyntaxExtensionKind}; @@ -964,7 +964,7 @@ pub struct Resolver<'a> { /// language items. empty_module: Module<'a>, module_map: FxHashMap<DefId, Module<'a>>, - binding_parent_modules: FxHashMap<PtrKey<'a, NameBinding<'a>>, Module<'a>>, + binding_parent_modules: FxHashMap<Interned<'a, NameBinding<'a>>, Module<'a>>, underscore_disambiguator: u32, /// Maps glob imports to the names of items actually imported. @@ -1115,7 +1115,7 @@ impl<'a> ResolverArenas<'a> { self.name_resolutions.alloc(Default::default()) } fn alloc_macro_rules_scope(&'a self, scope: MacroRulesScope<'a>) -> MacroRulesScopeRef<'a> { - PtrKey(self.dropless.alloc(Cell::new(scope))) + Interned::new_unchecked(self.dropless.alloc(Cell::new(scope))) } fn alloc_macro_rules_binding( &'a self, @@ -2784,7 +2784,7 @@ impl<'a> Resolver<'a> { return Res::Err; } } - Res::Def(DefKind::TyParam, _) | Res::SelfTy(..) => { + Res::Def(DefKind::TyParam, _) | Res::SelfTy { .. } => { for rib in ribs { let has_generic_params: HasGenericParams = match rib.kind { NormalRibKind @@ -2804,8 +2804,8 @@ impl<'a> Resolver<'a> { // HACK(min_const_generics): If we encounter `Self` in an anonymous constant // we can't easily tell if it's generic at this stage, so we instead remember // this and then enforce the self type to be concrete later on. - if let Res::SelfTy(trait_def, Some((impl_def, _))) = res { - res = Res::SelfTy(trait_def, Some((impl_def, true))); + if let Res::SelfTy { trait_, alias_to: Some((def, _)) } = res { + res = Res::SelfTy { trait_, alias_to: Some((def, true)) } } else { if record_used { self.report_error( @@ -2938,7 +2938,9 @@ impl<'a> Resolver<'a> { } fn set_binding_parent_module(&mut self, binding: &'a NameBinding<'a>, module: Module<'a>) { - if let Some(old_module) = self.binding_parent_modules.insert(PtrKey(binding), module) { + if let Some(old_module) = + self.binding_parent_modules.insert(Interned::new_unchecked(binding), module) + { if !ptr::eq(module, old_module) { span_bug!(binding.span, "parent module is reset for binding"); } @@ -2954,8 +2956,8 @@ impl<'a> Resolver<'a> { // is disambiguated to mitigate regressions from macro modularization. // Scoping for `macro_rules` behaves like scoping for `let` at module level, in general. match ( - self.binding_parent_modules.get(&PtrKey(macro_rules)), - self.binding_parent_modules.get(&PtrKey(modularized)), + self.binding_parent_modules.get(&Interned::new_unchecked(macro_rules)), + self.binding_parent_modules.get(&Interned::new_unchecked(modularized)), ) { (Some(macro_rules), Some(modularized)) => { macro_rules.nearest_parent_mod() == modularized.nearest_parent_mod() diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 82807e2d0a2..89c2a0c74bd 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -11,7 +11,7 @@ use rustc_ast_lowering::ResolverAstLowering; use rustc_ast_pretty::pprust; use rustc_attr::StabilityLevel; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::ptr_key::PtrKey; +use rustc_data_structures::intern::Interned; use rustc_data_structures::sync::Lrc; use rustc_errors::struct_span_err; use rustc_expand::base::{Annotatable, DeriveResolutions, Indeterminate, ResolverExpand}; @@ -71,7 +71,7 @@ pub enum MacroRulesScope<'a> { /// This helps to avoid uncontrollable growth of `macro_rules!` scope chains, /// which usually grow lineraly with the number of macro invocations /// in a module (including derives) and hurt performance. -pub(crate) type MacroRulesScopeRef<'a> = PtrKey<'a, Cell<MacroRulesScope<'a>>>; +pub(crate) type MacroRulesScopeRef<'a> = Interned<'a, Cell<MacroRulesScope<'a>>>; // Macro namespace is separated into two sub-namespaces, one for bang macros and // one for attribute-like macros (attributes, derives). diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs index 79d55b297fd..0ff56a30ea0 100644 --- a/compiler/rustc_save_analysis/src/dump_visitor.rs +++ b/compiler/rustc_save_analysis/src/dump_visitor.rs @@ -921,7 +921,7 @@ impl<'tcx> DumpVisitor<'tcx> { | HirDefKind::AssocTy, _, ) - | Res::SelfTy(..) => { + | Res::SelfTy { .. } => { self.dump_path_segment_ref(id, &hir::PathSegment::from_ident(ident)); } def => { diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs index 2eebddb47df..8b0adba9fab 100644 --- a/compiler/rustc_save_analysis/src/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -749,7 +749,7 @@ impl<'tcx> SaveContext<'tcx> { _, ) | Res::PrimTy(..) - | Res::SelfTy(..) + | Res::SelfTy { .. } | Res::ToolMod | Res::NonMacroAttr(..) | Res::SelfCtor(..) @@ -814,7 +814,7 @@ impl<'tcx> SaveContext<'tcx> { fn lookup_def_id(&self, ref_id: hir::HirId) -> Option<DefId> { match self.get_path_res(ref_id) { - Res::PrimTy(_) | Res::SelfTy(..) | Res::Err => None, + Res::PrimTy(_) | Res::SelfTy { .. } | Res::Err => None, def => def.opt_def_id(), } } diff --git a/compiler/rustc_save_analysis/src/sig.rs b/compiler/rustc_save_analysis/src/sig.rs index 4971bb6d1aa..3bb1d2ff357 100644 --- a/compiler/rustc_save_analysis/src/sig.rs +++ b/compiler/rustc_save_analysis/src/sig.rs @@ -573,7 +573,7 @@ impl<'hir> Sig for hir::Path<'hir> { let res = scx.get_path_res(id.ok_or("Missing id for Path")?); let (name, start, end) = match res { - Res::PrimTy(..) | Res::SelfTy(..) | Res::Err => { + Res::PrimTy(..) | Res::SelfTy { .. } | Res::Err => { return Ok(Signature { text: path_to_string(self), defs: vec![], refs: vec![] }); } Res::Def(DefKind::AssocConst | DefKind::Variant | DefKind::Ctor(..), _) => { diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 79962d5db89..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}; @@ -63,6 +63,22 @@ pub enum CFGuard { Checks, } +/// The different settings that the `-Z cf-protection` flag can have. +#[derive(Clone, Copy, PartialEq, Hash, Debug)] +pub enum CFProtection { + /// Do not enable control-flow protection + None, + + /// Emit control-flow protection for branches (enables indirect branch tracking). + Branch, + + /// Emit control-flow protection for returns. + Return, + + /// Emit control-flow protection for both branches and returns. + Full, +} + #[derive(Clone, Copy, Debug, PartialEq, Hash)] pub enum OptLevel { No, // -O0 @@ -920,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(); @@ -1004,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. @@ -1147,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", "", @@ -2630,11 +2733,11 @@ impl PpMode { /// we have an opt-in scheme here, so one is hopefully forced to think about /// how the hash should be calculated when adding a new command-line argument. crate mod dep_tracking { - use super::LdImpl; use super::{ - BranchProtection, CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage, - LinkerPluginLto, LocationDetail, LtoCli, OptLevel, OutputType, OutputTypes, Passes, - SourceFileHashAlgorithm, SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths, + BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType, + InstrumentCoverage, LdImpl, LinkerPluginLto, LocationDetail, LtoCli, OptLevel, OutputType, + OutputTypes, Passes, SourceFileHashAlgorithm, SwitchWithOptPath, SymbolManglingVersion, + TrimmedDefPaths, }; use crate::lint; use crate::options::WasiExecModel; @@ -2715,6 +2818,7 @@ crate mod dep_tracking { NativeLibKind, SanitizerSet, CFGuard, + CFProtection, TargetTriple, Edition, LinkerPluginLto, diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index ae1b638c344..0a4bd23937d 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -376,10 +376,11 @@ 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`"; + pub const parse_cfprotection: &str = "`none`|`no`|`n` (default), `branch`, `return`, or `full`|`yes`|`y` (equivalent to `branch` and `return`)"; pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`"; pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavor::one_of(); pub const parse_optimization_fuel: &str = "crate=integer"; @@ -638,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, @@ -695,6 +697,25 @@ mod parse { true } + crate fn parse_cfprotection(slot: &mut CFProtection, v: Option<&str>) -> bool { + if v.is_some() { + let mut bool_arg = None; + if parse_opt_bool(&mut bool_arg, v) { + *slot = if bool_arg.unwrap() { CFProtection::Full } else { CFProtection::None }; + return true; + } + } + + *slot = match v { + None | Some("none") => CFProtection::None, + Some("branch") => CFProtection::Branch, + Some("return") => CFProtection::Return, + Some("full") => CFProtection::Full, + Some(_) => return false, + }; + true + } + crate fn parse_linker_flavor(slot: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool { match v.and_then(LinkerFlavor::from_str) { Some(lf) => *slot = Some(lf), @@ -1142,6 +1163,8 @@ options! { "select which borrowck is used (`mir` or `migrate`) (default: `migrate`)"), branch_protection: BranchProtection = (BranchProtection::default(), parse_branch_protection, [TRACKED], "set options for branch target identification and pointer authentication on AArch64"), + cf_protection: CFProtection = (CFProtection::None, parse_cfprotection, [TRACKED], + "instrument control-flow architecture protection"), cgu_partitioning_strategy: Option<String> = (None, parse_opt_string, [TRACKED], "the codegen unit partitioning strategy to use"), chalk: bool = (false, parse_bool, [TRACKED], 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/Cargo.toml b/compiler/rustc_span/Cargo.toml index 781fb8c1e5d..7227b193f21 100644 --- a/compiler/rustc_span/Cargo.toml +++ b/compiler/rustc_span/Cargo.toml @@ -16,6 +16,6 @@ scoped-tls = "1.0" unicode-width = "0.1.4" cfg-if = "0.1.2" tracing = "0.1" -sha1 = { package = "sha-1", version = "0.9" } -sha2 = "0.9" -md5 = { package = "md-5", version = "0.9" } +sha1 = { package = "sha-1", version = "0.10.0" } +sha2 = "0.10.1" +md5 = { package = "md-5", version = "0.10.0" } diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index e0d6bd8cb7b..8265eb23c3d 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -172,10 +172,12 @@ impl LocalExpnId { /// The ID of the theoretical expansion that generates freshly parsed, unexpanded AST. pub const ROOT: LocalExpnId = LocalExpnId::from_u32(0); + #[inline] pub fn from_raw(idx: ExpnIndex) -> LocalExpnId { LocalExpnId::from_u32(idx.as_u32()) } + #[inline] pub fn as_raw(self) -> ExpnIndex { ExpnIndex::from_u32(self.as_u32()) } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 3ce9f852c3d..dea2fbf04be 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -68,8 +68,8 @@ use std::ops::{Add, Range, Sub}; use std::path::{Path, PathBuf}; use std::str::FromStr; +use md5::Digest; use md5::Md5; -use sha1::Digest; use sha1::Sha1; use sha2::Sha256; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 2e451502263..c746255e95e 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -423,6 +423,7 @@ symbols! { cfg_target_feature, cfg_target_has_atomic, cfg_target_has_atomic_equal_alignment, + cfg_target_has_atomic_load_store, cfg_target_thread_local, cfg_target_vendor, cfg_version, @@ -875,6 +876,7 @@ symbols! { mem_zeroed, member_constraints, memory, + memtag, message, meta, metadata_type, @@ -909,6 +911,7 @@ symbols! { naked, naked_functions, name, + names, native_link_modifiers, native_link_modifiers_as_needed, native_link_modifiers_bundle, @@ -1455,6 +1458,7 @@ symbols! { unsafe_block_in_unsafe_fn, unsafe_cell, unsafe_no_drop_flag, + unsafe_pin_internals, unsize, unsized_fn_params, unsized_locals, @@ -1479,6 +1483,7 @@ symbols! { va_list, va_start, val, + values, var, variant_count, vec, diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index c981b3ff546..cec1d4bc157 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -243,10 +243,10 @@ impl<'tcx> Printer<'tcx> for &mut SymbolPrinter<'tcx> { Ok(self) } - fn print_const(self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> { + fn print_const(self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> { // only print integers - if let ty::ConstKind::Value(ConstValue::Scalar(Scalar::Int { .. })) = ct.val { - if ct.ty.is_integral() { + if let ty::ConstKind::Value(ConstValue::Scalar(Scalar::Int { .. })) = ct.val() { + if ct.ty().is_integral() { return self.pretty_print_const(ct, true); } } diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index f8e8e15e78c..c21c3d3ac33 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -116,7 +116,7 @@ struct SymbolMangler<'tcx> { /// The values are start positions in `out`, in bytes. paths: FxHashMap<(DefId, &'tcx [GenericArg<'tcx>]), usize>, types: FxHashMap<Ty<'tcx>, usize>, - consts: FxHashMap<&'tcx ty::Const<'tcx>, usize>, + consts: FxHashMap<ty::Const<'tcx>, usize>, } impl<'tcx> SymbolMangler<'tcx> { @@ -420,7 +420,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { hir::Mutability::Not => "R", hir::Mutability::Mut => "Q", }); - if *r != ty::ReErased { + if !r.is_erased() { self = r.print(self)?; } self = ty.print(self)?; @@ -576,10 +576,10 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { Ok(self) } - fn print_const(mut self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> { + fn print_const(mut self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> { // We only mangle a typed value if the const can be evaluated. let ct = ct.eval(self.tcx, ty::ParamEnv::reveal_all()); - match ct.val { + match ct.val() { ty::ConstKind::Value(_) => {} // Placeholders (should be demangled as `_`). @@ -603,14 +603,14 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { } let start = self.out.len(); - match ct.ty.kind() { + match ct.ty().kind() { ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char => { - self = ct.ty.print(self)?; + self = ct.ty().print(self)?; - let mut bits = ct.eval_bits(self.tcx, ty::ParamEnv::reveal_all(), ct.ty); + let mut bits = ct.eval_bits(self.tcx, ty::ParamEnv::reveal_all(), ct.ty()); // Negative integer values are mangled using `n` as a "sign prefix". - if let ty::Int(ity) = ct.ty.kind() { + if let ty::Int(ity) = ct.ty().kind() { let val = Integer::from_int_ty(&self.tcx, *ity).size().sign_extend(bits) as i128; if val < 0 { @@ -627,7 +627,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { // handle `&str` and include both `&` ("R") and `str` ("e") prefixes. ty::Ref(_, ty, hir::Mutability::Not) if *ty == self.tcx.types.str_ => { self.push("R"); - match ct.val { + match ct.val() { ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => { // NOTE(eddyb) the following comment was kept from `ty::print::pretty`: // The `inspect` here is okay since we checked the bounds, and there are no @@ -671,7 +671,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { Ok(this) }; - match *ct.ty.kind() { + match *ct.ty().kind() { ty::Array(..) => { self.push("A"); self = print_field_list(self)?; @@ -721,7 +721,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { } _ => { - bug!("symbol_names: unsupported constant of type `{}` ({:?})", ct.ty, ct); + bug!("symbol_names: unsupported constant of type `{}` ({:?})", ct.ty(), ct); } } @@ -811,7 +811,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { ) -> Result<Self::Path, Self::Error> { // Don't print any regions if they're all erased. let print_regions = args.iter().any(|arg| match arg.unpack() { - GenericArgKind::Lifetime(r) => *r != ty::ReErased, + GenericArgKind::Lifetime(r) => !r.is_erased(), _ => false, }); let args = args.iter().cloned().filter(|arg| match arg.unpack() { 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/i686_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs index 74074cfb5dd..174294895bf 100644 --- a/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs @@ -24,7 +24,7 @@ pub fn target() -> Target { llvm_target: "i686-pc-windows-msvc".to_string(), pointer_width: 32, data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ - i64:64-f80:32-n8:16:32-a:0:32-S32" + i64:64-f80:128-n8:16:32-a:0:32-S32" .to_string(), arch: "x86".to_string(), options: base, diff --git a/compiler/rustc_target/src/spec/i686_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/i686_uwp_windows_msvc.rs index 05f204c5604..e2f65e7a7c9 100644 --- a/compiler/rustc_target/src/spec/i686_uwp_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/i686_uwp_windows_msvc.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { llvm_target: "i686-pc-windows-msvc".to_string(), pointer_width: 32, data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ - i64:64-f80:32-n8:16:32-a:0:32-S32" + i64:64-f80:128-n8:16:32-a:0:32-S32" .to_string(), arch: "x86".to_string(), options: base, 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 d735f3d41fd..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, ] @@ -1541,11 +1544,13 @@ impl Default for TargetOptions { impl Deref for Target { type Target = TargetOptions; + #[inline] fn deref(&self) -> &Self::Target { &self.options } } impl DerefMut for Target { + #[inline] fn deref_mut(&mut self) -> &mut Self::Target { &mut self.options } @@ -1881,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_target/src/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs index 69a404ec564..8fcdbc146af 100644 --- a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs +++ b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs @@ -43,7 +43,8 @@ pub fn target() -> Target { Target { llvm_target: "wasm32-unknown-emscripten".to_string(), pointer_width: 32, - data_layout: "e-m:e-p:32:32-i64:64-f128:64-n32:64-S128-ni:1:10:20".to_string(), + data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-f128:64-n32:64-S128-ni:1:10:20" + .to_string(), arch: "wasm32".to_string(), options: opts, } diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs index 134c6803b15..e50cf974094 100644 --- a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs +++ b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs @@ -54,7 +54,7 @@ pub fn target() -> Target { Target { llvm_target: "wasm32-unknown-unknown".to_string(), pointer_width: 32, - data_layout: "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20".to_string(), + data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".to_string(), arch: "wasm32".to_string(), options, } diff --git a/compiler/rustc_target/src/spec/wasm32_wasi.rs b/compiler/rustc_target/src/spec/wasm32_wasi.rs index 2dab206dc76..a4b81c9a278 100644 --- a/compiler/rustc_target/src/spec/wasm32_wasi.rs +++ b/compiler/rustc_target/src/spec/wasm32_wasi.rs @@ -109,7 +109,7 @@ pub fn target() -> Target { Target { llvm_target: "wasm32-wasi".to_string(), pointer_width: 32, - data_layout: "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20".to_string(), + data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".to_string(), arch: "wasm32".to_string(), options, } diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index ea0ac6318bc..c93ff0aa6e2 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -141,7 +141,7 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> { #[instrument(skip(self), level = "debug")] fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - match r { + match *r { // Ignore bound regions and `'static` regions that appear in the // type, we only need to remap regions that reference lifetimes // from the function declaraion. @@ -287,10 +287,10 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> { } } - fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { trace!("checking const {:?}", ct); // Find a const parameter - match ct.val { + match ct.val() { ty::ConstKind::Param(..) => { // Look it up in the substitution list. match self.map.get(&ct.into()).map(|k| k.unpack()) { @@ -311,7 +311,7 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> { ) .emit(); - self.tcx().const_error(ct.ty) + self.tcx().const_error(ct.ty()) } } } diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index f2ed5ae26a3..5fe7b62f454 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -437,16 +437,12 @@ impl<'tcx> AutoTraitFinder<'tcx> { for (new_region, old_region) in iter::zip(new_substs.regions(), old_substs.regions()) { - match (new_region, old_region) { + match (*new_region, *old_region) { // If both predicates have an `ReLateBound` (a HRTB) in the // same spot, we do nothing. - ( - ty::RegionKind::ReLateBound(_, _), - ty::RegionKind::ReLateBound(_, _), - ) => {} + (ty::ReLateBound(_, _), ty::ReLateBound(_, _)) => {} - (ty::RegionKind::ReLateBound(_, _), _) - | (_, ty::RegionKind::ReVar(_)) => { + (ty::ReLateBound(_, _), _) | (_, ty::ReVar(_)) => { // One of these is true: // The new predicate has a HRTB in a spot where the old // predicate does not (if they both had a HRTB, the previous @@ -472,8 +468,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { // `user_computed_preds`. return false; } - (_, ty::RegionKind::ReLateBound(_, _)) - | (ty::RegionKind::ReVar(_), _) => { + (_, ty::ReLateBound(_, _)) | (ty::ReVar(_), _) => { // This is the opposite situation as the previous arm. // One of these is true: // @@ -814,14 +809,14 @@ impl<'tcx> AutoTraitFinder<'tcx> { }; } ty::PredicateKind::ConstEquate(c1, c2) => { - let evaluate = |c: &'tcx ty::Const<'tcx>| { - if let ty::ConstKind::Unevaluated(unevaluated) = c.val { + let evaluate = |c: ty::Const<'tcx>| { + if let ty::ConstKind::Unevaluated(unevaluated) = c.val() { match select.infcx().const_eval_resolve( obligation.param_env, unevaluated, Some(obligation.cause.span), ) { - Ok(val) => Ok(ty::Const::from_value(select.tcx(), val, c.ty)), + Ok(val) => Ok(ty::Const::from_value(select.tcx(), val, c.ty())), Err(err) => Err(err), } } else { @@ -880,8 +875,8 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionReplacer<'a, 'tcx> { } fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - (match r { - ty::ReVar(vid) => self.vid_to_region.get(vid).cloned(), + (match *r { + ty::ReVar(vid) => self.vid_to_region.get(&vid).cloned(), _ => None, }) .unwrap_or_else(|| r.super_fold_with(self)) 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/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 21775a5c49f..b2aa72e0e67 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -4,8 +4,8 @@ //! [trait-resolution]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html //! [trait-specialization]: https://rustc-dev-guide.rust-lang.org/traits/specialization.html -use crate::infer::{CombinedSnapshot, InferOk, TyCtxtInferExt}; -use crate::traits::query::evaluate_obligation::InferCtxtExt; +use crate::infer::outlives::env::OutlivesEnvironment; +use crate::infer::{CombinedSnapshot, InferOk, RegionckMode}; use crate::traits::select::IntercrateAmbiguityCause; use crate::traits::util::impl_trait_ref_and_oblig; use crate::traits::SkipLeakCheck; @@ -13,9 +13,13 @@ use crate::traits::{ self, FulfillmentContext, Normalized, Obligation, ObligationCause, PredicateObligation, PredicateObligations, SelectionContext, }; +//use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; +use rustc_hir::CRATE_HIR_ID; +use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::traits::TraitEngine; use rustc_middle::traits::specialization_graph::OverlapMode; -use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences}; +use rustc_middle::ty::fast_reject::{self, SimplifyParams}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -82,8 +86,8 @@ where impl2_ref.iter().flat_map(|tref| tref.substs.types()), ) .any(|(ty1, ty2)| { - let t1 = fast_reject::simplify_type(tcx, ty1, SimplifyParams::No, StripReferences::No); - let t2 = fast_reject::simplify_type(tcx, ty2, SimplifyParams::No, StripReferences::No); + let t1 = fast_reject::simplify_type(tcx, ty1, SimplifyParams::No); + let t2 = fast_reject::simplify_type(tcx, ty2, SimplifyParams::No); if let (Some(t1), Some(t2)) = (t1, t2) { // Simplified successfully @@ -150,7 +154,10 @@ fn overlap<'cx, 'tcx>( impl2_def_id: DefId, overlap_mode: OverlapMode, ) -> Option<OverlapResult<'tcx>> { - debug!("overlap(impl1_def_id={:?}, impl2_def_id={:?})", impl1_def_id, impl2_def_id); + debug!( + "overlap(impl1_def_id={:?}, impl2_def_id={:?}, overlap_mode={:?})", + impl1_def_id, impl2_def_id, overlap_mode + ); selcx.infcx().probe_maybe_skip_leak_check(skip_leak_check.is_yes(), |snapshot| { overlap_within_probe( @@ -191,9 +198,6 @@ fn overlap_within_probe<'cx, 'tcx>( let impl1_header = with_fresh_ty_vars(selcx, param_env, impl1_def_id); let impl2_header = with_fresh_ty_vars(selcx, param_env, impl2_def_id); - debug!("overlap: impl1_header={:?}", impl1_header); - debug!("overlap: impl2_header={:?}", impl2_header); - let obligations = equate_impl_headers(selcx, &impl1_header, &impl2_header)?; debug!("overlap: unification check succeeded"); @@ -226,6 +230,7 @@ fn equate_impl_headers<'cx, 'tcx>( impl2_header: &ty::ImplHeader<'tcx>, ) -> Option<PredicateObligations<'tcx>> { // Do `a` and `b` unify? If not, no overlap. + debug!("equate_impl_headers(impl1_header={:?}, impl2_header={:?}", impl1_header, impl2_header); selcx .infcx() .at(&ObligationCause::dummy(), ty::ParamEnv::empty()) @@ -264,8 +269,11 @@ fn implicit_negative<'cx, 'tcx>( // If the obligation `&'?a str: Error` holds, it means that there's overlap. If that doesn't // hold we need to check if `&'?a str: !Error` holds, if doesn't hold there's overlap because // at some point an impl for `&'?a str: Error` could be added. + debug!( + "implicit_negative(impl1_header={:?}, impl2_header={:?}, obligations={:?})", + impl1_header, impl2_header, obligations + ); let infcx = selcx.infcx(); - let tcx = infcx.tcx; let opt_failing_obligation = impl1_header .predicates .iter() @@ -279,12 +287,7 @@ fn implicit_negative<'cx, 'tcx>( predicate: p, }) .chain(obligations) - .find(|o| { - loose_check(selcx, o) || tcx.features().negative_impls && negative_impl_exists(selcx, o) - }); - // FIXME: the call to `selcx.predicate_may_hold_fatal` above should be ported - // to the canonical trait query form, `infcx.predicate_may_hold`, once - // the new system supports intercrate mode (which coherence needs). + .find(|o| !selcx.predicate_may_hold_fatal(o)); if let Some(failing_obligation) = opt_failing_obligation { debug!("overlap: obligation unsatisfiable {:?}", failing_obligation); @@ -301,6 +304,7 @@ fn negative_impl<'cx, 'tcx>( impl1_def_id: DefId, impl2_def_id: DefId, ) -> bool { + debug!("negative_impl(impl1_def_id={:?}, impl2_def_id={:?})", impl1_def_id, impl2_def_id); let tcx = selcx.infcx().tcx; // create a parameter environment corresponding to a (placeholder) instantiation of impl1 @@ -348,7 +352,7 @@ fn negative_impl<'cx, 'tcx>( let opt_failing_obligation = obligations .into_iter() .chain(more_obligations) - .find(|o| negative_impl_exists(selcx, o)); + .find(|o| negative_impl_exists(selcx, impl1_env, impl1_def_id, o)); if let Some(failing_obligation) = opt_failing_obligation { debug!("overlap: obligation unsatisfiable {:?}", failing_obligation); @@ -359,24 +363,47 @@ fn negative_impl<'cx, 'tcx>( }) } -fn loose_check<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - o: &PredicateObligation<'tcx>, -) -> bool { - !selcx.predicate_may_hold_fatal(o) -} - fn negative_impl_exists<'cx, 'tcx>( selcx: &SelectionContext<'cx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + region_context: DefId, o: &PredicateObligation<'tcx>, ) -> bool { - let infcx = selcx.infcx(); + let infcx = &selcx.infcx().fork(); let tcx = infcx.tcx; o.flip_polarity(tcx) - .as_ref() .map(|o| { - // FIXME This isn't quite correct, regions should be included - selcx.infcx().predicate_must_hold_modulo_regions(o) + let mut fulfillment_cx = FulfillmentContext::new(); + fulfillment_cx.register_predicate_obligation(infcx, o); + + let errors = fulfillment_cx.select_all_or_error(infcx); + if !errors.is_empty() { + return false; + } + + let mut outlives_env = OutlivesEnvironment::new(param_env); + // FIXME -- add "assumed to be well formed" types into the `outlives_env` + + // "Save" the accumulated implied bounds into the outlives environment + // (due to the FIXME above, there aren't any, but this step is still needed). + // The "body id" is given as `CRATE_HIR_ID`, which is the same body-id used + // by the "dummy" causes elsewhere (body-id is only relevant when checking + // function bodies with closures). + outlives_env.save_implied_bounds(CRATE_HIR_ID); + + infcx.process_registered_region_obligations( + outlives_env.region_bound_pairs_map(), + Some(tcx.lifetimes.re_root_empty), + param_env, + ); + + let errors = + infcx.resolve_regions(region_context, &outlives_env, RegionckMode::default()); + if !errors.is_empty() { + return false; + } + + true }) .unwrap_or(false) } @@ -599,7 +626,7 @@ fn orphan_check_trait_ref<'tcx>( .substs .types() .flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)) - .find(|ty| ty_is_local_constructor(ty, in_crate)); + .find(|ty| ty_is_local_constructor(*ty, in_crate)); debug!("orphan_check_trait_ref: uncovered ty local_type: `{:?}`", local_type); diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 96a944017bc..1994faed70c 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -8,6 +8,7 @@ //! In this case we try to build an abstract representation of this constant using //! `thir_abstract_const` which can then be checked for structural equality with other //! generic constants mentioned in the `caller_bounds` of the current environment. +use rustc_data_structures::intern::Interned; use rustc_errors::ErrorReported; use rustc_hir::def::DefKind; use rustc_index::vec::IndexVec; @@ -201,9 +202,9 @@ impl<'tcx> AbstractConst<'tcx> { pub fn from_const( tcx: TyCtxt<'tcx>, - ct: &ty::Const<'tcx>, + ct: ty::Const<'tcx>, ) -> Result<Option<AbstractConst<'tcx>>, ErrorReported> { - match ct.val { + match ct.val() { ty::ConstKind::Unevaluated(uv) => AbstractConst::new(tcx, uv.shrink()), ty::ConstKind::Error(_) => Err(ErrorReported), _ => Ok(None), @@ -293,7 +294,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { } } - fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) { + fn visit_const(&mut self, ct: ty::Const<'tcx>) { self.is_poly |= ct.has_param_types_or_consts(); } } @@ -334,7 +335,11 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { self.recurse_build(self.body_id)?; for n in self.nodes.iter() { - if let Node::Leaf(ty::Const { val: ty::ConstKind::Unevaluated(ct), ty: _ }) = n { + if let Node::Leaf(ty::Const(Interned( + ty::ConstS { val: ty::ConstKind::Unevaluated(ct), ty: _ }, + _, + ))) = n + { // `AbstractConst`s should not contain any promoteds as they require references which // are not allowed. assert_eq!(ct.promoted, None); @@ -602,11 +607,11 @@ pub(super) fn try_unify<'tcx>( match (a.root(tcx), b.root(tcx)) { (Node::Leaf(a_ct), Node::Leaf(b_ct)) => { - if a_ct.ty != b_ct.ty { + if a_ct.ty() != b_ct.ty() { return false; } - match (a_ct.val, b_ct.val) { + match (a_ct.val(), b_ct.val()) { // We can just unify errors with everything to reduce the amount of // emitted errors here. (ty::ConstKind::Error(_), _) | (_, ty::ConstKind::Error(_)) => true, 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 f80fad19528..c3df17c83bb 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -21,10 +21,9 @@ use rustc_hir::Item; use rustc_hir::Node; use rustc_middle::thir::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::ExpectedFound; -use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences}; use rustc_middle::ty::fold::TypeFolder; use rustc_middle::ty::{ - self, AdtKind, SubtypePredicate, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, + self, SubtypePredicate, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, }; use rustc_session::DiagnosticMessageId; use rustc_span::symbol::{kw, sym}; @@ -40,6 +39,22 @@ use suggestions::InferCtxtExt as _; pub use rustc_infer::traits::error_reporting::*; +// When outputting impl candidates, prefer showing those that are more similar. +// +// We also compare candidates after skipping lifetimes, which has a lower +// priority than exact matches. +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub enum CandidateSimilarity { + Exact { ignoring_lifetimes: bool }, + Fuzzy { ignoring_lifetimes: bool }, +} + +#[derive(Debug, Clone, Copy)] +pub struct ImplCandidate<'tcx> { + pub trait_ref: ty::TraitRef<'tcx>, + pub similarity: CandidateSimilarity, +} + pub trait InferCtxtExt<'tcx> { fn report_fulfillment_errors( &self, @@ -1143,18 +1158,23 @@ trait InferCtxtPrivExt<'hir, 'tcx> { error: &MismatchedProjectionTypes<'tcx>, ); - fn fuzzy_match_tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool; + fn fuzzy_match_tys( + &self, + a: Ty<'tcx>, + b: Ty<'tcx>, + ignoring_lifetimes: bool, + ) -> Option<CandidateSimilarity>; fn describe_generator(&self, body_id: hir::BodyId) -> Option<&'static str>; fn find_similar_impl_candidates( &self, trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Vec<ty::TraitRef<'tcx>>; + ) -> Vec<ImplCandidate<'tcx>>; fn report_similar_impl_candidates( &self, - impl_candidates: Vec<ty::TraitRef<'tcx>>, + impl_candidates: Vec<ImplCandidate<'tcx>>, err: &mut DiagnosticBuilder<'_>, ); @@ -1231,7 +1251,7 @@ trait InferCtxtPrivExt<'hir, 'tcx> { fn is_recursive_obligation( &self, - obligated_types: &mut Vec<&ty::TyS<'tcx>>, + obligated_types: &mut Vec<Ty<'tcx>>, cause_code: &ObligationCauseCode<'tcx>, ) -> bool; } @@ -1417,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) }, ) }) @@ -1446,45 +1465,80 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { }); } - fn fuzzy_match_tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool { + fn fuzzy_match_tys( + &self, + mut a: Ty<'tcx>, + mut b: Ty<'tcx>, + ignoring_lifetimes: bool, + ) -> Option<CandidateSimilarity> { /// returns the fuzzy category of a given type, or None /// if the type can be equated to any type. - fn type_category(t: Ty<'_>) -> Option<u32> { + fn type_category(tcx: TyCtxt<'_>, t: Ty<'_>) -> Option<u32> { match t.kind() { ty::Bool => Some(0), ty::Char => Some(1), ty::Str => Some(2), - ty::Int(..) | ty::Uint(..) | ty::Infer(ty::IntVar(..)) => Some(3), - ty::Float(..) | ty::Infer(ty::FloatVar(..)) => Some(4), + ty::Adt(def, _) if tcx.is_diagnostic_item(sym::String, def.did) => Some(2), + ty::Int(..) + | ty::Uint(..) + | ty::Float(..) + | ty::Infer(ty::IntVar(..) | ty::FloatVar(..)) => Some(4), ty::Ref(..) | ty::RawPtr(..) => Some(5), ty::Array(..) | ty::Slice(..) => Some(6), ty::FnDef(..) | ty::FnPtr(..) => Some(7), ty::Dynamic(..) => Some(8), ty::Closure(..) => Some(9), ty::Tuple(..) => Some(10), - ty::Projection(..) => Some(11), - ty::Param(..) => Some(12), + ty::Param(..) => Some(11), + ty::Projection(..) => Some(12), ty::Opaque(..) => Some(13), ty::Never => Some(14), - ty::Adt(adt, ..) => match adt.adt_kind() { - AdtKind::Struct => Some(15), - AdtKind::Union => Some(16), - AdtKind::Enum => Some(17), - }, - ty::Generator(..) => Some(18), - ty::Foreign(..) => Some(19), - ty::GeneratorWitness(..) => Some(20), + ty::Adt(..) => Some(15), + ty::Generator(..) => Some(16), + ty::Foreign(..) => Some(17), + ty::GeneratorWitness(..) => Some(18), ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None, } } - match (type_category(a), type_category(b)) { - (Some(cat_a), Some(cat_b)) => match (a.kind(), b.kind()) { - (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => def_a == def_b, - _ => cat_a == cat_b, - }, - // infer and error can be equated to all types - _ => true, + let strip_references = |mut t: Ty<'tcx>| -> Ty<'tcx> { + loop { + match t.kind() { + ty::Ref(_, inner, _) | ty::RawPtr(ty::TypeAndMut { ty: inner, .. }) => { + t = *inner + } + _ => break t, + } + } + }; + + if !ignoring_lifetimes { + a = strip_references(a); + b = strip_references(b); + } + + let cat_a = type_category(self.tcx, a)?; + let cat_b = type_category(self.tcx, b)?; + if a == b { + Some(CandidateSimilarity::Exact { ignoring_lifetimes }) + } else if cat_a == cat_b { + match (a.kind(), b.kind()) { + (ty::Adt(def_a, _), ty::Adt(def_b, _)) => def_a == def_b, + // Matching on references results in a lot of unhelpful + // suggestions, so let's just not do that for now. + // + // We still upgrade successful matches to `ignoring_lifetimes: true` + // to prioritize that impl. + (ty::Ref(..) | ty::RawPtr(..), ty::Ref(..) | ty::RawPtr(..)) => { + self.fuzzy_match_tys(a, b, true).is_some() + } + _ => true, + } + .then_some(CandidateSimilarity::Fuzzy { ignoring_lifetimes }) + } else if ignoring_lifetimes { + None + } else { + self.fuzzy_match_tys(a, b, true) } } @@ -1500,58 +1554,25 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { fn find_similar_impl_candidates( &self, trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Vec<ty::TraitRef<'tcx>> { - // We simplify params and strip references here. - // - // This both removes a lot of unhelpful suggestions, e.g. - // when searching for `&Foo: Trait` it doesn't suggestion `impl Trait for &Bar`, - // while also suggesting impls for `&Foo` when we're looking for `Foo: Trait`. - // - // The second thing isn't necessarily always a good thing, but - // any other simple setup results in a far worse output, so 🤷 - let simp = fast_reject::simplify_type( - self.tcx, - trait_ref.skip_binder().self_ty(), - SimplifyParams::Yes, - StripReferences::Yes, - ); - let all_impls = self.tcx.all_impls(trait_ref.def_id()); - - match simp { - Some(simp) => all_impls - .filter_map(|def_id| { - let imp = self.tcx.impl_trait_ref(def_id).unwrap(); - let imp_simp = fast_reject::simplify_type( - self.tcx, - imp.self_ty(), - SimplifyParams::Yes, - StripReferences::Yes, - ); - if let Some(imp_simp) = imp_simp { - if simp != imp_simp { - return None; - } - } - if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative { - return None; - } - Some(imp) - }) - .collect(), - None => all_impls - .filter_map(|def_id| { - if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative { - return None; - } - self.tcx.impl_trait_ref(def_id) - }) - .collect(), - } + ) -> Vec<ImplCandidate<'tcx>> { + self.tcx + .all_impls(trait_ref.def_id()) + .filter_map(|def_id| { + if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative { + return None; + } + + let imp = self.tcx.impl_trait_ref(def_id).unwrap(); + + self.fuzzy_match_tys(trait_ref.skip_binder().self_ty(), imp.self_ty(), false) + .map(|similarity| ImplCandidate { trait_ref: imp, similarity }) + }) + .collect() } fn report_similar_impl_candidates( &self, - impl_candidates: Vec<ty::TraitRef<'tcx>>, + impl_candidates: Vec<ImplCandidate<'tcx>>, err: &mut DiagnosticBuilder<'_>, ) { if impl_candidates.is_empty() { @@ -1575,13 +1596,24 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { }; // Sort impl candidates so that ordering is consistent for UI tests. - let mut normalized_impl_candidates = - impl_candidates.iter().copied().map(normalize).collect::<Vec<String>>(); - - // Sort before taking the `..end` range, // because the ordering of `impl_candidates` may not be deterministic: // https://github.com/rust-lang/rust/pull/57475#issuecomment-455519507 - normalized_impl_candidates.sort(); + // + // Prefer more similar candidates first, then sort lexicographically + // by their normalized string representation. + let mut normalized_impl_candidates_and_similarities = impl_candidates + .into_iter() + .map(|ImplCandidate { trait_ref, similarity }| { + let normalized = normalize(trait_ref); + (similarity, normalized) + }) + .collect::<Vec<_>>(); + normalized_impl_candidates_and_similarities.sort(); + + let normalized_impl_candidates = normalized_impl_candidates_and_similarities + .into_iter() + .map(|(_, normalized)| normalized) + .collect::<Vec<_>>(); err.help(&format!( "the following implementations were found:{}{}", @@ -1744,7 +1776,11 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { return; } - let impl_candidates = self.find_similar_impl_candidates(trait_ref); + let impl_candidates = self + .find_similar_impl_candidates(trait_ref) + .into_iter() + .map(|candidate| candidate.trait_ref) + .collect(); let mut err = self.emit_inference_failure_err( body_id, span, @@ -2017,7 +2053,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { if let ty::Param(ty::ParamTy { name, .. }) = *ty.kind() { let infcx = self.infcx; - self.var_map.entry(ty).or_insert_with(|| { + *self.var_map.entry(ty).or_insert_with(|| { infcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeParameterDefinition(name, None), span: DUMMY_SP, @@ -2208,7 +2244,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { fn is_recursive_obligation( &self, - obligated_types: &mut Vec<&ty::TyS<'tcx>>, + obligated_types: &mut Vec<Ty<'tcx>>, cause_code: &ObligationCauseCode<'tcx>, ) -> bool { if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = cause_code { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 4e7a34d5951..6c8a08c09e7 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -56,7 +56,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { trait_ref.substs.types().skip(1), impl_trait_ref.substs.types().skip(1), ) - .all(|(u, v)| self.fuzzy_match_tys(u, v)) + .all(|(u, v)| self.fuzzy_match_tys(u, v, false).is_some()) { fuzzy_match_impls.push(def_id); } @@ -211,7 +211,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let type_string = self.tcx.type_of(def.did).to_string(); flags.push((sym::_Self, Some(format!("[{}]", type_string)))); - let len = len.val.try_to_value().and_then(|v| v.try_to_machine_usize(self.tcx)); + let len = + len.val().try_to_value().and_then(|v| v.try_to_machine_usize(self.tcx)); let string = match len { Some(n) => format!("[{}; {}]", type_string, n), None => format!("[{}; _]", type_string), 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 b594723aa0b..7df880a7cc0 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -167,7 +167,7 @@ pub trait InferCtxtExt<'tcx> { predicate: &T, param_env: ty::ParamEnv<'tcx>, cause_code: &ObligationCauseCode<'tcx>, - obligated_types: &mut Vec<&ty::TyS<'tcx>>, + obligated_types: &mut Vec<Ty<'tcx>>, seen_requirements: &mut FxHashSet<DefId>, ) where T: fmt::Display; @@ -839,7 +839,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let ty::Ref(_, inner_ty, _) = suggested_ty.kind() else { break; }; - suggested_ty = inner_ty; + suggested_ty = *inner_ty; let new_obligation = self.mk_trait_obligation_with_new_self_ty( obligation.param_env, @@ -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)); @@ -1597,7 +1593,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if let Some(cause) = typeck_results.generator_interior_types.as_ref().skip_binder().iter().find( |ty::GeneratorInteriorTypeCause { ty, .. }| { - ty_matches(typeck_results.generator_interior_types.rebind(ty)) + ty_matches(typeck_results.generator_interior_types.rebind(*ty)) }, ) { @@ -1904,7 +1900,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { predicate: &T, param_env: ty::ParamEnv<'tcx>, cause_code: &ObligationCauseCode<'tcx>, - obligated_types: &mut Vec<&ty::TyS<'tcx>>, + obligated_types: &mut Vec<Ty<'tcx>>, seen_requirements: &mut FxHashSet<DefId>, ) where T: fmt::Display, @@ -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/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index e7897887df7..1989184f48f 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -562,7 +562,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { // // Let's just see where this breaks :shrug: if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) = - (c1.val, c2.val) + (c1.val(), c2.val()) { if infcx.try_unify_abstract_consts(a.shrink(), b.shrink()) { return ProcessResult::Changed(vec![]); @@ -572,14 +572,14 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { let stalled_on = &mut pending_obligation.stalled_on; - let mut evaluate = |c: &'tcx Const<'tcx>| { - if let ty::ConstKind::Unevaluated(unevaluated) = c.val { + let mut evaluate = |c: Const<'tcx>| { + if let ty::ConstKind::Unevaluated(unevaluated) = c.val() { match self.selcx.infcx().const_eval_resolve( obligation.param_env, unevaluated, Some(obligation.cause.span), ) { - Ok(val) => Ok(Const::from_value(self.selcx.tcx(), val, c.ty)), + Ok(val) => Ok(Const::from_value(self.selcx.tcx(), val, c.ty())), Err(ErrorHandled::TooGeneric) => { stalled_on.extend( unevaluated diff --git a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs index bdf677a63b6..b05dbbe898a 100644 --- a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs @@ -309,23 +309,23 @@ impl<'tcx> OnUnimplementedFormatString { Piece::String(_) => (), // Normal string, no need to check it Piece::NextArgument(a) => match a.position { // `{Self}` is allowed - Position::ArgumentNamed(s) if s == kw::SelfUpper => (), + Position::ArgumentNamed(s, _) if s == kw::SelfUpper => (), // `{ThisTraitsName}` is allowed - Position::ArgumentNamed(s) if s == name => (), + Position::ArgumentNamed(s, _) if s == name => (), // `{from_method}` is allowed - Position::ArgumentNamed(s) if s == sym::from_method => (), + Position::ArgumentNamed(s, _) if s == sym::from_method => (), // `{from_desugaring}` is allowed - Position::ArgumentNamed(s) if s == sym::from_desugaring => (), + Position::ArgumentNamed(s, _) if s == sym::from_desugaring => (), // `{ItemContext}` is allowed - Position::ArgumentNamed(s) if s == sym::ItemContext => (), + Position::ArgumentNamed(s, _) if s == sym::ItemContext => (), // `{integral}` and `{integer}` and `{float}` are allowed - Position::ArgumentNamed(s) + Position::ArgumentNamed(s, _) if s == sym::integral || s == sym::integer_ || s == sym::float => { () } // So is `{A}` if A is a type parameter - Position::ArgumentNamed(s) => { + Position::ArgumentNamed(s, _) => { match generics.params.iter().find(|param| param.name == s) { Some(_) => (), None => { @@ -392,7 +392,7 @@ impl<'tcx> OnUnimplementedFormatString { .map(|p| match p { Piece::String(s) => s, Piece::NextArgument(a) => match a.position { - Position::ArgumentNamed(s) => match generic_map.get(&s) { + Position::ArgumentNamed(s, _) => match generic_map.get(&s) { Some(val) => val, None if s == name => &trait_str, None => { diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 36cc14610cb..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; @@ -499,7 +500,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { } } - fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { + fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> { if self.selcx.tcx().lazy_normalization() { constant } else { @@ -622,24 +623,24 @@ impl<'tcx> TypeFolder<'tcx> for BoundVarReplacer<'_, 'tcx> { } } - fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - match *ct { - ty::Const { val: ty::ConstKind::Bound(debruijn, _), ty: _ } + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + match ct.val() { + ty::ConstKind::Bound(debruijn, _) if debruijn.as_usize() + 1 > self.current_index.as_usize() + self.universe_indices.len() => { bug!("Bound vars outside of `self.universe_indices`"); } - ty::Const { val: ty::ConstKind::Bound(debruijn, bound_const), ty } - if debruijn >= self.current_index => - { + ty::ConstKind::Bound(debruijn, bound_const) if debruijn >= self.current_index => { let universe = self.universe_for(debruijn); let p = ty::PlaceholderConst { universe, - name: ty::BoundConst { var: bound_const, ty }, + name: ty::BoundConst { var: bound_const, ty: ct.ty() }, }; self.mapped_consts.insert(p, bound_const); - self.infcx.tcx.mk_const(ty::Const { val: ty::ConstKind::Placeholder(p), ty }) + self.infcx + .tcx + .mk_const(ty::ConstS { val: ty::ConstKind::Placeholder(p), ty: ct.ty() }) } _ if ct.has_vars_bound_at_or_above(self.current_index) => ct.super_fold_with(self), _ => ct, @@ -697,7 +698,7 @@ impl<'tcx> TypeFolder<'tcx> for PlaceholderReplacer<'_, 'tcx> { } fn fold_region(&mut self, r0: ty::Region<'tcx>) -> ty::Region<'tcx> { - let r1 = match r0 { + let r1 = match *r0 { ty::ReVar(_) => self .infcx .inner @@ -758,8 +759,8 @@ impl<'tcx> TypeFolder<'tcx> for PlaceholderReplacer<'_, 'tcx> { } } - fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - if let ty::Const { val: ty::ConstKind::Placeholder(p), ty } = *ct { + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + if let ty::ConstKind::Placeholder(p) = ct.val() { let replace_var = self.mapped_consts.get(&p); match replace_var { Some(replace_var) => { @@ -771,8 +772,10 @@ impl<'tcx> TypeFolder<'tcx> for PlaceholderReplacer<'_, 'tcx> { let db = ty::DebruijnIndex::from_usize( self.universe_indices.len() - index + self.current_index.as_usize() - 1, ); - self.tcx() - .mk_const(ty::Const { val: ty::ConstKind::Bound(db, *replace_var), ty }) + self.tcx().mk_const(ty::ConstS { + val: ty::ConstKind::Bound(db, *replace_var), + ty: ct.ty(), + }) } None => ct, } @@ -957,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![] }; @@ -1073,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 @@ -1180,7 +1173,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( ProjectionCandidate::TraitDef, bounds.iter(), true, - ) + ); } /// In the case of a trait object like @@ -1245,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 => {} } } } @@ -1862,7 +1862,7 @@ fn confirm_impl_candidate<'cx, 'tcx>( crate::traits::InternalSubsts::identity_for_item(tcx, assoc_ty.item.def_id); let did = ty::WithOptConstParam::unknown(assoc_ty.item.def_id); let val = ty::ConstKind::Unevaluated(ty::Unevaluated::new(did, identity_substs)); - tcx.mk_const(ty::Const { ty, val }).into() + tcx.mk_const(ty::ConstS { ty, val }).into() } else { ty.into() }; diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index f05582f0614..55903a3c36a 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -104,7 +104,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { | ty::Error(_) => true, // [T; N] and [T] have same properties as T. - ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, ty), + ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, *ty), // (T1..Tn) and closures have same properties as T1..Tn -- // check if *any* of those are trivial. diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 3c9e1bbcef2..6a2bd9ce1ea 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -140,8 +140,8 @@ impl<'tcx> TypeVisitor<'tcx> for MaxEscapingBoundVarVisitor { ControlFlow::CONTINUE } - fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { - match ct.val { + fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { + match ct.val() { ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => { self.escaping = self.escaping.max(debruijn.as_usize() - self.outer_index.as_usize()); @@ -188,7 +188,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { } if let Some(ty) = self.cache.get(&ty) { - return Ok(ty); + return Ok(*ty); } // See note in `rustc_trait_selection::traits::project` about why we @@ -324,8 +324,8 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { fn try_fold_const( &mut self, - constant: &'tcx ty::Const<'tcx>, - ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> { + constant: ty::Const<'tcx>, + ) -> Result<ty::Const<'tcx>, Self::Error> { let constant = constant.try_super_fold_with(self)?; Ok(constant.eval(self.infcx.tcx, self.param_env)) } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 639884844b2..84bc7cdff28 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -983,7 +983,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Lifetimes aren't allowed to change during unsizing. GenericArgKind::Lifetime(_) => None, - GenericArgKind::Const(ct) => match ct.val { + GenericArgKind::Const(ct) => match ct.val() { ty::ConstKind::Param(p) => Some(p.index), _ => None, }, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 47427395b93..3b69700530b 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -36,7 +36,7 @@ use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_middle::dep_graph::{DepKind, DepNodeIndex}; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::thir::abstract_const::NotConstEvaluatable; -use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences}; +use rustc_middle::ty::fast_reject::{self, SimplifyParams}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef}; @@ -643,7 +643,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // // Let's just see where this breaks :shrug: if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) = - (c1.val, c2.val) + (c1.val(), c2.val()) { if self.infcx.try_unify_abstract_consts(a.shrink(), b.shrink()) { return Ok(EvaluatedToOk); @@ -651,15 +651,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - let evaluate = |c: &'tcx ty::Const<'tcx>| { - if let ty::ConstKind::Unevaluated(unevaluated) = c.val { + let evaluate = |c: ty::Const<'tcx>| { + if let ty::ConstKind::Unevaluated(unevaluated) = c.val() { self.infcx .const_eval_resolve( obligation.param_env, unevaluated, Some(obligation.cause.span), ) - .map(|val| ty::Const::from_value(self.tcx(), val, c.ty)) + .map(|val| ty::Const::from_value(self.tcx(), val, c.ty())) } else { Ok(c) } @@ -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 + } } /////////////////////////////////////////////////////////////////////////// @@ -2033,7 +2059,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .skip_binder() // binder moved -\ .iter() .flat_map(|ty| { - let ty: ty::Binder<'tcx, Ty<'tcx>> = types.rebind(ty); // <----/ + let ty: ty::Binder<'tcx, Ty<'tcx>> = types.rebind(*ty); // <----/ self.infcx.commit_unconditionally(|_| { let placeholder_ty = self.infcx.replace_bound_vars_with_placeholders(ty); @@ -2172,14 +2198,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.tcx(), obligation_ty, SimplifyParams::Yes, - StripReferences::No, - ); - let simplified_impl_ty = fast_reject::simplify_type( - self.tcx(), - impl_ty, - SimplifyParams::No, - StripReferences::No, ); + let simplified_impl_ty = + fast_reject::simplify_type(self.tcx(), impl_ty, SimplifyParams::No); simplified_obligation_ty.is_some() && simplified_impl_ty.is_some() @@ -2714,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_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index b098e8590da..38a6220082f 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -510,7 +510,7 @@ crate fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<St for (mut p, _) in predicates { if let Some(poly_trait_ref) = p.to_opt_poly_trait_pred() { if Some(poly_trait_ref.def_id()) == sized_trait { - types_without_default_bounds.remove(poly_trait_ref.self_ty().skip_binder()); + types_without_default_bounds.remove(&poly_trait_ref.self_ty().skip_binder()); continue; } diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs index 5ee8b45e66b..497ac207bbe 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs @@ -2,7 +2,7 @@ use super::OverlapError; use crate::traits; use rustc_hir::def_id::DefId; -use rustc_middle::ty::fast_reject::{self, SimplifiedType, SimplifyParams, StripReferences}; +use rustc_middle::ty::fast_reject::{self, SimplifiedType, SimplifyParams}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; @@ -49,12 +49,7 @@ impl ChildrenExt<'_> for Children { /// Insert an impl into this set of children without comparing to any existing impls. fn insert_blindly(&mut self, tcx: TyCtxt<'_>, impl_def_id: DefId) { let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); - if let Some(st) = fast_reject::simplify_type( - tcx, - trait_ref.self_ty(), - SimplifyParams::No, - StripReferences::No, - ) { + if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), SimplifyParams::No) { debug!("insert_blindly: impl_def_id={:?} st={:?}", impl_def_id, st); self.non_blanket_impls.entry(st).or_default().push(impl_def_id) } else { @@ -69,12 +64,7 @@ impl ChildrenExt<'_> for Children { fn remove_existing(&mut self, tcx: TyCtxt<'_>, impl_def_id: DefId) { let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); let vec: &mut Vec<DefId>; - if let Some(st) = fast_reject::simplify_type( - tcx, - trait_ref.self_ty(), - SimplifyParams::No, - StripReferences::No, - ) { + if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), SimplifyParams::No) { debug!("remove_existing: impl_def_id={:?} st={:?}", impl_def_id, st); vec = self.non_blanket_impls.get_mut(&st).unwrap(); } else { @@ -322,12 +312,7 @@ impl GraphExt for Graph { let mut parent = trait_def_id; let mut last_lint = None; - let simplified = fast_reject::simplify_type( - tcx, - trait_ref.self_ty(), - SimplifyParams::No, - StripReferences::No, - ); + let simplified = fast_reject::simplify_type(tcx, trait_ref.self_ty(), SimplifyParams::No); // Descend the specialization tree, where `parent` is the current parent node. loop { diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 493cb199f11..2dd3b77a73c 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -41,7 +41,7 @@ pub fn obligations<'a, 'tcx>( .into() } GenericArgKind::Const(ct) => { - match ct.val { + match ct.val() { ty::ConstKind::Infer(infer) => { let resolved = infcx.shallow_resolve(infer); if resolved == infer { @@ -49,7 +49,9 @@ pub fn obligations<'a, 'tcx>( return None; } - infcx.tcx.mk_const(ty::Const { val: ty::ConstKind::Infer(resolved), ty: ct.ty }) + infcx + .tcx + .mk_const(ty::ConstS { val: ty::ConstKind::Infer(resolved), ty: ct.ty() }) } _ => ct, } @@ -198,7 +200,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>( trait_ref: &ty::TraitRef<'tcx>, item: Option<&hir::Item<'tcx>>, cause: &mut traits::ObligationCause<'tcx>, - pred: &ty::Predicate<'tcx>, + pred: ty::Predicate<'tcx>, ) { debug!( "extended_cause_with_original_assoc_item_obligation {:?} {:?} {:?} {:?}", @@ -319,7 +321,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { trait_ref, item, &mut cause, - &obligation.predicate, + obligation.predicate, ); traits::Obligation::with_depth(cause, depth, param_env, obligation.predicate) }; @@ -442,7 +444,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { GenericArgKind::Lifetime(_) => continue, GenericArgKind::Const(constant) => { - match constant.val { + match constant.val() { ty::ConstKind::Unevaluated(uv) => { let obligations = self.nominal_obligations(uv.def.did, uv.substs); self.out.extend(obligations); @@ -464,9 +466,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { if resolved != infer { let cause = self.cause(traits::MiscObligation); - let resolved_constant = self.infcx.tcx.mk_const(ty::Const { + let resolved_constant = self.infcx.tcx.mk_const(ty::ConstS { val: ty::ConstKind::Infer(resolved), - ..*constant + ty: constant.ty(), }); self.out.push(traits::Obligation::with_depth( cause, diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index 0170ab223b0..51b66e1bb65 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -711,11 +711,11 @@ fn bound_vars_for_item<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx var: ty::BoundVar::from_usize(substs.len()), kind: ty::BrAnon(substs.len() as u32), }; - tcx.mk_region(ty::RegionKind::ReLateBound(ty::INNERMOST, br)).into() + tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into() } ty::GenericParamDefKind::Const { .. } => tcx - .mk_const(ty::Const { + .mk_const(ty::ConstS { val: ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from(param.index)), ty: tcx.type_of(param.def_id), }) @@ -735,7 +735,7 @@ fn binders_for<'tcx>( chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General) } ty::subst::GenericArgKind::Const(c) => { - chalk_ir::VariableKind::Const(c.ty.lower_into(interner)) + chalk_ir::VariableKind::Const(c.ty().lower_into(interner)) } }), ) diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 6f143c1c607..9d810d0881b 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -35,7 +35,7 @@ use rustc_ast::ast; use rustc_middle::traits::{ChalkEnvironmentAndGoal, ChalkRustInterner as RustInterner}; use rustc_middle::ty::fold::TypeFolder; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; -use rustc_middle::ty::{self, Binder, Region, RegionKind, Ty, TyCtxt, TypeFoldable, TypeVisitor}; +use rustc_middle::ty::{self, Binder, Region, Ty, TyCtxt, TypeFoldable, TypeVisitor}; use rustc_span::def_id::DefId; use chalk_ir::{FnSig, ForeignDefId}; @@ -389,7 +389,7 @@ impl<'tcx> LowerInto<'tcx, Ty<'tcx>> for &chalk_ir::Ty<RustInterner<'tcx>> { TyKind::Array(ty, c) => { let ty = ty.lower_into(interner); let c = c.lower_into(interner); - ty::Array(ty, interner.tcx.mk_const(c)) + ty::Array(ty, c) } TyKind::FnDef(id, substitution) => ty::FnDef(id.0, substitution.lower_into(interner)), TyKind::Closure(closure, substitution) => { @@ -449,32 +449,30 @@ impl<'tcx> LowerInto<'tcx, Ty<'tcx>> for &chalk_ir::Ty<RustInterner<'tcx>> { impl<'tcx> LowerInto<'tcx, chalk_ir::Lifetime<RustInterner<'tcx>>> for Region<'tcx> { fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::Lifetime<RustInterner<'tcx>> { - use rustc_middle::ty::RegionKind::*; - - match self { - ReEarlyBound(_) => { + match *self { + ty::ReEarlyBound(_) => { panic!("Should have already been substituted."); } - ReLateBound(db, br) => chalk_ir::LifetimeData::BoundVar(chalk_ir::BoundVar::new( + ty::ReLateBound(db, br) => chalk_ir::LifetimeData::BoundVar(chalk_ir::BoundVar::new( chalk_ir::DebruijnIndex::new(db.as_u32()), br.var.as_usize(), )) .intern(interner), - ReFree(_) => unimplemented!(), - ReStatic => chalk_ir::LifetimeData::Static.intern(interner), - ReVar(_) => unimplemented!(), - RePlaceholder(placeholder_region) => { + ty::ReFree(_) => unimplemented!(), + ty::ReStatic => chalk_ir::LifetimeData::Static.intern(interner), + ty::ReVar(_) => unimplemented!(), + ty::RePlaceholder(placeholder_region) => { chalk_ir::LifetimeData::Placeholder(chalk_ir::PlaceholderIndex { ui: chalk_ir::UniverseIndex { counter: placeholder_region.universe.index() }, idx: 0, }) .intern(interner) } - ReEmpty(ui) => { + ty::ReEmpty(ui) => { chalk_ir::LifetimeData::Empty(chalk_ir::UniverseIndex { counter: ui.index() }) .intern(interner) } - ReErased => chalk_ir::LifetimeData::Erased.intern(interner), + ty::ReErased => chalk_ir::LifetimeData::Erased.intern(interner), } } } @@ -482,7 +480,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Lifetime<RustInterner<'tcx>>> for Region<'t impl<'tcx> LowerInto<'tcx, Region<'tcx>> for &chalk_ir::Lifetime<RustInterner<'tcx>> { fn lower_into(self, interner: RustInterner<'tcx>) -> Region<'tcx> { let kind = match self.data(interner) { - chalk_ir::LifetimeData::BoundVar(var) => ty::RegionKind::ReLateBound( + chalk_ir::LifetimeData::BoundVar(var) => ty::ReLateBound( ty::DebruijnIndex::from_u32(var.debruijn.depth()), ty::BoundRegion { var: ty::BoundVar::from_usize(var.index), @@ -490,12 +488,10 @@ impl<'tcx> LowerInto<'tcx, Region<'tcx>> for &chalk_ir::Lifetime<RustInterner<'t }, ), chalk_ir::LifetimeData::InferenceVar(_var) => unimplemented!(), - chalk_ir::LifetimeData::Placeholder(p) => { - ty::RegionKind::RePlaceholder(ty::Placeholder { - universe: ty::UniverseIndex::from_usize(p.ui.counter), - name: ty::BoundRegionKind::BrAnon(p.idx as u32), - }) - } + chalk_ir::LifetimeData::Placeholder(p) => ty::RePlaceholder(ty::Placeholder { + universe: ty::UniverseIndex::from_usize(p.ui.counter), + name: ty::BoundRegionKind::BrAnon(p.idx as u32), + }), chalk_ir::LifetimeData::Static => return interner.tcx.lifetimes.re_static, chalk_ir::LifetimeData::Empty(ui) => { ty::ReEmpty(ty::UniverseIndex::from_usize(ui.counter)) @@ -509,8 +505,8 @@ impl<'tcx> LowerInto<'tcx, Region<'tcx>> for &chalk_ir::Lifetime<RustInterner<'t impl<'tcx> LowerInto<'tcx, chalk_ir::Const<RustInterner<'tcx>>> for ty::Const<'tcx> { fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::Const<RustInterner<'tcx>> { - let ty = self.ty.lower_into(interner); - let value = match self.val { + let ty = self.ty().lower_into(interner); + let value = match self.val() { ty::ConstKind::Value(val) => { chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { interned: val }) } @@ -536,7 +532,7 @@ impl<'tcx> LowerInto<'tcx, ty::Const<'tcx>> for &chalk_ir::Const<RustInterner<'t chalk_ir::ConstValue::Placeholder(_p) => unimplemented!(), chalk_ir::ConstValue::Concrete(c) => ty::ConstKind::Value(c.interned), }; - ty::Const { ty, val } + interner.tcx.mk_const(ty::ConstS { ty, val }) } } @@ -572,7 +568,7 @@ impl<'tcx> LowerInto<'tcx, ty::subst::GenericArg<'tcx>> } chalk_ir::GenericArgData::Const(c) => { let c: ty::Const<'tcx> = c.lower_into(interner); - interner.tcx.mk_const(c).into() + c.into() } } } @@ -915,8 +911,8 @@ impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { } fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<Self::BreakTy> { - match r { - ty::ReLateBound(index, br) if *index == self.binder_index => match br.kind { + match *r { + ty::ReLateBound(index, br) if index == self.binder_index => match br.kind { ty::BoundRegionKind::BrNamed(def_id, _name) => { if !self.named_parameters.iter().any(|d| *d == def_id) { self.named_parameters.push(def_id); @@ -977,12 +973,12 @@ impl<'a, 'tcx> TypeFolder<'tcx> for NamedBoundVarSubstitutor<'a, 'tcx> { } fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> { - match r { - ty::ReLateBound(index, br) if *index == self.binder_index => match br.kind { + match *r { + ty::ReLateBound(index, br) if index == self.binder_index => match br.kind { ty::BrNamed(def_id, _name) => match self.named_parameters.get(&def_id) { Some(idx) => { let new_br = ty::BoundRegion { var: br.var, kind: ty::BrAnon(*idx) }; - return self.tcx.mk_region(RegionKind::ReLateBound(*index, new_br)); + return self.tcx.mk_region(ty::ReLateBound(index, new_br)); } None => panic!("Missing `BrNamed`."), }, @@ -1054,7 +1050,7 @@ impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> { } fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> { - match r { + match *r { // FIXME(chalk) - jackh726 - this currently isn't hit in any tests, // since canonicalization will already change these to canonical // variables (ty::ReLateBound). @@ -1064,14 +1060,14 @@ impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> { var: ty::BoundVar::from_u32(*idx), kind: ty::BrAnon(*idx), }; - self.tcx.mk_region(RegionKind::ReLateBound(self.binder_index, br)) + self.tcx.mk_region(ty::ReLateBound(self.binder_index, br)) } None => { let idx = self.named_regions.len() as u32; let br = ty::BoundRegion { var: ty::BoundVar::from_u32(idx), kind: ty::BrAnon(idx) }; self.named_regions.insert(_re.def_id, idx); - self.tcx.mk_region(RegionKind::ReLateBound(self.binder_index, br)) + self.tcx.mk_region(ty::ReLateBound(self.binder_index, br)) } }, @@ -1144,7 +1140,7 @@ impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector { } fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<Self::BreakTy> { - match r { + match *r { ty::RePlaceholder(p) if p.universe == self.universe_index => { if let ty::BoundRegionKind::BrAnon(anon) = p.name { self.next_anon_region_placeholder = self.next_anon_region_placeholder.max(anon); diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs index 087c216af14..455fc46a42e 100644 --- a/compiler/rustc_traits/src/dropck_outlives.rs +++ b/compiler/rustc_traits/src/dropck_outlives.rs @@ -192,7 +192,7 @@ fn dtorck_constraint_for_ty<'tcx>( ty::Array(ety, _) | ty::Slice(ety) => { // single-element containers, behave like their element rustc_data_structures::stack::ensure_sufficient_stack(|| { - dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ety, constraints) + dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, *ety, constraints) })?; } diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index 46c2f7e4cf2..a4aa965ec95 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -39,7 +39,7 @@ fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<'tcx> + PartialEq + // always only region relations, and we are about to // erase those anyway: debug_assert_eq!( - normalized_obligations.iter().find(|p| not_outlives_predicate(&p.predicate)), + normalized_obligations.iter().find(|p| not_outlives_predicate(p.predicate)), None, ); @@ -57,7 +57,7 @@ fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<'tcx> + PartialEq + }) } -fn not_outlives_predicate<'tcx>(p: &ty::Predicate<'tcx>) -> bool { +fn not_outlives_predicate<'tcx>(p: ty::Predicate<'tcx>) -> bool { match p.kind().skip_binder() { ty::PredicateKind::RegionOutlives(..) | ty::PredicateKind::TypeOutlives(..) => false, ty::PredicateKind::Trait(..) diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index e7cc0f69e9f..91c4398c178 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -90,8 +90,8 @@ impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { } fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { - match r { - ty::ReLateBound(index, br) if *index == self.binder_index => { + match *r { + ty::ReLateBound(index, br) if index == self.binder_index => { match self.vars.entry(br.var.as_u32()) { Entry::Vacant(entry) => { entry.insert(ty::BoundVariableKind::Region(br.kind)); diff --git a/compiler/rustc_ty_utils/src/representability.rs b/compiler/rustc_ty_utils/src/representability.rs index 1717959acc1..b08f8f62308 100644 --- a/compiler/rustc_ty_utils/src/representability.rs +++ b/compiler/rustc_ty_utils/src/representability.rs @@ -92,7 +92,7 @@ fn are_inner_types_recursive<'tcx>( seen, shadow_seen, representable_cache, - ty, + *ty, force_result, ), ty::Adt(def, substs) => { @@ -255,7 +255,7 @@ fn is_type_structurally_recursive<'tcx>( force_result: &mut bool, ) -> Representability { debug!("is_type_structurally_recursive: {:?} {:?}", ty, sp); - if let Some(representability) = representable_cache.get(ty) { + if let Some(representability) = representable_cache.get(&ty) { debug!( "is_type_structurally_recursive: {:?} {:?} - (cached) {:?}", ty, sp, representability diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index b882a940d40..e44f80d5ac3 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -410,7 +410,7 @@ fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Ty<'_>> { let self_ty = trait_ref.self_ty(); let self_ty_matches = match self_ty.kind() { - ty::Dynamic(ref data, ty::ReStatic) => data.principal().is_none(), + ty::Dynamic(ref data, re) if re.is_static() => data.principal().is_none(), _ => false, }; @@ -474,7 +474,7 @@ pub fn conservative_is_privately_uninhabited_raw<'tcx>( Some(0) | None => false, // If the array is definitely non-empty, it's uninhabited if // the type of its elements is uninhabited. - Some(1..) => tcx.conservative_is_privately_uninhabited(param_env.and(ty)), + Some(1..) => tcx.conservative_is_privately_uninhabited(param_env.and(*ty)), } } ty::Ref(..) => { diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index ec6fb622d32..e26f0033156 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -400,9 +400,11 @@ pub enum InferTy { /// they carry no values. impl UnifyKey for TyVid { type Value = (); + #[inline] fn index(&self) -> u32 { self.as_u32() } + #[inline] fn from_index(i: u32) -> TyVid { TyVid::from_u32(i) } @@ -419,6 +421,7 @@ impl UnifyKey for IntVid { fn index(&self) -> u32 { self.index } + #[inline] fn from_index(i: u32) -> IntVid { IntVid { index: i } } @@ -431,9 +434,11 @@ impl EqUnifyValue for FloatVarValue {} impl UnifyKey for FloatVid { type Value = Option<FloatVarValue>; + #[inline] fn index(&self) -> u32 { self.index } + #[inline] fn from_index(i: u32) -> FloatVid { FloatVid { index: i } } 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 366d20dbbc2..96f92049983 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -83,7 +83,7 @@ pub trait AstConv<'tcx> { ty: Ty<'tcx>, param: Option<&ty::GenericParamDef>, span: Span, - ) -> &'tcx Const<'tcx>; + ) -> Const<'tcx>; /// Projecting an associated type from a (potentially) /// higher-ranked trait reference is more complicated, because of @@ -1428,7 +1428,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // `trait_object_dummy_self`, so check for that. let references_self = match pred.skip_binder().term { ty::Term::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()), - ty::Term::Const(c) => c.ty.walk().any(|arg| arg == dummy_self.into()), + ty::Term::Const(c) => c.ty().walk().any(|arg| arg == dummy_self.into()), }; // If the projection output contains `Self`, force the user to @@ -1805,7 +1805,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Find the type of the associated item, and the trait where the associated // item is declared. let bound = match (&qself_ty.kind(), qself_res) { - (_, Res::SelfTy(Some(_), Some((impl_def_id, _)))) => { + (_, Res::SelfTy { trait_: Some(_), alias_to: Some((impl_def_id, _)) }) => { // `Self` in an impl of a trait -- we have a concrete self type and a // trait reference. let trait_ref = match tcx.impl_trait_ref(impl_def_id) { @@ -1826,7 +1826,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } ( &ty::Param(_), - Res::SelfTy(Some(param_did), None) | Res::Def(DefKind::TyParam, param_did), + Res::SelfTy { trait_: Some(param_did), alias_to: None } + | Res::Def(DefKind::TyParam, param_did), ) => self.find_bound_for_assoc_item(param_did.expect_local(), assoc_ident, span)?, _ => { if variant_resolution.is_some() { @@ -2270,13 +2271,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let index = generics.param_def_id_to_index[&def_id]; tcx.mk_ty_param(index, tcx.hir().name(hir_id)) } - Res::SelfTy(Some(_), None) => { + Res::SelfTy { trait_: Some(_), alias_to: None } => { // `Self` in trait or type alias. assert_eq!(opt_self_ty, None); self.prohibit_generics(path.segments); tcx.types.self_param } - Res::SelfTy(_, Some((def_id, forbid_generic))) => { + Res::SelfTy { trait_: _, alias_to: Some((def_id, forbid_generic)) } => { // `Self` in impl (we know the concrete type). assert_eq!(opt_self_ty, None); self.prohibit_generics(path.segments); @@ -2408,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), } } @@ -2668,7 +2674,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // If any of the derived region bounds are 'static, that is always // the best choice. - if derived_region_bounds.iter().any(|&r| ty::ReStatic == *r) { + if derived_region_bounds.iter().any(|r| r.is_static()) { return Some(tcx.lifetimes.re_static); } diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs index 405e4e8594a..3701b255b75 100644 --- a/compiler/rustc_typeck/src/check/_match.rs +++ b/compiler/rustc_typeck/src/check/_match.rs @@ -4,7 +4,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir::{self as hir, ExprKind}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::traits::Obligation; -use rustc_middle::ty::{self, ToPredicate, Ty, TyS}; +use rustc_middle::ty::{self, ToPredicate, Ty}; use rustc_span::{MultiSpan, Span}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::{ @@ -505,7 +505,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn opt_suggest_box_span( &self, span: Span, - outer_ty: &'tcx TyS<'tcx>, + outer_ty: Ty<'tcx>, orig_expected: Expectation<'tcx>, ) -> Option<Span> { match (orig_expected, self.ret_coercion_impl_trait.map(|ty| (self.body_id.owner, ty))) { diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs index 0fea0afb572..f64a90ed10e 100644 --- a/compiler/rustc_typeck/src/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -269,7 +269,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, }; autoref = Some(Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)), + kind: Adjust::Borrow(AutoBorrow::Ref(*region, mutbl)), target: method.sig.inputs()[0], }); } @@ -628,7 +628,7 @@ impl<'a, 'tcx> DeferredCallResolution<'tcx> { for (method_arg_ty, self_arg_ty) in iter::zip(method_sig.inputs().iter().skip(1), self.fn_sig.inputs()) { - fcx.demand_eqtype(self.call_expr.span, &self_arg_ty, &method_arg_ty); + fcx.demand_eqtype(self.call_expr.span, *self_arg_ty, *method_arg_ty); } fcx.demand_eqtype(self.call_expr.span, method_sig.output(), self.fn_sig.output()); diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index be0b7733579..56b6c090690 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -369,7 +369,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { .try_coerce( self.expr, fcx.tcx.mk_ref( - &ty::RegionKind::ReErased, + fcx.tcx.lifetimes.re_erased, TypeAndMut { ty: expr_ty, mutbl }, ), self.cast_ty, @@ -419,7 +419,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { .try_coerce( self.expr, fcx.tcx.mk_ref( - &ty::RegionKind::ReErased, + fcx.tcx.lifetimes.re_erased, TypeAndMut { ty: self.expr_ty, mutbl }, ), self.cast_ty, @@ -885,7 +885,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { }); // this will report a type mismatch if needed - fcx.demand_eqtype(self.span, ety, m_cast.ty); + fcx.demand_eqtype(self.span, *ety, m_cast.ty); return Ok(CastKind::ArrayPtrCast); } } diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 536a848e5bb..1650a62f79f 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -17,7 +17,7 @@ use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::layout::MAX_SIMD_LANES; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::util::{Discr, IntTypeExt}; -use rustc_middle::ty::{self, OpaqueTypeKey, ParamEnv, RegionKind, Ty, TyCtxt}; +use rustc_middle::ty::{self, OpaqueTypeKey, ParamEnv, Ty, TyCtxt}; use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS}; use rustc_span::symbol::sym; use rustc_span::{self, MultiSpan, Span}; @@ -269,7 +269,7 @@ pub(super) fn check_fn<'a, 'tcx>( ty::Adt(ref adt, _) => { adt.did == panic_info_did && mutbl == hir::Mutability::Not - && *region != RegionKind::ReStatic + && !region.is_static() } _ => false, }, @@ -382,12 +382,17 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b tcx.sess, field_span, E0740, - "unions may not contain fields that need dropping" + "unions cannot contain fields that may need dropping" + ) + .note( + "a type is guaranteed not to need dropping \ + when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type", ) .multipart_suggestion_verbose( - "wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped", + "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, @@ -469,8 +474,8 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>( fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { debug!("FindParentLifetimeVisitor: r={:?}", r); - if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r { - if *index < self.0.parent_count as u32 { + if let ty::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = *r { + if index < self.0.parent_count as u32 { return ControlFlow::Break(FoundParentLifetime); } else { return ControlFlow::CONTINUE; @@ -480,8 +485,8 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>( r.super_visit_with(self) } - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { - if let ty::ConstKind::Unevaluated(..) = c.val { + fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { + if let ty::ConstKind::Unevaluated(..) = c.val() { // FIXME(#72219) We currently don't detect lifetimes within substs // which would violate this check. Even though the particular substitution is not used // within the const, this should still be fixed. @@ -522,7 +527,12 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>( fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) { match arg.kind { hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments { - [PathSegment { res: Some(Res::SelfTy(_, impl_ref)), .. }] => { + [ + PathSegment { + res: Some(Res::SelfTy { trait_: _, alias_to: impl_ref }), + .. + }, + ] => { let impl_ty_name = impl_ref.map(|(def_id, _)| self.tcx.def_path_str(def_id)); self.selftys.push((path.span, impl_ty_name)); @@ -535,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( @@ -558,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/closure.rs b/compiler/rustc_typeck/src/check/closure.rs index e88099afa03..3c626837ef1 100644 --- a/compiler/rustc_typeck/src/check/closure.rs +++ b/compiler/rustc_typeck/src/check/closure.rs @@ -450,7 +450,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .skip_binder() .inputs() .iter() - .map(|ty| ArgKind::from_expected_ty(ty, None)) + .map(|ty| ArgKind::from_expected_ty(*ty, None)) .collect(); let (closure_span, found_args) = match self.get_fn_like_arguments(expr_map_node) { Some((sp, args)) => (Some(sp), args), diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index 3668ecd234c..be7ac006926 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -142,7 +142,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { where F: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>, { - self.unify(&a, &b) + self.unify(a, b) .and_then(|InferOk { value: ty, obligations }| success(f(ty), ty, obligations)) } @@ -472,7 +472,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } }; adjustments.push(Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(r_borrow, mutbl)), + kind: Adjust::Borrow(AutoBorrow::Ref(*r_borrow, mutbl)), target: ty, }); diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index 5bb528458c5..38449c2a76a 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -1306,7 +1306,7 @@ pub fn check_type_bounds<'tcx>( GenericParamDefKind::Const { .. } => { let bound_var = ty::BoundVariableKind::Const; bound_vars.push(bound_var); - tcx.mk_const(ty::Const { + tcx.mk_const(ty::ConstS { ty: tcx.type_of(param.def_id), val: ty::ConstKind::Bound( ty::INNERMOST, @@ -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 2409346298d..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 { @@ -734,7 +734,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, ref expr), _, &ty::Ref(_, checked, _), - ) if self.infcx.can_sub(self.param_env, checked, &expected).is_ok() => { + ) if self.infcx.can_sub(self.param_env, checked, expected).is_ok() => { // We have `&T`, check if what was expected was `T`. If so, // we may want to suggest removing a `&`. if sm.is_imported(expr.span) { @@ -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/dropck.rs b/compiler/rustc_typeck/src/check/dropck.rs index 89866c20b61..22d2022902f 100644 --- a/compiler/rustc_typeck/src/check/dropck.rs +++ b/compiler/rustc_typeck/src/check/dropck.rs @@ -362,9 +362,9 @@ impl<'tcx> TypeRelation<'tcx> for SimpleEqRelation<'tcx> { fn consts( &mut self, - a: &'tcx ty::Const<'tcx>, - b: &'tcx ty::Const<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { + a: ty::Const<'tcx>, + b: ty::Const<'tcx>, + ) -> RelateResult<'tcx, ty::Const<'tcx>> { debug!("SimpleEqRelation::consts(a={:?}, b={:?})", a, b); ty::relate::super_relate_consts(self, a, b) } diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 0347b6a4ab8..4869d193d80 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -421,9 +421,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Places may legitimately have unsized types. // For example, dereferences of a fat pointer and // the last field of a struct can be unsized. - ExpectHasType(ty) + ExpectHasType(*ty) } else { - Expectation::rvalue_hint(self, ty) + Expectation::rvalue_hint(self, *ty) } } _ => NoExpectation, @@ -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(); }; @@ -2181,7 +2178,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &hir::Expr<'_>, base: &hir::Expr<'_>, field: Ident, - len: &ty::Const<'tcx>, + len: ty::Const<'tcx>, ) { if let (Some(len), Ok(user_index)) = (len.try_eval_usize(self.tcx, self.param_env), field.as_str().parse::<u64>()) @@ -2216,7 +2213,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn no_such_field_err( &self, field: Ident, - expr_t: &'tcx ty::TyS<'tcx>, + expr_t: Ty<'tcx>, id: HirId, ) -> DiagnosticBuilder<'_> { let span = field.span; @@ -2233,7 +2230,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); // try to add a suggestion in case the field is a nested field of a field of the Adt - if let Some((fields, substs)) = self.get_field_candidates(span, &expr_t) { + if let Some((fields, substs)) = self.get_field_candidates(span, expr_t) { for candidate_field in fields.iter() { if let Some(field_path) = self.check_for_nested_field( span, @@ -2312,7 +2309,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { field_path.push(candidate_field.ident(self.tcx).normalize_to_macros_2_0()); let field_ty = candidate_field.ty(self.tcx, subst); - if let Some((nested_fields, subst)) = self.get_field_candidates(span, &field_ty) { + if let Some((nested_fields, subst)) = self.get_field_candidates(span, field_ty) { for field in nested_fields.iter() { let accessible = field.vis.is_accessible_from(id, self.tcx); if accessible { @@ -2449,7 +2446,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // allows them to be inferred based on how they are used later in the // function. if is_input { - let ty = self.structurally_resolved_type(expr.span, &ty); + let ty = self.structurally_resolved_type(expr.span, ty); match *ty.kind() { ty::FnDef(..) => { let fnptr_ty = self.tcx.mk_fn_ptr(ty.fn_sig(self.tcx)); diff --git a/compiler/rustc_typeck/src/check/fallback.rs b/compiler/rustc_typeck/src/check/fallback.rs index e5da33d113e..7214cdf3312 100644 --- a/compiler/rustc_typeck/src/check/fallback.rs +++ b/compiler/rustc_typeck/src/check/fallback.rs @@ -70,7 +70,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { // unconstrained opaque type variables, in addition to performing // other kinds of fallback. for ty in &self.unsolved_variables() { - fallback_has_occurred |= self.fallback_opaque_type_vars(ty); + fallback_has_occurred |= self.fallback_opaque_type_vars(*ty); } // See if we can make any more progress. @@ -176,7 +176,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { .type_var_origin(ty) .map(|origin| origin.span) .unwrap_or(rustc_span::DUMMY_SP); - let oty = self.inner.borrow().opaque_types_vars.get(ty).copied(); + let oty = self.inner.borrow().opaque_types_vars.get(&ty).copied(); if let Some(opaque_ty) = oty { debug!( "fallback_opaque_type_vars(ty={:?}): falling back to opaque type {:?}", diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 0f9803b969f..96bbc2800d5 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -498,14 +498,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty } - pub fn array_length_to_const(&self, length: &hir::ArrayLen) -> &'tcx ty::Const<'tcx> { + pub fn array_length_to_const(&self, length: &hir::ArrayLen) -> ty::Const<'tcx> { match length { &hir::ArrayLen::Infer(_, span) => self.ct_infer(self.tcx.types.usize, None, span), hir::ArrayLen::Body(anon_const) => self.to_const(anon_const), } } - pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> { + pub fn to_const(&self, ast_c: &hir::AnonConst) -> ty::Const<'tcx> { let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id); let c = ty::Const::from_anon_const(self.tcx, const_def_id); self.register_wf_obligation( @@ -520,7 +520,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, ast_c: &hir::AnonConst, param_def_id: DefId, - ) -> &'tcx ty::Const<'tcx> { + ) -> ty::Const<'tcx> { let const_def = ty::WithOptConstParam { did: self.tcx.hir().local_def_id(ast_c.hir_id), const_param_did: Some(param_def_id), @@ -605,7 +605,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { field: &'tcx ty::FieldDef, substs: SubstsRef<'tcx>, ) -> Ty<'tcx> { - self.normalize_associated_types_in(span, &field.ty(self.tcx, substs)) + self.normalize_associated_types_in(span, field.ty(self.tcx, substs)) } pub(in super::super) fn resolve_generator_interiors(&self, def_id: DefId) { @@ -756,7 +756,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // is polymorphic) and the expected return type. // No argument expectations are produced if unification fails. let origin = self.misc(call_span); - let ures = self.at(&origin, self.param_env).sup(ret_ty, &formal_ret); + let ures = self.at(&origin, self.param_env).sup(ret_ty, formal_ret); // FIXME(#27336) can't use ? here, Try::from_error doesn't default // to identity so the resulting type is not constrained. diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 1b93017c5aa..d05dd517f1e 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -578,7 +578,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => bug!("unexpected type: {:?}", ty), }, Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _) - | Res::SelfTy(..) => match ty.kind() { + | Res::SelfTy { .. } => match ty.kind() { ty::Adt(adt, substs) if !adt.is_enum() => { Some((adt.non_enum_variant(), adt.did, substs)) } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs index 3a81af03162..222c14d0d47 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs @@ -239,7 +239,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { ty: Ty<'tcx>, param: Option<&ty::GenericParamDef>, span: Span, - ) -> &'tcx Const<'tcx> { + ) -> Const<'tcx> { if let Some(param) = param { if let GenericArgKind::Const(ct) = self.var_for_def(span, param).unpack() { return ct; @@ -282,7 +282,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { if ty.has_escaping_bound_vars() { ty // FIXME: normalization and escaping regions } else { - self.normalize_associated_types_in(span, &ty) + self.normalize_associated_types_in(span, ty) } } 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/gather_locals.rs b/compiler/rustc_typeck/src/check/gather_locals.rs index e30871e4347..576dc6f127c 100644 --- a/compiler/rustc_typeck/src/check/gather_locals.rs +++ b/compiler/rustc_typeck/src/check/gather_locals.rs @@ -92,7 +92,7 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { debug!( "local variable {:?} is assigned type {}", decl.pat, - self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&decl.hir_id).unwrap().decl_ty) + self.fcx.ty_to_string(self.fcx.locals.borrow().get(&decl.hir_id).unwrap().decl_ty) ); } } @@ -137,7 +137,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { debug!( "pattern binding {} is assigned to {} with type {:?}", ident, - self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&p.hir_id).unwrap().decl_ty), + self.fcx.ty_to_string(self.fcx.locals.borrow().get(&p.hir_id).unwrap().decl_ty), var_ty ); } diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs index f154edf5a2a..d360f34ae70 100644 --- a/compiler/rustc_typeck/src/check/generator_interior.rs +++ b/compiler/rustc_typeck/src/check/generator_interior.rs @@ -155,7 +155,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { self.types.insert(ty::GeneratorInteriorTypeCause { span: source_span, - ty: &ty, + ty, scope_span, yield_span: yield_data.span, expr: expr.map(|e| e.hir_id), @@ -416,7 +416,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { let tcx = self.fcx.tcx; let ref_ty = tcx.mk_ref( // Use `ReErased` as `resolve_interior` is going to replace all the regions anyway. - tcx.mk_region(ty::RegionKind::ReErased), + tcx.mk_region(ty::ReErased), ty::TypeAndMut { ty, mutbl: hir::Mutability::Not }, ); self.record( 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 d7d52ab823c..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 @@ -4,7 +4,7 @@ use super::{ }; use hir::{ intravisit::{self, Visitor}, - Body, Expr, ExprKind, Guard, HirId, + Body, Expr, ExprKind, Guard, HirId, LoopIdError, }; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; @@ -85,6 +85,7 @@ struct DropRangeVisitor<'a, 'tcx> { expr_index: PostOrderId, tcx: TyCtxt<'tcx>, typeck_results: &'a TypeckResults<'tcx>, + label_stack: Vec<(Option<rustc_ast::Label>, PostOrderId)>, } impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> { @@ -101,7 +102,15 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> { hir, num_exprs, ); - Self { hir, places, drop_ranges, expr_index: PostOrderId::from_u32(0), typeck_results, tcx } + Self { + hir, + places, + drop_ranges, + expr_index: PostOrderId::from_u32(0), + typeck_results, + tcx, + label_stack: vec![], + } } fn record_drop(&mut self, value: TrackedValue) { @@ -209,6 +218,60 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> { self.drop_ranges.add_control_edge(self.expr_index + 1, self.expr_index + 1); } } + + /// Map a Destination to an equivalent expression node + /// + /// The destination field of a Break or Continue expression can target either an + /// expression or a block. The drop range analysis, however, only deals in + /// expression nodes, so blocks that might be the destination of a Break or Continue + /// will not have a PostOrderId. + /// + /// If the destination is an expression, this function will simply return that expression's + /// hir_id. If the destination is a block, this function will return the hir_id of last + /// expression in the block. + fn find_target_expression_from_destination( + &self, + destination: hir::Destination, + ) -> Result<HirId, LoopIdError> { + destination.target_id.map(|target| { + let node = self.hir.get(target); + match node { + hir::Node::Expr(_) => target, + hir::Node::Block(b) => find_last_block_expression(b), + hir::Node::Param(..) + | hir::Node::Item(..) + | hir::Node::ForeignItem(..) + | hir::Node::TraitItem(..) + | hir::Node::ImplItem(..) + | hir::Node::Variant(..) + | hir::Node::Field(..) + | hir::Node::AnonConst(..) + | hir::Node::Stmt(..) + | hir::Node::PathSegment(..) + | hir::Node::Ty(..) + | hir::Node::TraitRef(..) + | hir::Node::Binding(..) + | hir::Node::Pat(..) + | hir::Node::Arm(..) + | hir::Node::Local(..) + | hir::Node::Ctor(..) + | hir::Node::Lifetime(..) + | hir::Node::GenericParam(..) + | hir::Node::Visibility(..) + | hir::Node::Crate(..) + | hir::Node::Infer(..) => bug!("Unsupported branch target: {:?}", node), + } + }) + } +} + +fn find_last_block_expression(block: &hir::Block<'_>) -> HirId { + block.expr.map_or_else( + // If there is no tail expression, there will be at least one statement in the + // block because the block contains a break or continue statement. + || block.stmts.last().unwrap().hir_id, + |expr| expr.hir_id, + ) } impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> { @@ -320,8 +383,9 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> { }); } - ExprKind::Loop(body, ..) => { + ExprKind::Loop(body, label, ..) => { let loop_begin = self.expr_index + 1; + self.label_stack.push((label, loop_begin)); if body.stmts.is_empty() && body.expr.is_none() { // For empty loops we won't have updated self.expr_index after visiting the // body, meaning we'd get an edge from expr_index to expr_index + 1, but @@ -331,10 +395,31 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> { self.visit_block(body); self.drop_ranges.add_control_edge(self.expr_index, loop_begin); } + self.label_stack.pop(); } - ExprKind::Break(hir::Destination { target_id: Ok(target), .. }, ..) - | ExprKind::Continue(hir::Destination { target_id: Ok(target), .. }, ..) => { - self.drop_ranges.add_control_edge_hir_id(self.expr_index, target); + // Find the loop entry by searching through the label stack for either the last entry + // (if label is none), or the first entry where the label matches this one. The Loop + // case maintains this stack mapping labels to the PostOrderId for the loop entry. + ExprKind::Continue(hir::Destination { label, .. }, ..) => self + .label_stack + .iter() + .rev() + .find(|(loop_label, _)| label.is_none() || *loop_label == label) + .map_or((), |(_, target)| { + self.drop_ranges.add_control_edge(self.expr_index, *target) + }), + + ExprKind::Break(destination, ..) => { + // destination either points to an expression or to a block. We use + // find_target_expression_from_destination to use the last expression of the block + // if destination points to a block. + // + // We add an edge to the hir_id of the expression/block we are breaking out of, and + // then in process_deferred_edges we will map this hir_id to its PostOrderId, which + // will refer to the end of the block due to the post order traversal. + self.find_target_expression_from_destination(destination).map_or((), |target| { + self.drop_ranges.add_control_edge_hir_id(self.expr_index, target) + }) } ExprKind::Call(f, args) => { @@ -359,11 +444,9 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> { | ExprKind::Binary(..) | ExprKind::Block(..) | ExprKind::Box(..) - | ExprKind::Break(..) | ExprKind::Cast(..) | ExprKind::Closure(..) | ExprKind::ConstBlock(..) - | ExprKind::Continue(..) | ExprKind::DropTemps(..) | ExprKind::Err | ExprKind::Field(..) @@ -444,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) { @@ -454,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. @@ -462,11 +545,13 @@ impl DropRangesBuilder { /// Should be called after visiting the HIR but before solving the control flow, otherwise some /// edges will be missed. fn process_deferred_edges(&mut self) { + trace!("processing deferred edges. post_order_map={:#?}", self.post_order_map); let mut edges = vec![]; swap(&mut edges, &mut self.deferred_edges); edges.into_iter().for_each(|(from, to)| { - let to = *self.post_order_map.get(&to).expect("Expression ID not found"); trace!("Adding deferred edge from {:?} to {:?}", from, to); + let to = *self.post_order_map.get(&to).expect("Expression ID not found"); + trace!("target edge PostOrderId={:?}", to); self.add_control_edge(from, to) }); } diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs index 27c39934ba8..fdc3ba17e3c 100644 --- a/compiler/rustc_typeck/src/check/method/confirm.rs +++ b/compiler/rustc_typeck/src/check/method/confirm.rs @@ -185,7 +185,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { if unsize { let unsized_ty = if let ty::Array(elem_ty, _) = base_ty.kind() { - self.tcx.mk_slice(elem_ty) + self.tcx.mk_slice(*elem_ty) } else { bug!( "AutorefOrPtrAdjustment's unsize flag should only be set for array ty, found {}", @@ -201,8 +201,8 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { } Some(probe::AutorefOrPtrAdjustment::ToConstPtr) => { target = match target.kind() { - ty::RawPtr(ty::TypeAndMut { ty, mutbl }) => { - assert_eq!(*mutbl, hir::Mutability::Mut); + &ty::RawPtr(ty::TypeAndMut { ty, mutbl }) => { + assert_eq!(mutbl, hir::Mutability::Mut); self.tcx.mk_ptr(ty::TypeAndMut { mutbl: hir::Mutability::Not, ty }) } other => panic!("Cannot adjust receiver type {:?} to const ptr", other), diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs index d2dc21d84f6..e5ef52e0324 100644 --- a/compiler/rustc_typeck/src/check/method/mod.rs +++ b/compiler/rustc_typeck/src/check/method/mod.rs @@ -227,7 +227,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let ty::Ref(region, t_type, mutability) = self_ty.kind() { let trait_type = self .tcx - .mk_ref(region, ty::TypeAndMut { ty: t_type, mutbl: mutability.invert() }); + .mk_ref(*region, ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() }); // We probe again to see if there might be a borrow mutability discrepancy. match self.lookup_probe( span, diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs index cd1c0980a55..c429e0f1653 100644 --- a/compiler/rustc_typeck/src/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -515,7 +515,7 @@ fn method_autoderef_steps<'tcx>( steps.push(CandidateStep { self_ty: infcx.make_query_response_ignoring_pending_obligations( inference_vars, - infcx.tcx.mk_slice(elem_ty), + infcx.tcx.mk_slice(*elem_ty), ), autoderefs: dereferences, // this could be from an unsafe deref if we had @@ -1247,7 +1247,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } let ty = match self_ty.kind() { - ty::RawPtr(ty::TypeAndMut { ty, mutbl: hir::Mutability::Mut }) => ty, + &ty::RawPtr(ty::TypeAndMut { ty, mutbl: hir::Mutability::Mut }) => ty, _ => return None, }; diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 8aa22852a6f..a523ba286ec 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -9,8 +9,10 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; use rustc_hir::{ExprKind, Node, QPath}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_middle::ty::fast_reject::{simplify_type, SimplifyParams, StripReferences}; +use rustc_middle::traits::util::supertraits; +use rustc_middle::ty::fast_reject::{simplify_type, SimplifyParams}; use rustc_middle::ty::print::with_crate_prefix; +use rustc_middle::ty::ToPolyTraitRef; use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable}; use rustc_span::lev_distance; use rustc_span::symbol::{kw, sym, Ident}; @@ -40,7 +42,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Err(..) => return false, }; + // This conditional prevents us from asking to call errors and unresolved types. + // It might seem that we can use `predicate_must_hold_modulo_regions`, + // but since a Dummy binder is used to fill in the FnOnce trait's arguments, + // type resolution always gives a "maybe" here. + if self.autoderef(span, ty).any(|(ty, _)| { + info!("check deref {:?} error", ty); + matches!(ty.kind(), ty::Error(_) | ty::Infer(_)) + }) { + return false; + } + self.autoderef(span, ty).any(|(ty, _)| { + info!("check deref {:?} impl FnOnce", ty); self.probe(|_| { let fn_once_substs = tcx.mk_substs_trait( ty, @@ -703,7 +717,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut bound_spans = vec![]; let mut collect_type_param_suggestions = - |self_ty: Ty<'tcx>, parent_pred: &ty::Predicate<'tcx>, obligation: &str| { + |self_ty: Ty<'tcx>, parent_pred: ty::Predicate<'tcx>, obligation: &str| { // We don't care about regions here, so it's fine to skip the binder here. if let (ty::Param(_), ty::PredicateKind::Trait(p)) = (self_ty.kind(), parent_pred.kind().skip_binder()) @@ -892,7 +906,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .filter(|(pred, _, _parent_pred)| !skip_list.contains(&pred)) .filter_map(|(pred, parent_pred, _cause)| { format_pred(*pred).map(|(p, self_ty)| { - collect_type_param_suggestions(self_ty, pred, &p); + collect_type_param_suggestions(self_ty, *pred, &p); match parent_pred { None => format!("`{}`", &p), Some(parent_pred) => match format_pred(*parent_pred) { @@ -900,7 +914,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some((parent_p, _)) => { collect_type_param_suggestions( self_ty, - parent_pred, + *parent_pred, &p, ); format!("`{}`\nwhich is required by `{}`", p, parent_p) @@ -1086,8 +1100,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let ty::Ref(region, t_type, mutability) = rcvr_ty.kind() { if needs_mut { let trait_type = self.tcx.mk_ref( - region, - ty::TypeAndMut { ty: t_type, mutbl: mutability.invert() }, + *region, + ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() }, ); err.note(&format!("you need `{}` instead of `{}`", trait_type, rcvr_ty)); } @@ -1196,9 +1210,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(adt) if adt.did.is_local() => adt, _ => continue, }; - let can_derive = match self.tcx.get_diagnostic_name(trait_pred.def_id()) { - Some(sym::Default) => !adt.is_enum(), - Some( + if let Some(diagnostic_name) = self.tcx.get_diagnostic_name(trait_pred.def_id()) { + let can_derive = match diagnostic_name { + sym::Default => !adt.is_enum(), sym::Eq | sym::PartialEq | sym::Ord @@ -1206,16 +1220,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | sym::Clone | sym::Copy | sym::Hash - | sym::Debug, - ) => true, - _ => false, - }; - if can_derive { - derives.push(( - format!("{}", trait_pred.self_ty()), - self.tcx.def_span(adt.did), - format!("{}", trait_pred.trait_ref.print_only_trait_name()), - )); + | sym::Debug => true, + _ => false, + }; + if can_derive { + let self_name = trait_pred.self_ty().to_string(); + let self_span = self.tcx.def_span(adt.did); + if let Some(poly_trait_ref) = pred.to_opt_poly_trait_pred() { + for super_trait in supertraits(self.tcx, poly_trait_ref.to_poly_trait_ref()) + { + if let Some(parent_diagnostic_name) = + self.tcx.get_diagnostic_name(super_trait.def_id()) + { + derives.push(( + self_name.clone(), + self_span.clone(), + parent_diagnostic_name.to_string(), + )); + } + } + } + derives.push((self_name, self_span, diagnostic_name.to_string())); + } else { + traits.push(self.tcx.def_span(trait_pred.def_id())); + } } else { traits.push(self.tcx.def_span(trait_pred.def_id())); } @@ -1462,13 +1490,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // just this list. for (rcvr_ty, post) in &[ (rcvr_ty, ""), - (self.tcx.mk_mut_ref(&ty::ReErased, rcvr_ty), "&mut "), - (self.tcx.mk_imm_ref(&ty::ReErased, rcvr_ty), "&"), + (self.tcx.mk_mut_ref(self.tcx.lifetimes.re_erased, rcvr_ty), "&mut "), + (self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, rcvr_ty), "&"), ] { if let Ok(pick) = self.lookup_probe( span, item_name, - rcvr_ty, + *rcvr_ty, rcvr, crate::check::method::probe::ProbeScope::AllTraits, ) { @@ -1487,10 +1515,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { break; } for (rcvr_ty, pre) in &[ - (self.tcx.mk_lang_item(rcvr_ty, LangItem::OwnedBox), "Box::new"), - (self.tcx.mk_lang_item(rcvr_ty, LangItem::Pin), "Pin::new"), - (self.tcx.mk_diagnostic_item(rcvr_ty, sym::Arc), "Arc::new"), - (self.tcx.mk_diagnostic_item(rcvr_ty, sym::Rc), "Rc::new"), + (self.tcx.mk_lang_item(*rcvr_ty, LangItem::OwnedBox), "Box::new"), + (self.tcx.mk_lang_item(*rcvr_ty, LangItem::Pin), "Pin::new"), + (self.tcx.mk_diagnostic_item(*rcvr_ty, sym::Arc), "Arc::new"), + (self.tcx.mk_diagnostic_item(*rcvr_ty, sym::Rc), "Rc::new"), ] { if let Some(new_rcvr_t) = *rcvr_ty { if let Ok(pick) = self.lookup_probe( @@ -1748,8 +1776,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // FIXME: Even though negative bounds are not implemented, we could maybe handle // cases where a positive bound implies a negative impl. (candidates, Vec::new()) - } else if let Some(simp_rcvr_ty) = - simplify_type(self.tcx, rcvr_ty, SimplifyParams::Yes, StripReferences::No) + } else if let Some(simp_rcvr_ty) = simplify_type(self.tcx, rcvr_ty, SimplifyParams::Yes) { let mut potential_candidates = Vec::new(); let mut explicitly_negative = Vec::new(); @@ -1763,12 +1790,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) .any(|imp_did| { let imp = self.tcx.impl_trait_ref(imp_did).unwrap(); - let imp_simp = simplify_type( - self.tcx, - imp.self_ty(), - SimplifyParams::Yes, - StripReferences::No, - ); + let imp_simp = + simplify_type(self.tcx, imp.self_ty(), SimplifyParams::Yes); imp_simp.map_or(false, |s| s == simp_rcvr_ty) }) { diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index 74516acbfcf..dd49d6f4892 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -221,7 +221,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, }; let autoref = Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)), + kind: Adjust::Borrow(AutoBorrow::Ref(*region, mutbl)), target: method.sig.inputs()[0], }; self.apply_adjustments(lhs_expr, vec![autoref]); @@ -238,7 +238,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, }; let autoref = Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)), + kind: Adjust::Borrow(AutoBorrow::Ref(*region, mutbl)), target: method.sig.inputs()[1], }; // HACK(eddyb) Bypass checks due to reborrows being in @@ -399,8 +399,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; if let Ref(_, rty, _) = lhs_ty.kind() { - if self.infcx.type_is_copy_modulo_regions(self.param_env, rty, lhs_expr.span) - && self.lookup_op_method(rty, &[rhs_ty], Op::Binary(op, is_assign)).is_ok() + if self.infcx.type_is_copy_modulo_regions(self.param_env, *rty, lhs_expr.span) + && self.lookup_op_method(*rty, &[rhs_ty], Op::Binary(op, is_assign)).is_ok() { if let Ok(lstring) = source_map.span_to_snippet(lhs_expr.span) { let msg = &format!( @@ -452,7 +452,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx, self.body_id, &mut err, - ty, + *ty, rhs_ty, missing_trait, p, @@ -878,7 +878,7 @@ enum Op { /// Dereferences a single level of immutable referencing. fn deref_ty_if_possible<'tcx>(ty: Ty<'tcx>) -> Ty<'tcx> { match ty.kind() { - ty::Ref(_, ty, hir::Mutability::Not) => ty, + ty::Ref(_, ty, hir::Mutability::Not) => *ty, _ => ty, } } diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 62cd9c64a4a..e034adde1be 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -1935,7 +1935,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { element_ty: Ty<'tcx>, arr_ty: Ty<'tcx>, slice: Option<&'tcx Pat<'tcx>>, - len: &ty::Const<'tcx>, + len: ty::Const<'tcx>, min_len: u64, ) -> (Option<Ty<'tcx>>, Ty<'tcx>) { if let Some(len) = len.try_eval_usize(self.tcx, self.param_env) { @@ -2029,34 +2029,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.help("the semantics of slice patterns changed recently; see issue #62254"); } } else if Autoderef::new(&self.infcx, self.param_env, self.body_id, span, expected_ty, span) - .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..))) + .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..))) { if let (Some(span), true) = (ti.span, ti.origin_expr) { if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { - let applicability = match self.resolve_vars_if_possible(ti.expected).kind() { - ty::Adt(adt_def, _) - if self.tcx.is_diagnostic_item(sym::Option, adt_def.did) - || self.tcx.is_diagnostic_item(sym::Result, adt_def.did) => - { - // Slicing won't work here, but `.as_deref()` might (issue #91328). - err.span_suggestion( - span, - "consider using `as_deref` here", - format!("{}.as_deref()", snippet), - Applicability::MaybeIncorrect, - ); - None - } - // FIXME: instead of checking for Vec only, we could check whether the - // type implements `Deref<Target=X>`; see - // https://github.com/rust-lang/rust/pull/91343#discussion_r761466979 - ty::Adt(adt_def, _) - if self.tcx.is_diagnostic_item(sym::Vec, adt_def.did) => - { - Some(Applicability::MachineApplicable) + let applicability = Autoderef::new( + &self.infcx, + self.param_env, + self.body_id, + span, + self.resolve_vars_if_possible(ti.expected), + span, + ) + .find_map(|(ty, _)| { + match ty.kind() { + ty::Adt(adt_def, _) + if self.tcx.is_diagnostic_item(sym::Option, adt_def.did) + || self.tcx.is_diagnostic_item(sym::Result, adt_def.did) => + { + // Slicing won't work here, but `.as_deref()` might (issue #91328). + err.span_suggestion( + span, + "consider using `as_deref` here", + format!("{}.as_deref()", snippet), + Applicability::MaybeIncorrect, + ); + Some(None) + } + + ty::Slice(..) | ty::Array(..) => { + Some(Some(Applicability::MachineApplicable)) + } + + _ => None, } - _ => Some(Applicability::MaybeIncorrect), - }; + }) + .unwrap_or(Some(Applicability::MaybeIncorrect)); if let Some(applicability) = applicability { err.span_suggestion( diff --git a/compiler/rustc_typeck/src/check/place_op.rs b/compiler/rustc_typeck/src/check/place_op.rs index d01e21bcb23..318979b4627 100644 --- a/compiler/rustc_typeck/src/check/place_op.rs +++ b/compiler/rustc_typeck/src/check/place_op.rs @@ -31,7 +31,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.apply_adjustments( oprnd_expr, vec![Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(region, AutoBorrowMutability::Not)), + kind: Adjust::Borrow(AutoBorrow::Ref(*region, AutoBorrowMutability::Not)), target: method.sig.inputs()[0], }], ); @@ -142,7 +142,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if unsize { // We only unsize arrays here. if let ty::Array(element_ty, _) = adjusted_ty.kind() { - self_ty = self.tcx.mk_slice(element_ty); + self_ty = self.tcx.mk_slice(*element_ty); } else { continue; } @@ -165,9 +165,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut adjustments = self.adjust_steps(autoderef); if let ty::Ref(region, _, hir::Mutability::Not) = method.sig.inputs()[0].kind() { adjustments.push(Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(region, AutoBorrowMutability::Not)), + kind: Adjust::Borrow(AutoBorrow::Ref(*region, AutoBorrowMutability::Not)), target: self.tcx.mk_ref( - region, + *region, ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: adjusted_ty }, ), }); @@ -432,9 +432,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // not the case today. allow_two_phase_borrow: AllowTwoPhase::No, }; - adjustment.kind = Adjust::Borrow(AutoBorrow::Ref(region, mutbl)); - adjustment.target = - self.tcx.mk_ref(region, ty::TypeAndMut { ty: source, mutbl: mutbl.into() }); + adjustment.kind = Adjust::Borrow(AutoBorrow::Ref(*region, mutbl)); + adjustment.target = self + .tcx + .mk_ref(*region, ty::TypeAndMut { ty: source, mutbl: mutbl.into() }); } source = adjustment.target; } diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs index 4e50fbf56b2..513e8576f2d 100644 --- a/compiler/rustc_typeck/src/check/regionck.rs +++ b/compiler/rustc_typeck/src/check/regionck.rs @@ -689,7 +689,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { let rptr_ty = self.resolve_node_type(id); if let ty::Ref(r, _, _) = rptr_ty.kind() { debug!("rptr_ty={}", rptr_ty); - self.link_region(span, r, ty::BorrowKind::from_mutbl(mutbl), cmt_borrowed); + self.link_region(span, *r, ty::BorrowKind::from_mutbl(mutbl), cmt_borrowed); } } diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 313e3059096..949d857bff4 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -966,7 +966,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx, ty, max_capture_info.capture_kind, - Some(&ty::ReErased), + Some(self.tcx.lifetimes.re_erased), ) } }; @@ -997,7 +997,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx, capture.place.ty(), capture.info.capture_kind, - Some(&ty::ReErased), + Some(self.tcx.lifetimes.re_erased), ); // Checks if a capture implements any of the auto traits @@ -1499,7 +1499,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If the data will be moved out of this place, then the place will be truncated // at the first Deref in `adjust_upvar_borrow_kind_for_consume` and then moved into // the closure. - hir::CaptureBy::Value if !place.deref_tys().any(ty::TyS::is_ref) => { + hir::CaptureBy::Value if !place.deref_tys().any(Ty::is_ref) => { ty::UpvarCapture::ByValue } hir::CaptureBy::Value | hir::CaptureBy::Ref => ty::UpvarCapture::ByRef(ty::ImmBorrow), @@ -1813,7 +1813,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { ); // Raw pointers don't inherit mutability - if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) { + if place_with_id.place.deref_tys().any(Ty::is_unsafe_ptr) { capture_kind = ty::UpvarCapture::ByRef(ty::BorrowKind::ImmBorrow); } diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 71f45320e49..55757251e26 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -3,7 +3,7 @@ use crate::check::{FnCtxt, Inherited}; use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter}; use rustc_ast as ast; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -258,251 +258,186 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { .emit(); } } - - check_gat_where_clauses(tcx, trait_item, encl_trait_def_id); } /// Require that the user writes where clauses on GATs for the implicit /// outlives bounds involving trait parameters in trait functions and /// lifetimes passed as GAT substs. See `self-outlives-lint` test. /// -/// This trait will be our running example. We are currently WF checking the `Item` item... -/// -/// ```rust -/// trait LendingIterator { -/// type Item<'me>; // <-- WF checking this trait item -/// -/// fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>; +/// We use the following trait as an example throughout this function: +/// ```rust,ignore (this code fails due to this lint) +/// trait IntoIter { +/// type Iter<'a>: Iterator<Item = Self::Item<'a>>; +/// type Item<'a>; +/// fn into_iter<'a>(&'a self) -> Self::Iter<'a>; /// } /// ``` -fn check_gat_where_clauses( - tcx: TyCtxt<'_>, - trait_item: &hir::TraitItem<'_>, - encl_trait_def_id: DefId, -) { - let item = tcx.associated_item(trait_item.def_id); - // If the current trait item isn't a type, it isn't a GAT - if !matches!(item.kind, ty::AssocKind::Type) { - return; - } - let generics: &ty::Generics = tcx.generics_of(trait_item.def_id); - // If the current associated type doesn't have any (own) params, it's not a GAT - // FIXME(jackh726): we can also warn in the more general case - if generics.params.len() == 0 { - return; - } - let associated_items: &ty::AssocItems<'_> = tcx.associated_items(encl_trait_def_id); - let mut clauses: Option<FxHashSet<ty::Predicate<'_>>> = None; - // For every function in this trait... - // In our example, this would be the `next` method - for item in - associated_items.in_definition_order().filter(|item| matches!(item.kind, ty::AssocKind::Fn)) - { - // The clauses we that we would require from this function - let mut function_clauses = FxHashSet::default(); - - let id = hir::HirId::make_owner(item.def_id.expect_local()); - let param_env = tcx.param_env(item.def_id.expect_local()); - - let sig = tcx.fn_sig(item.def_id); - // Get the signature using placeholders. In our example, this would - // convert the late-bound 'a into a free region. - let sig = tcx.liberate_late_bound_regions(item.def_id, sig); - // Collect the arguments that are given to this GAT in the return type - // of the function signature. In our example, the GAT in the return - // type is `<Self as LendingIterator>::Item<'a>`, so 'a and Self are arguments. - let (regions, types) = - GATSubstCollector::visit(tcx, trait_item.def_id.to_def_id(), sig.output()); - - // If both regions and types are empty, then this GAT isn't in the - // return type, and we shouldn't try to do clause analysis - // (particularly, doing so would end up with an empty set of clauses, - // since the current method would require none, and we take the - // intersection of requirements of all methods) - if types.is_empty() && regions.is_empty() { - continue; - } - - // The types we can assume to be well-formed. In our example, this - // would be &'a mut Self, from the first argument. - let mut wf_tys = FxHashSet::default(); - wf_tys.extend(sig.inputs()); - - // For each region argument (e.g., 'a in our example), check for a - // relationship to the type arguments (e.g., Self). If there is an - // outlives relationship (`Self: 'a`), then we want to ensure that is - // reflected in a where clause on the GAT itself. - for (region, region_idx) in ®ions { - // Ignore `'static` lifetimes for the purpose of this lint: it's - // because we know it outlives everything and so doesn't give meaninful - // clues - if let ty::ReStatic = region { +fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRef]) { + // Associates every GAT's def_id to a list of possibly missing bounds detected by this lint. + let mut required_bounds_by_item = FxHashMap::default(); + + // Loop over all GATs together, because if this lint suggests adding a where-clause bound + // to one GAT, it might then require us to an additional bound on another GAT. + // In our `IntoIter` example, we discover a missing `Self: 'a` bound on `Iter<'a>`, which + // then in a second loop adds a `Self: 'a` bound to `Item` due to the relationship between + // those GATs. + loop { + let mut should_continue = false; + for gat_item in associated_items { + let gat_def_id = gat_item.id.def_id; + let gat_item = tcx.associated_item(gat_def_id); + // If this item is not an assoc ty, or has no substs, then it's not a GAT + if gat_item.kind != ty::AssocKind::Type { continue; } - for (ty, ty_idx) in &types { - // In our example, requires that Self: 'a - if ty_known_to_outlive(tcx, id, param_env, &wf_tys, *ty, *region) { - debug!(?ty_idx, ?region_idx); - debug!("required clause: {} must outlive {}", ty, region); - // Translate into the generic parameters of the GAT. In - // our example, the type was Self, which will also be - // Self in the GAT. - let ty_param = generics.param_at(*ty_idx, tcx); - let ty_param = tcx.mk_ty(ty::Param(ty::ParamTy { - index: ty_param.index, - name: ty_param.name, - })); - // Same for the region. In our example, 'a corresponds - // to the 'me parameter. - let region_param = generics.param_at(*region_idx, tcx); - let region_param = - tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion { - def_id: region_param.def_id, - index: region_param.index, - name: region_param.name, - })); - // The predicate we expect to see. (In our example, - // `Self: 'me`.) - let clause = ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate( - ty_param, - region_param, - )); - let clause = tcx.mk_predicate(ty::Binder::dummy(clause)); - function_clauses.insert(clause); - } - } - } - - // For each region argument (e.g., 'a in our example), also check for a - // relationship to the other region arguments. If there is an - // outlives relationship, then we want to ensure that is - // reflected in a where clause on the GAT itself. - for (region_a, region_a_idx) in ®ions { - // Ignore `'static` lifetimes for the purpose of this lint: it's - // because we know it outlives everything and so doesn't give meaninful - // clues - if let ty::ReStatic = region_a { + let gat_generics = tcx.generics_of(gat_def_id); + // FIXME(jackh726): we can also warn in the more general case + if gat_generics.params.is_empty() { continue; } - for (region_b, region_b_idx) in ®ions { - if region_a == region_b { - continue; - } - if let ty::ReStatic = region_b { + + // Gather the bounds with which all other items inside of this trait constrain the GAT. + // This is calculated by taking the intersection of the bounds that each item + // constrains the GAT with individually. + let mut new_required_bounds: Option<FxHashSet<ty::Predicate<'_>>> = None; + for item in associated_items { + let item_def_id = item.id.def_id; + // Skip our own GAT, since it does not constrain itself at all. + if item_def_id == gat_def_id { continue; } - if region_known_to_outlive(tcx, id, param_env, &wf_tys, *region_a, *region_b) { - debug!(?region_a_idx, ?region_b_idx); - debug!("required clause: {} must outlive {}", region_a, region_b); - // Translate into the generic parameters of the GAT. - let region_a_param = generics.param_at(*region_a_idx, tcx); - let region_a_param = - tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion { - def_id: region_a_param.def_id, - index: region_a_param.index, - name: region_a_param.name, - })); - // Same for the region. - let region_b_param = generics.param_at(*region_b_idx, tcx); - let region_b_param = - tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion { - def_id: region_b_param.def_id, - index: region_b_param.index, - name: region_b_param.name, - })); - // The predicate we expect to see. - let clause = ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate( - region_a_param, - region_b_param, - )); - let clause = tcx.mk_predicate(ty::Binder::dummy(clause)); - function_clauses.insert(clause); + let item_hir_id = item.id.hir_id(); + let param_env = tcx.param_env(item_def_id); + + let item_required_bounds = match item.kind { + // In our example, this corresponds to `into_iter` method + hir::AssocItemKind::Fn { .. } => { + // For methods, we check the function signature's return type for any GATs + // to constrain. In the `into_iter` case, we see that the return type + // `Self::Iter<'a>` is a GAT we want to gather any potential missing bounds from. + let sig: ty::FnSig<'_> = tcx.liberate_late_bound_regions( + item_def_id.to_def_id(), + tcx.fn_sig(item_def_id), + ); + gather_gat_bounds( + tcx, + param_env, + item_hir_id, + sig.output(), + // We also assume that all of the function signature's parameter types + // are well formed. + &sig.inputs().iter().copied().collect(), + gat_def_id, + gat_generics, + ) + } + // In our example, this corresponds to the `Iter` and `Item` associated types + hir::AssocItemKind::Type => { + // If our associated item is a GAT with missing bounds, add them to + // the param-env here. This allows this GAT to propagate missing bounds + // to other GATs. + let param_env = augment_param_env( + tcx, + param_env, + required_bounds_by_item.get(&item_def_id), + ); + gather_gat_bounds( + tcx, + param_env, + item_hir_id, + tcx.explicit_item_bounds(item_def_id) + .iter() + .copied() + .collect::<Vec<_>>(), + &FxHashSet::default(), + gat_def_id, + gat_generics, + ) + } + hir::AssocItemKind::Const => None, + }; + + if let Some(item_required_bounds) = item_required_bounds { + // Take the intersection of the required bounds for this GAT, and + // the item_required_bounds which are the ones implied by just + // this item alone. + // This is why we use an Option<_>, since we need to distinguish + // the empty set of bounds from the _uninitialized_ set of bounds. + if let Some(new_required_bounds) = &mut new_required_bounds { + new_required_bounds.retain(|b| item_required_bounds.contains(b)); + } else { + new_required_bounds = Some(item_required_bounds); + } } } - } - // Imagine we have: - // ``` - // trait Foo { - // type Bar<'me>; - // fn gimme(&self) -> Self::Bar<'_>; - // fn gimme_default(&self) -> Self::Bar<'static>; - // } - // ``` - // We only want to require clauses on `Bar` that we can prove from *all* functions (in this - // case, `'me` can be `static` from `gimme_default`) - match clauses.as_mut() { - Some(clauses) => { - clauses.drain_filter(|p| !function_clauses.contains(p)); - } - None => { - clauses = Some(function_clauses); + if let Some(new_required_bounds) = new_required_bounds { + let required_bounds = required_bounds_by_item.entry(gat_def_id).or_default(); + if new_required_bounds.into_iter().any(|p| required_bounds.insert(p)) { + // Iterate until our required_bounds no longer change + // Since they changed here, we should continue the loop + should_continue = true; + } } } + // We know that this loop will eventually halt, since we only set `should_continue` if the + // `required_bounds` for this item grows. Since we are not creating any new region or type + // variables, the set of all region and type bounds that we could ever insert are limited + // by the number of unique types and regions we observe in a given item. + if !should_continue { + break; + } } - // If there are any clauses that aren't provable, emit an error - let clauses = clauses.unwrap_or_default(); - debug!(?clauses); - if !clauses.is_empty() { - let param_env = tcx.param_env(trait_item.def_id); + for (gat_def_id, required_bounds) in required_bounds_by_item { + let gat_item_hir = tcx.hir().expect_trait_item(gat_def_id); + debug!(?required_bounds); + let param_env = tcx.param_env(gat_def_id); + let gat_hir = gat_item_hir.hir_id(); - let mut clauses: Vec<_> = clauses + let mut unsatisfied_bounds: Vec<_> = required_bounds .into_iter() .filter(|clause| match clause.kind().skip_binder() { ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => { - !region_known_to_outlive( - tcx, - trait_item.hir_id(), - param_env, - &FxHashSet::default(), - a, - b, - ) + !region_known_to_outlive(tcx, gat_hir, param_env, &FxHashSet::default(), a, b) } ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => { - !ty_known_to_outlive( - tcx, - trait_item.hir_id(), - param_env, - &FxHashSet::default(), - a, - b, - ) + !ty_known_to_outlive(tcx, gat_hir, param_env, &FxHashSet::default(), a, b) } _ => bug!("Unexpected PredicateKind"), }) - .map(|clause| format!("{}", clause)) + .map(|clause| clause.to_string()) .collect(); // We sort so that order is predictable - clauses.sort(); + unsatisfied_bounds.sort(); - if !clauses.is_empty() { - let plural = if clauses.len() > 1 { "s" } else { "" }; + if !unsatisfied_bounds.is_empty() { + let plural = if unsatisfied_bounds.len() > 1 { "s" } else { "" }; let mut err = tcx.sess.struct_span_err( - trait_item.span, - &format!("missing required bound{} on `{}`", plural, trait_item.ident), + gat_item_hir.span, + &format!("missing required bound{} on `{}`", plural, gat_item_hir.ident), ); let suggestion = format!( "{} {}", - if !trait_item.generics.where_clause.predicates.is_empty() { + if !gat_item_hir.generics.where_clause.predicates.is_empty() { "," } else { " where" }, - clauses.join(", "), + unsatisfied_bounds.join(", "), ); err.span_suggestion( - trait_item.generics.where_clause.tail_span_for_suggestion(), + gat_item_hir.generics.where_clause.tail_span_for_suggestion(), &format!("add the required where clause{}", plural), suggestion, Applicability::MachineApplicable, ); - let bound = if clauses.len() > 1 { "these bounds are" } else { "this bound is" }; + let bound = + if unsatisfied_bounds.len() > 1 { "these bounds are" } else { "this bound is" }; err.note(&format!( "{} currently required to ensure that impls have maximum flexibility", bound @@ -518,6 +453,143 @@ fn check_gat_where_clauses( } } +/// Add a new set of predicates to the caller_bounds of an existing param_env. +fn augment_param_env<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + new_predicates: Option<&FxHashSet<ty::Predicate<'tcx>>>, +) -> ty::ParamEnv<'tcx> { + let Some(new_predicates) = new_predicates else { + return param_env; + }; + + if new_predicates.is_empty() { + return param_env; + } + + let bounds = + tcx.mk_predicates(param_env.caller_bounds().iter().chain(new_predicates.iter().cloned())); + // FIXME(compiler-errors): Perhaps there is a case where we need to normalize this + // i.e. traits::normalize_param_env_or_error + ty::ParamEnv::new(bounds, param_env.reveal(), param_env.constness()) +} + +/// We use the following trait as an example throughout this function. +/// Specifically, let's assume that `to_check` here is the return type +/// of `into_iter`, and the GAT we are checking this for is `Iter`. +/// ```rust,ignore (this code fails due to this lint) +/// trait IntoIter { +/// type Iter<'a>: Iterator<Item = Self::Item<'a>>; +/// type Item<'a>; +/// fn into_iter<'a>(&'a self) -> Self::Iter<'a>; +/// } +/// ``` +fn gather_gat_bounds<'tcx, T: TypeFoldable<'tcx>>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + item_hir: hir::HirId, + to_check: T, + wf_tys: &FxHashSet<Ty<'tcx>>, + gat_def_id: LocalDefId, + gat_generics: &'tcx ty::Generics, +) -> Option<FxHashSet<ty::Predicate<'tcx>>> { + // The bounds we that we would require from `to_check` + let mut bounds = FxHashSet::default(); + + let (regions, types) = GATSubstCollector::visit(tcx, gat_def_id.to_def_id(), to_check); + + // If both regions and types are empty, then this GAT isn't in the + // set of types we are checking, and we shouldn't try to do clause analysis + // (particularly, doing so would end up with an empty set of clauses, + // since the current method would require none, and we take the + // intersection of requirements of all methods) + if types.is_empty() && regions.is_empty() { + return None; + } + + for (region_a, region_a_idx) in ®ions { + // Ignore `'static` lifetimes for the purpose of this lint: it's + // because we know it outlives everything and so doesn't give meaninful + // clues + if let ty::ReStatic = **region_a { + continue; + } + // For each region argument (e.g., `'a` in our example), check for a + // relationship to the type arguments (e.g., `Self`). If there is an + // outlives relationship (`Self: 'a`), then we want to ensure that is + // reflected in a where clause on the GAT itself. + for (ty, ty_idx) in &types { + // In our example, requires that `Self: 'a` + if ty_known_to_outlive(tcx, item_hir, param_env, &wf_tys, *ty, *region_a) { + debug!(?ty_idx, ?region_a_idx); + debug!("required clause: {} must outlive {}", ty, region_a); + // Translate into the generic parameters of the GAT. In + // our example, the type was `Self`, which will also be + // `Self` in the GAT. + let ty_param = gat_generics.param_at(*ty_idx, tcx); + let ty_param = tcx + .mk_ty(ty::Param(ty::ParamTy { index: ty_param.index, name: ty_param.name })); + // Same for the region. In our example, 'a corresponds + // to the 'me parameter. + let region_param = gat_generics.param_at(*region_a_idx, tcx); + let region_param = + tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion { + def_id: region_param.def_id, + index: region_param.index, + name: region_param.name, + })); + // The predicate we expect to see. (In our example, + // `Self: 'me`.) + let clause = + ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_param, region_param)); + let clause = tcx.mk_predicate(ty::Binder::dummy(clause)); + bounds.insert(clause); + } + } + + // For each region argument (e.g., `'a` in our example), also check for a + // relationship to the other region arguments. If there is an outlives + // relationship, then we want to ensure that is reflected in the where clause + // on the GAT itself. + for (region_b, region_b_idx) in ®ions { + // Again, skip `'static` because it outlives everything. Also, we trivially + // know that a region outlives itself. + if ty::ReStatic == **region_b || region_a == region_b { + continue; + } + if region_known_to_outlive(tcx, item_hir, param_env, &wf_tys, *region_a, *region_b) { + debug!(?region_a_idx, ?region_b_idx); + debug!("required clause: {} must outlive {}", region_a, region_b); + // Translate into the generic parameters of the GAT. + let region_a_param = gat_generics.param_at(*region_a_idx, tcx); + let region_a_param = + tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion { + def_id: region_a_param.def_id, + index: region_a_param.index, + name: region_a_param.name, + })); + // Same for the region. + let region_b_param = gat_generics.param_at(*region_b_idx, tcx); + let region_b_param = + tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion { + def_id: region_b_param.def_id, + index: region_b_param.index, + name: region_b_param.name, + })); + // The predicate we expect to see. + let clause = ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate( + region_a_param, + region_b_param, + )); + let clause = tcx.mk_predicate(ty::Binder::dummy(clause)); + bounds.insert(clause); + } + } + } + + Some(bounds) +} + /// Given a known `param_env` and a set of well formed types, can we prove that /// `ty` outlives `region`. fn ty_known_to_outlive<'tcx>( @@ -569,7 +641,7 @@ fn resolve_regions_with_wf_tys<'tcx>( wf_tys: &FxHashSet<Ty<'tcx>>, add_constraints: impl for<'a> FnOnce( &'a InferCtxt<'a, 'tcx>, - &'a Vec<(&'tcx ty::RegionKind, GenericKind<'tcx>)>, + &'a Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>, ), ) -> bool { // Unfortunately, we have to use a new `InferCtxt` each call, because @@ -1027,6 +1099,11 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) { FxHashSet::default() }); + + // Only check traits, don't check trait aliases + if let hir::ItemKind::Trait(_, _, _, _, items) = item.kind { + check_gat_where_clauses(tcx, items); + } } /// Checks all associated type defaults of trait `trait_def_id`. @@ -1298,8 +1375,8 @@ fn check_where_clauses<'tcx, 'fcx>( ControlFlow::BREAK } - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { - if let ty::ConstKind::Param(param) = c.val { + fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { + if let ty::ConstKind::Param(param) = c.val() { self.params.insert(param.index); } c.super_visit_with(self) diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index ec88bdf4a37..3843e7e54be 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -720,7 +720,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { } } - fn report_const_error(&self, c: &'tcx ty::Const<'tcx>) { + fn report_const_error(&self, c: ty::Const<'tcx>) { if !self.tcx.sess.has_errors() { self.infcx .emit_inference_failure_err( @@ -751,7 +751,7 @@ impl<'tcx> TypeFolder<'tcx> for EraseEarlyRegions<'tcx> { } } fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - if let ty::ReLateBound(..) = r { r } else { self.tcx.lifetimes.re_erased } + if r.is_late_bound() { r } else { self.tcx.lifetimes.re_erased } } } @@ -783,14 +783,14 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { self.tcx.lifetimes.re_erased } - fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { match self.infcx.fully_resolve(ct) { Ok(ct) => self.infcx.tcx.erase_regions(ct), Err(_) => { debug!("Resolver::fold_const: input const `{:?}` not fully resolvable", ct); self.report_const_error(ct); self.replaced_with_error = true; - self.tcx().const_error(ct.ty) + self.tcx().const_error(ct.ty()) } } } diff --git a/compiler/rustc_typeck/src/coherence/builtin.rs b/compiler/rustc_typeck/src/coherence/builtin.rs index dff6b7b58a0..401ba188728 100644 --- a/compiler/rustc_typeck/src/coherence/builtin.rs +++ b/compiler/rustc_typeck/src/coherence/builtin.rs @@ -147,7 +147,7 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did: use ty::TyKind::*; match (source.kind(), target.kind()) { (&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b)) - if infcx.at(&cause, param_env).eq(r_a, r_b).is_ok() && mutbl_a == *mutbl_b => {} + if infcx.at(&cause, param_env).eq(r_a, *r_b).is_ok() && mutbl_a == *mutbl_b => {} (&RawPtr(tm_a), &RawPtr(tm_b)) if tm_a.mutbl == tm_b.mutbl => (), (&Adt(def_a, substs_a), &Adt(def_b, substs_b)) if def_a.is_struct() && def_b.is_struct() => diff --git a/compiler/rustc_typeck/src/coherence/orphan.rs b/compiler/rustc_typeck/src/coherence/orphan.rs index 777bd640669..9bb31003796 100644 --- a/compiler/rustc_typeck/src/coherence/orphan.rs +++ b/compiler/rustc_typeck/src/coherence/orphan.rs @@ -301,7 +301,7 @@ impl<'tcx> TypeVisitor<'tcx> for AreUniqueParamsVisitor { } } fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { - match r { + match *r { ty::ReEarlyBound(p) => { if self.seen.insert(p.index) { ControlFlow::CONTINUE @@ -312,8 +312,8 @@ impl<'tcx> TypeVisitor<'tcx> for AreUniqueParamsVisitor { _ => ControlFlow::Break(NotUniqueParam::NotParam(r.into())), } } - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { - match c.val { + fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { + match c.val() { ty::ConstKind::Param(p) => { if self.seen.insert(p.index) { ControlFlow::CONTINUE diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 727ca19d6ff..18f54eb2246 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -389,13 +389,8 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { self.tcx().ty_error_with_message(span, "bad placeholder type") } - fn ct_infer( - &self, - ty: Ty<'tcx>, - _: Option<&ty::GenericParamDef>, - span: Span, - ) -> &'tcx Const<'tcx> { - let ty = self.tcx.fold_regions(ty, &mut false, |r, _| match r { + fn ct_infer(&self, ty: Ty<'tcx>, _: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> { + let ty = self.tcx.fold_regions(ty, &mut false, |r, _| match *r { ty::ReErased => self.tcx.lifetimes.re_static, _ => r, }); @@ -1878,7 +1873,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { Some(ty) => { let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id]; // Typeck doesn't expect erased regions to be returned from `type_of`. - let fn_sig = tcx.fold_regions(fn_sig, &mut false, |r, _| match r { + let fn_sig = tcx.fold_regions(fn_sig, &mut false, |r, _| match *r { ty::ReErased => tcx.lifetimes.re_static, _ => r, }); @@ -2162,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 // @@ -2182,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 @@ -2394,7 +2390,7 @@ fn const_evaluatable_predicates_of<'tcx>( fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) { let def_id = self.tcx.hir().local_def_id(c.hir_id); let ct = ty::Const::from_anon_const(self.tcx, def_id); - if let ty::ConstKind::Unevaluated(uv) = ct.val { + if let ty::ConstKind::Unevaluated(uv) = ct.val() { assert_eq!(uv.promoted, None); let span = self.tcx.hir().span(c.hir_id); self.preds.insert(( @@ -2591,7 +2587,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( } }; for (input, ty) in iter::zip(decl.inputs, fty.inputs().skip_binder()) { - check(input, ty) + check(input, *ty) } if let hir::FnRetTy::Return(ref ty) = decl.output { check(ty, fty.output().skip_binder()) @@ -3013,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) { @@ -3020,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 c911b781f3c..cd7343a3211 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -527,7 +527,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", ) } } @@ -639,7 +639,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { err.emit(); } } else { - self.found = Some((span, concrete_type)); + self.found = Some((span, *concrete_type)); } } } @@ -829,7 +829,7 @@ fn infer_placeholder_type<'a>( } // Typeck doesn't expect erased regions to be returned from `type_of`. - tcx.fold_regions(ty, &mut false, |r, _| match r { + tcx.fold_regions(ty, &mut false, |r, _| match *r { ty::ReErased => tcx.lifetimes.re_static, _ => r, }) diff --git a/compiler/rustc_typeck/src/constrained_generic_params.rs b/compiler/rustc_typeck/src/constrained_generic_params.rs index a0c8fc822df..909c99adab5 100644 --- a/compiler/rustc_typeck/src/constrained_generic_params.rs +++ b/compiler/rustc_typeck/src/constrained_generic_params.rs @@ -79,11 +79,11 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { ControlFlow::CONTINUE } - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { - match c.val { + fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { + match c.val() { ty::ConstKind::Unevaluated(..) if !self.include_nonconstraining => { // Constant expressions are not injective - return c.ty.visit_with(self); + return c.ty().visit_with(self); } ty::ConstKind::Param(data) => { self.parameters.push(Parameter::from(data)); diff --git a/compiler/rustc_typeck/src/hir_wf_check.rs b/compiler/rustc_typeck/src/hir_wf_check.rs index 7d1aedc8600..7b709b302f6 100644 --- a/compiler/rustc_typeck/src/hir_wf_check.rs +++ b/compiler/rustc_typeck/src/hir_wf_check.rs @@ -180,6 +180,6 @@ impl<'tcx> TypeFolder<'tcx> for EraseAllBoundRegions<'tcx> { self.tcx } fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> { - if let ty::ReLateBound(..) = r { &ty::ReErased } else { r } + if r.is_late_bound() { self.tcx.lifetimes.re_erased } else { r } } } diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs index d87e670a8fb..92f88a15ee4 100644 --- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs @@ -269,7 +269,7 @@ fn check_static_lifetimes<'tcx>( parent_substs: &Vec<GenericArg<'tcx>>, span: Span, ) { - if tcx.any_free_region_meets(parent_substs, |r| *r == ty::ReStatic) { + if tcx.any_free_region_meets(parent_substs, |r| r.is_static()) { tcx.sess.struct_span_err(span, "cannot specialize on `'static` lifetime").emit(); } } diff --git a/compiler/rustc_typeck/src/mem_categorization.rs b/compiler/rustc_typeck/src/mem_categorization.rs index 2c2d2be8bb5..1bbd6d29294 100644 --- a/compiler/rustc_typeck/src/mem_categorization.rs +++ b/compiler/rustc_typeck/src/mem_categorization.rs @@ -192,7 +192,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { if let Some(vec) = self.typeck_results.pat_adjustments().get(pat.hir_id) { if let Some(first_ty) = vec.first() { debug!("pat_ty(pat={:?}) found adjusted ty `{:?}`", pat, first_ty); - return Ok(first_ty); + return Ok(*first_ty); } } @@ -562,7 +562,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { Res::Def(DefKind::Ctor(CtorOf::Struct, ..), _) | Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _) | Res::SelfCtor(..) - | Res::SelfTy(..) => { + | Res::SelfTy { .. } => { // Structs and Unions have only have one variant. Ok(VariantIdx::new(0)) } diff --git a/compiler/rustc_typeck/src/outlives/mod.rs b/compiler/rustc_typeck/src/outlives/mod.rs index 78a9cb33fba..139be8a42de 100644 --- a/compiler/rustc_typeck/src/outlives/mod.rs +++ b/compiler/rustc_typeck/src/outlives/mod.rs @@ -105,14 +105,14 @@ fn inferred_outlives_crate(tcx: TyCtxt<'_>, (): ()) -> CratePredicatesMap<'_> { match kind1.unpack() { GenericArgKind::Type(ty1) => Some(( ty::Binder::dummy(ty::PredicateKind::TypeOutlives( - ty::OutlivesPredicate(ty1, region2), + ty::OutlivesPredicate(ty1, *region2), )) .to_predicate(tcx), span, )), GenericArgKind::Lifetime(region1) => Some(( ty::Binder::dummy(ty::PredicateKind::RegionOutlives( - ty::OutlivesPredicate(region1, region2), + ty::OutlivesPredicate(region1, *region2), )) .to_predicate(tcx), span, diff --git a/compiler/rustc_typeck/src/outlives/utils.rs b/compiler/rustc_typeck/src/outlives/utils.rs index 76ae2ee4356..54a5037b575 100644 --- a/compiler/rustc_typeck/src/outlives/utils.rs +++ b/compiler/rustc_typeck/src/outlives/utils.rs @@ -1,6 +1,6 @@ use rustc_infer::infer::outlives::components::{push_outlives_components, Component}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; -use rustc_middle::ty::{self, Region, RegionKind, Ty, TyCtxt}; +use rustc_middle::ty::{self, Region, Ty, TyCtxt}; use rustc_span::Span; use smallvec::smallvec; use std::collections::BTreeMap; @@ -133,7 +133,7 @@ pub fn insert_outlives_predicate<'tcx>( fn is_free_region(tcx: TyCtxt<'_>, region: Region<'_>) -> bool { // First, screen for regions that might appear in a type header. - match region { + match *region { // These correspond to `T: 'a` relationships: // // struct Foo<'a, T> { @@ -141,7 +141,7 @@ fn is_free_region(tcx: TyCtxt<'_>, region: Region<'_>) -> bool { // } // // We care about these, so fall through. - RegionKind::ReEarlyBound(_) => true, + ty::ReEarlyBound(_) => true, // These correspond to `T: 'static` relationships which can be // rather surprising. We are therefore putting this behind a @@ -150,7 +150,7 @@ fn is_free_region(tcx: TyCtxt<'_>, region: Region<'_>) -> bool { // struct Foo<'a, T> { // field: &'static T, // this would generate a ReStatic // } - RegionKind::ReStatic => tcx.sess.features_untracked().infer_static_outlives_requirements, + ty::ReStatic => tcx.sess.features_untracked().infer_static_outlives_requirements, // Late-bound regions can appear in `fn` types: // @@ -160,19 +160,16 @@ fn is_free_region(tcx: TyCtxt<'_>, region: Region<'_>) -> bool { // // The type above might generate a `T: 'b` bound, but we can // ignore it. We can't put it on the struct header anyway. - RegionKind::ReLateBound(..) => false, + ty::ReLateBound(..) => false, // This can appear in `where Self: ` bounds (#64855): // // struct Bar<T>(<Self as Foo>::Type) where Self: ; // struct Baz<'a>(&'a Self) where Self: ; - RegionKind::ReEmpty(_) => false, + ty::ReEmpty(_) => false, // These regions don't appear in types from type declarations: - RegionKind::ReErased - | RegionKind::ReVar(..) - | RegionKind::RePlaceholder(..) - | RegionKind::ReFree(..) => { + ty::ReErased | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReFree(..) => { bug!("unexpected region in outlives inference: {:?}", region); } } diff --git a/compiler/rustc_typeck/src/variance/constraints.rs b/compiler/rustc_typeck/src/variance/constraints.rs index 7c504a0d89c..1c8f848cf28 100644 --- a/compiler/rustc_typeck/src/variance/constraints.rs +++ b/compiler/rustc_typeck/src/variance/constraints.rs @@ -401,12 +401,12 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { fn add_constraints_from_const( &mut self, current: &CurrentItem, - val: &ty::Const<'tcx>, + val: ty::Const<'tcx>, variance: VarianceTermPtr<'a>, ) { debug!("add_constraints_from_const(val={:?}, variance={:?})", val, variance); - match &val.val { + match &val.val() { ty::ConstKind::Unevaluated(uv) => { self.add_constraints_from_invariant_substs(current, uv.substs, variance); } 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/btree/map.rs b/library/alloc/src/collections/btree/map.rs index cdb961d4cfb..67f5b386ecd 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -2052,6 +2052,8 @@ where #[stable(feature = "std_collections_from_array", since = "1.56.0")] impl<K: Ord, V, const N: usize> From<[(K, V); N]> for BTreeMap<K, V> { + /// Converts a `[(K, V); N]` into a `BTreeMap<(K, V)>`. + /// /// ``` /// use std::collections::BTreeMap; /// diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index 31df4e98ed7..a4315be74e3 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -1097,6 +1097,8 @@ impl<T: Ord> FromIterator<T> for BTreeSet<T> { #[stable(feature = "std_collections_from_array", since = "1.56.0")] impl<T: Ord, const N: usize> From<[T; N]> for BTreeSet<T> { + /// Converts a `[T; N]` into a `BTreeSet<T>`. + /// /// ``` /// use std::collections::BTreeSet; /// diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index 4a07d5d4bed..d81f24e7202 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -1953,6 +1953,8 @@ impl<T: Hash> Hash for LinkedList<T> { #[stable(feature = "std_collections_from_array", since = "1.56.0")] impl<T, const N: usize> From<[T; N]> for LinkedList<T> { + /// Converts a `[T; N]` into a `LinkedList<T>`. + /// /// ``` /// use std::collections::LinkedList; /// diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index a8a18d65585..7139a0fb94d 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -1,4 +1,4 @@ -//! A double-ended queue implemented with a growable ring buffer. +//! A double-ended queue (deque) implemented with a growable ring buffer. //! //! This queue has *O*(1) amortized inserts and removals from both ends of the //! container. It also has *O*(1) indexing like a vector. The contained elements @@ -156,7 +156,7 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for VecDeque<T, A> { #[stable(feature = "rust1", since = "1.0.0")] impl<T> Default for VecDeque<T> { - /// Creates an empty `VecDeque<T>`. + /// Creates an empty deque. #[inline] fn default() -> VecDeque<T> { VecDeque::new() @@ -483,14 +483,14 @@ impl<T, A: Allocator> VecDeque<T, A> { } impl<T> VecDeque<T> { - /// Creates an empty `VecDeque`. + /// Creates an empty deque. /// /// # Examples /// /// ``` /// use std::collections::VecDeque; /// - /// let vector: VecDeque<u32> = VecDeque::new(); + /// let deque: VecDeque<u32> = VecDeque::new(); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -499,14 +499,14 @@ impl<T> VecDeque<T> { VecDeque::new_in(Global) } - /// Creates an empty `VecDeque` with space for at least `capacity` elements. + /// Creates an empty deque with space for at least `capacity` elements. /// /// # Examples /// /// ``` /// use std::collections::VecDeque; /// - /// let vector: VecDeque<u32> = VecDeque::with_capacity(10); + /// let deque: VecDeque<u32> = VecDeque::with_capacity(10); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -517,14 +517,14 @@ impl<T> VecDeque<T> { } impl<T, A: Allocator> VecDeque<T, A> { - /// Creates an empty `VecDeque`. + /// Creates an empty deque. /// /// # Examples /// /// ``` /// use std::collections::VecDeque; /// - /// let vector: VecDeque<u32> = VecDeque::new(); + /// let deque: VecDeque<u32> = VecDeque::new(); /// ``` #[inline] #[unstable(feature = "allocator_api", issue = "32838")] @@ -532,14 +532,14 @@ impl<T, A: Allocator> VecDeque<T, A> { VecDeque::with_capacity_in(INITIAL_CAPACITY, alloc) } - /// Creates an empty `VecDeque` with space for at least `capacity` elements. + /// Creates an empty deque with space for at least `capacity` elements. /// /// # Examples /// /// ``` /// use std::collections::VecDeque; /// - /// let vector: VecDeque<u32> = VecDeque::with_capacity(10); + /// let deque: VecDeque<u32> = VecDeque::with_capacity(10); /// ``` #[unstable(feature = "allocator_api", issue = "32838")] pub fn with_capacity_in(capacity: usize, alloc: A) -> VecDeque<T, A> { @@ -636,7 +636,7 @@ impl<T, A: Allocator> VecDeque<T, A> { unsafe { ptr::swap(self.ptr().add(ri), self.ptr().add(rj)) } } - /// Returns the number of elements the `VecDeque` can hold without + /// Returns the number of elements the deque can hold without /// reallocating. /// /// # Examples @@ -654,7 +654,7 @@ impl<T, A: Allocator> VecDeque<T, A> { } /// Reserves the minimum capacity for exactly `additional` more elements to be inserted in the - /// given `VecDeque`. Does nothing if the capacity is already sufficient. + /// given deque. Does nothing if the capacity is already sufficient. /// /// Note that the allocator may give the collection more space than it requests. Therefore /// capacity can not be relied upon to be precisely minimal. Prefer [`reserve`] if future @@ -681,7 +681,7 @@ impl<T, A: Allocator> VecDeque<T, A> { } /// Reserves capacity for at least `additional` more elements to be inserted in the given - /// `VecDeque`. The collection may reserve more space to avoid frequent reallocations. + /// deque. The collection may reserve more space to avoid frequent reallocations. /// /// # Panics /// @@ -714,7 +714,7 @@ impl<T, A: Allocator> VecDeque<T, A> { } /// Tries to reserve the minimum capacity for exactly `additional` more elements to - /// be inserted in the given `VecDeque<T>`. After calling `try_reserve_exact`, + /// be inserted in the given deque. After calling `try_reserve_exact`, /// capacity will be greater than or equal to `self.len() + additional`. /// Does nothing if the capacity is already sufficient. /// @@ -756,7 +756,7 @@ impl<T, A: Allocator> VecDeque<T, A> { } /// Tries to reserve capacity for at least `additional` more elements to be inserted - /// in the given `VecDeque<T>`. The collection may reserve more space to avoid + /// in the given deque. The collection may reserve more space to avoid /// frequent reallocations. After calling `try_reserve`, capacity will be /// greater than or equal to `self.len() + additional`. Does nothing if /// capacity is already sufficient. @@ -805,10 +805,10 @@ impl<T, A: Allocator> VecDeque<T, A> { Ok(()) } - /// Shrinks the capacity of the `VecDeque` as much as possible. + /// Shrinks the capacity of the deque as much as possible. /// /// It will drop down as close as possible to the length but the allocator may still inform the - /// `VecDeque` that there is space for a few more elements. + /// deque that there is space for a few more elements. /// /// # Examples /// @@ -826,7 +826,7 @@ impl<T, A: Allocator> VecDeque<T, A> { self.shrink_to(0); } - /// Shrinks the capacity of the `VecDeque` with a lower bound. + /// Shrinks the capacity of the deque with a lower bound. /// /// The capacity will remain at least as large as both the length /// and the supplied value. @@ -909,10 +909,10 @@ impl<T, A: Allocator> VecDeque<T, A> { } } - /// Shortens the `VecDeque`, keeping the first `len` elements and dropping + /// Shortens the deque, keeping the first `len` elements and dropping /// the rest. /// - /// If `len` is greater than the `VecDeque`'s current length, this has no + /// If `len` is greater than the deque's current length, this has no /// effect. /// /// # Examples @@ -1027,10 +1027,10 @@ impl<T, A: Allocator> VecDeque<T, A> { } /// Returns a pair of slices which contain, in order, the contents of the - /// `VecDeque`. + /// deque. /// /// If [`make_contiguous`] was previously called, all elements of the - /// `VecDeque` will be in the first slice and the second slice will be empty. + /// deque will be in the first slice and the second slice will be empty. /// /// [`make_contiguous`]: VecDeque::make_contiguous /// @@ -1039,18 +1039,18 @@ impl<T, A: Allocator> VecDeque<T, A> { /// ``` /// use std::collections::VecDeque; /// - /// let mut vector = VecDeque::new(); + /// let mut deque = VecDeque::new(); /// - /// vector.push_back(0); - /// vector.push_back(1); - /// vector.push_back(2); + /// deque.push_back(0); + /// deque.push_back(1); + /// deque.push_back(2); /// - /// assert_eq!(vector.as_slices(), (&[0, 1, 2][..], &[][..])); + /// assert_eq!(deque.as_slices(), (&[0, 1, 2][..], &[][..])); /// - /// vector.push_front(10); - /// vector.push_front(9); + /// deque.push_front(10); + /// deque.push_front(9); /// - /// assert_eq!(vector.as_slices(), (&[9, 10][..], &[0, 1, 2][..])); + /// assert_eq!(deque.as_slices(), (&[9, 10][..], &[0, 1, 2][..])); /// ``` #[inline] #[stable(feature = "deque_extras_15", since = "1.5.0")] @@ -1062,10 +1062,10 @@ impl<T, A: Allocator> VecDeque<T, A> { } /// Returns a pair of slices which contain, in order, the contents of the - /// `VecDeque`. + /// deque. /// /// If [`make_contiguous`] was previously called, all elements of the - /// `VecDeque` will be in the first slice and the second slice will be empty. + /// deque will be in the first slice and the second slice will be empty. /// /// [`make_contiguous`]: VecDeque::make_contiguous /// @@ -1074,17 +1074,17 @@ impl<T, A: Allocator> VecDeque<T, A> { /// ``` /// use std::collections::VecDeque; /// - /// let mut vector = VecDeque::new(); + /// let mut deque = VecDeque::new(); /// - /// vector.push_back(0); - /// vector.push_back(1); + /// deque.push_back(0); + /// deque.push_back(1); /// - /// vector.push_front(10); - /// vector.push_front(9); + /// deque.push_front(10); + /// deque.push_front(9); /// - /// vector.as_mut_slices().0[0] = 42; - /// vector.as_mut_slices().1[0] = 24; - /// assert_eq!(vector.as_slices(), (&[42, 10][..], &[24, 1][..])); + /// deque.as_mut_slices().0[0] = 42; + /// deque.as_mut_slices().1[0] = 24; + /// assert_eq!(deque.as_slices(), (&[42, 10][..], &[24, 1][..])); /// ``` #[inline] #[stable(feature = "deque_extras_15", since = "1.5.0")] @@ -1097,34 +1097,34 @@ impl<T, A: Allocator> VecDeque<T, A> { } } - /// Returns the number of elements in the `VecDeque`. + /// Returns the number of elements in the deque. /// /// # Examples /// /// ``` /// use std::collections::VecDeque; /// - /// let mut v = VecDeque::new(); - /// assert_eq!(v.len(), 0); - /// v.push_back(1); - /// assert_eq!(v.len(), 1); + /// let mut deque = VecDeque::new(); + /// assert_eq!(deque.len(), 0); + /// deque.push_back(1); + /// assert_eq!(deque.len(), 1); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn len(&self) -> usize { count(self.tail, self.head, self.cap()) } - /// Returns `true` if the `VecDeque` is empty. + /// Returns `true` if the deque is empty. /// /// # Examples /// /// ``` /// use std::collections::VecDeque; /// - /// let mut v = VecDeque::new(); - /// assert!(v.is_empty()); - /// v.push_front(1); - /// assert!(!v.is_empty()); + /// let mut deque = VecDeque::new(); + /// assert!(deque.is_empty()); + /// deque.push_front(1); + /// assert!(!deque.is_empty()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn is_empty(&self) -> bool { @@ -1141,24 +1141,24 @@ impl<T, A: Allocator> VecDeque<T, A> { (tail, head) } - /// Creates an iterator that covers the specified range in the `VecDeque`. + /// Creates an iterator that covers the specified range in the deque. /// /// # 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. + /// the end point is greater than the length of the deque. /// /// # Examples /// /// ``` /// use std::collections::VecDeque; /// - /// let v: VecDeque<_> = [1, 2, 3].into(); - /// let range = v.range(2..).copied().collect::<VecDeque<_>>(); + /// let deque: VecDeque<_> = [1, 2, 3].into(); + /// let range = deque.range(2..).copied().collect::<VecDeque<_>>(); /// assert_eq!(range, [3]); /// /// // A full range covers all contents - /// let all = v.range(..); + /// let all = deque.range(..); /// assert_eq!(all.len(), 3); /// ``` #[inline] @@ -1176,29 +1176,29 @@ impl<T, A: Allocator> VecDeque<T, A> { } } - /// Creates an iterator that covers the specified mutable range in the `VecDeque`. + /// Creates an iterator that covers the specified mutable range in the deque. /// /// # 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. + /// the end point is greater than the length of the deque. /// /// # Examples /// /// ``` /// use std::collections::VecDeque; /// - /// let mut v: VecDeque<_> = [1, 2, 3].into(); - /// for v in v.range_mut(2..) { + /// let mut deque: VecDeque<_> = [1, 2, 3].into(); + /// for v in deque.range_mut(2..) { /// *v *= 2; /// } - /// assert_eq!(v, [1, 2, 6]); + /// assert_eq!(deque, [1, 2, 6]); /// /// // A full range covers all contents - /// for v in v.range_mut(..) { + /// for v in deque.range_mut(..) { /// *v *= 2; /// } - /// assert_eq!(v, [2, 4, 12]); + /// assert_eq!(deque, [2, 4, 12]); /// ``` #[inline] #[stable(feature = "deque_range", since = "1.51.0")] @@ -1215,34 +1215,38 @@ 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 - /// `VecDeque` 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 vector. + /// 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 /// /// ``` /// use std::collections::VecDeque; /// - /// let mut v: VecDeque<_> = [1, 2, 3].into(); - /// let drained = v.drain(2..).collect::<VecDeque<_>>(); + /// let mut deque: VecDeque<_> = [1, 2, 3].into(); + /// let drained = deque.drain(2..).collect::<VecDeque<_>>(); /// assert_eq!(drained, [3]); - /// assert_eq!(v, [1, 2]); + /// assert_eq!(deque, [1, 2]); /// - /// // A full range clears all contents - /// v.drain(..); - /// assert!(v.is_empty()); + /// // A full range clears all contents, like `clear()` does + /// deque.drain(..); + /// assert!(deque.is_empty()); /// ``` #[inline] #[stable(feature = "drain", since = "1.6.0")] @@ -1297,17 +1301,17 @@ impl<T, A: Allocator> VecDeque<T, A> { unsafe { Drain::new(drain_head, head, iter, deque) } } - /// Clears the `VecDeque`, removing all values. + /// Clears the deque, removing all values. /// /// # Examples /// /// ``` /// use std::collections::VecDeque; /// - /// let mut v = VecDeque::new(); - /// v.push_back(1); - /// v.clear(); - /// assert!(v.is_empty()); + /// let mut deque = VecDeque::new(); + /// deque.push_back(1); + /// deque.clear(); + /// assert!(deque.is_empty()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1315,7 +1319,7 @@ impl<T, A: Allocator> VecDeque<T, A> { self.truncate(0); } - /// Returns `true` if the `VecDeque` contains an element equal to the + /// Returns `true` if the deque contains an element equal to the /// given value. /// /// # Examples @@ -1323,13 +1327,13 @@ impl<T, A: Allocator> VecDeque<T, A> { /// ``` /// use std::collections::VecDeque; /// - /// let mut vector: VecDeque<u32> = VecDeque::new(); + /// let mut deque: VecDeque<u32> = VecDeque::new(); /// - /// vector.push_back(0); - /// vector.push_back(1); + /// deque.push_back(0); + /// deque.push_back(1); /// - /// assert_eq!(vector.contains(&1), true); - /// assert_eq!(vector.contains(&10), false); + /// assert_eq!(deque.contains(&1), true); + /// assert_eq!(deque.contains(&10), false); /// ``` #[stable(feature = "vec_deque_contains", since = "1.12.0")] pub fn contains(&self, x: &T) -> bool @@ -1340,7 +1344,7 @@ impl<T, A: Allocator> VecDeque<T, A> { a.contains(x) || b.contains(x) } - /// Provides a reference to the front element, or `None` if the `VecDeque` is + /// Provides a reference to the front element, or `None` if the deque is /// empty. /// /// # Examples @@ -1361,7 +1365,7 @@ impl<T, A: Allocator> VecDeque<T, A> { } /// Provides a mutable reference to the front element, or `None` if the - /// `VecDeque` is empty. + /// deque is empty. /// /// # Examples /// @@ -1384,7 +1388,7 @@ impl<T, A: Allocator> VecDeque<T, A> { self.get_mut(0) } - /// Provides a reference to the back element, or `None` if the `VecDeque` is + /// Provides a reference to the back element, or `None` if the deque is /// empty. /// /// # Examples @@ -1405,7 +1409,7 @@ impl<T, A: Allocator> VecDeque<T, A> { } /// Provides a mutable reference to the back element, or `None` if the - /// `VecDeque` is empty. + /// deque is empty. /// /// # Examples /// @@ -1428,7 +1432,7 @@ impl<T, A: Allocator> VecDeque<T, A> { self.get_mut(self.len().wrapping_sub(1)) } - /// Removes the first element and returns it, or `None` if the `VecDeque` is + /// Removes the first element and returns it, or `None` if the deque is /// empty. /// /// # Examples @@ -1455,7 +1459,7 @@ impl<T, A: Allocator> VecDeque<T, A> { } } - /// Removes the last element from the `VecDeque` and returns it, or `None` if + /// Removes the last element from the deque and returns it, or `None` if /// it is empty. /// /// # Examples @@ -1480,7 +1484,7 @@ impl<T, A: Allocator> VecDeque<T, A> { } } - /// Prepends an element to the `VecDeque`. + /// Prepends an element to the deque. /// /// # Examples /// @@ -1505,7 +1509,7 @@ impl<T, A: Allocator> VecDeque<T, A> { } } - /// Appends an element to the back of the `VecDeque`. + /// Appends an element to the back of the deque. /// /// # Examples /// @@ -1535,7 +1539,7 @@ impl<T, A: Allocator> VecDeque<T, A> { self.tail <= self.head } - /// Removes an element from anywhere in the `VecDeque` and returns it, + /// Removes an element from anywhere in the deque and returns it, /// replacing it with the first element. /// /// This does not preserve ordering, but is *O*(1). @@ -1570,8 +1574,8 @@ impl<T, A: Allocator> VecDeque<T, A> { self.pop_front() } - /// Removes an element from anywhere in the `VecDeque` and returns it, replacing it with the - /// last element. + /// Removes an element from anywhere in the deque and returns it, + /// replacing it with the last element. /// /// This does not preserve ordering, but is *O*(1). /// @@ -1605,14 +1609,14 @@ impl<T, A: Allocator> VecDeque<T, A> { self.pop_back() } - /// Inserts an element at `index` within the `VecDeque`, shifting all elements with indices - /// greater than or equal to `index` towards the back. + /// Inserts an element at `index` within the deque, shifting all elements + /// with indices greater than or equal to `index` towards the back. /// /// Element at index 0 is the front of the queue. /// /// # Panics /// - /// Panics if `index` is greater than `VecDeque`'s length + /// Panics if `index` is greater than deque's length /// /// # Examples /// @@ -1829,7 +1833,7 @@ impl<T, A: Allocator> VecDeque<T, A> { } } - /// Removes and returns the element at `index` from the `VecDeque`. + /// Removes and returns the element at `index` from the deque. /// Whichever end is closer to the removal point will be moved to make /// room, and all the affected elements will be moved to new positions. /// Returns `None` if `index` is out of bounds. @@ -2007,10 +2011,10 @@ impl<T, A: Allocator> VecDeque<T, A> { elem } - /// Splits the `VecDeque` into two at the given index. + /// Splits the deque into two at the given index. /// /// Returns a newly allocated `VecDeque`. `self` contains elements `[0, at)`, - /// and the returned `VecDeque` contains elements `[at, len)`. + /// and the returned deque contains elements `[at, len)`. /// /// Note that the capacity of `self` does not change. /// @@ -2227,7 +2231,7 @@ impl<T, A: Allocator> VecDeque<T, A> { debug_assert!(!self.is_full()); } - /// Modifies the `VecDeque` in-place so that `len()` is equal to `new_len`, + /// Modifies the deque in-place so that `len()` is equal to `new_len`, /// either by removing excess elements from the back or by appending /// elements generated by calling `generator` to the back. /// @@ -2272,7 +2276,7 @@ impl<T, A: Allocator> VecDeque<T, A> { /// /// Once the internal storage is contiguous, the [`as_slices`] and /// [`as_mut_slices`] methods will return the entire contents of the - /// `VecDeque` in a single slice. + /// deque in a single slice. /// /// [`as_slices`]: VecDeque::as_slices /// [`as_mut_slices`]: VecDeque::as_mut_slices @@ -2524,7 +2528,7 @@ impl<T, A: Allocator> VecDeque<T, A> { } } - /// Binary searches this sorted `VecDeque` for a given element. + /// Binary searches the sorted deque for a given element. /// /// If the value is found then [`Result::Ok`] is returned, containing the /// index of the matching element. If there are multiple matches, then any @@ -2556,7 +2560,7 @@ impl<T, A: Allocator> VecDeque<T, A> { /// assert!(matches!(r, Ok(1..=4))); /// ``` /// - /// If you want to insert an item to a sorted `VecDeque`, while maintaining + /// If you want to insert an item to a sorted deque, while maintaining /// sort order: /// /// ``` @@ -2577,12 +2581,12 @@ impl<T, A: Allocator> VecDeque<T, A> { self.binary_search_by(|e| e.cmp(x)) } - /// Binary searches this sorted `VecDeque` with a comparator function. + /// Binary searches the sorted deque with a comparator function. /// /// The comparator function should implement an order consistent - /// with the sort order of the underlying `VecDeque`, returning an - /// order code that indicates whether its argument is `Less`, - /// `Equal` or `Greater` than the desired target. + /// with the sort order of the deque, returning an order code that + /// indicates whether its argument is `Less`, `Equal` or `Greater` + /// than the desired target. /// /// If the value is found then [`Result::Ok`] is returned, containing the /// index of the matching element. If there are multiple matches, then any @@ -2630,9 +2634,9 @@ impl<T, A: Allocator> VecDeque<T, A> { } } - /// Binary searches this sorted `VecDeque` with a key extraction function. + /// Binary searches the sorted deque with a key extraction function. /// - /// Assumes that the `VecDeque` is sorted by the key, for instance with + /// Assumes that the deque is sorted by the key, for instance with /// [`make_contiguous().sort_by_key()`] using the same key extraction function. /// /// If the value is found then [`Result::Ok`] is returned, containing the @@ -2687,7 +2691,7 @@ impl<T, A: Allocator> VecDeque<T, A> { /// For example, [7, 15, 3, 5, 4, 12, 6] is a partitioned under the predicate x % 2 != 0 /// (all odd numbers are at the start, all even at the end). /// - /// If this deque is not partitioned, the returned result is unspecified and meaningless, + /// If the deque is not partitioned, the returned result is unspecified and meaningless, /// as this method performs a kind of binary search. /// /// See also [`binary_search`], [`binary_search_by`], and [`binary_search_by_key`]. @@ -2724,7 +2728,7 @@ impl<T, A: Allocator> VecDeque<T, A> { } impl<T: Clone, A: Allocator> VecDeque<T, A> { - /// Modifies the `VecDeque` in-place so that `len()` is equal to new_len, + /// Modifies the deque in-place so that `len()` is equal to new_len, /// either by removing excess elements from the back or by appending clones of `value` /// to the back. /// @@ -2878,7 +2882,7 @@ impl<T, A: Allocator> IntoIterator for VecDeque<T, A> { type Item = T; type IntoIter = IntoIter<T, A>; - /// Consumes the `VecDeque` into a front-to-back iterator yielding elements by + /// Consumes the deque into a front-to-back iterator yielding elements by /// value. fn into_iter(self) -> IntoIter<T, A> { IntoIter::new(self) @@ -3049,6 +3053,8 @@ impl<T, A: Allocator> From<VecDeque<T, A>> for Vec<T, A> { #[stable(feature = "std_collections_from_array", since = "1.56.0")] impl<T, const N: usize> From<[T; N]> for VecDeque<T> { + /// Converts a `[T; N]` into a `VecDeque<T>`. + /// /// ``` /// use std::collections::VecDeque; /// 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 bd3262b51d4..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, &[]); /// ``` @@ -2906,10 +2911,6 @@ impl<T: Clone> From<&mut [T]> for Vec<T> { #[cfg(not(no_global_oom_handling))] #[stable(feature = "vec_from_array", since = "1.44.0")] impl<T, const N: usize> From<[T; N]> for Vec<T> { - #[cfg(not(test))] - fn from(s: [T; N]) -> Vec<T> { - <[T]>::into_vec(box s) - } /// Allocate a `Vec<T>` and move `s`'s items into it. /// /// # Examples @@ -2917,6 +2918,11 @@ impl<T, const N: usize> From<[T; N]> for Vec<T> { /// ``` /// assert_eq!(Vec::from([1, 2, 3]), vec![1, 2, 3]); /// ``` + #[cfg(not(test))] + fn from(s: [T; N]) -> Vec<T> { + <[T]>::into_vec(box s) + } + #[cfg(test)] fn from(s: [T; N]) -> Vec<T> { crate::slice::into_vec(box s) 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/cell.rs b/library/core/src/cell.rs index feb94555658..aef7ad77568 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -315,6 +315,7 @@ impl<T: Ord + Copy> Ord for Cell<T> { #[stable(feature = "cell_from", since = "1.12.0")] #[rustc_const_unstable(feature = "const_convert", issue = "88674")] impl<T> const From<T> for Cell<T> { + /// Creates a new `Cell<T>` containing the given value. fn from(t: T) -> Cell<T> { Cell::new(t) } @@ -1244,6 +1245,7 @@ impl<T: ?Sized + Ord> Ord for RefCell<T> { #[stable(feature = "cell_from", since = "1.12.0")] #[rustc_const_unstable(feature = "const_convert", issue = "88674")] impl<T> const From<T> for RefCell<T> { + /// Creates a new `RefCell<T>` containing the given value. fn from(t: T) -> RefCell<T> { RefCell::new(t) } @@ -1979,6 +1981,7 @@ impl<T: Default> Default for UnsafeCell<T> { #[stable(feature = "cell_from", since = "1.12.0")] #[rustc_const_unstable(feature = "const_convert", issue = "88674")] impl<T> const From<T> for UnsafeCell<T> { + /// Creates a new `UnsafeCell<T>` containing the given value. fn from(t: T) -> UnsafeCell<T> { UnsafeCell::new(t) } diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 5566c2ffe87..0ceedf93633 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -538,6 +538,10 @@ impl<T, U> const Into<U> for T where U: ~const From<T>, { + /// Calls `U::from(self)`. + /// + /// That is, this conversion is whatever the implementation of + /// <code>[From]<T> for U</code> chooses to do. fn into(self) -> U { U::from(self) } @@ -547,6 +551,7 @@ where #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_convert", issue = "88674")] impl<T> const From<T> for T { + /// Returns the argument unchanged. fn from(t: T) -> T { t } 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/lazy.rs b/library/core/src/lazy.rs index 788f0cce01b..88826782a3d 100644 --- a/library/core/src/lazy.rs +++ b/library/core/src/lazy.rs @@ -75,6 +75,7 @@ impl<T: Eq> Eq for OnceCell<T> {} #[unstable(feature = "once_cell", issue = "74465")] impl<T> const From<T> for OnceCell<T> { + /// Creates a new `OnceCell<T>` which already contains the given `value`. fn from(value: T) -> Self { OnceCell { inner: UnsafeCell::new(Some(value)) } } diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 72d8e1b3903..aa1ad9362a9 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -155,7 +155,7 @@ #![feature(allow_internal_unstable)] #![feature(associated_type_bounds)] #![feature(auto_traits)] -#![cfg_attr(bootstrap, feature(cfg_target_has_atomic))] +#![feature(cfg_target_has_atomic)] #![cfg_attr(not(bootstrap), feature(cfg_target_has_atomic_equal_alignment))] #![feature(const_fn_floating_point_arithmetic)] #![feature(const_fn_fn_ptr_basics)] @@ -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/src/pin.rs b/library/core/src/pin.rs index 09fc6df5429..dec1b5270d5 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -406,7 +406,14 @@ use crate::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn, Receiver}; #[repr(transparent)] #[derive(Copy, Clone)] pub struct Pin<P> { - pointer: P, + // FIXME(#93176): this field is made `#[unstable] #[doc(hidden)] pub` to: + // - deter downstream users from accessing it (which would be unsound!), + // - let the `pin!` macro access it (such a macro requires using struct + // literal syntax in order to benefit from lifetime extension). + // Long-term, `unsafe` fields or macro hygiene are expected to offer more robust alternatives. + #[unstable(feature = "unsafe_pin_internals", issue = "none")] + #[doc(hidden)] + pub pointer: P, } // The following implementations aren't derived in order to avoid soundness @@ -909,3 +916,243 @@ impl<P, U> CoerceUnsized<Pin<U>> for Pin<P> where P: CoerceUnsized<U> {} #[stable(feature = "pin", since = "1.33.0")] impl<P, U> DispatchFromDyn<Pin<U>> for Pin<P> where P: DispatchFromDyn<U> {} + +/// Constructs a <code>[Pin]<[&mut] T></code>, by pinning[^1] a `value: T` _locally_[^2]. +/// +/// Unlike [`Box::pin`], this does not involve a heap allocation. +/// +/// [^1]: If the (type `T` of the) given value does not implement [`Unpin`], then this +/// effectively pins the `value` in memory, where it will be unable to be moved. +/// Otherwise, <code>[Pin]<[&mut] T></code> behaves like <code>[&mut] T</code>, and operations such +/// as [`mem::replace()`][crate::mem::replace] will allow extracting that value, and therefore, +/// moving it. +/// See [the `Unpin` section of the `pin` module][self#unpin] for more info. +/// +/// [^2]: This is usually dubbed "stack"-pinning. And whilst local values are almost always located +/// in the stack (_e.g._, when within the body of a non-`async` function), the truth is that inside +/// the body of an `async fn` or block —more generally, the body of a generator— any locals crossing +/// an `.await` point —a `yield` point— end up being part of the state captured by the `Future` —by +/// the `Generator`—, and thus will be stored wherever that one is. +/// +/// ## Examples +/// +/// ### Basic usage +/// +/// ```rust +/// #![feature(pin_macro)] +/// # use core::marker::PhantomPinned as Foo; +/// use core::pin::{pin, Pin}; +/// +/// fn stuff(foo: Pin<&mut Foo>) { +/// // … +/// # let _ = foo; +/// } +/// +/// let pinned_foo = pin!(Foo { /* … */ }); +/// stuff(pinned_foo); +/// // or, directly: +/// stuff(pin!(Foo { /* … */ })); +/// ``` +/// +/// ### Manually polling a `Future` (wihout `Unpin` bounds) +/// +/// ```rust +/// #![feature(pin_macro)] +/// use std::{ +/// future::Future, +/// pin::pin, +/// task::{Context, Poll}, +/// thread, +/// }; +/// # use std::{sync::Arc, task::Wake, thread::Thread}; +/// +/// # /// A waker that wakes up the current thread when called. +/// # struct ThreadWaker(Thread); +/// # +/// # impl Wake for ThreadWaker { +/// # fn wake(self: Arc<Self>) { +/// # self.0.unpark(); +/// # } +/// # } +/// # +/// /// Runs a future to completion. +/// fn block_on<Fut: Future>(fut: Fut) -> Fut::Output { +/// let waker_that_unparks_thread = // … +/// # Arc::new(ThreadWaker(thread::current())).into(); +/// let mut cx = Context::from_waker(&waker_that_unparks_thread); +/// // Pin the future so it can be polled. +/// let mut pinned_fut = pin!(fut); +/// loop { +/// match pinned_fut.as_mut().poll(&mut cx) { +/// Poll::Pending => thread::park(), +/// Poll::Ready(res) => return res, +/// } +/// } +/// } +/// # +/// # assert_eq!(42, block_on(async { 42 })); +/// ``` +/// +/// ### With `Generator`s +/// +/// ```rust +/// #![feature(generators, generator_trait, pin_macro)] +/// use core::{ +/// ops::{Generator, GeneratorState}, +/// pin::pin, +/// }; +/// +/// fn generator_fn() -> impl Generator<Yield = usize, Return = ()> /* not Unpin */ { +/// // Allow generator to be self-referential (not `Unpin`) +/// // vvvvvv so that locals can cross yield points. +/// static || { +/// let foo = String::from("foo"); // --+ +/// yield 0; // | <- crosses yield point! +/// println!("{}", &foo); // <----------+ +/// yield foo.len(); +/// } +/// } +/// +/// fn main() { +/// let mut generator = pin!(generator_fn()); +/// match generator.as_mut().resume(()) { +/// GeneratorState::Yielded(0) => {}, +/// _ => unreachable!(), +/// } +/// match generator.as_mut().resume(()) { +/// GeneratorState::Yielded(3) => {}, +/// _ => unreachable!(), +/// } +/// match generator.resume(()) { +/// GeneratorState::Yielded(_) => unreachable!(), +/// GeneratorState::Complete(()) => {}, +/// } +/// } +/// ``` +/// +/// ## Remarks +/// +/// Precisely because a value is pinned to local storage, the resulting <code>[Pin]<[&mut] T></code> +/// reference ends up borrowing a local tied to that block: it can't escape it. +/// +/// The following, for instance, fails to compile: +/// +/// ```rust,compile_fail +/// #![feature(pin_macro)] +/// use core::pin::{pin, Pin}; +/// # use core::{marker::PhantomPinned as Foo, mem::drop as stuff}; +/// +/// let x: Pin<&mut Foo> = { +/// let x: Pin<&mut Foo> = pin!(Foo { /* … */ }); +/// x +/// }; // <- Foo is dropped +/// stuff(x); // Error: use of dropped value +/// ``` +/// +/// <details><summary>Error message</summary> +/// +/// ```console +/// error[E0716]: temporary value dropped while borrowed +/// --> src/main.rs:9:28 +/// | +/// 8 | let x: Pin<&mut Foo> = { +/// | - borrow later stored here +/// 9 | let x: Pin<&mut Foo> = pin!(Foo { /* … */ }); +/// | ^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +/// 10 | x +/// 11 | }; // <- Foo is dropped +/// | - temporary value is freed at the end of this statement +/// | +/// = note: consider using a `let` binding to create a longer lived value +/// ``` +/// +/// </details> +/// +/// This makes [`pin!`] **unsuitable to pin values when intending to _return_ them**. Instead, the +/// value is expected to be passed around _unpinned_ until the point where it is to be consumed, +/// where it is then useful and even sensible to pin the value locally using [`pin!`]. +/// +/// If you really need to return a pinned value, consider using [`Box::pin`] instead. +/// +/// On the other hand, pinning to the stack[<sup>2</sup>](#fn2) using [`pin!`] is likely to be +/// cheaper than pinning into a fresh heap allocation using [`Box::pin`]. Moreover, by virtue of not +/// even needing an allocator, [`pin!`] is the main non-`unsafe` `#![no_std]`-compatible [`Pin`] +/// constructor. +/// +/// [`Box::pin`]: ../../std/boxed/struct.Box.html#method.pin +#[unstable(feature = "pin_macro", issue = "93178")] +#[rustc_macro_transparency = "semitransparent"] +#[allow_internal_unstable(unsafe_pin_internals)] +pub macro pin($value:expr $(,)?) { + // This is `Pin::new_unchecked(&mut { $value })`, so, for starters, let's + // review such a hypothetical macro (that any user-code could define): + // + // ```rust + // macro_rules! pin {( $value:expr ) => ( + // match &mut { $value } { at_value => unsafe { // Do not wrap `$value` in an `unsafe` block. + // $crate::pin::Pin::<&mut _>::new_unchecked(at_value) + // }} + // )} + // ``` + // + // Safety: + // - `type P = &mut _`. There are thus no pathological `Deref{,Mut}` impls + // that would break `Pin`'s invariants. + // - `{ $value }` is braced, making it a _block expression_, thus **moving** + // the given `$value`, and making it _become an **anonymous** temporary_. + // By virtue of being anonynomous, it can no longer be accessed, thus + // preventing any attemps to `mem::replace` it or `mem::forget` it, _etc._ + // + // This gives us a `pin!` definition that is sound, and which works, but only + // in certain scenarios: + // - If the `pin!(value)` expression is _directly_ fed to a function call: + // `let poll = pin!(fut).poll(cx);` + // - If the `pin!(value)` expression is part of a scrutinee: + // ```rust + // match pin!(fut) { pinned_fut => { + // pinned_fut.as_mut().poll(...); + // pinned_fut.as_mut().poll(...); + // }} // <- `fut` is dropped here. + // ``` + // Alas, it doesn't work for the more straight-forward use-case: `let` bindings. + // ```rust + // let pinned_fut = pin!(fut); // <- temporary value is freed at the end of this statement + // pinned_fut.poll(...) // error[E0716]: temporary value dropped while borrowed + // // note: consider using a `let` binding to create a longer lived value + // ``` + // - Issues such as this one are the ones motivating https://github.com/rust-lang/rfcs/pull/66 + // + // This makes such a macro incredibly unergonomic in practice, and the reason most macros + // out there had to take the path of being a statement/binding macro (_e.g._, `pin!(future);`) + // instead of featuring the more intuitive ergonomics of an expression macro. + // + // Luckily, there is a way to avoid the problem. Indeed, the problem stems from the fact that a + // temporary is dropped at the end of its enclosing statement when it is part of the parameters + // given to function call, which has precisely been the case with our `Pin::new_unchecked()`! + // For instance, + // ```rust + // let p = Pin::new_unchecked(&mut <temporary>); + // ``` + // becomes: + // ```rust + // let p = { let mut anon = <temporary>; &mut anon }; + // ``` + // + // However, when using a literal braced struct to construct the value, references to temporaries + // can then be taken. This makes Rust change the lifespan of such temporaries so that they are, + // instead, dropped _at the end of the enscoping block_. + // For instance, + // ```rust + // let p = Pin { pointer: &mut <temporary> }; + // ``` + // becomes: + // ```rust + // let mut anon = <temporary>; + // let p = Pin { pointer: &mut anon }; + // ``` + // which is *exactly* what we want. + // + // See https://doc.rust-lang.org/1.58.1/reference/destructors.html#temporary-lifetime-extension + // for more info. + $crate::pin::Pin::<&mut _> { pointer: &mut { $value } } +} diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 3f5d3f62c96..0aa8e9960a8 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -721,6 +721,9 @@ impl<T: ?Sized> const From<Unique<T>> for NonNull<T> { #[stable(feature = "nonnull", since = "1.25.0")] #[rustc_const_unstable(feature = "const_convert", issue = "88674")] impl<T: ?Sized> const From<&mut T> for NonNull<T> { + /// Converts a `&mut T` to a `NonNull<T>`. + /// + /// This conversion is safe and infallible since references cannot be null. #[inline] fn from(reference: &mut T) -> Self { // SAFETY: A mutable reference cannot be null. @@ -731,6 +734,9 @@ impl<T: ?Sized> const From<&mut T> for NonNull<T> { #[stable(feature = "nonnull", since = "1.25.0")] #[rustc_const_unstable(feature = "const_convert", issue = "88674")] impl<T: ?Sized> const From<&T> for NonNull<T> { + /// Converts a `&T` to a `NonNull<T>`. + /// + /// This conversion is safe and infallible since references cannot be null. #[inline] fn from(reference: &T) -> Self { // SAFETY: A reference cannot be null, so the conditions for diff --git a/library/core/src/ptr/unique.rs b/library/core/src/ptr/unique.rs index f5c624c225f..661d111c99d 100644 --- a/library/core/src/ptr/unique.rs +++ b/library/core/src/ptr/unique.rs @@ -178,6 +178,9 @@ impl<T: ?Sized> fmt::Pointer for Unique<T> { #[unstable(feature = "ptr_internals", issue = "none")] impl<T: ?Sized> const From<&mut T> for Unique<T> { + /// Converts a `&mut T` to a `Unique<T>`. + /// + /// This conversion is infallible since references cannot be null. #[inline] fn from(reference: &mut T) -> Self { // SAFETY: A mutable reference cannot be null diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs index 72af47c71dd..27c6b6f5bc0 100644 --- a/library/core/src/slice/cmp.rs +++ b/library/core/src/slice/cmp.rs @@ -1,7 +1,6 @@ //! Comparison traits for `[T]`. -use crate::cmp; -use crate::cmp::Ordering::{self, Greater, Less}; +use crate::cmp::{self, Ordering}; use crate::mem; use super::from_raw_parts; @@ -189,18 +188,18 @@ impl<A: Ord> SliceOrd for A { impl SliceOrd for u8 { #[inline] fn compare(left: &[Self], right: &[Self]) -> Ordering { - let order = - // SAFETY: `left` and `right` are references and are thus guaranteed to be valid. - // We use the minimum of both lengths which guarantees that both regions are - // valid for reads in that interval. - unsafe { memcmp(left.as_ptr(), right.as_ptr(), cmp::min(left.len(), right.len())) }; + // Since the length of a slice is always less than or equal to isize::MAX, this never underflows. + let diff = left.len() as isize - right.len() as isize; + // This comparison gets optimized away (on x86_64 and ARM) because the subtraction updates flags. + let len = if left.len() < right.len() { left.len() } else { right.len() }; + // SAFETY: `left` and `right` are references and are thus guaranteed to be valid. + // We use the minimum of both lengths which guarantees that both regions are + // valid for reads in that interval. + let mut order = unsafe { memcmp(left.as_ptr(), right.as_ptr(), len) as isize }; if order == 0 { - left.len().cmp(&right.len()) - } else if order < 0 { - Less - } else { - Greater + order = diff; } + order.cmp(&0) } } diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 792016902ae..9ee88dd6014 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -1295,6 +1295,7 @@ impl const From<bool> for AtomicBool { #[stable(feature = "atomic_from", since = "1.23.0")] #[rustc_const_unstable(feature = "const_convert", issue = "88674")] impl<T> const From<*mut T> for AtomicPtr<T> { + /// Converts a `*mut T` into an `AtomicPtr<T>`. #[inline] fn from(p: *mut T) -> Self { Self::new(p) diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs index 72a030617ad..41f0a25dbc3 100644 --- a/library/core/src/task/poll.rs +++ b/library/core/src/task/poll.rs @@ -243,7 +243,7 @@ impl<T, E> Poll<Option<Result<T, E>>> { #[stable(feature = "futures_api", since = "1.36.0")] #[rustc_const_unstable(feature = "const_convert", issue = "88674")] impl<T> const From<T> for Poll<T> { - /// Convert to a `Ready` variant. + /// Moves the value into a [`Poll::Ready`] to make a `Poll<T>`. /// /// # Example /// 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 1c512471c95..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)] @@ -45,6 +45,7 @@ #![feature(inline_const)] #![feature(is_sorted)] #![feature(pattern)] +#![feature(pin_macro)] #![feature(sort_internals)] #![feature(slice_take)] #![feature(maybe_uninit_uninit_array)] @@ -66,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)] @@ -122,6 +124,7 @@ mod ops; mod option; mod pattern; mod pin; +mod pin_macro; mod ptr; mod result; mod simd; diff --git a/library/core/tests/pin_macro.rs b/library/core/tests/pin_macro.rs new file mode 100644 index 00000000000..79c8c166c58 --- /dev/null +++ b/library/core/tests/pin_macro.rs @@ -0,0 +1,33 @@ +// edition:2021 +use core::{ + marker::PhantomPinned, + mem::{drop as stuff, transmute}, + pin::{pin, Pin}, +}; + +#[test] +fn basic() { + let it: Pin<&mut PhantomPinned> = pin!(PhantomPinned); + stuff(it); +} + +#[test] +fn extension_works_through_block() { + let it: Pin<&mut PhantomPinned> = { pin!(PhantomPinned) }; + stuff(it); +} + +#[test] +fn extension_works_through_unsafe_block() { + // "retro-type-inference" works as well. + let it: Pin<&mut PhantomPinned> = unsafe { pin!(transmute(())) }; + stuff(it); +} + +#[test] +fn unsize_coercion() { + let slice: Pin<&mut [PhantomPinned]> = pin!([PhantomPinned; 2]); + stuff(slice); + let dyn_obj: Pin<&mut dyn Send> = pin!([PhantomPinned; 2]); + stuff(dyn_obj); +} diff --git a/library/panic_unwind/src/gcc.rs b/library/panic_unwind/src/gcc.rs index 9d6ede73e3d..a0297b4b2f5 100644 --- a/library/panic_unwind/src/gcc.rs +++ b/library/panic_unwind/src/gcc.rs @@ -105,6 +105,9 @@ const UNWIND_DATA_REG: (i32, i32) = (0, 1); // RAX, RDX #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 / X0, X1 +#[cfg(target_arch = "m68k")] +const UNWIND_DATA_REG: (i32, i32) = (0, 1); // D0, D1 + #[cfg(any(target_arch = "mips", target_arch = "mips64"))] const UNWIND_DATA_REG: (i32, i32) = (4, 5); // A0, A1 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 b52cc97504a..1678367290e 100644 --- a/library/std/src/ffi/c_str.rs +++ b/library/std/src/ffi/c_str.rs @@ -881,6 +881,8 @@ impl Borrow<CStr> for CString { #[stable(feature = "cstring_from_cow_cstr", since = "1.28.0")] impl<'a> From<Cow<'a, CStr>> for CString { + /// Converts a `Cow<'a, CStr>` into a `CString`, by copying the contents if they are + /// borrowed. #[inline] fn from(s: Cow<'a, CStr>) -> Self { s.into_owned() @@ -889,6 +891,8 @@ impl<'a> From<Cow<'a, CStr>> for CString { #[stable(feature = "box_from_c_str", since = "1.17.0")] impl From<&CStr> for Box<CStr> { + /// Converts a `&CStr` into a `Box<CStr>`, + /// by copying the contents into a newly allocated [`Box`]. fn from(s: &CStr) -> Box<CStr> { let boxed: Box<[u8]> = Box::from(s.to_bytes_with_nul()); unsafe { Box::from_raw(Box::into_raw(boxed) as *mut CStr) } @@ -897,6 +901,8 @@ impl From<&CStr> for Box<CStr> { #[stable(feature = "box_from_cow", since = "1.45.0")] impl From<Cow<'_, CStr>> for Box<CStr> { + /// Converts a `Cow<'a, CStr>` into a `Box<CStr>`, + /// by copying the contents if they are borrowed. #[inline] fn from(cow: Cow<'_, CStr>) -> Box<CStr> { match cow { @@ -994,6 +1000,8 @@ impl From<CString> for Arc<CStr> { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From<&CStr> for Arc<CStr> { + /// Converts a `&CStr` into a `Arc<CStr>`, + /// by copying the contents into a newly allocated [`Arc`]. #[inline] fn from(s: &CStr) -> Arc<CStr> { let arc: Arc<[u8]> = Arc::from(s.to_bytes_with_nul()); @@ -1014,6 +1022,8 @@ impl From<CString> for Rc<CStr> { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From<&CStr> for Rc<CStr> { + /// Converts a `&CStr` into a `Rc<CStr>`, + /// by copying the contents into a newly allocated [`Rc`]. #[inline] fn from(s: &CStr) -> Rc<CStr> { let rc: Rc<[u8]> = Rc::from(s.to_bytes_with_nul()); @@ -1547,6 +1557,7 @@ impl ToOwned for CStr { #[stable(feature = "cstring_asref", since = "1.7.0")] impl From<&CStr> for CString { + /// Copies the contents of the `&CStr` into a newly allocated `CString`. fn from(s: &CStr) -> CString { s.to_owned() } diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 81f72e34d93..9b5e5d6c0cc 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -452,6 +452,8 @@ impl From<String> for OsString { #[stable(feature = "rust1", since = "1.0.0")] impl<T: ?Sized + AsRef<OsStr>> From<&T> for OsString { + /// Copies any value implementing <code>[AsRef]<[OsStr]></code> + /// into a newly allocated [`OsString`]. fn from(s: &T) -> OsString { s.as_ref().to_os_string() } @@ -942,6 +944,7 @@ impl OsStr { #[stable(feature = "box_from_os_str", since = "1.17.0")] impl From<&OsStr> for Box<OsStr> { + /// Copies the string into a newly allocated <code>[Box]<[OsStr]></code>. #[inline] fn from(s: &OsStr) -> Box<OsStr> { let rw = Box::into_raw(s.inner.into_box()) as *mut OsStr; @@ -951,6 +954,8 @@ impl From<&OsStr> for Box<OsStr> { #[stable(feature = "box_from_cow", since = "1.45.0")] impl From<Cow<'_, OsStr>> for Box<OsStr> { + /// Converts a `Cow<'a, OsStr>` into a <code>[Box]<[OsStr]></code>, + /// by copying the contents if they are borrowed. #[inline] fn from(cow: Cow<'_, OsStr>) -> Box<OsStr> { match cow { @@ -1000,6 +1005,7 @@ impl From<OsString> for Arc<OsStr> { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From<&OsStr> for Arc<OsStr> { + /// Copies the string into a newly allocated <code>[Arc]<[OsStr]></code>. #[inline] fn from(s: &OsStr) -> Arc<OsStr> { let arc = s.inner.into_arc(); @@ -1020,6 +1026,7 @@ impl From<OsString> for Rc<OsStr> { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From<&OsStr> for Rc<OsStr> { + /// Copies the string into a newly allocated <code>[Rc]<[OsStr]></code>. #[inline] fn from(s: &OsStr) -> Rc<OsStr> { let rc = s.inner.into_rc(); @@ -1029,6 +1036,7 @@ impl From<&OsStr> for Rc<OsStr> { #[stable(feature = "cow_from_osstr", since = "1.28.0")] impl<'a> From<OsString> for Cow<'a, OsStr> { + /// Moves the string into a [`Cow::Owned`]. #[inline] fn from(s: OsString) -> Cow<'a, OsStr> { Cow::Owned(s) @@ -1037,6 +1045,7 @@ impl<'a> From<OsString> for Cow<'a, OsStr> { #[stable(feature = "cow_from_osstr", since = "1.28.0")] impl<'a> From<&'a OsStr> for Cow<'a, OsStr> { + /// Converts the string reference into a [`Cow::Borrowed`]. #[inline] fn from(s: &'a OsStr) -> Cow<'a, OsStr> { Cow::Borrowed(s) @@ -1045,6 +1054,7 @@ impl<'a> From<&'a OsStr> for Cow<'a, OsStr> { #[stable(feature = "cow_from_osstr", since = "1.28.0")] impl<'a> From<&'a OsString> for Cow<'a, OsStr> { + /// Converts the string reference into a [`Cow::Borrowed`]. #[inline] fn from(s: &'a OsString) -> Cow<'a, OsStr> { Cow::Borrowed(s.as_os_str()) @@ -1053,6 +1063,8 @@ impl<'a> From<&'a OsString> for Cow<'a, OsStr> { #[stable(feature = "osstring_from_cow_osstr", since = "1.28.0")] impl<'a> From<Cow<'a, OsStr>> for OsString { + /// Converts a `Cow<'a, OsStr>` into an [`OsString`], + /// by copying the contents if they are borrowed. #[inline] fn from(s: Cow<'a, OsStr>) -> Self { s.into_owned() 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 3f7f0f88847..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 //////////////////////////////////////////////////////////////////////////////// @@ -1600,7 +1606,7 @@ impl From<Cow<'_, Path>> for Box<Path> { #[stable(feature = "path_buf_from_box", since = "1.18.0")] impl From<Box<Path>> for PathBuf { - /// Converts a `Box<Path>` into a `PathBuf` + /// Converts a <code>[Box]<[Path]></code> into a [`PathBuf`]. /// /// This conversion does not allocate or copy memory. #[inline] @@ -1611,7 +1617,7 @@ impl From<Box<Path>> for PathBuf { #[stable(feature = "box_from_path_buf", since = "1.20.0")] impl From<PathBuf> for Box<Path> { - /// Converts a `PathBuf` into a `Box<Path>` + /// Converts a [`PathBuf`] into a <code>[Box]<[Path]></code>. /// /// This conversion currently should not allocate memory, /// but this behavior is not guaranteed on all platforms or in all future versions. @@ -1631,7 +1637,7 @@ impl Clone for Box<Path> { #[stable(feature = "rust1", since = "1.0.0")] impl<T: ?Sized + AsRef<OsStr>> From<&T> for PathBuf { - /// Converts a borrowed `OsStr` to a `PathBuf`. + /// Converts a borrowed [`OsStr`] to a [`PathBuf`]. /// /// Allocates a [`PathBuf`] and copies the data into it. #[inline] diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 1f048905396..e3fff155e47 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -1277,7 +1277,7 @@ impl fmt::Debug for Stdio { #[stable(feature = "stdio_from", since = "1.20.0")] impl From<ChildStdin> for Stdio { - /// Converts a `ChildStdin` into a `Stdio` + /// Converts a [`ChildStdin`] into a [`Stdio`]. /// /// # Examples /// @@ -1306,7 +1306,7 @@ impl From<ChildStdin> for Stdio { #[stable(feature = "stdio_from", since = "1.20.0")] impl From<ChildStdout> for Stdio { - /// Converts a `ChildStdout` into a `Stdio` + /// Converts a [`ChildStdout`] into a [`Stdio`]. /// /// # Examples /// @@ -1335,7 +1335,7 @@ impl From<ChildStdout> for Stdio { #[stable(feature = "stdio_from", since = "1.20.0")] impl From<ChildStderr> for Stdio { - /// Converts a `ChildStderr` into a `Stdio` + /// Converts a [`ChildStderr`] into a [`Stdio`]. /// /// # Examples /// @@ -1366,7 +1366,7 @@ impl From<ChildStderr> for Stdio { #[stable(feature = "stdio_from", since = "1.20.0")] impl From<fs::File> for Stdio { - /// Converts a `File` into a `Stdio` + /// Converts a [`File`](fs::File) into a [`Stdio`]. /// /// # Examples /// 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/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index dfcd6124454..c7b6290693e 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -83,6 +83,7 @@ pub const CSTR_GREATER_THAN: c_int = 3; pub const FILE_ATTRIBUTE_READONLY: DWORD = 0x1; pub const FILE_ATTRIBUTE_DIRECTORY: DWORD = 0x10; pub const FILE_ATTRIBUTE_REPARSE_POINT: DWORD = 0x400; +pub const INVALID_FILE_ATTRIBUTES: DWORD = DWORD::MAX; pub const FILE_SHARE_DELETE: DWORD = 0x4; pub const FILE_SHARE_READ: DWORD = 0x1; @@ -1075,6 +1076,7 @@ extern "system" { lpBuffer: LPWSTR, lpFilePart: *mut LPWSTR, ) -> DWORD; + pub fn GetFileAttributesW(lpFileName: LPCWSTR) -> DWORD; } #[link(name = "ws2_32")] diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs index 7bfcac8de17..fafd1412d4c 100644 --- a/library/std/src/sys/windows/process.rs +++ b/library/std/src/sys/windows/process.rs @@ -394,7 +394,7 @@ fn resolve_exe<'a>( // Append `.exe` if not already there. path = path::append_suffix(path, EXE_SUFFIX.as_ref()); - if path.try_exists().unwrap_or(false) { + if program_exists(&path) { return Ok(path); } else { // It's ok to use `set_extension` here because the intent is to @@ -415,7 +415,7 @@ fn resolve_exe<'a>( if !has_extension { path.set_extension(EXE_EXTENSION); } - if let Ok(true) = path.try_exists() { Some(path) } else { None } + if program_exists(&path) { Some(path) } else { None } }); if let Some(path) = result { return Ok(path); @@ -485,6 +485,21 @@ where None } +/// Check if a file exists without following symlinks. +fn program_exists(path: &Path) -> bool { + unsafe { + to_u16s(path) + .map(|path| { + // Getting attributes using `GetFileAttributesW` does not follow symlinks + // and it will almost always be successful if the link exists. + // There are some exceptions for special system files (e.g. the pagefile) + // but these are not executable. + c::GetFileAttributesW(path.as_ptr()) != c::INVALID_FILE_ATTRIBUTES + }) + .unwrap_or(false) + } +} + impl Stdio { fn to_handle(&self, stdio_id: c::DWORD, pipe: &mut Option<AnonPipe>) -> io::Result<Handle> { match *self { diff --git a/library/std/src/sys/windows/process/tests.rs b/library/std/src/sys/windows/process/tests.rs index f1221767af3..d18c3d855bc 100644 --- a/library/std/src/sys/windows/process/tests.rs +++ b/library/std/src/sys/windows/process/tests.rs @@ -135,6 +135,8 @@ fn windows_env_unicode_case() { fn windows_exe_resolver() { use super::resolve_exe; use crate::io; + use crate::sys::fs::symlink; + use crate::sys_common::io::test::tmpdir; let env_paths = || env::var_os("PATH"); @@ -178,4 +180,13 @@ fn windows_exe_resolver() { // The application's directory is also searched. let current_exe = env::current_exe().unwrap(); assert!(resolve_exe(current_exe.file_name().unwrap().as_ref(), empty_paths, None).is_ok()); + + // Create a temporary path and add a broken symlink. + let temp = tmpdir(); + let mut exe_path = temp.path().to_owned(); + exe_path.push("exists.exe"); + symlink("<DOES NOT EXIST>".as_ref(), &exe_path).unwrap(); + + // A broken symlink should still be resolved. + assert!(resolve_exe(OsStr::new("exists.exe"), empty_paths, Some(temp.path().as_ref())).is_ok()); } diff --git a/library/stdarch b/library/stdarch -Subproject 863d31b8e1314e15d124384e5eaa9ab21e12bd7 +Subproject b4a0e07552cf90ef8f1a5b775bf70e4db94b3d6 diff --git a/library/test/src/cli.rs b/library/test/src/cli.rs index cb40b4e965b..b39701a3d42 100644 --- a/library/test/src/cli.rs +++ b/library/test/src/cli.rs @@ -109,12 +109,10 @@ fn optgroups() -> getopts::Options { unstable-options = Allow use of experimental features", "unstable-options", ) - .optflagopt( + .optflag( "", "report-time", - "Show execution time of each test. Available values: - plain = do not colorize the execution time (default); - colored = colorize output according to the `color` parameter value; + "Show execution time of each test. Threshold values for colorized output can be configured via `RUST_TEST_TIME_UNIT`, `RUST_TEST_TIME_INTEGRATION` and @@ -125,7 +123,6 @@ fn optgroups() -> getopts::Options { is 0.5 seconds, and the critical time is 2 seconds. Not available for --format=terse", - "plain|colored", ) .optflag( "", @@ -319,17 +316,12 @@ fn get_time_options( allow_unstable: bool, ) -> OptPartRes<Option<TestTimeOptions>> { let report_time = unstable_optflag!(matches, allow_unstable, "report-time"); - let colored_opt_str = matches.opt_str("report-time"); - let mut report_time_colored = report_time && colored_opt_str == Some("colored".into()); let ensure_test_time = unstable_optflag!(matches, allow_unstable, "ensure-time"); // If `ensure-test-time` option is provided, time output is enforced, // so user won't be confused if any of tests will silently fail. let options = if report_time || ensure_test_time { - if ensure_test_time && !report_time { - report_time_colored = true; - } - Some(TestTimeOptions::new_from_env(ensure_test_time, report_time_colored)) + Some(TestTimeOptions::new_from_env(ensure_test_time)) } else { None }; diff --git a/library/test/src/formatters/pretty.rs b/library/test/src/formatters/pretty.rs index 4726ae864df..041df5216d7 100644 --- a/library/test/src/formatters/pretty.rs +++ b/library/test/src/formatters/pretty.rs @@ -98,7 +98,7 @@ impl<T: Write> PrettyFormatter<T> { if let (Some(opts), Some(time)) = (self.time_options, exec_time) { let time_str = format!(" <{}>", time); - let color = if opts.colored { + let color = if self.use_color { if opts.is_critical(desc, time) { Some(term::color::RED) } else if opts.is_warn(desc, time) { diff --git a/library/test/src/tests.rs b/library/test/src/tests.rs index 9b9c5205686..d566dbc09f4 100644 --- a/library/test/src/tests.rs +++ b/library/test/src/tests.rs @@ -394,7 +394,6 @@ fn test_time_options_threshold() { let options = TestTimeOptions { error_on_excess: false, - colored: false, unit_threshold: unit.clone(), integration_threshold: integration.clone(), doctest_threshold: doc.clone(), diff --git a/library/test/src/time.rs b/library/test/src/time.rs index e0b6eadffa1..8c64e5d1b73 100644 --- a/library/test/src/time.rs +++ b/library/test/src/time.rs @@ -137,14 +137,13 @@ pub struct TestTimeOptions { /// Denotes if the test critical execution time limit excess should be considered /// a test failure. pub error_on_excess: bool, - pub colored: bool, pub unit_threshold: TimeThreshold, pub integration_threshold: TimeThreshold, pub doctest_threshold: TimeThreshold, } impl TestTimeOptions { - pub fn new_from_env(error_on_excess: bool, colored: bool) -> Self { + pub fn new_from_env(error_on_excess: bool) -> Self { let unit_threshold = TimeThreshold::from_env_var(time_constants::UNIT_ENV_NAME) .unwrap_or_else(Self::default_unit); @@ -155,7 +154,7 @@ impl TestTimeOptions { let doctest_threshold = TimeThreshold::from_env_var(time_constants::DOCTEST_ENV_NAME) .unwrap_or_else(Self::default_doctest); - Self { error_on_excess, colored, unit_threshold, integration_threshold, doctest_threshold } + Self { error_on_excess, unit_threshold, integration_threshold, doctest_threshold } } pub fn is_warn(&self, test: &TestDesc, exec_time: &TestExecTime) -> bool { diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index 5e15fe75a24..c8c5528b104 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -42,6 +42,9 @@ pub const unwinder_private_data_size: usize = 2; #[cfg(all(target_arch = "aarch64", target_pointer_width = "32"))] pub const unwinder_private_data_size: usize = 5; +#[cfg(target_arch = "m68k")] +pub const unwinder_private_data_size: usize = 2; + #[cfg(target_arch = "mips")] pub const unwinder_private_data_size: usize = 2; diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 472ee3fb014..029049d5434 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -734,6 +734,8 @@ fn copy_src_dirs( "llvm-project\\llvm", "llvm-project/compiler-rt", "llvm-project\\compiler-rt", + "llvm-project/cmake", + "llvm-project\\cmake", ]; if spath.contains("llvm-project") && !spath.ends_with("llvm-project") @@ -1875,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/bootstrap/native.rs b/src/bootstrap/native.rs index 14de1531f73..f0087523904 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -31,6 +31,29 @@ pub struct Meta { root: String, } +// Linker flags to pass to LLVM's CMake invocation. +#[derive(Debug, Clone, Default)] +struct LdFlags { + // CMAKE_EXE_LINKER_FLAGS + exe: OsString, + // CMAKE_SHARED_LINKER_FLAGS + shared: OsString, + // CMAKE_MODULE_LINKER_FLAGS + module: OsString, +} + +impl LdFlags { + fn push_all(&mut self, s: impl AsRef<OsStr>) { + let s = s.as_ref(); + self.exe.push(" "); + self.exe.push(s); + self.shared.push(" "); + self.shared.push(s); + self.module.push(" "); + self.module.push(s); + } +} + // This returns whether we've already previously built LLVM. // // It's used to avoid busting caches during x.py check -- if we've already built @@ -146,6 +169,7 @@ impl Step for Llvm { // https://llvm.org/docs/CMake.html let mut cfg = cmake::Config::new(builder.src.join(root)); + let mut ldflags = LdFlags::default(); let profile = match (builder.config.llvm_optimize, builder.config.llvm_release_debuginfo) { (false, _) => "Debug", @@ -238,18 +262,19 @@ impl Step for Llvm { cfg.define("LLVM_LINK_LLVM_DYLIB", "ON"); } - // For distribution we want the LLVM tools to be *statically* linked to libstdc++ - if builder.config.llvm_tools_enabled { - if !target.contains("msvc") { + // For distribution we want the LLVM tools to be *statically* linked to libstdc++. + // We also do this if the user explicitly requested static libstdc++. + if builder.config.llvm_tools_enabled || builder.config.llvm_static_stdcpp { + if !target.contains("msvc") && !target.contains("netbsd") { if target.contains("apple") { - cfg.define("CMAKE_EXE_LINKER_FLAGS", "-static-libstdc++"); + ldflags.push_all("-static-libstdc++"); } else { - cfg.define("CMAKE_EXE_LINKER_FLAGS", "-Wl,-Bsymbolic -static-libstdc++"); + ldflags.push_all("-Wl,-Bsymbolic -static-libstdc++"); } } } - if !target.contains("freebsd") && target.starts_with("riscv") { + if target.starts_with("riscv") && !target.contains("freebsd") { // RISC-V GCC erroneously requires linking against // `libatomic` when using 1-byte and 2-byte C++ // atomics but the LLVM build system check cannot @@ -257,12 +282,8 @@ impl Step for Llvm { // FreeBSD uses Clang as its system compiler and // provides no libatomic in its base system so does // not want this. - if !builder.config.llvm_tools_enabled { - cfg.define("CMAKE_EXE_LINKER_FLAGS", "-latomic"); - } else { - cfg.define("CMAKE_EXE_LINKER_FLAGS", "-latomic -static-libstdc++"); - } - cfg.define("CMAKE_SHARED_LINKER_FLAGS", "-latomic"); + ldflags.exe.push(" -latomic"); + ldflags.shared.push(" -latomic"); } if target.contains("msvc") { @@ -309,7 +330,7 @@ impl Step for Llvm { // Workaround for ppc32 lld limitation if target == "powerpc-unknown-freebsd" { - cfg.define("CMAKE_EXE_LINKER_FLAGS", "-fuse-ld=bfd"); + ldflags.exe.push(" -fuse-ld=bfd"); } // https://llvm.org/docs/HowToCrossCompileLLVM.html @@ -351,7 +372,7 @@ impl Step for Llvm { cfg.define("LLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN", "YES"); } - configure_cmake(builder, target, &mut cfg, true); + configure_cmake(builder, target, &mut cfg, true, ldflags); for (key, val) in &builder.config.llvm_build_config { cfg.define(key, val); @@ -399,6 +420,7 @@ fn configure_cmake( target: TargetSelection, cfg: &mut cmake::Config, use_compiler_launcher: bool, + mut ldflags: LdFlags, ) { // Do not print installation messages for up-to-date files. // LLVM and LLD builds can produce a lot of those and hit CI limits on log size. @@ -507,31 +529,38 @@ fn configure_cmake( } cfg.build_arg("-j").build_arg(builder.jobs().to_string()); - let mut cflags = builder.cflags(target, GitRepo::Llvm).join(" "); + let mut cflags: OsString = builder.cflags(target, GitRepo::Llvm).join(" ").into(); if let Some(ref s) = builder.config.llvm_cflags { - cflags.push_str(&format!(" {}", s)); + cflags.push(" "); + cflags.push(s); } // Some compiler features used by LLVM (such as thread locals) will not work on a min version below iOS 10. if target.contains("apple-ios") { if target.contains("86-") { - cflags.push_str(" -miphonesimulator-version-min=10.0"); + cflags.push(" -miphonesimulator-version-min=10.0"); } else { - cflags.push_str(" -miphoneos-version-min=10.0"); + cflags.push(" -miphoneos-version-min=10.0"); } } if builder.config.llvm_clang_cl.is_some() { - cflags.push_str(&format!(" --target={}", target)) + cflags.push(&format!(" --target={}", target)); } - cfg.define("CMAKE_C_FLAGS", cflags); - let mut cxxflags = builder.cflags(target, GitRepo::Llvm).join(" "); - if builder.config.llvm_static_stdcpp && !target.contains("msvc") && !target.contains("netbsd") { - cxxflags.push_str(" -static-libstdc++"); + if let Some(flags) = env::var_os("CFLAGS") { + cflags.push(" "); + cflags.push(flags); } + cfg.define("CMAKE_C_FLAGS", cflags); + let mut cxxflags: OsString = builder.cflags(target, GitRepo::Llvm).join(" ").into(); if let Some(ref s) = builder.config.llvm_cxxflags { - cxxflags.push_str(&format!(" {}", s)); + cxxflags.push(" "); + cxxflags.push(s); } if builder.config.llvm_clang_cl.is_some() { - cxxflags.push_str(&format!(" --target={}", target)) + cxxflags.push(&format!(" --target={}", target)); + } + if let Some(flags) = env::var_os("CXXFLAGS") { + cxxflags.push(" "); + cxxflags.push(flags); } cfg.define("CMAKE_CXX_FLAGS", cxxflags); if let Some(ar) = builder.ar(target) { @@ -550,12 +579,18 @@ fn configure_cmake( } } - if let Some(ref s) = builder.config.llvm_ldflags { - cfg.define("CMAKE_SHARED_LINKER_FLAGS", s); - cfg.define("CMAKE_MODULE_LINKER_FLAGS", s); - cfg.define("CMAKE_EXE_LINKER_FLAGS", s); + if let Some(ref flags) = builder.config.llvm_ldflags { + ldflags.push_all(flags); } + if let Some(flags) = env::var_os("LDFLAGS") { + ldflags.push_all(&flags); + } + + cfg.define("CMAKE_SHARED_LINKER_FLAGS", &ldflags.shared); + cfg.define("CMAKE_MODULE_LINKER_FLAGS", &ldflags.module); + cfg.define("CMAKE_EXE_LINKER_FLAGS", &ldflags.exe); + if env::var_os("SCCACHE_ERROR_LOG").is_some() { cfg.env("RUSTC_LOG", "sccache=warn"); } @@ -598,7 +633,7 @@ impl Step for Lld { t!(fs::create_dir_all(&out_dir)); let mut cfg = cmake::Config::new(builder.src.join("src/llvm-project/lld")); - configure_cmake(builder, target, &mut cfg, true); + configure_cmake(builder, target, &mut cfg, true, LdFlags::default()); // This is an awful, awful hack. Discovered when we migrated to using // clang-cl to compile LLVM/LLD it turns out that LLD, when built out of @@ -788,7 +823,7 @@ impl Step for Sanitizers { // Unfortunately sccache currently lacks support to build them successfully. // Disable compiler launcher on Darwin targets to avoid potential issues. let use_compiler_launcher = !self.target.contains("apple-darwin"); - configure_cmake(builder, self.target, &mut cfg, use_compiler_launcher); + configure_cmake(builder, self.target, &mut cfg, use_compiler_launcher, LdFlags::default()); t!(fs::create_dir_all(&out_dir)); cfg.out_dir(out_dir); diff --git a/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile index ef49904b53d..51645a81853 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile @@ -1,6 +1,6 @@ -FROM ubuntu:16.04 +FROM ubuntu:20.04 -RUN apt-get update && apt-get install -y --no-install-recommends \ +RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ g++ \ make \ ninja-build \ diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile index 52c73fd3bd1..f1c42b248f4 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile @@ -72,7 +72,7 @@ ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}" # https://github.com/puppeteer/puppeteer/issues/375 # # We also specify the version in case we need to update it to go around cache limitations. -RUN npm install -g browser-ui-test@0.7.1 --unsafe-perm=true +RUN npm install -g browser-ui-test@0.7.2 --unsafe-perm=true ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ diff --git a/src/doc/book b/src/doc/book -Subproject 98904efaa4fc968db8ff59cf2744d9f7ed15816 +Subproject 67b768c0b660a069a45f0e5d8ae2f679df1022a diff --git a/src/doc/nomicon b/src/doc/nomicon -Subproject 9493715a6280a1f74be759c7e1ef9999b5d13e6 +Subproject 90993eeac93dbf9388992de92965f99cf6f29a0 diff --git a/src/doc/reference b/src/doc/reference -Subproject 411c2f0d5cebf48453ae2d136ad0c5e611d39ae +Subproject 70fc73a6b908e08e66aa0306856c5211312f6c0 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide -Subproject 8763adb62c712df69b1d39ea3e692b6d696cc4d +Subproject 62f58394ba7b203f55ac35ddcc4c0b79578f570 diff --git a/src/doc/rustc/src/tests/index.md b/src/doc/rustc/src/tests/index.md index 23a9f31e8e7..0e0eb85db74 100644 --- a/src/doc/rustc/src/tests/index.md +++ b/src/doc/rustc/src/tests/index.md @@ -267,7 +267,7 @@ Controls the format of the output. Valid options: Writes the results of the tests to the given file. -#### `--report-time` _FORMAT_ +#### `--report-time` ⚠️ 🚧 This option is [unstable](#unstable-options), and requires the `-Z unstable-options` flag. See [tracking issue diff --git a/src/doc/rustdoc/src/command-line-arguments.md b/src/doc/rustdoc/src/command-line-arguments.md index 9de2e733de7..3ce57f88938 100644 --- a/src/doc/rustdoc/src/command-line-arguments.md +++ b/src/doc/rustdoc/src/command-line-arguments.md @@ -381,7 +381,7 @@ the same CSS rules as the official `light` theme. `--check-theme` flag, it discards all other flags and only performs the CSS rule comparison operation. -### `--crate-version`: control the crate version +## `--crate-version`: control the crate version Using this flag looks like this: @@ -418,9 +418,22 @@ Rustdoc only supports Rust source code and Markdown input formats. If the file ends in `.md` or `.markdown`, `rustdoc` treats it as a Markdown file. Otherwise, it assumes that the input file is Rust. +# Unstable command line arguments + ## `--nocapture` When this flag is used with `--test`, the output (stdout and stderr) of your tests won't be captured by rustdoc. Instead, the output will be directed to your terminal, as if you had run the test executable manually. This is especially useful for debugging your tests! + +## `--check` + +When this flag is supplied, rustdoc will type check and lint your code, but will not generate any +documentation or run your doctests. + +Using this flag looks like: + +```bash +rustdoc -Z unstable-options --check src/lib.rs +``` 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/cf-protection.md b/src/doc/unstable-book/src/compiler-flags/cf-protection.md new file mode 100644 index 00000000000..cc580ca9b42 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/cf-protection.md @@ -0,0 +1,40 @@ +# `cf-protection` + +This option enables control-flow enforcement technology (CET) on x86; a more detailed description of +CET is available [here]. Similar to `clang`, this flag takes one of the following values: + +- `none` - Disable CET completely (this is the default). +- `branch` - Enable indirect branch tracking (`IBT`). +- `return` - Enable shadow stack (`SHSTK`). +- `full` - Enable both `branch` and `return`. + +[here]: https://www.intel.com/content/www/us/en/develop/articles/technical-look-control-flow-enforcement-technology.html + +This flag only applies to the LLVM backend: it sets the `cf-protection-branch` and +`cf-protection-return` flags on LLVM modules. Note, however, that all compiled modules linked +together must have the flags set for the compiled output to be CET-enabled. Currently, Rust's +standard library does not ship with CET enabled by default, so you may need to rebuild all standard +modules with a `cargo` command like: + +```sh +$ RUSTFLAGS="-Z cf-protection=full" RUSTC="rustc-custom" cargo +nightly build -Z build-std --target x86_64-unknown-linux-gnu +``` + +### Detection + +An ELF binary is CET-enabled if it has the `IBT` and `SHSTK` tags, e.g.: + +```sh +$ readelf -a target/x86_64-unknown-linux-gnu/debug/example | grep feature: + Properties: x86 feature: IBT, SHSTK +``` + +### Troubleshooting + +To display modules that are not CET enabled, examine the linker errors available when `cet-report` is enabled: + +```sh +$ RUSTC_LOG=rustc_codegen_ssa::back::link=info rustc-custom -v -Z cf-protection=full -C link-arg="-Wl,-z,cet-report=warning" -o example example.rs +... +/usr/bin/ld: /.../build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-d73f7266be14cb8b.rlib(std-d73f7266be14cb8b.std.f7443020-cgu.12.rcgu.o): warning: missing IBT and SHSTK properties +``` diff --git a/src/doc/unstable-book/src/compiler-flags/report-time.md b/src/doc/unstable-book/src/compiler-flags/report-time.md index ac0093f77ae..9e6a1fb0005 100644 --- a/src/doc/unstable-book/src/compiler-flags/report-time.md +++ b/src/doc/unstable-book/src/compiler-flags/report-time.md @@ -21,11 +21,8 @@ Sample usage command: Available options: ```sh ---report-time [plain|colored] - Show execution time of each test. Available values: - plain = do not colorize the execution time (default); - colored = colorize output according to the `color` - parameter value; +--report-time + Show execution time of each test. Threshold values for colorized output can be configured via `RUST_TEST_TIME_UNIT`, `RUST_TEST_TIME_INTEGRATION` 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/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 18a4d8a4753..a3154d8f03b 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -297,7 +297,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { .get(name) .unwrap_or(&empty) .iter() - .map(|region| GenericBound::Outlives(Self::get_lifetime(region, names_map))) + .map(|region| GenericBound::Outlives(Self::get_lifetime(*region, names_map))) .collect(); if bounds.is_empty() { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e34faef9d6d..187bc13357a 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -218,9 +218,9 @@ impl Clean<Constant> for hir::ConstArg { } } -impl Clean<Option<Lifetime>> for ty::RegionKind { +impl Clean<Option<Lifetime>> for ty::Region<'_> { fn clean(&self, _cx: &mut DocContext<'_>) -> Option<Lifetime> { - match *self { + match **self { ty::ReStatic => Some(Lifetime::statik()), ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) => { Some(Lifetime(name)) @@ -327,7 +327,7 @@ impl<'tcx> Clean<Option<WherePredicate>> fn clean(&self, cx: &mut DocContext<'_>) -> Option<WherePredicate> { let ty::OutlivesPredicate(a, b) = self; - if let (ty::ReEmpty(_), ty::ReEmpty(_)) = (a, b) { + if a.is_empty() && b.is_empty() { return None; } @@ -342,7 +342,7 @@ impl<'tcx> Clean<Option<WherePredicate>> for ty::OutlivesPredicate<Ty<'tcx>, ty: fn clean(&self, cx: &mut DocContext<'_>) -> Option<WherePredicate> { let ty::OutlivesPredicate(ty, lt) = self; - if let ty::ReEmpty(_) = lt { + if lt.is_empty() { return None; } @@ -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); @@ -1460,7 +1455,7 @@ fn normalize<'tcx>(cx: &mut DocContext<'tcx>, ty: Ty<'_>) -> Option<Ty<'tcx>> { impl<'tcx> Clean<Type> for Ty<'tcx> { fn clean(&self, cx: &mut DocContext<'_>) -> Type { trace!("cleaning type: {:?}", self); - let ty = normalize(cx, self).unwrap_or(self); + let ty = normalize(cx, *self).unwrap_or(*self); match *ty.kind() { ty::Never => Primitive(PrimitiveType::Never), ty::Bool => Primitive(PrimitiveType::Bool), @@ -1646,7 +1641,7 @@ impl<'tcx> Clean<Constant> for ty::Const<'tcx> { fn clean(&self, cx: &mut DocContext<'_>) -> Constant { // FIXME: instead of storing the stringified expression, store `self` directly instead. Constant { - type_: self.ty.clean(cx), + type_: self.ty().clean(cx), kind: ConstantKind::TyConst { expr: self.to_string() }, } } 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/clean/types.rs b/src/librustdoc/clean/types.rs index 6feba34134c..74184427dd5 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1972,7 +1972,7 @@ impl Path { /// Checks if this is a `T::Name` path for an associated type. crate fn is_assoc_ty(&self) -> bool { match self.res { - Res::SelfTy(..) if self.segments.len() != 1 => true, + Res::SelfTy { .. } if self.segments.len() != 1 => true, Res::Def(DefKind::TyParam, _) if self.segments.len() != 1 => true, Res::Def(DefKind::AssocTy, _) => true, _ => false, diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index dabf1e878c9..1d312df1f78 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -89,7 +89,7 @@ fn external_generic_args( let args: Vec<_> = substs .iter() .filter_map(|kind| match kind.unpack() { - GenericArgKind::Lifetime(lt) => match lt { + GenericArgKind::Lifetime(lt) => match *lt { ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrAnon(_), .. }) => { Some(GenericArg::Lifetime(Lifetime::elided())) } @@ -226,8 +226,8 @@ crate fn name_from_pat(p: &hir::Pat<'_>) -> Symbol { }) } -crate fn print_const(cx: &DocContext<'_>, n: &ty::Const<'_>) -> String { - match n.val { +crate fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String { + match n.val() { ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs: _, promoted }) => { let mut s = if let Some(def) = def.as_local() { let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def.did); @@ -297,15 +297,15 @@ fn format_integer_with_underscore_sep(num: &str) -> String { .collect() } -fn print_const_with_custom_print_scalar(tcx: TyCtxt<'_>, ct: &ty::Const<'_>) -> String { +fn print_const_with_custom_print_scalar(tcx: TyCtxt<'_>, ct: ty::Const<'_>) -> String { // Use a slightly different format for integer types which always shows the actual value. // For all other types, fallback to the original `pretty_print_const`. - match (ct.val, ct.ty.kind()) { + match (ct.val(), ct.ty().kind()) { (ty::ConstKind::Value(ConstValue::Scalar(int)), ty::Uint(ui)) => { format!("{}{}", format_integer_with_underscore_sep(&int.to_string()), ui.name_str()) } (ty::ConstKind::Value(ConstValue::Scalar(int)), ty::Int(i)) => { - let ty = tcx.lift(ct.ty).unwrap(); + let ty = tcx.lift(ct.ty()).unwrap(); let size = tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size; let data = int.assert_bits(size); let sign_extended_data = size.sign_extend(data) as i128; @@ -355,7 +355,7 @@ crate fn resolve_type(cx: &mut DocContext<'_>, path: Path) -> Type { match path.res { Res::PrimTy(p) => Primitive(PrimitiveType::from(p)), - Res::SelfTy(..) if path.segments.len() == 1 => Generic(kw::SelfUpper), + Res::SelfTy { .. } if path.segments.len() == 1 => Generic(kw::SelfUpper), Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => Generic(path.segments[0].name), _ => { let _ = register_res(cx, path.res); @@ -397,11 +397,11 @@ crate fn register_res(cx: &mut DocContext<'_>, res: Res) -> DefId { | Union | Mod | ForeignTy | Const | Static | Macro(..) | TraitAlias), i, ) => (i, kind.into()), - // This is part of a trait definition; document the trait. - Res::SelfTy(Some(trait_def_id), _) => (trait_def_id, ItemType::Trait), - // This is an inherent impl; it doesn't have its own page. - Res::SelfTy(None, Some((impl_def_id, _))) => return impl_def_id, - Res::SelfTy(None, None) + // This is part of a trait definition or trait impl; document the trait. + Res::SelfTy { trait_: Some(trait_def_id), alias_to: _ } => (trait_def_id, ItemType::Trait), + // This is an inherent impl or a type definition; it doesn't have its own page. + Res::SelfTy { trait_: None, alias_to: Some((item_def_id, _)) } => return item_def_id, + Res::SelfTy { trait_: None, alias_to: None } | Res::PrimTy(_) | Res::ToolMod | Res::SelfCtor(_) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 1f14a333c00..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,19 +246,20 @@ 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, output_dir: None, file_loader: None, diagnostic_output: DiagnosticOutput::Default, - stderr: None, lint_caps, parse_sess_created: None, register_lints: Some(box crate::lint::register_lints), diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 6c55721c0dd..696397c5f67 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -91,13 +91,13 @@ 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, output_dir: None, file_loader: None, diagnostic_output: DiagnosticOutput::Default, - stderr: None, lint_caps, parse_sess_created: None, register_lints: Some(box crate::lint::register_lints), 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 4327a554fc6..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; } @@ -933,7 +932,7 @@ table, outline: none; border: 1px solid; border-radius: 2px; - padding: 5px 8px; + padding: 8px; font-size: 1rem; transition: border-color 300ms ease; width: 100%; 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 c3205165040..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( "", @@ -691,7 +694,6 @@ fn main_args(at_args: &[String]) -> MainResult { rustc_interface::util::run_in_thread_pool_with_globals( options.edition, 1, // this runs single-threaded, even in a parallel compiler - &None, move || main_options(options), ) } 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/llvm-project b/src/llvm-project -Subproject fdc8f411ec9253d4eeb7a572b058be4f2131fd1 +Subproject e29ac13bc97e26f886c3bfe72f9135e994c3cd0 diff --git a/src/test/codegen/cf-protection.rs b/src/test/codegen/cf-protection.rs new file mode 100644 index 00000000000..ccbc863f571 --- /dev/null +++ b/src/test/codegen/cf-protection.rs @@ -0,0 +1,38 @@ +// Test that the correct module flags are emitted with different control-flow protection flags. + +// revisions: undefined none branch return full +// needs-llvm-components: x86 +// [undefined] compile-flags: +// [none] compile-flags: -Z cf-protection=none +// [branch] compile-flags: -Z cf-protection=branch +// [return] compile-flags: -Z cf-protection=return +// [full] compile-flags: -Z cf-protection=full +// compile-flags: --target x86_64-unknown-linux-gnu + +#![crate_type = "lib"] +#![feature(no_core, lang_items)] +#![no_core] + +#[lang="sized"] +trait Sized { } + +// A basic test function. +pub fn test() { +} + +// undefined-NOT: !"cf-protection-branch" +// undefined-NOT: !"cf-protection-return" + +// none-NOT: !"cf-protection-branch" +// none-NOT: !"cf-protection-return" + +// branch-NOT: !"cf-protection-return" +// branch: !"cf-protection-branch", i32 1 +// branch-NOT: !"cf-protection-return" + +// return-NOT: !"cf-protection-branch" +// return: !"cf-protection-return", i32 1 +// return-NOT: !"cf-protection-branch" + +// full: !"cf-protection-branch", i32 1 +// full: !"cf-protection-return", i32 1 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/mir-opt/const_allocation.main.ConstProp.after.32bit.mir b/src/test/mir-opt/const_allocation.main.ConstProp.after.32bit.mir index 8e02dca4fb8..f8a8afa92e0 100644 --- a/src/test/mir-opt/const_allocation.main.ConstProp.after.32bit.mir +++ b/src/test/mir-opt/const_allocation.main.ConstProp.after.32bit.mir @@ -9,12 +9,9 @@ fn main() -> () { StorageLive(_1); // scope 0 at $DIR/const_allocation.rs:8:5: 8:8 StorageLive(_2); // scope 0 at $DIR/const_allocation.rs:8:5: 8:8 _2 = const {alloc1: &&[(Option<i32>, &[&str])]}; // scope 0 at $DIR/const_allocation.rs:8:5: 8:8 - // ty::Const - // + ty: &&[(std::option::Option<i32>, &[&str])] - // + val: Value(Scalar(alloc1)) // mir::Constant // + span: $DIR/const_allocation.rs:8:5: 8:8 - // + literal: Const { ty: &&[(std::option::Option<i32>, &[&str])], val: Value(Scalar(alloc1)) } + // + literal: Const { ty: &&[(Option<i32>, &[&str])], val: Value(Scalar(alloc1)) } _1 = (*_2); // scope 0 at $DIR/const_allocation.rs:8:5: 8:8 StorageDead(_2); // scope 0 at $DIR/const_allocation.rs:8:8: 8:9 StorageDead(_1); // scope 0 at $DIR/const_allocation.rs:8:8: 8:9 diff --git a/src/test/mir-opt/const_allocation.main.ConstProp.after.64bit.mir b/src/test/mir-opt/const_allocation.main.ConstProp.after.64bit.mir index 88cdbda2fae..1f1d857425e 100644 --- a/src/test/mir-opt/const_allocation.main.ConstProp.after.64bit.mir +++ b/src/test/mir-opt/const_allocation.main.ConstProp.after.64bit.mir @@ -9,12 +9,9 @@ fn main() -> () { StorageLive(_1); // scope 0 at $DIR/const_allocation.rs:8:5: 8:8 StorageLive(_2); // scope 0 at $DIR/const_allocation.rs:8:5: 8:8 _2 = const {alloc1: &&[(Option<i32>, &[&str])]}; // scope 0 at $DIR/const_allocation.rs:8:5: 8:8 - // ty::Const - // + ty: &&[(std::option::Option<i32>, &[&str])] - // + val: Value(Scalar(alloc1)) // mir::Constant // + span: $DIR/const_allocation.rs:8:5: 8:8 - // + literal: Const { ty: &&[(std::option::Option<i32>, &[&str])], val: Value(Scalar(alloc1)) } + // + literal: Const { ty: &&[(Option<i32>, &[&str])], val: Value(Scalar(alloc1)) } _1 = (*_2); // scope 0 at $DIR/const_allocation.rs:8:5: 8:8 StorageDead(_2); // scope 0 at $DIR/const_allocation.rs:8:8: 8:9 StorageDead(_1); // scope 0 at $DIR/const_allocation.rs:8:8: 8:9 diff --git a/src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir b/src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir index 059b721f5bb..8b5ad40c9f9 100644 --- a/src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir +++ b/src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir @@ -9,12 +9,9 @@ fn main() -> () { StorageLive(_1); // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 StorageLive(_2); // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 _2 = const {alloc1: &&[(Option<i32>, &[&u8])]}; // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 - // ty::Const - // + ty: &&[(std::option::Option<i32>, &[&u8])] - // + val: Value(Scalar(alloc1)) // mir::Constant // + span: $DIR/const_allocation2.rs:5:5: 5:8 - // + literal: Const { ty: &&[(std::option::Option<i32>, &[&u8])], val: Value(Scalar(alloc1)) } + // + literal: Const { ty: &&[(Option<i32>, &[&u8])], val: Value(Scalar(alloc1)) } _1 = (*_2); // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 StorageDead(_2); // scope 0 at $DIR/const_allocation2.rs:5:8: 5:9 StorageDead(_1); // scope 0 at $DIR/const_allocation2.rs:5:8: 5:9 diff --git a/src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir b/src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir index d6a97917d62..ef651f01c9b 100644 --- a/src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir +++ b/src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir @@ -9,12 +9,9 @@ fn main() -> () { StorageLive(_1); // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 StorageLive(_2); // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 _2 = const {alloc1: &&[(Option<i32>, &[&u8])]}; // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 - // ty::Const - // + ty: &&[(std::option::Option<i32>, &[&u8])] - // + val: Value(Scalar(alloc1)) // mir::Constant // + span: $DIR/const_allocation2.rs:5:5: 5:8 - // + literal: Const { ty: &&[(std::option::Option<i32>, &[&u8])], val: Value(Scalar(alloc1)) } + // + literal: Const { ty: &&[(Option<i32>, &[&u8])], val: Value(Scalar(alloc1)) } _1 = (*_2); // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 StorageDead(_2); // scope 0 at $DIR/const_allocation2.rs:5:8: 5:9 StorageDead(_1); // scope 0 at $DIR/const_allocation2.rs:5:8: 5:9 diff --git a/src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir b/src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir index 32000340dce..991cf40d1b7 100644 --- a/src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir +++ b/src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir @@ -9,9 +9,6 @@ fn main() -> () { StorageLive(_1); // scope 0 at $DIR/const_allocation3.rs:5:5: 5:8 StorageLive(_2); // scope 0 at $DIR/const_allocation3.rs:5:5: 5:8 _2 = const {alloc1: &&Packed}; // scope 0 at $DIR/const_allocation3.rs:5:5: 5:8 - // ty::Const - // + ty: &&Packed - // + val: Value(Scalar(alloc1)) // mir::Constant // + span: $DIR/const_allocation3.rs:5:5: 5:8 // + literal: Const { ty: &&Packed, val: Value(Scalar(alloc1)) } diff --git a/src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir b/src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir index cac882333ae..fb481697aa8 100644 --- a/src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir +++ b/src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir @@ -9,9 +9,6 @@ fn main() -> () { StorageLive(_1); // scope 0 at $DIR/const_allocation3.rs:5:5: 5:8 StorageLive(_2); // scope 0 at $DIR/const_allocation3.rs:5:5: 5:8 _2 = const {alloc1: &&Packed}; // scope 0 at $DIR/const_allocation3.rs:5:5: 5:8 - // ty::Const - // + ty: &&Packed - // + val: Value(Scalar(alloc1)) // mir::Constant // + span: $DIR/const_allocation3.rs:5:5: 5:8 // + literal: Const { ty: &&Packed, val: Value(Scalar(alloc1)) } diff --git a/src/test/mir-opt/const_promotion_extern_static.BAR-promoted[0].SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/const_promotion_extern_static.BAR-promoted[0].SimplifyCfg-elaborate-drops.after.mir index bec0fa9c049..666b805e822 100644 --- a/src/test/mir-opt/const_promotion_extern_static.BAR-promoted[0].SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/const_promotion_extern_static.BAR-promoted[0].SimplifyCfg-elaborate-drops.after.mir @@ -8,9 +8,6 @@ promoted[0] in BAR: &[&i32; 1] = { bb0: { _3 = const {alloc1: &i32}; // scope 0 at $DIR/const-promotion-extern-static.rs:9:33: 9:34 - // ty::Const - // + ty: &i32 - // + val: Value(Scalar(alloc1)) // mir::Constant // + span: $DIR/const-promotion-extern-static.rs:9:33: 9:34 // + literal: Const { ty: &i32, val: Value(Scalar(alloc1)) } diff --git a/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff index b480b257825..ad83e9c276e 100644 --- a/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff +++ b/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff @@ -18,9 +18,7 @@ - StorageLive(_5); // scope 0 at $DIR/const-promotion-extern-static.rs:9:33: 9:34 - _5 = const {alloc1: &i32}; // scope 0 at $DIR/const-promotion-extern-static.rs:9:33: 9:34 + _6 = const BAR::promoted[0]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 - // ty::Const -- // + ty: &i32 -- // + val: Value(Scalar(alloc1)) ++ // ty::Const + // + ty: &[&i32; 1] + // + val: Unevaluated(BAR, [], Some(promoted[0])) // mir::Constant diff --git a/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir index c01b31525b6..785c8386e88 100644 --- a/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir @@ -8,9 +8,6 @@ promoted[0] in FOO: &[&i32; 1] = { bb0: { _3 = const {alloc3: *const i32}; // scope 0 at $DIR/const-promotion-extern-static.rs:13:42: 13:43 - // ty::Const - // + ty: *const i32 - // + val: Value(Scalar(alloc3)) // mir::Constant // + span: $DIR/const-promotion-extern-static.rs:13:42: 13:43 // + literal: Const { ty: *const i32, val: Value(Scalar(alloc3)) } diff --git a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff index ed48f5dc9dc..a9cf3ca9767 100644 --- a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff +++ b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff @@ -20,9 +20,7 @@ - StorageLive(_5); // scope 1 at $DIR/const-promotion-extern-static.rs:13:42: 13:43 - _5 = const {alloc3: *const i32}; // scope 1 at $DIR/const-promotion-extern-static.rs:13:42: 13:43 + _6 = const FOO::promoted[0]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 - // ty::Const -- // + ty: *const i32 -- // + val: Value(Scalar(alloc3)) ++ // ty::Const + // + ty: &[&i32; 1] + // + val: Unevaluated(FOO, [], Some(promoted[0])) // mir::Constant diff --git a/src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff b/src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff new file mode 100644 index 00000000000..ee6c3b5f36f --- /dev/null +++ b/src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff @@ -0,0 +1,55 @@ +- // MIR for `main` before ConstProp ++ // MIR for `main` after ConstProp + + fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/invalid_constant.rs:15:11: 15:11 + let _1: std::option::Option<()>; // in scope 0 at $DIR/invalid_constant.rs:16:5: 16:12 + let mut _2: std::option::Option<std::option::Option<()>>; // in scope 0 at $DIR/invalid_constant.rs:16:7: 16:11 + scope 1 (inlined f) { // at $DIR/invalid_constant.rs:16:5: 16:12 + debug x => _2; // in scope 1 at $DIR/invalid_constant.rs:16:5: 16:12 + let mut _3: isize; // in scope 1 at $DIR/invalid_constant.rs:16:5: 16:12 + let _4: std::option::Option<()>; // in scope 1 at $DIR/invalid_constant.rs:16:5: 16:12 + scope 2 { + debug y => _4; // in scope 2 at $DIR/invalid_constant.rs:16:5: 16:12 + } + } + + bb0: { + discriminant(_2) = 0; // scope 0 at $DIR/invalid_constant.rs:16:7: 16:11 +- _3 = discriminant(_2); // scope 1 at $DIR/invalid_constant.rs:16:5: 16:12 +- switchInt(move _3) -> [0_isize: bb3, otherwise: bb2]; // scope 1 at $DIR/invalid_constant.rs:16:5: 16:12 ++ _3 = const 0_isize; // scope 1 at $DIR/invalid_constant.rs:16:5: 16:12 ++ switchInt(const 0_isize) -> [0_isize: bb3, otherwise: bb2]; // scope 1 at $DIR/invalid_constant.rs:16:5: 16:12 + } + + bb1: { + nop; // scope 0 at $DIR/invalid_constant.rs:15:11: 17:2 + return; // scope 0 at $DIR/invalid_constant.rs:17:2: 17:2 + } + + bb2: { +- _4 = ((_2 as Some).0: std::option::Option<()>); // scope 1 at $DIR/invalid_constant.rs:16:5: 16:12 +- _1 = _4; // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12 ++ _4 = const Scalar(0x02): Option::<()>; // scope 1 at $DIR/invalid_constant.rs:16:5: 16:12 ++ // ty::Const ++ // + ty: std::option::Option<()> ++ // + val: Value(Scalar(0x02)) ++ // mir::Constant ++ // + span: $DIR/invalid_constant.rs:16:5: 16:12 ++ // + literal: Const { ty: std::option::Option<()>, val: Value(Scalar(0x02)) } ++ _1 = const Scalar(0x02): Option::<()>; // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12 ++ // ty::Const ++ // + ty: std::option::Option<()> ++ // + val: Value(Scalar(0x02)) ++ // mir::Constant ++ // + span: $DIR/invalid_constant.rs:16:5: 16:12 ++ // + literal: Const { ty: std::option::Option<()>, val: Value(Scalar(0x02)) } + goto -> bb1; // scope 0 at $DIR/invalid_constant.rs:10:20: 10:21 + } + + bb3: { + discriminant(_1) = 0; // scope 1 at $DIR/invalid_constant.rs:16:5: 16:12 + goto -> bb1; // scope 0 at $DIR/invalid_constant.rs:9:17: 9:21 + } + } + diff --git a/src/test/mir-opt/const_prop/invalid_constant.rs b/src/test/mir-opt/const_prop/invalid_constant.rs new file mode 100644 index 00000000000..1eb6f37df59 --- /dev/null +++ b/src/test/mir-opt/const_prop/invalid_constant.rs @@ -0,0 +1,17 @@ +// Verify that we can pretty print invalid constant introduced +// by constant propagation. Regression test for issue #93688. +// +// compile-flags: -Copt-level=0 -Zinline-mir + +#[inline(always)] +pub fn f(x: Option<Option<()>>) -> Option<()> { + match x { + None => None, + Some(y) => y, + } +} + +// EMIT_MIR invalid_constant.main.ConstProp.diff +fn main() { + f(None); +} diff --git a/src/test/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff index afc62178463..1fd92ddd461 100644 --- a/src/test/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff @@ -24,9 +24,6 @@ StorageLive(_3); // scope 2 at $DIR/mutable_variable_no_prop.rs:9:13: 9:19 StorageLive(_4); // scope 2 at $DIR/mutable_variable_no_prop.rs:9:13: 9:19 _4 = const {alloc1: *mut u32}; // scope 2 at $DIR/mutable_variable_no_prop.rs:9:13: 9:19 - // ty::Const - // + ty: *mut u32 - // + val: Value(Scalar(alloc1)) // mir::Constant // + span: $DIR/mutable_variable_no_prop.rs:9:13: 9:19 // + literal: Const { ty: *mut u32, val: Value(Scalar(alloc1)) } diff --git a/src/test/mir-opt/const_prop/read_immutable_static.main.ConstProp.diff b/src/test/mir-opt/const_prop/read_immutable_static.main.ConstProp.diff index 13ef30d89a0..15b3e076642 100644 --- a/src/test/mir-opt/const_prop/read_immutable_static.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/read_immutable_static.main.ConstProp.diff @@ -17,9 +17,6 @@ StorageLive(_2); // scope 0 at $DIR/read_immutable_static.rs:7:13: 7:16 StorageLive(_3); // scope 0 at $DIR/read_immutable_static.rs:7:13: 7:16 _3 = const {alloc1: &u8}; // scope 0 at $DIR/read_immutable_static.rs:7:13: 7:16 - // ty::Const - // + ty: &u8 - // + val: Value(Scalar(alloc1)) // mir::Constant // + span: $DIR/read_immutable_static.rs:7:13: 7:16 // + literal: Const { ty: &u8, val: Value(Scalar(alloc1)) } @@ -28,9 +25,6 @@ StorageLive(_4); // scope 0 at $DIR/read_immutable_static.rs:7:19: 7:22 StorageLive(_5); // scope 0 at $DIR/read_immutable_static.rs:7:19: 7:22 _5 = const {alloc1: &u8}; // scope 0 at $DIR/read_immutable_static.rs:7:19: 7:22 - // ty::Const - // + ty: &u8 - // + val: Value(Scalar(alloc1)) // mir::Constant // + span: $DIR/read_immutable_static.rs:7:19: 7:22 // + literal: Const { ty: &u8, val: Value(Scalar(alloc1)) } diff --git a/src/test/run-make-fulldeps/coverage-llvmir/filecheck.testprog.txt b/src/test/run-make-fulldeps/coverage-llvmir/filecheck.testprog.txt index 1e2ecc2fbb1..84e67e53ea4 100644 --- a/src/test/run-make-fulldeps/coverage-llvmir/filecheck.testprog.txt +++ b/src/test/run-make-fulldeps/coverage-llvmir/filecheck.testprog.txt @@ -15,14 +15,14 @@ CHECK: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = {{private|i CHECK-SAME: section "[[INSTR_PROF_CNTS]]"{{.*}}, align 8 CHECK: @__profd__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = {{private|internal}} global -CHECK-SAME: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called, +CHECK-SAME: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called CHECK-SAME: section "[[INSTR_PROF_DATA]]"{{.*}}, align 8 CHECK: @__profc__R{{[a-zA-Z0-9_]+}}testprog4main = {{private|internal}} global CHECK-SAME: section "[[INSTR_PROF_CNTS]]"{{.*}}, align 8 CHECK: @__profd__R{{[a-zA-Z0-9_]+}}testprog4main = {{private|internal}} global -CHECK-SAME: @__profc__R{{[a-zA-Z0-9_]+}}testprog4main, +CHECK-SAME: @__profc__R{{[a-zA-Z0-9_]+}}testprog4main CHECK-SAME: section "[[INSTR_PROF_DATA]]"{{.*}}, align 8 CHECK: @__llvm_prf_nm = private constant diff --git a/src/test/run-make-fulldeps/issue-19371/foo.rs b/src/test/run-make-fulldeps/issue-19371/foo.rs index 4acabbb70ed..fd294b018af 100644 --- a/src/test/run-make-fulldeps/issue-19371/foo.rs +++ b/src/test/run-make-fulldeps/issue-19371/foo.rs @@ -49,13 +49,13 @@ 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), output_dir: None, file_loader: None, diagnostic_output: DiagnosticOutput::Default, - stderr: None, lint_caps: Default::default(), parse_sess_created: None, register_lints: None, 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/item-info-width.goml b/src/test/rustdoc-gui/item-info-width.goml index 82fcca94a18..7a32d902910 100644 --- a/src/test/rustdoc-gui/item-info-width.goml +++ b/src/test/rustdoc-gui/item-info-width.goml @@ -4,5 +4,5 @@ goto: file://|DOC_PATH|/lib2/struct.Foo.html size: (1100, 800) // We check that ".item-info" is bigger than its content. assert-css: (".item-info", {"width": "790px"}) -assert-css: (".item-info .stab", {"width": "339.562px"}) +assert-css: (".item-info .stab", {"width": "340px"}) assert-position: (".item-info .stab", {"x": 295}) 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-js-std/typed-query.js b/src/test/rustdoc-js-std/typed-query.js index f656aa72986..3915ee7dc5d 100644 --- a/src/test/rustdoc-js-std/typed-query.js +++ b/src/test/rustdoc-js-std/typed-query.js @@ -8,5 +8,7 @@ const EXPECTED = { { 'path': 'std', 'name': 'eprint' }, { 'path': 'std', 'name': 'println' }, { 'path': 'std', 'name': 'eprintln' }, + { 'path': 'std::pin', 'name': 'pin' }, + { 'path': 'core::pin', 'name': 'pin' }, ], }; 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/asm/bad-template.aarch64_mirunsafeck.stderr b/src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr index 3b1d922a7f7..11c4e01f418 100644 --- a/src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr +++ b/src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr @@ -23,10 +23,10 @@ LL | asm!("{1}", in(reg) foo); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` error: there is no argument named `a` - --> $DIR/bad-template.rs:36:15 + --> $DIR/bad-template.rs:36:16 | LL | asm!("{a}"); - | ^^^ + | ^ error: invalid reference to argument at index 0 --> $DIR/bad-template.rs:38:15 @@ -123,10 +123,10 @@ LL | global_asm!("{1}", const FOO); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` error: there is no argument named `a` - --> $DIR/bad-template.rs:63:14 + --> $DIR/bad-template.rs:63:15 | LL | global_asm!("{a}"); - | ^^^ + | ^ error: invalid reference to argument at index 0 --> $DIR/bad-template.rs:65:14 diff --git a/src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr b/src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr index 3b1d922a7f7..11c4e01f418 100644 --- a/src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr +++ b/src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr @@ -23,10 +23,10 @@ LL | asm!("{1}", in(reg) foo); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` error: there is no argument named `a` - --> $DIR/bad-template.rs:36:15 + --> $DIR/bad-template.rs:36:16 | LL | asm!("{a}"); - | ^^^ + | ^ error: invalid reference to argument at index 0 --> $DIR/bad-template.rs:38:15 @@ -123,10 +123,10 @@ LL | global_asm!("{1}", const FOO); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` error: there is no argument named `a` - --> $DIR/bad-template.rs:63:14 + --> $DIR/bad-template.rs:63:15 | LL | global_asm!("{a}"); - | ^^^ + | ^ error: invalid reference to argument at index 0 --> $DIR/bad-template.rs:65:14 diff --git a/src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr b/src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr index 3b69186f1e1..c198e0a69dd 100644 --- a/src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr +++ b/src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr @@ -23,10 +23,10 @@ LL | asm!("{1}", in(reg) foo); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` error: there is no argument named `a` - --> $DIR/bad-template.rs:36:15 + --> $DIR/bad-template.rs:36:16 | LL | asm!("{a}"); - | ^^^ + | ^ error: invalid reference to argument at index 0 --> $DIR/bad-template.rs:38:15 @@ -123,10 +123,10 @@ LL | global_asm!("{1}", const FOO); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` error: there is no argument named `a` - --> $DIR/bad-template.rs:63:14 + --> $DIR/bad-template.rs:63:15 | LL | global_asm!("{a}"); - | ^^^ + | ^ error: invalid reference to argument at index 0 --> $DIR/bad-template.rs:65:14 diff --git a/src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr b/src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr index 3b69186f1e1..c198e0a69dd 100644 --- a/src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr +++ b/src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr @@ -23,10 +23,10 @@ LL | asm!("{1}", in(reg) foo); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` error: there is no argument named `a` - --> $DIR/bad-template.rs:36:15 + --> $DIR/bad-template.rs:36:16 | LL | asm!("{a}"); - | ^^^ + | ^ error: invalid reference to argument at index 0 --> $DIR/bad-template.rs:38:15 @@ -123,10 +123,10 @@ LL | global_asm!("{1}", const FOO); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` error: there is no argument named `a` - --> $DIR/bad-template.rs:63:14 + --> $DIR/bad-template.rs:63:15 | LL | global_asm!("{a}"); - | ^^^ + | ^ error: invalid reference to argument at index 0 --> $DIR/bad-template.rs:65:14 diff --git a/src/test/ui/associated-types/associated-types-path-2.stderr b/src/test/ui/associated-types/associated-types-path-2.stderr index b3bb58f7814..f56631b12aa 100644 --- a/src/test/ui/associated-types/associated-types-path-2.stderr +++ b/src/test/ui/associated-types/associated-types-path-2.stderr @@ -15,6 +15,8 @@ error[E0277]: the trait bound `u32: Foo` is not satisfied LL | f1(2u32, 4u32); | ^^ the trait `Foo` is not implemented for `u32` | + = help: the following implementations were found: + <i32 as Foo> note: required by a bound in `f1` --> $DIR/associated-types-path-2.rs:13:14 | @@ -26,6 +28,9 @@ error[E0277]: the trait bound `u32: Foo` is not satisfied | LL | f1(2u32, 4u32); | ^^^^ the trait `Foo` is not implemented for `u32` + | + = help: the following implementations were found: + <i32 as Foo> error[E0277]: the trait bound `u32: Foo` is not satisfied --> $DIR/associated-types-path-2.rs:35:8 @@ -35,6 +40,8 @@ LL | f1(2u32, 4i32); | | | required by a bound introduced by this call | + = help: the following implementations were found: + <i32 as Foo> note: required by a bound in `f1` --> $DIR/associated-types-path-2.rs:13:14 | @@ -46,6 +53,9 @@ error[E0277]: the trait bound `u32: Foo` is not satisfied | LL | f1(2u32, 4i32); | ^^^^ the trait `Foo` is not implemented for `u32` + | + = help: the following implementations were found: + <i32 as Foo> error[E0308]: mismatched types --> $DIR/associated-types-path-2.rs:41:18 diff --git a/src/test/ui/associated-types/hr-associated-type-bound-1.stderr b/src/test/ui/associated-types/hr-associated-type-bound-1.stderr index 4eed5c9a008..ec28ca240be 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-1.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-1.stderr @@ -4,6 +4,8 @@ error[E0277]: the trait bound `str: Clone` is not satisfied LL | type U = str; | ^^^ the trait `Clone` is not implemented for `str` | + = help: the following implementations were found: + <String as Clone> note: required by a bound in `X` --> $DIR/hr-associated-type-bound-1.rs:3:33 | diff --git a/src/test/ui/associated-types/hr-associated-type-bound-object.stderr b/src/test/ui/associated-types/hr-associated-type-bound-object.stderr index 354f5ae4597..6d19186bde4 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-object.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-object.stderr @@ -4,8 +4,6 @@ error[E0277]: the trait bound `for<'b> <T as X<'b>>::U: Clone` is not satisfied LL | fn f<'a, T: X<'a> + ?Sized>(x: &<T as X<'a>>::U) { | ^^^^^ the trait `for<'b> Clone` is not implemented for `<T as X<'b>>::U` | - = help: the following implementations were found: - <&T as Clone> note: required by a bound in `X` --> $DIR/hr-associated-type-bound-object.rs:3:33 | diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr index 99f95c20051..e48ef8d17d1 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr @@ -4,6 +4,8 @@ error[E0277]: the trait bound `str: Clone` is not satisfied LL | type V = str; | ^^^ the trait `Clone` is not implemented for `str` | + = help: the following implementations were found: + <String as Clone> note: required by a bound in `Y` --> $DIR/hr-associated-type-bound-param-1.rs:4:36 | diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr index 354caef1e41..2fb3af38c0d 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr @@ -4,6 +4,8 @@ error[E0277]: the trait bound `str: Clone` is not satisfied LL | T: Z<'a, u16>, | ^^^^^^^^^^ the trait `Clone` is not implemented for `str` | + = help: the following implementations were found: + <String as Clone> note: required by a bound in `Z` --> $DIR/hr-associated-type-bound-param-2.rs:6:35 | @@ -19,6 +21,8 @@ error[E0277]: the trait bound `str: Clone` is not satisfied LL | T: Z<'a, u16>, | ^^^^^^^^^^ the trait `Clone` is not implemented for `str` | + = help: the following implementations were found: + <String as Clone> note: required by a bound in `Z` --> $DIR/hr-associated-type-bound-param-2.rs:6:35 | @@ -34,6 +38,8 @@ error[E0277]: the trait bound `str: Clone` is not satisfied LL | type W = str; | ^^^ the trait `Clone` is not implemented for `str` | + = help: the following implementations were found: + <String as Clone> note: required by a bound in `Z` --> $DIR/hr-associated-type-bound-param-2.rs:6:35 | diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr index 9935445c306..775f45ca829 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr @@ -4,6 +4,8 @@ error[E0277]: the trait bound `str: Clone` is not satisfied LL | type U = str; | ^^^ the trait `Clone` is not implemented for `str` | + = help: the following implementations were found: + <String as Clone> note: required by a bound in `X` --> $DIR/hr-associated-type-bound-param-3.rs:4:33 | diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr index c26324ee625..4e9b64ba832 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr @@ -4,6 +4,8 @@ error[E0277]: the trait bound `str: Clone` is not satisfied LL | type U = str; | ^^^ the trait `Clone` is not implemented for `str` | + = help: the following implementations were found: + <String as Clone> note: required by a bound in `X` --> $DIR/hr-associated-type-bound-param-4.rs:4:36 | diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr index 4c04d12a714..d00abf30d3b 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr @@ -4,6 +4,8 @@ error[E0277]: the trait bound `str: Clone` is not satisfied LL | type U = str; | ^^^ the trait `Clone` is not implemented for `str` | + = help: the following implementations were found: + <String as Clone> note: required by a bound in `X` --> $DIR/hr-associated-type-bound-param-5.rs:17:45 | @@ -19,6 +21,8 @@ error[E0277]: the trait bound `str: Clone` is not satisfied LL | type U = str; | ^^^ the trait `Clone` is not implemented for `str` | + = help: the following implementations were found: + <String as Clone> note: required by a bound in `X` --> $DIR/hr-associated-type-bound-param-5.rs:17:45 | diff --git a/src/test/ui/associated-types/substs-ppaux.rs b/src/test/ui/associated-types/substs-ppaux.rs index 974a1d961a0..66cd94d7a1b 100644 --- a/src/test/ui/associated-types/substs-ppaux.rs +++ b/src/test/ui/associated-types/substs-ppaux.rs @@ -25,7 +25,7 @@ fn foo<'z>() where &'z (): Sized { let x: () = <i8 as Foo<'static, 'static, u32>>::bar::<'static, char>; //[verbose]~^ ERROR mismatched types //[verbose]~| expected unit type `()` - //[verbose]~| found fn item `fn() {<i8 as Foo<ReStatic, ReStatic, u32>>::bar::<ReStatic, char>}` + //[verbose]~| found fn item `fn() {<i8 as Foo<ReStatic, ReStatic>>::bar::<ReStatic, char>}` //[normal]~^^^^ ERROR mismatched types //[normal]~| expected unit type `()` //[normal]~| found fn item `fn() {<i8 as Foo<'static, 'static>>::bar::<'static, char>}` diff --git a/src/test/ui/associated-types/substs-ppaux.verbose.stderr b/src/test/ui/associated-types/substs-ppaux.verbose.stderr index cf480223da2..b831f3b7a76 100644 --- a/src/test/ui/associated-types/substs-ppaux.verbose.stderr +++ b/src/test/ui/associated-types/substs-ppaux.verbose.stderr @@ -20,7 +20,7 @@ error[E0308]: mismatched types --> $DIR/substs-ppaux.rs:25:17 | LL | fn bar<'a, T>() where T: 'a {} - | --------------------------- fn() {<i8 as Foo<ReStatic, ReStatic, u32>>::bar::<ReStatic, char>} defined here + | --------------------------- fn() {<i8 as Foo<ReStatic, ReStatic>>::bar::<ReStatic, char>} defined here ... LL | let x: () = <i8 as Foo<'static, 'static, u32>>::bar::<'static, char>; | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found fn item @@ -28,7 +28,7 @@ LL | let x: () = <i8 as Foo<'static, 'static, u32>>::bar::<'static, char>; | expected due to this | = note: expected unit type `()` - found fn item `fn() {<i8 as Foo<ReStatic, ReStatic, u32>>::bar::<ReStatic, char>}` + found fn item `fn() {<i8 as Foo<ReStatic, ReStatic>>::bar::<ReStatic, char>}` help: use parentheses to call this function | LL | let x: () = <i8 as Foo<'static, 'static, u32>>::bar::<'static, char>(); 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/issue-93197.rs b/src/test/ui/async-await/issue-93197.rs index 05ec013d0af..c627fe17afb 100644 --- a/src/test/ui/async-await/issue-93197.rs +++ b/src/test/ui/async-await/issue-93197.rs @@ -1,6 +1,7 @@ // Regression test for #93197 // check-pass // edition:2021 +// compile-flags: -Zdrop-tracking #![feature(try_blocks)] 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/auto-traits/typeck-default-trait-impl-precedence.stderr b/src/test/ui/auto-traits/typeck-default-trait-impl-precedence.stderr index 8ce70b1ac06..5755778fef2 100644 --- a/src/test/ui/auto-traits/typeck-default-trait-impl-precedence.stderr +++ b/src/test/ui/auto-traits/typeck-default-trait-impl-precedence.stderr @@ -4,6 +4,8 @@ error[E0277]: the trait bound `u32: Signed` is not satisfied LL | is_defaulted::<&'static u32>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Signed` is not implemented for `u32` | + = help: the following implementations were found: + <i32 as Signed> note: required because of the requirements on the impl of `Defaulted` for `&'static u32` --> $DIR/typeck-default-trait-impl-precedence.rs:10:19 | diff --git a/src/test/ui/binop/issue-28837.stderr b/src/test/ui/binop/issue-28837.stderr index 10f243bab15..1875ea06a06 100644 --- a/src/test/ui/binop/issue-28837.stderr +++ b/src/test/ui/binop/issue-28837.stderr @@ -272,9 +272,9 @@ note: an implementation of `PartialOrd<_>` might be missing for `A` | LL | struct A; | ^^^^^^^^^ must implement `PartialOrd<_>` -help: consider annotating `A` with `#[derive(PartialOrd)]` +help: consider annotating `A` with `#[derive(PartialEq, PartialOrd)]` | -LL | #[derive(PartialOrd)] +LL | #[derive(PartialEq, PartialOrd)] | error[E0369]: binary operation `<=` cannot be applied to type `A` @@ -290,9 +290,9 @@ note: an implementation of `PartialOrd<_>` might be missing for `A` | LL | struct A; | ^^^^^^^^^ must implement `PartialOrd<_>` -help: consider annotating `A` with `#[derive(PartialOrd)]` +help: consider annotating `A` with `#[derive(PartialEq, PartialOrd)]` | -LL | #[derive(PartialOrd)] +LL | #[derive(PartialEq, PartialOrd)] | error[E0369]: binary operation `>` cannot be applied to type `A` @@ -308,9 +308,9 @@ note: an implementation of `PartialOrd<_>` might be missing for `A` | LL | struct A; | ^^^^^^^^^ must implement `PartialOrd<_>` -help: consider annotating `A` with `#[derive(PartialOrd)]` +help: consider annotating `A` with `#[derive(PartialEq, PartialOrd)]` | -LL | #[derive(PartialOrd)] +LL | #[derive(PartialEq, PartialOrd)] | error[E0369]: binary operation `>=` cannot be applied to type `A` @@ -326,9 +326,9 @@ note: an implementation of `PartialOrd<_>` might be missing for `A` | LL | struct A; | ^^^^^^^^^ must implement `PartialOrd<_>` -help: consider annotating `A` with `#[derive(PartialOrd)]` +help: consider annotating `A` with `#[derive(PartialEq, PartialOrd)]` | -LL | #[derive(PartialOrd)] +LL | #[derive(PartialEq, PartialOrd)] | error: aborting due to 15 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/chalkify/chalk_initial_program.stderr b/src/test/ui/chalkify/chalk_initial_program.stderr index f8b792ae536..7b0b3f85b39 100644 --- a/src/test/ui/chalkify/chalk_initial_program.stderr +++ b/src/test/ui/chalkify/chalk_initial_program.stderr @@ -4,6 +4,9 @@ error[E0277]: the trait bound `f32: Foo` is not satisfied LL | gimme::<f32>(); | ^^^ the trait `Foo` is not implemented for `f32` | + = help: the following implementations were found: + <i32 as Foo> + <u32 as Foo> note: required by a bound in `gimme` --> $DIR/chalk_initial_program.rs:9:13 | diff --git a/src/test/ui/chalkify/impl_wf.stderr b/src/test/ui/chalkify/impl_wf.stderr index 95e320726aa..2bc9f077f02 100644 --- a/src/test/ui/chalkify/impl_wf.stderr +++ b/src/test/ui/chalkify/impl_wf.stderr @@ -17,6 +17,8 @@ error[E0277]: the trait bound `f32: Foo` is not satisfied LL | impl Baz<f32> for f32 { } | ^^^^^^^^ the trait `Foo` is not implemented for `f32` | + = help: the following implementations were found: + <i32 as Foo> note: required by a bound in `Baz` --> $DIR/impl_wf.rs:18:31 | diff --git a/src/test/ui/chalkify/impl_wf_2.stderr b/src/test/ui/chalkify/impl_wf_2.stderr index 80ec03d6221..30cec80b036 100644 --- a/src/test/ui/chalkify/impl_wf_2.stderr +++ b/src/test/ui/chalkify/impl_wf_2.stderr @@ -4,6 +4,8 @@ error[E0277]: the trait bound `f32: Foo` is not satisfied LL | type Item = f32; | ^^^ the trait `Foo` is not implemented for `f32` | + = help: the following implementations were found: + <i32 as Foo> note: required by a bound in `Bar::Item` --> $DIR/impl_wf_2.rs:8:16 | diff --git a/src/test/ui/chalkify/type_wf.stderr b/src/test/ui/chalkify/type_wf.stderr index 57902efa201..6abd8b28760 100644 --- a/src/test/ui/chalkify/type_wf.stderr +++ b/src/test/ui/chalkify/type_wf.stderr @@ -5,7 +5,6 @@ LL | let s = S { | ^ the trait `Foo` is not implemented for `{float}` | = help: the following implementations were found: - <Option<T> as Foo> <i32 as Foo> note: required by a bound in `S` --> $DIR/type_wf.rs:6:13 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/coherence/auxiliary/error_lib.rs b/src/test/ui/coherence/auxiliary/error_lib.rs index 43806cb995c..19ff9ae62fd 100644 --- a/src/test/ui/coherence/auxiliary/error_lib.rs +++ b/src/test/ui/coherence/auxiliary/error_lib.rs @@ -1,5 +1,6 @@ #![crate_type = "lib"] #![feature(negative_impls)] +#![feature(with_negative_coherence)] pub trait Error {} impl !Error for &str {} diff --git a/src/test/ui/coherence/coherence-negative-outlives-lifetimes.rs b/src/test/ui/coherence/coherence-negative-outlives-lifetimes.rs new file mode 100644 index 00000000000..159788b1b77 --- /dev/null +++ b/src/test/ui/coherence/coherence-negative-outlives-lifetimes.rs @@ -0,0 +1,12 @@ +#![feature(negative_impls)] + +// FIXME: this should compile + +trait MyPredicate<'a> {} +impl<'a, T> !MyPredicate<'a> for &T where T: 'a {} +trait MyTrait<'a> {} +impl<'a, T: MyPredicate<'a>> MyTrait<'a> for T {} +impl<'a, T> MyTrait<'a> for &'a T {} +//~^ ERROR: conflicting implementations of trait `MyTrait<'_>` for type `&_` + +fn main() {} diff --git a/src/test/ui/coherence/coherence-negative-outlives-lifetimes.stderr b/src/test/ui/coherence/coherence-negative-outlives-lifetimes.stderr new file mode 100644 index 00000000000..263bd19b424 --- /dev/null +++ b/src/test/ui/coherence/coherence-negative-outlives-lifetimes.stderr @@ -0,0 +1,11 @@ +error[E0119]: conflicting implementations of trait `MyTrait<'_>` for type `&_` + --> $DIR/coherence-negative-outlives-lifetimes.rs:9:1 + | +LL | impl<'a, T: MyPredicate<'a>> MyTrait<'a> for T {} + | ---------------------------------------------- first implementation here +LL | impl<'a, T> MyTrait<'a> for &'a T {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `&_` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/coherence/coherence-overlap-negate-use-feature-gate.rs b/src/test/ui/coherence/coherence-overlap-negate-use-feature-gate.rs index e024eae9819..a0dd881d1aa 100644 --- a/src/test/ui/coherence/coherence-overlap-negate-use-feature-gate.rs +++ b/src/test/ui/coherence/coherence-overlap-negate-use-feature-gate.rs @@ -1,6 +1,6 @@ // check-pass -#![feature(negative_impls)] +#![feature(with_negative_coherence)] use std::ops::DerefMut; diff --git a/src/test/ui/coherence/coherence-overlap-negative-trait.rs b/src/test/ui/coherence/coherence-overlap-negative-trait.rs index ab65163bea4..8059d23ffd2 100644 --- a/src/test/ui/coherence/coherence-overlap-negative-trait.rs +++ b/src/test/ui/coherence/coherence-overlap-negative-trait.rs @@ -3,7 +3,7 @@ // // Check that if we promise to not impl what would overlap it doesn't actually overlap -#![feature(negative_impls)] +#![feature(with_negative_coherence)] extern crate error_lib as lib; use lib::Error; diff --git a/src/test/ui/coherence/coherence-overlap-with-regions.rs b/src/test/ui/coherence/coherence-overlap-with-regions.rs new file mode 100644 index 00000000000..32f01f41801 --- /dev/null +++ b/src/test/ui/coherence/coherence-overlap-with-regions.rs @@ -0,0 +1,16 @@ +// check-pass + +#![feature(negative_impls)] +#![feature(rustc_attrs)] +#![feature(with_negative_coherence)] + +#[rustc_strict_coherence] +trait Foo {} +impl<T> !Foo for &T where T: 'static {} + +#[rustc_strict_coherence] +trait Bar {} +impl<T: Foo> Bar for T {} +impl<T> Bar for &T where T: 'static {} + +fn main() {} diff --git a/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr b/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr index 8c8bfdc0e48..19813a491c9 100644 --- a/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr +++ b/src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr @@ -15,6 +15,7 @@ LL | fn uwu<const N: u8>() -> impl Traitor<N> { | = help: the following implementations were found: <u32 as Traitor<N, 2_u8>> + <u64 as Traitor<1_u8, 2_u8>> error[E0277]: the trait bound `u64: Traitor<1_u8, 1_u8>` is not satisfied --> $DIR/rp_impl_trait_fail.rs:22:13 @@ -24,6 +25,7 @@ LL | fn owo() -> impl Traitor { | = help: the following implementations were found: <u64 as Traitor<1_u8, 2_u8>> + <u32 as Traitor<N, 2_u8>> error: aborting due to 3 previous errors diff --git a/src/test/ui/derives/issue-91550.rs b/src/test/ui/derives/issue-91550.rs new file mode 100644 index 00000000000..56fd5ffa89e --- /dev/null +++ b/src/test/ui/derives/issue-91550.rs @@ -0,0 +1,29 @@ +use std::collections::HashSet; + +/// natural case from the issue +struct Value(u32); + +fn main() { + let hs = HashSet::<Value>::new(); + hs.insert(Value(0)); //~ ERROR +} + +/// synthetic cases +pub struct NoDerives; + +struct Object<T>(T); +impl<T: Eq> Object<T> { + fn use_eq(&self) {} +} +impl<T: Ord> Object<T> { + fn use_ord(&self) {} +} +impl<T: Ord + PartialOrd> Object<T> { + fn use_ord_and_partial_ord(&self) {} +} + +fn function(foo: Object<NoDerives>) { + foo.use_eq(); //~ ERROR + foo.use_ord(); //~ ERROR + foo.use_ord_and_partial_ord(); //~ ERROR +} diff --git a/src/test/ui/derives/issue-91550.stderr b/src/test/ui/derives/issue-91550.stderr new file mode 100644 index 00000000000..bf4b7c7da0d --- /dev/null +++ b/src/test/ui/derives/issue-91550.stderr @@ -0,0 +1,84 @@ +error[E0599]: the method `insert` exists for struct `HashSet<Value>`, but its trait bounds were not satisfied + --> $DIR/issue-91550.rs:8:8 + | +LL | struct Value(u32); + | ------------------ + | | + | doesn't satisfy `Value: Eq` + | doesn't satisfy `Value: Hash` +... +LL | hs.insert(Value(0)); + | ^^^^^^ method cannot be called on `HashSet<Value>` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `Value: Eq` + `Value: Hash` +help: consider annotating `Value` with `#[derive(Eq, Hash, PartialEq)]` + | +LL | #[derive(Eq, Hash, PartialEq)] + | + +error[E0599]: the method `use_eq` exists for struct `Object<NoDerives>`, but its trait bounds were not satisfied + --> $DIR/issue-91550.rs:26:9 + | +LL | pub struct NoDerives; + | --------------------- doesn't satisfy `NoDerives: Eq` +LL | +LL | struct Object<T>(T); + | -------------------- method `use_eq` not found for this +... +LL | foo.use_eq(); + | ^^^^^^ method cannot be called on `Object<NoDerives>` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `NoDerives: Eq` +help: consider annotating `NoDerives` with `#[derive(Eq, PartialEq)]` + | +LL | #[derive(Eq, PartialEq)] + | + +error[E0599]: the method `use_ord` exists for struct `Object<NoDerives>`, but its trait bounds were not satisfied + --> $DIR/issue-91550.rs:27:9 + | +LL | pub struct NoDerives; + | --------------------- doesn't satisfy `NoDerives: Ord` +LL | +LL | struct Object<T>(T); + | -------------------- method `use_ord` not found for this +... +LL | foo.use_ord(); + | ^^^^^^^ method cannot be called on `Object<NoDerives>` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `NoDerives: Ord` +help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]` + | +LL | #[derive(Eq, Ord, PartialEq, PartialOrd)] + | + +error[E0599]: the method `use_ord_and_partial_ord` exists for struct `Object<NoDerives>`, but its trait bounds were not satisfied + --> $DIR/issue-91550.rs:28:9 + | +LL | pub struct NoDerives; + | --------------------- + | | + | doesn't satisfy `NoDerives: Ord` + | doesn't satisfy `NoDerives: PartialOrd` +LL | +LL | struct Object<T>(T); + | -------------------- method `use_ord_and_partial_ord` not found for this +... +LL | foo.use_ord_and_partial_ord(); + | ^^^^^^^^^^^^^^^^^^^^^^^ method cannot be called on `Object<NoDerives>` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `NoDerives: Ord` + `NoDerives: PartialOrd` +help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]` + | +LL | #[derive(Eq, Ord, PartialEq, PartialOrd)] + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr b/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr index 5381a717dc3..dff98030191 100644 --- a/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr +++ b/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr @@ -11,7 +11,7 @@ LL | Foo::<i32>::bar(&1i8); <i8 as Foo<u16>> <i8 as Foo<u32>> <i8 as Foo<u64>> - <i8 as Foo<u8>> + and 5 others error[E0277]: the trait bound `u8: Foo<i32>` is not satisfied --> $DIR/issue-39802-show-5-trait-impls.rs:25:21 @@ -26,6 +26,7 @@ LL | Foo::<i32>::bar(&1u8); <u8 as Foo<u16>> <u8 as Foo<u32>> <u8 as Foo<u64>> + and 5 others error[E0277]: the trait bound `bool: Foo<i32>` is not satisfied --> $DIR/issue-39802-show-5-trait-impls.rs:26:21 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-cfg-target-has-atomic.rs b/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.rs new file mode 100644 index 00000000000..df9c51cb176 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.rs @@ -0,0 +1,14 @@ +fn main() { + cfg!(target_has_atomic_load_store = "8"); + //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change + cfg!(target_has_atomic_load_store = "16"); + //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change + cfg!(target_has_atomic_load_store = "32"); + //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change + cfg!(target_has_atomic_load_store = "64"); + //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change + cfg!(target_has_atomic_load_store = "128"); + //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change + cfg!(target_has_atomic_load_store = "ptr"); + //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change +} diff --git a/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.stderr b/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.stderr new file mode 100644 index 00000000000..b9e6830a9f0 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.stderr @@ -0,0 +1,57 @@ +error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:2:10 + | +LL | cfg!(target_has_atomic_load_store = "8"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #94039 <https://github.com/rust-lang/rust/issues/94039> for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:4:10 + | +LL | cfg!(target_has_atomic_load_store = "16"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #94039 <https://github.com/rust-lang/rust/issues/94039> for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:6:10 + | +LL | cfg!(target_has_atomic_load_store = "32"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #94039 <https://github.com/rust-lang/rust/issues/94039> for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:8:10 + | +LL | cfg!(target_has_atomic_load_store = "64"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #94039 <https://github.com/rust-lang/rust/issues/94039> for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:10:10 + | +LL | cfg!(target_has_atomic_load_store = "128"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #94039 <https://github.com/rust-lang/rust/issues/94039> for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:12:10 + | +LL | cfg!(target_has_atomic_load_store = "ptr"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #94039 <https://github.com/rust-lang/rust/issues/94039> for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error: aborting due to 6 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/feature-gates/feature-gate-unsafe_pin_internals.rs b/src/test/ui/feature-gates/feature-gate-unsafe_pin_internals.rs new file mode 100644 index 00000000000..0680d234403 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-unsafe_pin_internals.rs @@ -0,0 +1,17 @@ +// edition:2018 +#![forbid(incomplete_features, unsafe_code)] +#![feature(unsafe_pin_internals)] +//~^ ERROR the feature `unsafe_pin_internals` is incomplete and may not be safe to use + +use core::{marker::PhantomPinned, pin::Pin}; + +/// The `unsafe_pin_internals` is indeed unsound. +fn non_unsafe_pin_new_unchecked<T>(pointer: &mut T) -> Pin<&mut T> { + Pin { pointer } +} + +fn main() { + let mut self_referential = PhantomPinned; + let _: Pin<&mut PhantomPinned> = non_unsafe_pin_new_unchecked(&mut self_referential); + core::mem::forget(self_referential); // move and disable drop glue! +} diff --git a/src/test/ui/feature-gates/feature-gate-unsafe_pin_internals.stderr b/src/test/ui/feature-gates/feature-gate-unsafe_pin_internals.stderr new file mode 100644 index 00000000000..4d0c931b404 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-unsafe_pin_internals.stderr @@ -0,0 +1,14 @@ +error: the feature `unsafe_pin_internals` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/feature-gate-unsafe_pin_internals.rs:3:12 + | +LL | #![feature(unsafe_pin_internals)] + | ^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/feature-gate-unsafe_pin_internals.rs:2:11 + | +LL | #![forbid(incomplete_features, unsafe_code)] + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/feature-gates/feature-gate-untagged_unions.rs b/src/test/ui/feature-gates/feature-gate-untagged_unions.rs index f5f9631c3bc..af8d8e92b20 100644 --- a/src/test/ui/feature-gates/feature-gate-untagged_unions.rs +++ b/src/test/ui/feature-gates/feature-gate-untagged_unions.rs @@ -13,7 +13,7 @@ union U22<T> { // OK } union U3 { - a: String, //~ ERROR unions may not contain fields that need dropping + a: String, //~ ERROR unions cannot contain fields that may need dropping } union U32 { // field that does not drop but is not `Copy`, either -- this is the real feature gate test! @@ -21,7 +21,7 @@ union U32 { // field that does not drop but is not `Copy`, either -- this is the } union U4<T> { - a: T, //~ ERROR unions may not contain fields that need dropping + a: T, //~ ERROR unions cannot contain fields that may need dropping } union U5 { // Having a drop impl is OK diff --git a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr b/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr index 0967cb7ba8b..9e4a89f80c8 100644 --- a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr +++ b/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr @@ -7,24 +7,26 @@ LL | a: std::cell::RefCell<i32>, = note: see issue #55149 <https://github.com/rust-lang/rust/issues/55149> for more information = help: add `#![feature(untagged_unions)]` to the crate attributes to enable -error[E0740]: unions may not contain fields that need dropping +error[E0740]: unions cannot contain fields that may need dropping --> $DIR/feature-gate-untagged_unions.rs:16:5 | LL | a: String, | ^^^^^^^^^ | -help: wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped + = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type +help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped | LL | a: std::mem::ManuallyDrop<String>, | +++++++++++++++++++++++ + -error[E0740]: unions may not contain fields that need dropping +error[E0740]: unions cannot contain fields that may need dropping --> $DIR/feature-gate-untagged_unions.rs:24:5 | LL | a: T, | ^^^^ | -help: wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped + = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type +help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped | LL | a: std::mem::ManuallyDrop<T>, | +++++++++++++++++++++++ + diff --git a/src/test/ui/fmt/format-args-capture-issue-93378.stderr b/src/test/ui/fmt/format-args-capture-issue-93378.stderr index 588541044fe..b8e2b2afb38 100644 --- a/src/test/ui/fmt/format-args-capture-issue-93378.stderr +++ b/src/test/ui/fmt/format-args-capture-issue-93378.stderr @@ -10,10 +10,10 @@ error: invalid reference to positional argument 0 (no arguments were given) --> $DIR/format-args-capture-issue-93378.rs:9:23 | LL | println!("{a:.n$} {b:.*}"); - | ------- ^^^--^ - | | | - | | this precision flag adds an extra required argument at position 0, which is why there are 3 arguments expected - | this parameter corresponds to the precision flag + | - ^^^--^ + | | | + | | this precision flag adds an extra required argument at position 0, which is why there are 3 arguments expected + | this parameter corresponds to the precision flag | = note: positional arguments are zero-based = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html diff --git a/src/test/ui/fmt/format-args-capture-issue-94010.rs b/src/test/ui/fmt/format-args-capture-issue-94010.rs new file mode 100644 index 00000000000..bd03e9c93ae --- /dev/null +++ b/src/test/ui/fmt/format-args-capture-issue-94010.rs @@ -0,0 +1,7 @@ +fn main() { + const FOO: i32 = 123; + println!("{foo:X}"); + //~^ ERROR: cannot find value `foo` in this scope + println!("{:.foo$}", 0); + //~^ ERROR: cannot find value `foo` in this scope +} diff --git a/src/test/ui/fmt/format-args-capture-issue-94010.stderr b/src/test/ui/fmt/format-args-capture-issue-94010.stderr new file mode 100644 index 00000000000..ed90dc85536 --- /dev/null +++ b/src/test/ui/fmt/format-args-capture-issue-94010.stderr @@ -0,0 +1,20 @@ +error[E0425]: cannot find value `foo` in this scope + --> $DIR/format-args-capture-issue-94010.rs:3:16 + | +LL | const FOO: i32 = 123; + | --------------------- similarly named constant `FOO` defined here +LL | println!("{foo:X}"); + | ^^^ help: a constant with a similar name exists (notice the capitalization): `FOO` + +error[E0425]: cannot find value `foo` in this scope + --> $DIR/format-args-capture-issue-94010.rs:5:18 + | +LL | const FOO: i32 = 123; + | --------------------- similarly named constant `FOO` defined here +... +LL | println!("{:.foo$}", 0); + | ^^^ help: a constant with a similar name exists (notice the capitalization): `FOO` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/fmt/format-args-capture-missing-variables.stderr b/src/test/ui/fmt/format-args-capture-missing-variables.stderr index d53c206003f..d980e7be273 100644 --- a/src/test/ui/fmt/format-args-capture-missing-variables.stderr +++ b/src/test/ui/fmt/format-args-capture-missing-variables.stderr @@ -7,40 +7,40 @@ LL | format!("{valuea} {valueb}", valuea=5, valuec=7); | formatting specifier missing error[E0425]: cannot find value `foo` in this scope - --> $DIR/format-args-capture-missing-variables.rs:2:17 + --> $DIR/format-args-capture-missing-variables.rs:2:18 | LL | format!("{} {foo} {} {bar} {}", 1, 2, 3); - | ^^^^^ not found in this scope + | ^^^ not found in this scope error[E0425]: cannot find value `bar` in this scope - --> $DIR/format-args-capture-missing-variables.rs:2:26 + --> $DIR/format-args-capture-missing-variables.rs:2:27 | LL | format!("{} {foo} {} {bar} {}", 1, 2, 3); - | ^^^^^ not found in this scope + | ^^^ not found in this scope error[E0425]: cannot find value `foo` in this scope - --> $DIR/format-args-capture-missing-variables.rs:6:14 + --> $DIR/format-args-capture-missing-variables.rs:6:15 | LL | format!("{foo}"); - | ^^^^^ not found in this scope + | ^^^ not found in this scope error[E0425]: cannot find value `valueb` in this scope - --> $DIR/format-args-capture-missing-variables.rs:8:23 + --> $DIR/format-args-capture-missing-variables.rs:8:24 | LL | format!("{valuea} {valueb}", valuea=5, valuec=7); - | ^^^^^^^^ not found in this scope + | ^^^^^^ not found in this scope error[E0425]: cannot find value `foo` in this scope - --> $DIR/format-args-capture-missing-variables.rs:14:9 + --> $DIR/format-args-capture-missing-variables.rs:14:10 | LL | {foo} - | ^^^^^ not found in this scope + | ^^^ not found in this scope error[E0425]: cannot find value `foo` in this scope - --> $DIR/format-args-capture-missing-variables.rs:19:13 + --> $DIR/format-args-capture-missing-variables.rs:19:14 | LL | panic!("{foo} {bar}", bar=1); - | ^^^^^ not found in this scope + | ^^^ not found in this scope error: aborting due to 7 previous errors 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/fmt/ifmt-bad-arg.stderr b/src/test/ui/fmt/ifmt-bad-arg.stderr index acc4e95f5bb..3f1f1006713 100644 --- a/src/test/ui/fmt/ifmt-bad-arg.stderr +++ b/src/test/ui/fmt/ifmt-bad-arg.stderr @@ -263,34 +263,34 @@ LL | println!("{:.*}"); = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html error[E0425]: cannot find value `foo` in this scope - --> $DIR/ifmt-bad-arg.rs:27:17 + --> $DIR/ifmt-bad-arg.rs:27:18 | LL | format!("{} {foo} {} {bar} {}", 1, 2, 3); - | ^^^^^ not found in this scope + | ^^^ not found in this scope error[E0425]: cannot find value `bar` in this scope - --> $DIR/ifmt-bad-arg.rs:27:26 + --> $DIR/ifmt-bad-arg.rs:27:27 | LL | format!("{} {foo} {} {bar} {}", 1, 2, 3); - | ^^^^^ not found in this scope + | ^^^ not found in this scope error[E0425]: cannot find value `foo` in this scope - --> $DIR/ifmt-bad-arg.rs:31:14 + --> $DIR/ifmt-bad-arg.rs:31:15 | LL | format!("{foo}"); - | ^^^^^ not found in this scope + | ^^^ not found in this scope error[E0425]: cannot find value `valueb` in this scope - --> $DIR/ifmt-bad-arg.rs:45:23 + --> $DIR/ifmt-bad-arg.rs:45:24 | LL | format!("{valuea} {valueb}", valuea=5, valuec=7); - | ^^^^^^^^ not found in this scope + | ^^^^^^ not found in this scope error[E0425]: cannot find value `foo` in this scope - --> $DIR/ifmt-bad-arg.rs:60:9 + --> $DIR/ifmt-bad-arg.rs:60:10 | LL | {foo} - | ^^^^^ not found in this scope + | ^^^ not found in this scope error[E0308]: mismatched types --> $DIR/ifmt-bad-arg.rs:78:32 diff --git a/src/test/ui/functions-closures/fn-help-with-err-generic-is-not-function.rs b/src/test/ui/functions-closures/fn-help-with-err-generic-is-not-function.rs new file mode 100644 index 00000000000..26deb598762 --- /dev/null +++ b/src/test/ui/functions-closures/fn-help-with-err-generic-is-not-function.rs @@ -0,0 +1,22 @@ +struct Struct<T>(T); +impl Struct<T> +//~^ ERROR cannot find type `T` in this scope +//~| NOTE not found in this scope +//~| HELP you might be missing a type parameter +where + T: Copy, + //~^ ERROR cannot find type `T` in this scope + //~| NOTE not found in this scope +{ + // The part where it claims that there is no method named `len` is a bug. Feel free to fix it. + // This test is intended to ensure that a different bug, where it claimed + // that `v` was a function, does not regress. + fn method(v: Vec<u8>) { v.len(); } + //~^ ERROR type annotations needed + //~| NOTE cannot infer type + //~| NOTE type must be known at this point + //~| ERROR no method named `len` + //~| NOTE private field, not a method +} + +fn main() {} diff --git a/src/test/ui/functions-closures/fn-help-with-err-generic-is-not-function.stderr b/src/test/ui/functions-closures/fn-help-with-err-generic-is-not-function.stderr new file mode 100644 index 00000000000..958ce3c25d0 --- /dev/null +++ b/src/test/ui/functions-closures/fn-help-with-err-generic-is-not-function.stderr @@ -0,0 +1,32 @@ +error[E0412]: cannot find type `T` in this scope + --> $DIR/fn-help-with-err-generic-is-not-function.rs:2:13 + | +LL | impl Struct<T> + | - ^ not found in this scope + | | + | help: you might be missing a type parameter: `<T>` + +error[E0412]: cannot find type `T` in this scope + --> $DIR/fn-help-with-err-generic-is-not-function.rs:7:5 + | +LL | T: Copy, + | ^ not found in this scope + +error[E0282]: type annotations needed + --> $DIR/fn-help-with-err-generic-is-not-function.rs:14:31 + | +LL | fn method(v: Vec<u8>) { v.len(); } + | ^^^ cannot infer type + | + = note: type must be known at this point + +error[E0599]: no method named `len` found for struct `Vec<u8>` in the current scope + --> $DIR/fn-help-with-err-generic-is-not-function.rs:14:31 + | +LL | fn method(v: Vec<u8>) { v.len(); } + | ^^^ private field, not a method + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0282, E0412, E0599. +For more information about an error, try `rustc --explain E0282`. diff --git a/src/test/ui/functions-closures/fn-help-with-err.rs b/src/test/ui/functions-closures/fn-help-with-err.rs new file mode 100644 index 00000000000..f8a81af786f --- /dev/null +++ b/src/test/ui/functions-closures/fn-help-with-err.rs @@ -0,0 +1,16 @@ +// This test case checks the behavior of typeck::check::method::suggest::is_fn on Ty::Error. +fn main() { + let arc = std::sync::Arc::new(oops); + //~^ ERROR cannot find value `oops` in this scope + //~| NOTE not found + // The error "note: `arc` is a function, perhaps you wish to call it" MUST NOT appear. + arc.blablabla(); + //~^ ERROR no method named `blablabla` + //~| NOTE method not found + let arc2 = std::sync::Arc::new(|| 1); + // The error "note: `arc2` is a function, perhaps you wish to call it" SHOULD appear + arc2.blablabla(); + //~^ ERROR no method named `blablabla` + //~| NOTE method not found + //~| NOTE `arc2` is a function, perhaps you wish to call it +} diff --git a/src/test/ui/functions-closures/fn-help-with-err.stderr b/src/test/ui/functions-closures/fn-help-with-err.stderr new file mode 100644 index 00000000000..4d6b3282ad9 --- /dev/null +++ b/src/test/ui/functions-closures/fn-help-with-err.stderr @@ -0,0 +1,24 @@ +error[E0425]: cannot find value `oops` in this scope + --> $DIR/fn-help-with-err.rs:3:35 + | +LL | let arc = std::sync::Arc::new(oops); + | ^^^^ not found in this scope + +error[E0599]: no method named `blablabla` found for struct `Arc<_>` in the current scope + --> $DIR/fn-help-with-err.rs:7:9 + | +LL | arc.blablabla(); + | ^^^^^^^^^ method not found in `Arc<_>` + +error[E0599]: no method named `blablabla` found for struct `Arc<[closure@$DIR/fn-help-with-err.rs:10:36: 10:40]>` in the current scope + --> $DIR/fn-help-with-err.rs:12:10 + | +LL | arc2.blablabla(); + | ^^^^^^^^^ method not found in `Arc<[closure@$DIR/fn-help-with-err.rs:10:36: 10:40]>` + | + = note: `arc2` is a function, perhaps you wish to call it + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0425, E0599. +For more information about an error, try `rustc --explain E0425`. diff --git a/src/test/ui/generator/drop-control-flow.rs b/src/test/ui/generator/drop-control-flow.rs index 8540f7617ac..914a7d71dc4 100644 --- a/src/test/ui/generator/drop-control-flow.rs +++ b/src/test/ui/generator/drop-control-flow.rs @@ -1,4 +1,5 @@ // build-pass +// compile-flags: -Zdrop-tracking // FIXME(eholk): temporarily disabled while drop range tracking is disabled // (see generator_interior.rs:27) @@ -114,6 +115,22 @@ fn nested_loop() { }; } +fn loop_continue(b: bool) { + let _ = || { + let mut arr = [Ptr]; + let mut count = 0; + drop(arr); + while count < 3 { + count += 1; + yield; + if b { + arr = [Ptr]; + continue; + } + } + }; +} + fn main() { one_armed_if(true); if_let(Some(41)); @@ -122,4 +139,5 @@ fn main() { reinit(); loop_uninit(); nested_loop(); + loop_continue(true); } 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/generic-associated-types/self-outlives-lint.rs b/src/test/ui/generic-associated-types/self-outlives-lint.rs index fcc53b4ede0..300907adbfc 100644 --- a/src/test/ui/generic-associated-types/self-outlives-lint.rs +++ b/src/test/ui/generic-associated-types/self-outlives-lint.rs @@ -140,11 +140,19 @@ trait NotInReturn { // We obviously error for `Iterator`, but we should also error for `Item` trait IterableTwo { type Item<'a>; + //~^ missing required type Iterator<'a>: Iterator<Item = Self::Item<'a>>; //~^ missing required fn iter<'a>(&'a self) -> Self::Iterator<'a>; } +trait IterableTwoWhere { + type Item<'a>; + //~^ missing required + type Iterator<'a>: Iterator<Item = Self::Item<'a>> where Self: 'a; + fn iter<'a>(&'a self) -> Self::Iterator<'a>; +} + // We also should report region outlives clauses. Here, we know that `'y: 'x`, // because of `&'x &'y`, so we require that `'b: 'a`. trait RegionOutlives { diff --git a/src/test/ui/generic-associated-types/self-outlives-lint.stderr b/src/test/ui/generic-associated-types/self-outlives-lint.stderr index 3b9146ad875..fdb1f50a776 100644 --- a/src/test/ui/generic-associated-types/self-outlives-lint.stderr +++ b/src/test/ui/generic-associated-types/self-outlives-lint.stderr @@ -108,8 +108,19 @@ LL | type Bar<'b>; = note: this bound is currently required to ensure that impls have maximum flexibility = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information +error: missing required bound on `Item` + --> $DIR/self-outlives-lint.rs:142:5 + | +LL | type Item<'a>; + | ^^^^^^^^^^^^^- + | | + | help: add the required where clause: `where Self: 'a` + | + = note: this bound is currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information + error: missing required bound on `Iterator` - --> $DIR/self-outlives-lint.rs:143:5 + --> $DIR/self-outlives-lint.rs:144:5 | LL | type Iterator<'a>: Iterator<Item = Self::Item<'a>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -119,8 +130,19 @@ LL | type Iterator<'a>: Iterator<Item = Self::Item<'a>>; = note: this bound is currently required to ensure that impls have maximum flexibility = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information +error: missing required bound on `Item` + --> $DIR/self-outlives-lint.rs:150:5 + | +LL | type Item<'a>; + | ^^^^^^^^^^^^^- + | | + | help: add the required where clause: `where Self: 'a` + | + = note: this bound is currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information + error: missing required bound on `Bar` - --> $DIR/self-outlives-lint.rs:151:5 + --> $DIR/self-outlives-lint.rs:159:5 | LL | type Bar<'a, 'b>; | ^^^^^^^^^^^^^^^^- @@ -131,7 +153,7 @@ LL | type Bar<'a, 'b>; = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information error: missing required bound on `Fut` - --> $DIR/self-outlives-lint.rs:167:5 + --> $DIR/self-outlives-lint.rs:175:5 | LL | type Fut<'out>; | ^^^^^^^^^^^^^^- @@ -141,5 +163,5 @@ LL | type Fut<'out>; = note: this bound is currently required to ensure that impls have maximum flexibility = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information -error: aborting due to 13 previous errors +error: aborting due to 15 previous errors 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-35570.stderr b/src/test/ui/issues/issue-35570.stderr index dda6145e65a..2697d46bdb2 100644 --- a/src/test/ui/issues/issue-35570.stderr +++ b/src/test/ui/issues/issue-35570.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `for<'a> (): Trait2<'a>` is not satisfied - --> $DIR/issue-35570.rs:8:4 + --> $DIR/issue-35570.rs:8:40 | LL | fn _ice(param: Box<dyn for <'a> Trait1<<() as Trait2<'a>>::Ty>>) { - | ^^^^ the trait `for<'a> Trait2<'a>` is not implemented for `()` + | ^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Trait2<'a>` is not implemented for `()` 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/kindck/kindck-copy.stderr b/src/test/ui/kindck/kindck-copy.stderr index 6977804708d..e147366a224 100644 --- a/src/test/ui/kindck/kindck-copy.stderr +++ b/src/test/ui/kindck/kindck-copy.stderr @@ -6,6 +6,10 @@ LL | assert_copy::<&'static mut isize>(); | = help: the following implementations were found: <isize as Copy> + <f32 as Copy> + <f64 as Copy> + <i128 as Copy> + and 10 others note: required by a bound in `assert_copy` --> $DIR/kindck-copy.rs:5:18 | @@ -20,6 +24,10 @@ LL | assert_copy::<&'a mut isize>(); | = help: the following implementations were found: <isize as Copy> + <f32 as Copy> + <f64 as Copy> + <i128 as Copy> + and 10 others note: required by a bound in `assert_copy` --> $DIR/kindck-copy.rs:5:18 | diff --git a/src/test/ui/lexer/lex-bad-char-literals-1.stderr b/src/test/ui/lexer/lex-bad-char-literals-1.stderr index ed129a1d133..e6ff1f662bd 100644 --- a/src/test/ui/lexer/lex-bad-char-literals-1.stderr +++ b/src/test/ui/lexer/lex-bad-char-literals-1.stderr @@ -17,6 +17,10 @@ LL | '\●' | ^ unknown character escape | = help: for more information, visit <https://static.rust-lang.org/doc/master/reference.html#literals> +help: if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal + | +LL | r"\●" + | ~~~~~ error: unknown character escape: `\u{25cf}` --> $DIR/lex-bad-char-literals-1.rs:14:7 @@ -25,6 +29,10 @@ LL | "\●" | ^ unknown character escape | = help: for more information, visit <https://static.rust-lang.org/doc/master/reference.html#literals> +help: if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal + | +LL | r"\●" + | ~~~~~ error: aborting due to 4 previous errors diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr index 459198eec5a..983d6a06afa 100644 --- a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr @@ -6,7 +6,7 @@ LL | with_signature(x, |mut y| Box::new(y.next())) | = note: defining type: no_region::<'_#1r, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::boxed::Box<T, std::alloc::Global>,)) -> std::boxed::Box<(dyn Anything + '_#2r), std::alloc::Global>, + extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#2r)>, (), ] = note: number of external vids: 3 @@ -42,7 +42,7 @@ LL | with_signature(x, |mut y| Box::new(y.next())) | = note: defining type: correct_region::<'_#1r, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::boxed::Box<T, std::alloc::Global>,)) -> std::boxed::Box<(dyn Anything + '_#2r), std::alloc::Global>, + extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#2r)>, (), ] = note: number of external vids: 3 @@ -69,7 +69,7 @@ LL | with_signature(x, |mut y| Box::new(y.next())) | = note: defining type: wrong_region::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::boxed::Box<T, std::alloc::Global>,)) -> std::boxed::Box<(dyn Anything + '_#3r), std::alloc::Global>, + extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#3r)>, (), ] = note: number of external vids: 4 @@ -105,7 +105,7 @@ LL | with_signature(x, |mut y| Box::new(y.next())) | = note: defining type: outlives_region::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::boxed::Box<T, std::alloc::Global>,)) -> std::boxed::Box<(dyn Anything + '_#3r), std::alloc::Global>, + extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#3r)>, (), ] = note: number of external vids: 4 diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr index 6e8b3021d33..88d73e7a729 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr @@ -6,7 +6,7 @@ LL | with_signature(x, |y| y) | = note: defining type: no_region::<'_#1r, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::boxed::Box<T, std::alloc::Global>,)) -> std::boxed::Box<(dyn std::fmt::Debug + '_#2r), std::alloc::Global>, + extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn std::fmt::Debug + '_#2r)>, (), ] = note: number of external vids: 3 diff --git a/src/test/ui/optimization-remark.rs b/src/test/ui/optimization-remark.rs index 36549cbc554..d4b39c67016 100644 --- a/src/test/ui/optimization-remark.rs +++ b/src/test/ui/optimization-remark.rs @@ -1,6 +1,6 @@ // build-pass // ignore-pass -// no-system-llvm +// min-llvm-version: 14.0.0 // revisions: all inline merge1 merge2 // compile-flags: --crate-type=lib -Cdebuginfo=1 -Copt-level=2 // @@ -14,7 +14,7 @@ // [merge1] compile-flags: -Cremark=all -Cremark=giraffe // [merge2] compile-flags: -Cremark=inline -Cremark=giraffe // -// error-pattern: inline: f not inlined into g +// error-pattern: inline: 'f' not inlined into 'g' // dont-check-compiler-stderr #[no_mangle] diff --git a/src/test/ui/parser/bad-escape-suggest-raw-string.rs b/src/test/ui/parser/bad-escape-suggest-raw-string.rs new file mode 100644 index 00000000000..978b92cbcd2 --- /dev/null +++ b/src/test/ui/parser/bad-escape-suggest-raw-string.rs @@ -0,0 +1,7 @@ +fn main() { + let ok = r"ab\[c"; + let bad = "ab\[c"; + //~^ ERROR unknown character escape: `[` + //~| HELP for more information, visit <https://static.rust-lang.org/doc/master/reference.html#literals> + //~| HELP if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal +} diff --git a/src/test/ui/parser/bad-escape-suggest-raw-string.stderr b/src/test/ui/parser/bad-escape-suggest-raw-string.stderr new file mode 100644 index 00000000000..fc34bd3281a --- /dev/null +++ b/src/test/ui/parser/bad-escape-suggest-raw-string.stderr @@ -0,0 +1,14 @@ +error: unknown character escape: `[` + --> $DIR/bad-escape-suggest-raw-string.rs:3:19 + | +LL | let bad = "ab\[c"; + | ^ unknown character escape + | + = help: for more information, visit <https://static.rust-lang.org/doc/master/reference.html#literals> +help: if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal + | +LL | let bad = r"ab\[c"; + | ~~~~~~~~ + +error: aborting due to previous error + diff --git a/src/test/ui/pin-macro/cant_access_internals.rs b/src/test/ui/pin-macro/cant_access_internals.rs new file mode 100644 index 00000000000..120d08894f8 --- /dev/null +++ b/src/test/ui/pin-macro/cant_access_internals.rs @@ -0,0 +1,13 @@ +// edition:2018 +#![feature(pin_macro)] + +use core::{ + marker::PhantomPinned, + mem, + pin::{pin, Pin}, +}; + +fn main() { + let mut phantom_pinned = pin!(PhantomPinned); + mem::take(phantom_pinned.pointer); //~ ERROR use of unstable library feature 'unsafe_pin_internals' +} diff --git a/src/test/ui/pin-macro/cant_access_internals.stderr b/src/test/ui/pin-macro/cant_access_internals.stderr new file mode 100644 index 00000000000..060c9c48c21 --- /dev/null +++ b/src/test/ui/pin-macro/cant_access_internals.stderr @@ -0,0 +1,11 @@ +error[E0658]: use of unstable library feature 'unsafe_pin_internals' + --> $DIR/cant_access_internals.rs:12:15 + | +LL | mem::take(phantom_pinned.pointer); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(unsafe_pin_internals)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/pin-macro/lifetime_errors_on_promotion_misusage.rs b/src/test/ui/pin-macro/lifetime_errors_on_promotion_misusage.rs new file mode 100644 index 00000000000..ca2b6cf7593 --- /dev/null +++ b/src/test/ui/pin-macro/lifetime_errors_on_promotion_misusage.rs @@ -0,0 +1,29 @@ +// edition:2018 +#![feature(pin_macro)] + +use core::{ + convert::identity, + marker::PhantomPinned, + mem::drop as stuff, + pin::pin, +}; + +fn function_call_stops_borrow_extension() { + let phantom_pinned = identity(pin!(PhantomPinned)); + //~^ ERROR temporary value dropped while borrowed + stuff(phantom_pinned) +} + +fn promotion_only_works_for_the_innermost_block() { + let phantom_pinned = { + let phantom_pinned = pin!(PhantomPinned); + //~^ ERROR temporary value dropped while borrowed + phantom_pinned + }; + stuff(phantom_pinned) +} + +fn main() { + function_call_stops_borrow_extension(); + promotion_only_works_for_the_innermost_block(); +} diff --git a/src/test/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr b/src/test/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr new file mode 100644 index 00000000000..4971263af08 --- /dev/null +++ b/src/test/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr @@ -0,0 +1,31 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/lifetime_errors_on_promotion_misusage.rs:12:35 + | +LL | let phantom_pinned = identity(pin!(PhantomPinned)); + | ^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary which is freed while still in use +LL | +LL | stuff(phantom_pinned) + | -------------- borrow later used here + | + = note: consider using a `let` binding to create a longer lived value + = note: this error originates in the macro `pin` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0716]: temporary value dropped while borrowed + --> $DIR/lifetime_errors_on_promotion_misusage.rs:19:30 + | +LL | let phantom_pinned = { + | -------------- borrow later stored here +LL | let phantom_pinned = pin!(PhantomPinned); + | ^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +... +LL | }; + | - temporary value is freed at the end of this statement + | + = note: consider using a `let` binding to create a longer lived value + = note: this error originates in the macro `pin` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr b/src/test/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr index 44ef13c740c..6844e866532 100644 --- a/src/test/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr +++ b/src/test/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `for<'z> T: Trait2<'y, 'z>` is not satisfied - --> $DIR/regions-implied-bounds-projection-gap-hr-1.rs:21:4 + --> $DIR/regions-implied-bounds-projection-gap-hr-1.rs:21:49 | LL | fn callee<'x, 'y, T>(t: &'x dyn for<'z> Trait1< <T as Trait2<'y, 'z>>::Foo >) - | ^^^^^^ the trait `for<'z> Trait2<'y, 'z>` is not implemented for `T` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'z> Trait2<'y, 'z>` is not implemented for `T` | help: consider restricting type parameter `T` | 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/specialization/default-associated-type-bound-1.stderr b/src/test/ui/specialization/default-associated-type-bound-1.stderr index 6680a29f942..f88acfb2e79 100644 --- a/src/test/ui/specialization/default-associated-type-bound-1.stderr +++ b/src/test/ui/specialization/default-associated-type-bound-1.stderr @@ -14,6 +14,8 @@ error[E0277]: the trait bound `str: Clone` is not satisfied LL | default type U = str; | ^^^ the trait `Clone` is not implemented for `str` | + = help: the following implementations were found: + <String as Clone> note: required by a bound in `X::U` --> $DIR/default-associated-type-bound-1.rs:8:13 | diff --git a/src/test/ui/suggestions/into-str.stderr b/src/test/ui/suggestions/into-str.stderr index 0d9ecc32e08..470c0bfcf73 100644 --- a/src/test/ui/suggestions/into-str.stderr +++ b/src/test/ui/suggestions/into-str.stderr @@ -7,6 +7,12 @@ LL | foo(String::new()); | required by a bound introduced by this call | = note: to coerce a `String` into a `&str`, use `&*` as a prefix + = help: the following implementations were found: + <String as From<&String>> + <String as From<&mut str>> + <String as From<&str>> + <String as From<Box<str>>> + and 2 others = note: required because of the requirements on the impl of `Into<&str>` for `String` note: required by a bound in `foo` --> $DIR/into-str.rs:1:31 diff --git a/src/test/ui/suggestions/issue-71394-no-from-impl.stderr b/src/test/ui/suggestions/issue-71394-no-from-impl.stderr index 355f2038df8..79724377713 100644 --- a/src/test/ui/suggestions/issue-71394-no-from-impl.stderr +++ b/src/test/ui/suggestions/issue-71394-no-from-impl.stderr @@ -4,6 +4,9 @@ error[E0277]: the trait bound `&[i8]: From<&[u8]>` is not satisfied LL | let _: &[i8] = data.into(); | ^^^^ the trait `From<&[u8]>` is not implemented for `&[i8]` | + = help: the following implementations were found: + <[T; LANES] as From<Simd<T, LANES>>> + <[bool; LANES] as From<Mask<T, LANES>>> = note: required because of the requirements on the impl of `Into<&[i8]>` for `&[u8]` error: aborting due to previous error diff --git a/src/test/ui/suggestions/issue-84973-negative.stderr b/src/test/ui/suggestions/issue-84973-negative.stderr index 1f33374eb29..bacab64e264 100644 --- a/src/test/ui/suggestions/issue-84973-negative.stderr +++ b/src/test/ui/suggestions/issue-84973-negative.stderr @@ -6,6 +6,8 @@ LL | bar(a); | | | required by a bound introduced by this call | + = help: the following implementations were found: + <&f32 as Tr> note: required by a bound in `bar` --> $DIR/issue-84973-negative.rs:5:11 | diff --git a/src/test/ui/symbol-names/verbose.rs b/src/test/ui/symbol-names/verbose.rs new file mode 100644 index 00000000000..e00c592b6d2 --- /dev/null +++ b/src/test/ui/symbol-names/verbose.rs @@ -0,0 +1,15 @@ +// Regression test for issue #57596, where -Zverbose flag unintentionally +// affected produced symbols making it impossible to link between crates +// with a different value of the flag (for symbols involving generic +// arguments equal to defaults of their respective parameters). +// +// build-pass +// compile-flags: -Zverbose + +pub fn error(msg: String) -> Box<dyn std::error::Error> { + msg.into() +} + +fn main() { + error(String::new()); +} 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/traits/associated_type_bound/check-trait-object-bounds-1.stderr b/src/test/ui/traits/associated_type_bound/check-trait-object-bounds-1.stderr index 6333b4eb08c..907a1bd75a0 100644 --- a/src/test/ui/traits/associated_type_bound/check-trait-object-bounds-1.stderr +++ b/src/test/ui/traits/associated_type_bound/check-trait-object-bounds-1.stderr @@ -4,6 +4,8 @@ error[E0277]: the trait bound `str: Clone` is not satisfied LL | f::<dyn X<Y = str>>(); | ^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `str` | + = help: the following implementations were found: + <String as Clone> note: required by a bound in `f` --> $DIR/check-trait-object-bounds-1.rs:7:9 | diff --git a/src/test/ui/traits/associated_type_bound/check-trait-object-bounds-4.stderr b/src/test/ui/traits/associated_type_bound/check-trait-object-bounds-4.stderr index 9afae9a9638..b27f8d791a5 100644 --- a/src/test/ui/traits/associated_type_bound/check-trait-object-bounds-4.stderr +++ b/src/test/ui/traits/associated_type_bound/check-trait-object-bounds-4.stderr @@ -4,6 +4,8 @@ error[E0277]: the trait bound `str: Clone` is not satisfied LL | f::<dyn X<Y = str>>(); | ^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `str` | + = help: the following implementations were found: + <String as Clone> note: required by a bound in `f` --> $DIR/check-trait-object-bounds-4.rs:10:9 | diff --git a/src/test/ui/traits/issue-77982.stderr b/src/test/ui/traits/issue-77982.stderr index 3c4a5d95c13..413225d45a6 100644 --- a/src/test/ui/traits/issue-77982.stderr +++ b/src/test/ui/traits/issue-77982.stderr @@ -44,6 +44,7 @@ LL | opts.get(<String as AsRef<[u8]>>::as_ref(opt)); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LL | opts.get(<String as AsRef<str>>::as_ref(opt)); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + and 4 other candidates error[E0283]: type annotations needed --> $DIR/issue-77982.rs:13:44 diff --git a/src/test/ui/traits/issue-79458.stderr b/src/test/ui/traits/issue-79458.stderr index 3e83db142e0..b9700128373 100644 --- a/src/test/ui/traits/issue-79458.stderr +++ b/src/test/ui/traits/issue-79458.stderr @@ -9,6 +9,8 @@ LL | bar: &'a mut T | = help: the following implementations were found: <&T as Clone> + <*const T as Clone> + <*mut T as Clone> = note: `Clone` is implemented for `&T`, but not for `&mut T` = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/traits/negative-impls/auxiliary/foreign_trait.rs b/src/test/ui/traits/negative-impls/auxiliary/foreign_trait.rs index 681f26438e6..0e17f089048 100644 --- a/src/test/ui/traits/negative-impls/auxiliary/foreign_trait.rs +++ b/src/test/ui/traits/negative-impls/auxiliary/foreign_trait.rs @@ -1,4 +1,5 @@ #![feature(negative_impls)] +#![feature(with_negative_coherence)] pub trait ForeignTrait {} diff --git a/src/test/ui/traits/negative-impls/rely-on-negative-impl-in-coherence.rs b/src/test/ui/traits/negative-impls/rely-on-negative-impl-in-coherence.rs index 119ac05c33e..c1f96ab8c14 100644 --- a/src/test/ui/traits/negative-impls/rely-on-negative-impl-in-coherence.rs +++ b/src/test/ui/traits/negative-impls/rely-on-negative-impl-in-coherence.rs @@ -1,6 +1,7 @@ // check-pass #![feature(negative_impls)] +#![feature(with_negative_coherence)] // aux-build: foreign_trait.rs @@ -16,8 +17,8 @@ extern crate foreign_trait; use foreign_trait::ForeignTrait; -trait LocalTrait { } -impl<T: ForeignTrait> LocalTrait for T { } -impl LocalTrait for String { } +trait LocalTrait {} +impl<T: ForeignTrait> LocalTrait for T {} +impl LocalTrait for String {} -fn main() { } +fn main() {} diff --git a/src/test/ui/traits/suggest-deferences/issue-62530.stderr b/src/test/ui/traits/suggest-deferences/issue-62530.stderr index b77af7ddf47..299219431ef 100644 --- a/src/test/ui/traits/suggest-deferences/issue-62530.stderr +++ b/src/test/ui/traits/suggest-deferences/issue-62530.stderr @@ -8,6 +8,8 @@ LL | takes_type_parameter(&string); // Error | | help: consider adding dereference here: `&*string` | required by a bound introduced by this call | + = help: the following implementations were found: + <&str as SomeTrait> note: required by a bound in `takes_type_parameter` --> $DIR/issue-62530.rs:4:44 | diff --git a/src/test/ui/try-trait/bad-interconversion.stderr b/src/test/ui/try-trait/bad-interconversion.stderr index 80c5e6f529c..171051156b7 100644 --- a/src/test/ui/try-trait/bad-interconversion.stderr +++ b/src/test/ui/try-trait/bad-interconversion.stderr @@ -10,6 +10,9 @@ LL | Ok(Err(123_i32)?) = help: the following implementations were found: <u8 as From<NonZeroU8>> <u8 as From<bool>> + <f32 as From<i16>> + <f32 as From<i8>> + and 71 others = note: required because of the requirements on the impl of `FromResidual<Result<Infallible, i32>>` for `Result<u64, u8>` error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result` 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/test/ui/typeck/issue-91328.fixed b/src/test/ui/typeck/issue-91328.fixed index 81b6a996072..c0384399a92 100644 --- a/src/test/ui/typeck/issue-91328.fixed +++ b/src/test/ui/typeck/issue-91328.fixed @@ -34,4 +34,14 @@ fn baz(v: Vec<i32>) -> i32 { } } +fn qux(a: &Option<Box<[i32; 2]>>) -> i32 { + match a.as_deref() { + //~^ HELP: consider using `as_deref` here + Some([a, b]) => a + b, + //~^ ERROR: expected an array or slice + //~| NOTE: pattern cannot match with input type + _ => 42, + } +} + fn main() {} diff --git a/src/test/ui/typeck/issue-91328.rs b/src/test/ui/typeck/issue-91328.rs index e938d8f5c9f..63602d26f97 100644 --- a/src/test/ui/typeck/issue-91328.rs +++ b/src/test/ui/typeck/issue-91328.rs @@ -34,4 +34,14 @@ fn baz(v: Vec<i32>) -> i32 { } } +fn qux(a: &Option<Box<[i32; 2]>>) -> i32 { + match a { + //~^ HELP: consider using `as_deref` here + Some([a, b]) => a + b, + //~^ ERROR: expected an array or slice + //~| NOTE: pattern cannot match with input type + _ => 42, + } +} + fn main() {} diff --git a/src/test/ui/typeck/issue-91328.stderr b/src/test/ui/typeck/issue-91328.stderr index 96ad00cde4f..f2f407bcaff 100644 --- a/src/test/ui/typeck/issue-91328.stderr +++ b/src/test/ui/typeck/issue-91328.stderr @@ -25,6 +25,15 @@ LL | LL | [a, b] => a + b, | ^^^^^^ pattern cannot match with input type `Vec<i32>` -error: aborting due to 3 previous errors +error[E0529]: expected an array or slice, found `Box<[i32; 2]>` + --> $DIR/issue-91328.rs:40:14 + | +LL | match a { + | - help: consider using `as_deref` here: `a.as_deref()` +LL | +LL | Some([a, b]) => a + b, + | ^^^^^^ pattern cannot match with input type `Box<[i32; 2]>` + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0529`. diff --git a/src/test/ui/union/issue-41073.rs b/src/test/ui/union/issue-41073.rs index 91e9a0d0b65..80474b807e7 100644 --- a/src/test/ui/union/issue-41073.rs +++ b/src/test/ui/union/issue-41073.rs @@ -1,7 +1,7 @@ #![feature(untagged_unions)] union Test { - a: A, //~ ERROR unions may not contain fields that need dropping + a: A, //~ ERROR unions cannot contain fields that may need dropping b: B } diff --git a/src/test/ui/union/issue-41073.stderr b/src/test/ui/union/issue-41073.stderr index 8edf4db441b..7d4208b10da 100644 --- a/src/test/ui/union/issue-41073.stderr +++ b/src/test/ui/union/issue-41073.stderr @@ -1,10 +1,11 @@ -error[E0740]: unions may not contain fields that need dropping +error[E0740]: unions cannot contain fields that may need dropping --> $DIR/issue-41073.rs:4:5 | LL | a: A, | ^^^^ | -help: wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped + = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type +help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped | LL | a: std::mem::ManuallyDrop<A>, | +++++++++++++++++++++++ + diff --git a/src/test/ui/union/union-custom-drop.rs b/src/test/ui/union/union-custom-drop.rs index 8f816cc1b73..4b333631ec0 100644 --- a/src/test/ui/union/union-custom-drop.rs +++ b/src/test/ui/union/union-custom-drop.rs @@ -4,7 +4,7 @@ #![feature(untagged_unions)] union Foo { - bar: Bar, //~ ERROR unions may not contain fields that need dropping + bar: Bar, //~ ERROR unions cannot contain fields that may need dropping } union Bar { diff --git a/src/test/ui/union/union-custom-drop.stderr b/src/test/ui/union/union-custom-drop.stderr index 65ca5fd931d..b5579eeef09 100644 --- a/src/test/ui/union/union-custom-drop.stderr +++ b/src/test/ui/union/union-custom-drop.stderr @@ -1,10 +1,11 @@ -error[E0740]: unions may not contain fields that need dropping +error[E0740]: unions cannot contain fields that may need dropping --> $DIR/union-custom-drop.rs:7:5 | LL | bar: Bar, | ^^^^^^^^ | -help: wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped + = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type +help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped | LL | bar: std::mem::ManuallyDrop<Bar>, | +++++++++++++++++++++++ + diff --git a/src/test/ui/union/union-derive-clone.mirunsafeck.stderr b/src/test/ui/union/union-derive-clone.mirunsafeck.stderr index 146a627bcde..e8e65fe5d1d 100644 --- a/src/test/ui/union/union-derive-clone.mirunsafeck.stderr +++ b/src/test/ui/union/union-derive-clone.mirunsafeck.stderr @@ -16,9 +16,9 @@ LL | let w = u.clone(); = note: the following trait bounds were not satisfied: `CloneNoCopy: Copy` which is required by `U5<CloneNoCopy>: Clone` -help: consider annotating `CloneNoCopy` with `#[derive(Copy)]` +help: consider annotating `CloneNoCopy` with `#[derive(Clone, Copy)]` | -LL | #[derive(Copy)] +LL | #[derive(Clone, Copy)] | error[E0277]: the trait bound `U1: Copy` is not satisfied diff --git a/src/test/ui/union/union-derive-clone.thirunsafeck.stderr b/src/test/ui/union/union-derive-clone.thirunsafeck.stderr index 146a627bcde..e8e65fe5d1d 100644 --- a/src/test/ui/union/union-derive-clone.thirunsafeck.stderr +++ b/src/test/ui/union/union-derive-clone.thirunsafeck.stderr @@ -16,9 +16,9 @@ LL | let w = u.clone(); = note: the following trait bounds were not satisfied: `CloneNoCopy: Copy` which is required by `U5<CloneNoCopy>: Clone` -help: consider annotating `CloneNoCopy` with `#[derive(Copy)]` +help: consider annotating `CloneNoCopy` with `#[derive(Clone, Copy)]` | -LL | #[derive(Copy)] +LL | #[derive(Clone, Copy)] | error[E0277]: the trait bound `U1: Copy` is not satisfied diff --git a/src/test/ui/union/union-with-drop-fields.mirunsafeck.stderr b/src/test/ui/union/union-with-drop-fields.mirunsafeck.stderr index f5e9681735c..93fe996d2a4 100644 --- a/src/test/ui/union/union-with-drop-fields.mirunsafeck.stderr +++ b/src/test/ui/union/union-with-drop-fields.mirunsafeck.stderr @@ -1,32 +1,35 @@ -error[E0740]: unions may not contain fields that need dropping +error[E0740]: unions cannot contain fields that may need dropping --> $DIR/union-with-drop-fields.rs:11:5 | LL | a: String, | ^^^^^^^^^ | -help: wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped + = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type +help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped | LL | a: std::mem::ManuallyDrop<String>, | +++++++++++++++++++++++ + -error[E0740]: unions may not contain fields that need dropping +error[E0740]: unions cannot contain fields that may need dropping --> $DIR/union-with-drop-fields.rs:19:5 | LL | a: S, | ^^^^ | -help: wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped + = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type +help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped | LL | a: std::mem::ManuallyDrop<S>, | +++++++++++++++++++++++ + -error[E0740]: unions may not contain fields that need dropping +error[E0740]: unions cannot contain fields that may need dropping --> $DIR/union-with-drop-fields.rs:24:5 | LL | a: T, | ^^^^ | -help: wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped + = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type +help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped | LL | a: std::mem::ManuallyDrop<T>, | +++++++++++++++++++++++ + diff --git a/src/test/ui/union/union-with-drop-fields.rs b/src/test/ui/union/union-with-drop-fields.rs index 96c293418b6..a7a8b69e784 100644 --- a/src/test/ui/union/union-with-drop-fields.rs +++ b/src/test/ui/union/union-with-drop-fields.rs @@ -8,7 +8,7 @@ union U { } union W { - a: String, //~ ERROR unions may not contain fields that need dropping + a: String, //~ ERROR unions cannot contain fields that may need dropping b: String, // OK, only one field is reported } @@ -16,12 +16,12 @@ struct S(String); // `S` doesn't implement `Drop` trait, but still has non-trivial destructor union Y { - a: S, //~ ERROR unions may not contain fields that need dropping + a: S, //~ ERROR unions cannot contain fields that may need dropping } // We don't know if `T` is trivially-destructable or not until trans union J<T> { - a: T, //~ ERROR unions may not contain fields that need dropping + a: T, //~ ERROR unions cannot contain fields that may need dropping } union H<T: Copy> { diff --git a/src/test/ui/union/union-with-drop-fields.thirunsafeck.stderr b/src/test/ui/union/union-with-drop-fields.thirunsafeck.stderr index f5e9681735c..93fe996d2a4 100644 --- a/src/test/ui/union/union-with-drop-fields.thirunsafeck.stderr +++ b/src/test/ui/union/union-with-drop-fields.thirunsafeck.stderr @@ -1,32 +1,35 @@ -error[E0740]: unions may not contain fields that need dropping +error[E0740]: unions cannot contain fields that may need dropping --> $DIR/union-with-drop-fields.rs:11:5 | LL | a: String, | ^^^^^^^^^ | -help: wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped + = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type +help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped | LL | a: std::mem::ManuallyDrop<String>, | +++++++++++++++++++++++ + -error[E0740]: unions may not contain fields that need dropping +error[E0740]: unions cannot contain fields that may need dropping --> $DIR/union-with-drop-fields.rs:19:5 | LL | a: S, | ^^^^ | -help: wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped + = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type +help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped | LL | a: std::mem::ManuallyDrop<S>, | +++++++++++++++++++++++ + -error[E0740]: unions may not contain fields that need dropping +error[E0740]: unions cannot contain fields that may need dropping --> $DIR/union-with-drop-fields.rs:24:5 | LL | a: T, | ^^^^ | -help: wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped + = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type +help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped | LL | a: std::mem::ManuallyDrop<T>, | +++++++++++++++++++++++ + diff --git a/src/tools/build-manifest/Cargo.toml b/src/tools/build-manifest/Cargo.toml index dedafd85cfd..c022d3aa0ac 100644 --- a/src/tools/build-manifest/Cargo.toml +++ b/src/tools/build-manifest/Cargo.toml @@ -10,7 +10,7 @@ serde_json = "1.0" anyhow = "1.0.32" flate2 = "1.0.16" tar = "0.4.29" -sha2 = "0.9.1" +sha2 = "0.10.1" rayon = "1.5.1" hex = "0.4.2" num_cpus = "1.13.0" diff --git a/src/tools/cargo b/src/tools/cargo -Subproject c082648646cbb2be266df9ecbcdc253058158d6 +Subproject ea2a21c994ca1e4d4c49412827b3cf4dcb158b1 diff --git a/src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs b/src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs index e71f110820c..7637666d059 100644 --- a/src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs +++ b/src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs @@ -47,7 +47,7 @@ fn check_case_sensitive_file_extension_comparison(ctx: &LateContext<'_>, expr: & then { let mut ty = ctx.typeck_results().expr_ty(obj); ty = match ty.kind() { - ty::Ref(_, ty, ..) => ty, + ty::Ref(_, ty, ..) => *ty, _ => ty }; diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs index fb201d2c012..b80d55dd192 100644 --- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs +++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs @@ -123,7 +123,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { if let Some(fn_sig) = fn_sig_opt(self.cx, func.hir_id) { for (expr, bound) in iter::zip(*args, fn_sig.skip_binder().inputs()) { // Push found arg type, then visit arg. - self.ty_bounds.push(TyBound::Ty(bound)); + self.ty_bounds.push(TyBound::Ty(*bound)); self.visit_expr(expr); self.ty_bounds.pop(); } @@ -135,7 +135,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { if let Some(def_id) = self.cx.typeck_results().type_dependent_def_id(expr.hir_id) { let fn_sig = self.cx.tcx.fn_sig(def_id).skip_binder(); for (expr, bound) in iter::zip(*args, fn_sig.inputs()) { - self.ty_bounds.push(TyBound::Ty(bound)); + self.ty_bounds.push(TyBound::Ty(*bound)); self.visit_expr(expr); self.ty_bounds.pop(); } @@ -210,7 +210,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { fn fn_sig_opt<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<PolyFnSig<'tcx>> { let node_ty = cx.typeck_results().node_type_opt(hir_id)?; - // We can't use `TyS::fn_sig` because it automatically performs substs, this may result in FNs. + // We can't use `Ty::fn_sig` because it automatically performs substs, this may result in FNs. match node_ty.kind() { ty::FnDef(def_id, _) => Some(cx.tcx.fn_sig(*def_id)), ty::FnPtr(fn_sig) => Some(*fn_sig), 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/clippy_lints/src/eq_op.rs b/src/tools/clippy/clippy_lints/src/eq_op.rs index 24d7613e6f8..ea547793b1e 100644 --- a/src/tools/clippy/clippy_lints/src/eq_op.rs +++ b/src/tools/clippy/clippy_lints/src/eq_op.rs @@ -7,10 +7,10 @@ use clippy_utils::{ast_utils::is_useless_with_eq_exprs, eq_expr_value, is_in_tes use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{ - def::Res, def_id::DefId, BinOpKind, BorrowKind, Expr, ExprKind, GenericArg, ItemKind, QPath, Ty, TyKind, + def::Res, def_id::DefId, BinOpKind, BorrowKind, Expr, ExprKind, GenericArg, ItemKind, QPath, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{self, TyS}; +use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { @@ -279,7 +279,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { } } -fn in_impl<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, bin_op: DefId) -> Option<(&'tcx Ty<'tcx>, &'tcx Ty<'tcx>)> { +fn in_impl<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, bin_op: DefId) -> Option<(&'tcx rustc_hir::Ty<'tcx>, &'tcx rustc_hir::Ty<'tcx>)> { if_chain! { if let Some(block) = get_enclosing_block(cx, e.hir_id); if let Some(impl_def_id) = cx.tcx.impl_of_method(block.hir_id.owner.to_def_id()); @@ -301,7 +301,7 @@ fn in_impl<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, bin_op: DefId) -> Op } } -fn are_equal<'tcx>(cx: &LateContext<'tcx>, middle_ty: &TyS<'_>, hir_ty: &Ty<'_>) -> bool { +fn are_equal<'tcx>(cx: &LateContext<'tcx>, middle_ty: Ty<'_>, hir_ty: &rustc_hir::Ty<'_>) -> bool { if_chain! { if let ty::Adt(adt_def, _) = middle_ty.kind(); if let Some(local_did) = adt_def.did.as_local(); diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs index 17b0749a4a9..503aac8ccd0 100644 --- a/src/tools/clippy/clippy_lints/src/format_args.rs +++ b/src/tools/clippy/clippy_lints/src/format_args.rs @@ -211,7 +211,7 @@ where if overloaded_deref.is_some() { n_needed = n_total; } - ty = target; + ty = *target; } else { return (n_needed, ty); } diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs index 2a4bcd773c6..6b62748ffef 100644 --- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs +++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs @@ -118,7 +118,7 @@ fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap<hir // The values need to use the `ref` keyword if they can't be copied. // This will need to be adjusted if the lint want to support multable access in the future let src_is_ref = bound_ty.is_ref() && binding != hir::BindingAnnotation::Ref; - let needs_ref = !(src_is_ref || is_copy(cx, inner_ty)); + let needs_ref = !(src_is_ref || is_copy(cx, *inner_ty)); let slice_info = slices .entry(value_hir_id) diff --git a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs index 80260e4cd83..27db6388136 100644 --- a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs +++ b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs @@ -53,9 +53,9 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays { if let ItemKind::Const(hir_ty, _) = &item.kind; let ty = hir_ty_to_ty(cx.tcx, hir_ty); if let ty::Array(element_type, cst) = ty.kind(); - if let ConstKind::Value(ConstValue::Scalar(element_count)) = cst.val; + if let ConstKind::Value(ConstValue::Scalar(element_count)) = cst.val(); if let Ok(element_count) = element_count.to_machine_usize(&cx.tcx); - if let Ok(element_size) = cx.layout_of(element_type).map(|l| l.size.bytes()); + if let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()); if self.maximum_allowed_size < element_count * element_size; then { diff --git a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs index 1cc2c28c04a..57b0d709acd 100644 --- a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs +++ b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs @@ -43,9 +43,9 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { if_chain! { if let ExprKind::Repeat(_, _) = expr.kind; if let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind(); - if let ConstKind::Value(ConstValue::Scalar(element_count)) = cst.val; + if let ConstKind::Value(ConstValue::Scalar(element_count)) = cst.val(); if let Ok(element_count) = element_count.to_machine_usize(&cx.tcx); - if let Ok(element_size) = cx.layout_of(element_type).map(|l| l.size.bytes()); + if let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()); if self.maximum_allowed_size < element_count * element_size; then { span_lint_and_help( diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index 3418d276c53..35d10d53112 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -294,7 +294,7 @@ impl LenOutput<'_> { /// Checks if the given signature matches the expectations for `is_empty` fn check_is_empty_sig(sig: FnSig<'_>, self_kind: ImplicitSelfKind, len_output: LenOutput<'_>) -> bool { match &**sig.inputs_and_output { - [arg, res] if len_output.matches_is_empty_output(res) => { + [arg, res] if len_output.matches_is_empty_output(*res) => { matches!( (arg.kind(), self_kind), (ty::Ref(_, _, Mutability::Not), ImplicitSelfKind::ImmRef) diff --git a/src/tools/clippy/clippy_lints/src/lib.register_all.rs b/src/tools/clippy/clippy_lints/src/lib.register_all.rs index d93e34e76b4..4721b7f2b47 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_all.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_all.rs @@ -277,7 +277,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT), LintId::of(transmute::TRANSMUTE_NUM_TO_BYTES), LintId::of(transmute::TRANSMUTE_PTR_TO_REF), - LintId::of(transmute::TRANSMUTE_UNDEFINED_REPR), LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE), LintId::of(transmute::WRONG_TRANSMUTE), LintId::of(transmuting_null::TRANSMUTING_NULL), diff --git a/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs b/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs index d013daa8e08..4217fd3a3ea 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs @@ -58,7 +58,6 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), LintId::of(swap::ALMOST_SWAPPED), LintId::of(to_string_in_display::TO_STRING_IN_DISPLAY), - LintId::of(transmute::TRANSMUTE_UNDEFINED_REPR), LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE), LintId::of(transmute::WRONG_TRANSMUTE), LintId::of(transmuting_null::TRANSMUTING_NULL), diff --git a/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs b/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs index a7353790100..8d4dde42bbe 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs @@ -26,6 +26,7 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(strings::STRING_LIT_AS_BYTES), LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS), LintId::of(trailing_empty_array::TRAILING_EMPTY_ARRAY), + LintId::of(transmute::TRANSMUTE_UNDEFINED_REPR), LintId::of(transmute::USELESS_TRANSMUTE), LintId::of(use_self::USE_SELF), ]) diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs index e0150990cfe..fc50e8addcc 100644 --- a/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_block, walk_expr}; use rustc_hir::{Expr, Pat}; use rustc_lint::LateContext; -use rustc_middle::ty::{self, UintTy}; +use rustc_middle::ty::{self, Ty, UintTy}; // To trigger the EXPLICIT_COUNTER_LOOP lint, a variable must be // incremented exactly once in the loop body, and initialized to zero @@ -36,7 +36,7 @@ pub(super) fn check<'tcx>( then { let mut applicability = Applicability::MachineApplicable; - let int_name = match ty.map(ty::TyS::kind) { + let int_name = match ty.map(Ty::kind) { // usize or inferred Some(ty::Uint(UintTy::Usize)) | None => { span_lint_and_sugg( diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs index ef0221639aa..f6ef87264c0 100644 --- a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs +++ b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs @@ -335,8 +335,8 @@ struct Start<'hir> { fn get_slice_like_element_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> { match ty.kind() { ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Vec, adt.did) => Some(subs.type_at(0)), - ty::Ref(_, subty, _) => get_slice_like_element_ty(cx, subty), - ty::Slice(ty) | ty::Array(ty, _) => Some(ty), + ty::Ref(_, subty, _) => get_slice_like_element_ty(cx, *subty), + ty::Slice(ty) | ty::Array(ty, _) => Some(*ty), _ => None, } } diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs b/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs index f57dcc2f5c4..06190850bb0 100644 --- a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs @@ -12,7 +12,7 @@ use rustc_hir::{Block, Expr, ExprKind, HirId, HirIdSet, Local, Mutability, Node, use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::{self, TyS}; +use rustc_middle::ty::{self, Ty}; use rustc_span::sym; use rustc_span::{MultiSpan, Span}; @@ -334,8 +334,8 @@ fn detect_iter_and_into_iters<'tcx: 'a, 'a>( } } -fn get_captured_ids(cx: &LateContext<'_>, ty: &'_ TyS<'_>) -> HirIdSet { - fn get_captured_ids_recursive(cx: &LateContext<'_>, ty: &'_ TyS<'_>, set: &mut HirIdSet) { +fn get_captured_ids(cx: &LateContext<'_>, ty: Ty<'_>) -> HirIdSet { + fn get_captured_ids_recursive(cx: &LateContext<'_>, ty: Ty<'_>, set: &mut HirIdSet) { match ty.kind() { ty::Adt(_, generics) => { for generic in *generics { diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs index b6c746d3e39..772d251b620 100644 --- a/src/tools/clippy/clippy_lints/src/loops/utils.rs +++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs @@ -334,7 +334,7 @@ pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic // (&mut x).into_iter() ==> x.iter_mut() let arg_ty = cx.typeck_results().expr_ty_adjusted(arg); match &arg_ty.kind() { - ty::Ref(_, inner_ty, mutbl) if has_iter_method(cx, inner_ty).is_some() => { + ty::Ref(_, inner_ty, mutbl) if has_iter_method(cx, *inner_ty).is_some() => { let method_name = match mutbl { Mutability::Mut => "iter_mut", Mutability::Not => "iter", diff --git a/src/tools/clippy/clippy_lints/src/map_clone.rs b/src/tools/clippy/clippy_lints/src/map_clone.rs index 3f8eeb736fb..e233300e26a 100644 --- a/src/tools/clippy/clippy_lints/src/map_clone.rs +++ b/src/tools/clippy/clippy_lints/src/map_clone.rs @@ -100,7 +100,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone { let obj_ty = cx.typeck_results().expr_ty(obj); if let ty::Ref(_, ty, mutability) = obj_ty.kind() { if matches!(mutability, Mutability::Not) { - let copy = is_copy(cx, ty); + let copy = is_copy(cx, *ty); self.lint_explicit_closure(cx, e.span, args[0].span, copy); } } else { diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs index 61c5fa0872f..e195fddefab 100644 --- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs @@ -59,7 +59,7 @@ fn type_needs_ordered_drop_inner<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, see // Check if any component type has any. match ty.kind() { ty::Tuple(_) => ty.tuple_fields().any(|ty| type_needs_ordered_drop_inner(cx, ty, seen)), - ty::Array(ty, _) => type_needs_ordered_drop_inner(cx, ty, seen), + ty::Array(ty, _) => type_needs_ordered_drop_inner(cx, *ty, seen), ty::Adt(adt, subs) => adt .all_fields() .map(|f| f.ty(cx.tcx, subs)) diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs index 6ba279eaf12..0c4cb45d147 100644 --- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs @@ -8,7 +8,7 @@ use core::cmp::max; use rustc_errors::Applicability; use rustc_hir::{Arm, BindingAnnotation, Block, Expr, ExprKind, Pat, PatKind}; use rustc_lint::LateContext; -use rustc_middle::ty::{self, Ty, TyS}; +use rustc_middle::ty::{self, Ty}; use super::{MATCH_BOOL, SINGLE_MATCH, SINGLE_MATCH_ELSE}; @@ -162,10 +162,10 @@ fn check_opt_like<'a>( return; } - let in_candidate_enum = |path_info: &(String, &TyS<'_>)| -> bool { + let in_candidate_enum = |path_info: &(String, Ty<'_>)| -> bool { let (path, ty) = path_info; for &(ty_path, pat_path) in candidates { - if path == pat_path && match_type(cx, ty, ty_path) { + if path == pat_path && match_type(cx, *ty, ty_path) { return true; } } diff --git a/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs b/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs index 6fe69b8f01f..67a585edc25 100644 --- a/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs +++ b/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs @@ -30,7 +30,7 @@ pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, }; match inner_ty.kind() { // &T where T: Copy - ty::Ref(_, ty, _) if is_copy(cx, ty) => {}, + ty::Ref(_, ty, _) if is_copy(cx, *ty) => {}, _ => return, }; span_lint_and_sugg( diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs index d813edab687..c3cb02329a1 100644 --- a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs +++ b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs @@ -73,7 +73,7 @@ pub(super) fn check<'tcx>( match cx.qpath_res(p, fun.hir_id) { hir::def::Res::Def(hir::def::DefKind::Fn | hir::def::DefKind::AssocFn, def_id) => matches!( cx.tcx.fn_sig(def_id).output().skip_binder().kind(), - ty::Ref(ty::ReStatic, ..) + ty::Ref(re, ..) if re.is_static(), ), _ => false, } @@ -87,7 +87,7 @@ pub(super) fn check<'tcx>( .map_or(false, |method_id| { matches!( cx.tcx.fn_sig(method_id).output().skip_binder().kind(), - ty::Ref(ty::ReStatic, ..) + ty::Ref(re, ..) if re.is_static() ) }) }, diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs index ca33bfc643d..b93f1399eae 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs @@ -26,7 +26,7 @@ pub(super) fn check<'tcx>( }; match inner_ty.kind() { - ty::Ref(_, ty, _) if !is_copy(cx, ty) => {}, + ty::Ref(_, ty, _) if !is_copy(cx, *ty) => {}, _ => return, }; diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs b/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs index d74c910b676..68a75667914 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs @@ -8,7 +8,7 @@ use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_lint::LateContext; -use rustc_middle::ty::{self, Ty, TyS}; +use rustc_middle::ty::{self, Ty}; use rustc_span::symbol::sym; use std::borrow::Cow; @@ -37,8 +37,8 @@ fn parse_repeat_arg(cx: &LateContext<'_>, e: &Expr<'_>) -> Option<RepeatKind> { } else { let ty = cx.typeck_results().expr_ty(e); if is_type_diagnostic_item(cx, ty, sym::String) - || (is_type_lang_item(cx, ty, LangItem::OwnedBox) && get_ty_param(ty).map_or(false, TyS::is_str)) - || (match_type(cx, ty, &paths::COW) && get_ty_param(ty).map_or(false, TyS::is_str)) + || (is_type_lang_item(cx, ty, LangItem::OwnedBox) && get_ty_param(ty).map_or(false, Ty::is_str)) + || (match_type(cx, ty, &paths::COW) && get_ty_param(ty).map_or(false, Ty::is_str)) { Some(RepeatKind::String) } else { diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index c2202cb1e57..3021a40fae1 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -2106,7 +2106,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { let method_sig = cx.tcx.fn_sig(impl_item.def_id); let method_sig = cx.tcx.erase_late_bound_regions(method_sig); - let first_arg_ty = &method_sig.inputs().iter().next(); + let first_arg_ty = method_sig.inputs().iter().next(); // check conventions w.r.t. conversion method names and predicates if let Some(first_arg_ty) = first_arg_ty; @@ -2119,7 +2119,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if name == method_config.method_name && sig.decl.inputs.len() == method_config.param_count && method_config.output_type.matches(&sig.decl.output) && - method_config.self_kind.matches(cx, self_ty, first_arg_ty) && + method_config.self_kind.matches(cx, self_ty, *first_arg_ty) && fn_header_equals(method_config.fn_header, sig.header) && method_config.lifetime_param_cond(impl_item) { @@ -2151,7 +2151,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { cx, name, self_ty, - first_arg_ty, + *first_arg_ty, first_arg.pat.span, implements_trait, false diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index b67bfb6597b..7916fb8e3b4 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -105,7 +105,7 @@ fn check_addr_of_expr( if is_copy(cx, receiver_ty) || is_cow_into_owned(cx, method_name, method_def_id); if let Some(receiver_snippet) = snippet_opt(cx, receiver.span); then { - let (target_ty, n_target_refs) = peel_mid_ty_refs(target_ty); + let (target_ty, n_target_refs) = peel_mid_ty_refs(*target_ty); let (receiver_ty, n_receiver_refs) = peel_mid_ty_refs(receiver_ty); if receiver_ty == target_ty && n_target_refs >= n_receiver_refs { span_lint_and_sugg( @@ -228,7 +228,7 @@ fn check_other_call_arg<'tcx>( let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder(); if let Some(i) = call_args.iter().position(|arg| arg.hir_id == maybe_arg.hir_id); if let Some(input) = fn_sig.inputs().get(i); - let (input, n_refs) = peel_mid_ty_refs(input); + let (input, n_refs) = peel_mid_ty_refs(*input); if let (trait_predicates, projection_predicates) = get_input_traits_and_projections(cx, callee_def_id, input); if let Some(sized_def_id) = cx.tcx.lang_items().sized_trait(); if let [trait_predicate] = trait_predicates diff --git a/src/tools/clippy/clippy_lints/src/methods/utils.rs b/src/tools/clippy/clippy_lints/src/methods/utils.rs index c4cf994aaca..63c3273bd68 100644 --- a/src/tools/clippy/clippy_lints/src/methods/utils.rs +++ b/src/tools/clippy/clippy_lints/src/methods/utils.rs @@ -19,7 +19,7 @@ pub(super) fn derefs_to_slice<'tcx>( ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()), ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym::Vec), ty::Array(_, size) => size.try_eval_usize(cx.tcx, cx.param_env).is_some(), - ty::Ref(_, inner, _) => may_slice(cx, inner), + ty::Ref(_, inner, _) => may_slice(cx, *inner), _ => false, } } @@ -35,7 +35,7 @@ pub(super) fn derefs_to_slice<'tcx>( ty::Slice(_) => Some(expr), ty::Adt(def, _) if def.is_box() && may_slice(cx, ty.boxed_ty()) => Some(expr), ty::Ref(_, inner, _) => { - if may_slice(cx, inner) { + if may_slice(cx, *inner) { Some(expr) } else { None diff --git a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs index a2e09e5ecec..aecfea9c141 100644 --- a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs +++ b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs @@ -2,7 +2,7 @@ use crate::methods::SelfKind; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::is_copy; use rustc_lint::LateContext; -use rustc_middle::ty::TyS; +use rustc_middle::ty::Ty; use rustc_span::source_map::Span; use std::fmt; @@ -41,7 +41,7 @@ impl Convention { fn check<'tcx>( &self, cx: &LateContext<'tcx>, - self_ty: &'tcx TyS<'tcx>, + self_ty: Ty<'tcx>, other: &str, implements_trait: bool, is_trait_item: bool, @@ -84,8 +84,8 @@ impl fmt::Display for Convention { pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, item_name: &str, - self_ty: &'tcx TyS<'tcx>, - first_arg_ty: &'tcx TyS<'tcx>, + self_ty: Ty<'tcx>, + first_arg_ty: Ty<'tcx>, first_arg_span: Span, implements_trait: bool, is_trait_item: bool, diff --git a/src/tools/clippy/clippy_lints/src/methods/zst_offset.rs b/src/tools/clippy/clippy_lints/src/methods/zst_offset.rs index 866cf616679..e9f268da691 100644 --- a/src/tools/clippy/clippy_lints/src/methods/zst_offset.rs +++ b/src/tools/clippy/clippy_lints/src/methods/zst_offset.rs @@ -9,7 +9,7 @@ use super::ZST_OFFSET; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { if_chain! { if let ty::RawPtr(ty::TypeAndMut { ty, .. }) = cx.typeck_results().expr_ty(recv).kind(); - if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty)); + if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(*ty)); if layout.is_zst(); then { span_lint(cx, ZST_OFFSET, expr.span, "offset calculation on zero-sized value"); diff --git a/src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs b/src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs index d182a7d5249..195b2e5c2ee 100644 --- a/src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs @@ -4,7 +4,7 @@ use clippy_utils::sext; use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; +use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use std::fmt::Display; @@ -77,7 +77,7 @@ fn floating_point_operand_info<T: Display + PartialOrd + From<f32>>(f: &T) -> Op } } -fn might_have_negative_value(t: &ty::TyS<'_>) -> bool { +fn might_have_negative_value(t: Ty<'_>) -> bool { t.is_signed() || t.is_floating_point() } diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs index 1bdd805f658..b4e29101b39 100644 --- a/src/tools/clippy/clippy_lints/src/mut_key.rs +++ b/src/tools/clippy/clippy_lints/src/mut_key.rs @@ -113,7 +113,7 @@ fn check_sig<'tcx>(cx: &LateContext<'tcx>, item_hir_id: hir::HirId, decl: &hir:: let fn_def_id = cx.tcx.hir().local_def_id(item_hir_id); let fn_sig = cx.tcx.fn_sig(fn_def_id); for (hir_ty, ty) in iter::zip(decl.inputs, fn_sig.inputs().skip_binder()) { - check_ty(cx, hir_ty.span, ty); + check_ty(cx, hir_ty.span, *ty); } check_ty(cx, decl.output.span(), cx.tcx.erase_late_bound_regions(fn_sig.output())); } diff --git a/src/tools/clippy/clippy_lints/src/mut_mutex_lock.rs b/src/tools/clippy/clippy_lints/src/mut_mutex_lock.rs index 7871be41d62..b7f981faa2d 100644 --- a/src/tools/clippy/clippy_lints/src/mut_mutex_lock.rs +++ b/src/tools/clippy/clippy_lints/src/mut_mutex_lock.rs @@ -53,7 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for MutMutexLock { if path.ident.name == sym!(lock); let ty = cx.typeck_results().expr_ty(self_arg); if let ty::Ref(_, inner_ty, Mutability::Mut) = ty.kind(); - if is_type_diagnostic_item(cx, inner_ty, sym::Mutex); + if is_type_diagnostic_item(cx, *inner_ty, sym::Mutex); then { span_lint_and_sugg( cx, diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index 21ac6548b01..3ba99403f06 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -136,14 +136,14 @@ fn is_value_unfrozen_raw<'tcx>( result: Result<ConstValue<'tcx>, ErrorHandled>, ty: Ty<'tcx>, ) -> bool { - fn inner<'tcx>(cx: &LateContext<'tcx>, val: &'tcx Const<'tcx>) -> bool { - match val.ty.kind() { + fn inner<'tcx>(cx: &LateContext<'tcx>, val: Const<'tcx>) -> bool { + match val.ty().kind() { // the fact that we have to dig into every structs to search enums // leads us to the point checking `UnsafeCell` directly is the only option. ty::Adt(ty_def, ..) if Some(ty_def.did) == cx.tcx.lang_items().unsafe_cell_type() => true, ty::Array(..) | ty::Adt(..) | ty::Tuple(..) => { let val = cx.tcx.destructure_const(cx.param_env.and(val)); - val.fields.iter().any(|field| inner(cx, field)) + val.fields.iter().any(|field| inner(cx, *field)) }, _ => false, } diff --git a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs index ab1559c85d8..f4de999a928 100644 --- a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs +++ b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs @@ -205,7 +205,7 @@ fn ty_allowed_with_raw_pointer_heuristic<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'t ty::Tuple(_) => ty .tuple_fields() .all(|ty| ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait)), - ty::Array(ty, _) | ty::Slice(ty) => ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait), + ty::Array(ty, _) | ty::Slice(ty) => ty_allowed_with_raw_pointer_heuristic(cx, *ty, send_trait), ty::Adt(_, substs) => { if contains_pointer_like(cx, ty) { // descends only if ADT contains any raw pointers diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs index 3092ab8392a..d59249d7f13 100644 --- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs +++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs @@ -167,8 +167,8 @@ impl<'tcx> PassByRefOrValue { if_chain! { if !output_lts.contains(input_lt); - if is_copy(cx, ty); - if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes()); + if is_copy(cx, *ty); + if let Some(size) = cx.layout_of(*ty).ok().map(|l| l.size.bytes()); if size <= self.ref_min_size; if let hir::TyKind::Rptr(_, MutTy { ty: decl_ty, .. }) = input.kind; then { diff --git a/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs b/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs index 971729e5c54..f3515ea3c2d 100644 --- a/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs +++ b/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs @@ -116,7 +116,7 @@ fn get_pointee_ty_and_count_expr<'tcx>( if let ty::RawPtr(TypeAndMut { ty: pointee_ty, .. }) = cx.typeck_results().expr_ty(ptr_self).kind(); then { - return Some((pointee_ty, count)); + return Some((*pointee_ty, count)); } }; None diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs index 5257f5302cd..bca95b7f256 100644 --- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs @@ -98,7 +98,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate; if !bound_predicate.span.from_expansion(); if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind; - if let Some(PathSegment { res: Some(Res::SelfTy(Some(def_id), _)), .. }) = segments.first(); + if let Some(PathSegment { res: Some(Res::SelfTy{ trait_: Some(def_id), alias_to: _ }), .. }) = segments.first(); if let Some( Node::Item( diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs index 4c320deecc2..5e94ab6d048 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs @@ -376,7 +376,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.60.0"] pub TRANSMUTE_UNDEFINED_REPR, - correctness, + nursery, "transmute to or from a type with an undefined representation" } diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs index 5699f8e92cf..f3653199b37 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs @@ -38,7 +38,7 @@ pub(super) fn check<'tcx>( let arg = if from_ptr_ty.ty == *to_ref_ty { arg } else { - arg.as_ty(&format!("{} {}", cast, get_type_snippet(cx, qpath, to_ref_ty))) + arg.as_ty(&format!("{} {}", cast, get_type_snippet(cx, qpath, *to_ref_ty))) }; diag.span_suggestion( diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs index fdef8bac7f9..7570bc2a7a8 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs @@ -56,10 +56,10 @@ pub(super) fn check<'tcx>( "transmute from a reference to a reference", |diag| if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) { let ty_from_and_mut = ty::TypeAndMut { - ty: ty_from, + ty: *ty_from, mutbl: *from_mutbl }; - let ty_to_and_mut = ty::TypeAndMut { ty: ty_to, mutbl: *to_mutbl }; + let ty_to_and_mut = ty::TypeAndMut { ty: *ty_to, mutbl: *to_mutbl }; let sugg_paren = arg .as_ty(cx.tcx.mk_ptr(ty_from_and_mut)) .as_ty(cx.tcx.mk_ptr(ty_to_and_mut)); diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs index 030d2c23784..9ed5952a109 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs @@ -200,27 +200,27 @@ fn reduce_refs<'tcx>( loop { return match (from_ty.kind(), to_ty.kind()) { ( - ty::Ref(_, from_sub_ty, _) | ty::RawPtr(TypeAndMut { ty: from_sub_ty, .. }), - ty::Ref(_, to_sub_ty, _) | ty::RawPtr(TypeAndMut { ty: to_sub_ty, .. }), + &ty::Ref(_, from_sub_ty, _) | &ty::RawPtr(TypeAndMut { ty: from_sub_ty, .. }), + &ty::Ref(_, to_sub_ty, _) | &ty::RawPtr(TypeAndMut { ty: to_sub_ty, .. }), ) => { from_ty = from_sub_ty; to_ty = to_sub_ty; continue; }, - (ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. }), _) + (&ty::Ref(_, unsized_ty, _) | &ty::RawPtr(TypeAndMut { ty: unsized_ty, .. }), _) if !unsized_ty.is_sized(cx.tcx.at(span), cx.param_env) => { ReducedTys::FromFatPtr { unsized_ty } }, - (_, ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. })) + (_, &ty::Ref(_, unsized_ty, _) | &ty::RawPtr(TypeAndMut { ty: unsized_ty, .. })) if !unsized_ty.is_sized(cx.tcx.at(span), cx.param_env) => { ReducedTys::ToFatPtr { unsized_ty } }, - (ty::Ref(_, from_ty, _) | ty::RawPtr(TypeAndMut { ty: from_ty, .. }), _) => { + (&ty::Ref(_, from_ty, _) | &ty::RawPtr(TypeAndMut { ty: from_ty, .. }), _) => { ReducedTys::FromPtr { from_ty, to_ty } }, - (_, ty::Ref(_, to_ty, _) | ty::RawPtr(TypeAndMut { ty: to_ty, .. })) => { + (_, &ty::Ref(_, to_ty, _) | &ty::RawPtr(TypeAndMut { ty: to_ty, .. })) => { ReducedTys::ToPtr { from_ty, to_ty } }, _ => ReducedTys::Other { from_ty, to_ty }, @@ -247,7 +247,7 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx> }, ty::Tuple(args) => { let mut iter = args.iter().map(GenericArg::expect_ty); - let Some(sized_ty) = iter.find(|ty| !is_zero_sized_ty(cx, ty)) else { + let Some(sized_ty) = iter.find(|ty| !is_zero_sized_ty(cx, *ty)) else { return ReducedTy::OrderedFields(ty); }; if iter.all(|ty| is_zero_sized_ty(cx, ty)) { @@ -265,7 +265,7 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx> .fields .iter() .map(|f| cx.tcx.type_of(f.did).subst(cx.tcx, substs)); - let Some(sized_ty) = iter.find(|ty| !is_zero_sized_ty(cx, ty)) else { + let Some(sized_ty) = iter.find(|ty| !is_zero_sized_ty(cx, *ty)) else { return ReducedTy::OrderedFields(ty); }; if iter.all(|ty| is_zero_sized_ty(cx, ty)) { diff --git a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs index 998f97eb5d8..3cc3d40a143 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs @@ -34,7 +34,7 @@ pub(super) fn check<'tcx>( |diag| { if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) { let rty_and_mut = ty::TypeAndMut { - ty: rty, + ty: *rty, mutbl: *rty_mutbl, }; diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs index eee1229e1ef..7c39a08a336 100644 --- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs +++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs @@ -84,7 +84,8 @@ fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Ve let partial_ord_preds = get_trait_predicates_for_trait_id(cx, generics, cx.tcx.lang_items().partial_ord_trait()); // Trying to call erase_late_bound_regions on fn_sig.inputs() gives the following error - // The trait `rustc::ty::TypeFoldable<'_>` is not implemented for `&[&rustc::ty::TyS<'_>]` + // The trait `rustc::ty::TypeFoldable<'_>` is not implemented for + // `&[rustc_middle::ty::Ty<'_>]` let inputs_output = cx.tcx.erase_late_bound_regions(fn_sig.inputs_and_output()); inputs_output .iter() diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs index be20282b3b8..80164c59ba7 100644 --- a/src/tools/clippy/clippy_lints/src/use_self.rs +++ b/src/tools/clippy/clippy_lints/src/use_self.rs @@ -204,7 +204,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { ref types_to_skip, }) = self.stack.last(); if let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind; - if !matches!(path.res, Res::SelfTy(..) | Res::Def(DefKind::TyParam, _)); + if !matches!(path.res, Res::SelfTy { .. } | Res::Def(DefKind::TyParam, _)); if !types_to_skip.contains(&hir_ty.hir_id); let ty = if in_body > 0 { cx.typeck_results().node_type(hir_ty.hir_id) @@ -231,7 +231,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { } match expr.kind { ExprKind::Struct(QPath::Resolved(_, path), ..) => match path.res { - Res::SelfTy(..) => (), + Res::SelfTy { .. } => (), Res::Def(DefKind::Variant, _) => lint_path_to_variant(cx, path), _ => span_lint(cx, path.span), }, diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs index b0044695ea8..1fa6301ebd7 100644 --- a/src/tools/clippy/clippy_lints/src/write.rs +++ b/src/tools/clippy/clippy_lints/src/write.rs @@ -453,7 +453,7 @@ impl SimpleFormatArgs { } } }, - ArgumentNamed(n) => { + ArgumentNamed(n, _) => { if let Some(x) = self.named.iter_mut().find(|x| x.0 == n) { match x.1.as_slice() { // A non-empty format string has been seen already. diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 3f604d5166b..d40583c47dd 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -567,11 +567,11 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { } } -pub fn miri_to_const(result: &ty::Const<'_>) -> Option<Constant> { +pub fn miri_to_const(result: ty::Const<'_>) -> Option<Constant> { use rustc_middle::mir::interpret::ConstValue; - match result.val { + match result.val() { ty::ConstKind::Value(ConstValue::Scalar(Scalar::Int(int))) => { - match result.ty.kind() { + match result.ty().kind() { ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)), ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.assert_bits(int.size()))), ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits( @@ -590,7 +590,7 @@ pub fn miri_to_const(result: &ty::Const<'_>) -> Option<Constant> { _ => None, } }, - ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => match result.ty.kind() { + ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => match result.ty().kind() { ty::Ref(_, tam, _) => match tam.kind() { ty::Str => String::from_utf8( data.inspect_with_uninit_and_ptr_outside_interpreter(start..end) @@ -602,9 +602,9 @@ pub fn miri_to_const(result: &ty::Const<'_>) -> Option<Constant> { }, _ => None, }, - ty::ConstKind::Value(ConstValue::ByRef { alloc, offset: _ }) => match result.ty.kind() { + ty::ConstKind::Value(ConstValue::ByRef { alloc, offset: _ }) => match result.ty().kind() { ty::Array(sub_type, len) => match sub_type.kind() { - ty::Float(FloatTy::F32) => match miri_to_const(len) { + ty::Float(FloatTy::F32) => match miri_to_const(*len) { Some(Constant::Int(len)) => alloc .inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * len as usize)) .to_owned() @@ -618,7 +618,7 @@ pub fn miri_to_const(result: &ty::Const<'_>) -> Option<Constant> { .map(Constant::Vec), _ => None, }, - ty::Float(FloatTy::F64) => match miri_to_const(len) { + ty::Float(FloatTy::F64) => match miri_to_const(*len) { Some(Constant::Int(len)) => alloc .inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * len as usize)) .to_owned() diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 42955080c96..4bb401273c4 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1460,7 +1460,7 @@ pub fn is_self(slf: &Param<'_>) -> bool { pub fn is_self_ty(slf: &hir::Ty<'_>) -> bool { if let TyKind::Path(QPath::Resolved(None, path)) = slf.kind { - if let Res::SelfTy(..) = path.res { + if let Res::SelfTy { .. } = path.res { return true; } } @@ -1911,10 +1911,10 @@ pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<S let expr_type = cx.typeck_results().expr_ty_adjusted(expr); let expr_kind = expr_type.kind(); let is_primitive = match expr_kind { - rustc_ty::Slice(element_type) => is_recursively_primitive_type(element_type), + rustc_ty::Slice(element_type) => is_recursively_primitive_type(*element_type), rustc_ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), &rustc_ty::Slice(_)) => { if let rustc_ty::Slice(element_type) = inner_ty.kind() { - is_recursively_primitive_type(element_type) + is_recursively_primitive_type(*element_type) } else { unreachable!() } diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 7512039a480..c039fec955d 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -149,7 +149,7 @@ fn check_rvalue<'tcx>( Rvalue::Cast(CastKind::Misc, operand, cast_ty) => { use rustc_middle::ty::cast::CastTy; let cast_in = CastTy::from_ty(operand.ty(body, tcx)).expect("bad input type for cast"); - let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); + let cast_out = CastTy::from_ty(*cast_ty).expect("bad output type for cast"); match (cast_in, cast_out) { (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) => { Err((span, "casting pointers to ints is unstable in const fn".into())) diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 958e6d1ec46..b44899e6bd5 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -103,7 +103,7 @@ pub fn has_iter_method(cx: &LateContext<'_>, probably_ref_ty: Ty<'_>) -> Option< ]; let ty_to_check = match probably_ref_ty.kind() { - ty::Ref(_, ty_to_check, _) => ty_to_check, + ty::Ref(_, ty_to_check, _) => *ty_to_check, _ => probably_ref_ty, }; @@ -209,7 +209,7 @@ fn is_normalizable_helper<'tcx>( ty: Ty<'tcx>, cache: &mut FxHashMap<Ty<'tcx>, bool>, ) -> bool { - if let Some(&cached_result) = cache.get(ty) { + if let Some(&cached_result) = cache.get(&ty) { return cached_result; } // prevent recursive loops, false-negative is better than endless loop leading to stack overflow @@ -252,7 +252,7 @@ pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool { match ty.kind() { ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => true, ty::Ref(_, inner, _) if *inner.kind() == ty::Str => true, - ty::Array(inner_type, _) | ty::Slice(inner_type) => is_recursively_primitive_type(inner_type), + ty::Array(inner_type, _) | ty::Slice(inner_type) => is_recursively_primitive_type(*inner_type), ty::Tuple(inner_types) => inner_types.types().all(is_recursively_primitive_type), _ => false, } @@ -318,7 +318,7 @@ pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool { pub fn peel_mid_ty_refs(ty: Ty<'_>) -> (Ty<'_>, usize) { fn peel(ty: Ty<'_>, count: usize) -> (Ty<'_>, usize) { if let ty::Ref(_, ty, _) = ty.kind() { - peel(ty, count + 1) + peel(*ty, count + 1) } else { (ty, count) } @@ -331,8 +331,8 @@ pub fn peel_mid_ty_refs(ty: Ty<'_>) -> (Ty<'_>, usize) { pub fn peel_mid_ty_refs_is_mutable(ty: Ty<'_>) -> (Ty<'_>, usize, Mutability) { fn f(ty: Ty<'_>, count: usize, mutability: Mutability) -> (Ty<'_>, usize, Mutability) { match ty.kind() { - ty::Ref(_, ty, Mutability::Mut) => f(ty, count + 1, mutability), - ty::Ref(_, ty, Mutability::Not) => f(ty, count + 1, Mutability::Not), + ty::Ref(_, ty, Mutability::Mut) => f(*ty, count + 1, mutability), + ty::Ref(_, ty, Mutability::Not) => f(*ty, count + 1, Mutability::Not), _ => (ty, count, mutability), } } @@ -360,7 +360,7 @@ pub fn walk_ptrs_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> { pub fn walk_ptrs_ty_depth(ty: Ty<'_>) -> (Ty<'_>, usize) { fn inner(ty: Ty<'_>, depth: usize) -> (Ty<'_>, usize) { match ty.kind() { - ty::Ref(_, ty, _) => inner(ty, depth + 1), + ty::Ref(_, ty, _) => inner(*ty, depth + 1), _ => (ty, depth), } } @@ -394,7 +394,7 @@ pub fn same_type_and_consts<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { /// Checks if a given type looks safe to be uninitialized. pub fn is_uninit_value_valid_for_ty(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { match ty.kind() { - ty::Array(component, _) => is_uninit_value_valid_for_ty(cx, component), + ty::Array(component, _) => is_uninit_value_valid_for_ty(cx, *component), ty::Tuple(types) => types.types().all(|ty| is_uninit_value_valid_for_ty(cx, ty)), ty::Adt(adt, _) => cx.tcx.lang_items().maybe_uninit() == Some(adt.did), _ => false, diff --git a/src/tools/clippy/doc/common_tools_writing_lints.md b/src/tools/clippy/doc/common_tools_writing_lints.md index 36c454745ba..828bf4cbef9 100644 --- a/src/tools/clippy/doc/common_tools_writing_lints.md +++ b/src/tools/clippy/doc/common_tools_writing_lints.md @@ -26,7 +26,7 @@ Sometimes you may want to retrieve the type `Ty` of an expression `Expr`, for ex - does it implement a trait? This operation is performed using the [`expr_ty()`][expr_ty] method from the [`TypeckResults`][TypeckResults] struct, -that gives you access to the underlying structure [`TyS`][TyS]. +that gives you access to the underlying structure [`Ty`][Ty]. Example of use: ```rust @@ -259,7 +259,7 @@ expression with a different context from `a`. assert_eq!(x_is_some_span.ctxt(), x_unwrap_span.ctxt()); ``` -[TyS]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyS.html +[Ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html [TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.TyKind.html [TypeckResults]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html [expr_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html#method.expr_ty 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/rust-analyzer b/src/tools/rust-analyzer -Subproject ba330548023607717295f0dfd61b72eda41aa9d +Subproject 02904e99acc3daf39b56ed18aa07e62aeb9492c diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index da0c9b66a8c..52429fee461 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -93,11 +93,12 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[ "chrono", "cmake", "compiler_builtins", - "cpuid-bool", + "cpufeatures", "crc32fast", "crossbeam-deque", "crossbeam-epoch", "crossbeam-utils", + "crypto-common", "cstr", "datafrog", "difference", 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) { |
