Auto merge of #81113 - m-ou-se:rollup-a1unz4x, r=m-ou-se
Rollup of 13 pull requests Successful merges: - #79298 (correctly deal with late-bound lifetimes in anon consts) - #80031 (resolve: Reject ambiguity built-in attr vs different built-in attr) - #80201 (Add benchmark and fast path for BufReader::read_exact) - #80635 (Improve diagnostics when closure doesn't meet trait bound) - #80765 (resolve: Simplify collection of traits in scope) - #80932 (Allow downloading LLVM on Windows and MacOS) - #80983 (Remove is_dllimport_foreign_item definition from cg_ssa) - #81064 (Support non-stage0 check) - #81080 (Force vec![] to expression position only) - #81082 (BTreeMap: clean up a few more comments) - #81084 (Use Option::map instead of open-coding it) - #81095 (Use Option::unwrap_or instead of open-coding it) - #81107 (Add NonZeroUn::is_power_of_two) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
edeb631ad0
@ -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<String> {
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1281,11 +1281,6 @@ rustc_queries! {
|
||||
}
|
||||
|
||||
Other {
|
||||
query dllimport_foreign_items(_: CrateNum)
|
||||
-> FxHashSet<DefId> {
|
||||
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<ItemLocalId>> {
|
||||
Option<(LocalDefId, &'tcx FxHashSet<ItemLocalId>)> {
|
||||
desc { "testing if a region is late bound" }
|
||||
}
|
||||
query object_lifetime_defaults_map(_: LocalDefId)
|
||||
|
@ -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]> {
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -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 = {:?}",
|
||||
|
@ -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);
|
||||
|
@ -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];
|
||||
|
@ -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
|
||||
|
@ -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<TraitCandidate> {
|
||||
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<TraitCandidate> {
|
||||
self.r.traits_in_scope(
|
||||
self.current_trait_ref.as_ref().map(|(module, _)| *module),
|
||||
&self.parent_scope,
|
||||
ident.span.ctxt(),
|
||||
Some((ident.name, ns)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<ItemLocalId>)> {
|
||||
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 {
|
||||
|
@ -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,52 +1477,79 @@ impl<'a> Resolver<'a> {
|
||||
self.crate_loader.postprocess(krate);
|
||||
}
|
||||
|
||||
fn get_traits_in_module_containing_item(
|
||||
pub fn traits_in_scope(
|
||||
&mut self,
|
||||
ident: Ident,
|
||||
ns: Namespace,
|
||||
module: Module<'a>,
|
||||
found_traits: &mut Vec<TraitCandidate>,
|
||||
current_trait: Option<Module<'a>>,
|
||||
parent_scope: &ParentScope<'a>,
|
||||
ctxt: SyntaxContext,
|
||||
assoc_item: Option<(Symbol, Namespace)>,
|
||||
) -> Vec<TraitCandidate> {
|
||||
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,
|
||||
module: Module<'a>,
|
||||
assoc_item: Option<(Symbol, Namespace)>,
|
||||
found_traits: &mut Vec<TraitCandidate>,
|
||||
) {
|
||||
assert!(ns == TypeNS || ns == ValueNS);
|
||||
module.ensure_traits(self);
|
||||
let traits = module.traits.borrow();
|
||||
|
||||
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?")
|
||||
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 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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<Module<'a>>,
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
fn find_transitive_imports(
|
||||
&mut self,
|
||||
mut kind: &NameBindingKind<'_>,
|
||||
@ -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<TraitCandidate> {
|
||||
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,
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
#
|
||||
|
@ -184,7 +184,7 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::LeafOrInternal> {
|
||||
|
||||
/// 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<K, V> NodeRef<marker::Owned, K, V, marker::LeafOrInternal> {
|
||||
/// - When this is `Owned`, the `NodeRef` acts roughly like `Box<Node>`,
|
||||
/// 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<marker::Immut<'a>, K, V, Type> {
|
||||
|
||||
impl<K, V> NodeRef<marker::Owned, K, V, marker::LeafOrInternal> {
|
||||
/// 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<marker::Mut<'a>, 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<Root<K, V>>) {
|
||||
///
|
||||
/// # Safety
|
||||
/// The node must not be empty.
|
||||
unsafe fn pop(&mut self) -> (K, V, Option<Root<K, V>>) {
|
||||
debug_assert!(self.len() > 0);
|
||||
|
||||
let idx = self.len() - 1;
|
||||
|
@ -12,8 +12,7 @@ pub enum SearchResult<BorrowType, K, V, FoundType, GoDownType> {
|
||||
|
||||
/// 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.
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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),+]))
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -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 }
|
||||
|
@ -271,6 +271,20 @@ impl<R: Read> Read for BufReader<R> {
|
||||
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<usize> {
|
||||
let total_len = bufs.iter().map(|b| b.len()).sum::<usize>();
|
||||
if self.pos == self.cap && total_len >= self.buf.len() {
|
||||
|
@ -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::<Vec<_>>();
|
||||
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()));
|
||||
|
@ -416,6 +416,25 @@ where
|
||||
write(buf)
|
||||
}
|
||||
|
||||
pub(crate) fn default_read_exact<R: Read + ?Sized>(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`.
|
||||
|
@ -465,8 +465,21 @@ class RustBuild(object):
|
||||
|
||||
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:
|
||||
|
@ -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
|
||||
|
@ -377,6 +377,7 @@ struct Build {
|
||||
configure_args: Option<Vec<String>>,
|
||||
local_rebuild: Option<bool>,
|
||||
print_step_timings: Option<bool>,
|
||||
check_stage: Option<u32>,
|
||||
doc_stage: Option<u32>,
|
||||
build_stage: Option<u32>,
|
||||
test_stage: Option<u32>,
|
||||
@ -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 {
|
||||
|
@ -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())
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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")
|
||||
|
@ -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()
|
||||
})
|
||||
});
|
||||
|
||||
|
@ -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 <https://github.com/rust-lang/rust/issues/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]
|
||||
}
|
@ -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 <https://github.com/rust-lang/rust/issues/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`.
|
@ -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 <https://github.com/rust-lang/rust/issues/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]
|
||||
}
|
@ -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 <https://github.com/rust-lang/rust/issues/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`.
|
@ -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 <https://github.com/rust-lang/rust/issues/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]
|
||||
}
|
@ -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 <https://github.com/rust-lang/rust/issues/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`.
|
@ -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 <https://github.com/rust-lang/rust/issues/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]
|
||||
}
|
@ -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 <https://github.com/rust-lang/rust/issues/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`.
|
@ -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 <https://github.com/rust-lang/rust/issues/53488>
|
||||
struct S(String, String);
|
||||
|
||||
fn expect_fn<F: 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);
|
||||
}
|
@ -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 <https://github.com/rust-lang/rust/issues/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`.
|
18
src/test/ui/const-generics/late-bound-vars/in_closure.rs
Normal file
18
src/test/ui/const-generics/late-bound-vars/in_closure.rs
Normal file
@ -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();
|
||||
}
|
16
src/test/ui/const-generics/late-bound-vars/simple.rs
Normal file
16
src/test/ui/const-generics/late-bound-vars/simple.rs
Normal file
@ -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();
|
||||
}
|
53
src/test/ui/hygiene/traits-in-scope.rs
Normal file
53
src/test/ui/hygiene/traits-in-scope.rs
Normal file
@ -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();
|
||||
}
|
10
src/test/ui/macros/vec-macro-in-pattern.rs
Normal file
10
src/test/ui/macros/vec-macro-in-pattern.rs
Normal file
@ -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
|
||||
_ => {}
|
||||
}
|
||||
}
|
10
src/test/ui/macros/vec-macro-in-pattern.stderr
Normal file
10
src/test/ui/macros/vec-macro-in-pattern.stderr
Normal file
@ -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
|
||||
|
@ -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() {}
|
||||
|
@ -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`.
|
||||
|
@ -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
|
||||
_ => (),
|
||||
}
|
||||
}
|
@ -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
|
||||
_ => (),
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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]);
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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`.
|
Loading…
x
Reference in New Issue
Block a user