diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 6c2a871e520f9..544ef38c12c6d 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -214,11 +214,7 @@ fn handle_native(name: &str) -> &str { } pub fn target_cpu(sess: &Session) -> &str { - let name = match sess.opts.cg.target_cpu { - Some(ref s) => &**s, - None => &*sess.target.cpu, - }; - + let name = sess.opts.cg.target_cpu.as_ref().unwrap_or(&sess.target.cpu); handle_native(name) } @@ -254,8 +250,6 @@ pub fn handle_native_features(sess: &Session) -> Vec { } pub fn tune_cpu(sess: &Session) -> Option<&str> { - match sess.opts.debugging_opts.tune_cpu { - Some(ref s) => Some(handle_native(&**s)), - None => None, - } + let name = sess.opts.debugging_opts.tune_cpu.as_ref()?; + Some(handle_native(name)) } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index f47d2ada61a14..2ce5fe5ad504b 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -29,7 +29,6 @@ use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_session::cgu_reuse_tracker::CguReuse; use rustc_session::config::{self, EntryFnType}; -use rustc_session::utils::NativeLibKind; use rustc_session::Session; use rustc_target::abi::{Align, LayoutOf, VariantIdx}; @@ -817,32 +816,6 @@ pub fn provide_both(providers: &mut Providers) { } tcx.sess.opts.optimize }; - - providers.dllimport_foreign_items = |tcx, krate| { - let module_map = tcx.foreign_modules(krate); - - let dllimports = tcx - .native_libraries(krate) - .iter() - .filter(|lib| { - if !matches!(lib.kind, NativeLibKind::Dylib | NativeLibKind::Unspecified) { - return false; - } - let cfg = match lib.cfg { - Some(ref cfg) => cfg, - None => return true, - }; - attr::cfg_matches(cfg, &tcx.sess.parse_sess, None) - }) - .filter_map(|lib| lib.foreign_module) - .map(|id| &module_map[&id]) - .flat_map(|module| module.foreign_items.iter().cloned()) - .collect(); - dllimports - }; - - providers.is_dllimport_foreign_item = - |tcx, def_id| tcx.dllimport_foreign_items(def_id.krate).contains(&def_id); } fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> CguReuse { diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 8373304ea9134..e8c711cae64ef 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -56,36 +56,11 @@ crate fn annotate_err_with_kind( }; } -/// Instead of e.g. `vec![a, b, c]` in a pattern context, suggest `[a, b, c]`. -fn suggest_slice_pat(e: &mut DiagnosticBuilder<'_>, site_span: Span, parser: &Parser<'_>) { - let mut suggestion = None; - if let Ok(code) = parser.sess.source_map().span_to_snippet(site_span) { - if let Some(bang) = code.find('!') { - suggestion = Some(code[bang + 1..].to_string()); - } - } - if let Some(suggestion) = suggestion { - e.span_suggestion( - site_span, - "use a slice pattern here instead", - suggestion, - Applicability::MachineApplicable, - ); - } else { - e.span_label(site_span, "use a slice pattern here instead"); - } - e.help( - "for more information, see https://doc.rust-lang.org/edition-guide/\ - rust-2018/slice-patterns.html", - ); -} - fn emit_frag_parse_err( mut e: DiagnosticBuilder<'_>, parser: &Parser<'_>, orig_parser: &mut Parser<'_>, site_span: Span, - macro_ident: Ident, arm_span: Span, kind: AstFragmentKind, ) { @@ -113,9 +88,6 @@ fn emit_frag_parse_err( e.span_label(site_span, "in this macro invocation"); } match kind { - AstFragmentKind::Pat if macro_ident.name == sym::vec => { - suggest_slice_pat(&mut e, site_span, parser); - } // Try a statement if an expression is wanted but failed and suggest adding `;` to call. AstFragmentKind::Expr => match parse_ast_fragment(orig_parser, AstFragmentKind::Stmts) { Err(mut err) => err.cancel(), @@ -143,7 +115,7 @@ impl<'a> ParserAnyMacro<'a> { let fragment = match parse_ast_fragment(parser, kind) { Ok(f) => f, Err(err) => { - emit_frag_parse_err(err, parser, snapshot, site_span, macro_ident, arm_span, kind); + emit_frag_parse_err(err, parser, snapshot, site_span, arm_span, kind); return kind.dummy(site_span); } }; diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 4ede9d67b741f..a81eb747a335a 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -5,6 +5,7 @@ use rustc_ast as ast; use rustc_ast::NodeId; use rustc_macros::HashStable_Generic; use rustc_span::hygiene::MacroKind; +use rustc_span::Symbol; use std::array::IntoIter; use std::fmt::Debug; @@ -34,7 +35,7 @@ pub enum CtorKind { #[derive(HashStable_Generic)] pub enum NonMacroAttrKind { /// Single-segment attribute defined by the language (`#[inline]`) - Builtin, + Builtin(Symbol), /// Multi-segment custom attribute living in a "tool module" (`#[rustfmt::skip]`). Tool, /// Single-segment custom attribute registered by a derive macro (`#[serde(default)]`). @@ -371,7 +372,7 @@ impl CtorKind { impl NonMacroAttrKind { pub fn descr(self) -> &'static str { match self { - NonMacroAttrKind::Builtin => "built-in attribute", + NonMacroAttrKind::Builtin(..) => "built-in attribute", NonMacroAttrKind::Tool => "tool attribute", NonMacroAttrKind::DeriveHelper | NonMacroAttrKind::DeriveHelperCompat => { "derive helper attribute" @@ -393,7 +394,7 @@ impl NonMacroAttrKind { NonMacroAttrKind::Tool | NonMacroAttrKind::DeriveHelper | NonMacroAttrKind::DeriveHelperCompat => true, - NonMacroAttrKind::Builtin | NonMacroAttrKind::Registered => false, + NonMacroAttrKind::Builtin(..) | NonMacroAttrKind::Registered => false, } } } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 9770e67f2d25a..00ee7b8ec7709 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1281,11 +1281,6 @@ rustc_queries! { } Other { - query dllimport_foreign_items(_: CrateNum) - -> FxHashSet { - storage(ArenaCacheSelector<'tcx>) - desc { "dllimport_foreign_items" } - } query is_dllimport_foreign_item(def_id: DefId) -> bool { desc { |tcx| "is_dllimport_foreign_item({})", tcx.def_path_str(def_id) } } @@ -1316,7 +1311,7 @@ rustc_queries! { desc { "looking up a named region" } } query is_late_bound_map(_: LocalDefId) -> - Option<&'tcx FxHashSet> { + Option<(LocalDefId, &'tcx FxHashSet)> { desc { "testing if a region is late bound" } } query object_lifetime_defaults_map(_: LocalDefId) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index a355242f5ce67..1f7dc7bb79dfe 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -3,6 +3,7 @@ use crate::arena::Arena; use crate::dep_graph::DepGraph; use crate::hir::exports::ExportMap; +use crate::hir::place::Place as HirPlace; use crate::ich::{NodeIdHashingMode, StableHashingContext}; use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos}; use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource}; @@ -379,7 +380,7 @@ pub struct TypeckResults<'tcx> { /// Records the reasons that we picked the kind of each closure; /// not all closures are present in the map. - closure_kind_origins: ItemLocalMap<(Span, Symbol)>, + closure_kind_origins: ItemLocalMap<(Span, HirPlace<'tcx>)>, /// For each fn, records the "liberated" types of its arguments /// and return type. Liberated means that all bound regions @@ -642,11 +643,13 @@ impl<'tcx> TypeckResults<'tcx> { self.upvar_capture_map[&upvar_id] } - pub fn closure_kind_origins(&self) -> LocalTableInContext<'_, (Span, Symbol)> { + pub fn closure_kind_origins(&self) -> LocalTableInContext<'_, (Span, HirPlace<'tcx>)> { LocalTableInContext { hir_owner: self.hir_owner, data: &self.closure_kind_origins } } - pub fn closure_kind_origins_mut(&mut self) -> LocalTableInContextMut<'_, (Span, Symbol)> { + pub fn closure_kind_origins_mut( + &mut self, + ) -> LocalTableInContextMut<'_, (Span, HirPlace<'tcx>)> { LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.closure_kind_origins } } @@ -2578,7 +2581,8 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn is_late_bound(self, id: HirId) -> bool { - self.is_late_bound_map(id.owner).map_or(false, |set| set.contains(&id.local_id)) + self.is_late_bound_map(id.owner) + .map_or(false, |(owner, set)| owner == id.owner && set.contains(&id.local_id)) } pub fn object_lifetime_defaults(self, id: HirId) -> Option<&'tcx [ObjectLifetimeDefault]> { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 1399fc76e02d6..b1769b17b42b5 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -17,7 +17,9 @@ pub use self::IntVarValue::*; pub use self::Variance::*; use crate::hir::exports::ExportMap; -use crate::hir::place::Place as HirPlace; +use crate::hir::place::{ + Place as HirPlace, PlaceBase as HirPlaceBase, ProjectionKind as HirProjectionKind, +}; use crate::ich::StableHashingContext; use crate::middle::cstore::CrateStoreDyn; use crate::middle::resolve_lifetime::ObjectLifetimeDefault; @@ -734,6 +736,43 @@ pub struct CapturedPlace<'tcx> { pub info: CaptureInfo<'tcx>, } +pub fn place_to_string_for_capture(tcx: TyCtxt<'tcx>, place: &HirPlace<'tcx>) -> String { + let name = match place.base { + HirPlaceBase::Upvar(upvar_id) => tcx.hir().name(upvar_id.var_path.hir_id).to_string(), + _ => bug!("Capture_information should only contain upvars"), + }; + let mut curr_string = name; + + for (i, proj) in place.projections.iter().enumerate() { + match proj.kind { + HirProjectionKind::Deref => { + curr_string = format!("*{}", curr_string); + } + HirProjectionKind::Field(idx, variant) => match place.ty_before_projection(i).kind() { + ty::Adt(def, ..) => { + curr_string = format!( + "{}.{}", + curr_string, + def.variants[variant].fields[idx as usize].ident.name.as_str() + ); + } + ty::Tuple(_) => { + curr_string = format!("{}.{}", curr_string, idx); + } + _ => { + bug!( + "Field projection applied to a type other than Adt or Tuple: {:?}.", + place.ty_before_projection(i).kind() + ) + } + }, + proj => bug!("{:?} unexpected because it isn't captured", proj), + } + } + + curr_string.to_string() +} + /// Part of `MinCaptureInformationMap`; describes the capture kind (&, &mut, move) /// for a particular capture as well as identifying the part of the source code /// that triggered this capture to occur. diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs index 4ebc1cdca6059..9f97d5c9af7d8 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs @@ -103,7 +103,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let did = did.expect_local(); let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did); - if let Some((span, name)) = + if let Some((span, hir_place)) = self.infcx.tcx.typeck(did).closure_kind_origins().get(hir_id) { diag.span_note( @@ -111,7 +111,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &format!( "closure cannot be invoked more than once because it moves the \ variable `{}` out of its environment", - name, + ty::place_to_string_for_capture(self.infcx.tcx, hir_place) ), ); return; @@ -127,7 +127,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let did = did.expect_local(); let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did); - if let Some((span, name)) = + if let Some((span, hir_place)) = self.infcx.tcx.typeck(did).closure_kind_origins().get(hir_id) { diag.span_note( @@ -135,7 +135,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &format!( "closure cannot be moved more than once as it is not `Copy` due to \ moving the variable `{}` out of its environment", - name + ty::place_to_string_for_capture(self.infcx.tcx, hir_place) ), ); } diff --git a/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs b/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs index b7d22fab3dde6..157959b115947 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs @@ -39,10 +39,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { user_provided_sig = None; } else { let typeck_results = self.tcx().typeck(mir_def_id); - user_provided_sig = match typeck_results.user_provided_sigs.get(&mir_def_id.to_def_id()) - { - None => None, - Some(user_provided_poly_sig) => { + user_provided_sig = typeck_results.user_provided_sigs.get(&mir_def_id.to_def_id()).map( + |user_provided_poly_sig| { // Instantiate the canonicalized variables from // user-provided signature (e.g., the `_` in the code // above) with fresh variables. @@ -54,18 +52,16 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // Replace the bound items in the fn sig with fresh // variables, so that they represent the view from // "inside" the closure. - Some( - self.infcx - .replace_bound_vars_with_fresh_vars( - body.span, - LateBoundRegionConversionTime::FnCall, - poly_sig, - ) - .0, - ) - } - } - }; + self.infcx + .replace_bound_vars_with_fresh_vars( + body.span, + LateBoundRegionConversionTime::FnCall, + poly_sig, + ) + .0 + }, + ); + } debug!( "equate_inputs_and_outputs: normalized_input_tys = {:?}, local_decls = {:?}", diff --git a/compiler/rustc_mir/src/borrow_check/universal_regions.rs b/compiler/rustc_mir/src/borrow_check/universal_regions.rs index c1a0d9856b7ea..02d951b70e28d 100644 --- a/compiler/rustc_mir/src/borrow_check/universal_regions.rs +++ b/compiler/rustc_mir/src/borrow_check/universal_regions.rs @@ -788,13 +788,13 @@ fn for_each_late_bound_region_defined_on<'tcx>( fn_def_id: DefId, mut f: impl FnMut(ty::Region<'tcx>), ) { - if let Some(late_bounds) = tcx.is_late_bound_map(fn_def_id.expect_local()) { - for late_bound in late_bounds.iter() { - let hir_id = HirId { owner: fn_def_id.expect_local(), local_id: *late_bound }; + if let Some((owner, late_bounds)) = tcx.is_late_bound_map(fn_def_id.expect_local()) { + for &late_bound in late_bounds.iter() { + let hir_id = HirId { owner, local_id: late_bound }; let name = tcx.hir().name(hir_id); let region_def_id = tcx.hir().local_def_id(hir_id); let liberated_region = tcx.mk_region(ty::ReFree(ty::FreeRegion { - scope: fn_def_id, + scope: owner.to_def_id(), bound_region: ty::BoundRegionKind::BrNamed(region_def_id.to_def_id(), name), })); f(liberated_region); diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index e96fc185b7e03..4ab14c158d337 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -115,7 +115,7 @@ impl<'a> Resolver<'a> { self.get_module(parent_id) } - crate fn get_module(&mut self, def_id: DefId) -> Module<'a> { + pub fn get_module(&mut self, def_id: DefId) -> Module<'a> { // If this is a local module, it will be in `module_map`, no need to recalculate it. if let Some(def_id) = def_id.as_local() { return self.module_map[&def_id]; diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 4f8047ac2dff0..69fb6870d2c67 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -683,7 +683,7 @@ impl<'a> Resolver<'a> { )); } Scope::BuiltinAttrs => { - let res = Res::NonMacroAttr(NonMacroAttrKind::Builtin); + let res = Res::NonMacroAttr(NonMacroAttrKind::Builtin(kw::Empty)); if filter_fn(res) { suggestions.extend( BUILTIN_ATTRIBUTES diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 9de35a8006123..97e556f5a338d 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -14,7 +14,6 @@ use crate::{ResolutionError, Resolver, Segment, UseError}; use rustc_ast::ptr::P; use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use rustc_ast::*; -use rustc_ast::{unwrap_or, walk_list}; use rustc_ast_lowering::ResolverAstLowering; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::DiagnosticId; @@ -1911,7 +1910,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // it needs to be added to the trait map. if ns == ValueNS { let item_name = path.last().unwrap().ident; - let traits = self.get_traits_containing_item(item_name, ns); + let traits = self.traits_in_scope(item_name, ns); self.r.trait_map.insert(id, traits); } @@ -2371,12 +2370,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // field, we need to add any trait methods we find that match // the field name so that we can do some nice error reporting // later on in typeck. - let traits = self.get_traits_containing_item(ident, ValueNS); + let traits = self.traits_in_scope(ident, ValueNS); self.r.trait_map.insert(expr.id, traits); } ExprKind::MethodCall(ref segment, ..) => { debug!("(recording candidate traits for expr) recording traits for {}", expr.id); - let traits = self.get_traits_containing_item(segment.ident, ValueNS); + let traits = self.traits_in_scope(segment.ident, ValueNS); self.r.trait_map.insert(expr.id, traits); } _ => { @@ -2385,64 +2384,13 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } } - fn get_traits_containing_item( - &mut self, - mut ident: Ident, - ns: Namespace, - ) -> Vec { - debug!("(getting traits containing item) looking for '{}'", ident.name); - - let mut found_traits = Vec::new(); - // Look for the current trait. - if let Some((module, _)) = self.current_trait_ref { - if self - .r - .resolve_ident_in_module( - ModuleOrUniformRoot::Module(module), - ident, - ns, - &self.parent_scope, - false, - module.span, - ) - .is_ok() - { - let def_id = module.def_id().unwrap(); - found_traits.push(TraitCandidate { def_id, import_ids: smallvec![] }); - } - } - - ident.span = ident.span.normalize_to_macros_2_0(); - let mut search_module = self.parent_scope.module; - loop { - self.r.get_traits_in_module_containing_item( - ident, - ns, - search_module, - &mut found_traits, - &self.parent_scope, - ); - let mut span_data = ident.span.data(); - search_module = unwrap_or!( - self.r.hygienic_lexical_parent(search_module, &mut span_data.ctxt), - break - ); - ident.span = span_data.span(); - } - - if let Some(prelude) = self.r.prelude { - if !search_module.no_implicit_prelude { - self.r.get_traits_in_module_containing_item( - ident, - ns, - prelude, - &mut found_traits, - &self.parent_scope, - ); - } - } - - found_traits + fn traits_in_scope(&mut self, ident: Ident, ns: Namespace) -> Vec { + self.r.traits_in_scope( + self.current_trait_ref.as_ref().map(|(module, _)| *module), + &self.parent_scope, + ident.span.ctxt(), + Some((ident.name, ns)), + ) } } diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index aab5c3cf8f59d..1be06a446875b 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -11,7 +11,8 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, DefIdMap, LOCAL_CRATE}; +use rustc_hir::hir_id::ItemLocalId; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node, ParamName, QPath}; use rustc_hir::{GenericParamKind, HirIdMap, HirIdSet, LifetimeParamKind}; @@ -20,6 +21,7 @@ use rustc_middle::middle::resolve_lifetime::*; use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_session::lint; +use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; use std::borrow::Cow; @@ -284,7 +286,7 @@ pub fn provide(providers: &mut ty::query::Providers) { resolve_lifetimes, named_region_map: |tcx, id| tcx.resolve_lifetimes(LOCAL_CRATE).defs.get(&id), - is_late_bound_map: |tcx, id| tcx.resolve_lifetimes(LOCAL_CRATE).late_bound.get(&id), + is_late_bound_map, object_lifetime_defaults_map: |tcx, id| { tcx.resolve_lifetimes(LOCAL_CRATE).object_lifetime_defaults.get(&id) }, @@ -320,6 +322,32 @@ fn resolve_lifetimes(tcx: TyCtxt<'_>, for_krate: CrateNum) -> ResolveLifetimes { rl } +fn is_late_bound_map<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, +) -> Option<(LocalDefId, &'tcx FxHashSet)> { + match tcx.def_kind(def_id) { + DefKind::AnonConst => { + let mut def_id = tcx + .parent(def_id.to_def_id()) + .unwrap_or_else(|| bug!("anon const or closure without a parent")); + // We search for the next outer anon const or fn here + // while skipping closures. + // + // Note that for `AnonConst` we still just recurse until we + // find a function body, but who cares :shrug: + while tcx.is_closure(def_id) { + def_id = tcx + .parent(def_id) + .unwrap_or_else(|| bug!("anon const or closure without a parent")); + } + + tcx.is_late_bound_map(def_id.expect_local()) + } + _ => tcx.resolve_lifetimes(LOCAL_CRATE).late_bound.get(&def_id).map(|lt| (def_id, lt)), + } +} + fn krate(tcx: TyCtxt<'_>) -> NamedRegionMap { let krate = tcx.hir().krate(); let mut map = NamedRegionMap { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index c5b8f7d647ca7..af5341623758a 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -44,9 +44,9 @@ use rustc_index::vec::IndexVec; use rustc_metadata::creader::{CStore, CrateLoader}; use rustc_middle::hir::exports::ExportMap; use rustc_middle::middle::cstore::{CrateStore, MetadataLoaderDyn}; +use rustc_middle::span_bug; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, DefIdTree, ResolverOutputs}; -use rustc_middle::{bug, span_bug}; use rustc_session::lint; use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer}; use rustc_session::Session; @@ -1477,49 +1477,76 @@ impl<'a> Resolver<'a> { self.crate_loader.postprocess(krate); } - fn get_traits_in_module_containing_item( + pub fn traits_in_scope( + &mut self, + current_trait: Option>, + parent_scope: &ParentScope<'a>, + ctxt: SyntaxContext, + assoc_item: Option<(Symbol, Namespace)>, + ) -> Vec { + let mut found_traits = Vec::new(); + + if let Some(module) = current_trait { + if self.trait_may_have_item(Some(module), assoc_item) { + let def_id = module.def_id().unwrap(); + found_traits.push(TraitCandidate { def_id, import_ids: smallvec![] }); + } + } + + self.visit_scopes(ScopeSet::All(TypeNS, false), parent_scope, ctxt, |this, scope, _, _| { + match scope { + Scope::Module(module) => { + this.traits_in_module(module, assoc_item, &mut found_traits); + } + Scope::StdLibPrelude => { + if let Some(module) = this.prelude { + this.traits_in_module(module, assoc_item, &mut found_traits); + } + } + Scope::ExternPrelude | Scope::ToolPrelude | Scope::BuiltinTypes => {} + _ => unreachable!(), + } + None::<()> + }); + + found_traits + } + + fn traits_in_module( &mut self, - ident: Ident, - ns: Namespace, module: Module<'a>, + assoc_item: Option<(Symbol, Namespace)>, found_traits: &mut Vec, - parent_scope: &ParentScope<'a>, ) { - assert!(ns == TypeNS || ns == ValueNS); module.ensure_traits(self); let traits = module.traits.borrow(); + for (trait_name, trait_binding) in traits.as_ref().unwrap().iter() { + if self.trait_may_have_item(trait_binding.module(), assoc_item) { + let def_id = trait_binding.res().def_id(); + let import_ids = self.find_transitive_imports(&trait_binding.kind, *trait_name); + found_traits.push(TraitCandidate { def_id, import_ids }); + } + } + } - for &(trait_name, binding) in traits.as_ref().unwrap().iter() { - // Traits have pseudo-modules that can be used to search for the given ident. - if let Some(module) = binding.module() { - let mut ident = ident; - if ident.span.glob_adjust(module.expansion, binding.span).is_none() { - continue; - } - if self - .resolve_ident_in_module_unadjusted( - ModuleOrUniformRoot::Module(module), - ident, - ns, - parent_scope, - false, - module.span, - ) - .is_ok() - { - let import_ids = self.find_transitive_imports(&binding.kind, trait_name); - let trait_def_id = module.def_id().unwrap(); - found_traits.push(TraitCandidate { def_id: trait_def_id, import_ids }); - } - } else if let Res::Def(DefKind::TraitAlias, _) = binding.res() { - // For now, just treat all trait aliases as possible candidates, since we don't - // know if the ident is somewhere in the transitive bounds. - let import_ids = self.find_transitive_imports(&binding.kind, trait_name); - let trait_def_id = binding.res().def_id(); - found_traits.push(TraitCandidate { def_id: trait_def_id, import_ids }); - } else { - bug!("candidate is not trait or trait alias?") + // List of traits in scope is pruned on best effort basis. We reject traits not having an + // associated item with the given name and namespace (if specified). This is a conservative + // optimization, proper hygienic type-based resolution of associated items is done in typeck. + // We don't reject trait aliases (`trait_module == None`) because we don't have access to their + // associated items. + fn trait_may_have_item( + &mut self, + trait_module: Option>, + assoc_item: Option<(Symbol, Namespace)>, + ) -> bool { + match (trait_module, assoc_item) { + (Some(trait_module), Some((name, ns))) => { + self.resolutions(trait_module).borrow().iter().any(|resolution| { + let (&BindingKey { ident: assoc_ident, ns: assoc_ns, .. }, _) = resolution; + assoc_ns == ns && assoc_ident.name == name + }) } + _ => true, } } @@ -3227,34 +3254,6 @@ impl<'a> Resolver<'a> { }) } - /// This is equivalent to `get_traits_in_module_containing_item`, but without filtering by the associated item. - /// - /// This is used by rustdoc for intra-doc links. - pub fn traits_in_scope(&mut self, module_id: DefId) -> Vec { - let module = self.get_module(module_id); - module.ensure_traits(self); - let traits = module.traits.borrow(); - let to_candidate = - |this: &mut Self, &(trait_name, binding): &(Ident, &NameBinding<'_>)| TraitCandidate { - def_id: binding.res().def_id(), - import_ids: this.find_transitive_imports(&binding.kind, trait_name), - }; - - let mut candidates: Vec<_> = - traits.as_ref().unwrap().iter().map(|x| to_candidate(self, x)).collect(); - - if let Some(prelude) = self.prelude { - if !module.no_implicit_prelude { - prelude.ensure_traits(self); - candidates.extend( - prelude.traits.borrow().as_ref().unwrap().iter().map(|x| to_candidate(self, x)), - ); - } - } - - candidates - } - /// Rustdoc uses this to resolve things in a recoverable way. `ResolutionError<'a>` /// isn't something that can be returned because it can't be made to live that long, /// and also it's a private type. Fortunately rustdoc doesn't need to know the error, diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 5c74094ecd3ee..5d6120cd31076 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -757,7 +757,11 @@ impl<'a> Resolver<'a> { } Scope::BuiltinAttrs => { if is_builtin_attr_name(ident.name) { - ok(Res::NonMacroAttr(NonMacroAttrKind::Builtin), DUMMY_SP, this.arenas) + ok( + Res::NonMacroAttr(NonMacroAttrKind::Builtin(ident.name)), + DUMMY_SP, + this.arenas, + ) } else { Err(Determinacy::Determined) } @@ -810,13 +814,15 @@ impl<'a> Resolver<'a> { // Found another solution, if the first one was "weak", report an error. let (res, innermost_res) = (binding.res(), innermost_binding.res()); if res != innermost_res { - let builtin = Res::NonMacroAttr(NonMacroAttrKind::Builtin); + let is_builtin = |res| { + matches!(res, Res::NonMacroAttr(NonMacroAttrKind::Builtin(..))) + }; let derive_helper_compat = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat); let ambiguity_error_kind = if is_import { Some(AmbiguityKind::Import) - } else if innermost_res == builtin || res == builtin { + } else if is_builtin(innermost_res) || is_builtin(res) { Some(AmbiguityKind::BuiltinAttr) } else if innermost_res == derive_helper_compat || res == derive_helper_compat 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 795cf2e19decc..e78ccb3521914 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -589,23 +589,23 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if let Some(typeck_results) = self.in_progress_typeck_results { let typeck_results = typeck_results.borrow(); match (found_kind, typeck_results.closure_kind_origins().get(hir_id)) { - (ty::ClosureKind::FnOnce, Some((span, name))) => { + (ty::ClosureKind::FnOnce, Some((span, place))) => { err.span_label( *span, format!( "closure is `FnOnce` because it moves the \ variable `{}` out of its environment", - name + ty::place_to_string_for_capture(tcx, place) ), ); } - (ty::ClosureKind::FnMut, Some((span, name))) => { + (ty::ClosureKind::FnMut, Some((span, place))) => { err.span_label( *span, format!( "closure is `FnMut` because it mutates the \ variable `{}` here", - name + ty::place_to_string_for_capture(tcx, place) ), ); } diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index 0036edda36da5..d37d6bc4f2df6 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -365,12 +365,10 @@ fn check_region_bounds_on_impl_item<'tcx>( let item_kind = assoc_item_kind_str(impl_m); let def_span = tcx.sess.source_map().guess_head_span(span); let span = tcx.hir().get_generics(impl_m.def_id).map_or(def_span, |g| g.span); - let generics_span = if let Some(sp) = tcx.hir().span_if_local(trait_m.def_id) { + let generics_span = tcx.hir().span_if_local(trait_m.def_id).map(|sp| { let def_sp = tcx.sess.source_map().guess_head_span(sp); - Some(tcx.hir().get_generics(trait_m.def_id).map_or(def_sp, |g| g.span)) - } else { - None - }; + tcx.hir().get_generics(trait_m.def_id).map_or(def_sp, |g| g.span) + }); tcx.sess.emit_err(LifetimesOrBoundsMismatchOnTrait { span, diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index e8cbefd44ee6d..feda35daa617d 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -176,7 +176,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.demand_eqtype(span, inferred_kind.to_ty(self.tcx), closure_kind_ty); // If we have an origin, store it. - if let Some(origin) = delegate.current_origin { + if let Some(origin) = delegate.current_origin.clone() { + let origin = if self.tcx.features().capture_disjoint_fields { + origin + } else { + // FIXME(project-rfc-2229#26): Once rust-lang#80092 is merged, we should restrict the + // precision of origin as well. Otherwise, this will cause issues when project-rfc-2229#26 + // is fixed as we might see Index projections in the origin, which we can't print because + // we don't store enough information. + (origin.0, Place { projections: vec![], ..origin.1 }) + }; + self.typeck_results .borrow_mut() .closure_kind_origins_mut() @@ -563,7 +573,7 @@ struct InferBorrowKind<'a, 'tcx> { // If we modified `current_closure_kind`, this field contains a `Some()` with the // variable access that caused us to do so. - current_origin: Option<(Span, Symbol)>, + current_origin: Option<(Span, Place<'tcx>)>, /// For each Place that is captured by the closure, we track the minimal kind of /// access we need (ref, ref mut, move, etc) and the expression that resulted in such access. @@ -628,7 +638,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { upvar_id.closure_expr_id, ty::ClosureKind::FnOnce, usage_span, - var_name(tcx, upvar_id.var_path.hir_id), + place_with_id.place.clone(), ); let capture_info = ty::CaptureInfo { @@ -720,7 +730,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { upvar_id.closure_expr_id, ty::ClosureKind::FnMut, tcx.hir().span(diag_expr_id), - var_name(tcx, upvar_id.var_path.hir_id), + place_with_id.place.clone(), ); } } @@ -765,11 +775,11 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { closure_id: LocalDefId, new_kind: ty::ClosureKind, upvar_span: Span, - var_name: Symbol, + place: Place<'tcx>, ) { debug!( - "adjust_closure_kind(closure_id={:?}, new_kind={:?}, upvar_span={:?}, var_name={})", - closure_id, new_kind, upvar_span, var_name + "adjust_closure_kind(closure_id={:?}, new_kind={:?}, upvar_span={:?}, place={:?})", + closure_id, new_kind, upvar_span, place ); // Is this the closure whose kind is currently being inferred? @@ -797,7 +807,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { | (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { // new kind is stronger than the old kind self.current_closure_kind = new_kind; - self.current_origin = Some((upvar_span, var_name)); + self.current_origin = Some((upvar_span, place)); } } } diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index 7c9cfe69fc94b..6edce62f76bc9 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -384,9 +384,11 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); let common_hir_owner = fcx_typeck_results.hir_owner; - for (&id, &origin) in fcx_typeck_results.closure_kind_origins().iter() { - let hir_id = hir::HirId { owner: common_hir_owner, local_id: id }; - self.typeck_results.closure_kind_origins_mut().insert(hir_id, origin); + for (id, origin) in fcx_typeck_results.closure_kind_origins().iter() { + let hir_id = hir::HirId { owner: common_hir_owner, local_id: *id }; + let place_span = origin.0; + let place = self.resolve(origin.1.clone(), &place_span); + self.typeck_results.closure_kind_origins_mut().insert(hir_id, (place_span, place)); } } diff --git a/config.toml.example b/config.toml.example index 9e08ce9b27e0c..55b20adabd045 100644 --- a/config.toml.example +++ b/config.toml.example @@ -35,9 +35,11 @@ changelog-seen = 2 # Unless you're developing for a target where Rust CI doesn't build a compiler # toolchain or changing LLVM locally, you probably want to set this to true. # -# It's currently false by default due to being newly added; please file bugs if -# enabling this did not work for you on x86_64-unknown-linux-gnu. -# Other target triples are currently not supported; see #77084. +# This is false by default so that distributions don't unexpectedly download +# LLVM from the internet. +# +# All tier 1 targets are currently supported; set this to `"if-supported"` if +# you are not sure whether you're on a tier 1 target. # # We also currently only support this when building LLVM for the build triple. # diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index 220c98b294cef..928c6f9a3a88d 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -184,7 +184,7 @@ impl NodeRef { /// Removes the internal root node, using its first child as the new root node. /// As it is intended only to be called when the root node has only one child, - /// no cleanup is done on any of the other children. + /// no cleanup is done on any of the keys, values and other children. /// This decreases the height by 1 and is the opposite of `push_internal_level`. /// /// Requires exclusive access to the `Root` object but not to the root node; @@ -225,7 +225,7 @@ impl NodeRef { /// - When this is `Owned`, the `NodeRef` acts roughly like `Box`, /// but does not have a destructor, and must be cleaned up manually. /// Since any `NodeRef` allows navigating through the tree, `BorrowType` -/// effectively applies to the entire tree, not just the node itself. +/// effectively applies to the entire tree, not just to the node itself. /// - `K` and `V`: These are the types of keys and values stored in the nodes. /// - `Type`: This can be `Leaf`, `Internal`, or `LeafOrInternal`. When this is /// `Leaf`, the `NodeRef` points to a leaf node, when this is `Internal` the @@ -425,7 +425,7 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { impl NodeRef { /// Similar to `ascend`, gets a reference to a node's parent node, but also - /// deallocate the current node in the process. This is unsafe because the + /// deallocates the current node in the process. This is unsafe because the /// current node will still be accessible despite being deallocated. pub unsafe fn deallocate_and_ascend( self, @@ -661,7 +661,10 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { /// Removes a key-value pair from the end of the node and returns the pair. /// Also removes the edge that was to the right of that pair and, if the node /// is internal, returns the orphaned subtree that this edge owned. - fn pop(&mut self) -> (K, V, Option>) { + /// + /// # Safety + /// The node must not be empty. + unsafe fn pop(&mut self) -> (K, V, Option>) { debug_assert!(self.len() > 0); let idx = self.len() - 1; diff --git a/library/alloc/src/collections/btree/search.rs b/library/alloc/src/collections/btree/search.rs index ed7f95fe632fa..efe94ef175ce7 100644 --- a/library/alloc/src/collections/btree/search.rs +++ b/library/alloc/src/collections/btree/search.rs @@ -12,8 +12,7 @@ pub enum SearchResult { /// Looks up a given key in a (sub)tree headed by the given node, recursively. /// Returns a `Found` with the handle of the matching KV, if any. Otherwise, -/// returns a `GoDown` with the handle of the possible leaf edge where the key -/// belongs. +/// returns a `GoDown` with the handle of the leaf edge where the key belongs. /// /// The result is meaningful only if the tree is ordered by key, like the tree /// in a `BTreeMap` is. diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index d0bfa038aa13d..14a10aac061a4 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -140,6 +140,7 @@ #![feature(type_alias_impl_trait)] #![feature(associated_type_bounds)] #![feature(slice_group_by)] +#![feature(decl_macro)] // Allow testing this library #[cfg(test)] @@ -193,4 +194,11 @@ mod std { #[unstable(feature = "liballoc_internals", issue = "none", reason = "implementation detail")] pub mod __export { pub use core::format_args; + + /// Force AST node to an expression to improve diagnostics in pattern position. + #[rustc_macro_transparency = "semitransparent"] + #[unstable(feature = "liballoc_internals", issue = "none", reason = "implementation detail")] + pub macro force_expr($e:expr) { + $e + } } diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs index 7d4eff6185dbe..3a46763c3f608 100644 --- a/library/alloc/src/macros.rs +++ b/library/alloc/src/macros.rs @@ -37,16 +37,16 @@ #[cfg(not(test))] #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] -#[allow_internal_unstable(box_syntax)] +#[allow_internal_unstable(box_syntax, liballoc_internals)] macro_rules! vec { () => ( - $crate::vec::Vec::new() + $crate::__export::force_expr!($crate::vec::Vec::new()) ); ($elem:expr; $n:expr) => ( - $crate::vec::from_elem($elem, $n) + $crate::__export::force_expr!($crate::vec::from_elem($elem, $n)) ); ($($x:expr),+ $(,)?) => ( - <[_]>::into_vec(box [$($x),+]) + $crate::__export::force_expr!(<[_]>::into_vec(box [$($x),+])) ); } diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index ba8918b192fa3..111feb7dbec69 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -286,3 +286,43 @@ nonzero_integers_div! { NonZeroU128(u128); NonZeroUsize(usize); } + +macro_rules! nonzero_unsigned_is_power_of_two { + ( $( $Ty: ident )+ ) => { + $( + impl $Ty { + + /// Returns `true` if and only if `self == (1 << k)` for some `k`. + /// + /// On many architectures, this function can perform better than `is_power_of_two()` + /// on the underlying integer type, as special handling of zero can be avoided. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(nonzero_is_power_of_two)] + /// + #[doc = concat!("let eight = std::num::", stringify!($Ty), "::new(8).unwrap();")] + /// assert!(eight.is_power_of_two()); + #[doc = concat!("let ten = std::num::", stringify!($Ty), "::new(10).unwrap();")] + /// assert!(!ten.is_power_of_two()); + /// ``` + #[unstable(feature = "nonzero_is_power_of_two", issue = "81106")] + #[inline] + pub const fn is_power_of_two(self) -> bool { + // LLVM 11 normalizes `unchecked_sub(x, 1) & x == 0` to the implementation seen here. + // On the basic x86-64 target, this saves 3 instructions for the zero check. + // On x86_64 with BMI1, being nonzero lets it codegen to `BLSR`, which saves an instruction + // compared to the `POPCNT` implementation on the underlying integer type. + + intrinsics::ctpop(self.get()) < 2 + } + + } + )+ + } +} + +nonzero_unsigned_is_power_of_two! { NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroU128 NonZeroUsize } diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs index 16c18d6e14645..8bae3da1273eb 100644 --- a/library/std/src/io/buffered/bufreader.rs +++ b/library/std/src/io/buffered/bufreader.rs @@ -271,6 +271,20 @@ impl Read for BufReader { Ok(nread) } + // Small read_exacts from a BufReader are extremely common when used with a deserializer. + // The default implementation calls read in a loop, which results in surprisingly poor code + // generation for the common path where the buffer has enough bytes to fill the passed-in + // buffer. + fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { + if self.buffer().len() >= buf.len() { + buf.copy_from_slice(&self.buffer()[..buf.len()]); + self.consume(buf.len()); + return Ok(()); + } + + crate::io::default_read_exact(self, buf) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { let total_len = bufs.iter().map(|b| b.len()).sum::(); if self.pos == self.cap && total_len >= self.buf.len() { diff --git a/library/std/src/io/buffered/tests.rs b/library/std/src/io/buffered/tests.rs index 66a64f667baa4..f6c2b499567ab 100644 --- a/library/std/src/io/buffered/tests.rs +++ b/library/std/src/io/buffered/tests.rs @@ -443,6 +443,18 @@ fn bench_buffered_reader(b: &mut test::Bencher) { b.iter(|| BufReader::new(io::empty())); } +#[bench] +fn bench_buffered_reader_small_reads(b: &mut test::Bencher) { + let data = (0..u8::MAX).cycle().take(1024 * 4).collect::>(); + b.iter(|| { + let mut reader = BufReader::new(&data[..]); + let mut buf = [0u8; 4]; + for _ in 0..1024 { + reader.read_exact(&mut buf).unwrap(); + } + }); +} + #[bench] fn bench_buffered_writer(b: &mut test::Bencher) { b.iter(|| BufWriter::new(io::sink())); diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 3f5b7c0b29be6..c87a56586c65e 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -416,6 +416,25 @@ where write(buf) } +pub(crate) fn default_read_exact(this: &mut R, mut buf: &mut [u8]) -> Result<()> { + while !buf.is_empty() { + match this.read(buf) { + Ok(0) => break, + Ok(n) => { + let tmp = buf; + buf = &mut tmp[n..]; + } + Err(ref e) if e.kind() == ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } + } + if !buf.is_empty() { + Err(Error::new(ErrorKind::UnexpectedEof, "failed to fill whole buffer")) + } else { + Ok(()) + } +} + /// The `Read` trait allows for reading bytes from a source. /// /// Implementors of the `Read` trait are called 'readers'. @@ -766,23 +785,8 @@ pub trait Read { /// } /// ``` #[stable(feature = "read_exact", since = "1.6.0")] - fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<()> { - while !buf.is_empty() { - match self.read(buf) { - Ok(0) => break, - Ok(n) => { - let tmp = buf; - buf = &mut tmp[n..]; - } - Err(ref e) if e.kind() == ErrorKind::Interrupted => {} - Err(e) => return Err(e), - } - } - if !buf.is_empty() { - Err(Error::new(ErrorKind::UnexpectedEof, "failed to fill whole buffer")) - } else { - Ok(()) - } + fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> { + default_read_exact(self, buf) } /// Creates a "by reference" adaptor for this instance of `Read`. diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 6d2d7bbbef92c..5350c9eefe753 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -465,8 +465,21 @@ def download_stage0(self): def downloading_llvm(self): opt = self.get_toml('download-ci-llvm', 'llvm') + # This is currently all tier 1 targets (since others may not have CI + # artifacts) + # https://doc.rust-lang.org/rustc/platform-support.html#tier-1 + supported_platforms = [ + "aarch64-unknown-linux-gnu", + "i686-pc-windows-gnu", + "i686-pc-windows-msvc", + "i686-unknown-linux-gnu", + "x86_64-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-pc-windows-gnu", + "x86_64-pc-windows-msvc", + ] return opt == "true" \ - or (opt == "if-available" and self.build == "x86_64-unknown-linux-gnu") + or (opt == "if-available" and self.build in supported_platforms) def _download_stage0_helper(self, filename, pattern, tarball_suffix, date=None): if date is None: diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 72a979338a549..c19bb536ce83c 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -73,7 +73,7 @@ impl Step for Std { fn run(self, builder: &Builder<'_>) { let target = self.target; - let compiler = builder.compiler(0, builder.config.build); + let compiler = builder.compiler(builder.top_stage, builder.config.build); let mut cargo = builder.cargo( compiler, @@ -84,7 +84,10 @@ impl Step for Std { ); std_cargo(builder, target, compiler.stage, &mut cargo); - builder.info(&format!("Checking std artifacts ({} -> {})", &compiler.host, target)); + builder.info(&format!( + "Checking stage{} std artifacts ({} -> {})", + builder.top_stage, &compiler.host, target + )); run_cargo( builder, cargo, @@ -94,9 +97,13 @@ impl Step for Std { true, ); - let libdir = builder.sysroot_libdir(compiler, target); - let hostdir = builder.sysroot_libdir(compiler, compiler.host); - add_to_sysroot(&builder, &libdir, &hostdir, &libstd_stamp(builder, compiler, target)); + // We skip populating the sysroot in non-zero stage because that'll lead + // to rlib/rmeta conflicts if std gets built during this session. + if compiler.stage == 0 { + let libdir = builder.sysroot_libdir(compiler, target); + let hostdir = builder.sysroot_libdir(compiler, compiler.host); + add_to_sysroot(&builder, &libdir, &hostdir, &libstd_stamp(builder, compiler, target)); + } // Then run cargo again, once we've put the rmeta files for the library // crates into the sysroot. This is needed because e.g., core's tests @@ -124,8 +131,8 @@ impl Step for Std { } builder.info(&format!( - "Checking std test/bench/example targets ({} -> {})", - &compiler.host, target + "Checking stage{} std test/bench/example targets ({} -> {})", + builder.top_stage, &compiler.host, target )); run_cargo( builder, @@ -163,10 +170,20 @@ impl Step for Rustc { /// the `compiler` targeting the `target` architecture. The artifacts /// created will also be linked into the sysroot directory. fn run(self, builder: &Builder<'_>) { - let compiler = builder.compiler(0, builder.config.build); + let compiler = builder.compiler(builder.top_stage, builder.config.build); let target = self.target; - builder.ensure(Std { target }); + if compiler.stage != 0 { + // If we're not in stage 0, then we won't have a std from the beta + // compiler around. That means we need to make sure there's one in + // the sysroot for the compiler to find. Otherwise, we're going to + // fail when building crates that need to generate code (e.g., build + // scripts and their dependencies). + builder.ensure(crate::compile::Std { target: compiler.host, compiler }); + builder.ensure(crate::compile::Std { target, compiler }); + } else { + builder.ensure(Std { target }); + } let mut cargo = builder.cargo( compiler, @@ -187,7 +204,10 @@ impl Step for Rustc { cargo.arg("-p").arg(krate.name); } - builder.info(&format!("Checking compiler artifacts ({} -> {})", &compiler.host, target)); + builder.info(&format!( + "Checking stage{} compiler artifacts ({} -> {})", + builder.top_stage, &compiler.host, target + )); run_cargo( builder, cargo, @@ -225,7 +245,7 @@ impl Step for CodegenBackend { } fn run(self, builder: &Builder<'_>) { - let compiler = builder.compiler(0, builder.config.build); + let compiler = builder.compiler(builder.top_stage, builder.config.build); let target = self.target; let backend = self.backend; @@ -244,8 +264,8 @@ impl Step for CodegenBackend { rustc_cargo_env(builder, &mut cargo, target); builder.info(&format!( - "Checking {} artifacts ({} -> {})", - backend, &compiler.host.triple, target.triple + "Checking stage{} {} artifacts ({} -> {})", + builder.top_stage, backend, &compiler.host.triple, target.triple )); run_cargo( @@ -280,7 +300,7 @@ macro_rules! tool_check_step { } fn run(self, builder: &Builder<'_>) { - let compiler = builder.compiler(0, builder.config.build); + let compiler = builder.compiler(builder.top_stage, builder.config.build); let target = self.target; builder.ensure(Rustc { target }); @@ -301,7 +321,8 @@ macro_rules! tool_check_step { } builder.info(&format!( - "Checking {} artifacts ({} -> {})", + "Checking stage{} {} artifacts ({} -> {})", + builder.top_stage, stringify!($name).to_lowercase(), &compiler.host.triple, target.triple diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index f4d89a89c1467..ec1308ab82b51 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -377,6 +377,7 @@ struct Build { configure_args: Option>, local_rebuild: Option, print_step_timings: Option, + check_stage: Option, doc_stage: Option, build_stage: Option, test_stage: Option, @@ -676,6 +677,7 @@ impl Config { // See https://github.com/rust-lang/compiler-team/issues/326 config.stage = match config.cmd { + Subcommand::Check { .. } => flags.stage.or(build.check_stage).unwrap_or(0), Subcommand::Doc { .. } => flags.stage.or(build.doc_stage).unwrap_or(0), Subcommand::Build { .. } => flags.stage.or(build.build_stage).unwrap_or(1), Subcommand::Test { .. } => flags.stage.or(build.test_stage).unwrap_or(1), @@ -685,7 +687,6 @@ impl Config { // These are all bootstrap tools, which don't depend on the compiler. // The stage we pass shouldn't matter, but use 0 just in case. Subcommand::Clean { .. } - | Subcommand::Check { .. } | Subcommand::Clippy { .. } | Subcommand::Fix { .. } | Subcommand::Run { .. } @@ -816,8 +817,10 @@ impl Config { check_ci_llvm!(llvm.allow_old_toolchain); check_ci_llvm!(llvm.polly); - // CI-built LLVM is shared - config.llvm_link_shared = true; + // CI-built LLVM can be either dynamic or static. + let ci_llvm = config.out.join(&*config.build.triple).join("ci-llvm"); + let link_type = t!(std::fs::read_to_string(ci_llvm.join("link-type.txt"))); + config.llvm_link_shared = link_type == "dynamic"; } if config.llvm_thin_lto { diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index e2c2e19b0bc17..af9c0fb04bc9d 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1800,19 +1800,11 @@ fn add_env(builder: &Builder<'_>, cmd: &mut Command, target: TargetSelection) { } } -/// Maybe add libLLVM.so to the given destination lib-dir. It will only have -/// been built if LLVM tools are linked dynamically. +/// Maybe add LLVM object files to the given destination lib-dir. Allows either static or dynamic linking. /// -/// Note: This function does not yet support Windows, but we also don't support -/// linking LLVM tools dynamically on Windows yet. -fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir: &Path) { - if !builder.config.llvm_link_shared { - // We do not need to copy LLVM files into the sysroot if it is not - // dynamically linked; it is already included into librustc_llvm - // statically. - return; - } +/// Returns whether the files were actually copied. +fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir: &Path) -> bool { if let Some(config) = builder.config.target_config.get(&target) { if config.llvm_config.is_some() && !builder.config.llvm_from_ci { // If the LLVM was externally provided, then we don't currently copy @@ -1828,7 +1820,7 @@ fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir // // If the LLVM is coming from ourselves (just from CI) though, we // still want to install it, as it otherwise won't be available. - return; + return false; } } @@ -1837,31 +1829,48 @@ fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir // clear why this is the case, though. llvm-config will emit the versioned // paths and we don't want those in the sysroot (as we're expecting // unversioned paths). - if target.contains("apple-darwin") { + if target.contains("apple-darwin") && builder.config.llvm_link_shared { let src_libdir = builder.llvm_out(target).join("lib"); let llvm_dylib_path = src_libdir.join("libLLVM.dylib"); if llvm_dylib_path.exists() { builder.install(&llvm_dylib_path, dst_libdir, 0o644); } + !builder.config.dry_run } else if let Ok(llvm_config) = crate::native::prebuilt_llvm_config(builder, target) { - let files = output(Command::new(llvm_config).arg("--libfiles")); - for file in files.lines() { + let mut cmd = Command::new(llvm_config); + cmd.arg("--libfiles"); + builder.verbose(&format!("running {:?}", cmd)); + let files = output(&mut cmd); + for file in files.trim_end().split(' ') { builder.install(Path::new(file), dst_libdir, 0o644); } + !builder.config.dry_run + } else { + false } } /// Maybe add libLLVM.so to the target lib-dir for linking. pub fn maybe_install_llvm_target(builder: &Builder<'_>, target: TargetSelection, sysroot: &Path) { let dst_libdir = sysroot.join("lib/rustlib").join(&*target.triple).join("lib"); - maybe_install_llvm(builder, target, &dst_libdir); + // We do not need to copy LLVM files into the sysroot if it is not + // dynamically linked; it is already included into librustc_llvm + // statically. + if builder.config.llvm_link_shared { + maybe_install_llvm(builder, target, &dst_libdir); + } } /// Maybe add libLLVM.so to the runtime lib-dir for rustc itself. pub fn maybe_install_llvm_runtime(builder: &Builder<'_>, target: TargetSelection, sysroot: &Path) { let dst_libdir = sysroot.join(builder.sysroot_libdir_relative(Compiler { stage: 1, host: target })); - maybe_install_llvm(builder, target, &dst_libdir); + // We do not need to copy LLVM files into the sysroot if it is not + // dynamically linked; it is already included into librustc_llvm + // statically. + if builder.config.llvm_link_shared { + maybe_install_llvm(builder, target, &dst_libdir); + } } #[derive(Clone, Debug, Eq, Hash, PartialEq)] @@ -1973,7 +1982,10 @@ impl Step for RustDev { // `$ORIGIN/../lib` can find it. It may also be used as a dependency // of `rustc-dev` to support the inherited `-lLLVM` when using the // compiler libraries. - maybe_install_llvm(builder, target, &tarball.image_dir().join("lib")); + let dst_libdir = tarball.image_dir().join("lib"); + maybe_install_llvm(builder, target, &dst_libdir); + let link_type = if builder.config.llvm_link_shared { "dynamic" } else { "static" }; + t!(std::fs::write(tarball.image_dir().join("link-type.txt"), link_type), dst_libdir); Some(tarball.generate()) } diff --git a/src/bootstrap/download-ci-llvm-stamp b/src/bootstrap/download-ci-llvm-stamp index b29ecd65401df..fb5b058cb4d74 100644 --- a/src/bootstrap/download-ci-llvm-stamp +++ b/src/bootstrap/download-ci-llvm-stamp @@ -1,4 +1,4 @@ Change this file to make users of the `download-ci-llvm` configuration download a new version of LLVM from CI, even if the LLVM submodule hasn’t changed. -Last change is for: https://github.com/rust-lang/rust/pull/80087 +Last change is for: https://github.com/rust-lang/rust/pull/80932 diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index d6a45f1c17076..55062e11e029a 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -614,14 +614,10 @@ Arguments: }; if let Subcommand::Check { .. } = &cmd { - if matches.opt_str("stage").is_some() { - println!("--stage not supported for x.py check, always treated as stage 0"); - process::exit(1); - } if matches.opt_str("keep-stage").is_some() || matches.opt_str("keep-stage-std").is_some() { - println!("--keep-stage not supported for x.py check, only one stage available"); + println!("--keep-stage not yet supported for x.py check"); process::exit(1); } } diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 6412df3fd904e..609ac8b366952 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -171,7 +171,6 @@ impl Step for Llvm { .define("LLVM_TARGETS_TO_BUILD", llvm_targets) .define("LLVM_EXPERIMENTAL_TARGETS_TO_BUILD", llvm_exp_targets) .define("LLVM_INCLUDE_EXAMPLES", "OFF") - .define("LLVM_INCLUDE_TESTS", "OFF") .define("LLVM_INCLUDE_DOCS", "OFF") .define("LLVM_INCLUDE_BENCHMARKS", "OFF") .define("LLVM_ENABLE_TERMINFO", "OFF") diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 708d7710058d5..280984088a94e 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -19,7 +19,7 @@ use rustc_session::lint::{ builtin::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS}, Lint, }; -use rustc_span::hygiene::MacroKind; +use rustc_span::hygiene::{MacroKind, SyntaxContext}; use rustc_span::symbol::Ident; use rustc_span::symbol::Symbol; use rustc_span::DUMMY_SP; @@ -770,7 +770,12 @@ fn traits_implemented_by(cx: &DocContext<'_>, type_: DefId, module: DefId) -> Fx let mut cache = cx.module_trait_cache.borrow_mut(); let in_scope_traits = cache.entry(module).or_insert_with(|| { cx.enter_resolver(|resolver| { - resolver.traits_in_scope(module).into_iter().map(|candidate| candidate.def_id).collect() + let parent_scope = &ParentScope::module(resolver.get_module(module), resolver); + resolver + .traits_in_scope(None, parent_scope, SyntaxContext::root(), None) + .into_iter() + .map(|candidate| candidate.def_id) + .collect() }) }); diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-multi-variant-diagnostics.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-multi-variant-diagnostics.rs new file mode 100644 index 0000000000000..2916d8c794f22 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-multi-variant-diagnostics.rs @@ -0,0 +1,31 @@ +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +//~| `#[warn(incomplete_features)]` on by default +//~| see issue #53488 + +// Check that precise paths are being reported back in the error message. + + +enum MultiVariant { + Point(i32, i32), + Meta(i32) +} + +fn main() { + let mut point = MultiVariant::Point(10, -10,); + + let mut meta = MultiVariant::Meta(1); + + let c = || { + if let MultiVariant::Point(ref mut x, _) = point { + *x += 1; + } + + if let MultiVariant::Meta(ref mut v) = meta { + *v += 1; + } + }; + + let a = c; + let b = c; //~ ERROR use of moved value: `c` [E0382] +} diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-multi-variant-diagnostics.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-multi-variant-diagnostics.stderr new file mode 100644 index 0000000000000..de0bfe3bd769f --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-multi-variant-diagnostics.stderr @@ -0,0 +1,26 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/closure-origin-multi-variant-diagnostics.rs:1:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error[E0382]: use of moved value: `c` + --> $DIR/closure-origin-multi-variant-diagnostics.rs:30:13 + | +LL | let a = c; + | - value moved here +LL | let b = c; + | ^ value used here after move + | +note: closure cannot be moved more than once as it is not `Copy` due to moving the variable `point.0` out of its environment + --> $DIR/closure-origin-multi-variant-diagnostics.rs:20:52 + | +LL | if let MultiVariant::Point(ref mut x, _) = point { + | ^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.rs new file mode 100644 index 0000000000000..8486f03f2eb8e --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.rs @@ -0,0 +1,26 @@ +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +//~| `#[warn(incomplete_features)]` on by default +//~| see issue #53488 + +// Check that precise paths are being reported back in the error message. + +enum SingleVariant { + Point(i32, i32), +} + +fn main() { + let mut point = SingleVariant::Point(10, -10); + + let c = || { + // FIXME(project-rfc-2229#24): Change this to be a destructure pattern + // once this is fixed, to remove the warning. + if let SingleVariant::Point(ref mut x, _) = point { + //~^ WARNING: irrefutable if-let pattern + *x += 1; + } + }; + + let b = c; + let a = c; //~ ERROR use of moved value: `c` [E0382] +} diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.stderr new file mode 100644 index 0000000000000..ad66f6d7ffcaa --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.stderr @@ -0,0 +1,37 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/closure-origin-single-variant-diagnostics.rs:1:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +warning: irrefutable if-let pattern + --> $DIR/closure-origin-single-variant-diagnostics.rs:18:9 + | +LL | / if let SingleVariant::Point(ref mut x, _) = point { +LL | | +LL | | *x += 1; +LL | | } + | |_________^ + | + = note: `#[warn(irrefutable_let_patterns)]` on by default + +error[E0382]: use of moved value: `c` + --> $DIR/closure-origin-single-variant-diagnostics.rs:25:13 + | +LL | let b = c; + | - value moved here +LL | let a = c; + | ^ value used here after move + | +note: closure cannot be moved more than once as it is not `Copy` due to moving the variable `point.0` out of its environment + --> $DIR/closure-origin-single-variant-diagnostics.rs:18:53 + | +LL | if let SingleVariant::Point(ref mut x, _) = point { + | ^^^^^ + +error: aborting due to previous error; 2 warnings emitted + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-struct-diagnostics.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-struct-diagnostics.rs new file mode 100644 index 0000000000000..103890f1f3537 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-struct-diagnostics.rs @@ -0,0 +1,25 @@ +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +//~| `#[warn(incomplete_features)]` on by default +//~| see issue #53488 + +// Check that precise paths are being reported back in the error message. + +struct Y { + y: X +} + +struct X { + a: u32, + b: u32, +} + +fn main() { + let mut x = Y { y: X { a: 5, b: 0 } }; + let hello = || { + x.y.a += 1; + }; + + let b = hello; + let c = hello; //~ ERROR use of moved value: `hello` [E0382] +} diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-struct-diagnostics.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-struct-diagnostics.stderr new file mode 100644 index 0000000000000..474d77b7cd208 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-struct-diagnostics.stderr @@ -0,0 +1,26 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/closure-origin-struct-diagnostics.rs:1:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error[E0382]: use of moved value: `hello` + --> $DIR/closure-origin-struct-diagnostics.rs:24:13 + | +LL | let b = hello; + | ----- value moved here +LL | let c = hello; + | ^^^^^ value used here after move + | +note: closure cannot be moved more than once as it is not `Copy` due to moving the variable `x.y.a` out of its environment + --> $DIR/closure-origin-struct-diagnostics.rs:20:9 + | +LL | x.y.a += 1; + | ^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics-1.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics-1.rs new file mode 100644 index 0000000000000..6b078d2329c2f --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics-1.rs @@ -0,0 +1,16 @@ +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +//~| `#[warn(incomplete_features)]` on by default +//~| see issue #53488 + +// Check that precise paths are being reported back in the error message. + +fn main() { + let mut x = (5, 0); + let hello = || { + x.0 += 1; + }; + + let b = hello; + let c = hello; //~ ERROR use of moved value: `hello` [E0382] +} diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics-1.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics-1.stderr new file mode 100644 index 0000000000000..716728e96ecbb --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics-1.stderr @@ -0,0 +1,26 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/closure-origin-tuple-diagnostics-1.rs:1:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error[E0382]: use of moved value: `hello` + --> $DIR/closure-origin-tuple-diagnostics-1.rs:15:13 + | +LL | let b = hello; + | ----- value moved here +LL | let c = hello; + | ^^^^^ value used here after move + | +note: closure cannot be moved more than once as it is not `Copy` due to moving the variable `x.0` out of its environment + --> $DIR/closure-origin-tuple-diagnostics-1.rs:11:9 + | +LL | x.0 += 1; + | ^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics.rs new file mode 100644 index 0000000000000..0638db607690f --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics.rs @@ -0,0 +1,15 @@ +#![feature(capture_disjoint_fields)] +//~^ WARNING: the feature `capture_disjoint_fields` is incomplete +//~| `#[warn(incomplete_features)]` on by default +//~| see issue #53488 +struct S(String, String); + +fn expect_fn(_f: F) {} + +fn main() { + let s = S(format!("s"), format!("s")); + let c = || { //~ ERROR expected a closure that implements the `Fn` + let s = s.1; + }; + expect_fn(c); +} diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics.stderr new file mode 100644 index 0000000000000..77eb2a94ffb4d --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-tuple-diagnostics.stderr @@ -0,0 +1,23 @@ +warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/closure-origin-tuple-diagnostics.rs:1:12 + | +LL | #![feature(capture_disjoint_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #53488 for more information + +error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce` + --> $DIR/closure-origin-tuple-diagnostics.rs:11:13 + | +LL | let c = || { + | ^^ this closure implements `FnOnce`, not `Fn` +LL | let s = s.1; + | --- closure is `FnOnce` because it moves the variable `s.1` out of its environment +LL | }; +LL | expect_fn(c); + | --------- the requirement to implement `Fn` derives from here + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0525`. diff --git a/src/test/ui/const-generics/late-bound-vars/in_closure.rs b/src/test/ui/const-generics/late-bound-vars/in_closure.rs new file mode 100644 index 0000000000000..0aaeaffb4cb9d --- /dev/null +++ b/src/test/ui/const-generics/late-bound-vars/in_closure.rs @@ -0,0 +1,18 @@ +// run-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +const fn inner<'a>() -> usize where &'a (): Sized { + 3 +} + +fn test<'a>() { + let _ = || { + let _: [u8; inner::<'a>()]; + let _ = [0; inner::<'a>()]; + }; +} + +fn main() { + test(); +} diff --git a/src/test/ui/const-generics/late-bound-vars/simple.rs b/src/test/ui/const-generics/late-bound-vars/simple.rs new file mode 100644 index 0000000000000..2c411a3bdc5f3 --- /dev/null +++ b/src/test/ui/const-generics/late-bound-vars/simple.rs @@ -0,0 +1,16 @@ +// run-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +const fn inner<'a>() -> usize where &'a (): Sized { + 3 +} + +fn test<'a>() { + let _: [u8; inner::<'a>()]; + let _ = [0; inner::<'a>()]; +} + +fn main() { + test(); +} diff --git a/src/test/ui/hygiene/traits-in-scope.rs b/src/test/ui/hygiene/traits-in-scope.rs new file mode 100644 index 0000000000000..548bb226b713c --- /dev/null +++ b/src/test/ui/hygiene/traits-in-scope.rs @@ -0,0 +1,53 @@ +// Macros with def-site hygiene still bring traits into scope. +// It is not clear whether this is desirable behavior or not. +// It is also not clear how to prevent it if it is not desirable. + +// check-pass + +#![feature(decl_macro)] +#![feature(trait_alias)] + +mod traits { + pub trait Trait1 { + fn simple_import(&self) {} + } + pub trait Trait2 { + fn renamed_import(&self) {} + } + pub trait Trait3 { + fn underscore_import(&self) {} + } + pub trait Trait4 { + fn trait_alias(&self) {} + } + + impl Trait1 for () {} + impl Trait2 for () {} + impl Trait3 for () {} + impl Trait4 for () {} +} + +macro m1() { + use traits::Trait1; +} +macro m2() { + use traits::Trait2 as Alias; +} +macro m3() { + use traits::Trait3 as _; +} +macro m4() { + trait Alias = traits::Trait4; +} + +fn main() { + m1!(); + m2!(); + m3!(); + m4!(); + + ().simple_import(); + ().renamed_import(); + ().underscore_import(); + ().trait_alias(); +} diff --git a/src/test/ui/macros/vec-macro-in-pattern.rs b/src/test/ui/macros/vec-macro-in-pattern.rs new file mode 100644 index 0000000000000..ce4298b8bb334 --- /dev/null +++ b/src/test/ui/macros/vec-macro-in-pattern.rs @@ -0,0 +1,10 @@ +// This is a regression test for #61933 +// Verify that the vec![] macro may not be used in patterns +// and that the resulting diagnostic is actually helpful. + +fn main() { + match Some(vec![42]) { + Some(vec![43]) => {} //~ ERROR arbitrary expressions aren't allowed in patterns + _ => {} + } +} diff --git a/src/test/ui/macros/vec-macro-in-pattern.stderr b/src/test/ui/macros/vec-macro-in-pattern.stderr new file mode 100644 index 0000000000000..3dabebfdaa253 --- /dev/null +++ b/src/test/ui/macros/vec-macro-in-pattern.stderr @@ -0,0 +1,10 @@ +error: arbitrary expressions aren't allowed in patterns + --> $DIR/vec-macro-in-pattern.rs:7:14 + | +LL | Some(vec![43]) => {} + | ^^^^^^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + diff --git a/src/test/ui/proc-macro/ambiguous-builtin-attrs.rs b/src/test/ui/proc-macro/ambiguous-builtin-attrs.rs index 142efb3c6cdcf..5f45f6892d2e3 100644 --- a/src/test/ui/proc-macro/ambiguous-builtin-attrs.rs +++ b/src/test/ui/proc-macro/ambiguous-builtin-attrs.rs @@ -1,5 +1,5 @@ +// edition:2018 // aux-build:builtin-attrs.rs - #![feature(decl_macro)] //~ ERROR `feature` is ambiguous extern crate builtin_attrs; @@ -31,3 +31,7 @@ fn main() { Bench; NonExistent; //~ ERROR cannot find value `NonExistent` in this scope } + +use deny as allow; +#[allow(unused)] //~ ERROR `allow` is ambiguous (built-in attribute vs any other name) +fn builtin_renamed() {} diff --git a/src/test/ui/proc-macro/ambiguous-builtin-attrs.stderr b/src/test/ui/proc-macro/ambiguous-builtin-attrs.stderr index 276ee1cfd3562..dfd60dc92cc35 100644 --- a/src/test/ui/proc-macro/ambiguous-builtin-attrs.stderr +++ b/src/test/ui/proc-macro/ambiguous-builtin-attrs.stderr @@ -60,6 +60,20 @@ LL | use builtin_attrs::*; | ^^^^^^^^^^^^^^^^ = help: use `crate::repr` to refer to this attribute macro unambiguously +error[E0659]: `allow` is ambiguous (built-in attribute vs any other name) + --> $DIR/ambiguous-builtin-attrs.rs:36:3 + | +LL | #[allow(unused)] + | ^^^^^ ambiguous name + | + = note: `allow` could refer to a built-in attribute +note: `allow` could also refer to the built-in attribute imported here + --> $DIR/ambiguous-builtin-attrs.rs:35:5 + | +LL | use deny as allow; + | ^^^^^^^^^^^^^ + = help: use `crate::allow` to refer to this built-in attribute unambiguously + error[E0659]: `feature` is ambiguous (built-in attribute vs any other name) --> $DIR/ambiguous-builtin-attrs.rs:3:4 | @@ -80,7 +94,7 @@ error[E0517]: attribute should be applied to a struct, enum, or union LL | fn non_macro_expanded_location<#[repr(C)] T>() { | ^ - not a struct, enum, or union -error: aborting due to 7 previous errors +error: aborting due to 8 previous errors Some errors have detailed explanations: E0425, E0517, E0659. For more information about an error, try `rustc --explain E0425`. diff --git a/src/test/ui/suggestions/vec-macro-in-pattern.fixed b/src/test/ui/suggestions/vec-macro-in-pattern.fixed deleted file mode 100644 index e1695d6820a81..0000000000000 --- a/src/test/ui/suggestions/vec-macro-in-pattern.fixed +++ /dev/null @@ -1,8 +0,0 @@ -// run-rustfix -fn main() { - // everything after `.as_ref` should be suggested - match Some(vec![3]).as_ref().map(|v| v.as_slice()) { - Some([_x]) => (), //~ ERROR unexpected `(` after qualified path - _ => (), - } -} diff --git a/src/test/ui/suggestions/vec-macro-in-pattern.rs b/src/test/ui/suggestions/vec-macro-in-pattern.rs deleted file mode 100644 index 4843629fbcf90..0000000000000 --- a/src/test/ui/suggestions/vec-macro-in-pattern.rs +++ /dev/null @@ -1,8 +0,0 @@ -// run-rustfix -fn main() { - // everything after `.as_ref` should be suggested - match Some(vec![3]).as_ref().map(|v| v.as_slice()) { - Some(vec![_x]) => (), //~ ERROR unexpected `(` after qualified path - _ => (), - } -} diff --git a/src/test/ui/suggestions/vec-macro-in-pattern.stderr b/src/test/ui/suggestions/vec-macro-in-pattern.stderr deleted file mode 100644 index f9d0464ac88b1..0000000000000 --- a/src/test/ui/suggestions/vec-macro-in-pattern.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error: unexpected `(` after qualified path - --> $DIR/vec-macro-in-pattern.rs:5:14 - | -LL | Some(vec![_x]) => (), - | ^^^^^^^^ - | | - | unexpected `(` after qualified path - | the qualified path - | in this macro invocation - | help: use a slice pattern here instead: `[_x]` - | - = help: for more information, see https://doc.rust-lang.org/edition-guide/rust-2018/slice-patterns.html - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to previous error - diff --git a/src/test/ui/type/ascription/issue-47666.stderr b/src/test/ui/type/ascription/issue-47666.stderr index ba393ff1a208e..755eec23c2ee3 100644 --- a/src/test/ui/type/ascription/issue-47666.stderr +++ b/src/test/ui/type/ascription/issue-47666.stderr @@ -1,4 +1,4 @@ -error: expected type, found reserved keyword `box` +error: expected type, found `<[_]>::into_vec(box [0, 1])` --> $DIR/issue-47666.rs:3:25 | LL | let _ = Option:Some(vec![0, 1]); diff --git a/src/test/ui/underscore-imports/hygiene.rs b/src/test/ui/underscore-imports/hygiene.rs index a254f6eaa5980..c4db65245386f 100644 --- a/src/test/ui/underscore-imports/hygiene.rs +++ b/src/test/ui/underscore-imports/hygiene.rs @@ -1,5 +1,6 @@ -// Make sure that underscore imports have the same hygiene considerations as -// other imports. +// Make sure that underscore imports have the same hygiene considerations as other imports. + +// check-pass #![feature(decl_macro)] @@ -7,7 +8,6 @@ mod x { pub use std::ops::Deref as _; } - macro glob_import() { pub use crate::x::*; } @@ -35,6 +35,6 @@ fn main() { use crate::z::*; glob_import!(); underscore_import!(); - (&()).deref(); //~ ERROR no method named `deref` - (&mut ()).deref_mut(); //~ ERROR no method named `deref_mut` + (&()).deref(); + (&mut ()).deref_mut(); } diff --git a/src/test/ui/underscore-imports/hygiene.stderr b/src/test/ui/underscore-imports/hygiene.stderr deleted file mode 100644 index 2983613786038..0000000000000 --- a/src/test/ui/underscore-imports/hygiene.stderr +++ /dev/null @@ -1,27 +0,0 @@ -error[E0599]: no method named `deref` found for reference `&()` in the current scope - --> $DIR/hygiene.rs:38:11 - | -LL | (&()).deref(); - | ^^^^^ method not found in `&()` - | - = help: items from traits can only be used if the trait is in scope -help: the following trait is implemented but not in scope; perhaps add a `use` for it: - | -LL | use std::ops::Deref; - | - -error[E0599]: no method named `deref_mut` found for mutable reference `&mut ()` in the current scope - --> $DIR/hygiene.rs:39:15 - | -LL | (&mut ()).deref_mut(); - | ^^^^^^^^^ method not found in `&mut ()` - | - = help: items from traits can only be used if the trait is in scope -help: the following trait is implemented but not in scope; perhaps add a `use` for it: - | -LL | use std::ops::DerefMut; - | - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0599`.