Auto merge of #3384 - rust-lang:rustup-2024-03-17, r=RalfJung
Automatic Rustup
This commit is contained in:
commit
caa57dd518
341 changed files with 4872 additions and 3347 deletions
6
.github/workflows/dependencies.yml
vendored
6
.github/workflows/dependencies.yml
vendored
|
|
@ -6,6 +6,8 @@ on:
|
|||
schedule:
|
||||
# Run weekly
|
||||
- cron: '0 0 * * Sun'
|
||||
# Re-bump deps every 4 hours
|
||||
- cron: '0 */4 * * *'
|
||||
workflow_dispatch:
|
||||
# Needed so we can run it manually
|
||||
permissions:
|
||||
|
|
@ -135,8 +137,8 @@ jobs:
|
|||
gh pr edit cargo_update --title "${PR_TITLE}" --body-file body.md --repo $GITHUB_REPOSITORY
|
||||
|
||||
- name: open new pull request
|
||||
# Only run if there wasn't an existing PR
|
||||
if: steps.edit.outcome != 'success'
|
||||
# Only run if there wasn't an existing PR and if this is the weekly run
|
||||
if: steps.edit.outcome != 'success' && github.event.schedule == '0 0 * * Sun'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: gh pr create --title "${PR_TITLE}" --body-file body.md --repo $GITHUB_REPOSITORY
|
||||
|
|
|
|||
11
Cargo.lock
11
Cargo.lock
|
|
@ -4400,6 +4400,7 @@ dependencies = [
|
|||
"rustc_lexer",
|
||||
"rustc_macros",
|
||||
"rustc_middle",
|
||||
"rustc_privacy",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
|
|
@ -6279,12 +6280,14 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-bindgen"
|
||||
version = "0.52.0"
|
||||
version = "0.55.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "970efb0b6849eb8a87a898f586af7cc167567b070014c7434514c0bde0ca341c"
|
||||
checksum = "073ff8a486ebad239d557809d2cd5fe5e04ee1de29e09c6cd83fb0bae19b8a4c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"rayon",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"syn 2.0.52",
|
||||
"windows-metadata",
|
||||
]
|
||||
|
|
@ -6300,9 +6303,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-metadata"
|
||||
version = "0.52.0"
|
||||
version = "0.55.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "218fd59201e26acdbb894fa2b302d1de84bf3eec7d0eb894ac8e9c5a854ee4ef"
|
||||
checksum = "b602635050172a1fc57a35040d4d225baefc6098fefd97094919921d95961a7d"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
|
|
|
|||
|
|
@ -276,8 +276,10 @@ fn filtered_float_lit(
|
|||
Some(suffix) => LitKind::Float(
|
||||
symbol,
|
||||
ast::LitFloatType::Suffixed(match suffix {
|
||||
sym::f16 => ast::FloatTy::F16,
|
||||
sym::f32 => ast::FloatTy::F32,
|
||||
sym::f64 => ast::FloatTy::F64,
|
||||
sym::f128 => ast::FloatTy::F128,
|
||||
_ => return Err(LitError::InvalidFloatSuffix(suffix)),
|
||||
}),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -373,6 +373,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
(trait_ref, lowered_ty)
|
||||
});
|
||||
|
||||
self.is_in_trait_impl = trait_ref.is_some();
|
||||
let new_impl_items = self
|
||||
.arena
|
||||
.alloc_from_iter(impl_items.iter().map(|item| self.lower_impl_item_ref(item)));
|
||||
|
|
@ -978,13 +979,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
|
||||
fn lower_impl_item_ref(&mut self, i: &AssocItem) -> hir::ImplItemRef {
|
||||
let trait_item_def_id = self
|
||||
.resolver
|
||||
.get_partial_res(i.id)
|
||||
.map(|r| r.expect_full_res().opt_def_id())
|
||||
.unwrap_or(None);
|
||||
self.is_in_trait_impl = trait_item_def_id.is_some();
|
||||
|
||||
hir::ImplItemRef {
|
||||
id: hir::ImplItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } },
|
||||
ident: self.lower_ident(i.ident),
|
||||
|
|
@ -1000,7 +994,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
},
|
||||
AssocItemKind::MacCall(..) => unimplemented!(),
|
||||
},
|
||||
trait_item_def_id,
|
||||
trait_item_def_id: self
|
||||
.resolver
|
||||
.get_partial_res(i.id)
|
||||
.map(|r| r.expect_full_res().opt_def_id())
|
||||
.unwrap_or(None),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1527,6 +1527,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
generics,
|
||||
body.as_deref(),
|
||||
);
|
||||
walk_list!(self, visit_attribute, &item.attrs);
|
||||
self.visit_fn(kind, item.span, item.id);
|
||||
}
|
||||
AssocItemKind::Type(_) => {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use rustc_ast as ast;
|
||||
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
|
||||
use rustc_ast::{attr, AssocConstraint, AssocConstraintKind, NodeId};
|
||||
use rustc_ast::{PatKind, RangeEnd};
|
||||
use rustc_ast::{token, PatKind, RangeEnd};
|
||||
use rustc_feature::{AttributeGate, BuiltinAttribute, Features, GateIssue, BUILTIN_ATTRIBUTE_MAP};
|
||||
use rustc_session::parse::{feature_err, feature_err_issue, feature_warn};
|
||||
use rustc_session::Session;
|
||||
|
|
@ -378,6 +378,17 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
ast::ExprKind::TryBlock(_) => {
|
||||
gate!(&self, try_blocks, e.span, "`try` expression is experimental");
|
||||
}
|
||||
ast::ExprKind::Lit(token::Lit { kind: token::LitKind::Float, suffix, .. }) => {
|
||||
match suffix {
|
||||
Some(sym::f16) => {
|
||||
gate!(&self, f16, e.span, "the type `f16` is unstable")
|
||||
}
|
||||
Some(sym::f128) => {
|
||||
gate!(&self, f128, e.span, "the type `f128` is unstable")
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
visit::walk_expr(self, e)
|
||||
|
|
|
|||
|
|
@ -16,6 +16,9 @@ borrowck_borrow_due_to_use_closure =
|
|||
borrowck_borrow_due_to_use_coroutine =
|
||||
borrow occurs due to use in coroutine
|
||||
|
||||
borrowck_calling_operator_moves =
|
||||
calling this operator moves the value
|
||||
|
||||
borrowck_calling_operator_moves_lhs =
|
||||
calling this operator moves the left-hand side
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ use rustc_hir::def::{DefKind, Res};
|
|||
use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
|
||||
use rustc_hir::{CoroutineDesugaring, PatField};
|
||||
use rustc_hir::{CoroutineKind, CoroutineSource, LangItem};
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_middle::hir::nested_filter::OnlyBodies;
|
||||
use rustc_middle::mir::tcx::PlaceTy;
|
||||
use rustc_middle::mir::{
|
||||
|
|
@ -21,16 +20,21 @@ use rustc_middle::mir::{
|
|||
PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
|
||||
VarBindingForm,
|
||||
};
|
||||
use rustc_middle::ty::{self, suggest_constraining_type_params, PredicateKind, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{
|
||||
self, suggest_constraining_type_params, PredicateKind, ToPredicate, Ty, TyCtxt,
|
||||
TypeSuperVisitable, TypeVisitor,
|
||||
};
|
||||
use rustc_middle::util::CallKind;
|
||||
use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::hygiene::DesugaringKind;
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
use rustc_span::{BytePos, Span, Symbol};
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
|
||||
use rustc_trait_selection::traits::error_reporting::FindExprBySpan;
|
||||
use rustc_trait_selection::traits::ObligationCtxt;
|
||||
use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
|
||||
use std::iter;
|
||||
|
||||
use crate::borrow_set::TwoPhaseActivation;
|
||||
|
|
@ -39,7 +43,7 @@ use crate::diagnostics::conflict_errors::StorageDeadOrDrop::LocalStorageDead;
|
|||
use crate::diagnostics::{find_all_local_uses, CapturedMessageOpt};
|
||||
use crate::{
|
||||
borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf,
|
||||
InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind,
|
||||
InitializationRequiringAction, MirBorrowckCtxt, WriteKind,
|
||||
};
|
||||
|
||||
use super::{
|
||||
|
|
@ -114,7 +118,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
self.buffer_error(err);
|
||||
} else {
|
||||
if let Some((reported_place, _)) = self.has_move_error(&move_out_indices) {
|
||||
if self.prefixes(*reported_place, PrefixSet::All).any(|p| p == used_place) {
|
||||
if used_place.is_prefix_of(*reported_place) {
|
||||
debug!(
|
||||
"report_use_of_moved_or_uninitialized place: error suppressed mois={:?}",
|
||||
move_out_indices
|
||||
|
|
@ -283,7 +287,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
// something that already has `Fn`-like bounds (or is a closure), so we can't
|
||||
// restrict anyways.
|
||||
} else {
|
||||
self.suggest_adding_copy_bounds(&mut err, ty, span);
|
||||
let copy_did = self.infcx.tcx.require_lang_item(LangItem::Copy, Some(span));
|
||||
self.suggest_adding_bounds(&mut err, ty, copy_did, span);
|
||||
}
|
||||
|
||||
if needs_note {
|
||||
|
|
@ -422,8 +427,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
(None, &[][..], 0)
|
||||
};
|
||||
if let Some(def_id) = def_id
|
||||
&& let node =
|
||||
self.infcx.tcx.hir_node(self.infcx.tcx.local_def_id_to_hir_id(def_id))
|
||||
&& let node = self.infcx.tcx.hir_node_by_def_id(def_id)
|
||||
&& let Some(fn_sig) = node.fn_sig()
|
||||
&& let Some(ident) = node.ident()
|
||||
&& let Some(pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id)
|
||||
|
|
@ -775,7 +779,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn suggest_adding_copy_bounds(&self, err: &mut Diag<'_>, ty: Ty<'tcx>, span: Span) {
|
||||
fn suggest_adding_bounds(&self, err: &mut Diag<'_>, ty: Ty<'tcx>, def_id: DefId, span: Span) {
|
||||
let tcx = self.infcx.tcx;
|
||||
let generics = tcx.generics_of(self.mir_def_id());
|
||||
|
||||
|
|
@ -788,10 +792,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
};
|
||||
// Try to find predicates on *generic params* that would allow copying `ty`
|
||||
let ocx = ObligationCtxt::new(self.infcx);
|
||||
let copy_did = tcx.require_lang_item(LangItem::Copy, Some(span));
|
||||
let cause = ObligationCause::misc(span, self.mir_def_id());
|
||||
|
||||
ocx.register_bound(cause, self.param_env, ty, copy_did);
|
||||
ocx.register_bound(cause, self.param_env, ty, def_id);
|
||||
let errors = ocx.select_all_or_error();
|
||||
|
||||
// Only emit suggestion if all required predicates are on generic
|
||||
|
|
@ -877,6 +880,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
Some(borrow_span),
|
||||
None,
|
||||
);
|
||||
self.suggest_copy_for_type_in_cloned_ref(&mut err, place);
|
||||
self.buffer_error(err);
|
||||
}
|
||||
|
||||
|
|
@ -1215,10 +1219,104 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
);
|
||||
|
||||
self.suggest_using_local_if_applicable(&mut err, location, issued_borrow, explanation);
|
||||
self.suggest_copy_for_type_in_cloned_ref(&mut err, place);
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
fn suggest_copy_for_type_in_cloned_ref(&self, err: &mut Diag<'tcx>, place: Place<'tcx>) {
|
||||
let tcx = self.infcx.tcx;
|
||||
let hir = tcx.hir();
|
||||
let Some(body_id) = tcx.hir_node(self.mir_hir_id()).body_id() else { return };
|
||||
struct FindUselessClone<'hir> {
|
||||
pub clones: Vec<&'hir hir::Expr<'hir>>,
|
||||
}
|
||||
impl<'hir> FindUselessClone<'hir> {
|
||||
pub fn new() -> Self {
|
||||
Self { clones: vec![] }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'v> Visitor<'v> for FindUselessClone<'v> {
|
||||
fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
|
||||
// FIXME: use `lookup_method_for_diagnostic`?
|
||||
if let hir::ExprKind::MethodCall(segment, _rcvr, args, _span) = ex.kind
|
||||
&& segment.ident.name == sym::clone
|
||||
&& args.len() == 0
|
||||
{
|
||||
self.clones.push(ex);
|
||||
}
|
||||
hir::intravisit::walk_expr(self, ex);
|
||||
}
|
||||
}
|
||||
let mut expr_finder = FindUselessClone::new();
|
||||
|
||||
let body = hir.body(body_id).value;
|
||||
expr_finder.visit_expr(body);
|
||||
|
||||
pub struct Holds<'tcx> {
|
||||
ty: Ty<'tcx>,
|
||||
holds: bool,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Holds<'tcx> {
|
||||
type Result = std::ops::ControlFlow<()>;
|
||||
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
|
||||
if t == self.ty {
|
||||
self.holds = true;
|
||||
}
|
||||
t.super_visit_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
let mut types_to_constrain = FxIndexSet::default();
|
||||
|
||||
let local_ty = self.body.local_decls[place.local].ty;
|
||||
let typeck_results = tcx.typeck(self.mir_def_id());
|
||||
let clone = tcx.require_lang_item(LangItem::Clone, Some(body.span));
|
||||
for expr in expr_finder.clones {
|
||||
if let hir::ExprKind::MethodCall(_, rcvr, _, span) = expr.kind
|
||||
&& let Some(rcvr_ty) = typeck_results.node_type_opt(rcvr.hir_id)
|
||||
&& let Some(ty) = typeck_results.node_type_opt(expr.hir_id)
|
||||
&& rcvr_ty == ty
|
||||
&& let ty::Ref(_, inner, _) = rcvr_ty.kind()
|
||||
&& let inner = inner.peel_refs()
|
||||
&& let mut v = (Holds { ty: inner, holds: false })
|
||||
&& let _ = v.visit_ty(local_ty)
|
||||
&& v.holds
|
||||
&& let None = self.infcx.type_implements_trait_shallow(clone, inner, self.param_env)
|
||||
{
|
||||
err.span_label(
|
||||
span,
|
||||
format!(
|
||||
"this call doesn't do anything, the result is still `{rcvr_ty}` \
|
||||
because `{inner}` doesn't implement `Clone`",
|
||||
),
|
||||
);
|
||||
types_to_constrain.insert(inner);
|
||||
}
|
||||
}
|
||||
for ty in types_to_constrain {
|
||||
self.suggest_adding_bounds(err, ty, clone, body.span);
|
||||
if let ty::Adt(..) = ty.kind() {
|
||||
// The type doesn't implement Clone.
|
||||
let trait_ref = ty::Binder::dummy(ty::TraitRef::new(self.infcx.tcx, clone, [ty]));
|
||||
let obligation = Obligation::new(
|
||||
self.infcx.tcx,
|
||||
ObligationCause::dummy(),
|
||||
self.param_env,
|
||||
trait_ref,
|
||||
);
|
||||
self.infcx.err_ctxt().suggest_derive(
|
||||
&obligation,
|
||||
err,
|
||||
trait_ref.to_predicate(self.infcx.tcx),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, err))]
|
||||
fn suggest_using_local_if_applicable(
|
||||
&self,
|
||||
|
|
@ -1995,21 +2093,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
kind: Option<WriteKind>,
|
||||
) {
|
||||
let drop_span = place_span.1;
|
||||
let root_place =
|
||||
self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap();
|
||||
let borrowed_local = borrow.borrowed_place.local;
|
||||
|
||||
let borrow_spans = self.retrieve_borrow_spans(borrow);
|
||||
let borrow_span = borrow_spans.var_or_use_path_span();
|
||||
|
||||
assert!(root_place.projection.is_empty());
|
||||
let proper_span = self.body.local_decls[root_place.local].source_info.span;
|
||||
let proper_span = self.body.local_decls[borrowed_local].source_info.span;
|
||||
|
||||
let root_place_projection = self.infcx.tcx.mk_place_elems(root_place.projection);
|
||||
|
||||
if self.access_place_error_reported.contains(&(
|
||||
Place { local: root_place.local, projection: root_place_projection },
|
||||
borrow_span,
|
||||
)) {
|
||||
if self.access_place_error_reported.contains(&(Place::from(borrowed_local), borrow_span)) {
|
||||
debug!(
|
||||
"suppressing access_place error when borrow doesn't live long enough for {:?}",
|
||||
borrow_span
|
||||
|
|
@ -2017,12 +2108,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
self.access_place_error_reported.insert((
|
||||
Place { local: root_place.local, projection: root_place_projection },
|
||||
borrow_span,
|
||||
));
|
||||
self.access_place_error_reported.insert((Place::from(borrowed_local), borrow_span));
|
||||
|
||||
let borrowed_local = borrow.borrowed_place.local;
|
||||
if self.body.local_decls[borrowed_local].is_ref_to_thread_local() {
|
||||
let err =
|
||||
self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span);
|
||||
|
|
@ -2544,9 +2631,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
};
|
||||
(format!("{local_kind}`{place_desc}`"), format!("`{place_desc}` is borrowed here"))
|
||||
} else {
|
||||
let root_place =
|
||||
self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap();
|
||||
let local = root_place.local;
|
||||
let local = borrow.borrowed_place.local;
|
||||
match self.body.local_kind(local) {
|
||||
LocalKind::Arg => (
|
||||
"function parameter".to_string(),
|
||||
|
|
|
|||
|
|
@ -1050,7 +1050,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
);
|
||||
err.subdiagnostic(self.dcx(), CaptureReasonNote::FnOnceMoveInCall { var_span });
|
||||
}
|
||||
CallKind::Operator { self_arg, .. } => {
|
||||
CallKind::Operator { self_arg, trait_id, .. } => {
|
||||
let self_arg = self_arg.unwrap();
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
|
|
@ -1062,9 +1062,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
},
|
||||
);
|
||||
if self.fn_self_span_reported.insert(fn_span) {
|
||||
let lang = self.infcx.tcx.lang_items();
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
CaptureReasonNote::LhsMoveByOperator { span: self_arg.span },
|
||||
if [lang.not_trait(), lang.deref_trait(), lang.neg_trait()]
|
||||
.contains(&Some(trait_id))
|
||||
{
|
||||
CaptureReasonNote::UnOpMoveByOperator { span: self_arg.span }
|
||||
} else {
|
||||
CaptureReasonNote::LhsMoveByOperator { span: self_arg.span }
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1226,20 +1233,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
{
|
||||
let msg = match &errors[..] {
|
||||
[] => "you can `clone` the value and consume it, but this \
|
||||
might not be your desired behavior"
|
||||
might not be your desired behavior"
|
||||
.to_string(),
|
||||
[error] => {
|
||||
format!(
|
||||
"you could `clone` the value and consume it, if \
|
||||
the `{}` trait bound could be satisfied",
|
||||
"you could `clone` the value and consume it, if the \
|
||||
`{}` trait bound could be satisfied",
|
||||
error.obligation.predicate,
|
||||
)
|
||||
}
|
||||
[errors @ .., last] => {
|
||||
format!(
|
||||
"you could `clone` the value and consume it, if \
|
||||
the following trait bounds could be satisfied: {} \
|
||||
and `{}`",
|
||||
"you could `clone` the value and consume it, if the \
|
||||
following trait bounds could be satisfied: \
|
||||
{} and `{}`",
|
||||
errors
|
||||
.iter()
|
||||
.map(|e| format!("`{}`", e.obligation.predicate))
|
||||
|
|
|
|||
|
|
@ -672,11 +672,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
};
|
||||
(
|
||||
true,
|
||||
td.as_local().and_then(|tld| match self.infcx.tcx.opt_hir_node_by_def_id(tld) {
|
||||
Some(Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Trait(_, _, _, _, items),
|
||||
..
|
||||
})) => {
|
||||
td.as_local().and_then(|tld| match self.infcx.tcx.hir_node_by_def_id(tld) {
|
||||
Node::Item(hir::Item { kind: hir::ItemKind::Trait(_, _, _, _, items), .. }) => {
|
||||
let mut f_in_trait_opt = None;
|
||||
for hir::TraitItemRef { id: fi, kind: k, .. } in *items {
|
||||
let hi = fi.hir_id();
|
||||
|
|
@ -1475,11 +1472,9 @@ fn get_mut_span_in_struct_field<'tcx>(
|
|||
if let ty::Ref(_, ty, _) = ty.kind()
|
||||
&& let ty::Adt(def, _) = ty.kind()
|
||||
&& let field = def.all_fields().nth(field.index())?
|
||||
// Use the HIR types to construct the diagnostic message.
|
||||
&& let node = tcx.opt_hir_node_by_def_id(field.did.as_local()?)?
|
||||
// Now we're dealing with the actual struct that we're going to suggest a change to,
|
||||
// we can expect a field that is an immutable reference to a type.
|
||||
&& let hir::Node::Field(field) = node
|
||||
&& let hir::Node::Field(field) = tcx.hir_node_by_def_id(field.did.as_local()?)
|
||||
&& let hir::TyKind::Ref(lt, hir::MutTy { mutbl: hir::Mutability::Not, ty }) = field.ty.kind
|
||||
{
|
||||
return Some(lt.ident.span.between(ty.span));
|
||||
|
|
|
|||
|
|
@ -1,7 +1,4 @@
|
|||
//! From the NLL RFC: "The deep [aka 'supporting'] prefixes for an
|
||||
//! place are formed by stripping away fields and derefs, except that
|
||||
//! we stop when we reach the deref of a shared reference. [...] "
|
||||
//!
|
||||
//! From the NLL RFC:
|
||||
//! "Shallow prefixes are found by stripping away fields, but stop at
|
||||
//! any dereference. So: writing a path like `a` is illegal if `a.b`
|
||||
//! is borrowed. But: writing `a` is legal if `*a` is borrowed,
|
||||
|
|
@ -9,9 +6,7 @@
|
|||
|
||||
use super::MirBorrowckCtxt;
|
||||
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::mir::{Body, PlaceRef, ProjectionElem};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_middle::mir::{PlaceRef, ProjectionElem};
|
||||
|
||||
pub trait IsPrefixOf<'tcx> {
|
||||
fn is_prefix_of(&self, other: PlaceRef<'tcx>) -> bool;
|
||||
|
|
@ -25,9 +20,7 @@ impl<'tcx> IsPrefixOf<'tcx> for PlaceRef<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) struct Prefixes<'cx, 'tcx> {
|
||||
body: &'cx Body<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
pub(super) struct Prefixes<'tcx> {
|
||||
kind: PrefixSet,
|
||||
next: Option<PlaceRef<'tcx>>,
|
||||
}
|
||||
|
|
@ -39,24 +32,18 @@ pub(super) enum PrefixSet {
|
|||
All,
|
||||
/// Stops at any dereference.
|
||||
Shallow,
|
||||
/// Stops at the deref of a shared reference.
|
||||
Supporting,
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
/// Returns an iterator over the prefixes of `place`
|
||||
/// (inclusive) from longest to smallest, potentially
|
||||
/// terminating the iteration early based on `kind`.
|
||||
pub(super) fn prefixes(
|
||||
&self,
|
||||
place_ref: PlaceRef<'tcx>,
|
||||
kind: PrefixSet,
|
||||
) -> Prefixes<'cx, 'tcx> {
|
||||
Prefixes { next: Some(place_ref), kind, body: self.body, tcx: self.infcx.tcx }
|
||||
pub(super) fn prefixes(&self, place_ref: PlaceRef<'tcx>, kind: PrefixSet) -> Prefixes<'tcx> {
|
||||
Prefixes { next: Some(place_ref), kind }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
|
||||
impl<'tcx> Iterator for Prefixes<'tcx> {
|
||||
type Item = PlaceRef<'tcx>;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let mut cursor = self.next?;
|
||||
|
|
@ -91,57 +78,23 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
|
|||
panic!("Subtype projection is not allowed before borrow check")
|
||||
}
|
||||
ProjectionElem::Deref => {
|
||||
// (handled below)
|
||||
match self.kind {
|
||||
PrefixSet::Shallow => {
|
||||
// Shallow prefixes are found by stripping away
|
||||
// fields, but stop at *any* dereference.
|
||||
// So we can just stop the traversal now.
|
||||
self.next = None;
|
||||
return Some(cursor);
|
||||
}
|
||||
PrefixSet::All => {
|
||||
// All prefixes: just blindly enqueue the base
|
||||
// of the projection.
|
||||
self.next = Some(cursor_base);
|
||||
return Some(cursor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(elem, ProjectionElem::Deref);
|
||||
|
||||
match self.kind {
|
||||
PrefixSet::Shallow => {
|
||||
// Shallow prefixes are found by stripping away
|
||||
// fields, but stop at *any* dereference.
|
||||
// So we can just stop the traversal now.
|
||||
self.next = None;
|
||||
return Some(cursor);
|
||||
}
|
||||
PrefixSet::All => {
|
||||
// All prefixes: just blindly enqueue the base
|
||||
// of the projection.
|
||||
self.next = Some(cursor_base);
|
||||
return Some(cursor);
|
||||
}
|
||||
PrefixSet::Supporting => {
|
||||
// Fall through!
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(self.kind, PrefixSet::Supporting);
|
||||
// Supporting prefixes: strip away fields and
|
||||
// derefs, except we stop at the deref of a shared
|
||||
// reference.
|
||||
|
||||
let ty = cursor_base.ty(self.body, self.tcx).ty;
|
||||
match ty.kind() {
|
||||
ty::RawPtr(_) | ty::Ref(_ /*rgn*/, _ /*ty*/, hir::Mutability::Not) => {
|
||||
// don't continue traversing over derefs of raw pointers or shared
|
||||
// borrows.
|
||||
self.next = None;
|
||||
return Some(cursor);
|
||||
}
|
||||
|
||||
ty::Ref(_ /*rgn*/, _ /*ty*/, hir::Mutability::Mut) => {
|
||||
self.next = Some(cursor_base);
|
||||
return Some(cursor);
|
||||
}
|
||||
|
||||
ty::Adt(..) if ty.is_box() => {
|
||||
self.next = Some(cursor_base);
|
||||
return Some(cursor);
|
||||
}
|
||||
|
||||
_ => panic!("unknown type fed to Projection Deref."),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -368,6 +368,11 @@ pub(crate) enum CaptureReasonNote {
|
|||
#[primary_span]
|
||||
var_span: Span,
|
||||
},
|
||||
#[note(borrowck_calling_operator_moves)]
|
||||
UnOpMoveByOperator {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[note(borrowck_calling_operator_moves_lhs)]
|
||||
LhsMoveByOperator {
|
||||
#[primary_span]
|
||||
|
|
|
|||
|
|
@ -44,10 +44,9 @@ jobs:
|
|||
env:
|
||||
TARGET_TRIPLE: x86_64-apple-darwin
|
||||
# cross-compile from Linux to Windows using mingw
|
||||
# FIXME The wine version in Ubuntu 22.04 is missing ProcessPrng
|
||||
#- os: ubuntu-latest
|
||||
# env:
|
||||
# TARGET_TRIPLE: x86_64-pc-windows-gnu
|
||||
- os: ubuntu-latest
|
||||
env:
|
||||
TARGET_TRIPLE: x86_64-pc-windows-gnu
|
||||
- os: ubuntu-latest
|
||||
env:
|
||||
TARGET_TRIPLE: aarch64-unknown-linux-gnu
|
||||
|
|
@ -81,11 +80,11 @@ jobs:
|
|||
if: matrix.os == 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
|
||||
run: rustup set default-host x86_64-pc-windows-gnu
|
||||
|
||||
#- name: Install MinGW toolchain and wine
|
||||
# if: matrix.os == 'ubuntu-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
|
||||
# run: |
|
||||
# sudo apt-get update
|
||||
# sudo apt-get install -y gcc-mingw-w64-x86-64 wine-stable
|
||||
- name: Install MinGW toolchain and wine
|
||||
if: matrix.os == 'ubuntu-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y gcc-mingw-w64-x86-64 wine-stable
|
||||
|
||||
- name: Install AArch64 toolchain and qemu
|
||||
if: matrix.os == 'ubuntu-latest' && matrix.env.TARGET_TRIPLE == 'aarch64-unknown-linux-gnu'
|
||||
|
|
@ -108,6 +107,15 @@ jobs:
|
|||
- name: Prepare dependencies
|
||||
run: ./y.sh prepare
|
||||
|
||||
# The Wine version shipped with Ubuntu 22.04 doesn't implement bcryptprimitives.dll
|
||||
- name: Build bcryptprimitives.dll shim for Wine
|
||||
if: matrix.os == 'ubuntu-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
|
||||
run: |
|
||||
rustup target add x86_64-pc-windows-gnu
|
||||
mkdir wine_shims
|
||||
rustc patches/bcryptprimitives.rs -Copt-level=3 -Clto=fat --out-dir wine_shims --target x86_64-pc-windows-gnu
|
||||
echo "WINEPATH=$(pwd)/wine_shims" >> $GITHUB_ENV
|
||||
|
||||
- name: Build
|
||||
run: ./y.sh build --sysroot none
|
||||
|
||||
|
|
@ -234,11 +242,11 @@ jobs:
|
|||
if: matrix.os == 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
|
||||
run: rustup set default-host x86_64-pc-windows-gnu
|
||||
|
||||
- name: Install MinGW toolchain and wine
|
||||
- name: Install MinGW toolchain
|
||||
if: matrix.os == 'ubuntu-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y gcc-mingw-w64-x86-64 wine-stable
|
||||
sudo apt-get install -y gcc-mingw-w64-x86-64
|
||||
|
||||
- name: Prepare dependencies
|
||||
run: ./y.sh prepare
|
||||
|
|
|
|||
|
|
@ -167,6 +167,14 @@ fn main() {
|
|||
transmute_fat_pointer();
|
||||
|
||||
rust_call_abi();
|
||||
|
||||
const fn no_str() -> Option<Box<str>> {
|
||||
None
|
||||
}
|
||||
|
||||
static STATIC_WITH_MAYBE_NESTED_BOX: &Option<Box<str>> = &no_str();
|
||||
|
||||
println!("{:?}", STATIC_WITH_MAYBE_NESTED_BOX);
|
||||
}
|
||||
|
||||
fn panic(_: u128) {
|
||||
|
|
|
|||
22
compiler/rustc_codegen_cranelift/patches/bcryptprimitives.rs
Normal file
22
compiler/rustc_codegen_cranelift/patches/bcryptprimitives.rs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// Shim for bcryptprimitives.dll. The Wine version shipped with Ubuntu 22.04
|
||||
// doesn't support it yet. Authored by @ChrisDenton
|
||||
|
||||
#![crate_type = "cdylib"]
|
||||
#![allow(nonstandard_style)]
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "system" fn ProcessPrng(mut pbData: *mut u8, mut cbData: usize) -> i32 {
|
||||
while cbData > 0 {
|
||||
let size = core::cmp::min(cbData, u32::MAX as usize);
|
||||
RtlGenRandom(pbData, size as u32);
|
||||
cbData -= size;
|
||||
pbData = pbData.add(size);
|
||||
}
|
||||
1
|
||||
}
|
||||
|
||||
#[link(name = "advapi32")]
|
||||
extern "system" {
|
||||
#[link_name = "SystemFunction036"]
|
||||
pub fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: u32) -> u8;
|
||||
}
|
||||
|
|
@ -42,12 +42,9 @@ checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
|
|||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.83"
|
||||
version = "1.0.90"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2024-03-08"
|
||||
channel = "nightly-2024-03-16"
|
||||
components = ["rust-src", "rustc-dev", "llvm-tools"]
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ rm -r tests/run-make/symbols-include-type-name # --emit=asm not supported
|
|||
rm -r tests/run-make/target-specs # i686 not supported by Cranelift
|
||||
rm -r tests/run-make/mismatching-target-triples # same
|
||||
rm tests/ui/asm/x86_64/issue-96797.rs # const and sym inline asm operands don't work entirely correctly
|
||||
rm tests/ui/asm/x86_64/goto.rs # inline asm labels not supported
|
||||
|
||||
# requires LTO
|
||||
rm -r tests/run-make/cdylib
|
||||
|
|
@ -121,6 +122,7 @@ rm -r tests/run-make/optimization-remarks-dir # remarks are LLVM specific
|
|||
rm tests/ui/mir/mir_misc_casts.rs # depends on deduplication of constants
|
||||
rm tests/ui/mir/mir_raw_fat_ptr.rs # same
|
||||
rm tests/ui/consts/issue-33537.rs # same
|
||||
rm tests/ui/consts/const-mut-refs-crate.rs # same
|
||||
|
||||
# rustdoc-clif passes extra args, suppressing the help message when no args are passed
|
||||
rm -r tests/run-make/issue-88756-default-output
|
||||
|
|
|
|||
|
|
@ -53,7 +53,11 @@ pub(crate) fn codegen_tls_ref<'tcx>(
|
|||
let call = fx.bcx.ins().call(func_ref, &[]);
|
||||
fx.bcx.func.dfg.first_result(call)
|
||||
} else {
|
||||
let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false);
|
||||
let data_id = data_id_for_static(
|
||||
fx.tcx, fx.module, def_id, false,
|
||||
// For a declaration the stated mutability doesn't matter.
|
||||
false,
|
||||
);
|
||||
let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
|
||||
if fx.clif_comments.enabled() {
|
||||
fx.add_comment(local_data_id, format!("tls {:?}", def_id));
|
||||
|
|
@ -164,7 +168,11 @@ pub(crate) fn codegen_const_value<'tcx>(
|
|||
}
|
||||
GlobalAlloc::Static(def_id) => {
|
||||
assert!(fx.tcx.is_static(def_id));
|
||||
let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false);
|
||||
let data_id = data_id_for_static(
|
||||
fx.tcx, fx.module, def_id, false,
|
||||
// For a declaration the stated mutability doesn't matter.
|
||||
false,
|
||||
);
|
||||
let local_data_id =
|
||||
fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
|
||||
if fx.clif_comments.enabled() {
|
||||
|
|
@ -232,21 +240,19 @@ fn data_id_for_static(
|
|||
module: &mut dyn Module,
|
||||
def_id: DefId,
|
||||
definition: bool,
|
||||
definition_writable: bool,
|
||||
) -> DataId {
|
||||
let attrs = tcx.codegen_fn_attrs(def_id);
|
||||
|
||||
let instance = Instance::mono(tcx, def_id).polymorphize(tcx);
|
||||
let symbol_name = tcx.symbol_name(instance).name;
|
||||
let ty = instance.ty(tcx, ParamEnv::reveal_all());
|
||||
let is_mutable = if tcx.is_mutable_static(def_id) {
|
||||
true
|
||||
} else {
|
||||
!ty.is_freeze(tcx, ParamEnv::reveal_all())
|
||||
};
|
||||
let align = tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap().align.pref.bytes();
|
||||
|
||||
if let Some(import_linkage) = attrs.import_linkage {
|
||||
assert!(!definition);
|
||||
assert!(!tcx.is_mutable_static(def_id));
|
||||
|
||||
let ty = instance.ty(tcx, ParamEnv::reveal_all());
|
||||
let align = tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap().align.pref.bytes();
|
||||
|
||||
let linkage = if import_linkage == rustc_middle::mir::mono::Linkage::ExternalWeak
|
||||
|| import_linkage == rustc_middle::mir::mono::Linkage::WeakAny
|
||||
|
|
@ -259,7 +265,7 @@ fn data_id_for_static(
|
|||
let data_id = match module.declare_data(
|
||||
symbol_name,
|
||||
linkage,
|
||||
is_mutable,
|
||||
false,
|
||||
attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL),
|
||||
) {
|
||||
Ok(data_id) => data_id,
|
||||
|
|
@ -307,7 +313,7 @@ fn data_id_for_static(
|
|||
let data_id = match module.declare_data(
|
||||
symbol_name,
|
||||
linkage,
|
||||
is_mutable,
|
||||
definition_writable,
|
||||
attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL),
|
||||
) {
|
||||
Ok(data_id) => data_id,
|
||||
|
|
@ -341,7 +347,13 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
|
|||
|
||||
let alloc = tcx.eval_static_initializer(def_id).unwrap();
|
||||
|
||||
let data_id = data_id_for_static(tcx, module, def_id, true);
|
||||
let data_id = data_id_for_static(
|
||||
tcx,
|
||||
module,
|
||||
def_id,
|
||||
true,
|
||||
alloc.inner().mutability == Mutability::Mut,
|
||||
);
|
||||
(data_id, alloc, section_name)
|
||||
}
|
||||
};
|
||||
|
|
@ -421,7 +433,11 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
|
|||
// Don't push a `TodoItem::Static` here, as it will cause statics used by
|
||||
// multiple crates to be duplicated between them. It isn't necessary anyway,
|
||||
// as it will get pushed by `codegen_static` when necessary.
|
||||
data_id_for_static(tcx, module, def_id, false)
|
||||
data_id_for_static(
|
||||
tcx, module, def_id, false,
|
||||
// For a declaration the stated mutability doesn't matter.
|
||||
false,
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1216,20 +1216,29 @@ fn add_sanitizer_libraries(
|
|||
crate_type: CrateType,
|
||||
linker: &mut dyn Linker,
|
||||
) {
|
||||
if sess.target.is_like_android {
|
||||
// Sanitizer runtime libraries are provided dynamically on Android
|
||||
// targets.
|
||||
return;
|
||||
}
|
||||
|
||||
if sess.opts.unstable_opts.external_clangrt {
|
||||
// Linking against in-tree sanitizer runtimes is disabled via
|
||||
// `-Z external-clangrt`
|
||||
return;
|
||||
}
|
||||
|
||||
if matches!(crate_type, CrateType::Rlib | CrateType::Staticlib) {
|
||||
return;
|
||||
}
|
||||
|
||||
// On macOS and Windows using MSVC the runtimes are distributed as dylibs
|
||||
// which should be linked to both executables and dynamic libraries.
|
||||
// Everywhere else the runtimes are currently distributed as static
|
||||
// libraries which should be linked to executables only.
|
||||
let needs_runtime = !sess.target.is_like_android
|
||||
&& match crate_type {
|
||||
CrateType::Executable => true,
|
||||
CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => {
|
||||
sess.target.is_like_osx || sess.target.is_like_msvc
|
||||
}
|
||||
CrateType::Rlib | CrateType::Staticlib => false,
|
||||
};
|
||||
|
||||
if !needs_runtime {
|
||||
if matches!(crate_type, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro)
|
||||
&& !(sess.target.is_like_osx || sess.target.is_like_msvc)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -929,6 +929,15 @@ impl<'a> Linker for MsvcLinker<'a> {
|
|||
// from the CodeView line tables in the object files.
|
||||
self.cmd.arg("/DEBUG");
|
||||
|
||||
// Default to emitting only the file name of the PDB file into
|
||||
// the binary instead of the full path. Emitting the full path
|
||||
// may leak private information (such as user names).
|
||||
// See https://github.com/rust-lang/rust/issues/87825.
|
||||
//
|
||||
// This default behavior can be overridden by explicitly passing
|
||||
// `-Clink-arg=/PDBALTPATH:...` to rustc.
|
||||
self.cmd.arg("/PDBALTPATH:%_PDB%");
|
||||
|
||||
// This will cause the Microsoft linker to embed .natvis info into the PDB file
|
||||
let natvis_dir_path = self.sess.sysroot.join("lib\\rustlib\\etc");
|
||||
if let Ok(natvis_dir) = fs::read_dir(&natvis_dir_path) {
|
||||
|
|
|
|||
|
|
@ -949,6 +949,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
/// Runs the close in "validation" mode, which means the machine's memory read hooks will be
|
||||
/// suppressed. Needless to say, this must only be set with great care! Cannot be nested.
|
||||
pub(super) fn run_for_validation<R>(&self, f: impl FnOnce() -> R) -> R {
|
||||
// This deliberately uses `==` on `bool` to follow the pattern
|
||||
// `assert!(val.replace(new) == old)`.
|
||||
assert!(
|
||||
self.memory.validation_in_progress.replace(true) == false,
|
||||
"`validation_in_progress` was already set"
|
||||
|
|
|
|||
|
|
@ -18,8 +18,14 @@ impl Mmap {
|
|||
/// However in practice most callers do not ensure this, so uses of this function are likely unsound.
|
||||
#[inline]
|
||||
pub unsafe fn map(file: File) -> io::Result<Self> {
|
||||
// Safety: the caller must ensure that this is safe.
|
||||
unsafe { memmap2::Mmap::map(&file).map(Mmap) }
|
||||
// By default, memmap2 creates shared mappings, implying that we could see updates to the
|
||||
// file through the mapping. That would violate our precondition; so by requesting a
|
||||
// map_copy_read_only we do not lose anything.
|
||||
// This mapping mode also improves our support for filesystems such as cacheless virtiofs.
|
||||
// For more details see https://github.com/rust-lang/rust/issues/122262
|
||||
//
|
||||
// SAFETY: The caller must ensure that this is safe.
|
||||
unsafe { memmap2::MmapOptions::new().map_copy_read_only(&file).map(Mmap) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -580,6 +580,13 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
"`may_dangle` has unstable semantics and may be removed in the future",
|
||||
),
|
||||
|
||||
rustc_attr!(
|
||||
rustc_never_type_mode, Normal, template!(NameValueStr: "fallback_to_unit|fallback_to_niko|fallback_to_never|no_fallback"), ErrorFollowing,
|
||||
@only_local: true,
|
||||
"`rustc_never_type_fallback` is used to experiment with never type fallback and work on \
|
||||
never type stabilization, and will never be stable"
|
||||
),
|
||||
|
||||
// ==========================================================================
|
||||
// Internal attributes: Runtime related:
|
||||
// ==========================================================================
|
||||
|
|
|
|||
|
|
@ -463,6 +463,10 @@ declare_features! (
|
|||
(unstable, extended_varargs_abi_support, "1.65.0", Some(100189)),
|
||||
/// Allows defining `extern type`s.
|
||||
(unstable, extern_types, "1.23.0", Some(43467)),
|
||||
/// Allow using 128-bit (quad precision) floating point numbers.
|
||||
(unstable, f128, "CURRENT_RUSTC_VERSION", Some(116909)),
|
||||
/// Allow using 16-bit (half precision) floating point numbers.
|
||||
(unstable, f16, "CURRENT_RUSTC_VERSION", Some(116909)),
|
||||
/// Allows the use of `#[ffi_const]` on foreign functions.
|
||||
(unstable, ffi_const, "1.45.0", Some(58328)),
|
||||
/// Allows the use of `#[ffi_pure]` on foreign functions.
|
||||
|
|
|
|||
|
|
@ -2444,7 +2444,7 @@ pub enum PrimTy {
|
|||
|
||||
impl PrimTy {
|
||||
/// All of the primitive types
|
||||
pub const ALL: [Self; 17] = [
|
||||
pub const ALL: [Self; 19] = [
|
||||
// any changes here should also be reflected in `PrimTy::from_name`
|
||||
Self::Int(IntTy::I8),
|
||||
Self::Int(IntTy::I16),
|
||||
|
|
@ -2458,9 +2458,10 @@ impl PrimTy {
|
|||
Self::Uint(UintTy::U64),
|
||||
Self::Uint(UintTy::U128),
|
||||
Self::Uint(UintTy::Usize),
|
||||
Self::Float(FloatTy::F16),
|
||||
Self::Float(FloatTy::F32),
|
||||
Self::Float(FloatTy::F64),
|
||||
// FIXME(f16_f128): add these when enabled below
|
||||
Self::Float(FloatTy::F128),
|
||||
Self::Bool,
|
||||
Self::Char,
|
||||
Self::Str,
|
||||
|
|
@ -2508,12 +2509,10 @@ impl PrimTy {
|
|||
sym::u64 => Self::Uint(UintTy::U64),
|
||||
sym::u128 => Self::Uint(UintTy::U128),
|
||||
sym::usize => Self::Uint(UintTy::Usize),
|
||||
sym::f16 => Self::Float(FloatTy::F16),
|
||||
sym::f32 => Self::Float(FloatTy::F32),
|
||||
sym::f64 => Self::Float(FloatTy::F64),
|
||||
// FIXME(f16_f128): enabling these will open the gates of f16 and f128 being
|
||||
// understood by rustc.
|
||||
// sym::f16 => Self::Float(FloatTy::F16),
|
||||
// sym::f128 => Self::Float(FloatTy::F128),
|
||||
sym::f128 => Self::Float(FloatTy::F128),
|
||||
sym::bool => Self::Bool,
|
||||
sym::char => Self::Char,
|
||||
sym::str => Self::Str,
|
||||
|
|
|
|||
|
|
@ -351,6 +351,7 @@ hir_analysis_rpitit_refined = impl trait in impl method signature does not match
|
|||
.label = return type from trait method defined here
|
||||
.unmatched_bound_label = this bound is stronger than that defined on the trait
|
||||
.note = add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
|
||||
.feedback_note = we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information
|
||||
|
||||
hir_analysis_self_in_impl_self =
|
||||
`Self` is not valid in the self type of an impl block
|
||||
|
|
|
|||
|
|
@ -149,7 +149,6 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
|
|||
polarity,
|
||||
param_ty,
|
||||
bounds,
|
||||
false,
|
||||
only_self_bounds,
|
||||
);
|
||||
}
|
||||
|
|
@ -231,14 +230,13 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
|
|||
/// **A note on binders:** given something like `T: for<'a> Iterator<Item = &'a u32>`, the
|
||||
/// `trait_ref` here will be `for<'a> T: Iterator`. The `binding` data however is from *inside*
|
||||
/// the binder (e.g., `&'a u32`) and hence may reference bound regions.
|
||||
#[instrument(level = "debug", skip(self, bounds, speculative, dup_bindings, path_span))]
|
||||
#[instrument(level = "debug", skip(self, bounds, dup_bindings, path_span))]
|
||||
pub(super) fn add_predicates_for_ast_type_binding(
|
||||
&self,
|
||||
hir_ref_id: hir::HirId,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
binding: &hir::TypeBinding<'tcx>,
|
||||
bounds: &mut Bounds<'tcx>,
|
||||
speculative: bool,
|
||||
dup_bindings: &mut FxIndexMap<DefId, Span>,
|
||||
path_span: Span,
|
||||
only_self_bounds: OnlySelfBounds,
|
||||
|
|
@ -317,19 +315,17 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
|
|||
}
|
||||
tcx.check_stability(assoc_item.def_id, Some(hir_ref_id), binding.span, None);
|
||||
|
||||
if !speculative {
|
||||
dup_bindings
|
||||
.entry(assoc_item.def_id)
|
||||
.and_modify(|prev_span| {
|
||||
tcx.dcx().emit_err(errors::ValueOfAssociatedStructAlreadySpecified {
|
||||
span: binding.span,
|
||||
prev_span: *prev_span,
|
||||
item_name: binding.ident,
|
||||
def_path: tcx.def_path_str(assoc_item.container_id(tcx)),
|
||||
});
|
||||
})
|
||||
.or_insert(binding.span);
|
||||
}
|
||||
dup_bindings
|
||||
.entry(assoc_item.def_id)
|
||||
.and_modify(|prev_span| {
|
||||
tcx.dcx().emit_err(errors::ValueOfAssociatedStructAlreadySpecified {
|
||||
span: binding.span,
|
||||
prev_span: *prev_span,
|
||||
item_name: binding.ident,
|
||||
def_path: tcx.def_path_str(assoc_item.container_id(tcx)),
|
||||
});
|
||||
})
|
||||
.or_insert(binding.span);
|
||||
|
||||
let projection_ty = if let ty::AssocKind::Fn = assoc_kind {
|
||||
let mut emitted_bad_param_err = None;
|
||||
|
|
@ -433,9 +429,8 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
|
|||
});
|
||||
|
||||
// Provide the resolved type of the associated constant to `type_of(AnonConst)`.
|
||||
if !speculative
|
||||
&& let hir::TypeBindingKind::Equality { term: hir::Term::Const(anon_const) } =
|
||||
binding.kind
|
||||
if let hir::TypeBindingKind::Equality { term: hir::Term::Const(anon_const) } =
|
||||
binding.kind
|
||||
{
|
||||
let ty = alias_ty.map_bound(|ty| tcx.type_of(ty.def_id).instantiate(tcx, ty.args));
|
||||
// Since the arguments passed to the alias type above may contain early-bound
|
||||
|
|
@ -463,42 +458,40 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
|
|||
hir::Term::Const(ct) => ty::Const::from_anon_const(tcx, ct.def_id).into(),
|
||||
};
|
||||
|
||||
if !speculative {
|
||||
// Find any late-bound regions declared in `ty` that are not
|
||||
// declared in the trait-ref or assoc_item. These are not well-formed.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
|
||||
// for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
|
||||
let late_bound_in_projection_ty =
|
||||
tcx.collect_constrained_late_bound_regions(projection_ty);
|
||||
let late_bound_in_term =
|
||||
tcx.collect_referenced_late_bound_regions(trait_ref.rebind(term));
|
||||
debug!(?late_bound_in_projection_ty);
|
||||
debug!(?late_bound_in_term);
|
||||
// Find any late-bound regions declared in `ty` that are not
|
||||
// declared in the trait-ref or assoc_item. These are not well-formed.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
|
||||
// for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
|
||||
let late_bound_in_projection_ty =
|
||||
tcx.collect_constrained_late_bound_regions(projection_ty);
|
||||
let late_bound_in_term =
|
||||
tcx.collect_referenced_late_bound_regions(trait_ref.rebind(term));
|
||||
debug!(?late_bound_in_projection_ty);
|
||||
debug!(?late_bound_in_term);
|
||||
|
||||
// FIXME: point at the type params that don't have appropriate lifetimes:
|
||||
// struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
|
||||
// ---- ---- ^^^^^^^
|
||||
// NOTE(associated_const_equality): This error should be impossible to trigger
|
||||
// with associated const equality bounds.
|
||||
self.validate_late_bound_regions(
|
||||
late_bound_in_projection_ty,
|
||||
late_bound_in_term,
|
||||
|br_name| {
|
||||
struct_span_code_err!(
|
||||
tcx.dcx(),
|
||||
binding.span,
|
||||
E0582,
|
||||
"binding for associated type `{}` references {}, \
|
||||
which does not appear in the trait input types",
|
||||
binding.ident,
|
||||
br_name
|
||||
)
|
||||
},
|
||||
);
|
||||
}
|
||||
// FIXME: point at the type params that don't have appropriate lifetimes:
|
||||
// struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
|
||||
// ---- ---- ^^^^^^^
|
||||
// NOTE(associated_const_equality): This error should be impossible to trigger
|
||||
// with associated const equality bounds.
|
||||
self.validate_late_bound_regions(
|
||||
late_bound_in_projection_ty,
|
||||
late_bound_in_term,
|
||||
|br_name| {
|
||||
struct_span_code_err!(
|
||||
tcx.dcx(),
|
||||
binding.span,
|
||||
E0582,
|
||||
"binding for associated type `{}` references {}, \
|
||||
which does not appear in the trait input types",
|
||||
binding.ident,
|
||||
br_name
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
// "Desugar" a constraint like `T: Iterator<Item = u32>` this to
|
||||
// the "projection predicate" for:
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ use rustc_span::symbol::{sym, Ident};
|
|||
use rustc_span::{Span, Symbol, DUMMY_SP};
|
||||
use rustc_trait_selection::traits::object_safety_violations_for_assoc_item;
|
||||
|
||||
impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
impl<'tcx> dyn AstConv<'tcx> + '_ {
|
||||
/// On missing type parameters, emit an E0393 error and provide a structured suggestion using
|
||||
/// the type parameter's name as a placeholder.
|
||||
pub(crate) fn complain_about_missing_type_params(
|
||||
|
|
@ -349,6 +349,118 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
})
|
||||
}
|
||||
|
||||
pub(super) fn report_ambiguous_associated_type(
|
||||
&self,
|
||||
span: Span,
|
||||
types: &[String],
|
||||
traits: &[String],
|
||||
name: Symbol,
|
||||
) -> ErrorGuaranteed {
|
||||
let mut err =
|
||||
struct_span_code_err!(self.tcx().dcx(), span, E0223, "ambiguous associated type");
|
||||
if self
|
||||
.tcx()
|
||||
.resolutions(())
|
||||
.confused_type_with_std_module
|
||||
.keys()
|
||||
.any(|full_span| full_span.contains(span))
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_lo(),
|
||||
"you are looking for the module in `std`, not the primitive type",
|
||||
"std::",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else {
|
||||
let mut types = types.to_vec();
|
||||
types.sort();
|
||||
let mut traits = traits.to_vec();
|
||||
traits.sort();
|
||||
match (&types[..], &traits[..]) {
|
||||
([], []) => {
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
format!(
|
||||
"if there were a type named `Type` that implements a trait named \
|
||||
`Trait` with associated type `{name}`, you could use the \
|
||||
fully-qualified path",
|
||||
),
|
||||
format!("<Type as Trait>::{name}"),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
([], [trait_str]) => {
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
format!(
|
||||
"if there were a type named `Example` that implemented `{trait_str}`, \
|
||||
you could use the fully-qualified path",
|
||||
),
|
||||
format!("<Example as {trait_str}>::{name}"),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
([], traits) => {
|
||||
err.span_suggestions(
|
||||
span,
|
||||
format!(
|
||||
"if there were a type named `Example` that implemented one of the \
|
||||
traits with associated type `{name}`, you could use the \
|
||||
fully-qualified path",
|
||||
),
|
||||
traits
|
||||
.iter()
|
||||
.map(|trait_str| format!("<Example as {trait_str}>::{name}"))
|
||||
.collect::<Vec<_>>(),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
([type_str], []) => {
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
format!(
|
||||
"if there were a trait named `Example` with associated type `{name}` \
|
||||
implemented for `{type_str}`, you could use the fully-qualified path",
|
||||
),
|
||||
format!("<{type_str} as Example>::{name}"),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
(types, []) => {
|
||||
err.span_suggestions(
|
||||
span,
|
||||
format!(
|
||||
"if there were a trait named `Example` with associated type `{name}` \
|
||||
implemented for one of the types, you could use the fully-qualified \
|
||||
path",
|
||||
),
|
||||
types
|
||||
.into_iter()
|
||||
.map(|type_str| format!("<{type_str} as Example>::{name}")),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
(types, traits) => {
|
||||
let mut suggestions = vec![];
|
||||
for type_str in types {
|
||||
for trait_str in traits {
|
||||
suggestions.push(format!("<{type_str} as {trait_str}>::{name}"));
|
||||
}
|
||||
}
|
||||
err.span_suggestions(
|
||||
span,
|
||||
"use fully-qualified syntax",
|
||||
suggestions,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
let reported = err.emit();
|
||||
self.set_tainted_by_errors(reported);
|
||||
reported
|
||||
}
|
||||
|
||||
pub(crate) fn complain_about_ambiguous_inherent_assoc_type(
|
||||
&self,
|
||||
name: Ident,
|
||||
|
|
|
|||
|
|
@ -409,15 +409,12 @@ pub fn check_generic_arg_count_for_call(
|
|||
seg: &hir::PathSegment<'_>,
|
||||
is_method_call: IsMethodCall,
|
||||
) -> GenericArgCountResult {
|
||||
let empty_args = hir::GenericArgs::none();
|
||||
let gen_args = seg.args.unwrap_or(&empty_args);
|
||||
let gen_pos = match is_method_call {
|
||||
IsMethodCall::Yes => GenericArgPosition::MethodCall,
|
||||
IsMethodCall::No => GenericArgPosition::Value,
|
||||
};
|
||||
let has_self = generics.parent.is_none() && generics.has_self;
|
||||
|
||||
check_generic_arg_count(tcx, def_id, seg, generics, gen_args, gen_pos, has_self, seg.infer_args)
|
||||
check_generic_arg_count(tcx, def_id, seg, generics, gen_pos, has_self)
|
||||
}
|
||||
|
||||
/// Checks that the correct number of generic arguments have been provided.
|
||||
|
|
@ -428,11 +425,10 @@ pub(crate) fn check_generic_arg_count(
|
|||
def_id: DefId,
|
||||
seg: &hir::PathSegment<'_>,
|
||||
gen_params: &ty::Generics,
|
||||
gen_args: &hir::GenericArgs<'_>,
|
||||
gen_pos: GenericArgPosition,
|
||||
has_self: bool,
|
||||
infer_args: bool,
|
||||
) -> GenericArgCountResult {
|
||||
let gen_args = seg.args();
|
||||
let default_counts = gen_params.own_defaults();
|
||||
let param_counts = gen_params.own_counts();
|
||||
|
||||
|
|
@ -453,7 +449,7 @@ pub(crate) fn check_generic_arg_count(
|
|||
.count();
|
||||
let named_const_param_count = param_counts.consts - synth_const_param_count;
|
||||
let infer_lifetimes =
|
||||
(gen_pos != GenericArgPosition::Type || infer_args) && !gen_args.has_lifetime_params();
|
||||
(gen_pos != GenericArgPosition::Type || seg.infer_args) && !gen_args.has_lifetime_params();
|
||||
|
||||
if gen_pos != GenericArgPosition::Type
|
||||
&& let Some(b) = gen_args.bindings.first()
|
||||
|
|
@ -586,7 +582,7 @@ pub(crate) fn check_generic_arg_count(
|
|||
};
|
||||
|
||||
let args_correct = {
|
||||
let expected_min = if infer_args {
|
||||
let expected_min = if seg.infer_args {
|
||||
0
|
||||
} else {
|
||||
param_counts.consts + named_type_param_count
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamNa
|
|||
|
||||
use super::AstConv;
|
||||
|
||||
impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
impl<'tcx> dyn AstConv<'tcx> + '_ {
|
||||
/// Make sure that we are in the condition to suggest the blanket implementation.
|
||||
pub(super) fn maybe_lint_blanket_trait_impl<G: EmissionGuarantee>(
|
||||
&self,
|
||||
|
|
|
|||
|
|
@ -214,7 +214,7 @@ pub trait CreateInstantiationsForGenericArgsCtxt<'a, 'tcx> {
|
|||
) -> ty::GenericArg<'tcx>;
|
||||
}
|
||||
|
||||
impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
impl<'tcx> dyn AstConv<'tcx> + '_ {
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
pub fn ast_region_to_region(
|
||||
&self,
|
||||
|
|
@ -284,8 +284,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
def_id,
|
||||
&[],
|
||||
item_segment,
|
||||
item_segment.args(),
|
||||
item_segment.infer_args,
|
||||
None,
|
||||
ty::BoundConstness::NotConst,
|
||||
);
|
||||
|
|
@ -330,14 +328,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
/// type itself: `['a]`. The returned `GenericArgsRef` concatenates these two
|
||||
/// lists: `[Vec<u8>, u8, 'a]`.
|
||||
#[instrument(level = "debug", skip(self, span), ret)]
|
||||
fn create_args_for_ast_path<'a>(
|
||||
fn create_args_for_ast_path(
|
||||
&self,
|
||||
span: Span,
|
||||
def_id: DefId,
|
||||
parent_args: &[ty::GenericArg<'tcx>],
|
||||
seg: &hir::PathSegment<'_>,
|
||||
generic_args: &'a hir::GenericArgs<'tcx>,
|
||||
infer_args: bool,
|
||||
segment: &hir::PathSegment<'tcx>,
|
||||
self_ty: Option<Ty<'tcx>>,
|
||||
constness: ty::BoundConstness,
|
||||
) -> (GenericArgsRef<'tcx>, GenericArgCountResult) {
|
||||
|
|
@ -365,12 +361,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
let mut arg_count = check_generic_arg_count(
|
||||
tcx,
|
||||
def_id,
|
||||
seg,
|
||||
segment,
|
||||
generics,
|
||||
generic_args,
|
||||
GenericArgPosition::Type,
|
||||
self_ty.is_some(),
|
||||
infer_args,
|
||||
);
|
||||
|
||||
if let Err(err) = &arg_count.correct
|
||||
|
|
@ -388,7 +382,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
}
|
||||
|
||||
struct InstantiationsForAstPathCtxt<'a, 'tcx> {
|
||||
astconv: &'a (dyn AstConv<'tcx> + 'a),
|
||||
astconv: &'a dyn AstConv<'tcx>,
|
||||
def_id: DefId,
|
||||
generic_args: &'a GenericArgs<'tcx>,
|
||||
span: Span,
|
||||
|
|
@ -547,9 +541,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
astconv: self,
|
||||
def_id,
|
||||
span,
|
||||
generic_args,
|
||||
generic_args: segment.args(),
|
||||
inferred_params: vec![],
|
||||
infer_args,
|
||||
infer_args: segment.infer_args,
|
||||
};
|
||||
if let ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst = constness
|
||||
&& generics.has_self
|
||||
|
|
@ -592,8 +586,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
item_def_id,
|
||||
parent_args,
|
||||
item_segment,
|
||||
item_segment.args(),
|
||||
item_segment.infer_args,
|
||||
None,
|
||||
ty::BoundConstness::NotConst,
|
||||
);
|
||||
|
|
@ -647,7 +639,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
/// where `'a` is a bound region at depth 0. Similarly, the `poly_trait_ref` would be
|
||||
/// `Bar<'a>`. The returned poly-trait-ref will have this binder instantiated explicitly,
|
||||
/// however.
|
||||
#[instrument(level = "debug", skip(self, span, constness, bounds, speculative))]
|
||||
#[instrument(level = "debug", skip(self, span, constness, bounds))]
|
||||
pub(crate) fn instantiate_poly_trait_ref(
|
||||
&self,
|
||||
trait_ref: &hir::TraitRef<'tcx>,
|
||||
|
|
@ -656,12 +648,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
polarity: ty::ImplPolarity,
|
||||
self_ty: Ty<'tcx>,
|
||||
bounds: &mut Bounds<'tcx>,
|
||||
speculative: bool,
|
||||
only_self_bounds: OnlySelfBounds,
|
||||
) -> GenericArgCountResult {
|
||||
let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise());
|
||||
let trait_segment = trait_ref.path.segments.last().unwrap();
|
||||
let args = trait_segment.args();
|
||||
|
||||
self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
|
||||
self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, false);
|
||||
|
|
@ -671,8 +661,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
trait_def_id,
|
||||
&[],
|
||||
trait_segment,
|
||||
args,
|
||||
trait_segment.infer_args,
|
||||
Some(self_ty),
|
||||
constness,
|
||||
);
|
||||
|
|
@ -690,7 +678,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
bounds.push_trait_bound(tcx, poly_trait_ref, span, polarity);
|
||||
|
||||
let mut dup_bindings = FxIndexMap::default();
|
||||
for binding in args.bindings {
|
||||
for binding in trait_segment.args().bindings {
|
||||
// Don't register additional associated type bounds for negative bounds,
|
||||
// since we should have emitten an error for them earlier, and they will
|
||||
// not be well-formed!
|
||||
|
|
@ -708,7 +696,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
poly_trait_ref,
|
||||
binding,
|
||||
bounds,
|
||||
speculative,
|
||||
&mut dup_bindings,
|
||||
binding.span,
|
||||
only_self_bounds,
|
||||
|
|
@ -729,12 +716,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
// FIXME(effects) move all host param things in astconv to hir lowering
|
||||
constness: ty::BoundConstness,
|
||||
) -> ty::TraitRef<'tcx> {
|
||||
let (generic_args, _) = self.create_args_for_ast_trait_ref(
|
||||
self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, is_impl);
|
||||
|
||||
let (generic_args, _) = self.create_args_for_ast_path(
|
||||
span,
|
||||
trait_def_id,
|
||||
self_ty,
|
||||
&[],
|
||||
trait_segment,
|
||||
is_impl,
|
||||
Some(self_ty),
|
||||
constness,
|
||||
);
|
||||
if let Some(b) = trait_segment.args().bindings.first() {
|
||||
|
|
@ -743,30 +732,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
ty::TraitRef::new(self.tcx(), trait_def_id, generic_args)
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, span))]
|
||||
fn create_args_for_ast_trait_ref<'a>(
|
||||
&self,
|
||||
span: Span,
|
||||
trait_def_id: DefId,
|
||||
self_ty: Ty<'tcx>,
|
||||
trait_segment: &'a hir::PathSegment<'tcx>,
|
||||
is_impl: bool,
|
||||
constness: ty::BoundConstness,
|
||||
) -> (GenericArgsRef<'tcx>, GenericArgCountResult) {
|
||||
self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, is_impl);
|
||||
|
||||
self.create_args_for_ast_path(
|
||||
span,
|
||||
trait_def_id,
|
||||
&[],
|
||||
trait_segment,
|
||||
trait_segment.args(),
|
||||
trait_segment.infer_args,
|
||||
Some(self_ty),
|
||||
constness,
|
||||
)
|
||||
}
|
||||
|
||||
fn trait_defines_associated_item_named(
|
||||
&self,
|
||||
trait_def_id: DefId,
|
||||
|
|
@ -801,115 +766,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
}
|
||||
}
|
||||
|
||||
fn report_ambiguous_associated_type(
|
||||
&self,
|
||||
span: Span,
|
||||
types: &[String],
|
||||
traits: &[String],
|
||||
name: Symbol,
|
||||
) -> ErrorGuaranteed {
|
||||
let mut err =
|
||||
struct_span_code_err!(self.tcx().dcx(), span, E0223, "ambiguous associated type");
|
||||
if self
|
||||
.tcx()
|
||||
.resolutions(())
|
||||
.confused_type_with_std_module
|
||||
.keys()
|
||||
.any(|full_span| full_span.contains(span))
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_lo(),
|
||||
"you are looking for the module in `std`, not the primitive type",
|
||||
"std::",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else {
|
||||
let mut types = types.to_vec();
|
||||
types.sort();
|
||||
let mut traits = traits.to_vec();
|
||||
traits.sort();
|
||||
match (&types[..], &traits[..]) {
|
||||
([], []) => {
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
format!(
|
||||
"if there were a type named `Type` that implements a trait named \
|
||||
`Trait` with associated type `{name}`, you could use the \
|
||||
fully-qualified path",
|
||||
),
|
||||
format!("<Type as Trait>::{name}"),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
([], [trait_str]) => {
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
format!(
|
||||
"if there were a type named `Example` that implemented `{trait_str}`, \
|
||||
you could use the fully-qualified path",
|
||||
),
|
||||
format!("<Example as {trait_str}>::{name}"),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
([], traits) => {
|
||||
err.span_suggestions(
|
||||
span,
|
||||
format!(
|
||||
"if there were a type named `Example` that implemented one of the \
|
||||
traits with associated type `{name}`, you could use the \
|
||||
fully-qualified path",
|
||||
),
|
||||
traits.iter().map(|trait_str| format!("<Example as {trait_str}>::{name}")),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
([type_str], []) => {
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
format!(
|
||||
"if there were a trait named `Example` with associated type `{name}` \
|
||||
implemented for `{type_str}`, you could use the fully-qualified path",
|
||||
),
|
||||
format!("<{type_str} as Example>::{name}"),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
(types, []) => {
|
||||
err.span_suggestions(
|
||||
span,
|
||||
format!(
|
||||
"if there were a trait named `Example` with associated type `{name}` \
|
||||
implemented for one of the types, you could use the fully-qualified \
|
||||
path",
|
||||
),
|
||||
types
|
||||
.into_iter()
|
||||
.map(|type_str| format!("<{type_str} as Example>::{name}")),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
(types, traits) => {
|
||||
let mut suggestions = vec![];
|
||||
for type_str in types {
|
||||
for trait_str in traits {
|
||||
suggestions.push(format!("<{type_str} as {trait_str}>::{name}"));
|
||||
}
|
||||
}
|
||||
err.span_suggestions(
|
||||
span,
|
||||
"use fully-qualified syntax",
|
||||
suggestions,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
let reported = err.emit();
|
||||
self.set_tainted_by_errors(reported);
|
||||
reported
|
||||
}
|
||||
|
||||
// Search for a bound on a type parameter which includes the associated item
|
||||
// given by `assoc_name`. `ty_param_def_id` is the `DefId` of the type parameter
|
||||
// This function will fail if there are no suitable bounds or there is
|
||||
|
|
@ -2471,8 +2327,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
def_id,
|
||||
&[],
|
||||
&hir::PathSegment::invalid(),
|
||||
&GenericArgs::none(),
|
||||
true,
|
||||
None,
|
||||
ty::BoundConstness::NotConst,
|
||||
);
|
||||
|
|
@ -2552,9 +2406,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
|
||||
pub fn ty_of_arg(&self, ty: &hir::Ty<'tcx>, expected_ty: Option<Ty<'tcx>>) -> Ty<'tcx> {
|
||||
match ty.kind {
|
||||
hir::TyKind::Infer if expected_ty.is_some() => {
|
||||
self.record_ty(ty.hir_id, expected_ty.unwrap(), ty.span);
|
||||
expected_ty.unwrap()
|
||||
hir::TyKind::Infer if let Some(expected_ty) = expected_ty => {
|
||||
self.record_ty(ty.hir_id, expected_ty, ty.span);
|
||||
expected_ty
|
||||
}
|
||||
_ => self.ast_ty_to_ty(ty),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ use smallvec::{smallvec, SmallVec};
|
|||
|
||||
use super::AstConv;
|
||||
|
||||
impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
impl<'tcx> dyn AstConv<'tcx> + '_ {
|
||||
pub(super) fn conv_object_ty_poly_trait_ref(
|
||||
&self,
|
||||
span: Span,
|
||||
|
|
@ -44,7 +44,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
ty::ImplPolarity::Positive,
|
||||
dummy_self,
|
||||
&mut bounds,
|
||||
false,
|
||||
// True so we don't populate `bounds` with associated type bounds, even
|
||||
// though they're disallowed from object types.
|
||||
OnlySelfBounds(true),
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use rustc_data_structures::fx::FxIndexSet;
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::infer::{outlives::env::OutlivesEnvironment, TyCtxtInferExt};
|
||||
use rustc_lint_defs::builtin::REFINING_IMPL_TRAIT;
|
||||
use rustc_lint_defs::builtin::{REFINING_IMPL_TRAIT_INTERNAL, REFINING_IMPL_TRAIT_REACHABLE};
|
||||
use rustc_middle::traits::{ObligationCause, Reveal};
|
||||
use rustc_middle::ty::{
|
||||
self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperVisitable, TypeVisitable, TypeVisitor,
|
||||
|
|
@ -23,26 +23,23 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
|
|||
if !tcx.impl_method_has_trait_impl_trait_tys(impl_m.def_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
// unreachable traits don't have any library guarantees, there's no need to do this check.
|
||||
if trait_m
|
||||
let is_internal = trait_m
|
||||
.container_id(tcx)
|
||||
.as_local()
|
||||
.is_some_and(|trait_def_id| !tcx.effective_visibilities(()).is_reachable(trait_def_id))
|
||||
{
|
||||
return;
|
||||
}
|
||||
// If a type in the trait ref is private, then there's also no reason to do this check.
|
||||
|| impl_trait_ref.args.iter().any(|arg| {
|
||||
if let Some(ty) = arg.as_type()
|
||||
&& let Some(self_visibility) = type_visibility(tcx, ty)
|
||||
{
|
||||
return !self_visibility.is_public();
|
||||
}
|
||||
false
|
||||
});
|
||||
|
||||
// If a type in the trait ref is private, then there's also no reason to do this check.
|
||||
let impl_def_id = impl_m.container_id(tcx);
|
||||
for arg in impl_trait_ref.args {
|
||||
if let Some(ty) = arg.as_type()
|
||||
&& let Some(self_visibility) = type_visibility(tcx, ty)
|
||||
&& !self_visibility.is_public()
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let impl_m_args = ty::GenericArgs::identity_for_item(tcx, impl_m.def_id);
|
||||
let trait_m_to_impl_m_args = impl_m_args.rebase_onto(tcx, impl_def_id, impl_trait_ref.args);
|
||||
let bound_trait_m_sig = tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_m_to_impl_m_args);
|
||||
|
|
@ -85,6 +82,7 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
|
|||
trait_m.def_id,
|
||||
impl_m.def_id,
|
||||
None,
|
||||
is_internal,
|
||||
);
|
||||
return;
|
||||
};
|
||||
|
|
@ -104,6 +102,7 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
|
|||
trait_m.def_id,
|
||||
impl_m.def_id,
|
||||
None,
|
||||
is_internal,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
|
@ -198,6 +197,7 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
|
|||
trait_m.def_id,
|
||||
impl_m.def_id,
|
||||
Some(span),
|
||||
is_internal,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
|
@ -235,6 +235,7 @@ fn report_mismatched_rpitit_signature<'tcx>(
|
|||
trait_m_def_id: DefId,
|
||||
impl_m_def_id: DefId,
|
||||
unmatched_bound: Option<Span>,
|
||||
is_internal: bool,
|
||||
) {
|
||||
let mapping = std::iter::zip(
|
||||
tcx.fn_sig(trait_m_def_id).skip_binder().bound_vars(),
|
||||
|
|
@ -287,7 +288,7 @@ fn report_mismatched_rpitit_signature<'tcx>(
|
|||
|
||||
let span = unmatched_bound.unwrap_or(span);
|
||||
tcx.emit_node_span_lint(
|
||||
REFINING_IMPL_TRAIT,
|
||||
if is_internal { REFINING_IMPL_TRAIT_INTERNAL } else { REFINING_IMPL_TRAIT_REACHABLE },
|
||||
tcx.local_def_id_to_hir_id(impl_m_def_id.expect_local()),
|
||||
span,
|
||||
crate::errors::ReturnPositionImplTraitInTraitRefined {
|
||||
|
|
|
|||
|
|
@ -42,8 +42,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
|
|||
if !def_id.is_local() {
|
||||
return None;
|
||||
}
|
||||
let hir_id = tcx.local_def_id_to_hir_id(def_id.expect_local());
|
||||
match tcx.hir_node(hir_id) {
|
||||
match tcx.hir_node_by_def_id(def_id.expect_local()) {
|
||||
Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. }) => {
|
||||
generics.params.is_empty().not().then_some(generics.span)
|
||||
}
|
||||
|
|
@ -57,8 +56,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
|
|||
if !def_id.is_local() {
|
||||
return None;
|
||||
}
|
||||
let hir_id = tcx.local_def_id_to_hir_id(def_id.expect_local());
|
||||
match tcx.hir_node(hir_id) {
|
||||
match tcx.hir_node_by_def_id(def_id.expect_local()) {
|
||||
Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. }) => {
|
||||
Some(generics.where_clause_span)
|
||||
}
|
||||
|
|
@ -79,8 +77,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
|
|||
if !def_id.is_local() {
|
||||
return None;
|
||||
}
|
||||
let hir_id = tcx.local_def_id_to_hir_id(def_id.expect_local());
|
||||
match tcx.hir_node(hir_id) {
|
||||
match tcx.hir_node_by_def_id(def_id.expect_local()) {
|
||||
Node::Item(hir::Item { kind: hir::ItemKind::Fn(fn_sig, _, _), .. }) => {
|
||||
Some(fn_sig.decl.output.span())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ fn get_owner_return_paths(
|
|||
) -> Option<(LocalDefId, ReturnsVisitor<'_>)> {
|
||||
let hir_id = tcx.local_def_id_to_hir_id(def_id);
|
||||
let parent_id = tcx.hir().get_parent_item(hir_id).def_id;
|
||||
tcx.opt_hir_node_by_def_id(parent_id).and_then(|node| node.body_id()).map(|body_id| {
|
||||
tcx.hir_node_by_def_id(parent_id).body_id().map(|body_id| {
|
||||
let body = tcx.hir().body(body_id);
|
||||
let mut visitor = ReturnsVisitor::default();
|
||||
visitor.visit_body(body);
|
||||
|
|
|
|||
|
|
@ -1969,13 +1969,10 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
|
|||
// Match the existing behavior.
|
||||
if pred.is_global() && !pred.has_type_flags(TypeFlags::HAS_BINDER_VARS) {
|
||||
let pred = self.normalize(span, None, pred);
|
||||
let hir_node = tcx.opt_hir_node_by_def_id(self.body_def_id);
|
||||
|
||||
// only use the span of the predicate clause (#90869)
|
||||
|
||||
if let Some(hir::Generics { predicates, .. }) =
|
||||
hir_node.and_then(|node| node.generics())
|
||||
{
|
||||
let hir_node = tcx.hir_node_by_def_id(self.body_def_id);
|
||||
if let Some(hir::Generics { predicates, .. }) = hir_node.generics() {
|
||||
span = predicates
|
||||
.iter()
|
||||
// There seems to be no better way to find out which predicate we are in
|
||||
|
|
|
|||
|
|
@ -595,12 +595,14 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
|
|||
tcx.ensure().type_of(def_id);
|
||||
tcx.ensure().impl_trait_header(def_id);
|
||||
tcx.ensure().predicates_of(def_id);
|
||||
tcx.ensure().associated_items(def_id);
|
||||
}
|
||||
hir::ItemKind::Trait(..) => {
|
||||
tcx.ensure().generics_of(def_id);
|
||||
tcx.ensure().trait_def(def_id);
|
||||
tcx.at(it.span).super_predicates_of(def_id);
|
||||
tcx.ensure().predicates_of(def_id);
|
||||
tcx.ensure().associated_items(def_id);
|
||||
}
|
||||
hir::ItemKind::TraitAlias(..) => {
|
||||
tcx.ensure().generics_of(def_id);
|
||||
|
|
|
|||
|
|
@ -609,10 +609,8 @@ pub(super) fn implied_predicates_with_filter(
|
|||
return tcx.super_predicates_of(trait_def_id);
|
||||
};
|
||||
|
||||
let trait_hir_id = tcx.local_def_id_to_hir_id(trait_def_id);
|
||||
|
||||
let Node::Item(item) = tcx.hir_node(trait_hir_id) else {
|
||||
bug!("trait_node_id {} is not an item", trait_hir_id);
|
||||
let Node::Item(item) = tcx.hir_node_by_def_id(trait_def_id) else {
|
||||
bug!("trait_def_id {trait_def_id:?} is not an item");
|
||||
};
|
||||
|
||||
let (generics, bounds) = match item.kind {
|
||||
|
|
|
|||
|
|
@ -108,8 +108,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
|
|||
.unwrap()
|
||||
.0
|
||||
.def_id;
|
||||
let item_ctxt = &ItemCtxt::new(tcx, item_def_id) as &dyn crate::astconv::AstConv<'_>;
|
||||
let ty = item_ctxt.ast_ty_to_ty(hir_ty);
|
||||
let ty = ItemCtxt::new(tcx, item_def_id).to_ty(hir_ty);
|
||||
|
||||
// Iterate through the generics of the projection to find the one that corresponds to
|
||||
// the def_id that this query was called with. We filter to only type and const args here
|
||||
|
|
|
|||
|
|
@ -371,11 +371,10 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>(
|
|||
return mir_opaque_ty.ty;
|
||||
}
|
||||
|
||||
let scope = tcx.local_def_id_to_hir_id(owner_def_id);
|
||||
debug!(?scope);
|
||||
debug!(?owner_def_id);
|
||||
let mut locator = RpitConstraintChecker { def_id, tcx, found: mir_opaque_ty };
|
||||
|
||||
match tcx.hir_node(scope) {
|
||||
match tcx.hir_node_by_def_id(owner_def_id) {
|
||||
Node::Item(it) => intravisit::walk_item(&mut locator, it),
|
||||
Node::ImplItem(it) => intravisit::walk_impl_item(&mut locator, it),
|
||||
Node::TraitItem(it) => intravisit::walk_trait_item(&mut locator, it),
|
||||
|
|
|
|||
|
|
@ -1072,6 +1072,7 @@ pub struct UnusedAssociatedTypeBounds {
|
|||
#[derive(LintDiagnostic)]
|
||||
#[diag(hir_analysis_rpitit_refined)]
|
||||
#[note]
|
||||
#[note(hir_analysis_feedback_note)]
|
||||
pub(crate) struct ReturnPositionImplTraitInTraitRefined<'tcx> {
|
||||
#[suggestion(applicability = "maybe-incorrect", code = "{pre}{return_ty}{post}")]
|
||||
pub impl_return_span: Span,
|
||||
|
|
|
|||
|
|
@ -100,19 +100,16 @@ mod variance;
|
|||
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_middle::middle;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{Ty, TyCtxt};
|
||||
use rustc_middle::util;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::{symbol::sym, Span, DUMMY_SP};
|
||||
use rustc_span::{symbol::sym, Span};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use rustc_trait_selection::traits;
|
||||
|
||||
use astconv::{AstConv, OnlySelfBounds};
|
||||
use bounds::Bounds;
|
||||
use rustc_hir::def::DefKind;
|
||||
|
||||
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||
|
||||
fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) {
|
||||
|
|
@ -222,31 +219,5 @@ pub fn hir_ty_to_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx>
|
|||
// def-ID that will be used to determine the traits/predicates in
|
||||
// scope. This is derived from the enclosing item-like thing.
|
||||
let env_def_id = tcx.hir().get_parent_item(hir_ty.hir_id);
|
||||
let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.def_id);
|
||||
item_cx.astconv().ast_ty_to_ty(hir_ty)
|
||||
}
|
||||
|
||||
pub fn hir_trait_to_predicates<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
hir_trait: &hir::TraitRef<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
) -> Bounds<'tcx> {
|
||||
// In case there are any projections, etc., find the "environment"
|
||||
// def-ID that will be used to determine the traits/predicates in
|
||||
// scope. This is derived from the enclosing item-like thing.
|
||||
let env_def_id = tcx.hir().get_parent_item(hir_trait.hir_ref_id);
|
||||
let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.def_id);
|
||||
let mut bounds = Bounds::default();
|
||||
let _ = &item_cx.astconv().instantiate_poly_trait_ref(
|
||||
hir_trait,
|
||||
DUMMY_SP,
|
||||
ty::BoundConstness::NotConst,
|
||||
ty::ImplPolarity::Positive,
|
||||
self_ty,
|
||||
&mut bounds,
|
||||
true,
|
||||
OnlySelfBounds(false),
|
||||
);
|
||||
|
||||
bounds
|
||||
collect::ItemCtxt::new(tcx, env_def_id.def_id).to_ty(hir_ty)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -234,11 +234,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
// Next, make sure that we have no type expectation.
|
||||
let Some(ret) = self
|
||||
.tcx
|
||||
.opt_hir_node_by_def_id(self.body_id)
|
||||
.and_then(|owner| owner.fn_decl())
|
||||
.map(|decl| decl.output.span())
|
||||
let Some(ret) =
|
||||
self.tcx.hir_node_by_def_id(self.body_id).fn_decl().map(|decl| decl.output.span())
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -780,7 +780,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
decl: &hir::FnDecl<'tcx>,
|
||||
closure_kind: hir::ClosureKind,
|
||||
) -> ty::PolyFnSig<'tcx> {
|
||||
let astconv: &dyn AstConv<'_> = self;
|
||||
let astconv = self.astconv();
|
||||
|
||||
trace!("decl = {:#?}", decl);
|
||||
debug!(?closure_kind);
|
||||
|
|
@ -985,7 +985,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
decl: &hir::FnDecl<'tcx>,
|
||||
guar: ErrorGuaranteed,
|
||||
) -> ty::PolyFnSig<'tcx> {
|
||||
let astconv: &dyn AstConv<'_> = self;
|
||||
let astconv = self.astconv();
|
||||
let err_ty = Ty::new_error(self.tcx, guar);
|
||||
|
||||
let supplied_arguments = decl.inputs.iter().map(|a| {
|
||||
|
|
|
|||
|
|
@ -1071,7 +1071,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
err.span_suggestion_verbose(
|
||||
*span,
|
||||
"use the type name directly",
|
||||
self.tcx.value_path_str_with_args(*alias_to, e_args),
|
||||
self.tcx.value_path_str_with_args(e_def.did(), e_args),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -890,21 +890,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
let encl_item_id = self.tcx.hir().get_parent_item(expr.hir_id);
|
||||
|
||||
if let Some(hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Fn(..),
|
||||
span: encl_fn_span,
|
||||
..
|
||||
}))
|
||||
| Some(hir::Node::TraitItem(hir::TraitItem {
|
||||
if let hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Fn(..), span: encl_fn_span, ..
|
||||
})
|
||||
| hir::Node::TraitItem(hir::TraitItem {
|
||||
kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)),
|
||||
span: encl_fn_span,
|
||||
..
|
||||
}))
|
||||
| Some(hir::Node::ImplItem(hir::ImplItem {
|
||||
})
|
||||
| hir::Node::ImplItem(hir::ImplItem {
|
||||
kind: hir::ImplItemKind::Fn(..),
|
||||
span: encl_fn_span,
|
||||
..
|
||||
})) = self.tcx.opt_hir_node_by_def_id(encl_item_id.def_id)
|
||||
}) = self.tcx.hir_node_by_def_id(encl_item_id.def_id)
|
||||
{
|
||||
// We are inside a function body, so reporting "return statement
|
||||
// outside of function body" needs an explanation.
|
||||
|
|
|
|||
|
|
@ -4,8 +4,22 @@ use rustc_data_structures::{
|
|||
graph::{iterate::DepthFirstSearch, vec_graph::VecGraph},
|
||||
unord::{UnordBag, UnordMap, UnordSet},
|
||||
};
|
||||
use rustc_hir::def_id::CRATE_DEF_ID;
|
||||
use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_span::sym;
|
||||
|
||||
enum DivergingFallbackBehavior {
|
||||
/// Always fallback to `()` (aka "always spontaneous decay")
|
||||
FallbackToUnit,
|
||||
/// Sometimes fallback to `!`, but mainly fallback to `()` so that most of the crates are not broken.
|
||||
FallbackToNiko,
|
||||
/// Always fallback to `!` (which should be equivalent to never falling back + not making
|
||||
/// never-to-any coercions unless necessary)
|
||||
FallbackToNever,
|
||||
/// Don't fallback at all
|
||||
NoFallback,
|
||||
}
|
||||
|
||||
impl<'tcx> FnCtxt<'_, 'tcx> {
|
||||
/// Performs type inference fallback, setting `FnCtxt::fallback_has_occurred`
|
||||
|
|
@ -64,7 +78,9 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
|||
return false;
|
||||
}
|
||||
|
||||
let diverging_fallback = self.calculate_diverging_fallback(&unresolved_variables);
|
||||
let diverging_behavior = self.diverging_fallback_behavior();
|
||||
let diverging_fallback =
|
||||
self.calculate_diverging_fallback(&unresolved_variables, diverging_behavior);
|
||||
|
||||
// We do fallback in two passes, to try to generate
|
||||
// better error messages.
|
||||
|
|
@ -78,6 +94,32 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
|||
fallback_occurred
|
||||
}
|
||||
|
||||
fn diverging_fallback_behavior(&self) -> DivergingFallbackBehavior {
|
||||
let Some((mode, span)) = self
|
||||
.tcx
|
||||
.get_attr(CRATE_DEF_ID, sym::rustc_never_type_mode)
|
||||
.map(|attr| (attr.value_str().unwrap(), attr.span))
|
||||
else {
|
||||
if self.tcx.features().never_type_fallback {
|
||||
return DivergingFallbackBehavior::FallbackToNiko;
|
||||
}
|
||||
|
||||
return DivergingFallbackBehavior::FallbackToUnit;
|
||||
};
|
||||
|
||||
match mode {
|
||||
sym::fallback_to_unit => DivergingFallbackBehavior::FallbackToUnit,
|
||||
sym::fallback_to_niko => DivergingFallbackBehavior::FallbackToNiko,
|
||||
sym::fallback_to_never => DivergingFallbackBehavior::FallbackToNever,
|
||||
sym::no_fallback => DivergingFallbackBehavior::NoFallback,
|
||||
_ => {
|
||||
self.tcx.dcx().span_err(span, format!("unknown never type mode: `{mode}` (supported: `fallback_to_unit`, `fallback_to_niko`, `fallback_to_never` and `no_fallback`)"));
|
||||
|
||||
DivergingFallbackBehavior::FallbackToUnit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fallback_effects(&self) -> bool {
|
||||
let unsolved_effects = self.unsolved_effects();
|
||||
|
||||
|
|
@ -232,6 +274,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
|||
fn calculate_diverging_fallback(
|
||||
&self,
|
||||
unresolved_variables: &[Ty<'tcx>],
|
||||
behavior: DivergingFallbackBehavior,
|
||||
) -> UnordMap<Ty<'tcx>, Ty<'tcx>> {
|
||||
debug!("calculate_diverging_fallback({:?})", unresolved_variables);
|
||||
|
||||
|
|
@ -345,39 +388,61 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
|||
output: infer_var_infos.items().any(|info| info.output),
|
||||
};
|
||||
|
||||
if found_infer_var_info.self_in_trait && found_infer_var_info.output {
|
||||
// This case falls back to () to ensure that the code pattern in
|
||||
// tests/ui/never_type/fallback-closure-ret.rs continues to
|
||||
// compile when never_type_fallback is enabled.
|
||||
//
|
||||
// This rule is not readily explainable from first principles,
|
||||
// but is rather intended as a patchwork fix to ensure code
|
||||
// which compiles before the stabilization of never type
|
||||
// fallback continues to work.
|
||||
//
|
||||
// Typically this pattern is encountered in a function taking a
|
||||
// closure as a parameter, where the return type of that closure
|
||||
// (checked by `relationship.output`) is expected to implement
|
||||
// some trait (checked by `relationship.self_in_trait`). This
|
||||
// can come up in non-closure cases too, so we do not limit this
|
||||
// rule to specifically `FnOnce`.
|
||||
//
|
||||
// When the closure's body is something like `panic!()`, the
|
||||
// return type would normally be inferred to `!`. However, it
|
||||
// needs to fall back to `()` in order to still compile, as the
|
||||
// trait is specifically implemented for `()` but not `!`.
|
||||
//
|
||||
// For details on the requirements for these relationships to be
|
||||
// set, see the relationship finding module in
|
||||
// compiler/rustc_trait_selection/src/traits/relationships.rs.
|
||||
debug!("fallback to () - found trait and projection: {:?}", diverging_vid);
|
||||
diverging_fallback.insert(diverging_ty, self.tcx.types.unit);
|
||||
} else if can_reach_non_diverging {
|
||||
debug!("fallback to () - reached non-diverging: {:?}", diverging_vid);
|
||||
diverging_fallback.insert(diverging_ty, self.tcx.types.unit);
|
||||
} else {
|
||||
debug!("fallback to ! - all diverging: {:?}", diverging_vid);
|
||||
diverging_fallback.insert(diverging_ty, Ty::new_diverging_default(self.tcx));
|
||||
use DivergingFallbackBehavior::*;
|
||||
match behavior {
|
||||
FallbackToUnit => {
|
||||
debug!("fallback to () - legacy: {:?}", diverging_vid);
|
||||
diverging_fallback.insert(diverging_ty, self.tcx.types.unit);
|
||||
}
|
||||
FallbackToNiko => {
|
||||
if found_infer_var_info.self_in_trait && found_infer_var_info.output {
|
||||
// This case falls back to () to ensure that the code pattern in
|
||||
// tests/ui/never_type/fallback-closure-ret.rs continues to
|
||||
// compile when never_type_fallback is enabled.
|
||||
//
|
||||
// This rule is not readily explainable from first principles,
|
||||
// but is rather intended as a patchwork fix to ensure code
|
||||
// which compiles before the stabilization of never type
|
||||
// fallback continues to work.
|
||||
//
|
||||
// Typically this pattern is encountered in a function taking a
|
||||
// closure as a parameter, where the return type of that closure
|
||||
// (checked by `relationship.output`) is expected to implement
|
||||
// some trait (checked by `relationship.self_in_trait`). This
|
||||
// can come up in non-closure cases too, so we do not limit this
|
||||
// rule to specifically `FnOnce`.
|
||||
//
|
||||
// When the closure's body is something like `panic!()`, the
|
||||
// return type would normally be inferred to `!`. However, it
|
||||
// needs to fall back to `()` in order to still compile, as the
|
||||
// trait is specifically implemented for `()` but not `!`.
|
||||
//
|
||||
// For details on the requirements for these relationships to be
|
||||
// set, see the relationship finding module in
|
||||
// compiler/rustc_trait_selection/src/traits/relationships.rs.
|
||||
debug!("fallback to () - found trait and projection: {:?}", diverging_vid);
|
||||
diverging_fallback.insert(diverging_ty, self.tcx.types.unit);
|
||||
} else if can_reach_non_diverging {
|
||||
debug!("fallback to () - reached non-diverging: {:?}", diverging_vid);
|
||||
diverging_fallback.insert(diverging_ty, self.tcx.types.unit);
|
||||
} else {
|
||||
debug!("fallback to ! - all diverging: {:?}", diverging_vid);
|
||||
diverging_fallback.insert(diverging_ty, self.tcx.types.never);
|
||||
}
|
||||
}
|
||||
FallbackToNever => {
|
||||
debug!(
|
||||
"fallback to ! - `rustc_never_type_mode = \"fallback_to_never\")`: {:?}",
|
||||
diverging_vid
|
||||
);
|
||||
diverging_fallback.insert(diverging_ty, self.tcx.types.never);
|
||||
}
|
||||
NoFallback => {
|
||||
debug!(
|
||||
"no fallback - `rustc_never_type_mode = \"no_fallback\"`: {:?}",
|
||||
diverging_vid
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2172,16 +2172,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// Try to find earlier invocations of this closure to find if the type mismatch
|
||||
// is because of inference. If we find one, point at them.
|
||||
let mut call_finder = FindClosureArg { tcx: self.tcx, calls: vec![] };
|
||||
let node = self
|
||||
.tcx
|
||||
.opt_local_def_id_to_hir_id(
|
||||
self.tcx.hir().get_parent_item(call_expr.hir_id).def_id,
|
||||
)
|
||||
.map(|hir_id| self.tcx.hir_node(hir_id));
|
||||
match node {
|
||||
Some(hir::Node::Item(item)) => call_finder.visit_item(item),
|
||||
Some(hir::Node::TraitItem(item)) => call_finder.visit_trait_item(item),
|
||||
Some(hir::Node::ImplItem(item)) => call_finder.visit_impl_item(item),
|
||||
let parent_def_id = self.tcx.hir().get_parent_item(call_expr.hir_id).def_id;
|
||||
match self.tcx.hir_node_by_def_id(parent_def_id) {
|
||||
hir::Node::Item(item) => call_finder.visit_item(item),
|
||||
hir::Node::TraitItem(item) => call_finder.visit_trait_item(item),
|
||||
hir::Node::ImplItem(item) => call_finder.visit_impl_item(item),
|
||||
_ => {}
|
||||
}
|
||||
let typeck = self.typeck_results.borrow();
|
||||
|
|
|
|||
|
|
@ -2126,8 +2126,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
let TypeError::FixedArraySize(sz) = terr else {
|
||||
return None;
|
||||
};
|
||||
let tykind = match self.tcx.opt_hir_node_by_def_id(trace.cause.body_id) {
|
||||
Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) => {
|
||||
let tykind = match self.tcx.hir_node_by_def_id(trace.cause.body_id) {
|
||||
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. }) => {
|
||||
let body = hir.body(*body_id);
|
||||
struct LetVisitor {
|
||||
span: Span,
|
||||
|
|
@ -2156,7 +2156,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
}
|
||||
LetVisitor { span }.visit_body(body).break_value()
|
||||
}
|
||||
Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _, _), .. })) => {
|
||||
hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _, _), .. }) => {
|
||||
Some(&ty.peel_refs().kind)
|
||||
}
|
||||
_ => None,
|
||||
|
|
@ -2527,15 +2527,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
.filter(|p| matches!(p.kind, ty::GenericParamDefKind::Lifetime))
|
||||
.map(|p| p.name)
|
||||
.collect::<Vec<_>>();
|
||||
if let Some(hir_id) = self.tcx.opt_local_def_id_to_hir_id(lifetime_scope) {
|
||||
// consider late-bound lifetimes ...
|
||||
used_names.extend(self.tcx.late_bound_vars(hir_id).into_iter().filter_map(|p| {
|
||||
match p {
|
||||
ty::BoundVariableKind::Region(lt) => lt.get_name(),
|
||||
_ => None,
|
||||
}
|
||||
}))
|
||||
}
|
||||
let hir_id = self.tcx.local_def_id_to_hir_id(lifetime_scope);
|
||||
// consider late-bound lifetimes ...
|
||||
used_names.extend(self.tcx.late_bound_vars(hir_id).into_iter().filter_map(
|
||||
|p| match p {
|
||||
ty::BoundVariableKind::Region(lt) => lt.get_name(),
|
||||
_ => None,
|
||||
},
|
||||
));
|
||||
(b'a'..=b'z')
|
||||
.map(|c| format!("'{}", c as char))
|
||||
.find(|candidate| !used_names.iter().any(|e| e.as_str() == candidate))
|
||||
|
|
|
|||
|
|
@ -459,7 +459,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
|||
tcx.hir().trait_impls(trait_did).iter().find_map(|&impl_did| {
|
||||
if let Node::Item(Item {
|
||||
kind: ItemKind::Impl(hir::Impl { self_ty, .. }), ..
|
||||
}) = tcx.opt_hir_node_by_def_id(impl_did)?
|
||||
}) = tcx.hir_node_by_def_id(impl_did)
|
||||
&& trait_objects.iter().all(|did| {
|
||||
// FIXME: we should check `self_ty` against the receiver
|
||||
// type in the `UnifyReceiver` context, but for now, use
|
||||
|
|
|
|||
|
|
@ -804,23 +804,22 @@ fn foo(&self) -> Self::T { String::new() }
|
|||
) -> bool {
|
||||
let tcx = self.tcx;
|
||||
|
||||
let Some(hir_id) = body_owner_def_id.as_local() else {
|
||||
return false;
|
||||
};
|
||||
let Some(hir_id) = tcx.opt_local_def_id_to_hir_id(hir_id) else {
|
||||
let Some(def_id) = body_owner_def_id.as_local() else {
|
||||
return false;
|
||||
};
|
||||
|
||||
// When `body_owner` is an `impl` or `trait` item, look in its associated types for
|
||||
// `expected` and point at it.
|
||||
let hir_id = tcx.local_def_id_to_hir_id(def_id);
|
||||
let parent_id = tcx.hir().get_parent_item(hir_id);
|
||||
let item = tcx.opt_hir_node_by_def_id(parent_id.def_id);
|
||||
let item = tcx.hir_node_by_def_id(parent_id.def_id);
|
||||
|
||||
debug!("expected_projection parent item {:?}", item);
|
||||
|
||||
let param_env = tcx.param_env(body_owner_def_id);
|
||||
|
||||
match item {
|
||||
Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Trait(.., items), .. })) => {
|
||||
hir::Node::Item(hir::Item { kind: hir::ItemKind::Trait(.., items), .. }) => {
|
||||
// FIXME: account for `#![feature(specialization)]`
|
||||
for item in &items[..] {
|
||||
match item.kind {
|
||||
|
|
@ -845,10 +844,10 @@ fn foo(&self) -> Self::T { String::new() }
|
|||
}
|
||||
}
|
||||
}
|
||||
Some(hir::Node::Item(hir::Item {
|
||||
hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Impl(hir::Impl { items, .. }),
|
||||
..
|
||||
})) => {
|
||||
}) => {
|
||||
for item in &items[..] {
|
||||
if let hir::AssocItemKind::Type = item.kind {
|
||||
let assoc_ty = tcx.type_of(item.id.owner_id).instantiate_identity();
|
||||
|
|
|
|||
|
|
@ -2468,6 +2468,8 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
|
|||
ty: Ty<'tcx>,
|
||||
init: InitKind,
|
||||
) -> Option<InitError> {
|
||||
let ty = cx.tcx.try_normalize_erasing_regions(cx.param_env, ty).unwrap_or(ty);
|
||||
|
||||
use rustc_type_ir::TyKind::*;
|
||||
match ty.kind() {
|
||||
// Primitive types that don't like 0 as a value.
|
||||
|
|
|
|||
|
|
@ -313,6 +313,12 @@ fn register_builtins(store: &mut LintStore) {
|
|||
// MACRO_USE_EXTERN_CRATE
|
||||
);
|
||||
|
||||
add_lint_group!(
|
||||
"refining_impl_trait",
|
||||
REFINING_IMPL_TRAIT_REACHABLE,
|
||||
REFINING_IMPL_TRAIT_INTERNAL
|
||||
);
|
||||
|
||||
// Register renamed and removed lints.
|
||||
store.register_renamed("single_use_lifetime", "single_use_lifetimes");
|
||||
store.register_renamed("elided_lifetime_in_path", "elided_lifetimes_in_paths");
|
||||
|
|
|
|||
|
|
@ -561,10 +561,11 @@ fn lint_literal<'tcx>(
|
|||
ty::Float(t) => {
|
||||
let is_infinite = match lit.node {
|
||||
ast::LitKind::Float(v, _) => match t {
|
||||
ty::FloatTy::F16 => unimplemented!("f16_f128"),
|
||||
// FIXME(f16_f128): add this check once we have library support
|
||||
ty::FloatTy::F16 => Ok(false),
|
||||
ty::FloatTy::F32 => v.as_str().parse().map(f32::is_infinite),
|
||||
ty::FloatTy::F64 => v.as_str().parse().map(f64::is_infinite),
|
||||
ty::FloatTy::F128 => unimplemented!("f16_f128"),
|
||||
ty::FloatTy::F128 => Ok(false),
|
||||
},
|
||||
_ => bug!(),
|
||||
};
|
||||
|
|
@ -984,7 +985,14 @@ pub fn transparent_newtype_field<'a, 'tcx>(
|
|||
}
|
||||
|
||||
/// Is type known to be non-null?
|
||||
fn ty_is_known_nonnull<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, mode: CItemKind) -> bool {
|
||||
fn ty_is_known_nonnull<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
mode: CItemKind,
|
||||
) -> bool {
|
||||
let ty = tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty);
|
||||
|
||||
match ty.kind() {
|
||||
ty::FnPtr(_) => true,
|
||||
ty::Ref(..) => true,
|
||||
|
|
@ -1004,7 +1012,7 @@ fn ty_is_known_nonnull<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, mode: CItemKind) -
|
|||
def.variants()
|
||||
.iter()
|
||||
.filter_map(|variant| transparent_newtype_field(tcx, variant))
|
||||
.any(|field| ty_is_known_nonnull(tcx, field.ty(tcx, args), mode))
|
||||
.any(|field| ty_is_known_nonnull(tcx, param_env, field.ty(tcx, args), mode))
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
|
|
@ -1012,7 +1020,13 @@ fn ty_is_known_nonnull<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, mode: CItemKind) -
|
|||
|
||||
/// Given a non-null scalar (or transparent) type `ty`, return the nullable version of that type.
|
||||
/// If the type passed in was not scalar, returns None.
|
||||
fn get_nullable_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
|
||||
fn get_nullable_type<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Option<Ty<'tcx>> {
|
||||
let ty = tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty);
|
||||
|
||||
Some(match *ty.kind() {
|
||||
ty::Adt(field_def, field_args) => {
|
||||
let inner_field_ty = {
|
||||
|
|
@ -1028,22 +1042,19 @@ fn get_nullable_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>>
|
|||
.expect("No non-zst fields in transparent type.")
|
||||
.ty(tcx, field_args)
|
||||
};
|
||||
return get_nullable_type(tcx, inner_field_ty);
|
||||
return get_nullable_type(tcx, param_env, inner_field_ty);
|
||||
}
|
||||
ty::Int(ty) => Ty::new_int(tcx, ty),
|
||||
ty::Uint(ty) => Ty::new_uint(tcx, ty),
|
||||
ty::RawPtr(ty_mut) => Ty::new_ptr(tcx, ty_mut),
|
||||
// As these types are always non-null, the nullable equivalent of
|
||||
// Option<T> of these types are their raw pointer counterparts.
|
||||
// `Option<T>` of these types are their raw pointer counterparts.
|
||||
ty::Ref(_region, ty, mutbl) => Ty::new_ptr(tcx, ty::TypeAndMut { ty, mutbl }),
|
||||
ty::FnPtr(..) => {
|
||||
// There is no nullable equivalent for Rust's function pointers -- you
|
||||
// must use an Option<fn(..) -> _> to represent it.
|
||||
ty
|
||||
}
|
||||
|
||||
// We should only ever reach this case if ty_is_known_nonnull is extended
|
||||
// to other types.
|
||||
// There is no nullable equivalent for Rust's function pointers,
|
||||
// you must use an `Option<fn(..) -> _>` to represent it.
|
||||
ty::FnPtr(..) => ty,
|
||||
// We should only ever reach this case if `ty_is_known_nonnull` is
|
||||
// extended to other types.
|
||||
ref unhandled => {
|
||||
debug!(
|
||||
"get_nullable_type: Unhandled scalar kind: {:?} while checking {:?}",
|
||||
|
|
@ -1056,7 +1067,7 @@ fn get_nullable_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>>
|
|||
|
||||
/// Check if this enum can be safely exported based on the "nullable pointer optimization". If it
|
||||
/// can, return the type that `ty` can be safely converted to, otherwise return `None`.
|
||||
/// Currently restricted to function pointers, boxes, references, `core::num::NonZero*`,
|
||||
/// Currently restricted to function pointers, boxes, references, `core::num::NonZero`,
|
||||
/// `core::ptr::NonNull`, and `#[repr(transparent)]` newtypes.
|
||||
/// FIXME: This duplicates code in codegen.
|
||||
pub(crate) fn repr_nullable_ptr<'tcx>(
|
||||
|
|
@ -1075,7 +1086,7 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
|
|||
_ => return None,
|
||||
};
|
||||
|
||||
if !ty_is_known_nonnull(tcx, field_ty, ckind) {
|
||||
if !ty_is_known_nonnull(tcx, param_env, field_ty, ckind) {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
|
@ -1099,10 +1110,10 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
|
|||
WrappingRange { start: 0, end }
|
||||
if end == field_ty_scalar.size(&tcx).unsigned_int_max() - 1 =>
|
||||
{
|
||||
return Some(get_nullable_type(tcx, field_ty).unwrap());
|
||||
return Some(get_nullable_type(tcx, param_env, field_ty).unwrap());
|
||||
}
|
||||
WrappingRange { start: 1, .. } => {
|
||||
return Some(get_nullable_type(tcx, field_ty).unwrap());
|
||||
return Some(get_nullable_type(tcx, param_env, field_ty).unwrap());
|
||||
}
|
||||
WrappingRange { start, end } => {
|
||||
unreachable!("Unhandled start and end range: ({}, {})", start, end)
|
||||
|
|
|
|||
|
|
@ -79,7 +79,8 @@ declare_lint_pass! {
|
|||
PROC_MACRO_BACK_COMPAT,
|
||||
PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
|
||||
PUB_USE_OF_PRIVATE_EXTERN_CRATE,
|
||||
REFINING_IMPL_TRAIT,
|
||||
REFINING_IMPL_TRAIT_INTERNAL,
|
||||
REFINING_IMPL_TRAIT_REACHABLE,
|
||||
RENAMED_AND_REMOVED_LINTS,
|
||||
REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
|
||||
RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES,
|
||||
|
|
@ -130,6 +131,7 @@ declare_lint_pass! {
|
|||
UNUSED_VARIABLES,
|
||||
USELESS_DEPRECATED,
|
||||
WARNINGS,
|
||||
WASM_C_ABI,
|
||||
WHERE_CLAUSES_OBJECT_SAFETY,
|
||||
WRITES_THROUGH_IMMUTABLE_POINTER,
|
||||
// tidy-alphabetical-end
|
||||
|
|
@ -4401,8 +4403,10 @@ declare_lint! {
|
|||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `refining_impl_trait` lint detects usages of return-position impl
|
||||
/// traits in trait signatures which are refined by implementations.
|
||||
/// The `refining_impl_trait_reachable` lint detects `impl Trait` return
|
||||
/// types in method signatures that are refined by a publically reachable
|
||||
/// trait implementation, meaning the implementation adds information about
|
||||
/// the return type that is not present in the trait.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
|
|
@ -4424,7 +4428,7 @@ declare_lint! {
|
|||
/// fn main() {
|
||||
/// // users can observe that the return type of
|
||||
/// // `<&str as AsDisplay>::as_display()` is `&str`.
|
||||
/// let x: &str = "".as_display();
|
||||
/// let _x: &str = "".as_display();
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
|
|
@ -4432,13 +4436,80 @@ declare_lint! {
|
|||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Return-position impl trait in traits (RPITITs) desugar to associated types,
|
||||
/// and callers of methods for types where the implementation is known are
|
||||
/// Callers of methods for types where the implementation is known are
|
||||
/// able to observe the types written in the impl signature. This may be
|
||||
/// intended behavior, but may also pose a semver hazard for authors of libraries
|
||||
/// who do not wish to make stronger guarantees about the types than what is
|
||||
/// written in the trait signature.
|
||||
pub REFINING_IMPL_TRAIT,
|
||||
/// intended behavior, but may also lead to implementation details being
|
||||
/// revealed unintentionally. In particular, it may pose a semver hazard
|
||||
/// for authors of libraries who do not wish to make stronger guarantees
|
||||
/// about the types than what is written in the trait signature.
|
||||
///
|
||||
/// `refining_impl_trait` is a lint group composed of two lints:
|
||||
///
|
||||
/// * `refining_impl_trait_reachable`, for refinements that are publically
|
||||
/// reachable outside a crate, and
|
||||
/// * `refining_impl_trait_internal`, for refinements that are only visible
|
||||
/// within a crate.
|
||||
///
|
||||
/// We are seeking feedback on each of these lints; see issue
|
||||
/// [#121718](https://github.com/rust-lang/rust/issues/121718) for more
|
||||
/// information.
|
||||
pub REFINING_IMPL_TRAIT_REACHABLE,
|
||||
Warn,
|
||||
"impl trait in impl method signature does not match trait method signature",
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `refining_impl_trait_internal` lint detects `impl Trait` return
|
||||
/// types in method signatures that are refined by a trait implementation,
|
||||
/// meaning the implementation adds information about the return type that
|
||||
/// is not present in the trait.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// #![deny(refining_impl_trait)]
|
||||
///
|
||||
/// use std::fmt::Display;
|
||||
///
|
||||
/// trait AsDisplay {
|
||||
/// fn as_display(&self) -> impl Display;
|
||||
/// }
|
||||
///
|
||||
/// impl<'s> AsDisplay for &'s str {
|
||||
/// fn as_display(&self) -> Self {
|
||||
/// *self
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// // users can observe that the return type of
|
||||
/// // `<&str as AsDisplay>::as_display()` is `&str`.
|
||||
/// let _x: &str = "".as_display();
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Callers of methods for types where the implementation is known are
|
||||
/// able to observe the types written in the impl signature. This may be
|
||||
/// intended behavior, but may also lead to implementation details being
|
||||
/// revealed unintentionally. In particular, it may pose a semver hazard
|
||||
/// for authors of libraries who do not wish to make stronger guarantees
|
||||
/// about the types than what is written in the trait signature.
|
||||
///
|
||||
/// `refining_impl_trait` is a lint group composed of two lints:
|
||||
///
|
||||
/// * `refining_impl_trait_reachable`, for refinements that are publically
|
||||
/// reachable outside a crate, and
|
||||
/// * `refining_impl_trait_internal`, for refinements that are only visible
|
||||
/// within a crate.
|
||||
///
|
||||
/// We are seeking feedback on each of these lints; see issue
|
||||
/// [#121718](https://github.com/rust-lang/rust/issues/121718) for more
|
||||
/// information.
|
||||
pub REFINING_IMPL_TRAIT_INTERNAL,
|
||||
Warn,
|
||||
"impl trait in impl method signature does not match trait method signature",
|
||||
}
|
||||
|
|
@ -4564,3 +4635,41 @@ declare_lint! {
|
|||
reference: "issue #120192 <https://github.com/rust-lang/rust/issues/120192>",
|
||||
};
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `wasm_c_abi` lint detects crate dependencies that are incompatible
|
||||
/// with future versions of Rust that will emit spec-compliant C ABI.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,ignore (needs extern crate)
|
||||
/// #![deny(wasm_c_abi)]
|
||||
/// ```
|
||||
///
|
||||
/// This will produce:
|
||||
///
|
||||
/// ```text
|
||||
/// error: the following packages contain code that will be rejected by a future version of Rust: wasm-bindgen v0.2.87
|
||||
/// |
|
||||
/// note: the lint level is defined here
|
||||
/// --> src/lib.rs:1:9
|
||||
/// |
|
||||
/// 1 | #![deny(wasm_c_abi)]
|
||||
/// | ^^^^^^^^^^
|
||||
/// ```
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Rust has historically emitted non-spec-compliant C ABI. This has caused
|
||||
/// incompatibilities between other compilers and Wasm targets. In a future
|
||||
/// version of Rust this will be fixed and therefore dependencies relying
|
||||
/// on the non-spec-compliant C ABI will stop functioning.
|
||||
pub WASM_C_ABI,
|
||||
Warn,
|
||||
"detects dependencies that are incompatible with the Wasm C ABI",
|
||||
@future_incompatible = FutureIncompatibleInfo {
|
||||
reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
|
||||
reference: "issue #71871 <https://github.com/rust-lang/rust/issues/71871>",
|
||||
};
|
||||
crate_level_only
|
||||
}
|
||||
|
|
|
|||
|
|
@ -281,6 +281,8 @@ metadata_unsupported_abi =
|
|||
metadata_unsupported_abi_i686 =
|
||||
ABI not supported by `#[link(kind = "raw-dylib")]` on i686
|
||||
|
||||
metadata_wasm_c_abi =
|
||||
older versions of the `wasm-bindgen` crate will be incompatible with future versions of Rust; please update to `wasm-bindgen` v0.2.88
|
||||
metadata_wasm_import_form =
|
||||
wasm import module must be of the form `wasm_import_module = "string"`
|
||||
|
||||
|
|
|
|||
|
|
@ -31,8 +31,9 @@ use proc_macro::bridge::client::ProcMacro;
|
|||
use std::error::Error;
|
||||
use std::ops::Fn;
|
||||
use std::path::Path;
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
use std::{cmp, iter};
|
||||
use std::{cmp, env, iter};
|
||||
|
||||
/// The backend's way to give the crate store access to the metadata in a library.
|
||||
/// Note that it returns the raw metadata bytes stored in the library file, whether
|
||||
|
|
@ -397,7 +398,8 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
|
|||
name: Symbol,
|
||||
private_dep: Option<bool>,
|
||||
) -> Result<CrateNum, CrateError> {
|
||||
let _prof_timer = self.sess.prof.generic_activity("metadata_register_crate");
|
||||
let _prof_timer =
|
||||
self.sess.prof.generic_activity_with_arg("metadata_register_crate", name.as_str());
|
||||
|
||||
let Library { source, metadata } = lib;
|
||||
let crate_root = metadata.get_root();
|
||||
|
|
@ -985,6 +987,44 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn report_future_incompatible_deps(&self, krate: &ast::Crate) {
|
||||
let name = self.tcx.crate_name(LOCAL_CRATE);
|
||||
|
||||
if name.as_str() == "wasm_bindgen" {
|
||||
let major = env::var("CARGO_PKG_VERSION_MAJOR")
|
||||
.ok()
|
||||
.and_then(|major| u64::from_str(&major).ok());
|
||||
let minor = env::var("CARGO_PKG_VERSION_MINOR")
|
||||
.ok()
|
||||
.and_then(|minor| u64::from_str(&minor).ok());
|
||||
let patch = env::var("CARGO_PKG_VERSION_PATCH")
|
||||
.ok()
|
||||
.and_then(|patch| u64::from_str(&patch).ok());
|
||||
|
||||
match (major, minor, patch) {
|
||||
// v1 or bigger is valid.
|
||||
(Some(1..), _, _) => return,
|
||||
// v0.3 or bigger is valid.
|
||||
(Some(0), Some(3..), _) => return,
|
||||
// v0.2.88 or bigger is valid.
|
||||
(Some(0), Some(2), Some(88..)) => return,
|
||||
// Not using Cargo.
|
||||
(None, None, None) => return,
|
||||
_ => (),
|
||||
}
|
||||
|
||||
// Make a point span rather than covering the whole file
|
||||
let span = krate.spans.inner_span.shrink_to_lo();
|
||||
|
||||
self.sess.psess.buffer_lint(
|
||||
lint::builtin::WASM_C_ABI,
|
||||
span,
|
||||
ast::CRATE_NODE_ID,
|
||||
crate::fluent_generated::metadata_wasm_c_abi,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn postprocess(&mut self, krate: &ast::Crate) {
|
||||
self.inject_forced_externs();
|
||||
self.inject_profiler_runtime(krate);
|
||||
|
|
@ -992,6 +1032,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
|
|||
self.inject_panic_runtime(krate);
|
||||
|
||||
self.report_unused_deps(krate);
|
||||
self.report_future_incompatible_deps(krate);
|
||||
|
||||
info!("{:?}", CrateDump(self.cstore));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1339,8 +1339,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
is_doc_hidden: false,
|
||||
};
|
||||
let attr_iter = tcx
|
||||
.opt_local_def_id_to_hir_id(def_id)
|
||||
.map_or(Default::default(), |hir_id| tcx.hir().attrs(hir_id))
|
||||
.hir()
|
||||
.attrs(tcx.local_def_id_to_hir_id(def_id))
|
||||
.iter()
|
||||
.filter(|attr| analyze_attr(attr, &mut state));
|
||||
|
||||
|
|
|
|||
|
|
@ -158,12 +158,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
self.hir_owner_nodes(owner_id).node()
|
||||
}
|
||||
|
||||
/// Retrieves the `hir::Node` corresponding to `id`, returning `None` if cannot be found.
|
||||
#[inline]
|
||||
pub fn opt_hir_node_by_def_id(self, id: LocalDefId) -> Option<Node<'tcx>> {
|
||||
Some(self.hir_node_by_def_id(id))
|
||||
}
|
||||
|
||||
/// Retrieves the `hir::Node` corresponding to `id`.
|
||||
pub fn hir_node(self, id: HirId) -> Node<'tcx> {
|
||||
self.hir_owner_nodes(id.owner).nodes[id.local_id].node
|
||||
|
|
@ -239,8 +233,7 @@ impl<'hir> Map<'hir> {
|
|||
}
|
||||
|
||||
pub fn get_if_local(self, id: DefId) -> Option<Node<'hir>> {
|
||||
id.as_local()
|
||||
.and_then(|id| Some(self.tcx.hir_node(self.tcx.opt_local_def_id_to_hir_id(id)?)))
|
||||
id.as_local().map(|id| self.tcx.hir_node_by_def_id(id))
|
||||
}
|
||||
|
||||
pub fn get_generics(self, id: LocalDefId) -> Option<&'hir Generics<'hir>> {
|
||||
|
|
@ -304,7 +297,7 @@ impl<'hir> Map<'hir> {
|
|||
/// Given a `LocalDefId`, returns the `BodyId` associated with it,
|
||||
/// if the node is a body owner, otherwise returns `None`.
|
||||
pub fn maybe_body_owned_by(self, id: LocalDefId) -> Option<BodyId> {
|
||||
let node = self.tcx.opt_hir_node_by_def_id(id)?;
|
||||
let node = self.tcx.hir_node_by_def_id(id);
|
||||
let (_, body_id) = associated_body(node)?;
|
||||
Some(body_id)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::fmt;
|
|||
use either::{Either, Left, Right};
|
||||
|
||||
use rustc_apfloat::{
|
||||
ieee::{Double, Single},
|
||||
ieee::{Double, Half, Quad, Single},
|
||||
Float,
|
||||
};
|
||||
use rustc_macros::HashStable;
|
||||
|
|
@ -201,6 +201,11 @@ impl<Prov> Scalar<Prov> {
|
|||
Self::from_int(i, cx.data_layout().pointer_size)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_f16(f: Half) -> Self {
|
||||
Scalar::Int(f.into())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_f32(f: Single) -> Self {
|
||||
Scalar::Int(f.into())
|
||||
|
|
@ -211,6 +216,11 @@ impl<Prov> Scalar<Prov> {
|
|||
Scalar::Int(f.into())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_f128(f: Quad) -> Self {
|
||||
Scalar::Int(f.into())
|
||||
}
|
||||
|
||||
/// This is almost certainly not the method you want! You should dispatch on the type
|
||||
/// and use `to_{u8,u16,...}`/`scalar_to_ptr` to perform ptr-to-int / int-to-ptr casts as needed.
|
||||
///
|
||||
|
|
@ -422,6 +432,11 @@ impl<'tcx, Prov: Provenance> Scalar<Prov> {
|
|||
Ok(F::from_bits(self.to_bits(Size::from_bits(F::BITS))?))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_f16(self) -> InterpResult<'tcx, Half> {
|
||||
self.to_float()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_f32(self) -> InterpResult<'tcx, Single> {
|
||||
self.to_float()
|
||||
|
|
@ -431,4 +446,9 @@ impl<'tcx, Prov: Provenance> Scalar<Prov> {
|
|||
pub fn to_f64(self) -> InterpResult<'tcx, Double> {
|
||||
self.to_float()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_f128(self) -> InterpResult<'tcx, Quad> {
|
||||
self.to_float()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -321,9 +321,13 @@ pub enum ExprKind<'tcx> {
|
|||
Cast {
|
||||
source: ExprId,
|
||||
},
|
||||
/// Forces its contents to be treated as a value expression, not a place
|
||||
/// expression. This is inserted in some places where an operation would
|
||||
/// otherwise be erased completely (e.g. some no-op casts), but we still
|
||||
/// need to ensure that its operand is treated as a value and not a place.
|
||||
Use {
|
||||
source: ExprId,
|
||||
}, // Use a lexpr to get a vexpr.
|
||||
},
|
||||
/// A coercion from `!` to any type.
|
||||
NeverToAny {
|
||||
source: ExprId,
|
||||
|
|
@ -338,6 +342,13 @@ pub enum ExprKind<'tcx> {
|
|||
Loop {
|
||||
body: ExprId,
|
||||
},
|
||||
/// Special expression representing the `let` part of an `if let` or similar construct
|
||||
/// (including `if let` guards in match arms, and let-chains formed by `&&`).
|
||||
///
|
||||
/// This isn't considered a real expression in surface Rust syntax, so it can
|
||||
/// only appear in specific situations, such as within the condition of an `if`.
|
||||
///
|
||||
/// (Not to be confused with [`StmtKind::Let`], which is a normal `let` statement.)
|
||||
Let {
|
||||
expr: ExprId,
|
||||
pat: Box<Pat<'tcx>>,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use rustc_apfloat::ieee::{Double, Single};
|
||||
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
|
||||
use rustc_apfloat::Float;
|
||||
use rustc_errors::{DiagArgValue, IntoDiagArg};
|
||||
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
|
||||
|
|
@ -369,6 +369,11 @@ impl ScalarInt {
|
|||
Ok(F::from_bits(self.to_bits(Size::from_bits(F::BITS))?))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_f16(self) -> Result<Half, Size> {
|
||||
self.try_to_float()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_f32(self) -> Result<Single, Size> {
|
||||
self.try_to_float()
|
||||
|
|
@ -378,6 +383,11 @@ impl ScalarInt {
|
|||
pub fn try_to_f64(self) -> Result<Double, Size> {
|
||||
self.try_to_float()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_f128(self) -> Result<Quad, Size> {
|
||||
self.try_to_float()
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! from {
|
||||
|
|
@ -450,6 +460,22 @@ impl TryFrom<ScalarInt> for char {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Half> for ScalarInt {
|
||||
#[inline]
|
||||
fn from(f: Half) -> Self {
|
||||
// We trust apfloat to give us properly truncated data.
|
||||
Self { data: f.to_bits(), size: NonZero::new((Half::BITS / 8) as u8).unwrap() }
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<ScalarInt> for Half {
|
||||
type Error = Size;
|
||||
#[inline]
|
||||
fn try_from(int: ScalarInt) -> Result<Self, Size> {
|
||||
int.to_bits(Size::from_bytes(2)).map(Self::from_bits)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Single> for ScalarInt {
|
||||
#[inline]
|
||||
fn from(f: Single) -> Self {
|
||||
|
|
@ -482,6 +508,22 @@ impl TryFrom<ScalarInt> for Double {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Quad> for ScalarInt {
|
||||
#[inline]
|
||||
fn from(f: Quad) -> Self {
|
||||
// We trust apfloat to give us properly truncated data.
|
||||
Self { data: f.to_bits(), size: NonZero::new((Quad::BITS / 8) as u8).unwrap() }
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<ScalarInt> for Quad {
|
||||
type Error = Size;
|
||||
#[inline]
|
||||
fn try_from(int: ScalarInt) -> Result<Self, Size> {
|
||||
int.to_bits(Size::from_bytes(16)).map(Self::from_bits)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ScalarInt {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// Dispatch to LowerHex below.
|
||||
|
|
|
|||
|
|
@ -1265,11 +1265,9 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
break (scope, ty::BrNamed(def_id.into(), self.item_name(def_id.into())));
|
||||
};
|
||||
|
||||
let is_impl_item = match self.opt_hir_node_by_def_id(suitable_region_binding_scope) {
|
||||
Some(Node::Item(..) | Node::TraitItem(..)) => false,
|
||||
Some(Node::ImplItem(..)) => {
|
||||
self.is_bound_region_in_impl_item(suitable_region_binding_scope)
|
||||
}
|
||||
let is_impl_item = match self.hir_node_by_def_id(suitable_region_binding_scope) {
|
||||
Node::Item(..) | Node::TraitItem(..) => false,
|
||||
Node::ImplItem(..) => self.is_bound_region_in_impl_item(suitable_region_binding_scope),
|
||||
_ => false,
|
||||
};
|
||||
|
||||
|
|
@ -2355,10 +2353,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
self.intrinsic_raw(def_id)
|
||||
}
|
||||
|
||||
pub fn opt_local_def_id_to_hir_id(self, local_def_id: LocalDefId) -> Option<HirId> {
|
||||
Some(self.local_def_id_to_hir_id(local_def_id))
|
||||
}
|
||||
|
||||
pub fn next_trait_solver_globally(self) -> bool {
|
||||
self.sess.opts.unstable_opts.next_solver.map_or(false, |c| c.globally)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ mir_build_borrow_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe
|
|||
|
||||
mir_build_borrow_of_moved_value = borrow of moved value
|
||||
.label = value moved into `{$name}` here
|
||||
.occurs_because_label = move occurs because `{$name}` has type `{$ty}` which does not implement the `Copy` trait
|
||||
.occurs_because_label = move occurs because `{$name}` has type `{$ty}`, which does not implement the `Copy` trait
|
||||
.value_borrowed_label = value borrowed here after move
|
||||
.suggestion = borrow this binding in the pattern to avoid moving the value
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use crate::build::expr::as_place::PlaceBuilder;
|
||||
use crate::build::scope::DropKind;
|
||||
use itertools::Itertools;
|
||||
use rustc_apfloat::ieee::{Double, Single};
|
||||
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
|
||||
use rustc_apfloat::Float;
|
||||
use rustc_ast::attr;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
|
|
@ -1060,7 +1060,8 @@ pub(crate) fn parse_float_into_scalar(
|
|||
) -> Option<Scalar> {
|
||||
let num = num.as_str();
|
||||
match float_ty {
|
||||
ty::FloatTy::F16 => unimplemented!("f16_f128"),
|
||||
// FIXME(f16_f128): When available, compare to the library parser as with `f32` and `f64`
|
||||
ty::FloatTy::F16 => num.parse::<Half>().ok().map(Scalar::from_f16),
|
||||
ty::FloatTy::F32 => {
|
||||
let Ok(rust_f) = num.parse::<f32>() else { return None };
|
||||
let mut f = num
|
||||
|
|
@ -1107,7 +1108,8 @@ pub(crate) fn parse_float_into_scalar(
|
|||
|
||||
Some(Scalar::from_f64(f))
|
||||
}
|
||||
ty::FloatTy::F128 => unimplemented!("f16_f128"),
|
||||
// FIXME(f16_f128): When available, compare to the library parser as with `f32` and `f64`
|
||||
ty::FloatTy::F128 => num.parse::<Quad>().ok().map(Scalar::from_f128),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -393,7 +393,9 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
Operand::Constant(box constant) => {
|
||||
if let Ok(constant) = self.ecx.eval_mir_constant(&constant.const_, None, None) {
|
||||
if let Ok(constant) =
|
||||
self.ecx.eval_mir_constant(&constant.const_, Some(constant.span), None)
|
||||
{
|
||||
self.assign_constant(state, place, constant, &[]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -416,7 +416,8 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> {
|
|||
match rhs {
|
||||
// If we expect `lhs ?= A`, we have an opportunity if we assume `constant == A`.
|
||||
Operand::Constant(constant) => {
|
||||
let constant = self.ecx.eval_mir_constant(&constant.const_, None, None).ok()?;
|
||||
let constant =
|
||||
self.ecx.eval_mir_constant(&constant.const_, Some(constant.span), None).ok()?;
|
||||
self.process_constant(bb, lhs, constant, state);
|
||||
}
|
||||
// Transfer the conditions on the copied rhs.
|
||||
|
|
|
|||
|
|
@ -828,14 +828,17 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
|
|||
// a codegen-time error). rustc stops after collection if there was an error, so this
|
||||
// ensures codegen never has to worry about failing consts.
|
||||
// (codegen relies on this and ICEs will happen if this is violated.)
|
||||
let val = match const_.eval(self.tcx, param_env, None) {
|
||||
let val = match const_.eval(self.tcx, param_env, Some(constant.span)) {
|
||||
Ok(v) => v,
|
||||
Err(ErrorHandled::Reported(..)) => return,
|
||||
Err(ErrorHandled::TooGeneric(..)) => span_bug!(
|
||||
self.body.source_info(location).span,
|
||||
"collection encountered polymorphic constant: {:?}",
|
||||
const_
|
||||
),
|
||||
Err(err @ ErrorHandled::Reported(..)) => {
|
||||
err.emit_note(self.tcx);
|
||||
return;
|
||||
}
|
||||
};
|
||||
collect_const_value(self.tcx, val, self.output);
|
||||
MirVisitor::visit_ty(self, const_.ty(), TyContext::Location(location));
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ rustc_index = { path = "../rustc_index" }
|
|||
rustc_lexer = { path = "../rustc_lexer" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_middle = { path = "../rustc_middle" }
|
||||
rustc_privacy = { path = "../rustc_privacy" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
rustc_target = { path = "../rustc_target" }
|
||||
|
|
|
|||
|
|
@ -33,15 +33,13 @@ use crate::errors::{
|
|||
// may need to be marked as live.
|
||||
fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
|
||||
matches!(
|
||||
tcx.opt_hir_node_by_def_id(def_id),
|
||||
Some(
|
||||
Node::Item(..)
|
||||
| Node::ImplItem(..)
|
||||
| Node::ForeignItem(..)
|
||||
| Node::TraitItem(..)
|
||||
| Node::Variant(..)
|
||||
| Node::AnonConst(..)
|
||||
)
|
||||
tcx.hir_node_by_def_id(def_id),
|
||||
Node::Item(..)
|
||||
| Node::ImplItem(..)
|
||||
| Node::ForeignItem(..)
|
||||
| Node::TraitItem(..)
|
||||
| Node::Variant(..)
|
||||
| Node::AnonConst(..)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -316,33 +314,31 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
|
|||
// tuple struct constructor function
|
||||
let id = self.struct_constructors.get(&id).copied().unwrap_or(id);
|
||||
|
||||
if let Some(node) = self.tcx.opt_hir_node_by_def_id(id) {
|
||||
// When using `#[allow]` or `#[expect]` of `dead_code`, we do a QOL improvement
|
||||
// by declaring fn calls, statics, ... within said items as live, as well as
|
||||
// the item itself, although technically this is not the case.
|
||||
//
|
||||
// This means that the lint for said items will never be fired.
|
||||
//
|
||||
// This doesn't make any difference for the item declared with `#[allow]`, as
|
||||
// the lint firing will be a nop, as it will be silenced by the `#[allow]` of
|
||||
// the item.
|
||||
//
|
||||
// However, for `#[expect]`, the presence or absence of the lint is relevant,
|
||||
// so we don't add it to the list of live symbols when it comes from a
|
||||
// `#[expect]`. This means that we will correctly report an item as live or not
|
||||
// for the `#[expect]` case.
|
||||
//
|
||||
// Note that an item can and will be duplicated on the worklist with different
|
||||
// `ComesFromAllowExpect`, particularly if it was added from the
|
||||
// `effective_visibilities` query or from the `#[allow]`/`#[expect]` checks,
|
||||
// this "duplication" is essential as otherwise a function with `#[expect]`
|
||||
// called from a `pub fn` may be falsely reported as not live, falsely
|
||||
// triggering the `unfulfilled_lint_expectations` lint.
|
||||
if comes_from_allow_expect != ComesFromAllowExpect::Yes {
|
||||
self.live_symbols.insert(id);
|
||||
}
|
||||
self.visit_node(node);
|
||||
// When using `#[allow]` or `#[expect]` of `dead_code`, we do a QOL improvement
|
||||
// by declaring fn calls, statics, ... within said items as live, as well as
|
||||
// the item itself, although technically this is not the case.
|
||||
//
|
||||
// This means that the lint for said items will never be fired.
|
||||
//
|
||||
// This doesn't make any difference for the item declared with `#[allow]`, as
|
||||
// the lint firing will be a nop, as it will be silenced by the `#[allow]` of
|
||||
// the item.
|
||||
//
|
||||
// However, for `#[expect]`, the presence or absence of the lint is relevant,
|
||||
// so we don't add it to the list of live symbols when it comes from a
|
||||
// `#[expect]`. This means that we will correctly report an item as live or not
|
||||
// for the `#[expect]` case.
|
||||
//
|
||||
// Note that an item can and will be duplicated on the worklist with different
|
||||
// `ComesFromAllowExpect`, particularly if it was added from the
|
||||
// `effective_visibilities` query or from the `#[allow]`/`#[expect]` checks,
|
||||
// this "duplication" is essential as otherwise a function with `#[expect]`
|
||||
// called from a `pub fn` may be falsely reported as not live, falsely
|
||||
// triggering the `unfulfilled_lint_expectations` lint.
|
||||
if comes_from_allow_expect != ComesFromAllowExpect::Yes {
|
||||
self.live_symbols.insert(id);
|
||||
}
|
||||
self.visit_node(self.tcx.hir_node_by_def_id(id));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -739,8 +735,8 @@ fn check_item<'tcx>(
|
|||
for local_def_id in local_def_ids {
|
||||
// check the function may construct Self
|
||||
let mut may_construct_self = true;
|
||||
if let Some(hir_id) = tcx.opt_local_def_id_to_hir_id(local_def_id)
|
||||
&& let Some(fn_sig) = tcx.hir().fn_sig_by_hir_id(hir_id)
|
||||
if let Some(fn_sig) =
|
||||
tcx.hir().fn_sig_by_hir_id(tcx.local_def_id_to_hir_id(local_def_id))
|
||||
{
|
||||
may_construct_self =
|
||||
matches!(fn_sig.decl.implicit_self, hir::ImplicitSelfKind::None);
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId,
|
|||
{
|
||||
// non-local main imports are handled below
|
||||
if let Some(def_id) = def_id.as_local()
|
||||
&& matches!(tcx.opt_hir_node_by_def_id(def_id), Some(Node::ForeignItem(_)))
|
||||
&& matches!(tcx.hir_node_by_def_id(def_id), Node::ForeignItem(_))
|
||||
{
|
||||
tcx.dcx().emit_err(ExternMain { span: tcx.def_span(def_id) });
|
||||
return None;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
// reachable as well.
|
||||
|
||||
use hir::def_id::LocalDefIdSet;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
|
|
@ -15,7 +16,8 @@ use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}
|
|||
use rustc_middle::middle::privacy::{self, Level};
|
||||
use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc};
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_middle::ty::{self, ExistentialTraitRef, TyCtxt};
|
||||
use rustc_privacy::DefIdVisitor;
|
||||
use rustc_session::config::CrateType;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
|
|
@ -65,23 +67,8 @@ impl<'tcx> Visitor<'tcx> for ReachableContext<'tcx> {
|
|||
_ => None,
|
||||
};
|
||||
|
||||
if let Some(res) = res
|
||||
&& let Some(def_id) = res.opt_def_id().and_then(|el| el.as_local())
|
||||
{
|
||||
if self.def_id_represents_local_inlined_item(def_id.to_def_id()) {
|
||||
self.worklist.push(def_id);
|
||||
} else {
|
||||
match res {
|
||||
// Reachable constants and reachable statics can have their contents inlined
|
||||
// into other crates. Mark them as reachable and recurse into their body.
|
||||
Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::Static { .. }, _) => {
|
||||
self.worklist.push(def_id);
|
||||
}
|
||||
_ => {
|
||||
self.reachable_symbols.insert(def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(res) = res {
|
||||
self.propagate_item(res);
|
||||
}
|
||||
|
||||
intravisit::walk_expr(self, expr)
|
||||
|
|
@ -116,26 +103,25 @@ impl<'tcx> ReachableContext<'tcx> {
|
|||
return false;
|
||||
};
|
||||
|
||||
match self.tcx.opt_hir_node_by_def_id(def_id) {
|
||||
Some(Node::Item(item)) => match item.kind {
|
||||
match self.tcx.hir_node_by_def_id(def_id) {
|
||||
Node::Item(item) => match item.kind {
|
||||
hir::ItemKind::Fn(..) => item_might_be_inlined(self.tcx, def_id.into()),
|
||||
_ => false,
|
||||
},
|
||||
Some(Node::TraitItem(trait_method)) => match trait_method.kind {
|
||||
Node::TraitItem(trait_method) => match trait_method.kind {
|
||||
hir::TraitItemKind::Const(_, ref default) => default.is_some(),
|
||||
hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)) => true,
|
||||
hir::TraitItemKind::Fn(_, hir::TraitFn::Required(_))
|
||||
| hir::TraitItemKind::Type(..) => false,
|
||||
},
|
||||
Some(Node::ImplItem(impl_item)) => match impl_item.kind {
|
||||
Node::ImplItem(impl_item) => match impl_item.kind {
|
||||
hir::ImplItemKind::Const(..) => true,
|
||||
hir::ImplItemKind::Fn(..) => {
|
||||
item_might_be_inlined(self.tcx, impl_item.hir_id().owner.to_def_id())
|
||||
}
|
||||
hir::ImplItemKind::Type(_) => false,
|
||||
},
|
||||
Some(_) => false,
|
||||
None => false, // This will happen for default methods.
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -147,9 +133,7 @@ impl<'tcx> ReachableContext<'tcx> {
|
|||
continue;
|
||||
}
|
||||
|
||||
if let Some(ref item) = self.tcx.opt_hir_node_by_def_id(search_item) {
|
||||
self.propagate_node(item, search_item);
|
||||
}
|
||||
self.propagate_node(&self.tcx.hir_node_by_def_id(search_item), search_item);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -201,17 +185,9 @@ impl<'tcx> ReachableContext<'tcx> {
|
|||
hir::ItemKind::Const(_, _, init) => {
|
||||
self.visit_nested_body(init);
|
||||
}
|
||||
|
||||
// Reachable statics are inlined if read from another constant or static
|
||||
// in other crates. Additionally anonymous nested statics may be created
|
||||
// when evaluating a static, so preserve those, too.
|
||||
hir::ItemKind::Static(_, _, init) => {
|
||||
// FIXME(oli-obk): remove this body walking and instead walk the evaluated initializer
|
||||
// to find nested items that end up in the final value instead of also marking symbols
|
||||
// as reachable that are only needed for evaluation.
|
||||
self.visit_nested_body(init);
|
||||
hir::ItemKind::Static(..) => {
|
||||
if let Ok(alloc) = self.tcx.eval_static_initializer(item.owner_id.def_id) {
|
||||
self.propagate_statics_from_alloc(item.owner_id.def_id, alloc);
|
||||
self.propagate_from_alloc(alloc);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -282,28 +258,89 @@ impl<'tcx> ReachableContext<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Finds anonymous nested statics created for nested allocations and adds them to `reachable_symbols`.
|
||||
fn propagate_statics_from_alloc(&mut self, root: LocalDefId, alloc: ConstAllocation<'tcx>) {
|
||||
/// Finds things to add to `reachable_symbols` within allocations.
|
||||
/// In contrast to visit_nested_body this ignores things that were only needed to evaluate
|
||||
/// the allocation.
|
||||
fn propagate_from_alloc(&mut self, alloc: ConstAllocation<'tcx>) {
|
||||
if !self.any_library {
|
||||
return;
|
||||
}
|
||||
for (_, prov) in alloc.0.provenance().ptrs().iter() {
|
||||
match self.tcx.global_alloc(prov.alloc_id()) {
|
||||
GlobalAlloc::Static(def_id) => {
|
||||
if let Some(def_id) = def_id.as_local()
|
||||
&& self.tcx.local_parent(def_id) == root
|
||||
// This is the main purpose of this function: add the def_id we find
|
||||
// to `reachable_symbols`.
|
||||
&& self.reachable_symbols.insert(def_id)
|
||||
&& let Ok(alloc) = self.tcx.eval_static_initializer(def_id)
|
||||
{
|
||||
self.propagate_statics_from_alloc(root, alloc);
|
||||
self.propagate_item(Res::Def(self.tcx.def_kind(def_id), def_id))
|
||||
}
|
||||
GlobalAlloc::Function(instance) => {
|
||||
// Manually visit to actually see the instance's `DefId`. Type visitors won't see it
|
||||
self.propagate_item(Res::Def(
|
||||
self.tcx.def_kind(instance.def_id()),
|
||||
instance.def_id(),
|
||||
));
|
||||
self.visit(instance.args);
|
||||
}
|
||||
GlobalAlloc::VTable(ty, trait_ref) => {
|
||||
self.visit(ty);
|
||||
// Manually visit to actually see the trait's `DefId`. Type visitors won't see it
|
||||
if let Some(trait_ref) = trait_ref {
|
||||
let ExistentialTraitRef { def_id, args } = trait_ref.skip_binder();
|
||||
self.visit_def_id(def_id, "", &"");
|
||||
self.visit(args);
|
||||
}
|
||||
}
|
||||
GlobalAlloc::Function(_) | GlobalAlloc::VTable(_, _) | GlobalAlloc::Memory(_) => {}
|
||||
GlobalAlloc::Memory(alloc) => self.propagate_from_alloc(alloc),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn propagate_item(&mut self, res: Res) {
|
||||
let Res::Def(kind, def_id) = res else { return };
|
||||
let Some(def_id) = def_id.as_local() else { return };
|
||||
match kind {
|
||||
DefKind::Static { nested: true, .. } => {
|
||||
// This is the main purpose of this function: add the def_id we find
|
||||
// to `reachable_symbols`.
|
||||
if self.reachable_symbols.insert(def_id) {
|
||||
if let Ok(alloc) = self.tcx.eval_static_initializer(def_id) {
|
||||
// This cannot cause infinite recursion, because we abort by inserting into the
|
||||
// work list once we hit a normal static. Nested statics, even if they somehow
|
||||
// become recursive, are also not infinitely recursing, because of the
|
||||
// `reachable_symbols` check above.
|
||||
// We still need to protect against stack overflow due to deeply nested statics.
|
||||
ensure_sufficient_stack(|| self.propagate_from_alloc(alloc));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Reachable constants and reachable statics can have their contents inlined
|
||||
// into other crates. Mark them as reachable and recurse into their body.
|
||||
DefKind::Const | DefKind::AssocConst | DefKind::Static { .. } => {
|
||||
self.worklist.push(def_id);
|
||||
}
|
||||
_ => {
|
||||
if self.def_id_represents_local_inlined_item(def_id.to_def_id()) {
|
||||
self.worklist.push(def_id);
|
||||
} else {
|
||||
self.reachable_symbols.insert(def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> DefIdVisitor<'tcx> for ReachableContext<'tcx> {
|
||||
type Result = ();
|
||||
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn visit_def_id(
|
||||
&mut self,
|
||||
def_id: DefId,
|
||||
_kind: &str,
|
||||
_descr: &dyn std::fmt::Display,
|
||||
) -> Self::Result {
|
||||
self.propagate_item(Res::Def(self.tcx.def_kind(def_id), def_id))
|
||||
}
|
||||
}
|
||||
|
||||
fn check_item<'tcx>(
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ impl<'tcx> fmt::Display for LazyDefPathStr<'tcx> {
|
|||
/// First, it doesn't have overridable `fn visit_trait_ref`, so we have to catch trait `DefId`s
|
||||
/// manually. Second, it doesn't visit some type components like signatures of fn types, or traits
|
||||
/// in `impl Trait`, see individual comments in `DefIdVisitorSkeleton::visit_ty`.
|
||||
trait DefIdVisitor<'tcx> {
|
||||
pub trait DefIdVisitor<'tcx> {
|
||||
type Result: VisitorResult = ();
|
||||
const SHALLOW: bool = false;
|
||||
const SKIP_ASSOC_TYS: bool = false;
|
||||
|
|
@ -98,7 +98,7 @@ trait DefIdVisitor<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
struct DefIdVisitorSkeleton<'v, 'tcx, V: ?Sized> {
|
||||
pub struct DefIdVisitorSkeleton<'v, 'tcx, V: ?Sized> {
|
||||
def_id_visitor: &'v mut V,
|
||||
visited_opaque_tys: FxHashSet<DefId>,
|
||||
dummy: PhantomData<TyCtxt<'tcx>>,
|
||||
|
|
|
|||
|
|
@ -5,8 +5,10 @@ use rustc_middle::bug;
|
|||
use rustc_middle::ty;
|
||||
use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK;
|
||||
use rustc_session::lint::BuiltinLintDiag;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext};
|
||||
use rustc_span::sym;
|
||||
use rustc_span::symbol::{kw, Ident};
|
||||
use rustc_span::Span;
|
||||
|
||||
|
|
@ -598,7 +600,35 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
result
|
||||
}
|
||||
Scope::BuiltinTypes => match this.builtin_types_bindings.get(&ident.name) {
|
||||
Some(binding) => Ok((*binding, Flags::empty())),
|
||||
Some(binding) => {
|
||||
if matches!(ident.name, sym::f16)
|
||||
&& !this.tcx.features().f16
|
||||
&& !ident.span.allows_unstable(sym::f16)
|
||||
&& finalize.is_some()
|
||||
{
|
||||
feature_err(
|
||||
this.tcx.sess,
|
||||
sym::f16,
|
||||
ident.span,
|
||||
"the type `f16` is unstable",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
if matches!(ident.name, sym::f128)
|
||||
&& !this.tcx.features().f128
|
||||
&& !ident.span.allows_unstable(sym::f128)
|
||||
&& finalize.is_some()
|
||||
{
|
||||
feature_err(
|
||||
this.tcx.sess,
|
||||
sym::f128,
|
||||
ident.span,
|
||||
"the type `f128` is unstable",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
Ok((*binding, Flags::empty()))
|
||||
}
|
||||
None => Err(Determinacy::Determined),
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ use rustc_middle::middle::resolve_bound_vars::Set1;
|
|||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_session::config::{CrateType, ResolveDocLinks};
|
||||
use rustc_session::lint;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::source_map::{respan, Spanned};
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::{BytePos, Span, SyntaxContext};
|
||||
|
|
@ -4138,6 +4139,25 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
|||
&& PrimTy::from_name(path[0].ident.name).is_some() =>
|
||||
{
|
||||
let prim = PrimTy::from_name(path[0].ident.name).unwrap();
|
||||
let tcx = self.r.tcx();
|
||||
|
||||
let gate_err_sym_msg = match prim {
|
||||
PrimTy::Float(FloatTy::F16) if !tcx.features().f16 => {
|
||||
Some((sym::f16, "the type `f16` is unstable"))
|
||||
}
|
||||
PrimTy::Float(FloatTy::F128) if !tcx.features().f128 => {
|
||||
Some((sym::f128, "the type `f128` is unstable"))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
if let Some((sym, msg)) = gate_err_sym_msg {
|
||||
let span = path[0].ident.span;
|
||||
if !span.allows_unstable(sym) {
|
||||
feature_err(tcx.sess, sym, span, msg).emit();
|
||||
}
|
||||
};
|
||||
|
||||
PartialRes::with_unresolved_segments(Res::PrimTy(prim), path.len() - 1)
|
||||
}
|
||||
PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
|
||||
|
|
|
|||
|
|
@ -167,12 +167,13 @@ pub fn unindent_doc_fragments(docs: &mut [DocFragment]) {
|
|||
///
|
||||
/// Note: remove the trailing newline where appropriate
|
||||
pub fn add_doc_fragment(out: &mut String, frag: &DocFragment) {
|
||||
let s = frag.doc.as_str();
|
||||
let mut iter = s.lines();
|
||||
if s.is_empty() {
|
||||
if frag.doc == kw::Empty {
|
||||
out.push('\n');
|
||||
return;
|
||||
}
|
||||
let s = frag.doc.as_str();
|
||||
let mut iter = s.lines();
|
||||
|
||||
while let Some(line) = iter.next() {
|
||||
if line.chars().any(|c| !c.is_whitespace()) {
|
||||
assert!(line.len() >= frag.indent);
|
||||
|
|
|
|||
|
|
@ -1645,6 +1645,8 @@ options! {
|
|||
"emit the bc module with thin LTO info (default: yes)"),
|
||||
export_executable_symbols: bool = (false, parse_bool, [TRACKED],
|
||||
"export symbols from executables, as if they were dynamic libraries"),
|
||||
external_clangrt: bool = (false, parse_bool, [UNTRACKED],
|
||||
"rely on user specified linker commands to find clangrt"),
|
||||
extra_const_ub_checks: bool = (false, parse_bool, [TRACKED],
|
||||
"turns on more checks to detect const UB, which can be slow (default: no)"),
|
||||
#[rustc_lint_opt_deny_field_access("use `Session::fewer_names` instead of this field")]
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ impl<'tcx> MutVisitor<'tcx> for BodyBuilder<'tcx> {
|
|||
|
||||
fn visit_constant(&mut self, constant: &mut mir::ConstOperand<'tcx>, location: mir::Location) {
|
||||
let const_ = self.monomorphize(constant.const_);
|
||||
let val = match const_.eval(self.tcx, ty::ParamEnv::reveal_all(), None) {
|
||||
let val = match const_.eval(self.tcx, ty::ParamEnv::reveal_all(), Some(constant.span)) {
|
||||
Ok(v) => v,
|
||||
Err(mir::interpret::ErrorHandled::Reported(..)) => return,
|
||||
Err(mir::interpret::ErrorHandled::TooGeneric(..)) => {
|
||||
|
|
|
|||
|
|
@ -815,6 +815,9 @@ symbols! {
|
|||
fadd_algebraic,
|
||||
fadd_fast,
|
||||
fake_variadic,
|
||||
fallback_to_never,
|
||||
fallback_to_niko,
|
||||
fallback_to_unit,
|
||||
fdiv_algebraic,
|
||||
fdiv_fast,
|
||||
feature,
|
||||
|
|
@ -1233,6 +1236,7 @@ symbols! {
|
|||
no_crate_inject,
|
||||
no_debug,
|
||||
no_default_passes,
|
||||
no_fallback,
|
||||
no_implicit_prelude,
|
||||
no_inline,
|
||||
no_link,
|
||||
|
|
@ -1551,6 +1555,7 @@ symbols! {
|
|||
rustc_mir,
|
||||
rustc_must_implement_one_of,
|
||||
rustc_never_returns_null_ptr,
|
||||
rustc_never_type_mode,
|
||||
rustc_no_mir_inline,
|
||||
rustc_nonnull_optimization_guaranteed,
|
||||
rustc_nounwind,
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
/// Used to set on_unimplemented's `ItemContext`
|
||||
/// to be the enclosing (async) block/function/closure
|
||||
fn describe_enclosure(&self, def_id: LocalDefId) -> Option<&'static str> {
|
||||
match self.tcx.opt_hir_node_by_def_id(def_id)? {
|
||||
match self.tcx.hir_node_by_def_id(def_id) {
|
||||
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. }) => Some("a function"),
|
||||
hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. }) => {
|
||||
Some("a trait method")
|
||||
|
|
|
|||
|
|
@ -261,7 +261,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
|
||||
// FIXME: Add check for trait bound that is already present, particularly `?Sized` so we
|
||||
// don't suggest `T: Sized + ?Sized`.
|
||||
while let Some(node) = self.tcx.opt_hir_node_by_def_id(body_id) {
|
||||
loop {
|
||||
let node = self.tcx.hir_node_by_def_id(body_id);
|
||||
match node {
|
||||
hir::Node::Item(hir::Item {
|
||||
ident,
|
||||
|
|
@ -987,10 +988,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
else {
|
||||
return false;
|
||||
};
|
||||
let arg_node = self.tcx.hir_node(*arg_hir_id);
|
||||
let Node::Expr(Expr { kind: hir::ExprKind::Path(_), .. }) = arg_node else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let clone_trait = self.tcx.require_lang_item(LangItem::Clone, None);
|
||||
let has_clone = |ty| {
|
||||
|
|
@ -998,6 +995,39 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
.must_apply_modulo_regions()
|
||||
};
|
||||
|
||||
let existing_clone_call = match self.tcx.hir_node(*arg_hir_id) {
|
||||
// It's just a variable. Propose cloning it.
|
||||
Node::Expr(Expr { kind: hir::ExprKind::Path(_), .. }) => None,
|
||||
// It's already a call to `clone()`. We might be able to suggest
|
||||
// adding a `+ Clone` bound, though.
|
||||
Node::Expr(Expr {
|
||||
kind:
|
||||
hir::ExprKind::MethodCall(
|
||||
hir::PathSegment { ident, .. },
|
||||
_receiver,
|
||||
&[],
|
||||
call_span,
|
||||
),
|
||||
hir_id,
|
||||
..
|
||||
}) if ident.name == sym::clone
|
||||
&& !call_span.from_expansion()
|
||||
&& !has_clone(*inner_ty) =>
|
||||
{
|
||||
// We only care about method calls corresponding to the real `Clone` trait.
|
||||
let Some(typeck_results) = self.typeck_results.as_ref() else { return false };
|
||||
let Some((DefKind::AssocFn, did)) = typeck_results.type_dependent_def(*hir_id)
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
if self.tcx.trait_of_item(did) != Some(clone_trait) {
|
||||
return false;
|
||||
}
|
||||
Some(ident.span)
|
||||
}
|
||||
_ => return false,
|
||||
};
|
||||
|
||||
let new_obligation = self.mk_trait_obligation_with_new_self_ty(
|
||||
obligation.param_env,
|
||||
trait_pred.map_bound(|trait_pred| (trait_pred, *inner_ty)),
|
||||
|
|
@ -1015,12 +1045,23 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
None,
|
||||
);
|
||||
}
|
||||
err.span_suggestion_verbose(
|
||||
obligation.cause.span.shrink_to_hi(),
|
||||
"consider using clone here",
|
||||
".clone()".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
if let Some(existing_clone_call) = existing_clone_call {
|
||||
err.span_note(
|
||||
existing_clone_call,
|
||||
format!(
|
||||
"this `clone()` copies the reference, \
|
||||
which does not do anything, \
|
||||
because `{inner_ty}` does not implement `Clone`"
|
||||
),
|
||||
);
|
||||
} else {
|
||||
err.span_suggestion_verbose(
|
||||
obligation.cause.span.shrink_to_hi(),
|
||||
"consider using clone here",
|
||||
".clone()".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
false
|
||||
|
|
@ -1685,8 +1726,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
) -> bool {
|
||||
let hir = self.tcx.hir();
|
||||
let node = self.tcx.opt_hir_node_by_def_id(obligation.cause.body_id);
|
||||
if let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. })) = node
|
||||
let node = self.tcx.hir_node_by_def_id(obligation.cause.body_id);
|
||||
if let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. }) = node
|
||||
&& let hir::ExprKind::Block(blk, _) = &hir.body(*body_id).value.kind
|
||||
&& sig.decl.output.span().overlaps(span)
|
||||
&& blk.expr.is_none()
|
||||
|
|
@ -1720,8 +1761,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Span> {
|
||||
let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, ..), .. })) =
|
||||
self.tcx.opt_hir_node_by_def_id(obligation.cause.body_id)
|
||||
let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, ..), .. }) =
|
||||
self.tcx.hir_node_by_def_id(obligation.cause.body_id)
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
|
|
@ -1813,10 +1854,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
}
|
||||
|
||||
let hir = self.tcx.hir();
|
||||
let node = self.tcx.opt_hir_node_by_def_id(obligation.cause.body_id);
|
||||
if let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) =
|
||||
node
|
||||
{
|
||||
let node = self.tcx.hir_node_by_def_id(obligation.cause.body_id);
|
||||
if let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. }) = node {
|
||||
let body = hir.body(*body_id);
|
||||
// Point at all the `return`s in the function as they have failed trait bounds.
|
||||
let mut visitor = ReturnsVisitor::default();
|
||||
|
|
@ -4450,7 +4489,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
}
|
||||
return;
|
||||
};
|
||||
let Some(hir::Node::TraitItem(item)) = self.tcx.opt_hir_node_by_def_id(fn_def_id) else {
|
||||
let hir::Node::TraitItem(item) = self.tcx.hir_node_by_def_id(fn_def_id) else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -2497,11 +2497,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
err.code(E0790);
|
||||
|
||||
if let Some(local_def_id) = data.trait_ref.def_id.as_local()
|
||||
&& let Some(hir::Node::Item(hir::Item {
|
||||
&& let hir::Node::Item(hir::Item {
|
||||
ident: trait_name,
|
||||
kind: hir::ItemKind::Trait(_, _, _, _, trait_item_refs),
|
||||
..
|
||||
})) = self.tcx.opt_hir_node_by_def_id(local_def_id)
|
||||
}) = self.tcx.hir_node_by_def_id(local_def_id)
|
||||
&& let Some(method_ref) = trait_item_refs
|
||||
.iter()
|
||||
.find(|item_ref| item_ref.ident == *assoc_item_name)
|
||||
|
|
@ -3073,29 +3073,29 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
let src = trait_ref.args.type_at(1);
|
||||
let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`");
|
||||
let safe_transmute_explanation = match reason {
|
||||
rustc_transmute::Reason::SrcIsUnspecified => {
|
||||
format!("`{src}` does not have a well-specified layout")
|
||||
rustc_transmute::Reason::SrcIsNotYetSupported => {
|
||||
format!("analyzing the transmutability of `{src}` is not yet supported.")
|
||||
}
|
||||
|
||||
rustc_transmute::Reason::DstIsUnspecified => {
|
||||
format!("`{dst}` does not have a well-specified layout")
|
||||
rustc_transmute::Reason::DstIsNotYetSupported => {
|
||||
format!("analyzing the transmutability of `{dst}` is not yet supported.")
|
||||
}
|
||||
|
||||
rustc_transmute::Reason::DstIsBitIncompatible => {
|
||||
format!("At least one value of `{src}` isn't a bit-valid value of `{dst}`")
|
||||
format!("at least one value of `{src}` isn't a bit-valid value of `{dst}`")
|
||||
}
|
||||
|
||||
rustc_transmute::Reason::DstMayHaveSafetyInvariants => {
|
||||
format!("`{dst}` may carry safety invariants")
|
||||
}
|
||||
rustc_transmute::Reason::DstIsTooBig => {
|
||||
format!("The size of `{src}` is smaller than the size of `{dst}`")
|
||||
format!("the size of `{src}` is smaller than the size of `{dst}`")
|
||||
}
|
||||
rustc_transmute::Reason::DstRefIsTooBig { src, dst } => {
|
||||
let src_size = src.size;
|
||||
let dst_size = dst.size;
|
||||
format!(
|
||||
"The referent size of `{src}` ({src_size} bytes) is smaller than that of `{dst}` ({dst_size} bytes)"
|
||||
"the referent size of `{src}` ({src_size} bytes) is smaller than that of `{dst}` ({dst_size} bytes)"
|
||||
)
|
||||
}
|
||||
rustc_transmute::Reason::SrcSizeOverflow => {
|
||||
|
|
@ -3113,7 +3113,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
dst_min_align,
|
||||
} => {
|
||||
format!(
|
||||
"The minimum alignment of `{src}` ({src_min_align}) should be greater than that of `{dst}` ({dst_min_align})"
|
||||
"the minimum alignment of `{src}` ({src_min_align}) should be greater than that of `{dst}` ({dst_min_align})"
|
||||
)
|
||||
}
|
||||
rustc_transmute::Reason::DstIsMoreUnique => {
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ pub fn clause_obligations<'tcx>(
|
|||
wf.compute(ty.into());
|
||||
}
|
||||
ty::ClauseKind::Projection(t) => {
|
||||
wf.compute_projection(t.projection_ty);
|
||||
wf.compute_alias(t.projection_ty);
|
||||
wf.compute(match t.term.unpack() {
|
||||
ty::TermKind::Ty(ty) => ty.into(),
|
||||
ty::TermKind::Const(c) => c.into(),
|
||||
|
|
@ -436,9 +436,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Pushes the obligations required for `trait_ref::Item` to be WF
|
||||
/// Pushes the obligations required for an alias (except inherent) to be WF
|
||||
/// into `self.out`.
|
||||
fn compute_projection(&mut self, data: ty::AliasTy<'tcx>) {
|
||||
fn compute_alias(&mut self, data: ty::AliasTy<'tcx>) {
|
||||
// A projection is well-formed if
|
||||
//
|
||||
// (a) its predicates hold (*)
|
||||
|
|
@ -466,6 +466,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
|||
self.compute_projection_args(data.args);
|
||||
}
|
||||
|
||||
/// Pushes the obligations required for an inherent alias to be WF
|
||||
/// into `self.out`.
|
||||
// FIXME(inherent_associated_types): Merge this function with `fn compute_alias`.
|
||||
fn compute_inherent_projection(&mut self, data: ty::AliasTy<'tcx>) {
|
||||
// An inherent projection is well-formed if
|
||||
//
|
||||
|
|
@ -688,8 +691,8 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
|
|||
// Simple cases that are WF if their type args are WF.
|
||||
}
|
||||
|
||||
ty::Alias(ty::Projection, data) => {
|
||||
self.compute_projection(data);
|
||||
ty::Alias(ty::Projection | ty::Opaque | ty::Weak, data) => {
|
||||
self.compute_alias(data);
|
||||
return; // Subtree handled by compute_projection.
|
||||
}
|
||||
ty::Alias(ty::Inherent, data) => {
|
||||
|
|
@ -791,21 +794,6 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
|
|||
// types appearing in the fn signature.
|
||||
}
|
||||
|
||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
|
||||
// All of the requirements on type parameters
|
||||
// have already been checked for `impl Trait` in
|
||||
// return position. We do need to check type-alias-impl-trait though.
|
||||
if self.tcx().is_type_alias_impl_trait(def_id) {
|
||||
let obligations = self.nominal_obligations(def_id, args);
|
||||
self.out.extend(obligations);
|
||||
}
|
||||
}
|
||||
|
||||
ty::Alias(ty::Weak, ty::AliasTy { def_id, args, .. }) => {
|
||||
let obligations = self.nominal_obligations(def_id, args);
|
||||
self.out.extend(obligations);
|
||||
}
|
||||
|
||||
ty::Dynamic(data, r, _) => {
|
||||
// WfObject
|
||||
//
|
||||
|
|
|
|||
|
|
@ -186,8 +186,8 @@ pub(crate) mod rustc {
|
|||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub(crate) enum Err {
|
||||
/// The layout of the type is unspecified.
|
||||
Unspecified,
|
||||
/// The layout of the type is not yet supported.
|
||||
NotYetSupported,
|
||||
/// This error will be surfaced elsewhere by rustc, so don't surface it.
|
||||
UnknownLayout,
|
||||
/// Overflow size
|
||||
|
|
@ -288,14 +288,14 @@ pub(crate) mod rustc {
|
|||
if members.len() == 0 {
|
||||
Ok(Tree::unit())
|
||||
} else {
|
||||
Err(Err::Unspecified)
|
||||
Err(Err::NotYetSupported)
|
||||
}
|
||||
}
|
||||
|
||||
ty::Array(ty, len) => {
|
||||
let len = len
|
||||
.try_eval_target_usize(tcx, ParamEnv::reveal_all())
|
||||
.ok_or(Err::Unspecified)?;
|
||||
.ok_or(Err::NotYetSupported)?;
|
||||
let elt = Tree::from_ty(*ty, tcx)?;
|
||||
Ok(std::iter::repeat(elt)
|
||||
.take(len as usize)
|
||||
|
|
@ -307,7 +307,7 @@ pub(crate) mod rustc {
|
|||
|
||||
// If the layout is ill-specified, halt.
|
||||
if !(adt_def.repr().c() || adt_def.repr().int.is_some()) {
|
||||
return Err(Err::Unspecified);
|
||||
return Err(Err::NotYetSupported);
|
||||
}
|
||||
|
||||
// Compute a summary of the type's layout.
|
||||
|
|
@ -348,7 +348,7 @@ pub(crate) mod rustc {
|
|||
AdtKind::Union => {
|
||||
// is the layout well-defined?
|
||||
if !adt_def.repr().c() {
|
||||
return Err(Err::Unspecified);
|
||||
return Err(Err::NotYetSupported);
|
||||
}
|
||||
|
||||
let ty_layout = layout_of(tcx, ty)?;
|
||||
|
|
@ -384,7 +384,7 @@ pub(crate) mod rustc {
|
|||
}))
|
||||
}
|
||||
|
||||
_ => Err(Err::Unspecified),
|
||||
_ => Err(Err::NotYetSupported),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,10 +43,10 @@ pub enum Condition<R> {
|
|||
/// Answers "why wasn't the source type transmutable into the destination type?"
|
||||
#[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone)]
|
||||
pub enum Reason<T> {
|
||||
/// The layout of the source type is unspecified.
|
||||
SrcIsUnspecified,
|
||||
/// The layout of the destination type is unspecified.
|
||||
DstIsUnspecified,
|
||||
/// The layout of the source type is not yet supported.
|
||||
SrcIsNotYetSupported,
|
||||
/// The layout of the destination type is not yet supported.
|
||||
DstIsNotYetSupported,
|
||||
/// The layout of the destination type is bit-incompatible with the source type.
|
||||
DstIsBitIncompatible,
|
||||
/// The destination type may carry safety invariants.
|
||||
|
|
|
|||
|
|
@ -56,8 +56,8 @@ mod rustc {
|
|||
}
|
||||
(Err(Err::UnknownLayout), _) => Answer::No(Reason::SrcLayoutUnknown),
|
||||
(_, Err(Err::UnknownLayout)) => Answer::No(Reason::DstLayoutUnknown),
|
||||
(Err(Err::Unspecified), _) => Answer::No(Reason::SrcIsUnspecified),
|
||||
(_, Err(Err::Unspecified)) => Answer::No(Reason::DstIsUnspecified),
|
||||
(Err(Err::NotYetSupported), _) => Answer::No(Reason::SrcIsNotYetSupported),
|
||||
(_, Err(Err::NotYetSupported)) => Answer::No(Reason::DstIsNotYetSupported),
|
||||
(Err(Err::SizeOverflow), _) => Answer::No(Reason::SrcSizeOverflow),
|
||||
(_, Err(Err::SizeOverflow)) => Answer::No(Reason::DstSizeOverflow),
|
||||
(Ok(src), Ok(dst)) => MaybeTransmutableQuery { src, dst, assume, context }.answer(),
|
||||
|
|
|
|||
|
|
@ -325,11 +325,7 @@ fn associated_type_for_impl_trait_in_impl(
|
|||
) -> LocalDefId {
|
||||
let impl_local_def_id = tcx.local_parent(impl_fn_def_id);
|
||||
|
||||
let decl = tcx
|
||||
.opt_hir_node_by_def_id(impl_fn_def_id)
|
||||
.expect("expected item")
|
||||
.fn_decl()
|
||||
.expect("expected decl");
|
||||
let decl = tcx.hir_node_by_def_id(impl_fn_def_id).fn_decl().expect("expected decl");
|
||||
let span = match decl.output {
|
||||
hir::FnRetTy::DefaultReturn(_) => tcx.def_span(impl_fn_def_id),
|
||||
hir::FnRetTy::Return(ty) => ty.span,
|
||||
|
|
|
|||
|
|
@ -4,23 +4,15 @@ use crate::cmp::Ordering;
|
|||
use crate::fmt;
|
||||
use crate::hash::{Hash, Hasher};
|
||||
use crate::intrinsics;
|
||||
use crate::marker::StructuralPartialEq;
|
||||
use crate::marker::{Freeze, StructuralPartialEq};
|
||||
use crate::ops::{BitOr, BitOrAssign, Div, Neg, Rem};
|
||||
use crate::panic::{RefUnwindSafe, UnwindSafe};
|
||||
use crate::ptr;
|
||||
use crate::str::FromStr;
|
||||
|
||||
use super::from_str_radix;
|
||||
use super::{IntErrorKind, ParseIntError};
|
||||
|
||||
mod private {
|
||||
#[unstable(
|
||||
feature = "nonzero_internals",
|
||||
reason = "implementation detail which may disappear or be replaced at any time",
|
||||
issue = "none"
|
||||
)]
|
||||
#[const_trait]
|
||||
pub trait Sealed {}
|
||||
}
|
||||
|
||||
/// A marker trait for primitive types which can be zero.
|
||||
///
|
||||
/// This is an implementation detail for <code>[NonZero]\<T></code> which may disappear or be replaced at any time.
|
||||
|
|
@ -34,38 +26,70 @@ mod private {
|
|||
issue = "none"
|
||||
)]
|
||||
#[const_trait]
|
||||
pub unsafe trait ZeroablePrimitive: Sized + Copy + private::Sealed {}
|
||||
pub unsafe trait ZeroablePrimitive: Sized + Copy + private::Sealed {
|
||||
#[doc(hidden)]
|
||||
type NonZeroInner: Sized + Copy;
|
||||
}
|
||||
|
||||
macro_rules! impl_zeroable_primitive {
|
||||
($primitive:ty) => {
|
||||
#[unstable(
|
||||
feature = "nonzero_internals",
|
||||
reason = "implementation detail which may disappear or be replaced at any time",
|
||||
issue = "none"
|
||||
)]
|
||||
impl const private::Sealed for $primitive {}
|
||||
($($NonZeroInner:ident ( $primitive:ty )),+ $(,)?) => {
|
||||
mod private {
|
||||
#[unstable(
|
||||
feature = "nonzero_internals",
|
||||
reason = "implementation detail which may disappear or be replaced at any time",
|
||||
issue = "none"
|
||||
)]
|
||||
#[const_trait]
|
||||
pub trait Sealed {}
|
||||
|
||||
#[unstable(
|
||||
feature = "nonzero_internals",
|
||||
reason = "implementation detail which may disappear or be replaced at any time",
|
||||
issue = "none"
|
||||
)]
|
||||
unsafe impl const ZeroablePrimitive for $primitive {}
|
||||
$(
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
#[repr(transparent)]
|
||||
#[rustc_layout_scalar_valid_range_start(1)]
|
||||
#[rustc_nonnull_optimization_guaranteed]
|
||||
#[unstable(
|
||||
feature = "nonzero_internals",
|
||||
reason = "implementation detail which may disappear or be replaced at any time",
|
||||
issue = "none"
|
||||
)]
|
||||
pub struct $NonZeroInner($primitive);
|
||||
)+
|
||||
}
|
||||
|
||||
$(
|
||||
#[unstable(
|
||||
feature = "nonzero_internals",
|
||||
reason = "implementation detail which may disappear or be replaced at any time",
|
||||
issue = "none"
|
||||
)]
|
||||
impl const private::Sealed for $primitive {}
|
||||
|
||||
#[unstable(
|
||||
feature = "nonzero_internals",
|
||||
reason = "implementation detail which may disappear or be replaced at any time",
|
||||
issue = "none"
|
||||
)]
|
||||
unsafe impl const ZeroablePrimitive for $primitive {
|
||||
type NonZeroInner = private::$NonZeroInner;
|
||||
}
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
||||
impl_zeroable_primitive!(u8);
|
||||
impl_zeroable_primitive!(u16);
|
||||
impl_zeroable_primitive!(u32);
|
||||
impl_zeroable_primitive!(u64);
|
||||
impl_zeroable_primitive!(u128);
|
||||
impl_zeroable_primitive!(usize);
|
||||
impl_zeroable_primitive!(i8);
|
||||
impl_zeroable_primitive!(i16);
|
||||
impl_zeroable_primitive!(i32);
|
||||
impl_zeroable_primitive!(i64);
|
||||
impl_zeroable_primitive!(i128);
|
||||
impl_zeroable_primitive!(isize);
|
||||
impl_zeroable_primitive!(
|
||||
NonZeroU8Inner(u8),
|
||||
NonZeroU16Inner(u16),
|
||||
NonZeroU32Inner(u32),
|
||||
NonZeroU64Inner(u64),
|
||||
NonZeroU128Inner(u128),
|
||||
NonZeroUsizeInner(usize),
|
||||
NonZeroI8Inner(i8),
|
||||
NonZeroI16Inner(i16),
|
||||
NonZeroI32Inner(i32),
|
||||
NonZeroI64Inner(i64),
|
||||
NonZeroI128Inner(i128),
|
||||
NonZeroIsizeInner(isize),
|
||||
);
|
||||
|
||||
/// A value that is known not to equal zero.
|
||||
///
|
||||
|
|
@ -80,10 +104,9 @@ impl_zeroable_primitive!(isize);
|
|||
/// ```
|
||||
#[unstable(feature = "generic_nonzero", issue = "120257")]
|
||||
#[repr(transparent)]
|
||||
#[rustc_layout_scalar_valid_range_start(1)]
|
||||
#[rustc_nonnull_optimization_guaranteed]
|
||||
#[rustc_diagnostic_item = "NonZero"]
|
||||
pub struct NonZero<T: ZeroablePrimitive>(T);
|
||||
pub struct NonZero<T: ZeroablePrimitive>(T::NonZeroInner);
|
||||
|
||||
macro_rules! impl_nonzero_fmt {
|
||||
($Trait:ident) => {
|
||||
|
|
@ -107,6 +130,26 @@ impl_nonzero_fmt!(Octal);
|
|||
impl_nonzero_fmt!(LowerHex);
|
||||
impl_nonzero_fmt!(UpperHex);
|
||||
|
||||
macro_rules! impl_nonzero_auto_trait {
|
||||
(unsafe $Trait:ident) => {
|
||||
#[stable(feature = "nonzero", since = "1.28.0")]
|
||||
unsafe impl<T> $Trait for NonZero<T> where T: ZeroablePrimitive + $Trait {}
|
||||
};
|
||||
($Trait:ident) => {
|
||||
#[stable(feature = "nonzero", since = "1.28.0")]
|
||||
impl<T> $Trait for NonZero<T> where T: ZeroablePrimitive + $Trait {}
|
||||
};
|
||||
}
|
||||
|
||||
// Implement auto-traits manually based on `T` to avoid docs exposing
|
||||
// the `ZeroablePrimitive::NonZeroInner` implementation detail.
|
||||
impl_nonzero_auto_trait!(unsafe Freeze);
|
||||
impl_nonzero_auto_trait!(RefUnwindSafe);
|
||||
impl_nonzero_auto_trait!(unsafe Send);
|
||||
impl_nonzero_auto_trait!(unsafe Sync);
|
||||
impl_nonzero_auto_trait!(Unpin);
|
||||
impl_nonzero_auto_trait!(UnwindSafe);
|
||||
|
||||
#[stable(feature = "nonzero", since = "1.28.0")]
|
||||
impl<T> Clone for NonZero<T>
|
||||
where
|
||||
|
|
@ -114,8 +157,7 @@ where
|
|||
{
|
||||
#[inline]
|
||||
fn clone(&self) -> Self {
|
||||
// SAFETY: The contained value is non-zero.
|
||||
unsafe { Self(self.0) }
|
||||
Self(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -188,19 +230,19 @@ where
|
|||
#[inline]
|
||||
fn max(self, other: Self) -> Self {
|
||||
// SAFETY: The maximum of two non-zero values is still non-zero.
|
||||
unsafe { Self(self.get().max(other.get())) }
|
||||
unsafe { Self::new_unchecked(self.get().max(other.get())) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn min(self, other: Self) -> Self {
|
||||
// SAFETY: The minimum of two non-zero values is still non-zero.
|
||||
unsafe { Self(self.get().min(other.get())) }
|
||||
unsafe { Self::new_unchecked(self.get().min(other.get())) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn clamp(self, min: Self, max: Self) -> Self {
|
||||
// SAFETY: A non-zero value clamped between two non-zero values is still non-zero.
|
||||
unsafe { Self(self.get().clamp(min.get(), max.get())) }
|
||||
unsafe { Self::new_unchecked(self.get().clamp(min.get(), max.get())) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -240,7 +282,7 @@ where
|
|||
#[inline]
|
||||
fn bitor(self, rhs: Self) -> Self::Output {
|
||||
// SAFETY: Bitwise OR of two non-zero values is still non-zero.
|
||||
unsafe { Self(self.get() | rhs.get()) }
|
||||
unsafe { Self::new_unchecked(self.get() | rhs.get()) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -254,7 +296,7 @@ where
|
|||
#[inline]
|
||||
fn bitor(self, rhs: T) -> Self::Output {
|
||||
// SAFETY: Bitwise OR of a non-zero value with anything is still non-zero.
|
||||
unsafe { Self(self.get() | rhs) }
|
||||
unsafe { Self::new_unchecked(self.get() | rhs) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -268,7 +310,7 @@ where
|
|||
#[inline]
|
||||
fn bitor(self, rhs: NonZero<T>) -> Self::Output {
|
||||
// SAFETY: Bitwise OR of anything with a non-zero value is still non-zero.
|
||||
unsafe { NonZero(self | rhs.get()) }
|
||||
unsafe { NonZero::new_unchecked(self | rhs.get()) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -346,7 +388,7 @@ where
|
|||
pub fn from_mut(n: &mut T) -> Option<&mut Self> {
|
||||
// SAFETY: Memory layout optimization guarantees that `Option<NonZero<T>>` has
|
||||
// the same layout and size as `T`, with `0` representing `None`.
|
||||
let opt_n = unsafe { &mut *(n as *mut T as *mut Option<Self>) };
|
||||
let opt_n = unsafe { &mut *(ptr::from_mut(n).cast::<Option<Self>>()) };
|
||||
|
||||
opt_n.as_mut()
|
||||
}
|
||||
|
|
@ -390,12 +432,17 @@ where
|
|||
// memory somewhere. If the value of `self` was from by-value argument
|
||||
// of some not-inlined function, LLVM don't have range metadata
|
||||
// to understand that the value cannot be zero.
|
||||
match Self::new(self.0) {
|
||||
Some(Self(n)) => n,
|
||||
//
|
||||
// SAFETY: `Self` is guaranteed to have the same layout as `Option<Self>`.
|
||||
match unsafe { intrinsics::transmute_unchecked(self) } {
|
||||
None => {
|
||||
// SAFETY: `NonZero` is guaranteed to only contain non-zero values, so this is unreachable.
|
||||
unsafe { intrinsics::unreachable() }
|
||||
}
|
||||
Some(Self(inner)) => {
|
||||
// SAFETY: `T::NonZeroInner` is guaranteed to have the same layout as `T`.
|
||||
unsafe { intrinsics::transmute_unchecked(inner) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1114,7 +1114,7 @@ const unsafe fn swap_nonoverlapping_simple_untyped<T>(x: *mut T, y: *mut T, coun
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_const_unstable(feature = "const_replace", issue = "83164")]
|
||||
#[rustc_diagnostic_item = "ptr_replace"]
|
||||
pub const unsafe fn replace<T>(dst: *mut T, mut src: T) -> T {
|
||||
pub const unsafe fn replace<T>(dst: *mut T, src: T) -> T {
|
||||
// SAFETY: the caller must guarantee that `dst` is valid to be
|
||||
// cast to a mutable reference (valid for writes, aligned, initialized),
|
||||
// and cannot overlap `src` since `dst` must point to a distinct
|
||||
|
|
@ -1128,9 +1128,8 @@ pub const unsafe fn replace<T>(dst: *mut T, mut src: T) -> T {
|
|||
align: usize = align_of::<T>(),
|
||||
) => is_aligned_and_not_null(addr, align)
|
||||
);
|
||||
mem::swap(&mut *dst, &mut src); // cannot overlap
|
||||
mem::replace(&mut *dst, src)
|
||||
}
|
||||
src
|
||||
}
|
||||
|
||||
/// Reads the value from `src` without moving it. This leaves the
|
||||
|
|
|
|||
|
|
@ -1782,6 +1782,7 @@ fn windows_unix_socket_exists() {
|
|||
}
|
||||
let mut addr = c::SOCKADDR_UN { sun_family: c::AF_UNIX, sun_path: mem::zeroed() };
|
||||
let bytes = socket_path.as_os_str().as_encoded_bytes();
|
||||
let bytes = core::slice::from_raw_parts(bytes.as_ptr().cast::<i8>(), bytes.len());
|
||||
addr.sun_path[..bytes.len()].copy_from_slice(bytes);
|
||||
let len = mem::size_of_val(&addr) as i32;
|
||||
let result = c::bind(socket, ptr::addr_of!(addr).cast::<c::SOCKADDR>(), len);
|
||||
|
|
|
|||
|
|
@ -51,6 +51,8 @@ use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut, SeekFrom};
|
|||
/// // We might want to use a BufReader here for efficiency, but let's
|
||||
/// // keep this example focused.
|
||||
/// let mut file = File::create("foo.txt")?;
|
||||
/// // First, we need to allocate 10 bytes to be able to write into.
|
||||
/// file.set_len(10)?;
|
||||
///
|
||||
/// write_ten_bytes_at_end(&mut file)?;
|
||||
/// # Ok(())
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ mod as_keyword {}
|
|||
|
||||
#[doc(keyword = "break")]
|
||||
//
|
||||
/// Exit early from a loop.
|
||||
/// Exit early from a loop or labelled block.
|
||||
///
|
||||
/// When `break` is encountered, execution of the associated loop body is
|
||||
/// immediately terminated.
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -13,22 +13,21 @@ pub macro thread_local_inner {
|
|||
(@key $t:ty, const $init:expr) => {{
|
||||
#[inline]
|
||||
#[deny(unsafe_op_in_unsafe_fn)]
|
||||
// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint
|
||||
#[cfg_attr(bootstrap, allow(static_mut_ref))]
|
||||
#[cfg_attr(not(bootstrap), allow(static_mut_refs))]
|
||||
unsafe fn __getit(
|
||||
_init: $crate::option::Option<&mut $crate::option::Option<$t>>,
|
||||
) -> $crate::option::Option<&'static $t> {
|
||||
const INIT_EXPR: $t = $init;
|
||||
// If the platform has support for `#[thread_local]`, use it.
|
||||
#[thread_local]
|
||||
static mut VAL: $t = INIT_EXPR;
|
||||
// We use `UnsafeCell` here instead of `static mut` to ensure any generated TLS shims
|
||||
// have a nonnull attribute on their return value.
|
||||
static VAL: $crate::cell::UnsafeCell<$t> = $crate::cell::UnsafeCell::new(INIT_EXPR);
|
||||
|
||||
// If a dtor isn't needed we can do something "very raw" and
|
||||
// just get going.
|
||||
if !$crate::mem::needs_drop::<$t>() {
|
||||
unsafe {
|
||||
return $crate::option::Option::Some(&VAL)
|
||||
return $crate::option::Option::Some(&*VAL.get())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -55,15 +54,15 @@ pub macro thread_local_inner {
|
|||
// so now.
|
||||
0 => {
|
||||
$crate::thread::local_impl::Key::<$t>::register_dtor(
|
||||
$crate::ptr::addr_of_mut!(VAL) as *mut $crate::primitive::u8,
|
||||
VAL.get() as *mut $crate::primitive::u8,
|
||||
destroy,
|
||||
);
|
||||
STATE.set(1);
|
||||
$crate::option::Option::Some(&VAL)
|
||||
$crate::option::Option::Some(&*VAL.get())
|
||||
}
|
||||
// 1 == the destructor is registered and the value
|
||||
// is valid, so return the pointer.
|
||||
1 => $crate::option::Option::Some(&VAL),
|
||||
1 => $crate::option::Option::Some(&*VAL.get()),
|
||||
// otherwise the destructor has already run, so we
|
||||
// can't give access.
|
||||
_ => $crate::option::Option::None,
|
||||
|
|
|
|||
|
|
@ -131,6 +131,8 @@ v("musl-root-riscv32gc", "target.riscv32gc-unknown-linux-musl.musl-root",
|
|||
"riscv32gc-unknown-linux-musl install directory")
|
||||
v("musl-root-riscv64gc", "target.riscv64gc-unknown-linux-musl.musl-root",
|
||||
"riscv64gc-unknown-linux-musl install directory")
|
||||
v("musl-root-loongarch64", "target.loongarch64-unknown-linux-musl.musl-root",
|
||||
"loongarch64-unknown-linux-musl install directory")
|
||||
v("qemu-armhf-rootfs", "target.arm-unknown-linux-gnueabihf.qemu-rootfs",
|
||||
"rootfs in qemu testing, you probably don't want to use this")
|
||||
v("qemu-aarch64-rootfs", "target.aarch64-unknown-linux-gnu.qemu-rootfs",
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
use std::io::Write;
|
||||
use std::process;
|
||||
use std::str::FromStr;
|
||||
use std::{
|
||||
env,
|
||||
fs::{self, OpenOptions},
|
||||
|
|
@ -136,16 +137,25 @@ fn check_version(config: &Config) -> Option<String> {
|
|||
let latest_change_id = CONFIG_CHANGE_HISTORY.last().unwrap().change_id;
|
||||
let warned_id_path = config.out.join("bootstrap").join(".last-warned-change-id");
|
||||
|
||||
if let Some(id) = config.change_id {
|
||||
if let Some(mut id) = config.change_id {
|
||||
if id == latest_change_id {
|
||||
return None;
|
||||
}
|
||||
|
||||
if let Ok(last_warned_id) = fs::read_to_string(&warned_id_path) {
|
||||
if latest_change_id.to_string() == last_warned_id {
|
||||
return None;
|
||||
// Always try to use `change-id` from .last-warned-change-id first. If it doesn't exist,
|
||||
// then use the one from the config.toml. This way we never show the same warnings
|
||||
// more than once.
|
||||
if let Ok(t) = fs::read_to_string(&warned_id_path) {
|
||||
let last_warned_id =
|
||||
usize::from_str(&t).expect(&format!("{} is corrupted.", warned_id_path.display()));
|
||||
|
||||
// We only use the last_warned_id if it exists in `CONFIG_CHANGE_HISTORY`.
|
||||
// Otherwise, we may retrieve all the changes if it's not the highest value.
|
||||
// For better understanding, refer to `change_tracker::find_recent_config_change_ids`.
|
||||
if CONFIG_CHANGE_HISTORY.iter().any(|config| config.change_id == last_warned_id) {
|
||||
id = last_warned_id;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let changes = find_recent_config_change_ids(id);
|
||||
|
||||
|
|
|
|||
|
|
@ -231,7 +231,7 @@ impl Step for Std {
|
|||
let target_sysroot_bin =
|
||||
builder.sysroot_libdir(compiler, target).parent().unwrap().join("bin");
|
||||
t!(fs::create_dir_all(&target_sysroot_bin));
|
||||
builder.cp_r(&src_sysroot_bin, &target_sysroot_bin);
|
||||
builder.cp_link_r(&src_sysroot_bin, &target_sysroot_bin);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -307,7 +307,7 @@ fn copy_and_stamp(
|
|||
dependency_type: DependencyType,
|
||||
) {
|
||||
let target = libdir.join(name);
|
||||
builder.copy(&sourcedir.join(name), &target);
|
||||
builder.copy_link(&sourcedir.join(name), &target);
|
||||
|
||||
target_deps.push((target, dependency_type));
|
||||
}
|
||||
|
|
@ -316,7 +316,7 @@ fn copy_llvm_libunwind(builder: &Builder<'_>, target: TargetSelection, libdir: &
|
|||
let libunwind_path = builder.ensure(llvm::Libunwind { target });
|
||||
let libunwind_source = libunwind_path.join("libunwind.a");
|
||||
let libunwind_target = libdir.join("libunwind.a");
|
||||
builder.copy(&libunwind_source, &libunwind_target);
|
||||
builder.copy_link(&libunwind_source, &libunwind_target);
|
||||
libunwind_target
|
||||
}
|
||||
|
||||
|
|
@ -385,7 +385,7 @@ fn copy_self_contained_objects(
|
|||
for &obj in &["crtbegin.o", "crtbeginS.o", "crtend.o", "crtendS.o"] {
|
||||
let src = crt_path.join(obj);
|
||||
let target = libdir_self_contained.join(obj);
|
||||
builder.copy(&src, &target);
|
||||
builder.copy_link(&src, &target);
|
||||
target_deps.push((target, DependencyType::TargetSelfContained));
|
||||
}
|
||||
|
||||
|
|
@ -418,7 +418,7 @@ fn copy_self_contained_objects(
|
|||
for obj in ["crt2.o", "dllcrt2.o"].iter() {
|
||||
let src = compiler_file(builder, &builder.cc(target), target, CLang::C, obj);
|
||||
let target = libdir_self_contained.join(obj);
|
||||
builder.copy(&src, &target);
|
||||
builder.copy_link(&src, &target);
|
||||
target_deps.push((target, DependencyType::TargetSelfContained));
|
||||
}
|
||||
}
|
||||
|
|
@ -637,7 +637,7 @@ impl Step for StdLink {
|
|||
let stage0_bin_dir = builder.out.join(host).join("stage0/bin");
|
||||
let sysroot_bin_dir = sysroot.join("bin");
|
||||
t!(fs::create_dir_all(&sysroot_bin_dir));
|
||||
builder.cp_r(&stage0_bin_dir, &sysroot_bin_dir);
|
||||
builder.cp_link_r(&stage0_bin_dir, &sysroot_bin_dir);
|
||||
|
||||
// Copy all *.so files from stage0/lib to stage0-sysroot/lib
|
||||
let stage0_lib_dir = builder.out.join(host).join("stage0/lib");
|
||||
|
|
@ -646,7 +646,8 @@ impl Step for StdLink {
|
|||
let file = t!(file);
|
||||
let path = file.path();
|
||||
if path.is_file() && is_dylib(&file.file_name().into_string().unwrap()) {
|
||||
builder.copy(&path, &sysroot.join("lib").join(path.file_name().unwrap()));
|
||||
builder
|
||||
.copy_link(&path, &sysroot.join("lib").join(path.file_name().unwrap()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -661,7 +662,7 @@ impl Step for StdLink {
|
|||
.join(host)
|
||||
.join("codegen-backends");
|
||||
if stage0_codegen_backends.exists() {
|
||||
builder.cp_r(&stage0_codegen_backends, &sysroot_codegen_backends);
|
||||
builder.cp_link_r(&stage0_codegen_backends, &sysroot_codegen_backends);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -684,7 +685,7 @@ fn copy_sanitizers(
|
|||
|
||||
for runtime in &runtimes {
|
||||
let dst = libdir.join(&runtime.name);
|
||||
builder.copy(&runtime.path, &dst);
|
||||
builder.copy_link(&runtime.path, &dst);
|
||||
|
||||
// The `aarch64-apple-ios-macabi` and `x86_64-apple-ios-macabi` are also supported for
|
||||
// sanitizers, but they share a sanitizer runtime with `${arch}-apple-darwin`, so we do
|
||||
|
|
@ -790,7 +791,7 @@ impl Step for StartupObjects {
|
|||
}
|
||||
|
||||
let target = sysroot_dir.join((*file).to_string() + ".o");
|
||||
builder.copy(dst_file, &target);
|
||||
builder.copy_link(dst_file, &target);
|
||||
target_deps.push((target, DependencyType::Target));
|
||||
}
|
||||
|
||||
|
|
@ -812,7 +813,7 @@ fn cp_rustc_component_to_ci_sysroot(
|
|||
if src.is_dir() {
|
||||
t!(fs::create_dir_all(dst));
|
||||
} else {
|
||||
builder.copy(&src, &dst);
|
||||
builder.copy_link(&src, &dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1443,7 +1444,7 @@ fn copy_codegen_backends_to_sysroot(
|
|||
let dot = filename.find('.').unwrap();
|
||||
format!("{}-{}{}", &filename[..dash], builder.rust_release(), &filename[dot..])
|
||||
};
|
||||
builder.copy(file, &dst.join(target_filename));
|
||||
builder.copy_link(file, &dst.join(target_filename));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1599,7 +1600,7 @@ impl Step for Sysroot {
|
|||
OsStr::new(std::env::consts::DLL_EXTENSION),
|
||||
];
|
||||
let ci_rustc_dir = builder.config.ci_rustc_dir();
|
||||
builder.cp_filtered(&ci_rustc_dir, &sysroot, &|path| {
|
||||
builder.cp_link_filtered(&ci_rustc_dir, &sysroot, &|path| {
|
||||
if path.extension().map_or(true, |ext| !filtered_extensions.contains(&ext)) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1791,7 +1792,7 @@ impl Step for Assemble {
|
|||
let filename = f.file_name().into_string().unwrap();
|
||||
if (is_dylib(&filename) || is_debug_info(&filename)) && !proc_macros.contains(&filename)
|
||||
{
|
||||
builder.copy(&f.path(), &rustc_libdir.join(&filename));
|
||||
builder.copy_link(&f.path(), &rustc_libdir.join(&filename));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1805,7 +1806,7 @@ impl Step for Assemble {
|
|||
if let Some(lld_install) = lld_install {
|
||||
let src_exe = exe("lld", target_compiler.host);
|
||||
let dst_exe = exe("rust-lld", target_compiler.host);
|
||||
builder.copy(&lld_install.join("bin").join(src_exe), &libdir_bin.join(dst_exe));
|
||||
builder.copy_link(&lld_install.join("bin").join(src_exe), &libdir_bin.join(dst_exe));
|
||||
let self_contained_lld_dir = libdir_bin.join("gcc-ld");
|
||||
t!(fs::create_dir_all(&self_contained_lld_dir));
|
||||
let lld_wrapper_exe = builder.ensure(crate::core::build_steps::tool::LldWrapper {
|
||||
|
|
@ -1813,7 +1814,7 @@ impl Step for Assemble {
|
|||
target: target_compiler.host,
|
||||
});
|
||||
for name in crate::LLD_FILE_NAMES {
|
||||
builder.copy(
|
||||
builder.copy_link(
|
||||
&lld_wrapper_exe,
|
||||
&self_contained_lld_dir.join(exe(name, target_compiler.host)),
|
||||
);
|
||||
|
|
@ -1838,7 +1839,7 @@ impl Step for Assemble {
|
|||
// When using `download-ci-llvm`, some of the tools
|
||||
// may not exist, so skip trying to copy them.
|
||||
if src_path.exists() {
|
||||
builder.copy(&src_path, &libdir_bin.join(&tool_exe));
|
||||
builder.copy_link(&src_path, &libdir_bin.join(&tool_exe));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1851,7 +1852,7 @@ impl Step for Assemble {
|
|||
extra_features: vec![],
|
||||
});
|
||||
let tool_exe = exe("llvm-bitcode-linker", target_compiler.host);
|
||||
builder.copy(&src_path, &libdir_bin.join(&tool_exe));
|
||||
builder.copy_link(&src_path, &libdir_bin.join(&tool_exe));
|
||||
}
|
||||
|
||||
// Ensure that `libLLVM.so` ends up in the newly build compiler directory,
|
||||
|
|
@ -1865,7 +1866,7 @@ impl Step for Assemble {
|
|||
let bindir = sysroot.join("bin");
|
||||
t!(fs::create_dir_all(bindir));
|
||||
let compiler = builder.rustc(target_compiler);
|
||||
builder.copy(&rustc, &compiler);
|
||||
builder.copy_link(&rustc, &compiler);
|
||||
|
||||
target_compiler
|
||||
}
|
||||
|
|
@ -1891,7 +1892,7 @@ pub fn add_to_sysroot(
|
|||
DependencyType::Target => sysroot_dst,
|
||||
DependencyType::TargetSelfContained => self_contained_dst,
|
||||
};
|
||||
builder.copy(&path, &dst.join(path.file_name().unwrap()));
|
||||
builder.copy_link(&path, &dst.join(path.file_name().unwrap()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -272,7 +272,7 @@ fn make_win_dist(
|
|||
let dist_bin_dir = rust_root.join("bin/");
|
||||
fs::create_dir_all(&dist_bin_dir).expect("creating dist_bin_dir failed");
|
||||
for src in rustc_dlls {
|
||||
builder.copy_to_folder(&src, &dist_bin_dir);
|
||||
builder.copy_link_to_folder(&src, &dist_bin_dir);
|
||||
}
|
||||
|
||||
//Copy platform tools to platform-specific bin directory
|
||||
|
|
@ -284,7 +284,7 @@ fn make_win_dist(
|
|||
.join("self-contained");
|
||||
fs::create_dir_all(&target_bin_dir).expect("creating target_bin_dir failed");
|
||||
for src in target_tools {
|
||||
builder.copy_to_folder(&src, &target_bin_dir);
|
||||
builder.copy_link_to_folder(&src, &target_bin_dir);
|
||||
}
|
||||
|
||||
// Warn windows-gnu users that the bundled GCC cannot compile C files
|
||||
|
|
@ -304,7 +304,7 @@ fn make_win_dist(
|
|||
.join("self-contained");
|
||||
fs::create_dir_all(&target_lib_dir).expect("creating target_lib_dir failed");
|
||||
for src in target_libs {
|
||||
builder.copy_to_folder(&src, &target_lib_dir);
|
||||
builder.copy_link_to_folder(&src, &target_lib_dir);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -400,7 +400,7 @@ impl Step for Rustc {
|
|||
|
||||
// Copy rustc binary
|
||||
t!(fs::create_dir_all(image.join("bin")));
|
||||
builder.cp_r(&src.join("bin"), &image.join("bin"));
|
||||
builder.cp_link_r(&src.join("bin"), &image.join("bin"));
|
||||
|
||||
// If enabled, copy rustdoc binary
|
||||
if builder
|
||||
|
|
@ -458,13 +458,13 @@ impl Step for Rustc {
|
|||
if builder.config.lld_enabled {
|
||||
let src_dir = builder.sysroot_libdir(compiler, host).parent().unwrap().join("bin");
|
||||
let rust_lld = exe("rust-lld", compiler.host);
|
||||
builder.copy(&src_dir.join(&rust_lld), &dst_dir.join(&rust_lld));
|
||||
builder.copy_link(&src_dir.join(&rust_lld), &dst_dir.join(&rust_lld));
|
||||
let self_contained_lld_src_dir = src_dir.join("gcc-ld");
|
||||
let self_contained_lld_dst_dir = dst_dir.join("gcc-ld");
|
||||
t!(fs::create_dir(&self_contained_lld_dst_dir));
|
||||
for name in crate::LLD_FILE_NAMES {
|
||||
let exe_name = exe(name, compiler.host);
|
||||
builder.copy(
|
||||
builder.copy_link(
|
||||
&self_contained_lld_src_dir.join(&exe_name),
|
||||
&self_contained_lld_dst_dir.join(&exe_name),
|
||||
);
|
||||
|
|
@ -609,9 +609,9 @@ fn copy_target_libs(builder: &Builder<'_>, target: TargetSelection, image: &Path
|
|||
t!(fs::create_dir_all(&self_contained_dst));
|
||||
for (path, dependency_type) in builder.read_stamp_file(stamp) {
|
||||
if dependency_type == DependencyType::TargetSelfContained {
|
||||
builder.copy(&path, &self_contained_dst.join(path.file_name().unwrap()));
|
||||
builder.copy_link(&path, &self_contained_dst.join(path.file_name().unwrap()));
|
||||
} else if dependency_type == DependencyType::Target || builder.config.build == target {
|
||||
builder.copy(&path, &dst.join(path.file_name().unwrap()));
|
||||
builder.copy_link(&path, &dst.join(path.file_name().unwrap()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -865,7 +865,8 @@ fn copy_src_dirs(
|
|||
for item in src_dirs {
|
||||
let dst = &dst_dir.join(item);
|
||||
t!(fs::create_dir_all(dst));
|
||||
builder.cp_filtered(&base.join(item), dst, &|path| filter_fn(exclude_dirs, item, path));
|
||||
builder
|
||||
.cp_link_filtered(&base.join(item), dst, &|path| filter_fn(exclude_dirs, item, path));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -923,7 +924,7 @@ impl Step for Src {
|
|||
&dst_src,
|
||||
);
|
||||
for file in src_files.iter() {
|
||||
builder.copy(&builder.src.join(file), &dst_src.join(file));
|
||||
builder.copy_link(&builder.src.join(file), &dst_src.join(file));
|
||||
}
|
||||
|
||||
tarball.generate()
|
||||
|
|
@ -979,7 +980,7 @@ impl Step for PlainSourceTarball {
|
|||
|
||||
// Copy the files normally
|
||||
for item in &src_files {
|
||||
builder.copy(&builder.src.join(item), &plain_dst_src.join(item));
|
||||
builder.copy_link(&builder.src.join(item), &plain_dst_src.join(item));
|
||||
}
|
||||
|
||||
// Create the version file
|
||||
|
|
@ -1608,7 +1609,7 @@ impl Step for Extended {
|
|||
|
||||
let prepare = |name: &str| {
|
||||
builder.create_dir(&pkg.join(name));
|
||||
builder.cp_r(
|
||||
builder.cp_link_r(
|
||||
&work.join(format!("{}-{}", pkgname(builder, name), target.triple)),
|
||||
&pkg.join(name),
|
||||
);
|
||||
|
|
@ -1672,7 +1673,7 @@ impl Step for Extended {
|
|||
} else {
|
||||
name.to_string()
|
||||
};
|
||||
builder.cp_r(
|
||||
builder.cp_link_r(
|
||||
&work.join(format!("{}-{}", pkgname(builder, name), target.triple)).join(dir),
|
||||
&exe.join(name),
|
||||
);
|
||||
|
|
@ -2040,7 +2041,7 @@ fn install_llvm_file(
|
|||
if install_symlink {
|
||||
// For download-ci-llvm, also install the symlink, to match what LLVM does. Using a
|
||||
// symlink is fine here, as this is not a rustup component.
|
||||
builder.copy(&source, &full_dest);
|
||||
builder.copy_link(&source, &full_dest);
|
||||
} else {
|
||||
// Otherwise, replace the symlink with an equivalent linker script. This is used when
|
||||
// projects like miri link against librustc_driver.so. We don't use a symlink, as
|
||||
|
|
|
|||
|
|
@ -520,7 +520,10 @@ impl Step for SharedAssets {
|
|||
t!(fs::write(&version_info, info));
|
||||
}
|
||||
|
||||
builder.copy(&builder.src.join("src").join("doc").join("rust.css"), &out.join("rust.css"));
|
||||
builder.copy_link(
|
||||
&builder.src.join("src").join("doc").join("rust.css"),
|
||||
&out.join("rust.css"),
|
||||
);
|
||||
|
||||
SharedAssetsPaths { version_info }
|
||||
}
|
||||
|
|
@ -718,7 +721,7 @@ fn doc_std(
|
|||
let _guard = builder.msg_doc(compiler, description, target);
|
||||
|
||||
builder.run(&mut cargo.into());
|
||||
builder.cp_r(&out_dir, out);
|
||||
builder.cp_link_r(&out_dir, out);
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||
|
|
@ -1151,7 +1154,7 @@ impl Step for RustcBook {
|
|||
let out_base = builder.md_doc_out(self.target).join("rustc");
|
||||
t!(fs::create_dir_all(&out_base));
|
||||
let out_listing = out_base.join("src/lints");
|
||||
builder.cp_r(&builder.src.join("src/doc/rustc"), &out_base);
|
||||
builder.cp_link_r(&builder.src.join("src/doc/rustc"), &out_base);
|
||||
builder.info(&format!("Generating lint docs ({})", self.target));
|
||||
|
||||
let rustc = builder.rustc(self.compiler);
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue