Merge from rustc

This commit is contained in:
The Miri Cronjob Bot 2024-03-17 05:22:24 +00:00
commit 0dff16a30c
340 changed files with 4871 additions and 3346 deletions

View file

@ -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

View file

@ -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"

View file

@ -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)),
}),
),

View file

@ -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),
}
}

View file

@ -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(_) => {

View file

@ -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)

View file

@ -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

View file

@ -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(),

View file

@ -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))

View file

@ -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));

View file

@ -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."),
}
}
}
}

View file

@ -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]

View file

@ -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

View file

@ -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) {

View 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;
}

View file

@ -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"

View file

@ -1,3 +1,3 @@
[toolchain]
channel = "nightly-2024-03-08"
channel = "nightly-2024-03-16"
components = ["rust-src", "rustc-dev", "llvm-tools"]

View file

@ -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

View file

@ -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,
)
}
};

View file

@ -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;
}

View file

@ -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) {

View file

@ -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"

View file

@ -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) }
}
}

View file

@ -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:
// ==========================================================================

View file

@ -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.

View file

@ -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,

View file

@ -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

View file

@ -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:

View file

@ -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,

View file

@ -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

View file

@ -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,

View file

@ -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),
}

View file

@ -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),

View file

@ -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 {

View file

@ -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())
}

View file

@ -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);

View file

@ -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

View file

@ -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);

View file

@ -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 {

View file

@ -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

View file

@ -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),

View file

@ -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,

View file

@ -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)
}

View file

@ -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;
};

View file

@ -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| {

View file

@ -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,
);
}

View file

@ -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.

View file

@ -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
);
}
}
}

View file

@ -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();

View file

@ -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))

View file

@ -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

View file

@ -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();

View file

@ -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.

View file

@ -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");

View file

@ -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)

View file

@ -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
}

View file

@ -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"`

View file

@ -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));
}

View file

@ -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));

View file

@ -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)
}

View file

@ -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()
}
}

View file

@ -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>>,

View file

@ -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.

View file

@ -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)
}

View file

@ -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

View file

@ -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),
}
}

View file

@ -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, &[]);
}
}

View file

@ -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.

View file

@ -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));

View file

@ -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" }

View file

@ -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);

View file

@ -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;

View file

@ -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>(

View file

@ -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>>,

View file

@ -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),
},
};

View file

@ -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)) => {

View file

@ -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);

View file

@ -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")]

View file

@ -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(..)) => {

View file

@ -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,

View file

@ -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")

View file

@ -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;
};

View file

@ -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 => {

View file

@ -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
//

View file

@ -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),
}
}

View file

@ -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.

View file

@ -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(),

View file

@ -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,

View file

@ -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) }
}
}
}
}

View file

@ -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

View file

@ -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);

View file

@ -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(())

View file

@ -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

View file

@ -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,

View file

@ -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",

View file

@ -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);

View file

@ -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()));
}
}

View file

@ -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

View file

@ -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