Merge from rustc
This commit is contained in:
commit
581989d1c6
668 changed files with 7073 additions and 4620 deletions
|
|
@ -3507,7 +3507,6 @@ dependencies = [
|
|||
"cc",
|
||||
"either",
|
||||
"itertools",
|
||||
"jobserver",
|
||||
"libc",
|
||||
"object 0.36.5",
|
||||
"pathdiff",
|
||||
|
|
|
|||
|
|
@ -1382,6 +1382,7 @@ impl Expr {
|
|||
| ExprKind::Tup(_)
|
||||
| ExprKind::Type(..)
|
||||
| ExprKind::Underscore
|
||||
| ExprKind::UnsafeBinderCast(..)
|
||||
| ExprKind::While(..)
|
||||
| ExprKind::Err(_)
|
||||
| ExprKind::Dummy => ExprPrecedence::Unambiguous,
|
||||
|
|
@ -1509,7 +1510,13 @@ pub enum ExprKind {
|
|||
/// `'label: for await? pat in iter { block }`
|
||||
///
|
||||
/// This is desugared to a combination of `loop` and `match` expressions.
|
||||
ForLoop { pat: P<Pat>, iter: P<Expr>, body: P<Block>, label: Option<Label>, kind: ForLoopKind },
|
||||
ForLoop {
|
||||
pat: P<Pat>,
|
||||
iter: P<Expr>,
|
||||
body: P<Block>,
|
||||
label: Option<Label>,
|
||||
kind: ForLoopKind,
|
||||
},
|
||||
/// Conditionless loop (can be exited with `break`, `continue`, or `return`).
|
||||
///
|
||||
/// `'label: loop { block }`
|
||||
|
|
@ -1614,6 +1621,8 @@ pub enum ExprKind {
|
|||
/// A `format_args!()` expression.
|
||||
FormatArgs(P<FormatArgs>),
|
||||
|
||||
UnsafeBinderCast(UnsafeBinderCastKind, P<Expr>, Option<P<Ty>>),
|
||||
|
||||
/// Placeholder for an expression that wasn't syntactically well formed in some way.
|
||||
Err(ErrorGuaranteed),
|
||||
|
||||
|
|
@ -1652,6 +1661,16 @@ impl GenBlockKind {
|
|||
}
|
||||
}
|
||||
|
||||
/// Whether we're unwrapping or wrapping an unsafe binder
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
#[derive(Encodable, Decodable, HashStable_Generic)]
|
||||
pub enum UnsafeBinderCastKind {
|
||||
// e.g. `&i32` -> `unsafe<'a> &'a i32`
|
||||
Wrap,
|
||||
// e.g. `unsafe<'a> &'a i32` -> `&i32`
|
||||
Unwrap,
|
||||
}
|
||||
|
||||
/// The explicit `Self` type in a "qualified path". The actual
|
||||
/// path, including the trait and the associated item, is stored
|
||||
/// separately. `position` represents the index of the associated
|
||||
|
|
@ -2223,6 +2242,12 @@ pub struct BareFnTy {
|
|||
pub decl_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct UnsafeBinderTy {
|
||||
pub generic_params: ThinVec<GenericParam>,
|
||||
pub inner_ty: P<Ty>,
|
||||
}
|
||||
|
||||
/// The various kinds of type recognized by the compiler.
|
||||
//
|
||||
// Adding a new variant? Please update `test_ty` in `tests/ui/macros/stringify.rs`.
|
||||
|
|
@ -2242,6 +2267,8 @@ pub enum TyKind {
|
|||
PinnedRef(Option<Lifetime>, MutTy),
|
||||
/// A bare function (e.g., `fn(usize) -> bool`).
|
||||
BareFn(P<BareFnTy>),
|
||||
/// An unsafe existential lifetime binder (e.g., `unsafe<'a> &'a ()`).
|
||||
UnsafeBinder(P<UnsafeBinderTy>),
|
||||
/// The never type (`!`).
|
||||
Never,
|
||||
/// A tuple (`(A, B, C, D,...)`).
|
||||
|
|
@ -2877,7 +2904,7 @@ pub enum ModKind {
|
|||
/// or with definition outlined to a separate file `mod foo;` and already loaded from it.
|
||||
/// The inner span is from the first token past `{` to the last token until `}`,
|
||||
/// or from the first to the last token in the loaded file.
|
||||
Loaded(ThinVec<P<Item>>, Inline, ModSpans),
|
||||
Loaded(ThinVec<P<Item>>, Inline, ModSpans, Result<(), ErrorGuaranteed>),
|
||||
/// Module with definition outlined to a separate file `mod foo;` but not yet loaded from it.
|
||||
Unloaded,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -558,6 +558,11 @@ pub fn walk_ty<T: MutVisitor>(vis: &mut T, ty: &mut P<Ty>) {
|
|||
vis.visit_fn_decl(decl);
|
||||
vis.visit_span(decl_span);
|
||||
}
|
||||
TyKind::UnsafeBinder(binder) => {
|
||||
let UnsafeBinderTy { generic_params, inner_ty } = binder.deref_mut();
|
||||
generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
|
||||
vis.visit_ty(inner_ty);
|
||||
}
|
||||
TyKind::Tup(tys) => visit_thin_vec(tys, |ty| vis.visit_ty(ty)),
|
||||
TyKind::Paren(ty) => vis.visit_ty(ty),
|
||||
TyKind::Pat(ty, pat) => {
|
||||
|
|
@ -1212,7 +1217,12 @@ impl WalkItemKind for ItemKind {
|
|||
ItemKind::Mod(safety, mod_kind) => {
|
||||
visit_safety(vis, safety);
|
||||
match mod_kind {
|
||||
ModKind::Loaded(items, _inline, ModSpans { inner_span, inject_use_span }) => {
|
||||
ModKind::Loaded(
|
||||
items,
|
||||
_inline,
|
||||
ModSpans { inner_span, inject_use_span },
|
||||
_,
|
||||
) => {
|
||||
items.flat_map_in_place(|item| vis.flat_map_item(item));
|
||||
vis.visit_span(inner_span);
|
||||
vis.visit_span(inject_use_span);
|
||||
|
|
@ -1775,6 +1785,12 @@ pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, token
|
|||
ExprKind::TryBlock(body) => vis.visit_block(body),
|
||||
ExprKind::Lit(_token) => {}
|
||||
ExprKind::IncludedBytes(_bytes) => {}
|
||||
ExprKind::UnsafeBinderCast(_kind, expr, ty) => {
|
||||
vis.visit_expr(expr);
|
||||
if let Some(ty) = ty {
|
||||
vis.visit_ty(ty);
|
||||
}
|
||||
}
|
||||
ExprKind::Err(_guar) => {}
|
||||
ExprKind::Dummy => {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -152,6 +152,7 @@ pub fn leading_labeled_expr(mut expr: &ast::Expr) -> bool {
|
|||
| Underscore
|
||||
| Yeet(..)
|
||||
| Yield(..)
|
||||
| UnsafeBinderCast(..)
|
||||
| Err(..)
|
||||
| Dummy => return false,
|
||||
}
|
||||
|
|
@ -232,6 +233,7 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<TrailingBrace<'_>> {
|
|||
| Paren(_)
|
||||
| Try(_)
|
||||
| Yeet(None)
|
||||
| UnsafeBinderCast(..)
|
||||
| Err(_)
|
||||
| Dummy => break None,
|
||||
}
|
||||
|
|
@ -253,6 +255,10 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> {
|
|||
ty = &mut_ty.ty;
|
||||
}
|
||||
|
||||
ast::TyKind::UnsafeBinder(binder) => {
|
||||
ty = &binder.inner_ty;
|
||||
}
|
||||
|
||||
ast::TyKind::BareFn(fn_ty) => match &fn_ty.decl.output {
|
||||
ast::FnRetTy::Default(_) => break None,
|
||||
ast::FnRetTy::Ty(ret) => ty = ret,
|
||||
|
|
|
|||
|
|
@ -380,7 +380,7 @@ impl WalkItemKind for ItemKind {
|
|||
try_visit!(visitor.visit_fn(kind, span, id));
|
||||
}
|
||||
ItemKind::Mod(_unsafety, mod_kind) => match mod_kind {
|
||||
ModKind::Loaded(items, _inline, _inner_span) => {
|
||||
ModKind::Loaded(items, _inline, _inner_span, _) => {
|
||||
walk_list!(visitor, visit_item, items);
|
||||
}
|
||||
ModKind::Unloaded => {}
|
||||
|
|
@ -522,6 +522,10 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result {
|
|||
walk_list!(visitor, visit_generic_param, generic_params);
|
||||
try_visit!(visitor.visit_fn_decl(decl));
|
||||
}
|
||||
TyKind::UnsafeBinder(binder) => {
|
||||
walk_list!(visitor, visit_generic_param, &binder.generic_params);
|
||||
try_visit!(visitor.visit_ty(&binder.inner_ty));
|
||||
}
|
||||
TyKind::Path(maybe_qself, path) => {
|
||||
try_visit!(visitor.visit_qself(maybe_qself));
|
||||
try_visit!(visitor.visit_path(path, *id));
|
||||
|
|
@ -1226,6 +1230,10 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
|
|||
ExprKind::TryBlock(body) => try_visit!(visitor.visit_block(body)),
|
||||
ExprKind::Lit(_token) => {}
|
||||
ExprKind::IncludedBytes(_bytes) => {}
|
||||
ExprKind::UnsafeBinderCast(_kind, expr, ty) => {
|
||||
try_visit!(visitor.visit_expr(expr));
|
||||
visit_opt!(visitor, visit_ty, ty);
|
||||
}
|
||||
ExprKind::Err(_guar) => {}
|
||||
ExprKind::Dummy => {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use rustc_ast::{Block, BlockCheckMode, Local, LocalKind, Stmt, StmtKind};
|
||||
use rustc_hir as hir;
|
||||
use rustc_span::sym;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext};
|
||||
|
|
@ -82,11 +83,21 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
(self.arena.alloc_from_iter(stmts), expr)
|
||||
}
|
||||
|
||||
/// Return an `ImplTraitContext` that allows impl trait in bindings if
|
||||
/// the feature gate is enabled, or issues a feature error if it is not.
|
||||
fn impl_trait_in_bindings_ctxt(&self, position: ImplTraitPosition) -> ImplTraitContext {
|
||||
if self.tcx.features().impl_trait_in_bindings() {
|
||||
ImplTraitContext::InBinding
|
||||
} else {
|
||||
ImplTraitContext::FeatureGated(position, sym::impl_trait_in_bindings)
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_local(&mut self, l: &Local) -> &'hir hir::LetStmt<'hir> {
|
||||
let ty = l
|
||||
.ty
|
||||
.as_ref()
|
||||
.map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Variable)));
|
||||
// Let statements are allowed to have impl trait in bindings.
|
||||
let ty = l.ty.as_ref().map(|t| {
|
||||
self.lower_ty(t, self.impl_trait_in_bindings_ctxt(ImplTraitPosition::Variable))
|
||||
});
|
||||
let init = l.kind.init().map(|init| self.lower_expr(init));
|
||||
let hir_id = self.lower_node_id(l.id);
|
||||
let pat = self.lower_pat(&l.pat);
|
||||
|
|
|
|||
|
|
@ -379,6 +379,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
|
||||
ExprKind::Err(guar) => hir::ExprKind::Err(*guar),
|
||||
|
||||
ExprKind::UnsafeBinderCast(kind, expr, ty) => hir::ExprKind::UnsafeBinderCast(
|
||||
*kind,
|
||||
self.lower_expr(expr),
|
||||
ty.as_ref().map(|ty| {
|
||||
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast))
|
||||
}),
|
||||
),
|
||||
|
||||
ExprKind::Dummy => {
|
||||
span_bug!(e.span, "lowered ExprKind::Dummy")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -238,7 +238,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
})
|
||||
}
|
||||
ItemKind::Mod(_, mod_kind) => match mod_kind {
|
||||
ModKind::Loaded(items, _, spans) => {
|
||||
ModKind::Loaded(items, _, spans, _) => {
|
||||
hir::ItemKind::Mod(self.lower_mod(items, spans))
|
||||
}
|
||||
ModKind::Unloaded => panic!("`mod` items should have been loaded by now"),
|
||||
|
|
|
|||
|
|
@ -260,6 +260,13 @@ enum ImplTraitContext {
|
|||
/// equivalent to a new opaque type like `type T = impl Debug; fn foo() -> T`.
|
||||
///
|
||||
OpaqueTy { origin: hir::OpaqueTyOrigin<LocalDefId> },
|
||||
|
||||
/// Treat `impl Trait` as a "trait ascription", which is like a type
|
||||
/// variable but that also enforces that a set of trait goals hold.
|
||||
///
|
||||
/// This is useful to guide inference for unnameable types.
|
||||
InBinding,
|
||||
|
||||
/// `impl Trait` is unstably accepted in this position.
|
||||
FeatureGated(ImplTraitPosition, Symbol),
|
||||
/// `impl Trait` is not accepted in this position.
|
||||
|
|
@ -1228,6 +1235,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
param_names: self.lower_fn_params_to_names(&f.decl),
|
||||
}))
|
||||
}
|
||||
TyKind::UnsafeBinder(f) => {
|
||||
let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params);
|
||||
hir::TyKind::UnsafeBinder(self.arena.alloc(hir::UnsafeBinderTy {
|
||||
generic_params,
|
||||
inner_ty: self.lower_ty(&f.inner_ty, itctx),
|
||||
}))
|
||||
}
|
||||
TyKind::Never => hir::TyKind::Never,
|
||||
TyKind::Tup(tys) => hir::TyKind::Tup(
|
||||
self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty_direct(ty, itctx))),
|
||||
|
|
@ -1320,6 +1334,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
path
|
||||
}
|
||||
ImplTraitContext::InBinding => {
|
||||
hir::TyKind::TraitAscription(self.lower_param_bounds(bounds, itctx))
|
||||
}
|
||||
ImplTraitContext::FeatureGated(position, feature) => {
|
||||
let guar = self
|
||||
.tcx
|
||||
|
|
|
|||
|
|
@ -1029,7 +1029,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
self.dcx().emit_err(errors::UnsafeItem { span, kind: "module" });
|
||||
}
|
||||
// Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
|
||||
if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))
|
||||
if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _, _))
|
||||
&& !attr::contains_name(&item.attrs, sym::path)
|
||||
{
|
||||
self.check_mod_file_item_asciionly(item.ident);
|
||||
|
|
|
|||
|
|
@ -560,6 +560,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
|||
gate_all!(return_type_notation, "return type notation is experimental");
|
||||
gate_all!(pin_ergonomics, "pinned reference syntax is experimental");
|
||||
gate_all!(unsafe_fields, "`unsafe` fields are experimental");
|
||||
gate_all!(unsafe_binders, "unsafe binder types are experimental");
|
||||
|
||||
if !visitor.features.never_patterns() {
|
||||
if let Some(spans) = spans.get(&sym::never_patterns) {
|
||||
|
|
|
|||
|
|
@ -1198,6 +1198,14 @@ impl<'a> State<'a> {
|
|||
ast::TyKind::BareFn(f) => {
|
||||
self.print_ty_fn(f.ext, f.safety, &f.decl, None, &f.generic_params);
|
||||
}
|
||||
ast::TyKind::UnsafeBinder(f) => {
|
||||
self.ibox(INDENT_UNIT);
|
||||
self.word("unsafe");
|
||||
self.print_generic_params(&f.generic_params);
|
||||
self.nbsp();
|
||||
self.print_type(&f.inner_ty);
|
||||
self.end();
|
||||
}
|
||||
ast::TyKind::Path(None, path) => {
|
||||
self.print_path(path, false, 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -772,6 +772,25 @@ impl<'a> State<'a> {
|
|||
self.word_nbsp("try");
|
||||
self.print_block_with_attrs(blk, attrs)
|
||||
}
|
||||
ast::ExprKind::UnsafeBinderCast(kind, expr, ty) => {
|
||||
self.word("builtin # ");
|
||||
match kind {
|
||||
ast::UnsafeBinderCastKind::Wrap => self.word("wrap_binder"),
|
||||
ast::UnsafeBinderCastKind::Unwrap => self.word("unwrap_binder"),
|
||||
}
|
||||
self.popen();
|
||||
self.ibox(0);
|
||||
self.print_expr(expr, FixupContext::default());
|
||||
|
||||
if let Some(ty) = ty {
|
||||
self.word(",");
|
||||
self.space();
|
||||
self.print_type(ty);
|
||||
}
|
||||
|
||||
self.end();
|
||||
self.pclose();
|
||||
}
|
||||
ast::ExprKind::Err(_) => {
|
||||
self.popen();
|
||||
self.word("/*ERROR*/");
|
||||
|
|
|
|||
|
|
@ -34,6 +34,25 @@ pub struct BorrowSet<'tcx> {
|
|||
pub(crate) locals_state_at_exit: LocalsStateAtExit,
|
||||
}
|
||||
|
||||
// These methods are public to support borrowck consumers.
|
||||
impl<'tcx> BorrowSet<'tcx> {
|
||||
pub fn location_map(&self) -> &FxIndexMap<Location, BorrowData<'tcx>> {
|
||||
&self.location_map
|
||||
}
|
||||
|
||||
pub fn activation_map(&self) -> &FxIndexMap<Location, Vec<BorrowIndex>> {
|
||||
&self.activation_map
|
||||
}
|
||||
|
||||
pub fn local_map(&self) -> &FxIndexMap<mir::Local, FxIndexSet<BorrowIndex>> {
|
||||
&self.local_map
|
||||
}
|
||||
|
||||
pub fn locals_state_at_exit(&self) -> &LocalsStateAtExit {
|
||||
&self.locals_state_at_exit
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Index<BorrowIndex> for BorrowSet<'tcx> {
|
||||
type Output = BorrowData<'tcx>;
|
||||
|
||||
|
|
@ -45,7 +64,7 @@ impl<'tcx> Index<BorrowIndex> for BorrowSet<'tcx> {
|
|||
/// Location where a two-phase borrow is activated, if a borrow
|
||||
/// is in fact a two-phase borrow.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub(crate) enum TwoPhaseActivation {
|
||||
pub enum TwoPhaseActivation {
|
||||
NotTwoPhase,
|
||||
NotActivated,
|
||||
ActivatedAt(Location),
|
||||
|
|
@ -68,6 +87,33 @@ pub struct BorrowData<'tcx> {
|
|||
pub(crate) assigned_place: mir::Place<'tcx>,
|
||||
}
|
||||
|
||||
// These methods are public to support borrowck consumers.
|
||||
impl<'tcx> BorrowData<'tcx> {
|
||||
pub fn reserve_location(&self) -> Location {
|
||||
self.reserve_location
|
||||
}
|
||||
|
||||
pub fn activation_location(&self) -> TwoPhaseActivation {
|
||||
self.activation_location
|
||||
}
|
||||
|
||||
pub fn kind(&self) -> mir::BorrowKind {
|
||||
self.kind
|
||||
}
|
||||
|
||||
pub fn region(&self) -> RegionVid {
|
||||
self.region
|
||||
}
|
||||
|
||||
pub fn borrowed_place(&self) -> mir::Place<'tcx> {
|
||||
self.borrowed_place
|
||||
}
|
||||
|
||||
pub fn assigned_place(&self) -> mir::Place<'tcx> {
|
||||
self.assigned_place
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Display for BorrowData<'tcx> {
|
||||
fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let kind = match self.kind {
|
||||
|
|
@ -120,7 +166,7 @@ impl LocalsStateAtExit {
|
|||
}
|
||||
|
||||
impl<'tcx> BorrowSet<'tcx> {
|
||||
pub(crate) fn build(
|
||||
pub fn build(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
locals_are_invalidated_at_exit: bool,
|
||||
|
|
|
|||
|
|
@ -5,15 +5,15 @@ use rustc_index::{IndexSlice, IndexVec};
|
|||
use rustc_middle::mir::{Body, Promoted};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
||||
pub use super::borrow_set::{BorrowData, BorrowSet, TwoPhaseActivation};
|
||||
pub use super::constraints::OutlivesConstraint;
|
||||
pub use super::dataflow::{BorrowIndex, Borrows, calculate_borrows_out_of_scope_at_location};
|
||||
pub use super::facts::{AllFacts as PoloniusInput, RustcFacts};
|
||||
pub use super::facts::{AllFacts as PoloniusInput, PoloniusRegionVid, RustcFacts};
|
||||
pub use super::location::{LocationTable, RichLocation};
|
||||
pub use super::nll::PoloniusOutput;
|
||||
pub use super::place_ext::PlaceExt;
|
||||
pub use super::places_conflict::{PlaceConflictBias, places_conflict};
|
||||
pub use super::region_infer::RegionInferenceContext;
|
||||
use crate::borrow_set::BorrowSet;
|
||||
|
||||
/// Options determining the output behavior of [`get_body_with_borrowck_facts`].
|
||||
///
|
||||
|
|
|
|||
|
|
@ -8,7 +8,10 @@ use rustc_middle::mir::{
|
|||
};
|
||||
use rustc_middle::ty::{RegionVid, TyCtxt};
|
||||
use rustc_mir_dataflow::fmt::DebugWithContext;
|
||||
use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces};
|
||||
use rustc_mir_dataflow::impls::{
|
||||
EverInitializedPlaces, EverInitializedPlacesDomain, MaybeUninitializedPlaces,
|
||||
MaybeUninitializedPlacesDomain,
|
||||
};
|
||||
use rustc_mir_dataflow::{Analysis, GenKill, JoinSemiLattice, SwitchIntEdgeEffects};
|
||||
use tracing::debug;
|
||||
|
||||
|
|
@ -24,7 +27,7 @@ pub(crate) struct Borrowck<'a, 'tcx> {
|
|||
}
|
||||
|
||||
impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
|
||||
type Domain = BorrowckDomain<'a, 'tcx>;
|
||||
type Domain = BorrowckDomain;
|
||||
|
||||
const NAME: &'static str = "borrowck";
|
||||
|
||||
|
|
@ -41,48 +44,48 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
|
|||
unreachable!();
|
||||
}
|
||||
|
||||
fn apply_before_statement_effect(
|
||||
fn apply_early_statement_effect(
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
stmt: &mir::Statement<'tcx>,
|
||||
loc: Location,
|
||||
) {
|
||||
self.borrows.apply_before_statement_effect(&mut state.borrows, stmt, loc);
|
||||
self.uninits.apply_before_statement_effect(&mut state.uninits, stmt, loc);
|
||||
self.ever_inits.apply_before_statement_effect(&mut state.ever_inits, stmt, loc);
|
||||
self.borrows.apply_early_statement_effect(&mut state.borrows, stmt, loc);
|
||||
self.uninits.apply_early_statement_effect(&mut state.uninits, stmt, loc);
|
||||
self.ever_inits.apply_early_statement_effect(&mut state.ever_inits, stmt, loc);
|
||||
}
|
||||
|
||||
fn apply_statement_effect(
|
||||
fn apply_primary_statement_effect(
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
stmt: &mir::Statement<'tcx>,
|
||||
loc: Location,
|
||||
) {
|
||||
self.borrows.apply_statement_effect(&mut state.borrows, stmt, loc);
|
||||
self.uninits.apply_statement_effect(&mut state.uninits, stmt, loc);
|
||||
self.ever_inits.apply_statement_effect(&mut state.ever_inits, stmt, loc);
|
||||
self.borrows.apply_primary_statement_effect(&mut state.borrows, stmt, loc);
|
||||
self.uninits.apply_primary_statement_effect(&mut state.uninits, stmt, loc);
|
||||
self.ever_inits.apply_primary_statement_effect(&mut state.ever_inits, stmt, loc);
|
||||
}
|
||||
|
||||
fn apply_before_terminator_effect(
|
||||
fn apply_early_terminator_effect(
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
term: &mir::Terminator<'tcx>,
|
||||
loc: Location,
|
||||
) {
|
||||
self.borrows.apply_before_terminator_effect(&mut state.borrows, term, loc);
|
||||
self.uninits.apply_before_terminator_effect(&mut state.uninits, term, loc);
|
||||
self.ever_inits.apply_before_terminator_effect(&mut state.ever_inits, term, loc);
|
||||
self.borrows.apply_early_terminator_effect(&mut state.borrows, term, loc);
|
||||
self.uninits.apply_early_terminator_effect(&mut state.uninits, term, loc);
|
||||
self.ever_inits.apply_early_terminator_effect(&mut state.ever_inits, term, loc);
|
||||
}
|
||||
|
||||
fn apply_terminator_effect<'mir>(
|
||||
fn apply_primary_terminator_effect<'mir>(
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
term: &'mir mir::Terminator<'tcx>,
|
||||
loc: Location,
|
||||
) -> TerminatorEdges<'mir, 'tcx> {
|
||||
self.borrows.apply_terminator_effect(&mut state.borrows, term, loc);
|
||||
self.uninits.apply_terminator_effect(&mut state.uninits, term, loc);
|
||||
self.ever_inits.apply_terminator_effect(&mut state.ever_inits, term, loc);
|
||||
self.borrows.apply_primary_terminator_effect(&mut state.borrows, term, loc);
|
||||
self.uninits.apply_primary_terminator_effect(&mut state.uninits, term, loc);
|
||||
self.ever_inits.apply_primary_terminator_effect(&mut state.ever_inits, term, loc);
|
||||
|
||||
// This return value doesn't matter. It's only used by `iterate_to_fixpoint`, which this
|
||||
// analysis doesn't use.
|
||||
|
|
@ -110,14 +113,14 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl JoinSemiLattice for BorrowckDomain<'_, '_> {
|
||||
impl JoinSemiLattice for BorrowckDomain {
|
||||
fn join(&mut self, _other: &Self) -> bool {
|
||||
// This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use.
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, C> DebugWithContext<C> for BorrowckDomain<'_, 'tcx>
|
||||
impl<'tcx, C> DebugWithContext<C> for BorrowckDomain
|
||||
where
|
||||
C: rustc_mir_dataflow::move_paths::HasMoveData<'tcx>,
|
||||
{
|
||||
|
|
@ -160,10 +163,10 @@ where
|
|||
|
||||
/// The transient state of the dataflow analyses used by the borrow checker.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub(crate) struct BorrowckDomain<'a, 'tcx> {
|
||||
pub(crate) borrows: <Borrows<'a, 'tcx> as Analysis<'tcx>>::Domain,
|
||||
pub(crate) uninits: <MaybeUninitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain,
|
||||
pub(crate) ever_inits: <EverInitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain,
|
||||
pub(crate) struct BorrowckDomain {
|
||||
pub(crate) borrows: BorrowsDomain,
|
||||
pub(crate) uninits: MaybeUninitializedPlacesDomain,
|
||||
pub(crate) ever_inits: EverInitializedPlacesDomain,
|
||||
}
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
|
|
@ -503,7 +506,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
|
|||
/// That means they went out of a nonlexical scope
|
||||
fn kill_loans_out_of_scope_at_location(
|
||||
&self,
|
||||
trans: &mut <Self as Analysis<'tcx>>::Domain,
|
||||
state: &mut <Self as Analysis<'tcx>>::Domain,
|
||||
location: Location,
|
||||
) {
|
||||
// NOTE: The state associated with a given `location`
|
||||
|
|
@ -518,14 +521,14 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
|
|||
// region, then setting that gen-bit will override any
|
||||
// potential kill introduced here.
|
||||
if let Some(indices) = self.borrows_out_of_scope_at_location.get(&location) {
|
||||
trans.kill_all(indices.iter().copied());
|
||||
state.kill_all(indices.iter().copied());
|
||||
}
|
||||
}
|
||||
|
||||
/// Kill any borrows that conflict with `place`.
|
||||
fn kill_borrows_on_place(
|
||||
&self,
|
||||
trans: &mut <Self as Analysis<'tcx>>::Domain,
|
||||
state: &mut <Self as Analysis<'tcx>>::Domain,
|
||||
place: Place<'tcx>,
|
||||
) {
|
||||
debug!("kill_borrows_on_place: place={:?}", place);
|
||||
|
|
@ -543,7 +546,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
|
|||
// `places_conflict` for every borrow.
|
||||
if place.projection.is_empty() {
|
||||
if !self.body.local_decls[place.local].is_ref_to_static() {
|
||||
trans.kill_all(other_borrows_of_local);
|
||||
state.kill_all(other_borrows_of_local);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -562,10 +565,12 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
|
|||
)
|
||||
});
|
||||
|
||||
trans.kill_all(definitely_conflicting_borrows);
|
||||
state.kill_all(definitely_conflicting_borrows);
|
||||
}
|
||||
}
|
||||
|
||||
type BorrowsDomain = BitSet<BorrowIndex>;
|
||||
|
||||
/// Forward dataflow computation of the set of borrows that are in scope at a particular location.
|
||||
/// - we gen the introduced loans
|
||||
/// - we kill loans on locals going out of (regular) scope
|
||||
|
|
@ -574,7 +579,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
|
|||
/// - we also kill loans of conflicting places when overwriting a shared path: e.g. borrows of
|
||||
/// `a.b.c` when `a` is overwritten.
|
||||
impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
|
||||
type Domain = BitSet<BorrowIndex>;
|
||||
type Domain = BorrowsDomain;
|
||||
|
||||
const NAME: &'static str = "borrows";
|
||||
|
||||
|
|
@ -588,18 +593,18 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
|
|||
// function execution, so this method has no effect.
|
||||
}
|
||||
|
||||
fn apply_before_statement_effect(
|
||||
fn apply_early_statement_effect(
|
||||
&mut self,
|
||||
trans: &mut Self::Domain,
|
||||
state: &mut Self::Domain,
|
||||
_statement: &mir::Statement<'tcx>,
|
||||
location: Location,
|
||||
) {
|
||||
self.kill_loans_out_of_scope_at_location(trans, location);
|
||||
self.kill_loans_out_of_scope_at_location(state, location);
|
||||
}
|
||||
|
||||
fn apply_statement_effect(
|
||||
fn apply_primary_statement_effect(
|
||||
&mut self,
|
||||
trans: &mut Self::Domain,
|
||||
state: &mut Self::Domain,
|
||||
stmt: &mir::Statement<'tcx>,
|
||||
location: Location,
|
||||
) {
|
||||
|
|
@ -617,18 +622,18 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
|
|||
panic!("could not find BorrowIndex for location {location:?}");
|
||||
});
|
||||
|
||||
trans.gen_(index);
|
||||
state.gen_(index);
|
||||
}
|
||||
|
||||
// Make sure there are no remaining borrows for variables
|
||||
// that are assigned over.
|
||||
self.kill_borrows_on_place(trans, *lhs);
|
||||
self.kill_borrows_on_place(state, *lhs);
|
||||
}
|
||||
|
||||
mir::StatementKind::StorageDead(local) => {
|
||||
// Make sure there are no remaining borrows for locals that
|
||||
// are gone out of scope.
|
||||
self.kill_borrows_on_place(trans, Place::from(*local));
|
||||
self.kill_borrows_on_place(state, Place::from(*local));
|
||||
}
|
||||
|
||||
mir::StatementKind::FakeRead(..)
|
||||
|
|
@ -646,18 +651,18 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn apply_before_terminator_effect(
|
||||
fn apply_early_terminator_effect(
|
||||
&mut self,
|
||||
trans: &mut Self::Domain,
|
||||
state: &mut Self::Domain,
|
||||
_terminator: &mir::Terminator<'tcx>,
|
||||
location: Location,
|
||||
) {
|
||||
self.kill_loans_out_of_scope_at_location(trans, location);
|
||||
self.kill_loans_out_of_scope_at_location(state, location);
|
||||
}
|
||||
|
||||
fn apply_terminator_effect<'mir>(
|
||||
fn apply_primary_terminator_effect<'mir>(
|
||||
&mut self,
|
||||
trans: &mut Self::Domain,
|
||||
state: &mut Self::Domain,
|
||||
terminator: &'mir mir::Terminator<'tcx>,
|
||||
_location: Location,
|
||||
) -> TerminatorEdges<'mir, 'tcx> {
|
||||
|
|
@ -666,7 +671,7 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
|
|||
if let mir::InlineAsmOperand::Out { place: Some(place), .. }
|
||||
| mir::InlineAsmOperand::InOut { out_place: Some(place), .. } = *op
|
||||
{
|
||||
self.kill_borrows_on_place(trans, place);
|
||||
self.kill_borrows_on_place(state, place);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1100,12 +1100,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
}
|
||||
let decl_span = local_decl.source_info.span;
|
||||
|
||||
let label = match *local_decl.local_info() {
|
||||
let amp_mut_sugg = match *local_decl.local_info() {
|
||||
LocalInfo::User(mir::BindingForm::ImplicitSelf(_)) => {
|
||||
let suggestion = suggest_ampmut_self(self.infcx.tcx, decl_span);
|
||||
let additional =
|
||||
local_trait.map(|span| (span, suggest_ampmut_self(self.infcx.tcx, span)));
|
||||
Some((true, decl_span, suggestion, additional))
|
||||
Some(AmpMutSugg { has_sugg: true, span: decl_span, suggestion, additional })
|
||||
}
|
||||
|
||||
LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
|
||||
|
|
@ -1150,7 +1150,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
None
|
||||
}
|
||||
None => {
|
||||
let (has_sugg, decl_span, sugg) = if name != kw::SelfLower {
|
||||
if name != kw::SelfLower {
|
||||
suggest_ampmut(
|
||||
self.infcx.tcx,
|
||||
local_decl.ty,
|
||||
|
|
@ -1165,7 +1165,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
..
|
||||
})) => {
|
||||
let sugg = suggest_ampmut_self(self.infcx.tcx, decl_span);
|
||||
(true, decl_span, sugg)
|
||||
Some(AmpMutSugg {
|
||||
has_sugg: true,
|
||||
span: decl_span,
|
||||
suggestion: sugg,
|
||||
additional: None,
|
||||
})
|
||||
}
|
||||
// explicit self (eg `self: &'a Self`)
|
||||
_ => suggest_ampmut(
|
||||
|
|
@ -1176,8 +1181,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
opt_ty_info,
|
||||
),
|
||||
}
|
||||
};
|
||||
Some((has_sugg, decl_span, sugg, None))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1187,15 +1191,24 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
..
|
||||
})) => {
|
||||
let pattern_span: Span = local_decl.source_info.span;
|
||||
suggest_ref_mut(self.infcx.tcx, pattern_span)
|
||||
.map(|span| (true, span, "mut ".to_owned(), None))
|
||||
suggest_ref_mut(self.infcx.tcx, pattern_span).map(|span| AmpMutSugg {
|
||||
has_sugg: true,
|
||||
span,
|
||||
suggestion: "mut ".to_owned(),
|
||||
additional: None,
|
||||
})
|
||||
}
|
||||
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
match label {
|
||||
Some((true, err_help_span, suggested_code, additional)) => {
|
||||
match amp_mut_sugg {
|
||||
Some(AmpMutSugg {
|
||||
has_sugg: true,
|
||||
span: err_help_span,
|
||||
suggestion: suggested_code,
|
||||
additional,
|
||||
}) => {
|
||||
let mut sugg = vec![(err_help_span, suggested_code)];
|
||||
if let Some(s) = additional {
|
||||
sugg.push(s);
|
||||
|
|
@ -1217,7 +1230,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
);
|
||||
}
|
||||
}
|
||||
Some((false, err_label_span, message, _)) => {
|
||||
Some(AmpMutSugg {
|
||||
has_sugg: false, span: err_label_span, suggestion: message, ..
|
||||
}) => {
|
||||
let def_id = self.body.source.def_id();
|
||||
let hir_id = if let Some(local_def_id) = def_id.as_local()
|
||||
&& let Some(body) = self.infcx.tcx.hir().maybe_body_owned_by(local_def_id)
|
||||
|
|
@ -1422,6 +1437,13 @@ fn suggest_ampmut_self<'tcx>(tcx: TyCtxt<'tcx>, span: Span) -> String {
|
|||
}
|
||||
}
|
||||
|
||||
struct AmpMutSugg {
|
||||
has_sugg: bool,
|
||||
span: Span,
|
||||
suggestion: String,
|
||||
additional: Option<(Span, String)>,
|
||||
}
|
||||
|
||||
// When we want to suggest a user change a local variable to be a `&mut`, there
|
||||
// are three potential "obvious" things to highlight:
|
||||
//
|
||||
|
|
@ -1443,7 +1465,7 @@ fn suggest_ampmut<'tcx>(
|
|||
decl_span: Span,
|
||||
opt_assignment_rhs_span: Option<Span>,
|
||||
opt_ty_info: Option<Span>,
|
||||
) -> (bool, Span, String) {
|
||||
) -> Option<AmpMutSugg> {
|
||||
// if there is a RHS and it starts with a `&` from it, then check if it is
|
||||
// mutable, and if not, put suggest putting `mut ` to make it mutable.
|
||||
// we don't have to worry about lifetime annotations here because they are
|
||||
|
|
@ -1456,6 +1478,11 @@ fn suggest_ampmut<'tcx>(
|
|||
&& let Ok(src) = tcx.sess.source_map().span_to_snippet(assignment_rhs_span)
|
||||
&& let Some(stripped) = src.strip_prefix('&')
|
||||
{
|
||||
let is_raw_ref = stripped.trim_start().starts_with("raw ");
|
||||
// We don't support raw refs yet
|
||||
if is_raw_ref {
|
||||
return None;
|
||||
}
|
||||
let is_mut = if let Some(rest) = stripped.trim_start().strip_prefix("mut") {
|
||||
match rest.chars().next() {
|
||||
// e.g. `&mut x`
|
||||
|
|
@ -1479,7 +1506,12 @@ fn suggest_ampmut<'tcx>(
|
|||
|
||||
// FIXME(Ezrashaw): returning is bad because we still might want to
|
||||
// update the annotated type, see #106857.
|
||||
return (true, span, "mut ".to_owned());
|
||||
return Some(AmpMutSugg {
|
||||
has_sugg: true,
|
||||
span,
|
||||
suggestion: "mut ".to_owned(),
|
||||
additional: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1504,18 +1536,23 @@ fn suggest_ampmut<'tcx>(
|
|||
&& let Some(ws_pos) = src.find(char::is_whitespace)
|
||||
{
|
||||
let span = span.with_lo(span.lo() + BytePos(ws_pos as u32)).shrink_to_lo();
|
||||
(true, span, " mut".to_owned())
|
||||
Some(AmpMutSugg { has_sugg: true, span, suggestion: " mut".to_owned(), additional: None })
|
||||
// if there is already a binding, we modify it to be `mut`
|
||||
} else if binding_exists {
|
||||
// shrink the span to just after the `&` in `&variable`
|
||||
let span = span.with_lo(span.lo() + BytePos(1)).shrink_to_lo();
|
||||
(true, span, "mut ".to_owned())
|
||||
Some(AmpMutSugg { has_sugg: true, span, suggestion: "mut ".to_owned(), additional: None })
|
||||
} else {
|
||||
// otherwise, suggest that the user annotates the binding; we provide the
|
||||
// type of the local.
|
||||
let ty = decl_ty.builtin_deref(true).unwrap();
|
||||
|
||||
(false, span, format!("{}mut {}", if decl_ty.is_ref() { "&" } else { "*" }, ty))
|
||||
Some(AmpMutSugg {
|
||||
has_sugg: false,
|
||||
span,
|
||||
suggestion: format!("{}mut {}", if decl_ty.is_ref() { "&" } else { "*" }, ty),
|
||||
additional: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ use rustc_mir_dataflow::impls::{
|
|||
use rustc_mir_dataflow::move_paths::{
|
||||
InitIndex, InitLocation, LookupResult, MoveData, MoveOutIndex, MovePathIndex,
|
||||
};
|
||||
use rustc_mir_dataflow::{Analysis, EntrySets, Results, ResultsVisitor, visit_results};
|
||||
use rustc_mir_dataflow::{Analysis, EntryStates, Results, ResultsVisitor, visit_results};
|
||||
use rustc_session::lint::builtin::UNUSED_MUT;
|
||||
use rustc_span::{Span, Symbol};
|
||||
use smallvec::SmallVec;
|
||||
|
|
@ -426,14 +426,14 @@ fn get_flow_results<'a, 'tcx>(
|
|||
ever_inits: ever_inits.analysis,
|
||||
};
|
||||
|
||||
assert_eq!(borrows.entry_sets.len(), uninits.entry_sets.len());
|
||||
assert_eq!(borrows.entry_sets.len(), ever_inits.entry_sets.len());
|
||||
let entry_sets: EntrySets<'_, Borrowck<'_, '_>> =
|
||||
itertools::izip!(borrows.entry_sets, uninits.entry_sets, ever_inits.entry_sets)
|
||||
assert_eq!(borrows.entry_states.len(), uninits.entry_states.len());
|
||||
assert_eq!(borrows.entry_states.len(), ever_inits.entry_states.len());
|
||||
let entry_states: EntryStates<'_, Borrowck<'_, '_>> =
|
||||
itertools::izip!(borrows.entry_states, uninits.entry_states, ever_inits.entry_states)
|
||||
.map(|(borrows, uninits, ever_inits)| BorrowckDomain { borrows, uninits, ever_inits })
|
||||
.collect();
|
||||
|
||||
Results { analysis, entry_sets }
|
||||
Results { analysis, entry_states }
|
||||
}
|
||||
|
||||
pub(crate) struct BorrowckInferCtxt<'tcx> {
|
||||
|
|
@ -600,10 +600,10 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
|
|||
// 3. assignments do not affect things loaned out as immutable
|
||||
// 4. moves do not affect things loaned out in any way
|
||||
impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, '_, 'tcx> {
|
||||
fn visit_statement_before_primary_effect(
|
||||
fn visit_after_early_statement_effect(
|
||||
&mut self,
|
||||
_results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
|
||||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
state: &BorrowckDomain,
|
||||
stmt: &'a Statement<'tcx>,
|
||||
location: Location,
|
||||
) {
|
||||
|
|
@ -674,10 +674,10 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<
|
|||
}
|
||||
}
|
||||
|
||||
fn visit_terminator_before_primary_effect(
|
||||
fn visit_after_early_terminator_effect(
|
||||
&mut self,
|
||||
_results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
|
||||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
state: &BorrowckDomain,
|
||||
term: &'a Terminator<'tcx>,
|
||||
loc: Location,
|
||||
) {
|
||||
|
|
@ -787,10 +787,10 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<
|
|||
}
|
||||
}
|
||||
|
||||
fn visit_terminator_after_primary_effect(
|
||||
fn visit_after_primary_terminator_effect(
|
||||
&mut self,
|
||||
_results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
|
||||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
state: &BorrowckDomain,
|
||||
term: &'a Terminator<'tcx>,
|
||||
loc: Location,
|
||||
) {
|
||||
|
|
@ -983,7 +983,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
place_span: (Place<'tcx>, Span),
|
||||
kind: (AccessDepth, ReadOrWrite),
|
||||
is_local_mutation_allowed: LocalMutationIsAllowed,
|
||||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
state: &BorrowckDomain,
|
||||
) {
|
||||
let (sd, rw) = kind;
|
||||
|
||||
|
|
@ -1032,7 +1032,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
place_span: (Place<'tcx>, Span),
|
||||
sd: AccessDepth,
|
||||
rw: ReadOrWrite,
|
||||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
state: &BorrowckDomain,
|
||||
) -> bool {
|
||||
let mut error_reported = false;
|
||||
|
||||
|
|
@ -1172,7 +1172,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
location: Location,
|
||||
place_span: (Place<'tcx>, Span),
|
||||
kind: AccessDepth,
|
||||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
state: &BorrowckDomain,
|
||||
) {
|
||||
// Write of P[i] or *P requires P init'd.
|
||||
self.check_if_assigned_path_is_moved(location, place_span, state);
|
||||
|
|
@ -1190,7 +1190,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
&mut self,
|
||||
location: Location,
|
||||
(rvalue, span): (&'a Rvalue<'tcx>, Span),
|
||||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
state: &BorrowckDomain,
|
||||
) {
|
||||
match rvalue {
|
||||
&Rvalue::Ref(_ /*rgn*/, bk, place) => {
|
||||
|
|
@ -1448,7 +1448,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
&mut self,
|
||||
location: Location,
|
||||
(operand, span): (&'a Operand<'tcx>, Span),
|
||||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
state: &BorrowckDomain,
|
||||
) {
|
||||
match *operand {
|
||||
Operand::Copy(place) => {
|
||||
|
|
@ -1568,12 +1568,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_activations(
|
||||
&mut self,
|
||||
location: Location,
|
||||
span: Span,
|
||||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
) {
|
||||
fn check_activations(&mut self, location: Location, span: Span, state: &BorrowckDomain) {
|
||||
// Two-phase borrow support: For each activation that is newly
|
||||
// generated at this statement, check if it interferes with
|
||||
// another borrow.
|
||||
|
|
@ -1731,7 +1726,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
location: Location,
|
||||
desired_action: InitializationRequiringAction,
|
||||
place_span: (PlaceRef<'tcx>, Span),
|
||||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
state: &BorrowckDomain,
|
||||
) {
|
||||
let maybe_uninits = &state.uninits;
|
||||
|
||||
|
|
@ -1836,7 +1831,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
location: Location,
|
||||
desired_action: InitializationRequiringAction,
|
||||
place_span: (PlaceRef<'tcx>, Span),
|
||||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
state: &BorrowckDomain,
|
||||
) {
|
||||
let maybe_uninits = &state.uninits;
|
||||
|
||||
|
|
@ -1935,7 +1930,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
&mut self,
|
||||
location: Location,
|
||||
(place, span): (Place<'tcx>, Span),
|
||||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
state: &BorrowckDomain,
|
||||
) {
|
||||
debug!("check_if_assigned_path_is_moved place: {:?}", place);
|
||||
|
||||
|
|
@ -2001,7 +1996,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
location: Location,
|
||||
base: PlaceRef<'tcx>,
|
||||
span: Span,
|
||||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
state: &BorrowckDomain,
|
||||
) {
|
||||
// rust-lang/rust#21232: Until Rust allows reads from the
|
||||
// initialized parts of partially initialized structs, we
|
||||
|
|
@ -2092,7 +2087,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
(place, span): (Place<'tcx>, Span),
|
||||
kind: ReadOrWrite,
|
||||
is_local_mutation_allowed: LocalMutationIsAllowed,
|
||||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
state: &BorrowckDomain,
|
||||
location: Location,
|
||||
) -> bool {
|
||||
debug!(
|
||||
|
|
@ -2206,18 +2201,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn is_local_ever_initialized(
|
||||
&self,
|
||||
local: Local,
|
||||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
) -> Option<InitIndex> {
|
||||
fn is_local_ever_initialized(&self, local: Local, state: &BorrowckDomain) -> Option<InitIndex> {
|
||||
let mpi = self.move_data.rev_lookup.find_local(local)?;
|
||||
let ii = &self.move_data.init_path_map[mpi];
|
||||
ii.into_iter().find(|&&index| state.ever_inits.contains(index)).copied()
|
||||
}
|
||||
|
||||
/// Adds the place into the used mutable variables set
|
||||
fn add_used_mut(&mut self, root_place: RootPlace<'tcx>, state: &BorrowckDomain<'a, 'tcx>) {
|
||||
fn add_used_mut(&mut self, root_place: RootPlace<'tcx>, state: &BorrowckDomain) {
|
||||
match root_place {
|
||||
RootPlace { place_local: local, place_projection: [], is_local_mutation_allowed } => {
|
||||
// If the local may have been initialized, and it is now currently being
|
||||
|
|
|
|||
|
|
@ -275,7 +275,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
user_ty: ty::UserType<'tcx>,
|
||||
span: Span,
|
||||
) {
|
||||
let ty::UserType::Ty(user_ty) = user_ty else { bug!() };
|
||||
let ty::UserTypeKind::Ty(user_ty) = user_ty.kind else { bug!() };
|
||||
|
||||
// A fast path for a common case with closure input/output types.
|
||||
if let ty::Infer(_) = user_ty.kind() {
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
) {
|
||||
self.ascribe_user_type_skip_wf(
|
||||
arg_decl.ty,
|
||||
ty::UserType::Ty(user_ty),
|
||||
ty::UserType::new(ty::UserTypeKind::Ty(user_ty)),
|
||||
arg_decl.source_info.span,
|
||||
);
|
||||
}
|
||||
|
|
@ -119,7 +119,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
let output_decl = &body.local_decls[RETURN_PLACE];
|
||||
self.ascribe_user_type_skip_wf(
|
||||
output_decl.ty,
|
||||
ty::UserType::Ty(user_provided_sig.output()),
|
||||
ty::UserType::new(ty::UserTypeKind::Ty(user_provided_sig.output())),
|
||||
output_decl.source_info.span,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ use rustc_middle::ty::visit::TypeVisitableExt;
|
|||
use rustc_middle::ty::{
|
||||
self, Binder, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, CoroutineArgsExt,
|
||||
Dynamic, GenericArgsRef, OpaqueHiddenType, OpaqueTypeKey, RegionVid, Ty, TyCtxt, UserArgs,
|
||||
UserType, UserTypeAnnotationIndex,
|
||||
UserTypeAnnotationIndex,
|
||||
};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_mir_dataflow::ResultsCursor;
|
||||
|
|
@ -370,7 +370,10 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
|||
} else {
|
||||
self.cx.ascribe_user_type(
|
||||
constant.const_.ty(),
|
||||
UserType::TypeOf(uv.def, UserArgs { args: uv.args, user_self_ty: None }),
|
||||
ty::UserType::new(ty::UserTypeKind::TypeOf(uv.def, UserArgs {
|
||||
args: uv.args,
|
||||
user_self_ty: None,
|
||||
})),
|
||||
locations.span(self.cx.body),
|
||||
);
|
||||
}
|
||||
|
|
@ -991,9 +994,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
for user_annotation in self.user_type_annotations {
|
||||
let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation;
|
||||
let annotation = self.instantiate_canonical(span, user_ty);
|
||||
if let ty::UserType::TypeOf(def, args) = annotation
|
||||
if let ty::UserTypeKind::TypeOf(def, args) = annotation.kind
|
||||
&& let DefKind::InlineConst = tcx.def_kind(def)
|
||||
{
|
||||
assert!(annotation.bounds.is_empty());
|
||||
self.check_inline_const(inferred_ty, def.expect_local(), args, span);
|
||||
} else {
|
||||
self.ascribe_user_type(inferred_ty, annotation, span);
|
||||
|
|
|
|||
|
|
@ -323,7 +323,8 @@ impl<'cx, 'a> Context<'cx, 'a> {
|
|||
| ExprKind::While(_, _, _)
|
||||
| ExprKind::Yeet(_)
|
||||
| ExprKind::Become(_)
|
||||
| ExprKind::Yield(_) => {}
|
||||
| ExprKind::Yield(_)
|
||||
| ExprKind::UnsafeBinderCast(..) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -141,8 +141,10 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
|
|||
|
||||
// We don't want to recurse into anything other than mods, since
|
||||
// mods or tests inside of functions will break things
|
||||
if let ast::ItemKind::Mod(_, ModKind::Loaded(.., ast::ModSpans { inner_span: span, .. })) =
|
||||
item.kind
|
||||
if let ast::ItemKind::Mod(
|
||||
_,
|
||||
ModKind::Loaded(.., ast::ModSpans { inner_span: span, .. }, _),
|
||||
) = item.kind
|
||||
{
|
||||
let prev_tests = mem::take(&mut self.tests);
|
||||
walk_item_kind(
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
use std::sync::{Arc, Condvar, Mutex};
|
||||
|
||||
use jobserver::HelperThread;
|
||||
use rustc_data_structures::jobserver::{self, HelperThread};
|
||||
use rustc_errors::DiagCtxtHandle;
|
||||
use rustc_session::Session;
|
||||
|
||||
// FIXME don't panic when a worker thread panics
|
||||
|
||||
|
|
@ -14,14 +13,13 @@ pub(super) struct ConcurrencyLimiter {
|
|||
}
|
||||
|
||||
impl ConcurrencyLimiter {
|
||||
pub(super) fn new(sess: &Session, pending_jobs: usize) -> Self {
|
||||
pub(super) fn new(pending_jobs: usize) -> Self {
|
||||
let state = Arc::new(Mutex::new(state::ConcurrencyLimiterState::new(pending_jobs)));
|
||||
let available_token_condvar = Arc::new(Condvar::new());
|
||||
|
||||
let state_helper = state.clone();
|
||||
let available_token_condvar_helper = available_token_condvar.clone();
|
||||
let helper_thread = sess
|
||||
.jobserver
|
||||
let helper_thread = jobserver::client()
|
||||
.clone()
|
||||
.into_helper_thread(move |token| {
|
||||
let mut state = state_helper.lock().unwrap();
|
||||
|
|
@ -113,7 +111,7 @@ impl Drop for ConcurrencyLimiterToken {
|
|||
}
|
||||
|
||||
mod state {
|
||||
use jobserver::Acquired;
|
||||
use rustc_data_structures::jobserver::Acquired;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) struct ConcurrencyLimiterState {
|
||||
|
|
|
|||
|
|
@ -679,7 +679,7 @@ pub(crate) fn run_aot(
|
|||
metadata_module: None,
|
||||
metadata,
|
||||
crate_info: CrateInfo::new(tcx, target_cpu),
|
||||
concurrency_limiter: ConcurrencyLimiter::new(tcx.sess, 0),
|
||||
concurrency_limiter: ConcurrencyLimiter::new(0),
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -711,7 +711,7 @@ pub(crate) fn run_aot(
|
|||
CguReuse::PreLto | CguReuse::PostLto => false,
|
||||
});
|
||||
|
||||
let concurrency_limiter = IntoDynSyncSend(ConcurrencyLimiter::new(tcx.sess, todo_cgus.len()));
|
||||
let concurrency_limiter = IntoDynSyncSend(ConcurrencyLimiter::new(todo_cgus.len()));
|
||||
|
||||
let modules = tcx.sess.time("codegen mono items", || {
|
||||
let mut modules: Vec<_> = par_map(todo_cgus, |(_, cgu)| {
|
||||
|
|
|
|||
|
|
@ -287,12 +287,7 @@ fn dep_symbol_lookup_fn(
|
|||
|
||||
let mut dylib_paths = Vec::new();
|
||||
|
||||
let data = &crate_info
|
||||
.dependency_formats
|
||||
.iter()
|
||||
.find(|(crate_type, _data)| *crate_type == rustc_session::config::CrateType::Executable)
|
||||
.unwrap()
|
||||
.1;
|
||||
let data = &crate_info.dependency_formats[&rustc_session::config::CrateType::Executable].1;
|
||||
// `used_crates` is in reverse postorder in terms of dependencies. Reverse the order here to
|
||||
// get a postorder which ensures that all dependencies of a dylib are loaded before the dylib
|
||||
// itself. This helps the dynamic linker to find dylibs not in the regular dynamic library
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@
|
|||
#![warn(unused_lifetimes)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
extern crate jobserver;
|
||||
#[macro_use]
|
||||
extern crate rustc_middle;
|
||||
extern crate rustc_abi;
|
||||
|
|
@ -175,7 +174,11 @@ impl CodegenBackend for CraneliftCodegenBackend {
|
|||
}
|
||||
}
|
||||
|
||||
fn target_features(&self, sess: &Session, _allow_unstable: bool) -> Vec<rustc_span::Symbol> {
|
||||
fn target_features_cfg(
|
||||
&self,
|
||||
sess: &Session,
|
||||
_allow_unstable: bool,
|
||||
) -> Vec<rustc_span::Symbol> {
|
||||
// FIXME return the actually used target features. this is necessary for #[cfg(target_feature)]
|
||||
if sess.target.arch == "x86_64" && sess.target.os != "none" {
|
||||
// x86_64 mandates SSE2 support
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ codegen_gcc_lto_not_supported =
|
|||
LTO is not supported. You may get a linker error.
|
||||
|
||||
codegen_gcc_forbidden_ctarget_feature =
|
||||
target feature `{$feature}` cannot be toggled with `-Ctarget-feature`
|
||||
target feature `{$feature}` cannot be toggled with `-Ctarget-feature`: {$reason}
|
||||
|
||||
codegen_gcc_unwinding_inline_asm =
|
||||
GCC backend does not support unwinding from inline asm
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ pub(crate) struct UnstableCTargetFeature<'a> {
|
|||
#[diag(codegen_gcc_forbidden_ctarget_feature)]
|
||||
pub(crate) struct ForbiddenCTargetFeature<'a> {
|
||||
pub feature: &'a str,
|
||||
pub reason: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable;
|
|||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_middle::bug;
|
||||
use rustc_session::Session;
|
||||
use rustc_target::target_features::{RUSTC_SPECIFIC_FEATURES, Stability};
|
||||
use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES;
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
|
||||
use crate::errors::{
|
||||
|
|
@ -94,13 +94,17 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
|
|||
};
|
||||
sess.dcx().emit_warn(unknown_feature);
|
||||
}
|
||||
Some((_, Stability::Stable, _)) => {}
|
||||
Some((_, Stability::Unstable(_), _)) => {
|
||||
// An unstable feature. Warn about using it.
|
||||
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
|
||||
}
|
||||
Some((_, Stability::Forbidden { .. }, _)) => {
|
||||
sess.dcx().emit_err(ForbiddenCTargetFeature { feature });
|
||||
Some((_, stability, _)) => {
|
||||
if let Err(reason) =
|
||||
stability.compute_toggleability(&sess.target).allow_toggle()
|
||||
{
|
||||
sess.dcx().emit_warn(ForbiddenCTargetFeature { feature, reason });
|
||||
} else if stability.requires_nightly().is_some() {
|
||||
// An unstable feature. Warn about using it. (It makes little sense
|
||||
// to hard-error here since we just warn about fully unknown
|
||||
// features above).
|
||||
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -260,8 +260,8 @@ impl CodegenBackend for GccCodegenBackend {
|
|||
.join(sess)
|
||||
}
|
||||
|
||||
fn target_features(&self, sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
|
||||
target_features(sess, allow_unstable, &self.target_info)
|
||||
fn target_features_cfg(&self, sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
|
||||
target_features_cfg(sess, allow_unstable, &self.target_info)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -472,7 +472,8 @@ fn to_gcc_opt_level(optlevel: Option<OptLevel>) -> OptimizationLevel {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn target_features(
|
||||
/// Returns the features that should be set in `cfg(target_feature)`.
|
||||
fn target_features_cfg(
|
||||
sess: &Session,
|
||||
allow_unstable: bool,
|
||||
target_info: &LockedTargetInfo,
|
||||
|
|
@ -481,9 +482,9 @@ pub fn target_features(
|
|||
sess.target
|
||||
.rust_target_features()
|
||||
.iter()
|
||||
.filter(|(_, gate, _)| gate.is_supported())
|
||||
.filter(|(_, gate, _)| gate.in_cfg())
|
||||
.filter_map(|&(feature, gate, _)| {
|
||||
if sess.is_nightly_build() || allow_unstable || gate.is_stable() {
|
||||
if sess.is_nightly_build() || allow_unstable || gate.requires_nightly().is_none() {
|
||||
Some(feature)
|
||||
} else {
|
||||
None
|
||||
|
|
|
|||
|
|
@ -75,10 +75,10 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
|
|||
|
||||
// Encode all filenames referenced by coverage mappings in this CGU.
|
||||
let filenames_buffer = global_file_table.make_filenames_buffer(tcx);
|
||||
|
||||
let filenames_size = filenames_buffer.len();
|
||||
let filenames_val = cx.const_bytes(&filenames_buffer);
|
||||
let filenames_ref = llvm_cov::hash_bytes(&filenames_buffer);
|
||||
// The `llvm-cov` tool uses this hash to associate each covfun record with
|
||||
// its corresponding filenames table, since the final binary will typically
|
||||
// contain multiple covmap records from different compilation units.
|
||||
let filenames_hash = llvm_cov::hash_bytes(&filenames_buffer);
|
||||
|
||||
let mut unused_function_names = Vec::new();
|
||||
|
||||
|
|
@ -101,7 +101,7 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
|
|||
for covfun in &covfun_records {
|
||||
unused_function_names.extend(covfun.mangled_function_name_if_unused());
|
||||
|
||||
covfun::generate_covfun_record(cx, filenames_ref, covfun)
|
||||
covfun::generate_covfun_record(cx, filenames_hash, covfun)
|
||||
}
|
||||
|
||||
// For unused functions, we need to take their mangled names and store them
|
||||
|
|
@ -126,7 +126,7 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
|
|||
// Generate the coverage map header, which contains the filenames used by
|
||||
// this CGU's coverage mappings, and store it in a well-known global.
|
||||
// (This is skipped if we returned early due to having no covfun records.)
|
||||
generate_covmap_record(cx, covmap_version, filenames_size, filenames_val);
|
||||
generate_covmap_record(cx, covmap_version, &filenames_buffer);
|
||||
}
|
||||
|
||||
/// Maps "global" (per-CGU) file ID numbers to their underlying filenames.
|
||||
|
|
@ -225,38 +225,35 @@ fn span_file_name(tcx: TyCtxt<'_>, span: Span) -> Symbol {
|
|||
/// Generates the contents of the covmap record for this CGU, which mostly
|
||||
/// consists of a header and a list of filenames. The record is then stored
|
||||
/// as a global variable in the `__llvm_covmap` section.
|
||||
fn generate_covmap_record<'ll>(
|
||||
cx: &CodegenCx<'ll, '_>,
|
||||
version: u32,
|
||||
filenames_size: usize,
|
||||
filenames_val: &'ll llvm::Value,
|
||||
) {
|
||||
debug!("cov map: filenames_size = {}, 0-based version = {}", filenames_size, version);
|
||||
|
||||
// Create the coverage data header (Note, fields 0 and 2 are now always zero,
|
||||
// as of `llvm::coverage::CovMapVersion::Version4`.)
|
||||
let zero_was_n_records_val = cx.const_u32(0);
|
||||
let filenames_size_val = cx.const_u32(filenames_size as u32);
|
||||
let zero_was_coverage_size_val = cx.const_u32(0);
|
||||
let version_val = cx.const_u32(version);
|
||||
let cov_data_header_val = cx.const_struct(
|
||||
&[zero_was_n_records_val, filenames_size_val, zero_was_coverage_size_val, version_val],
|
||||
/*packed=*/ false,
|
||||
fn generate_covmap_record<'ll>(cx: &CodegenCx<'ll, '_>, version: u32, filenames_buffer: &[u8]) {
|
||||
// A covmap record consists of four target-endian u32 values, followed by
|
||||
// the encoded filenames table. Two of the header fields are unused in
|
||||
// modern versions of the LLVM coverage mapping format, and are always 0.
|
||||
// <https://llvm.org/docs/CoverageMappingFormat.html#llvm-ir-representation>
|
||||
// See also `src/llvm-project/clang/lib/CodeGen/CoverageMappingGen.cpp`.
|
||||
let covmap_header = cx.const_struct(
|
||||
&[
|
||||
cx.const_u32(0), // (unused)
|
||||
cx.const_u32(filenames_buffer.len() as u32),
|
||||
cx.const_u32(0), // (unused)
|
||||
cx.const_u32(version),
|
||||
],
|
||||
/* packed */ false,
|
||||
);
|
||||
let covmap_record = cx
|
||||
.const_struct(&[covmap_header, cx.const_bytes(filenames_buffer)], /* packed */ false);
|
||||
|
||||
// Create the complete LLVM coverage data value to add to the LLVM IR
|
||||
let covmap_data =
|
||||
cx.const_struct(&[cov_data_header_val, filenames_val], /*packed=*/ false);
|
||||
|
||||
let llglobal = llvm::add_global(cx.llmod, cx.val_ty(covmap_data), &llvm_cov::covmap_var_name());
|
||||
llvm::set_initializer(llglobal, covmap_data);
|
||||
llvm::set_global_constant(llglobal, true);
|
||||
llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
|
||||
llvm::set_section(llglobal, &llvm_cov::covmap_section_name(cx.llmod));
|
||||
let covmap_global =
|
||||
llvm::add_global(cx.llmod, cx.val_ty(covmap_record), &llvm_cov::covmap_var_name());
|
||||
llvm::set_initializer(covmap_global, covmap_record);
|
||||
llvm::set_global_constant(covmap_global, true);
|
||||
llvm::set_linkage(covmap_global, llvm::Linkage::PrivateLinkage);
|
||||
llvm::set_section(covmap_global, &llvm_cov::covmap_section_name(cx.llmod));
|
||||
// LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
|
||||
// <https://llvm.org/docs/CoverageMappingFormat.html>
|
||||
llvm::set_alignment(llglobal, Align::EIGHT);
|
||||
cx.add_used_global(llglobal);
|
||||
llvm::set_alignment(covmap_global, Align::EIGHT);
|
||||
|
||||
cx.add_used_global(covmap_global);
|
||||
}
|
||||
|
||||
/// Each CGU will normally only emit coverage metadata for the functions that it actually generates.
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ fn fill_region_tables<'tcx>(
|
|||
/// as a global variable in the `__llvm_covfun` section.
|
||||
pub(crate) fn generate_covfun_record<'tcx>(
|
||||
cx: &CodegenCx<'_, 'tcx>,
|
||||
filenames_ref: u64,
|
||||
filenames_hash: u64,
|
||||
covfun: &CovfunRecord<'tcx>,
|
||||
) {
|
||||
let &CovfunRecord {
|
||||
|
|
@ -155,46 +155,45 @@ pub(crate) fn generate_covfun_record<'tcx>(
|
|||
regions,
|
||||
);
|
||||
|
||||
// Concatenate the encoded coverage mappings
|
||||
let coverage_mapping_size = coverage_mapping_buffer.len();
|
||||
let coverage_mapping_val = cx.const_bytes(&coverage_mapping_buffer);
|
||||
|
||||
// A covfun record consists of four target-endian integers, followed by the
|
||||
// encoded mapping data in bytes. Note that the length field is 32 bits.
|
||||
// <https://llvm.org/docs/CoverageMappingFormat.html#llvm-ir-representation>
|
||||
// See also `src/llvm-project/clang/lib/CodeGen/CoverageMappingGen.cpp` and
|
||||
// `COVMAP_V3` in `src/llvm-project/llvm/include/llvm/ProfileData/InstrProfData.inc`.
|
||||
let func_name_hash = llvm_cov::hash_bytes(mangled_function_name.as_bytes());
|
||||
let func_name_hash_val = cx.const_u64(func_name_hash);
|
||||
let coverage_mapping_size_val = cx.const_u32(coverage_mapping_size as u32);
|
||||
let source_hash_val = cx.const_u64(source_hash);
|
||||
let filenames_ref_val = cx.const_u64(filenames_ref);
|
||||
let func_record_val = cx.const_struct(
|
||||
let covfun_record = cx.const_struct(
|
||||
&[
|
||||
func_name_hash_val,
|
||||
coverage_mapping_size_val,
|
||||
source_hash_val,
|
||||
filenames_ref_val,
|
||||
coverage_mapping_val,
|
||||
cx.const_u64(func_name_hash),
|
||||
cx.const_u32(coverage_mapping_buffer.len() as u32),
|
||||
cx.const_u64(source_hash),
|
||||
cx.const_u64(filenames_hash),
|
||||
cx.const_bytes(&coverage_mapping_buffer),
|
||||
],
|
||||
/*packed=*/ true,
|
||||
// This struct needs to be packed, so that the 32-bit length field
|
||||
// doesn't have unexpected padding.
|
||||
true,
|
||||
);
|
||||
|
||||
// Choose a variable name to hold this function's covfun data.
|
||||
// Functions that are used have a suffix ("u") to distinguish them from
|
||||
// unused copies of the same function (from different CGUs), so that if a
|
||||
// linker sees both it won't discard the used copy's data.
|
||||
let func_record_var_name =
|
||||
CString::new(format!("__covrec_{:X}{}", func_name_hash, if is_used { "u" } else { "" }))
|
||||
.unwrap();
|
||||
debug!("function record var name: {:?}", func_record_var_name);
|
||||
let u = if is_used { "u" } else { "" };
|
||||
let covfun_var_name = CString::new(format!("__covrec_{func_name_hash:X}{u}")).unwrap();
|
||||
debug!("function record var name: {covfun_var_name:?}");
|
||||
|
||||
let llglobal = llvm::add_global(cx.llmod, cx.val_ty(func_record_val), &func_record_var_name);
|
||||
llvm::set_initializer(llglobal, func_record_val);
|
||||
llvm::set_global_constant(llglobal, true);
|
||||
llvm::set_linkage(llglobal, llvm::Linkage::LinkOnceODRLinkage);
|
||||
llvm::set_visibility(llglobal, llvm::Visibility::Hidden);
|
||||
llvm::set_section(llglobal, cx.covfun_section_name());
|
||||
let covfun_global = llvm::add_global(cx.llmod, cx.val_ty(covfun_record), &covfun_var_name);
|
||||
llvm::set_initializer(covfun_global, covfun_record);
|
||||
llvm::set_global_constant(covfun_global, true);
|
||||
llvm::set_linkage(covfun_global, llvm::Linkage::LinkOnceODRLinkage);
|
||||
llvm::set_visibility(covfun_global, llvm::Visibility::Hidden);
|
||||
llvm::set_section(covfun_global, cx.covfun_section_name());
|
||||
// LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
|
||||
// <https://llvm.org/docs/CoverageMappingFormat.html>
|
||||
llvm::set_alignment(llglobal, Align::EIGHT);
|
||||
llvm::set_alignment(covfun_global, Align::EIGHT);
|
||||
if cx.target_spec().supports_comdat() {
|
||||
llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name);
|
||||
llvm::set_comdat(cx.llmod, covfun_global, &covfun_var_name);
|
||||
}
|
||||
cx.add_used_global(llglobal);
|
||||
|
||||
cx.add_used_global(covfun_global);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ use std::mem::ManuallyDrop;
|
|||
use back::owned_target_machine::OwnedTargetMachine;
|
||||
use back::write::{create_informational_target_machine, create_target_machine};
|
||||
use errors::ParseTargetMachineConfig;
|
||||
pub use llvm_util::target_features;
|
||||
pub use llvm_util::target_features_cfg;
|
||||
use rustc_ast::expand::allocator::AllocatorKind;
|
||||
use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
|
||||
use rustc_codegen_ssa::back::write::{
|
||||
|
|
@ -330,8 +330,8 @@ impl CodegenBackend for LlvmCodegenBackend {
|
|||
llvm_util::print_version();
|
||||
}
|
||||
|
||||
fn target_features(&self, sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
|
||||
target_features(sess, allow_unstable)
|
||||
fn target_features_cfg(&self, sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
|
||||
target_features_cfg(sess, allow_unstable)
|
||||
}
|
||||
|
||||
fn codegen_crate<'tcx>(
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ use rustc_session::Session;
|
|||
use rustc_session::config::{PrintKind, PrintRequest};
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_target::spec::{MergeFunctions, PanicStrategy, SmallDataThresholdSupport};
|
||||
use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATURES, Stability};
|
||||
use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATURES};
|
||||
|
||||
use crate::back::write::create_informational_target_machine;
|
||||
use crate::errors::{
|
||||
|
|
@ -300,7 +300,7 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
|
|||
/// Must express features in the way Rust understands them.
|
||||
///
|
||||
/// We do not have to worry about RUSTC_SPECIFIC_FEATURES here, those are handled outside codegen.
|
||||
pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
|
||||
pub fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
|
||||
let mut features: FxHashSet<Symbol> = Default::default();
|
||||
|
||||
// Add base features for the target.
|
||||
|
|
@ -316,7 +316,7 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
|
|||
sess.target
|
||||
.rust_target_features()
|
||||
.iter()
|
||||
.filter(|(_, gate, _)| gate.is_supported())
|
||||
.filter(|(_, gate, _)| gate.in_cfg())
|
||||
.filter(|(feature, _, _)| {
|
||||
// skip checking special features, as LLVM may not understand them
|
||||
if RUSTC_SPECIAL_FEATURES.contains(feature) {
|
||||
|
|
@ -372,9 +372,9 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
|
|||
sess.target
|
||||
.rust_target_features()
|
||||
.iter()
|
||||
.filter(|(_, gate, _)| gate.is_supported())
|
||||
.filter(|(_, gate, _)| gate.in_cfg())
|
||||
.filter_map(|&(feature, gate, _)| {
|
||||
if sess.is_nightly_build() || allow_unstable || gate.is_stable() {
|
||||
if sess.is_nightly_build() || allow_unstable || gate.requires_nightly().is_none() {
|
||||
Some(feature)
|
||||
} else {
|
||||
None
|
||||
|
|
@ -493,7 +493,7 @@ fn print_target_features(sess: &Session, tm: &llvm::TargetMachine, out: &mut Str
|
|||
.rust_target_features()
|
||||
.iter()
|
||||
.filter_map(|(feature, gate, _implied)| {
|
||||
if !gate.is_supported() {
|
||||
if !gate.in_cfg() {
|
||||
// Only list (experimentally) supported features.
|
||||
return None;
|
||||
}
|
||||
|
|
@ -716,13 +716,17 @@ pub(crate) fn global_llvm_features(
|
|||
};
|
||||
sess.dcx().emit_warn(unknown_feature);
|
||||
}
|
||||
Some((_, Stability::Stable, _)) => {}
|
||||
Some((_, Stability::Unstable(_), _)) => {
|
||||
// An unstable feature. Warn about using it.
|
||||
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
|
||||
}
|
||||
Some((_, Stability::Forbidden { reason }, _)) => {
|
||||
sess.dcx().emit_warn(ForbiddenCTargetFeature { feature, reason });
|
||||
Some((_, stability, _)) => {
|
||||
if let Err(reason) =
|
||||
stability.compute_toggleability(&sess.target).allow_toggle()
|
||||
{
|
||||
sess.dcx().emit_warn(ForbiddenCTargetFeature { feature, reason });
|
||||
} else if stability.requires_nightly().is_some() {
|
||||
// An unstable feature. Warn about using it. It makes little sense
|
||||
// to hard-error here since we just warn about fully unknown
|
||||
// features above.
|
||||
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ bitflags = "2.4.1"
|
|||
cc = "1.1.23"
|
||||
either = "1.5.0"
|
||||
itertools = "0.12"
|
||||
jobserver = "0.1.28"
|
||||
pathdiff = "0.2.0"
|
||||
regex = "1.4"
|
||||
rustc_abi = { path = "../rustc_abi" }
|
||||
|
|
|
|||
|
|
@ -236,7 +236,13 @@ pub fn each_linked_rlib(
|
|||
) -> Result<(), errors::LinkRlibError> {
|
||||
let crates = info.used_crates.iter();
|
||||
|
||||
let fmts = if crate_type.is_none() {
|
||||
let fmts = if let Some(crate_type) = crate_type {
|
||||
let Some(fmts) = info.dependency_formats.get(&crate_type) else {
|
||||
return Err(errors::LinkRlibError::MissingFormat);
|
||||
};
|
||||
|
||||
fmts
|
||||
} else {
|
||||
for combination in info.dependency_formats.iter().combinations(2) {
|
||||
let (ty1, list1) = &combination[0];
|
||||
let (ty2, list2) = &combination[1];
|
||||
|
|
@ -252,18 +258,7 @@ pub fn each_linked_rlib(
|
|||
if info.dependency_formats.is_empty() {
|
||||
return Err(errors::LinkRlibError::MissingFormat);
|
||||
}
|
||||
&info.dependency_formats[0].1
|
||||
} else {
|
||||
let fmts = info
|
||||
.dependency_formats
|
||||
.iter()
|
||||
.find_map(|&(ty, ref list)| if Some(ty) == crate_type { Some(list) } else { None });
|
||||
|
||||
let Some(fmts) = fmts else {
|
||||
return Err(errors::LinkRlibError::MissingFormat);
|
||||
};
|
||||
|
||||
fmts
|
||||
info.dependency_formats.first().unwrap().1
|
||||
};
|
||||
|
||||
for &cnum in crates {
|
||||
|
|
@ -624,8 +619,7 @@ fn link_staticlib(
|
|||
let fmts = codegen_results
|
||||
.crate_info
|
||||
.dependency_formats
|
||||
.iter()
|
||||
.find_map(|&(ty, ref list)| if ty == CrateType::Staticlib { Some(list) } else { None })
|
||||
.get(&CrateType::Staticlib)
|
||||
.expect("no dependency formats for staticlib");
|
||||
|
||||
let mut all_rust_dylibs = vec![];
|
||||
|
|
@ -2355,11 +2349,10 @@ fn linker_with_args(
|
|||
// they are used within inlined functions or instantiated generic functions. We do this *after*
|
||||
// handling the raw-dylib symbols in the current crate to make sure that those are chosen first
|
||||
// by the linker.
|
||||
let (_, dependency_linkage) = codegen_results
|
||||
let dependency_linkage = codegen_results
|
||||
.crate_info
|
||||
.dependency_formats
|
||||
.iter()
|
||||
.find(|(ty, _)| *ty == crate_type)
|
||||
.get(&crate_type)
|
||||
.expect("failed to find crate type in dependency format list");
|
||||
|
||||
// We sort the libraries below
|
||||
|
|
@ -2738,11 +2731,10 @@ fn add_upstream_rust_crates(
|
|||
// Linking to a rlib involves just passing it to the linker (the linker
|
||||
// will slurp up the object files inside), and linking to a dynamic library
|
||||
// involves just passing the right -l flag.
|
||||
let (_, data) = codegen_results
|
||||
let data = codegen_results
|
||||
.crate_info
|
||||
.dependency_formats
|
||||
.iter()
|
||||
.find(|(ty, _)| *ty == crate_type)
|
||||
.get(&crate_type)
|
||||
.expect("failed to find crate type in dependency format list");
|
||||
|
||||
if sess.target.is_like_aix {
|
||||
|
|
|
|||
|
|
@ -1749,7 +1749,7 @@ fn for_each_exported_symbols_include_dep<'tcx>(
|
|||
}
|
||||
|
||||
let formats = tcx.dependency_formats(());
|
||||
let deps = formats.iter().find_map(|(t, list)| (*t == crate_type).then_some(list)).unwrap();
|
||||
let deps = &formats[&crate_type];
|
||||
|
||||
for (index, dep_format) in deps.iter().enumerate() {
|
||||
let cnum = CrateNum::new(index + 1);
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ use std::sync::Arc;
|
|||
use std::sync::mpsc::{Receiver, Sender, channel};
|
||||
use std::{fs, io, mem, str, thread};
|
||||
|
||||
use jobserver::{Acquired, Client};
|
||||
use rustc_ast::attr;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
||||
use rustc_data_structures::jobserver::{self, Acquired};
|
||||
use rustc_data_structures::memmap::Mmap;
|
||||
use rustc_data_structures::profiling::{SelfProfilerRef, VerboseTimingGuard};
|
||||
use rustc_errors::emitter::Emitter;
|
||||
|
|
@ -456,7 +456,6 @@ pub(crate) fn start_async_codegen<B: ExtraBackendMethods>(
|
|||
metadata_module: Option<CompiledModule>,
|
||||
) -> OngoingCodegen<B> {
|
||||
let (coordinator_send, coordinator_receive) = channel();
|
||||
let sess = tcx.sess;
|
||||
|
||||
let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
|
||||
let no_builtins = attr::contains_name(crate_attrs, sym::no_builtins);
|
||||
|
|
@ -477,7 +476,6 @@ pub(crate) fn start_async_codegen<B: ExtraBackendMethods>(
|
|||
shared_emitter,
|
||||
codegen_worker_send,
|
||||
coordinator_receive,
|
||||
sess.jobserver.clone(),
|
||||
Arc::new(regular_config),
|
||||
Arc::new(metadata_config),
|
||||
Arc::new(allocator_config),
|
||||
|
|
@ -1093,7 +1091,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
shared_emitter: SharedEmitter,
|
||||
codegen_worker_send: Sender<CguMessage>,
|
||||
coordinator_receive: Receiver<Box<dyn Any + Send>>,
|
||||
jobserver: Client,
|
||||
regular_config: Arc<ModuleConfig>,
|
||||
metadata_config: Arc<ModuleConfig>,
|
||||
allocator_config: Arc<ModuleConfig>,
|
||||
|
|
@ -1145,7 +1142,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
// get tokens on `coordinator_receive` which will
|
||||
// get managed in the main loop below.
|
||||
let coordinator_send2 = coordinator_send.clone();
|
||||
let helper = jobserver
|
||||
let helper = jobserver::client()
|
||||
.into_helper_thread(move |token| {
|
||||
drop(coordinator_send2.send(Box::new(Message::Token::<B>(token))));
|
||||
})
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use rustc_middle::ty::TyCtxt;
|
|||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::symbol::{Symbol, sym};
|
||||
use rustc_target::target_features::{self, Stability};
|
||||
use rustc_target::target_features;
|
||||
|
||||
use crate::errors;
|
||||
|
||||
|
|
@ -20,7 +20,7 @@ use crate::errors;
|
|||
pub(crate) fn from_target_feature_attr(
|
||||
tcx: TyCtxt<'_>,
|
||||
attr: &ast::Attribute,
|
||||
rust_target_features: &UnordMap<String, target_features::Stability>,
|
||||
rust_target_features: &UnordMap<String, target_features::StabilityComputed>,
|
||||
target_features: &mut Vec<TargetFeature>,
|
||||
) {
|
||||
let Some(list) = attr.meta_item_list() else { return };
|
||||
|
|
@ -63,32 +63,24 @@ pub(crate) fn from_target_feature_attr(
|
|||
return None;
|
||||
};
|
||||
|
||||
// Only allow target features whose feature gates have been enabled.
|
||||
let allowed = match stability {
|
||||
Stability::Forbidden { .. } => false,
|
||||
Stability::Stable => true,
|
||||
Stability::Unstable(name) => rust_features.enabled(*name),
|
||||
};
|
||||
if !allowed {
|
||||
match stability {
|
||||
Stability::Stable => unreachable!(),
|
||||
&Stability::Unstable(lang_feature_name) => {
|
||||
feature_err(
|
||||
&tcx.sess,
|
||||
lang_feature_name,
|
||||
item.span(),
|
||||
format!("the target feature `{feature}` is currently unstable"),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
Stability::Forbidden { reason } => {
|
||||
tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
|
||||
span: item.span(),
|
||||
feature,
|
||||
reason,
|
||||
});
|
||||
}
|
||||
}
|
||||
// Only allow target features whose feature gates have been enabled
|
||||
// and which are permitted to be toggled.
|
||||
if let Err(reason) = stability.allow_toggle() {
|
||||
tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
|
||||
span: item.span(),
|
||||
feature,
|
||||
reason,
|
||||
});
|
||||
} else if let Some(nightly_feature) = stability.requires_nightly()
|
||||
&& !rust_features.enabled(nightly_feature)
|
||||
{
|
||||
feature_err(
|
||||
&tcx.sess,
|
||||
nightly_feature,
|
||||
item.span(),
|
||||
format!("the target feature `{feature}` is currently unstable"),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
Some(Symbol::intern(feature))
|
||||
}));
|
||||
|
|
@ -156,18 +148,19 @@ pub(crate) fn provide(providers: &mut Providers) {
|
|||
*providers = Providers {
|
||||
rust_target_features: |tcx, cnum| {
|
||||
assert_eq!(cnum, LOCAL_CRATE);
|
||||
let target = &tcx.sess.target;
|
||||
if tcx.sess.opts.actually_rustdoc {
|
||||
// rustdoc needs to be able to document functions that use all the features, so
|
||||
// whitelist them all
|
||||
rustc_target::target_features::all_rust_features()
|
||||
.map(|(a, b)| (a.to_string(), b))
|
||||
.map(|(a, b)| (a.to_string(), b.compute_toggleability(target)))
|
||||
.collect()
|
||||
} else {
|
||||
tcx.sess
|
||||
.target
|
||||
.rust_target_features()
|
||||
.iter()
|
||||
.map(|&(a, b, _)| (a.to_string(), b))
|
||||
.map(|&(a, b, _)| (a.to_string(), b.compute_toggleability(target)))
|
||||
.collect()
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -45,7 +45,9 @@ pub trait CodegenBackend {
|
|||
|
||||
fn print(&self, _req: &PrintRequest, _out: &mut String, _sess: &Session) {}
|
||||
|
||||
fn target_features(&self, _sess: &Session, _allow_unstable: bool) -> Vec<Symbol> {
|
||||
/// Returns the features that should be set in `cfg(target_features)`.
|
||||
/// RUSTC_SPECIFIC_FEATURES should be skipped here, those are handled outside codegen.
|
||||
fn target_features_cfg(&self, _sess: &Session, _allow_unstable: bool) -> Vec<Symbol> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -573,12 +573,27 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
) => {}
|
||||
Rvalue::ShallowInitBox(_, _) => {}
|
||||
|
||||
Rvalue::UnaryOp(_, operand) => {
|
||||
Rvalue::UnaryOp(op, operand) => {
|
||||
let ty = operand.ty(self.body, self.tcx);
|
||||
if is_int_bool_float_or_char(ty) {
|
||||
// Int, bool, float, and char operations are fine.
|
||||
} else {
|
||||
span_bug!(self.span, "non-primitive type in `Rvalue::UnaryOp`: {:?}", ty);
|
||||
match op {
|
||||
UnOp::Not | UnOp::Neg => {
|
||||
if is_int_bool_float_or_char(ty) {
|
||||
// Int, bool, float, and char operations are fine.
|
||||
} else {
|
||||
span_bug!(
|
||||
self.span,
|
||||
"non-primitive type in `Rvalue::UnaryOp{op:?}`: {ty:?}",
|
||||
);
|
||||
}
|
||||
}
|
||||
UnOp::PtrMetadata => {
|
||||
if !ty.is_ref() && !ty.is_unsafe_ptr() {
|
||||
span_bug!(
|
||||
self.span,
|
||||
"non-pointer type in `Rvalue::UnaryOp({op:?})`: {ty:?}",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -329,7 +329,7 @@ where
|
|||
self.transfer_function(state).initialize_state();
|
||||
}
|
||||
|
||||
fn apply_statement_effect(
|
||||
fn apply_primary_statement_effect(
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
statement: &mir::Statement<'tcx>,
|
||||
|
|
@ -338,7 +338,7 @@ where
|
|||
self.transfer_function(state).visit_statement(statement, location);
|
||||
}
|
||||
|
||||
fn apply_terminator_effect<'mir>(
|
||||
fn apply_primary_terminator_effect<'mir>(
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
terminator: &'mir mir::Terminator<'tcx>,
|
||||
|
|
|
|||
|
|
@ -4,27 +4,29 @@ use rustc_hir::def_id::{DefId, LocalDefId};
|
|||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
||||
pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
|
||||
fn parent_impl_constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness {
|
||||
let parent_id = tcx.local_parent(def_id);
|
||||
matches!(tcx.def_kind(parent_id), DefKind::Impl { .. })
|
||||
&& tcx.constness(parent_id) == hir::Constness::Const
|
||||
if matches!(tcx.def_kind(parent_id), DefKind::Impl { .. })
|
||||
&& let Some(header) = tcx.impl_trait_header(parent_id)
|
||||
{
|
||||
header.constness
|
||||
} else {
|
||||
hir::Constness::NotConst
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether an item is considered to be `const`. If it is a constructor, anonymous const,
|
||||
/// const block, const item or associated const, it is const. If it is a trait impl/function,
|
||||
/// Checks whether an item is considered to be `const`. If it is a constructor, it is const.
|
||||
/// If it is an assoc method or function,
|
||||
/// return if it has a `const` modifier. If it is an intrinsic, report whether said intrinsic
|
||||
/// has a `rustc_const_{un,}stable` attribute. Otherwise, return `Constness::NotConst`.
|
||||
/// has a `rustc_const_{un,}stable` attribute. Otherwise, panic.
|
||||
fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness {
|
||||
let node = tcx.hir_node_by_def_id(def_id);
|
||||
|
||||
match node {
|
||||
hir::Node::Ctor(_)
|
||||
| hir::Node::AnonConst(_)
|
||||
| hir::Node::ConstBlock(_)
|
||||
hir::Node::Ctor(hir::VariantData::Tuple(..))
|
||||
| hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) => {
|
||||
hir::Constness::Const
|
||||
}
|
||||
hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.constness,
|
||||
hir::Node::ForeignItem(_) => {
|
||||
// Foreign items cannot be evaluated at compile-time.
|
||||
hir::Constness::NotConst
|
||||
|
|
@ -38,10 +40,12 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness {
|
|||
|
||||
// If the function itself is not annotated with `const`, it may still be a `const fn`
|
||||
// if it resides in a const trait impl.
|
||||
let is_const = is_parent_const_impl_raw(tcx, def_id);
|
||||
if is_const { hir::Constness::Const } else { hir::Constness::NotConst }
|
||||
parent_impl_constness(tcx, def_id)
|
||||
} else {
|
||||
hir::Constness::NotConst
|
||||
tcx.dcx().span_bug(
|
||||
tcx.def_span(def_id),
|
||||
format!("should not be requesting the constness of items that can't be const: {node:#?}: {:?}", tcx.def_kind(def_id))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -249,10 +249,9 @@ impl<'tcx> CompileTimeInterpCx<'tcx> {
|
|||
} else if self.tcx.is_lang_item(def_id, LangItem::PanicFmt) {
|
||||
// For panic_fmt, call const_panic_fmt instead.
|
||||
let const_def_id = self.tcx.require_lang_item(LangItem::ConstPanicFmt, None);
|
||||
// FIXME(@lcnr): why does this use an empty env if we've got a `param_env` right here.
|
||||
let new_instance = ty::Instance::expect_resolve(
|
||||
*self.tcx,
|
||||
ty::TypingEnv::fully_monomorphized(),
|
||||
self.typing_env(),
|
||||
const_def_id,
|
||||
instance.args,
|
||||
self.cur_span(),
|
||||
|
|
|
|||
|
|
@ -540,10 +540,14 @@ pub trait Machine<'tcx>: Sized {
|
|||
interp_ok(ReturnAction::Normal)
|
||||
}
|
||||
|
||||
/// Called immediately after an "immediate" local variable is read
|
||||
/// Called immediately after an "immediate" local variable is read in a given frame
|
||||
/// (i.e., this is called for reads that do not end up accessing addressable memory).
|
||||
#[inline(always)]
|
||||
fn after_local_read(_ecx: &InterpCx<'tcx, Self>, _local: mir::Local) -> InterpResult<'tcx> {
|
||||
fn after_local_read(
|
||||
_ecx: &InterpCx<'tcx, Self>,
|
||||
_frame: &Frame<'tcx, Self::Provenance, Self::FrameExtra>,
|
||||
_local: mir::Local,
|
||||
) -> InterpResult<'tcx> {
|
||||
interp_ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@ use rustc_middle::{bug, mir, span_bug, ty};
|
|||
use tracing::trace;
|
||||
|
||||
use super::{
|
||||
CtfeProvenance, InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, OffsetMode,
|
||||
PlaceTy, Pointer, Projectable, Provenance, Scalar, alloc_range, err_ub, from_known_layout,
|
||||
interp_ok, mir_assign_valid_types, throw_ub,
|
||||
CtfeProvenance, Frame, InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta,
|
||||
OffsetMode, PlaceTy, Pointer, Projectable, Provenance, Scalar, alloc_range, err_ub,
|
||||
from_known_layout, interp_ok, mir_assign_valid_types, throw_ub,
|
||||
};
|
||||
|
||||
/// An `Immediate` represents a single immediate self-contained Rust value.
|
||||
|
|
@ -297,6 +297,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
|
|||
|
||||
#[inline]
|
||||
pub fn from_bool(b: bool, tcx: TyCtxt<'tcx>) -> Self {
|
||||
// Can use any typing env, since `bool` is always monomorphic.
|
||||
let layout = tcx
|
||||
.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(tcx.types.bool))
|
||||
.unwrap();
|
||||
|
|
@ -305,17 +306,18 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
|
|||
|
||||
#[inline]
|
||||
pub fn from_ordering(c: std::cmp::Ordering, tcx: TyCtxt<'tcx>) -> Self {
|
||||
// Can use any typing env, since `Ordering` is always monomorphic.
|
||||
let ty = tcx.ty_ordering_enum(None);
|
||||
let layout =
|
||||
tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)).unwrap();
|
||||
Self::from_scalar(Scalar::from_i8(c as i8), layout)
|
||||
}
|
||||
|
||||
pub fn from_pair(a: Self, b: Self, tcx: TyCtxt<'tcx>) -> Self {
|
||||
let layout = tcx
|
||||
pub fn from_pair(a: Self, b: Self, cx: &(impl HasTypingEnv<'tcx> + HasTyCtxt<'tcx>)) -> Self {
|
||||
let layout = cx
|
||||
.tcx()
|
||||
.layout_of(
|
||||
ty::TypingEnv::fully_monomorphized()
|
||||
.as_query_input(Ty::new_tup(tcx, &[a.layout.ty, b.layout.ty])),
|
||||
cx.typing_env().as_query_input(Ty::new_tup(cx.tcx(), &[a.layout.ty, b.layout.ty])),
|
||||
)
|
||||
.unwrap();
|
||||
Self::from_scalar_pair(a.to_scalar(), b.to_scalar(), layout)
|
||||
|
|
@ -706,23 +708,32 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
interp_ok(str)
|
||||
}
|
||||
|
||||
/// Read from a local of the current frame.
|
||||
/// Will not access memory, instead an indirect `Operand` is returned.
|
||||
///
|
||||
/// This is public because it is used by [priroda](https://github.com/oli-obk/priroda) to get an
|
||||
/// OpTy from a local.
|
||||
/// Read from a local of the current frame. Convenience method for [`InterpCx::local_at_frame_to_op`].
|
||||
pub fn local_to_op(
|
||||
&self,
|
||||
local: mir::Local,
|
||||
layout: Option<TyAndLayout<'tcx>>,
|
||||
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
|
||||
let frame = self.frame();
|
||||
self.local_at_frame_to_op(self.frame(), local, layout)
|
||||
}
|
||||
|
||||
/// Read from a local of a given frame.
|
||||
/// Will not access memory, instead an indirect `Operand` is returned.
|
||||
///
|
||||
/// This is public because it is used by [Aquascope](https://github.com/cognitive-engineering-lab/aquascope/)
|
||||
/// to get an OpTy from a local.
|
||||
pub fn local_at_frame_to_op(
|
||||
&self,
|
||||
frame: &Frame<'tcx, M::Provenance, M::FrameExtra>,
|
||||
local: mir::Local,
|
||||
layout: Option<TyAndLayout<'tcx>>,
|
||||
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
|
||||
let layout = self.layout_of_local(frame, local, layout)?;
|
||||
let op = *frame.locals[local].access()?;
|
||||
if matches!(op, Operand::Immediate(_)) {
|
||||
assert!(!layout.is_unsized());
|
||||
}
|
||||
M::after_local_read(self, local)?;
|
||||
M::after_local_read(self, frame, local)?;
|
||||
interp_ok(OpTy { op, layout })
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -222,7 +222,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
let res = ImmTy::from_scalar_int(result, left.layout);
|
||||
return interp_ok(if with_overflow {
|
||||
let overflow = ImmTy::from_bool(overflow, *self.tcx);
|
||||
ImmTy::from_pair(res, overflow, *self.tcx)
|
||||
ImmTy::from_pair(res, overflow, self)
|
||||
} else {
|
||||
res
|
||||
});
|
||||
|
|
@ -279,7 +279,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
let res = ImmTy::from_scalar_int(result, left.layout);
|
||||
if with_overflow {
|
||||
let overflow = ImmTy::from_bool(overflow, *self.tcx);
|
||||
ImmTy::from_pair(res, overflow, *self.tcx)
|
||||
ImmTy::from_pair(res, overflow, self)
|
||||
} else {
|
||||
res
|
||||
}
|
||||
|
|
|
|||
|
|
@ -584,8 +584,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
interp_ok(())
|
||||
}
|
||||
|
||||
/// This is public because it is used by [Aquascope](https://github.com/cognitive-engineering-lab/aquascope/)
|
||||
/// to analyze all the locals in a stack frame.
|
||||
#[inline(always)]
|
||||
pub(super) fn layout_of_local(
|
||||
pub fn layout_of_local(
|
||||
&self,
|
||||
frame: &Frame<'tcx, M::Provenance, M::FrameExtra>,
|
||||
local: mir::Local,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ use rustc_middle::ty::layout::FnAbiOf;
|
|||
use rustc_middle::ty::{self, Instance, Ty};
|
||||
use rustc_middle::{bug, mir, span_bug};
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::{DesugaringKind, Span};
|
||||
use rustc_target::callconv::FnAbi;
|
||||
use tracing::{info, instrument, trace};
|
||||
|
||||
|
|
@ -80,7 +81,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
use rustc_middle::mir::StatementKind::*;
|
||||
|
||||
match &stmt.kind {
|
||||
Assign(box (place, rvalue)) => self.eval_rvalue_into_place(rvalue, *place)?,
|
||||
Assign(box (place, rvalue)) => {
|
||||
self.eval_rvalue_into_place(rvalue, *place, stmt.source_info.span)?
|
||||
}
|
||||
|
||||
SetDiscriminant { place, variant_index } => {
|
||||
let dest = self.eval_place(**place)?;
|
||||
|
|
@ -159,6 +162,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
&mut self,
|
||||
rvalue: &mir::Rvalue<'tcx>,
|
||||
place: mir::Place<'tcx>,
|
||||
span: Span,
|
||||
) -> InterpResult<'tcx> {
|
||||
let dest = self.eval_place(place)?;
|
||||
// FIXME: ensure some kind of non-aliasing between LHS and RHS?
|
||||
|
|
@ -250,8 +254,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
let src = self.eval_place(place)?;
|
||||
let place = self.force_allocation(&src)?;
|
||||
let mut val = ImmTy::from_immediate(place.to_ref(self), dest.layout);
|
||||
if !place_base_raw {
|
||||
if !place_base_raw
|
||||
&& span.desugaring_kind() != Some(DesugaringKind::IndexBoundsCheckReborrow)
|
||||
{
|
||||
// If this was not already raw, it needs retagging.
|
||||
// As a special hack, we exclude the desugared `PtrMetadata(&raw const *_n)`
|
||||
// from indexing. (Really we should not do any retag on `&raw` but that does not
|
||||
// currently work with Stacked Borrows.)
|
||||
val = M::retag_ptr_value(self, mir::RetagKind::Raw, &val)?;
|
||||
}
|
||||
self.write_immediate(*val, &dest)?;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::sync::{LazyLock, OnceLock};
|
||||
|
||||
pub use jobserver_crate::Client;
|
||||
pub use jobserver_crate::{Acquired, Client, HelperThread};
|
||||
use jobserver_crate::{FromEnv, FromEnvErrorKind};
|
||||
|
||||
// We can only call `from_env_ext` once per process
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ use rustc_errors::registry::Registry;
|
|||
use rustc_errors::{ColorConfig, DiagCtxt, ErrCode, FatalError, PResult, markdown};
|
||||
use rustc_feature::find_gated_cfg;
|
||||
use rustc_interface::util::{self, get_codegen_backend};
|
||||
use rustc_interface::{Linker, Queries, interface, passes};
|
||||
use rustc_interface::{Linker, interface, passes};
|
||||
use rustc_lint::unerased_lint_store;
|
||||
use rustc_metadata::creader::MetadataLoader;
|
||||
use rustc_metadata::locator;
|
||||
|
|
@ -158,13 +158,10 @@ pub trait Callbacks {
|
|||
/// Called after parsing the crate root. Submodules are not yet parsed when
|
||||
/// this callback is called. Return value instructs the compiler whether to
|
||||
/// continue the compilation afterwards (defaults to `Compilation::Continue`)
|
||||
#[deprecated = "This callback will likely be removed or stop giving access \
|
||||
to the TyCtxt in the future. Use either the after_expansion \
|
||||
or the after_analysis callback instead."]
|
||||
fn after_crate_root_parsing<'tcx>(
|
||||
fn after_crate_root_parsing(
|
||||
&mut self,
|
||||
_compiler: &interface::Compiler,
|
||||
_queries: &'tcx Queries<'tcx>,
|
||||
_queries: &ast::Crate,
|
||||
) -> Compilation {
|
||||
Compilation::Continue
|
||||
}
|
||||
|
|
@ -173,7 +170,7 @@ pub trait Callbacks {
|
|||
fn after_expansion<'tcx>(
|
||||
&mut self,
|
||||
_compiler: &interface::Compiler,
|
||||
_queries: &'tcx Queries<'tcx>,
|
||||
_tcx: TyCtxt<'tcx>,
|
||||
) -> Compilation {
|
||||
Compilation::Continue
|
||||
}
|
||||
|
|
@ -350,6 +347,8 @@ fn run_compiler(
|
|||
|
||||
callbacks.config(&mut config);
|
||||
|
||||
let registered_lints = config.register_lints.is_some();
|
||||
|
||||
interface::run_compiler(config, |compiler| {
|
||||
let sess = &compiler.sess;
|
||||
let codegen_backend = &*compiler.codegen_backend;
|
||||
|
|
@ -365,7 +364,7 @@ fn run_compiler(
|
|||
// `--help`/`-Zhelp`/`-Chelp`. This is the earliest it can run, because
|
||||
// it must happen after lints are registered, during session creation.
|
||||
if sess.opts.describe_lints {
|
||||
describe_lints(sess);
|
||||
describe_lints(sess, registered_lints);
|
||||
return early_exit();
|
||||
}
|
||||
|
||||
|
|
@ -416,8 +415,9 @@ fn run_compiler(
|
|||
return early_exit();
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
if callbacks.after_crate_root_parsing(compiler, queries) == Compilation::Stop {
|
||||
if callbacks.after_crate_root_parsing(compiler, &*queries.parse().borrow())
|
||||
== Compilation::Stop
|
||||
{
|
||||
return early_exit();
|
||||
}
|
||||
|
||||
|
|
@ -425,18 +425,18 @@ fn run_compiler(
|
|||
return early_exit();
|
||||
}
|
||||
|
||||
// Make sure name resolution and macro expansion is run.
|
||||
queries.global_ctxt().enter(|tcx| tcx.resolver_for_lowering());
|
||||
|
||||
if let Some(metrics_dir) = &sess.opts.unstable_opts.metrics_dir {
|
||||
queries.global_ctxt().enter(|tcxt| dump_feature_usage_metrics(tcxt, metrics_dir));
|
||||
}
|
||||
|
||||
if callbacks.after_expansion(compiler, queries) == Compilation::Stop {
|
||||
return early_exit();
|
||||
}
|
||||
|
||||
queries.global_ctxt().enter(|tcx| {
|
||||
// Make sure name resolution and macro expansion is run.
|
||||
let _ = tcx.resolver_for_lowering();
|
||||
|
||||
if let Some(metrics_dir) = &sess.opts.unstable_opts.metrics_dir {
|
||||
dump_feature_usage_metrics(tcx, metrics_dir);
|
||||
}
|
||||
|
||||
if callbacks.after_expansion(compiler, tcx) == Compilation::Stop {
|
||||
return early_exit();
|
||||
}
|
||||
|
||||
passes::write_dep_info(tcx);
|
||||
|
||||
if sess.opts.output_types.contains_key(&OutputType::DepInfo)
|
||||
|
|
@ -982,7 +982,7 @@ the command line flag directly.
|
|||
}
|
||||
|
||||
/// Write to stdout lint command options, together with a list of all available lints
|
||||
pub fn describe_lints(sess: &Session) {
|
||||
pub fn describe_lints(sess: &Session, registered_lints: bool) {
|
||||
safe_println!(
|
||||
"
|
||||
Available lint options:
|
||||
|
|
@ -1086,7 +1086,7 @@ Available lint options:
|
|||
|
||||
print_lint_groups(builtin_groups, true);
|
||||
|
||||
match (sess.registered_lints, loaded.len(), loaded_groups.len()) {
|
||||
match (registered_lints, loaded.len(), loaded_groups.len()) {
|
||||
(false, 0, _) | (false, _, 0) => {
|
||||
safe_println!("Lint tools like Clippy can load additional lints and lint groups.");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3048,11 +3048,19 @@ impl FileWithAnnotatedLines {
|
|||
// working correctly.
|
||||
let middle = min(ann.line_start + 4, ann.line_end);
|
||||
// We'll show up to 4 lines past the beginning of the multispan start.
|
||||
// We will *not* include the tail of lines that are only whitespace.
|
||||
// We will *not* include the tail of lines that are only whitespace, a comment or
|
||||
// a bare delimiter.
|
||||
let filter = |s: &str| {
|
||||
let s = s.trim();
|
||||
// Consider comments as empty, but don't consider docstrings to be empty.
|
||||
!(s.starts_with("//") && !(s.starts_with("///") || s.starts_with("//!")))
|
||||
// Consider lines with nothing but whitespace, a single delimiter as empty.
|
||||
&& !["", "{", "}", "(", ")", "[", "]"].contains(&s)
|
||||
};
|
||||
let until = (ann.line_start..middle)
|
||||
.rev()
|
||||
.filter_map(|line| file.get_line(line - 1).map(|s| (line + 1, s)))
|
||||
.find(|(_, s)| !s.trim().is_empty())
|
||||
.find(|(_, s)| filter(s))
|
||||
.map(|(line, _)| line)
|
||||
.unwrap_or(ann.line_start);
|
||||
for line in ann.line_start + 1..until {
|
||||
|
|
@ -3060,7 +3068,8 @@ impl FileWithAnnotatedLines {
|
|||
add_annotation_to_file(&mut output, Lrc::clone(&file), line, ann.as_line());
|
||||
}
|
||||
let line_end = ann.line_end - 1;
|
||||
if middle < line_end {
|
||||
let end_is_empty = file.get_line(line_end - 1).map_or(false, |s| !filter(&s));
|
||||
if middle < line_end && !end_is_empty {
|
||||
add_annotation_to_file(&mut output, Lrc::clone(&file), line_end, ann.as_line());
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -723,7 +723,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
item_inner.kind,
|
||||
ItemKind::Mod(
|
||||
_,
|
||||
ModKind::Unloaded | ModKind::Loaded(_, Inline::No, _),
|
||||
ModKind::Unloaded | ModKind::Loaded(_, Inline::No, _, _),
|
||||
)
|
||||
) =>
|
||||
{
|
||||
|
|
@ -889,7 +889,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
fn visit_item(&mut self, item: &'ast ast::Item) {
|
||||
match &item.kind {
|
||||
ItemKind::Mod(_, mod_kind)
|
||||
if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _)) =>
|
||||
if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _, _)) =>
|
||||
{
|
||||
feature_err(
|
||||
self.sess,
|
||||
|
|
@ -1195,7 +1195,7 @@ impl InvocationCollectorNode for P<ast::Item> {
|
|||
|
||||
let ecx = &mut collector.cx;
|
||||
let (file_path, dir_path, dir_ownership) = match mod_kind {
|
||||
ModKind::Loaded(_, inline, _) => {
|
||||
ModKind::Loaded(_, inline, _, _) => {
|
||||
// Inline `mod foo { ... }`, but we still need to push directories.
|
||||
let (dir_path, dir_ownership) = mod_dir_path(
|
||||
ecx.sess,
|
||||
|
|
@ -1217,15 +1217,21 @@ impl InvocationCollectorNode for P<ast::Item> {
|
|||
ModKind::Unloaded => {
|
||||
// We have an outline `mod foo;` so we need to parse the file.
|
||||
let old_attrs_len = attrs.len();
|
||||
let ParsedExternalMod { items, spans, file_path, dir_path, dir_ownership } =
|
||||
parse_external_mod(
|
||||
ecx.sess,
|
||||
ident,
|
||||
span,
|
||||
&ecx.current_expansion.module,
|
||||
ecx.current_expansion.dir_ownership,
|
||||
&mut attrs,
|
||||
);
|
||||
let ParsedExternalMod {
|
||||
items,
|
||||
spans,
|
||||
file_path,
|
||||
dir_path,
|
||||
dir_ownership,
|
||||
had_parse_error,
|
||||
} = parse_external_mod(
|
||||
ecx.sess,
|
||||
ident,
|
||||
span,
|
||||
&ecx.current_expansion.module,
|
||||
ecx.current_expansion.dir_ownership,
|
||||
&mut attrs,
|
||||
);
|
||||
|
||||
if let Some(lint_store) = ecx.lint_store {
|
||||
lint_store.pre_expansion_lint(
|
||||
|
|
@ -1239,7 +1245,7 @@ impl InvocationCollectorNode for P<ast::Item> {
|
|||
);
|
||||
}
|
||||
|
||||
*mod_kind = ModKind::Loaded(items, Inline::No, spans);
|
||||
*mod_kind = ModKind::Loaded(items, Inline::No, spans, had_parse_error);
|
||||
node.attrs = attrs;
|
||||
if node.attrs.len() > old_attrs_len {
|
||||
// If we loaded an out-of-line module and added some inner attributes,
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ pub(crate) struct ParsedExternalMod {
|
|||
pub file_path: PathBuf,
|
||||
pub dir_path: PathBuf,
|
||||
pub dir_ownership: DirOwnership,
|
||||
pub had_parse_error: Result<(), ErrorGuaranteed>,
|
||||
}
|
||||
|
||||
pub enum ModError<'a> {
|
||||
|
|
@ -74,14 +75,17 @@ pub(crate) fn parse_external_mod(
|
|||
attrs.extend(inner_attrs);
|
||||
(items, inner_span, mp.file_path)
|
||||
};
|
||||
|
||||
// (1) ...instead, we return a dummy module.
|
||||
let (items, spans, file_path) =
|
||||
result.map_err(|err| err.report(sess, span)).unwrap_or_default();
|
||||
let ((items, spans, file_path), had_parse_error) = match result {
|
||||
Err(err) => (Default::default(), Err(err.report(sess, span))),
|
||||
Ok(result) => (result, Ok(())),
|
||||
};
|
||||
|
||||
// Extract the directory path for submodules of the module.
|
||||
let dir_path = file_path.parent().unwrap_or(&file_path).to_owned();
|
||||
|
||||
ParsedExternalMod { items, spans, file_path, dir_path, dir_ownership }
|
||||
ParsedExternalMod { items, spans, file_path, dir_path, dir_ownership, had_parse_error }
|
||||
}
|
||||
|
||||
pub(crate) fn mod_dir_path(
|
||||
|
|
|
|||
|
|
@ -126,9 +126,6 @@ declare_features! (
|
|||
better implied higher-ranked implied bounds support"
|
||||
)
|
||||
),
|
||||
/// Allows `impl Trait` in bindings (`let`, `const`, `static`).
|
||||
(removed, impl_trait_in_bindings, "1.55.0", Some(63065),
|
||||
Some("the implementation was not maintainable, the feature may get reintroduced once the current refactorings are done")),
|
||||
(removed, import_shadowing, "1.0.0", None, None),
|
||||
/// Allows in-band quantification of lifetime bindings (e.g., `fn foo(x: &'a u8) -> &'a u8`).
|
||||
(removed, in_band_lifetimes, "1.23.0", Some(44524),
|
||||
|
|
|
|||
|
|
@ -342,6 +342,7 @@ declare_features! (
|
|||
(unstable, sse4a_target_feature, "1.27.0", Some(44839)),
|
||||
(unstable, tbm_target_feature, "1.27.0", Some(44839)),
|
||||
(unstable, wasm_target_feature, "1.30.0", Some(44839)),
|
||||
(unstable, x87_target_feature, "CURRENT_RUSTC_VERSION", Some(44839)),
|
||||
// !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
|
||||
// Features are listed in alphabetical order. Tidy will fail if you don't keep it this way.
|
||||
// !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
|
||||
|
|
@ -516,6 +517,8 @@ declare_features! (
|
|||
(unstable, if_let_guard, "1.47.0", Some(51114)),
|
||||
/// Allows `impl Trait` to be used inside associated types (RFC 2515).
|
||||
(unstable, impl_trait_in_assoc_type, "1.70.0", Some(63063)),
|
||||
/// Allows `impl Trait` in bindings (`let`).
|
||||
(unstable, impl_trait_in_bindings, "1.64.0", Some(63065)),
|
||||
/// Allows `impl Trait` as output type in `Fn` traits in return position of functions.
|
||||
(unstable, impl_trait_in_fn_trait_return, "1.64.0", Some(99697)),
|
||||
/// Allows associated types in inherent impls.
|
||||
|
|
@ -635,6 +638,8 @@ declare_features! (
|
|||
/// Allows creation of instances of a struct by moving fields that have
|
||||
/// not changed from prior instances of the same struct (RFC #2528)
|
||||
(unstable, type_changing_struct_update, "1.58.0", Some(86555)),
|
||||
/// Allows using `unsafe<'a> &'a T` unsafe binder types.
|
||||
(incomplete, unsafe_binders, "CURRENT_RUSTC_VERSION", Some(130516)),
|
||||
/// Allows declaring fields `unsafe`.
|
||||
(incomplete, unsafe_fields, "CURRENT_RUSTC_VERSION", Some(132922)),
|
||||
/// Allows const generic parameters to be defined with types that
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use rustc_ast::{
|
|||
};
|
||||
pub use rustc_ast::{
|
||||
BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity, ByRef, CaptureBy,
|
||||
ImplPolarity, IsAuto, Movability, Mutability, UnOp,
|
||||
ImplPolarity, IsAuto, Movability, Mutability, UnOp, UnsafeBinderCastKind,
|
||||
};
|
||||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_data_structures::sorted_map::SortedMap;
|
||||
|
|
@ -1740,6 +1740,7 @@ impl Expr<'_> {
|
|||
| ExprKind::Struct(..)
|
||||
| ExprKind::Tup(_)
|
||||
| ExprKind::Type(..)
|
||||
| ExprKind::UnsafeBinderCast(..)
|
||||
| ExprKind::Err(_) => ExprPrecedence::Unambiguous,
|
||||
|
||||
ExprKind::DropTemps(ref expr, ..) => expr.precedence(),
|
||||
|
|
@ -1769,6 +1770,9 @@ impl Expr<'_> {
|
|||
// https://github.com/rust-lang/rfcs/blob/master/text/0803-type-ascription.md#type-ascription-and-temporaries
|
||||
ExprKind::Type(ref e, _) => e.is_place_expr(allow_projections_from),
|
||||
|
||||
// Unsafe binder cast preserves place-ness of the sub-expression.
|
||||
ExprKind::UnsafeBinderCast(_, e, _) => e.is_place_expr(allow_projections_from),
|
||||
|
||||
ExprKind::Unary(UnOp::Deref, _) => true,
|
||||
|
||||
ExprKind::Field(ref base, _) | ExprKind::Index(ref base, _, _) => {
|
||||
|
|
@ -1850,7 +1854,8 @@ impl Expr<'_> {
|
|||
| ExprKind::Field(base, _)
|
||||
| ExprKind::Index(base, _, _)
|
||||
| ExprKind::AddrOf(.., base)
|
||||
| ExprKind::Cast(base, _) => {
|
||||
| ExprKind::Cast(base, _)
|
||||
| ExprKind::UnsafeBinderCast(_, base, _) => {
|
||||
// This isn't exactly true for `Index` and all `Unary`, but we are using this
|
||||
// method exclusively for diagnostics and there's a *cultural* pressure against
|
||||
// them being used only for its side-effects.
|
||||
|
|
@ -2020,6 +2025,22 @@ pub fn is_range_literal(expr: &Expr<'_>) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
/// Checks if the specified expression needs parentheses for prefix
|
||||
/// or postfix suggestions to be valid.
|
||||
/// For example, `a + b` requires parentheses to suggest `&(a + b)`,
|
||||
/// but just `a` does not.
|
||||
/// Similarly, `(a + b).c()` also requires parentheses.
|
||||
/// This should not be used for other types of suggestions.
|
||||
pub fn expr_needs_parens(expr: &Expr<'_>) -> bool {
|
||||
match expr.kind {
|
||||
// parenthesize if needed (Issue #46756)
|
||||
ExprKind::Cast(_, _) | ExprKind::Binary(_, _, _) => true,
|
||||
// parenthesize borrows of range literals (Issue #54505)
|
||||
_ if is_range_literal(expr) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
pub enum ExprKind<'hir> {
|
||||
/// Allow anonymous constants from an inline `const` block
|
||||
|
|
@ -2144,6 +2165,10 @@ pub enum ExprKind<'hir> {
|
|||
/// A suspension point for coroutines (i.e., `yield <expr>`).
|
||||
Yield(&'hir Expr<'hir>, YieldSource),
|
||||
|
||||
/// Operators which can be used to interconvert `unsafe` binder types.
|
||||
/// e.g. `unsafe<'a> &'a i32` <=> `&i32`.
|
||||
UnsafeBinderCast(UnsafeBinderCastKind, &'hir Expr<'hir>, Option<&'hir Ty<'hir>>),
|
||||
|
||||
/// A placeholder for an expression that wasn't syntactically well formed in some way.
|
||||
Err(rustc_span::ErrorGuaranteed),
|
||||
}
|
||||
|
|
@ -2780,6 +2805,12 @@ pub struct BareFnTy<'hir> {
|
|||
pub param_names: &'hir [Ident],
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
pub struct UnsafeBinderTy<'hir> {
|
||||
pub generic_params: &'hir [GenericParam<'hir>],
|
||||
pub inner_ty: &'hir Ty<'hir>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
pub struct OpaqueTy<'hir> {
|
||||
pub hir_id: HirId,
|
||||
|
|
@ -2878,6 +2909,8 @@ pub enum TyKind<'hir> {
|
|||
Ref(&'hir Lifetime, MutTy<'hir>),
|
||||
/// A bare function (e.g., `fn(usize) -> bool`).
|
||||
BareFn(&'hir BareFnTy<'hir>),
|
||||
/// An unsafe binder type (e.g. `unsafe<'a> Foo<'a>`).
|
||||
UnsafeBinder(&'hir UnsafeBinderTy<'hir>),
|
||||
/// The never type (`!`).
|
||||
Never,
|
||||
/// A tuple (`(A, B, C, D, ...)`).
|
||||
|
|
@ -2889,6 +2922,8 @@ pub enum TyKind<'hir> {
|
|||
Path(QPath<'hir>),
|
||||
/// An opaque type definition itself. This is only used for `impl Trait`.
|
||||
OpaqueDef(&'hir OpaqueTy<'hir>),
|
||||
/// A trait ascription type, which is `impl Trait` within a local binding.
|
||||
TraitAscription(GenericBounds<'hir>),
|
||||
/// A trait object type `Bound1 + Bound2 + Bound3`
|
||||
/// where `Bound` is a trait or a lifetime.
|
||||
TraitObject(&'hir [PolyTraitRef<'hir>], &'hir Lifetime, TraitObjectSyntax),
|
||||
|
|
@ -4042,9 +4077,7 @@ impl<'hir> Node<'hir> {
|
|||
_ => None,
|
||||
},
|
||||
Node::TraitItem(ti) => match ti.kind {
|
||||
TraitItemKind::Fn(ref sig, TraitFn::Provided(_)) => {
|
||||
Some(FnKind::Method(ti.ident, sig))
|
||||
}
|
||||
TraitItemKind::Fn(ref sig, _) => Some(FnKind::Method(ti.ident, sig)),
|
||||
_ => None,
|
||||
},
|
||||
Node::ImplItem(ii) => match ii.kind {
|
||||
|
|
|
|||
|
|
@ -857,6 +857,10 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
|
|||
ExprKind::Yield(ref subexpression, _) => {
|
||||
try_visit!(visitor.visit_expr(subexpression));
|
||||
}
|
||||
ExprKind::UnsafeBinderCast(_kind, expr, ty) => {
|
||||
try_visit!(visitor.visit_expr(expr));
|
||||
visit_opt!(visitor, visit_ty, ty);
|
||||
}
|
||||
ExprKind::Lit(_) | ExprKind::Err(_) => {}
|
||||
}
|
||||
V::Result::output()
|
||||
|
|
@ -886,12 +890,19 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul
|
|||
walk_list!(visitor, visit_generic_param, function_declaration.generic_params);
|
||||
try_visit!(visitor.visit_fn_decl(function_declaration.decl));
|
||||
}
|
||||
TyKind::UnsafeBinder(ref unsafe_binder) => {
|
||||
walk_list!(visitor, visit_generic_param, unsafe_binder.generic_params);
|
||||
try_visit!(visitor.visit_ty(unsafe_binder.inner_ty));
|
||||
}
|
||||
TyKind::Path(ref qpath) => {
|
||||
try_visit!(visitor.visit_qpath(qpath, typ.hir_id, typ.span));
|
||||
}
|
||||
TyKind::OpaqueDef(opaque) => {
|
||||
try_visit!(visitor.visit_opaque_ty(opaque));
|
||||
}
|
||||
TyKind::TraitAscription(bounds) => {
|
||||
walk_list!(visitor, visit_param_bound, bounds);
|
||||
}
|
||||
TyKind::Array(ref ty, ref length) => {
|
||||
try_visit!(visitor.visit_ty(ty));
|
||||
try_visit!(visitor.visit_const_arg(length));
|
||||
|
|
|
|||
|
|
@ -246,6 +246,18 @@ hir_analysis_invalid_receiver_ty = invalid `self` parameter type: `{$receiver_ty
|
|||
hir_analysis_invalid_receiver_ty_help =
|
||||
consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
|
||||
|
||||
hir_analysis_invalid_receiver_ty_help_no_arbitrary_self_types =
|
||||
consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
|
||||
|
||||
hir_analysis_invalid_receiver_ty_help_nonnull_note =
|
||||
`NonNull` does not implement `Receiver` because it has methods that may shadow the referent; consider wrapping your `NonNull` in a newtype wrapper for which you implement `Receiver`
|
||||
|
||||
hir_analysis_invalid_receiver_ty_help_weak_note =
|
||||
`Weak` does not implement `Receiver` because it has methods that may shadow the referent; consider wrapping your `Weak` in a newtype wrapper for which you implement `Receiver`
|
||||
|
||||
hir_analysis_invalid_receiver_ty_no_arbitrary_self_types = invalid `self` parameter type: `{$receiver_ty}`
|
||||
.note = type of `self` must be `Self` or a type that dereferences to it
|
||||
|
||||
hir_analysis_invalid_union_field =
|
||||
field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
|
||||
.note = union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ use {rustc_ast as ast, rustc_hir as hir};
|
|||
use crate::autoderef::Autoderef;
|
||||
use crate::collect::CollectItemTypesVisitor;
|
||||
use crate::constrained_generic_params::{Parameter, identify_constrained_generic_params};
|
||||
use crate::errors::InvalidReceiverTyHint;
|
||||
use crate::{errors, fluent_generated as fluent};
|
||||
|
||||
pub(super) struct WfCheckingCtxt<'a, 'tcx> {
|
||||
|
|
@ -1748,8 +1749,25 @@ fn check_method_receiver<'tcx>(
|
|||
// Report error; would not have worked with `arbitrary_self_types[_pointers]`.
|
||||
{
|
||||
match receiver_validity_err {
|
||||
ReceiverValidityError::DoesNotDeref if arbitrary_self_types_level.is_some() => {
|
||||
let hint = match receiver_ty
|
||||
.builtin_deref(false)
|
||||
.unwrap_or(receiver_ty)
|
||||
.ty_adt_def()
|
||||
.and_then(|adt_def| tcx.get_diagnostic_name(adt_def.did()))
|
||||
{
|
||||
Some(sym::RcWeak | sym::ArcWeak) => Some(InvalidReceiverTyHint::Weak),
|
||||
Some(sym::NonNull) => Some(InvalidReceiverTyHint::NonNull),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty, hint })
|
||||
}
|
||||
ReceiverValidityError::DoesNotDeref => {
|
||||
tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty })
|
||||
tcx.dcx().emit_err(errors::InvalidReceiverTyNoArbitrarySelfTypes {
|
||||
span,
|
||||
receiver_ty,
|
||||
})
|
||||
}
|
||||
ReceiverValidityError::MethodGenericParamUsed => {
|
||||
tcx.dcx().emit_err(errors::InvalidGenericReceiverTy { span, receiver_ty })
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ use rustc_errors::{
|
|||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::{self, Visitor, walk_generics};
|
||||
use rustc_hir::{self as hir, GenericParamKind, Node};
|
||||
use rustc_hir::{self as hir, GenericParamKind, HirId, Node};
|
||||
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_middle::hir::nested_filter;
|
||||
|
|
@ -201,12 +201,13 @@ pub(crate) fn placeholder_type_error_diag<'cx, 'tcx>(
|
|||
placeholder_types.iter().map(|sp| (*sp, (*type_name).to_string())).collect();
|
||||
|
||||
if let Some(generics) = generics {
|
||||
if let Some(arg) = params.iter().find(|arg| {
|
||||
matches!(arg.name, hir::ParamName::Plain(Ident { name: kw::Underscore, .. }))
|
||||
if let Some(span) = params.iter().find_map(|arg| match arg.name {
|
||||
hir::ParamName::Plain(Ident { name: kw::Underscore, span }) => Some(span),
|
||||
_ => None,
|
||||
}) {
|
||||
// Account for `_` already present in cases like `struct S<_>(_);` and suggest
|
||||
// `struct S<T>(T);` instead of `struct S<_, T>(T);`.
|
||||
sugg.push((arg.span, (*type_name).to_string()));
|
||||
sugg.push((span, (*type_name).to_string()));
|
||||
} else if let Some(span) = generics.span_for_param_suggestion() {
|
||||
// Account for bounds, we want `fn foo<T: E, K>(_: K)` not `fn foo<T, K: E>(_: K)`.
|
||||
sugg.push((span, format!(", {type_name}")));
|
||||
|
|
@ -436,6 +437,15 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
|
|||
ty::Const::new_error_with_message(self.tcx(), span, "bad placeholder constant")
|
||||
}
|
||||
|
||||
fn register_trait_ascription_bounds(
|
||||
&self,
|
||||
_: Vec<(ty::Clause<'tcx>, Span)>,
|
||||
_: HirId,
|
||||
span: Span,
|
||||
) {
|
||||
self.dcx().span_delayed_bug(span, "trait ascription type not allowed here");
|
||||
}
|
||||
|
||||
fn probe_ty_param_bounds(
|
||||
&self,
|
||||
span: Span,
|
||||
|
|
@ -1330,7 +1340,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
|
|||
..
|
||||
})
|
||||
| Item(hir::Item { kind: ItemKind::Fn(sig, generics, _), .. }) => {
|
||||
infer_return_ty_for_fn_sig(sig, generics, def_id, &icx)
|
||||
lower_fn_sig_recovering_infer_ret_ty(&icx, sig, generics, def_id)
|
||||
}
|
||||
|
||||
ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => {
|
||||
|
|
@ -1347,7 +1357,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
|
|||
None,
|
||||
)
|
||||
} else {
|
||||
infer_return_ty_for_fn_sig(sig, generics, def_id, &icx)
|
||||
lower_fn_sig_recovering_infer_ret_ty(&icx, sig, generics, def_id)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1397,99 +1407,108 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
|
|||
ty::EarlyBinder::bind(output)
|
||||
}
|
||||
|
||||
fn infer_return_ty_for_fn_sig<'tcx>(
|
||||
sig: &hir::FnSig<'tcx>,
|
||||
generics: &hir::Generics<'_>,
|
||||
def_id: LocalDefId,
|
||||
fn lower_fn_sig_recovering_infer_ret_ty<'tcx>(
|
||||
icx: &ItemCtxt<'tcx>,
|
||||
sig: &'tcx hir::FnSig<'tcx>,
|
||||
generics: &'tcx hir::Generics<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
) -> ty::PolyFnSig<'tcx> {
|
||||
if let Some(infer_ret_ty) = sig.decl.output.get_infer_ret_ty() {
|
||||
return recover_infer_ret_ty(icx, infer_ret_ty, generics, def_id);
|
||||
}
|
||||
|
||||
icx.lowerer().lower_fn_ty(
|
||||
icx.tcx().local_def_id_to_hir_id(def_id),
|
||||
sig.header.safety,
|
||||
sig.header.abi,
|
||||
sig.decl,
|
||||
Some(generics),
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
fn recover_infer_ret_ty<'tcx>(
|
||||
icx: &ItemCtxt<'tcx>,
|
||||
infer_ret_ty: &'tcx hir::Ty<'tcx>,
|
||||
generics: &'tcx hir::Generics<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
) -> ty::PolyFnSig<'tcx> {
|
||||
let tcx = icx.tcx;
|
||||
let hir_id = tcx.local_def_id_to_hir_id(def_id);
|
||||
|
||||
match sig.decl.output.get_infer_ret_ty() {
|
||||
Some(ty) => {
|
||||
let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id];
|
||||
// Typeck doesn't expect erased regions to be returned from `type_of`.
|
||||
// This is a heuristic approach. If the scope has region parameters,
|
||||
// we should change fn_sig's lifetime from `ReErased` to `ReError`,
|
||||
// otherwise to `ReStatic`.
|
||||
let has_region_params = generics.params.iter().any(|param| match param.kind {
|
||||
GenericParamKind::Lifetime { .. } => true,
|
||||
_ => false,
|
||||
});
|
||||
let fn_sig = fold_regions(tcx, fn_sig, |r, _| match *r {
|
||||
ty::ReErased => {
|
||||
if has_region_params {
|
||||
ty::Region::new_error_with_message(
|
||||
tcx,
|
||||
DUMMY_SP,
|
||||
"erased region is not allowed here in return type",
|
||||
)
|
||||
} else {
|
||||
tcx.lifetimes.re_static
|
||||
}
|
||||
}
|
||||
_ => r,
|
||||
});
|
||||
let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id];
|
||||
|
||||
let mut visitor = HirPlaceholderCollector::default();
|
||||
visitor.visit_ty(ty);
|
||||
|
||||
let mut diag = bad_placeholder(icx.lowerer(), visitor.0, "return type");
|
||||
let ret_ty = fn_sig.output();
|
||||
// Don't leak types into signatures unless they're nameable!
|
||||
// For example, if a function returns itself, we don't want that
|
||||
// recursive function definition to leak out into the fn sig.
|
||||
let mut recovered_ret_ty = None;
|
||||
|
||||
if let Some(suggestable_ret_ty) = ret_ty.make_suggestable(tcx, false, None) {
|
||||
diag.span_suggestion(
|
||||
ty.span,
|
||||
"replace with the correct return type",
|
||||
suggestable_ret_ty,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
recovered_ret_ty = Some(suggestable_ret_ty);
|
||||
} else if let Some(sugg) = suggest_impl_trait(
|
||||
&tcx.infer_ctxt().build(TypingMode::non_body_analysis()),
|
||||
tcx.param_env(def_id),
|
||||
ret_ty,
|
||||
) {
|
||||
diag.span_suggestion(
|
||||
ty.span,
|
||||
"replace with an appropriate return type",
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else if ret_ty.is_closure() {
|
||||
diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound");
|
||||
// Typeck doesn't expect erased regions to be returned from `type_of`.
|
||||
// This is a heuristic approach. If the scope has region parameters,
|
||||
// we should change fn_sig's lifetime from `ReErased` to `ReError`,
|
||||
// otherwise to `ReStatic`.
|
||||
let has_region_params = generics.params.iter().any(|param| match param.kind {
|
||||
GenericParamKind::Lifetime { .. } => true,
|
||||
_ => false,
|
||||
});
|
||||
let fn_sig = fold_regions(tcx, fn_sig, |r, _| match *r {
|
||||
ty::ReErased => {
|
||||
if has_region_params {
|
||||
ty::Region::new_error_with_message(
|
||||
tcx,
|
||||
DUMMY_SP,
|
||||
"erased region is not allowed here in return type",
|
||||
)
|
||||
} else {
|
||||
tcx.lifetimes.re_static
|
||||
}
|
||||
// Also note how `Fn` traits work just in case!
|
||||
if ret_ty.is_closure() {
|
||||
diag.note(
|
||||
"for more information on `Fn` traits and closure types, see \
|
||||
https://doc.rust-lang.org/book/ch13-01-closures.html",
|
||||
);
|
||||
}
|
||||
|
||||
let guar = diag.emit();
|
||||
ty::Binder::dummy(tcx.mk_fn_sig(
|
||||
fn_sig.inputs().iter().copied(),
|
||||
recovered_ret_ty.unwrap_or_else(|| Ty::new_error(tcx, guar)),
|
||||
fn_sig.c_variadic,
|
||||
fn_sig.safety,
|
||||
fn_sig.abi,
|
||||
))
|
||||
}
|
||||
None => icx.lowerer().lower_fn_ty(
|
||||
hir_id,
|
||||
sig.header.safety,
|
||||
sig.header.abi,
|
||||
sig.decl,
|
||||
Some(generics),
|
||||
None,
|
||||
),
|
||||
_ => r,
|
||||
});
|
||||
|
||||
let mut visitor = HirPlaceholderCollector::default();
|
||||
visitor.visit_ty(infer_ret_ty);
|
||||
|
||||
let mut diag = bad_placeholder(icx.lowerer(), visitor.0, "return type");
|
||||
let ret_ty = fn_sig.output();
|
||||
|
||||
// Don't leak types into signatures unless they're nameable!
|
||||
// For example, if a function returns itself, we don't want that
|
||||
// recursive function definition to leak out into the fn sig.
|
||||
let mut recovered_ret_ty = None;
|
||||
if let Some(suggestable_ret_ty) = ret_ty.make_suggestable(tcx, false, None) {
|
||||
diag.span_suggestion(
|
||||
infer_ret_ty.span,
|
||||
"replace with the correct return type",
|
||||
suggestable_ret_ty,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
recovered_ret_ty = Some(suggestable_ret_ty);
|
||||
} else if let Some(sugg) = suggest_impl_trait(
|
||||
&tcx.infer_ctxt().build(TypingMode::non_body_analysis()),
|
||||
tcx.param_env(def_id),
|
||||
ret_ty,
|
||||
) {
|
||||
diag.span_suggestion(
|
||||
infer_ret_ty.span,
|
||||
"replace with an appropriate return type",
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else if ret_ty.is_closure() {
|
||||
diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound");
|
||||
}
|
||||
|
||||
// Also note how `Fn` traits work just in case!
|
||||
if ret_ty.is_closure() {
|
||||
diag.note(
|
||||
"for more information on `Fn` traits and closure types, see \
|
||||
https://doc.rust-lang.org/book/ch13-01-closures.html",
|
||||
);
|
||||
}
|
||||
let guar = diag.emit();
|
||||
ty::Binder::dummy(tcx.mk_fn_sig(
|
||||
fn_sig.inputs().iter().copied(),
|
||||
recovered_ret_ty.unwrap_or_else(|| Ty::new_error(tcx, guar)),
|
||||
fn_sig.c_variadic,
|
||||
fn_sig.safety,
|
||||
fn_sig.abi,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn suggest_impl_trait<'tcx>(
|
||||
|
|
@ -1611,7 +1630,7 @@ fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::ImplTrai
|
|||
impl_.of_trait.as_ref().map(|ast_trait_ref| {
|
||||
let selfty = tcx.type_of(def_id).instantiate_identity();
|
||||
|
||||
check_impl_constness(tcx, tcx.is_const_trait_impl(def_id.to_def_id()), ast_trait_ref);
|
||||
check_impl_constness(tcx, impl_.constness, ast_trait_ref);
|
||||
|
||||
let trait_ref = icx.lowerer().lower_impl_trait_ref(ast_trait_ref, selfty);
|
||||
|
||||
|
|
@ -1619,22 +1638,23 @@ fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::ImplTrai
|
|||
trait_ref: ty::EarlyBinder::bind(trait_ref),
|
||||
safety: impl_.safety,
|
||||
polarity: polarity_of_impl(tcx, def_id, impl_, item.span),
|
||||
constness: impl_.constness,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn check_impl_constness(
|
||||
tcx: TyCtxt<'_>,
|
||||
is_const: bool,
|
||||
constness: hir::Constness,
|
||||
hir_trait_ref: &hir::TraitRef<'_>,
|
||||
) -> Option<ErrorGuaranteed> {
|
||||
if !is_const {
|
||||
return None;
|
||||
) {
|
||||
if let hir::Constness::NotConst = constness {
|
||||
return;
|
||||
}
|
||||
|
||||
let trait_def_id = hir_trait_ref.trait_def_id()?;
|
||||
let Some(trait_def_id) = hir_trait_ref.trait_def_id() else { return };
|
||||
if tcx.is_const_trait(trait_def_id) {
|
||||
return None;
|
||||
return;
|
||||
}
|
||||
|
||||
let trait_name = tcx.item_name(trait_def_id).to_string();
|
||||
|
|
@ -1650,14 +1670,14 @@ fn check_impl_constness(
|
|||
),
|
||||
(false, _) | (_, false) => (None, ""),
|
||||
};
|
||||
Some(tcx.dcx().emit_err(errors::ConstImplForNonConstTrait {
|
||||
tcx.dcx().emit_err(errors::ConstImplForNonConstTrait {
|
||||
trait_ref_span: hir_trait_ref.path.span,
|
||||
trait_name,
|
||||
local_trait_span,
|
||||
suggestion_pre,
|
||||
marking: (),
|
||||
adding: (),
|
||||
}))
|
||||
});
|
||||
}
|
||||
|
||||
fn polarity_of_impl(
|
||||
|
|
|
|||
|
|
@ -470,6 +470,12 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
|
|||
self.outer_index.shift_out(1);
|
||||
res
|
||||
}
|
||||
hir::TyKind::UnsafeBinder(_) => {
|
||||
self.outer_index.shift_in(1);
|
||||
let res = intravisit::walk_ty(self, ty);
|
||||
self.outer_index.shift_out(1);
|
||||
res
|
||||
}
|
||||
_ => intravisit::walk_ty(self, ty),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -781,6 +781,36 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
intravisit::walk_ty(this, ty);
|
||||
});
|
||||
}
|
||||
hir::TyKind::UnsafeBinder(binder) => {
|
||||
let (mut bound_vars, binders): (FxIndexMap<LocalDefId, ResolvedArg>, Vec<_>) =
|
||||
binder
|
||||
.generic_params
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(late_bound_idx, param)| {
|
||||
(
|
||||
(param.def_id, ResolvedArg::late(late_bound_idx as u32, param)),
|
||||
late_arg_as_bound_arg(self.tcx, param),
|
||||
)
|
||||
})
|
||||
.unzip();
|
||||
|
||||
deny_non_region_late_bound(self.tcx, &mut bound_vars, "function pointer types");
|
||||
|
||||
self.record_late_bound_vars(ty.hir_id, binders);
|
||||
let scope = Scope::Binder {
|
||||
hir_id: ty.hir_id,
|
||||
bound_vars,
|
||||
s: self.scope,
|
||||
scope_type: BinderScopeType::Normal,
|
||||
where_bound_origin: None,
|
||||
};
|
||||
self.with(scope, |this| {
|
||||
// a bare fn has no bounds, so everything
|
||||
// contained within is scoped within its binder.
|
||||
intravisit::walk_ty(this, ty);
|
||||
});
|
||||
}
|
||||
hir::TyKind::TraitObject(bounds, lifetime, _) => {
|
||||
debug!(?bounds, ?lifetime, "TraitObject");
|
||||
let scope = Scope::TraitRefBoundary { s: self.scope };
|
||||
|
|
@ -822,6 +852,21 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
};
|
||||
self.with(scope, |this| this.visit_ty(mt.ty));
|
||||
}
|
||||
hir::TyKind::TraitAscription(bounds) => {
|
||||
let scope = Scope::TraitRefBoundary { s: self.scope };
|
||||
self.with(scope, |this| {
|
||||
let scope = Scope::LateBoundary {
|
||||
s: this.scope,
|
||||
what: "`impl Trait` in binding",
|
||||
deny_late_regions: true,
|
||||
};
|
||||
this.with(scope, |this| {
|
||||
for bound in bounds {
|
||||
this.visit_param_bound(bound);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
_ => intravisit::walk_ty(self, ty),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1655,6 +1655,24 @@ pub(crate) struct NonConstRange {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum InvalidReceiverTyHint {
|
||||
#[note(hir_analysis_invalid_receiver_ty_help_weak_note)]
|
||||
Weak,
|
||||
#[note(hir_analysis_invalid_receiver_ty_help_nonnull_note)]
|
||||
NonNull,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_invalid_receiver_ty_no_arbitrary_self_types, code = E0307)]
|
||||
#[note]
|
||||
#[help(hir_analysis_invalid_receiver_ty_help_no_arbitrary_self_types)]
|
||||
pub(crate) struct InvalidReceiverTyNoArbitrarySelfTypes<'tcx> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub receiver_ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_invalid_receiver_ty, code = E0307)]
|
||||
#[note]
|
||||
|
|
@ -1663,6 +1681,8 @@ pub(crate) struct InvalidReceiverTy<'tcx> {
|
|||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub receiver_ty: Ty<'tcx>,
|
||||
#[subdiagnostic]
|
||||
pub hint: Option<InvalidReceiverTyHint>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::struct_span_code_err;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::fold::BottomUpFolder;
|
||||
|
|
@ -11,7 +10,7 @@ use rustc_middle::ty::{
|
|||
self, DynKind, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable,
|
||||
TypeVisitableExt, Upcast,
|
||||
};
|
||||
use rustc_span::{ErrorGuaranteed, Span};
|
||||
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
|
||||
use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility;
|
||||
use rustc_trait_selection::traits::{self, hir_ty_lowering_dyn_compatibility_violations};
|
||||
use rustc_type_ir::elaborate::ClauseWithSupertraitSpan;
|
||||
|
|
@ -128,8 +127,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
}
|
||||
|
||||
let mut associated_types: FxIndexMap<Span, FxIndexSet<DefId>> = FxIndexMap::default();
|
||||
let mut needed_associated_types = FxIndexSet::default();
|
||||
|
||||
let principal_span = regular_traits.first().map_or(DUMMY_SP, |info| info.bottom().1);
|
||||
let regular_traits_refs_spans = trait_bounds
|
||||
.into_iter()
|
||||
.filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
|
||||
|
|
@ -145,13 +145,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let bound_predicate = pred.kind();
|
||||
match bound_predicate.skip_binder() {
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
|
||||
let pred = bound_predicate.rebind(pred);
|
||||
associated_types.entry(original_span).or_default().extend(
|
||||
tcx.associated_items(pred.def_id())
|
||||
// FIXME(negative_bounds): Handle this correctly...
|
||||
let trait_ref =
|
||||
tcx.anonymize_bound_vars(bound_predicate.rebind(pred.trait_ref));
|
||||
needed_associated_types.extend(
|
||||
tcx.associated_items(trait_ref.def_id())
|
||||
.in_definition_order()
|
||||
.filter(|item| item.kind == ty::AssocKind::Type)
|
||||
.filter(|item| !item.is_impl_trait_in_trait())
|
||||
.map(|item| item.def_id),
|
||||
// If the associated type has a `where Self: Sized` bound,
|
||||
// we do not need to constrain the associated type.
|
||||
.filter(|item| !tcx.generics_require_sized_self(item.def_id))
|
||||
.map(|item| (item.def_id, trait_ref)),
|
||||
);
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => {
|
||||
|
|
@ -201,26 +206,25 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
// So every `Projection` clause is an `Assoc = Foo` bound. `associated_types` contains all associated
|
||||
// types's `DefId`, so the following loop removes all the `DefIds` of the associated types that have a
|
||||
// corresponding `Projection` clause
|
||||
for def_ids in associated_types.values_mut() {
|
||||
for (projection_bound, span) in &projection_bounds {
|
||||
let def_id = projection_bound.item_def_id();
|
||||
def_ids.swap_remove(&def_id);
|
||||
if tcx.generics_require_sized_self(def_id) {
|
||||
tcx.emit_node_span_lint(
|
||||
UNUSED_ASSOCIATED_TYPE_BOUNDS,
|
||||
hir_id,
|
||||
*span,
|
||||
crate::errors::UnusedAssociatedTypeBounds { span: *span },
|
||||
);
|
||||
}
|
||||
for (projection_bound, span) in &projection_bounds {
|
||||
let def_id = projection_bound.item_def_id();
|
||||
let trait_ref = tcx.anonymize_bound_vars(
|
||||
projection_bound.map_bound(|p| p.projection_term.trait_ref(tcx)),
|
||||
);
|
||||
needed_associated_types.swap_remove(&(def_id, trait_ref));
|
||||
if tcx.generics_require_sized_self(def_id) {
|
||||
tcx.emit_node_span_lint(
|
||||
UNUSED_ASSOCIATED_TYPE_BOUNDS,
|
||||
hir_id,
|
||||
*span,
|
||||
crate::errors::UnusedAssociatedTypeBounds { span: *span },
|
||||
);
|
||||
}
|
||||
// If the associated type has a `where Self: Sized` bound, we do not need to constrain the associated
|
||||
// type in the `dyn Trait`.
|
||||
def_ids.retain(|def_id| !tcx.generics_require_sized_self(def_id));
|
||||
}
|
||||
|
||||
if let Err(guar) = self.check_for_required_assoc_tys(
|
||||
associated_types,
|
||||
principal_span,
|
||||
needed_associated_types,
|
||||
potential_assoc_types,
|
||||
hir_trait_bounds,
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ use rustc_hir as hir;
|
|||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::query::Key;
|
||||
use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _};
|
||||
use rustc_middle::ty::{
|
||||
self, AdtDef, Binder, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeVisitableExt,
|
||||
|
|
@ -722,51 +721,42 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
/// emit a generic note suggesting using a `where` clause to constraint instead.
|
||||
pub(crate) fn check_for_required_assoc_tys(
|
||||
&self,
|
||||
associated_types: FxIndexMap<Span, FxIndexSet<DefId>>,
|
||||
principal_span: Span,
|
||||
missing_assoc_types: FxIndexSet<(DefId, ty::PolyTraitRef<'tcx>)>,
|
||||
potential_assoc_types: Vec<usize>,
|
||||
trait_bounds: &[hir::PolyTraitRef<'_>],
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
if associated_types.values().all(|v| v.is_empty()) {
|
||||
if missing_assoc_types.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let tcx = self.tcx();
|
||||
// FIXME: Marked `mut` so that we can replace the spans further below with a more
|
||||
// appropriate one, but this should be handled earlier in the span assignment.
|
||||
let associated_types: FxIndexMap<Span, Vec<_>> = associated_types
|
||||
// FIXME: This logic needs some more care w.r.t handling of conflicts
|
||||
let missing_assoc_types: Vec<_> = missing_assoc_types
|
||||
.into_iter()
|
||||
.map(|(span, def_ids)| {
|
||||
(span, def_ids.into_iter().map(|did| tcx.associated_item(did)).collect())
|
||||
})
|
||||
.map(|(def_id, trait_ref)| (tcx.associated_item(def_id), trait_ref))
|
||||
.collect();
|
||||
let mut names: FxIndexMap<String, Vec<Symbol>> = Default::default();
|
||||
let mut names: FxIndexMap<_, Vec<Symbol>> = Default::default();
|
||||
let mut names_len = 0;
|
||||
|
||||
// Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and
|
||||
// `issue-22560.rs`.
|
||||
let mut trait_bound_spans: Vec<Span> = vec![];
|
||||
let mut dyn_compatibility_violations = Ok(());
|
||||
for (span, items) in &associated_types {
|
||||
if !items.is_empty() {
|
||||
trait_bound_spans.push(*span);
|
||||
}
|
||||
for assoc_item in items {
|
||||
let trait_def_id = assoc_item.container_id(tcx);
|
||||
names.entry(tcx.def_path_str(trait_def_id)).or_default().push(assoc_item.name);
|
||||
names_len += 1;
|
||||
for (assoc_item, trait_ref) in &missing_assoc_types {
|
||||
names.entry(trait_ref).or_default().push(assoc_item.name);
|
||||
names_len += 1;
|
||||
|
||||
let violations =
|
||||
dyn_compatibility_violations_for_assoc_item(tcx, trait_def_id, *assoc_item);
|
||||
if !violations.is_empty() {
|
||||
dyn_compatibility_violations = Err(report_dyn_incompatibility(
|
||||
tcx,
|
||||
*span,
|
||||
None,
|
||||
trait_def_id,
|
||||
&violations,
|
||||
)
|
||||
.emit());
|
||||
}
|
||||
let violations =
|
||||
dyn_compatibility_violations_for_assoc_item(tcx, trait_ref.def_id(), *assoc_item);
|
||||
if !violations.is_empty() {
|
||||
dyn_compatibility_violations = Err(report_dyn_incompatibility(
|
||||
tcx,
|
||||
principal_span,
|
||||
None,
|
||||
trait_ref.def_id(),
|
||||
&violations,
|
||||
)
|
||||
.emit());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -814,6 +804,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
.into_iter()
|
||||
.map(|(trait_, mut assocs)| {
|
||||
assocs.sort();
|
||||
let trait_ = trait_.print_trait_sugared();
|
||||
format!("{} in `{trait_}`", match &assocs[..] {
|
||||
[] => String::new(),
|
||||
[only] => format!("`{only}`"),
|
||||
|
|
@ -827,10 +818,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
names.sort();
|
||||
let names = names.join(", ");
|
||||
|
||||
trait_bound_spans.sort();
|
||||
let mut err = struct_span_code_err!(
|
||||
self.dcx(),
|
||||
trait_bound_spans,
|
||||
principal_span,
|
||||
E0191,
|
||||
"the value of the associated type{} {} must be specified",
|
||||
pluralize!(names_len),
|
||||
|
|
@ -840,81 +830,83 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let mut types_count = 0;
|
||||
let mut where_constraints = vec![];
|
||||
let mut already_has_generics_args_suggestion = false;
|
||||
for (span, assoc_items) in &associated_types {
|
||||
let mut names: UnordMap<_, usize> = Default::default();
|
||||
for item in assoc_items {
|
||||
types_count += 1;
|
||||
*names.entry(item.name).or_insert(0) += 1;
|
||||
}
|
||||
let mut dupes = false;
|
||||
let mut shadows = false;
|
||||
for item in assoc_items {
|
||||
let prefix = if names[&item.name] > 1 {
|
||||
let trait_def_id = item.container_id(tcx);
|
||||
dupes = true;
|
||||
format!("{}::", tcx.def_path_str(trait_def_id))
|
||||
} else if bound_names.get(&item.name).is_some_and(|x| x != &item) {
|
||||
let trait_def_id = item.container_id(tcx);
|
||||
shadows = true;
|
||||
format!("{}::", tcx.def_path_str(trait_def_id))
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
let mut is_shadowed = false;
|
||||
let mut names: UnordMap<_, usize> = Default::default();
|
||||
for (item, _) in &missing_assoc_types {
|
||||
types_count += 1;
|
||||
*names.entry(item.name).or_insert(0) += 1;
|
||||
}
|
||||
let mut dupes = false;
|
||||
let mut shadows = false;
|
||||
for (item, trait_ref) in &missing_assoc_types {
|
||||
let prefix = if names[&item.name] > 1 {
|
||||
let trait_def_id = trait_ref.def_id();
|
||||
dupes = true;
|
||||
format!("{}::", tcx.def_path_str(trait_def_id))
|
||||
} else if bound_names.get(&item.name).is_some_and(|x| *x != item) {
|
||||
let trait_def_id = trait_ref.def_id();
|
||||
shadows = true;
|
||||
format!("{}::", tcx.def_path_str(trait_def_id))
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
if let Some(assoc_item) = bound_names.get(&item.name)
|
||||
&& assoc_item != &item
|
||||
{
|
||||
is_shadowed = true;
|
||||
let mut is_shadowed = false;
|
||||
|
||||
let rename_message =
|
||||
if assoc_item.def_id.is_local() { ", consider renaming it" } else { "" };
|
||||
err.span_label(
|
||||
tcx.def_span(assoc_item.def_id),
|
||||
format!("`{}{}` shadowed here{}", prefix, item.name, rename_message),
|
||||
);
|
||||
}
|
||||
|
||||
let rename_message = if is_shadowed { ", consider renaming it" } else { "" };
|
||||
|
||||
if let Some(sp) = tcx.hir().span_if_local(item.def_id) {
|
||||
err.span_label(
|
||||
sp,
|
||||
format!("`{}{}` defined here{}", prefix, item.name, rename_message),
|
||||
);
|
||||
}
|
||||
}
|
||||
if potential_assoc_types.len() == assoc_items.len() {
|
||||
// When the amount of missing associated types equals the number of
|
||||
// extra type arguments present. A suggesting to replace the generic args with
|
||||
// associated types is already emitted.
|
||||
already_has_generics_args_suggestion = true;
|
||||
} else if let (Ok(snippet), false, false) =
|
||||
(tcx.sess.source_map().span_to_snippet(*span), dupes, shadows)
|
||||
if let Some(assoc_item) = bound_names.get(&item.name)
|
||||
&& *assoc_item != item
|
||||
{
|
||||
let types: Vec<_> =
|
||||
assoc_items.iter().map(|item| format!("{} = Type", item.name)).collect();
|
||||
let code = if snippet.ends_with('>') {
|
||||
// The user wrote `Trait<'a>` or similar and we don't have a type we can
|
||||
// suggest, but at least we can clue them to the correct syntax
|
||||
// `Trait<'a, Item = Type>` while accounting for the `<'a>` in the
|
||||
// suggestion.
|
||||
format!("{}, {}>", &snippet[..snippet.len() - 1], types.join(", "))
|
||||
} else if in_expr_or_pat {
|
||||
// The user wrote `Iterator`, so we don't have a type we can suggest, but at
|
||||
// least we can clue them to the correct syntax `Iterator::<Item = Type>`.
|
||||
format!("{}::<{}>", snippet, types.join(", "))
|
||||
} else {
|
||||
// The user wrote `Iterator`, so we don't have a type we can suggest, but at
|
||||
// least we can clue them to the correct syntax `Iterator<Item = Type>`.
|
||||
format!("{}<{}>", snippet, types.join(", "))
|
||||
};
|
||||
suggestions.push((*span, code));
|
||||
} else if dupes {
|
||||
where_constraints.push(*span);
|
||||
is_shadowed = true;
|
||||
|
||||
let rename_message =
|
||||
if assoc_item.def_id.is_local() { ", consider renaming it" } else { "" };
|
||||
err.span_label(
|
||||
tcx.def_span(assoc_item.def_id),
|
||||
format!("`{}{}` shadowed here{}", prefix, item.name, rename_message),
|
||||
);
|
||||
}
|
||||
|
||||
let rename_message = if is_shadowed { ", consider renaming it" } else { "" };
|
||||
|
||||
if let Some(sp) = tcx.hir().span_if_local(item.def_id) {
|
||||
err.span_label(
|
||||
sp,
|
||||
format!("`{}{}` defined here{}", prefix, item.name, rename_message),
|
||||
);
|
||||
}
|
||||
}
|
||||
if potential_assoc_types.len() == missing_assoc_types.len() {
|
||||
// When the amount of missing associated types equals the number of
|
||||
// extra type arguments present. A suggesting to replace the generic args with
|
||||
// associated types is already emitted.
|
||||
already_has_generics_args_suggestion = true;
|
||||
} else if let (Ok(snippet), false, false) =
|
||||
(tcx.sess.source_map().span_to_snippet(principal_span), dupes, shadows)
|
||||
{
|
||||
let types: Vec<_> = missing_assoc_types
|
||||
.iter()
|
||||
.map(|(item, _)| format!("{} = Type", item.name))
|
||||
.collect();
|
||||
let code = if snippet.ends_with('>') {
|
||||
// The user wrote `Trait<'a>` or similar and we don't have a type we can
|
||||
// suggest, but at least we can clue them to the correct syntax
|
||||
// `Trait<'a, Item = Type>` while accounting for the `<'a>` in the
|
||||
// suggestion.
|
||||
format!("{}, {}>", &snippet[..snippet.len() - 1], types.join(", "))
|
||||
} else if in_expr_or_pat {
|
||||
// The user wrote `Iterator`, so we don't have a type we can suggest, but at
|
||||
// least we can clue them to the correct syntax `Iterator::<Item = Type>`.
|
||||
format!("{}::<{}>", snippet, types.join(", "))
|
||||
} else {
|
||||
// The user wrote `Iterator`, so we don't have a type we can suggest, but at
|
||||
// least we can clue them to the correct syntax `Iterator<Item = Type>`.
|
||||
format!("{}<{}>", snippet, types.join(", "))
|
||||
};
|
||||
suggestions.push((principal_span, code));
|
||||
} else if dupes {
|
||||
where_constraints.push(principal_span);
|
||||
}
|
||||
|
||||
let where_msg = "consider introducing a new type parameter, adding `where` constraints \
|
||||
using the fully-qualified path to the associated types";
|
||||
if !where_constraints.is_empty() && suggestions.is_empty() {
|
||||
|
|
@ -925,32 +917,29 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
if suggestions.len() != 1 || already_has_generics_args_suggestion {
|
||||
// We don't need this label if there's an inline suggestion, show otherwise.
|
||||
for (span, assoc_items) in &associated_types {
|
||||
let mut names: FxIndexMap<_, usize> = FxIndexMap::default();
|
||||
for item in assoc_items {
|
||||
types_count += 1;
|
||||
*names.entry(item.name).or_insert(0) += 1;
|
||||
}
|
||||
let mut label = vec![];
|
||||
for item in assoc_items {
|
||||
let postfix = if names[&item.name] > 1 {
|
||||
let trait_def_id = item.container_id(tcx);
|
||||
format!(" (from trait `{}`)", tcx.def_path_str(trait_def_id))
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
label.push(format!("`{}`{}", item.name, postfix));
|
||||
}
|
||||
if !label.is_empty() {
|
||||
err.span_label(
|
||||
*span,
|
||||
format!(
|
||||
"associated type{} {} must be specified",
|
||||
pluralize!(label.len()),
|
||||
label.join(", "),
|
||||
),
|
||||
);
|
||||
}
|
||||
let mut names: FxIndexMap<_, usize> = FxIndexMap::default();
|
||||
for (item, _) in &missing_assoc_types {
|
||||
types_count += 1;
|
||||
*names.entry(item.name).or_insert(0) += 1;
|
||||
}
|
||||
let mut label = vec![];
|
||||
for (item, trait_ref) in &missing_assoc_types {
|
||||
let postfix = if names[&item.name] > 1 {
|
||||
format!(" (from trait `{}`)", trait_ref.print_trait_sugared())
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
label.push(format!("`{}`{}", item.name, postfix));
|
||||
}
|
||||
if !label.is_empty() {
|
||||
err.span_label(
|
||||
principal_span,
|
||||
format!(
|
||||
"associated type{} {} must be specified",
|
||||
pluralize!(label.len()),
|
||||
label.join(", "),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
suggestions.sort_by_key(|&(span, _)| span);
|
||||
|
|
@ -1007,8 +996,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
)),
|
||||
..
|
||||
}) = node
|
||||
&& let Some(ty_def_id) = qself_ty.ty_def_id()
|
||||
&& let [inherent_impl] = tcx.inherent_impls(ty_def_id)
|
||||
&& let Some(adt_def) = qself_ty.ty_adt_def()
|
||||
&& let [inherent_impl] = tcx.inherent_impls(adt_def.did())
|
||||
&& let name = format!("{ident2}_{ident3}")
|
||||
&& let Some(ty::AssocItem { kind: ty::AssocKind::Fn, .. }) = tcx
|
||||
.associated_items(inherent_impl)
|
||||
|
|
|
|||
|
|
@ -123,6 +123,13 @@ pub trait HirTyLowerer<'tcx> {
|
|||
/// Returns the const to use when a const is omitted.
|
||||
fn ct_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx>;
|
||||
|
||||
fn register_trait_ascription_bounds(
|
||||
&self,
|
||||
bounds: Vec<(ty::Clause<'tcx>, Span)>,
|
||||
hir_id: HirId,
|
||||
span: Span,
|
||||
);
|
||||
|
||||
/// Probe bounds in scope where the bounded type coincides with the given type parameter.
|
||||
///
|
||||
/// Rephrased, this returns bounds of the form `T: Trait`, where `T` is a type parameter
|
||||
|
|
@ -2312,6 +2319,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
self.lower_fn_ty(hir_ty.hir_id, bf.safety, bf.abi, bf.decl, None, Some(hir_ty)),
|
||||
)
|
||||
}
|
||||
hir::TyKind::UnsafeBinder(_binder) => {
|
||||
let guar = self
|
||||
.dcx()
|
||||
.struct_span_err(hir_ty.span, "unsafe binders are not yet implemented")
|
||||
.emit();
|
||||
Ty::new_error(tcx, guar)
|
||||
}
|
||||
hir::TyKind::TraitObject(bounds, lifetime, repr) => {
|
||||
if let Some(guar) = self.prohibit_or_lint_bare_trait_object_ty(hir_ty) {
|
||||
// Don't continue with type analysis if the `dyn` keyword is missing
|
||||
|
|
@ -2368,6 +2382,25 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
|
||||
self.lower_opaque_ty(opaque_ty.def_id, in_trait)
|
||||
}
|
||||
hir::TyKind::TraitAscription(hir_bounds) => {
|
||||
// Impl trait in bindings lower as an infer var with additional
|
||||
// set of type bounds.
|
||||
let self_ty = self.ty_infer(None, hir_ty.span);
|
||||
let mut bounds = Bounds::default();
|
||||
self.lower_bounds(
|
||||
self_ty,
|
||||
hir_bounds.iter(),
|
||||
&mut bounds,
|
||||
ty::List::empty(),
|
||||
PredicateFilter::All,
|
||||
);
|
||||
self.register_trait_ascription_bounds(
|
||||
bounds.clauses().collect(),
|
||||
hir_ty.hir_id,
|
||||
hir_ty.span,
|
||||
);
|
||||
self_ty
|
||||
}
|
||||
// If we encounter a type relative path with RTN generics, then it must have
|
||||
// *not* gone through `lower_ty_maybe_return_type_notation`, and therefore
|
||||
// it's certainly in an illegal position.
|
||||
|
|
|
|||
|
|
@ -288,7 +288,13 @@ impl<'a> State<'a> {
|
|||
hir::TyKind::BareFn(f) => {
|
||||
self.print_ty_fn(f.abi, f.safety, f.decl, None, f.generic_params, f.param_names);
|
||||
}
|
||||
hir::TyKind::UnsafeBinder(unsafe_binder) => {
|
||||
self.print_unsafe_binder(unsafe_binder);
|
||||
}
|
||||
hir::TyKind::OpaqueDef(..) => self.word("/*impl Trait*/"),
|
||||
hir::TyKind::TraitAscription(bounds) => {
|
||||
self.print_bounds("impl", bounds);
|
||||
}
|
||||
hir::TyKind::Path(ref qpath) => self.print_qpath(qpath, false),
|
||||
hir::TyKind::TraitObject(bounds, lifetime, syntax) => {
|
||||
if syntax == ast::TraitObjectSyntax::Dyn {
|
||||
|
|
@ -339,6 +345,15 @@ impl<'a> State<'a> {
|
|||
self.end()
|
||||
}
|
||||
|
||||
fn print_unsafe_binder(&mut self, unsafe_binder: &hir::UnsafeBinderTy<'_>) {
|
||||
self.ibox(INDENT_UNIT);
|
||||
self.word("unsafe");
|
||||
self.print_generic_params(unsafe_binder.generic_params);
|
||||
self.nbsp();
|
||||
self.print_type(unsafe_binder.inner_ty);
|
||||
self.end();
|
||||
}
|
||||
|
||||
fn print_foreign_item(&mut self, item: &hir::ForeignItem<'_>) {
|
||||
self.hardbreak_if_not_bol();
|
||||
self.maybe_print_comment(item.span.lo());
|
||||
|
|
@ -1530,6 +1545,19 @@ impl<'a> State<'a> {
|
|||
|
||||
self.word(")");
|
||||
}
|
||||
hir::ExprKind::UnsafeBinderCast(kind, expr, ty) => {
|
||||
match kind {
|
||||
hir::UnsafeBinderCastKind::Wrap => self.word("wrap_binder!("),
|
||||
hir::UnsafeBinderCastKind::Unwrap => self.word("unwrap_binder!("),
|
||||
}
|
||||
self.print_expr(expr);
|
||||
if let Some(ty) = ty {
|
||||
self.word(",");
|
||||
self.space();
|
||||
self.print_type(ty);
|
||||
}
|
||||
self.word(")");
|
||||
}
|
||||
hir::ExprKind::Yield(expr, _) => {
|
||||
self.word_space("yield");
|
||||
self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Jump);
|
||||
|
|
|
|||
|
|
@ -72,12 +72,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
if self.try_structurally_resolve_type(expr.span, ty).is_never()
|
||||
&& self.expr_guaranteed_to_constitute_read_for_never(expr)
|
||||
{
|
||||
if let Some(_) = self.typeck_results.borrow().adjustments().get(expr.hir_id) {
|
||||
if let Some(adjustments) = self.typeck_results.borrow().adjustments().get(expr.hir_id) {
|
||||
let reported = self.dcx().span_delayed_bug(
|
||||
expr.span,
|
||||
"expression with never type wound up being adjusted",
|
||||
);
|
||||
return Ty::new_error(self.tcx(), reported);
|
||||
|
||||
return if let [Adjustment { kind: Adjust::NeverToAny, target }] = &adjustments[..] {
|
||||
target.to_owned()
|
||||
} else {
|
||||
Ty::new_error(self.tcx(), reported)
|
||||
};
|
||||
}
|
||||
|
||||
let adj_ty = self.next_ty_var(expr.span);
|
||||
|
|
@ -329,6 +334,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// Assignment does call `drop_in_place`, though, but its safety
|
||||
// requirements are not the same.
|
||||
ExprKind::AddrOf(..) | hir::ExprKind::Field(..) => false,
|
||||
|
||||
// Place-preserving expressions only constitute reads if their
|
||||
// parent expression constitutes a read.
|
||||
ExprKind::Type(..) | ExprKind::UnsafeBinderCast(..) => {
|
||||
self.expr_guaranteed_to_constitute_read_for_never(expr)
|
||||
}
|
||||
|
||||
ExprKind::Assign(lhs, _, _) => {
|
||||
// Only the LHS does not constitute a read
|
||||
expr.hir_id != lhs.hir_id
|
||||
|
|
@ -353,7 +365,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
| ExprKind::Binary(_, _, _)
|
||||
| ExprKind::Unary(_, _)
|
||||
| ExprKind::Cast(_, _)
|
||||
| ExprKind::Type(_, _)
|
||||
| ExprKind::DropTemps(_)
|
||||
| ExprKind::If(_, _, _)
|
||||
| ExprKind::Closure(_)
|
||||
|
|
@ -564,7 +575,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.check_expr_index(base, idx, expr, brackets_span)
|
||||
}
|
||||
ExprKind::Yield(value, _) => self.check_expr_yield(value, expr),
|
||||
hir::ExprKind::Err(guar) => Ty::new_error(tcx, guar),
|
||||
ExprKind::UnsafeBinderCast(kind, expr, ty) => {
|
||||
self.check_expr_unsafe_binder_cast(kind, expr, ty, expected)
|
||||
}
|
||||
ExprKind::Err(guar) => Ty::new_error(tcx, guar),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1634,6 +1648,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_expr_unsafe_binder_cast(
|
||||
&self,
|
||||
_kind: hir::UnsafeBinderCastKind,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
_hir_ty: Option<&'tcx hir::Ty<'tcx>>,
|
||||
_expected: Expectation<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
let guar =
|
||||
self.dcx().struct_span_err(expr.span, "unsafe binders are not yet implemented").emit();
|
||||
Ty::new_error(self.tcx, guar)
|
||||
}
|
||||
|
||||
fn check_expr_array(
|
||||
&self,
|
||||
args: &'tcx [hir::Expr<'tcx>],
|
||||
|
|
|
|||
|
|
@ -341,6 +341,10 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
self.walk_expr(subexpr)?;
|
||||
}
|
||||
|
||||
hir::ExprKind::UnsafeBinderCast(_, subexpr, _) => {
|
||||
self.walk_expr(subexpr)?;
|
||||
}
|
||||
|
||||
hir::ExprKind::Unary(hir::UnOp::Deref, base) => {
|
||||
// *base
|
||||
self.walk_expr(base)?;
|
||||
|
|
@ -1360,7 +1364,10 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
self.cat_res(expr.hir_id, expr.span, expr_ty, res)
|
||||
}
|
||||
|
||||
// both type ascription and unsafe binder casts don't affect
|
||||
// the place-ness of the subexpression.
|
||||
hir::ExprKind::Type(e, _) => self.cat_expr(e),
|
||||
hir::ExprKind::UnsafeBinderCast(_, e, _) => self.cat_expr(e),
|
||||
|
||||
hir::ExprKind::AddrOf(..)
|
||||
| hir::ExprKind::Call(..)
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@ use std::slice;
|
|||
use rustc_abi::FieldIdx;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorOf, DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{ExprKind, GenericArg, HirId, Node, QPath};
|
||||
use rustc_hir::{self as hir, ExprKind, GenericArg, HirId, Node, QPath, intravisit};
|
||||
use rustc_hir_analysis::hir_ty_lowering::errors::GenericsArgsErrExtend;
|
||||
use rustc_hir_analysis::hir_ty_lowering::generics::{
|
||||
check_generic_arg_count_for_call, lower_generic_args,
|
||||
|
|
@ -25,7 +25,7 @@ use rustc_middle::ty::fold::TypeFoldable;
|
|||
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
|
||||
use rustc_middle::ty::{
|
||||
self, AdtKind, CanonicalUserType, GenericArgKind, GenericArgsRef, GenericParamDefKind,
|
||||
IsIdentity, Ty, TyCtxt, UserArgs, UserSelfTy, UserType,
|
||||
IsIdentity, Ty, TyCtxt, UserArgs, UserSelfTy,
|
||||
};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_session::lint;
|
||||
|
|
@ -216,11 +216,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
debug!("fcx {}", self.tag());
|
||||
|
||||
if Self::can_contain_user_lifetime_bounds((args, user_self_ty)) {
|
||||
let canonicalized =
|
||||
self.canonicalize_user_type_annotation(UserType::TypeOf(def_id, UserArgs {
|
||||
args,
|
||||
user_self_ty,
|
||||
}));
|
||||
let canonicalized = self.canonicalize_user_type_annotation(ty::UserType::new(
|
||||
ty::UserTypeKind::TypeOf(def_id, UserArgs { args, user_self_ty }),
|
||||
));
|
||||
debug!(?canonicalized);
|
||||
self.write_user_type_annotation(hir_id, canonicalized);
|
||||
}
|
||||
|
|
@ -462,13 +460,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
LoweredTy::from_raw(self, hir_ty.span, ty)
|
||||
}
|
||||
|
||||
/// Walk a `hir_ty` and collect any clauses that may have come from a type
|
||||
/// within the `hir_ty`. These clauses will be canonicalized with a user type
|
||||
/// annotation so that we can enforce these bounds in borrowck, too.
|
||||
pub(crate) fn collect_impl_trait_clauses_from_hir_ty(
|
||||
&self,
|
||||
hir_ty: &'tcx hir::Ty<'tcx>,
|
||||
) -> ty::Clauses<'tcx> {
|
||||
struct CollectClauses<'a, 'tcx> {
|
||||
clauses: Vec<ty::Clause<'tcx>>,
|
||||
fcx: &'a FnCtxt<'a, 'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> intravisit::Visitor<'tcx> for CollectClauses<'_, 'tcx> {
|
||||
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
|
||||
if let Some(clauses) = self.fcx.trait_ascriptions.borrow().get(&ty.hir_id.local_id)
|
||||
{
|
||||
self.clauses.extend(clauses.iter().cloned());
|
||||
}
|
||||
intravisit::walk_ty(self, ty)
|
||||
}
|
||||
}
|
||||
|
||||
let mut clauses = CollectClauses { clauses: vec![], fcx: self };
|
||||
clauses.visit_ty(hir_ty);
|
||||
self.tcx.mk_clauses(&clauses.clauses)
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
pub(crate) fn lower_ty_saving_user_provided_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
|
||||
pub(crate) fn lower_ty_saving_user_provided_ty(&self, hir_ty: &'tcx hir::Ty<'tcx>) -> Ty<'tcx> {
|
||||
let ty = self.lower_ty(hir_ty);
|
||||
debug!(?ty);
|
||||
|
||||
if Self::can_contain_user_lifetime_bounds(ty.raw) {
|
||||
let c_ty = self.canonicalize_response(UserType::Ty(ty.raw));
|
||||
let c_ty = self.canonicalize_response(ty::UserType::new(ty::UserTypeKind::Ty(ty.raw)));
|
||||
debug!(?c_ty);
|
||||
self.typeck_results.borrow_mut().user_provided_types_mut().insert(hir_ty.hir_id, c_ty);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,10 +10,11 @@ use std::ops::Deref;
|
|||
|
||||
use hir::def_id::CRATE_DEF_ID;
|
||||
use rustc_errors::DiagCtxtHandle;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::{self as hir, HirId, ItemLocalMap};
|
||||
use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, RegionInferReason};
|
||||
use rustc_infer::infer;
|
||||
use rustc_infer::traits::Obligation;
|
||||
use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::Ident;
|
||||
|
|
@ -114,6 +115,12 @@ pub(crate) struct FnCtxt<'a, 'tcx> {
|
|||
|
||||
pub(super) diverging_fallback_behavior: DivergingFallbackBehavior,
|
||||
pub(super) diverging_block_behavior: DivergingBlockBehavior,
|
||||
|
||||
/// Clauses that we lowered as part of the `impl_trait_in_bindings` feature.
|
||||
///
|
||||
/// These are stored here so we may collect them when canonicalizing user
|
||||
/// type ascriptions later.
|
||||
pub(super) trait_ascriptions: RefCell<ItemLocalMap<Vec<ty::Clause<'tcx>>>>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
|
@ -141,6 +148,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
fallback_has_occurred: Cell::new(false),
|
||||
diverging_fallback_behavior,
|
||||
diverging_block_behavior,
|
||||
trait_ascriptions: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -252,6 +260,30 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn register_trait_ascription_bounds(
|
||||
&self,
|
||||
bounds: Vec<(ty::Clause<'tcx>, Span)>,
|
||||
hir_id: HirId,
|
||||
_span: Span,
|
||||
) {
|
||||
for (clause, span) in bounds {
|
||||
if clause.has_escaping_bound_vars() {
|
||||
self.dcx().span_delayed_bug(span, "clause should have no escaping bound vars");
|
||||
continue;
|
||||
}
|
||||
|
||||
self.trait_ascriptions.borrow_mut().entry(hir_id.local_id).or_default().push(clause);
|
||||
|
||||
let clause = self.normalize(span, clause);
|
||||
self.register_predicate(Obligation::new(
|
||||
self.tcx,
|
||||
self.misc(span),
|
||||
self.param_env,
|
||||
clause,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
fn probe_ty_param_bounds(
|
||||
&self,
|
||||
_: Span,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
|
|||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{
|
||||
Arm, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, GenericBound, HirId,
|
||||
Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicateKind,
|
||||
Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicateKind, expr_needs_parens,
|
||||
};
|
||||
use rustc_hir_analysis::collect::suggest_impl_trait;
|
||||
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
|
||||
|
|
@ -35,7 +35,6 @@ use tracing::{debug, instrument};
|
|||
|
||||
use super::FnCtxt;
|
||||
use crate::fn_ctxt::rustc_span::BytePos;
|
||||
use crate::hir::is_range_literal;
|
||||
use crate::method::probe;
|
||||
use crate::method::probe::{IsSuggestion, Mode, ProbeScope};
|
||||
use crate::{errors, fluent_generated as fluent};
|
||||
|
|
@ -2648,7 +2647,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
let make_sugg = |expr: &Expr<'_>, span: Span, sugg: &str| {
|
||||
if self.needs_parentheses(expr) {
|
||||
if expr_needs_parens(expr) {
|
||||
(
|
||||
vec![
|
||||
(span.shrink_to_lo(), format!("{prefix}{sugg}(")),
|
||||
|
|
@ -2861,7 +2860,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
return None;
|
||||
}
|
||||
|
||||
if self.needs_parentheses(expr) {
|
||||
if expr_needs_parens(expr) {
|
||||
return Some((
|
||||
vec![
|
||||
(span, format!("{suggestion}(")),
|
||||
|
|
@ -2902,16 +2901,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
false
|
||||
}
|
||||
|
||||
fn needs_parentheses(&self, expr: &hir::Expr<'_>) -> bool {
|
||||
match expr.kind {
|
||||
// parenthesize if needed (Issue #46756)
|
||||
hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true,
|
||||
// parenthesize borrows of range literals (Issue #54505)
|
||||
_ if is_range_literal(expr) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn suggest_cast(
|
||||
&self,
|
||||
err: &mut Diag<'_>,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use rustc_hir as hir;
|
|||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::{HirId, PatKind};
|
||||
use rustc_infer::traits::ObligationCauseCode;
|
||||
use rustc_middle::ty::{Ty, UserType};
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use tracing::debug;
|
||||
|
|
@ -92,7 +92,12 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
|
|||
Some(ref ty) => {
|
||||
let o_ty = self.fcx.lower_ty(ty);
|
||||
|
||||
let c_ty = self.fcx.infcx.canonicalize_user_type_annotation(UserType::Ty(o_ty.raw));
|
||||
let c_ty = self.fcx.infcx.canonicalize_user_type_annotation(
|
||||
ty::UserType::new_with_bounds(
|
||||
ty::UserTypeKind::Ty(o_ty.raw),
|
||||
self.fcx.collect_impl_trait_clauses_from_hir_ty(ty),
|
||||
),
|
||||
);
|
||||
debug!("visit_local: ty.hir_id={:?} o_ty={:?} c_ty={:?}", ty.hir_id, o_ty, c_ty);
|
||||
self.fcx
|
||||
.typeck_results
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ use rustc_middle::ty::adjustment::{
|
|||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::{
|
||||
self, GenericArgs, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, UserArgs,
|
||||
UserType,
|
||||
};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::{DUMMY_SP, Span};
|
||||
|
|
@ -491,9 +490,8 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
|||
user_self_ty: None, // not relevant here
|
||||
};
|
||||
|
||||
self.fcx.canonicalize_user_type_annotation(UserType::TypeOf(
|
||||
pick.item.def_id,
|
||||
user_args,
|
||||
self.fcx.canonicalize_user_type_annotation(ty::UserType::new(
|
||||
ty::UserTypeKind::TypeOf(pick.item.def_id, user_args),
|
||||
))
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -10,8 +10,12 @@ use rustc_errors::{
|
|||
};
|
||||
use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||
use rustc_hir::pat_util::EnumerateAndAdjustIterator;
|
||||
use rustc_hir::{self as hir, BindingMode, ByRef, HirId, LangItem, Mutability, Pat, PatKind};
|
||||
use rustc_hir::{
|
||||
self as hir, BindingMode, ByRef, ExprKind, HirId, LangItem, Mutability, Pat, PatKind,
|
||||
expr_needs_parens,
|
||||
};
|
||||
use rustc_infer::infer;
|
||||
use rustc_middle::traits::PatternOriginExpr;
|
||||
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
|
||||
|
|
@ -94,10 +98,32 @@ struct PatInfo<'a, 'tcx> {
|
|||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
fn pattern_cause(&self, ti: &TopInfo<'tcx>, cause_span: Span) -> ObligationCause<'tcx> {
|
||||
// If origin_expr exists, then expected represents the type of origin_expr.
|
||||
// If span also exists, then span == origin_expr.span (although it doesn't need to exist).
|
||||
// In that case, we can peel away references from both and treat them
|
||||
// as the same.
|
||||
let origin_expr_info = ti.origin_expr.map(|mut cur_expr| {
|
||||
let mut count = 0;
|
||||
|
||||
// cur_ty may have more layers of references than cur_expr.
|
||||
// We can only make suggestions about cur_expr, however, so we'll
|
||||
// use that as our condition for stopping.
|
||||
while let ExprKind::AddrOf(.., inner) = &cur_expr.kind {
|
||||
cur_expr = inner;
|
||||
count += 1;
|
||||
}
|
||||
|
||||
PatternOriginExpr {
|
||||
peeled_span: cur_expr.span,
|
||||
peeled_count: count,
|
||||
peeled_prefix_suggestion_parentheses: expr_needs_parens(cur_expr),
|
||||
}
|
||||
});
|
||||
|
||||
let code = ObligationCauseCode::Pattern {
|
||||
span: ti.span,
|
||||
root_ty: ti.expected,
|
||||
origin_expr: ti.origin_expr.is_some(),
|
||||
origin_expr: origin_expr_info,
|
||||
};
|
||||
self.cause(cause_span, code)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -476,7 +476,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
for (local_id, c_ty) in sorted_user_provided_types {
|
||||
let hir_id = HirId { owner: common_hir_owner, local_id };
|
||||
|
||||
if let ty::UserType::TypeOf(_, user_args) = c_ty.value {
|
||||
if let ty::UserTypeKind::TypeOf(_, user_args) = c_ty.value.kind {
|
||||
// This is a unit-testing mechanism.
|
||||
let span = self.tcx().hir().span(hir_id);
|
||||
// We need to buffer the errors in order to guarantee a consistent
|
||||
|
|
|
|||
|
|
@ -371,7 +371,6 @@ pub(crate) fn initialize_checked_jobserver(early_dcx: &EarlyDiagCtxt) {
|
|||
|
||||
// JUSTIFICATION: before session exists, only config
|
||||
#[allow(rustc::bad_opt_access)]
|
||||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R {
|
||||
trace!("run_compiler");
|
||||
|
||||
|
|
@ -425,7 +424,11 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
|
|||
config.opts.unstable_opts.translate_directionality_markers,
|
||||
) {
|
||||
Ok(bundle) => bundle,
|
||||
Err(e) => early_dcx.early_fatal(format!("failed to load fluent bundle: {e}")),
|
||||
Err(e) => {
|
||||
// We can't translate anything if we failed to load translations
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
early_dcx.early_fatal(format!("failed to load fluent bundle: {e}"))
|
||||
}
|
||||
};
|
||||
|
||||
let mut locale_resources = config.locale_resources;
|
||||
|
|
@ -479,7 +482,6 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
|
|||
let mut lint_store = rustc_lint::new_lint_store(sess.enable_internal_lints());
|
||||
if let Some(register_lints) = config.register_lints.as_deref() {
|
||||
register_lints(&sess, &mut lint_store);
|
||||
sess.registered_lints = true;
|
||||
}
|
||||
sess.lint_store = Some(Lrc::new(lint_store));
|
||||
|
||||
|
|
|
|||
|
|
@ -1125,6 +1125,18 @@ pub(crate) fn start_codegen<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
// This must run after monomorphization so that all generic types
|
||||
// have been instantiated.
|
||||
if tcx.sess.opts.unstable_opts.print_type_sizes {
|
||||
tcx.sess.code_stats.print_type_sizes();
|
||||
}
|
||||
|
||||
if tcx.sess.opts.unstable_opts.print_vtable_sizes {
|
||||
let crate_name = tcx.crate_name(LOCAL_CRATE);
|
||||
|
||||
tcx.sess.code_stats.print_vtable_sizes(crate_name);
|
||||
}
|
||||
|
||||
codegen
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -127,18 +127,6 @@ impl Linker {
|
|||
) -> Linker {
|
||||
let ongoing_codegen = passes::start_codegen(codegen_backend, tcx);
|
||||
|
||||
// This must run after monomorphization so that all generic types
|
||||
// have been instantiated.
|
||||
if tcx.sess.opts.unstable_opts.print_type_sizes {
|
||||
tcx.sess.code_stats.print_type_sizes();
|
||||
}
|
||||
|
||||
if tcx.sess.opts.unstable_opts.print_vtable_sizes {
|
||||
let crate_name = tcx.crate_name(LOCAL_CRATE);
|
||||
|
||||
tcx.sess.code_stats.print_vtable_sizes(crate_name);
|
||||
}
|
||||
|
||||
Linker {
|
||||
dep_graph: tcx.dep_graph.clone(),
|
||||
output_filenames: Arc::clone(tcx.output_filenames(())),
|
||||
|
|
|
|||
|
|
@ -35,10 +35,10 @@ pub type MakeBackendFn = fn() -> Box<dyn CodegenBackend>;
|
|||
pub fn add_configuration(cfg: &mut Cfg, sess: &mut Session, codegen_backend: &dyn CodegenBackend) {
|
||||
let tf = sym::target_feature;
|
||||
|
||||
let unstable_target_features = codegen_backend.target_features(sess, true);
|
||||
let unstable_target_features = codegen_backend.target_features_cfg(sess, true);
|
||||
sess.unstable_target_features.extend(unstable_target_features.iter().cloned());
|
||||
|
||||
let target_features = codegen_backend.target_features(sess, false);
|
||||
let target_features = codegen_backend.target_features_cfg(sess, false);
|
||||
sess.target_features.extend(target_features.iter().cloned());
|
||||
|
||||
cfg.extend(target_features.into_iter().map(|feat| (tf, Some(feat))));
|
||||
|
|
|
|||
|
|
@ -806,10 +806,14 @@ lint_unexpected_cfg_add_build_rs_println = or consider adding `{$build_rs_printl
|
|||
lint_unexpected_cfg_add_cargo_feature = consider using a Cargo feature instead
|
||||
lint_unexpected_cfg_add_cargo_toml_lint_cfg = or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:{$cargo_toml_lint_cfg}
|
||||
lint_unexpected_cfg_add_cmdline_arg = to expect this configuration use `{$cmdline_arg}`
|
||||
lint_unexpected_cfg_cargo_update = the {$macro_kind} `{$macro_name}` may come from an old version of it's defining crate, try updating your dependencies with `cargo update`
|
||||
|
||||
lint_unexpected_cfg_define_features = consider defining some features in `Cargo.toml`
|
||||
lint_unexpected_cfg_doc_cargo = see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
|
||||
lint_unexpected_cfg_doc_rustc = see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
|
||||
|
||||
lint_unexpected_cfg_from_external_macro_origin = using a cfg inside a {$macro_kind} will use the cfgs from the destination crate and not the ones from the defining crate
|
||||
lint_unexpected_cfg_from_external_macro_refer = try refering to `{$macro_name}` crate for guidance on how handle this unexpected cfg
|
||||
lint_unexpected_cfg_name = unexpected `cfg` condition name: `{$name}`
|
||||
lint_unexpected_cfg_name_expected_names = expected names are: {$possibilities}{$and_more ->
|
||||
[0] {""}
|
||||
|
|
|
|||
|
|
@ -3038,7 +3038,7 @@ impl EarlyLintPass for SpecialModuleName {
|
|||
for item in &krate.items {
|
||||
if let ast::ItemKind::Mod(
|
||||
_,
|
||||
ast::ModKind::Unloaded | ast::ModKind::Loaded(_, ast::Inline::No, _),
|
||||
ast::ModKind::Unloaded | ast::ModKind::Loaded(_, ast::Inline::No, _, _),
|
||||
) = item.kind
|
||||
{
|
||||
if item.attrs.iter().any(|a| a.has_name(sym::path)) {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
use rustc_hir::def_id::LOCAL_CRATE;
|
||||
use rustc_middle::bug;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::ExpectedValues;
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
use rustc_span::{ExpnKind, Span, Symbol, sym};
|
||||
|
||||
use crate::lints;
|
||||
|
||||
|
|
@ -60,6 +61,35 @@ fn cargo_help_sub(
|
|||
}
|
||||
}
|
||||
|
||||
fn rustc_macro_help(span: Span) -> Option<lints::UnexpectedCfgRustcMacroHelp> {
|
||||
let oexpn = span.ctxt().outer_expn_data();
|
||||
if let Some(def_id) = oexpn.macro_def_id
|
||||
&& let ExpnKind::Macro(macro_kind, macro_name) = oexpn.kind
|
||||
&& def_id.krate != LOCAL_CRATE
|
||||
{
|
||||
Some(lints::UnexpectedCfgRustcMacroHelp { macro_kind: macro_kind.descr(), macro_name })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn cargo_macro_help(span: Span) -> Option<lints::UnexpectedCfgCargoMacroHelp> {
|
||||
let oexpn = span.ctxt().outer_expn_data();
|
||||
if let Some(def_id) = oexpn.macro_def_id
|
||||
&& let ExpnKind::Macro(macro_kind, macro_name) = oexpn.kind
|
||||
&& def_id.krate != LOCAL_CRATE
|
||||
{
|
||||
Some(lints::UnexpectedCfgCargoMacroHelp {
|
||||
macro_kind: macro_kind.descr(),
|
||||
macro_name,
|
||||
// FIXME: Get access to a `TyCtxt` from an `EarlyContext`
|
||||
// crate_name: cx.tcx.crate_name(def_id.krate),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn unexpected_cfg_name(
|
||||
sess: &Session,
|
||||
(name, name_span): (Symbol, Span),
|
||||
|
|
@ -85,6 +115,7 @@ pub(super) fn unexpected_cfg_name(
|
|||
};
|
||||
|
||||
let is_from_cargo = rustc_session::utils::was_invoked_from_cargo();
|
||||
let is_from_external_macro = rustc_middle::lint::in_external_macro(sess, name_span);
|
||||
let mut is_feature_cfg = name == sym::feature;
|
||||
|
||||
let code_sugg = if is_feature_cfg && is_from_cargo {
|
||||
|
|
@ -185,12 +216,21 @@ pub(super) fn unexpected_cfg_name(
|
|||
};
|
||||
|
||||
let invocation_help = if is_from_cargo {
|
||||
let sub = if !is_feature_cfg { Some(cargo_help_sub(sess, &inst)) } else { None };
|
||||
lints::unexpected_cfg_name::InvocationHelp::Cargo { sub }
|
||||
let help = if !is_feature_cfg && !is_from_external_macro {
|
||||
Some(cargo_help_sub(sess, &inst))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
lints::unexpected_cfg_name::InvocationHelp::Cargo {
|
||||
help,
|
||||
macro_help: cargo_macro_help(name_span),
|
||||
}
|
||||
} else {
|
||||
lints::unexpected_cfg_name::InvocationHelp::Rustc(lints::UnexpectedCfgRustcHelp::new(
|
||||
&inst(EscapeQuotes::No),
|
||||
))
|
||||
let help = lints::UnexpectedCfgRustcHelp::new(&inst(EscapeQuotes::No));
|
||||
lints::unexpected_cfg_name::InvocationHelp::Rustc {
|
||||
help,
|
||||
macro_help: rustc_macro_help(name_span),
|
||||
}
|
||||
};
|
||||
|
||||
lints::UnexpectedCfgName { code_sugg, invocation_help, name }
|
||||
|
|
@ -216,7 +256,9 @@ pub(super) fn unexpected_cfg_value(
|
|||
.copied()
|
||||
.flatten()
|
||||
.collect();
|
||||
|
||||
let is_from_cargo = rustc_session::utils::was_invoked_from_cargo();
|
||||
let is_from_external_macro = rustc_middle::lint::in_external_macro(sess, name_span);
|
||||
|
||||
// Show the full list if all possible values for a given name, but don't do it
|
||||
// for names as the possibilities could be very long
|
||||
|
|
@ -284,25 +326,31 @@ pub(super) fn unexpected_cfg_value(
|
|||
};
|
||||
|
||||
let invocation_help = if is_from_cargo {
|
||||
let help = if name == sym::feature {
|
||||
let help = if name == sym::feature && !is_from_external_macro {
|
||||
if let Some((value, _value_span)) = value {
|
||||
Some(lints::unexpected_cfg_value::CargoHelp::AddFeature { value })
|
||||
} else {
|
||||
Some(lints::unexpected_cfg_value::CargoHelp::DefineFeatures)
|
||||
}
|
||||
} else if can_suggest_adding_value {
|
||||
} else if can_suggest_adding_value && !is_from_external_macro {
|
||||
Some(lints::unexpected_cfg_value::CargoHelp::Other(cargo_help_sub(sess, &inst)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
lints::unexpected_cfg_value::InvocationHelp::Cargo(help)
|
||||
lints::unexpected_cfg_value::InvocationHelp::Cargo {
|
||||
help,
|
||||
macro_help: cargo_macro_help(name_span),
|
||||
}
|
||||
} else {
|
||||
let help = if can_suggest_adding_value {
|
||||
Some(lints::UnexpectedCfgRustcHelp::new(&inst(EscapeQuotes::No)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
lints::unexpected_cfg_value::InvocationHelp::Rustc(help)
|
||||
lints::unexpected_cfg_value::InvocationHelp::Rustc {
|
||||
help,
|
||||
macro_help: rustc_macro_help(name_span),
|
||||
}
|
||||
};
|
||||
|
||||
lints::UnexpectedCfgValue {
|
||||
|
|
|
|||
|
|
@ -192,6 +192,8 @@ fn is_temporary_rvalue(expr: &Expr<'_>) -> bool {
|
|||
| ExprKind::DropTemps(..)
|
||||
| ExprKind::Let(..) => false,
|
||||
|
||||
ExprKind::UnsafeBinderCast(..) => false,
|
||||
|
||||
// Not applicable
|
||||
ExprKind::Type(..) | ExprKind::Err(..) => false,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -422,6 +422,7 @@ impl<'tcx, 'a> Visitor<'tcx> for FindSignificantDropper<'tcx, 'a> {
|
|||
hir::ExprKind::Unary(_, expr)
|
||||
| hir::ExprKind::Cast(expr, _)
|
||||
| hir::ExprKind::Type(expr, _)
|
||||
| hir::ExprKind::UnsafeBinderCast(_, expr, _)
|
||||
| hir::ExprKind::Yield(expr, _)
|
||||
| hir::ExprKind::AddrOf(_, _, expr)
|
||||
| hir::ExprKind::Match(expr, _, _)
|
||||
|
|
|
|||
|
|
@ -2172,6 +2172,25 @@ impl UnexpectedCfgRustcHelp {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(lint_unexpected_cfg_from_external_macro_origin)]
|
||||
#[help(lint_unexpected_cfg_from_external_macro_refer)]
|
||||
pub(crate) struct UnexpectedCfgRustcMacroHelp {
|
||||
pub macro_kind: &'static str,
|
||||
pub macro_name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(lint_unexpected_cfg_from_external_macro_origin)]
|
||||
#[help(lint_unexpected_cfg_from_external_macro_refer)]
|
||||
#[help(lint_unexpected_cfg_cargo_update)]
|
||||
pub(crate) struct UnexpectedCfgCargoMacroHelp {
|
||||
pub macro_kind: &'static str,
|
||||
pub macro_name: Symbol,
|
||||
// FIXME: Figure out a way to get the crate name
|
||||
// crate_name: String,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unexpected_cfg_name)]
|
||||
pub(crate) struct UnexpectedCfgName {
|
||||
|
|
@ -2276,10 +2295,17 @@ pub(crate) mod unexpected_cfg_name {
|
|||
#[note(lint_unexpected_cfg_doc_cargo)]
|
||||
Cargo {
|
||||
#[subdiagnostic]
|
||||
sub: Option<super::UnexpectedCfgCargoHelp>,
|
||||
macro_help: Option<super::UnexpectedCfgCargoMacroHelp>,
|
||||
#[subdiagnostic]
|
||||
help: Option<super::UnexpectedCfgCargoHelp>,
|
||||
},
|
||||
#[note(lint_unexpected_cfg_doc_rustc)]
|
||||
Rustc(#[subdiagnostic] super::UnexpectedCfgRustcHelp),
|
||||
Rustc {
|
||||
#[subdiagnostic]
|
||||
macro_help: Option<super::UnexpectedCfgRustcMacroHelp>,
|
||||
#[subdiagnostic]
|
||||
help: super::UnexpectedCfgRustcHelp,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2382,9 +2408,19 @@ pub(crate) mod unexpected_cfg_value {
|
|||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum InvocationHelp {
|
||||
#[note(lint_unexpected_cfg_doc_cargo)]
|
||||
Cargo(#[subdiagnostic] Option<CargoHelp>),
|
||||
Cargo {
|
||||
#[subdiagnostic]
|
||||
help: Option<CargoHelp>,
|
||||
#[subdiagnostic]
|
||||
macro_help: Option<super::UnexpectedCfgCargoMacroHelp>,
|
||||
},
|
||||
#[note(lint_unexpected_cfg_doc_rustc)]
|
||||
Rustc(#[subdiagnostic] Option<super::UnexpectedCfgRustcHelp>),
|
||||
Rustc {
|
||||
#[subdiagnostic]
|
||||
help: Option<super::UnexpectedCfgRustcHelp>,
|
||||
#[subdiagnostic]
|
||||
macro_help: Option<super::UnexpectedCfgRustcMacroHelp>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ pub(crate) fn calculate(tcx: TyCtxt<'_>) -> Dependencies {
|
|||
verify_ok(tcx, &linkage);
|
||||
(ty, linkage)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
|
||||
|
|
|
|||
|
|
@ -1264,12 +1264,7 @@ fn should_encode_fn_sig(def_kind: DefKind) -> bool {
|
|||
|
||||
fn should_encode_constness(def_kind: DefKind) -> bool {
|
||||
match def_kind {
|
||||
DefKind::Fn
|
||||
| DefKind::AssocFn
|
||||
| DefKind::Closure
|
||||
| DefKind::Impl { of_trait: true }
|
||||
| DefKind::Variant
|
||||
| DefKind::Ctor(..) => true,
|
||||
DefKind::Fn | DefKind::AssocFn | DefKind::Closure | DefKind::Ctor(_, CtorKind::Fn) => true,
|
||||
|
||||
DefKind::Struct
|
||||
| DefKind::Union
|
||||
|
|
@ -1281,7 +1276,7 @@ fn should_encode_constness(def_kind: DefKind) -> bool {
|
|||
| DefKind::Static { .. }
|
||||
| DefKind::TyAlias
|
||||
| DefKind::OpaqueTy
|
||||
| DefKind::Impl { of_trait: false }
|
||||
| DefKind::Impl { .. }
|
||||
| DefKind::ForeignTy
|
||||
| DefKind::ConstParam
|
||||
| DefKind::InlineConst
|
||||
|
|
@ -1296,6 +1291,8 @@ fn should_encode_constness(def_kind: DefKind) -> bool {
|
|||
| DefKind::LifetimeParam
|
||||
| DefKind::GlobalAsm
|
||||
| DefKind::ExternCrate
|
||||
| DefKind::Ctor(_, CtorKind::Const)
|
||||
| DefKind::Variant
|
||||
| DefKind::SyntheticCoroutineBody => false,
|
||||
}
|
||||
}
|
||||
|
|
@ -2164,10 +2161,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
fn encode_dylib_dependency_formats(&mut self) -> LazyArray<Option<LinkagePreference>> {
|
||||
empty_proc_macro!(self);
|
||||
let formats = self.tcx.dependency_formats(());
|
||||
for (ty, arr) in formats.iter() {
|
||||
if *ty != CrateType::Dylib {
|
||||
continue;
|
||||
}
|
||||
if let Some(arr) = formats.get(&CrateType::Dylib) {
|
||||
return self.lazy_array(arr.iter().map(|slot| match *slot {
|
||||
Linkage::NotLinked | Linkage::IncludedFromDylib => None,
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
// FIXME: move this file to rustc_metadata::dependency_format, but
|
||||
// this will introduce circular dependency between rustc_metadata and rustc_middle
|
||||
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_macros::{Decodable, Encodable, HashStable};
|
||||
use rustc_session::config::CrateType;
|
||||
|
||||
|
|
@ -18,7 +19,7 @@ pub type DependencyList = Vec<Linkage>;
|
|||
/// A mapping of all required dependencies for a particular flavor of output.
|
||||
///
|
||||
/// This is local to the tcx, and is generally relevant to one session.
|
||||
pub type Dependencies = Vec<(CrateType, DependencyList)>;
|
||||
pub type Dependencies = FxIndexMap<CrateType, DependencyList>;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug, HashStable, Encodable, Decodable)]
|
||||
pub enum Linkage {
|
||||
|
|
|
|||
|
|
@ -467,6 +467,9 @@ impl<'tcx> Const<'tcx> {
|
|||
let const_val = tcx.valtree_to_const_val((ty, valtree));
|
||||
Self::Val(const_val, ty)
|
||||
}
|
||||
ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args }) => {
|
||||
Self::Unevaluated(UnevaluatedConst { def, args, promoted: None }, ty)
|
||||
}
|
||||
_ => Self::Ty(ty, c),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -294,10 +294,22 @@ pub enum Linkage {
|
|||
Common,
|
||||
}
|
||||
|
||||
/// Specifies the symbol visibility with regards to dynamic linking.
|
||||
///
|
||||
/// Visibility doesn't have any effect when linkage is internal.
|
||||
///
|
||||
/// DSO means dynamic shared object, that is a dynamically linked executable or dylib.
|
||||
#[derive(Copy, Clone, PartialEq, Debug, HashStable)]
|
||||
pub enum Visibility {
|
||||
/// Export the symbol from the DSO and apply overrides of the symbol by outside DSOs to within
|
||||
/// the DSO if the object file format supports this.
|
||||
Default,
|
||||
/// Hide the symbol outside of the defining DSO even when external linkage is used to export it
|
||||
/// from the object file.
|
||||
Hidden,
|
||||
/// Export the symbol from the DSO, but don't apply overrides of the symbol by outside DSOs to
|
||||
/// within the DSO. Equivalent to default visibility with object file formats that don't support
|
||||
/// overriding exported symbols by another DSO.
|
||||
Protected,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,8 @@ pub trait Key: Sized {
|
|||
None
|
||||
}
|
||||
|
||||
fn ty_def_id(&self) -> Option<DefId> {
|
||||
/// Used to detect when ADT def ids are used as keys in a cycle for better error reporting.
|
||||
fn def_id_for_ty_in_cycle(&self) -> Option<DefId> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
@ -423,7 +424,7 @@ impl<'tcx> Key for Ty<'tcx> {
|
|||
DUMMY_SP
|
||||
}
|
||||
|
||||
fn ty_def_id(&self) -> Option<DefId> {
|
||||
fn def_id_for_ty_in_cycle(&self) -> Option<DefId> {
|
||||
match *self.kind() {
|
||||
ty::Adt(adt, _) => Some(adt.did()),
|
||||
ty::Coroutine(def_id, ..) => Some(def_id),
|
||||
|
|
@ -471,8 +472,8 @@ impl<'tcx, T: Key> Key for ty::PseudoCanonicalInput<'tcx, T> {
|
|||
self.value.default_span(tcx)
|
||||
}
|
||||
|
||||
fn ty_def_id(&self) -> Option<DefId> {
|
||||
self.value.ty_def_id()
|
||||
fn def_id_for_ty_in_cycle(&self) -> Option<DefId> {
|
||||
self.value.def_id_for_ty_in_cycle()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -593,7 +594,7 @@ impl<'tcx> Key for (ValidityRequirement, ty::PseudoCanonicalInput<'tcx, Ty<'tcx>
|
|||
DUMMY_SP
|
||||
}
|
||||
|
||||
fn ty_def_id(&self) -> Option<DefId> {
|
||||
fn def_id_for_ty_in_cycle(&self) -> Option<DefId> {
|
||||
match self.1.value.kind() {
|
||||
ty::Adt(adt, _) => Some(adt.did()),
|
||||
_ => None,
|
||||
|
|
|
|||
|
|
@ -746,7 +746,10 @@ rustc_queries! {
|
|||
desc { |tcx| "computing drop-check constraints for `{}`", tcx.def_path_str(key) }
|
||||
}
|
||||
|
||||
/// Returns `true` if this is a const fn / const impl.
|
||||
/// Returns the constness of function-like things (tuple struct/variant constructors, functions,
|
||||
/// methods)
|
||||
///
|
||||
/// Will ICE if used on things that are always const or never const.
|
||||
///
|
||||
/// **Do not call this function manually.** It is only meant to cache the base data for the
|
||||
/// higher-level functions. Consider using `is_const_fn` or `is_const_trait_impl` instead.
|
||||
|
|
@ -2230,7 +2233,7 @@ rustc_queries! {
|
|||
}
|
||||
|
||||
/// Returns the Rust target features for the current target. These are not always the same as LLVM target features!
|
||||
query rust_target_features(_: CrateNum) -> &'tcx UnordMap<String, rustc_target::target_features::Stability> {
|
||||
query rust_target_features(_: CrateNum) -> &'tcx UnordMap<String, rustc_target::target_features::StabilityComputed> {
|
||||
arena_cache
|
||||
eval_always
|
||||
desc { "looking up Rust target features" }
|
||||
|
|
|
|||
|
|
@ -44,16 +44,16 @@ pub struct DynamicQuery<'tcx, C: QueryCache> {
|
|||
pub format_value: fn(&C::Value) -> String,
|
||||
}
|
||||
|
||||
pub struct QuerySystemFns<'tcx> {
|
||||
pub struct QuerySystemFns {
|
||||
pub engine: QueryEngine,
|
||||
pub local_providers: Providers,
|
||||
pub extern_providers: ExternProviders,
|
||||
pub encode_query_results: fn(
|
||||
pub encode_query_results: for<'tcx> fn(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
encoder: &mut CacheEncoder<'_, 'tcx>,
|
||||
query_result_index: &mut EncodedDepNodeIndex,
|
||||
),
|
||||
pub try_mark_green: fn(tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool,
|
||||
pub try_mark_green: for<'tcx> fn(tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool,
|
||||
}
|
||||
|
||||
pub struct QuerySystem<'tcx> {
|
||||
|
|
@ -68,7 +68,7 @@ pub struct QuerySystem<'tcx> {
|
|||
/// This is `None` if we are not incremental compilation mode
|
||||
pub on_disk_cache: Option<OnDiskCache>,
|
||||
|
||||
pub fns: QuerySystemFns<'tcx>,
|
||||
pub fns: QuerySystemFns,
|
||||
|
||||
pub jobs: AtomicU64,
|
||||
}
|
||||
|
|
@ -323,7 +323,7 @@ macro_rules! define_callbacks {
|
|||
// Increase this limit if necessary, but do try to keep the size low if possible
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
const _: () = {
|
||||
if mem::size_of::<Key<'static>>() > 80 {
|
||||
if mem::size_of::<Key<'static>>() > 88 {
|
||||
panic!("{}", concat!(
|
||||
"the query `",
|
||||
stringify!($name),
|
||||
|
|
|
|||
|
|
@ -316,8 +316,8 @@ pub enum ObligationCauseCode<'tcx> {
|
|||
span: Option<Span>,
|
||||
/// The root expected type induced by a scrutinee or type expression.
|
||||
root_ty: Ty<'tcx>,
|
||||
/// Whether the `Span` came from an expression or a type expression.
|
||||
origin_expr: bool,
|
||||
/// Information about the `Span`, if it came from an expression, otherwise `None`.
|
||||
origin_expr: Option<PatternOriginExpr>,
|
||||
},
|
||||
|
||||
/// Computing common supertype in an if expression
|
||||
|
|
@ -530,6 +530,25 @@ pub struct MatchExpressionArmCause<'tcx> {
|
|||
pub tail_defines_return_position_impl_trait: Option<LocalDefId>,
|
||||
}
|
||||
|
||||
/// Information about the origin expression of a pattern, relevant to diagnostics.
|
||||
/// Fields here refer to the scrutinee of a pattern.
|
||||
/// If the scrutinee isn't given in the diagnostic, then this won't exist.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
#[derive(TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)]
|
||||
pub struct PatternOriginExpr {
|
||||
/// A span representing the scrutinee expression, with all leading references
|
||||
/// peeled from the expression.
|
||||
/// Only references in the expression are peeled - if the expression refers to a variable
|
||||
/// whose type is a reference, then that reference is kept because it wasn't created
|
||||
/// in the expression.
|
||||
pub peeled_span: Span,
|
||||
/// The number of references that were peeled to produce `peeled_span`.
|
||||
pub peeled_count: usize,
|
||||
/// Does the peeled expression need to be wrapped in parentheses for
|
||||
/// a prefix suggestion (i.e., dereference) to be valid.
|
||||
pub peeled_prefix_suggestion_parentheses: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
#[derive(TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)]
|
||||
pub struct IfExpressionCause<'tcx> {
|
||||
|
|
|
|||
|
|
@ -3141,7 +3141,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
/// Whether the trait impl is marked const. This does not consider stability or feature gates.
|
||||
pub fn is_const_trait_impl(self, def_id: DefId) -> bool {
|
||||
self.def_kind(def_id) == DefKind::Impl { of_trait: true }
|
||||
&& self.constness(def_id) == hir::Constness::Const
|
||||
&& self.impl_trait_header(def_id).unwrap().constness == hir::Constness::Const
|
||||
}
|
||||
|
||||
pub fn intrinsic(self, def_id: impl IntoQueryParam<DefId> + Copy) -> Option<ty::IntrinsicDef> {
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ pub use self::sty::{
|
|||
pub use self::trait_def::TraitDef;
|
||||
pub use self::typeck_results::{
|
||||
CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, IsIdentity,
|
||||
TypeckResults, UserType, UserTypeAnnotationIndex,
|
||||
TypeckResults, UserType, UserTypeAnnotationIndex, UserTypeKind,
|
||||
};
|
||||
pub use self::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
|
||||
use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason};
|
||||
|
|
@ -254,6 +254,7 @@ pub struct ImplTraitHeader<'tcx> {
|
|||
pub trait_ref: ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>>,
|
||||
pub polarity: ImplPolarity,
|
||||
pub safety: hir::Safety,
|
||||
pub constness: hir::Constness,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)]
|
||||
|
|
@ -2005,17 +2006,25 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
let def_id: DefId = def_id.into();
|
||||
match self.def_kind(def_id) {
|
||||
DefKind::Impl { of_trait: true } => {
|
||||
self.constness(def_id) == hir::Constness::Const
|
||||
&& self.is_const_trait(
|
||||
self.trait_id_of_impl(def_id)
|
||||
.expect("expected trait for trait implementation"),
|
||||
)
|
||||
let header = self.impl_trait_header(def_id).unwrap();
|
||||
header.constness == hir::Constness::Const
|
||||
&& self.is_const_trait(header.trait_ref.skip_binder().def_id)
|
||||
}
|
||||
DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) => {
|
||||
self.constness(def_id) == hir::Constness::Const
|
||||
}
|
||||
DefKind::Trait => self.is_const_trait(def_id),
|
||||
DefKind::AssocTy | DefKind::AssocFn => {
|
||||
DefKind::AssocTy => {
|
||||
let parent_def_id = self.parent(def_id);
|
||||
match self.def_kind(parent_def_id) {
|
||||
DefKind::Impl { of_trait: false } => false,
|
||||
DefKind::Impl { of_trait: true } | DefKind::Trait => {
|
||||
self.is_conditionally_const(parent_def_id)
|
||||
}
|
||||
_ => bug!("unexpected parent item of associated type: {parent_def_id:?}"),
|
||||
}
|
||||
}
|
||||
DefKind::AssocFn => {
|
||||
let parent_def_id = self.parent(def_id);
|
||||
match self.def_kind(parent_def_id) {
|
||||
DefKind::Impl { of_trait: false } => {
|
||||
|
|
@ -2024,7 +2033,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
DefKind::Impl { of_trait: true } | DefKind::Trait => {
|
||||
self.is_conditionally_const(parent_def_id)
|
||||
}
|
||||
_ => bug!("unexpected parent item of associated item: {parent_def_id:?}"),
|
||||
_ => bug!("unexpected parent item of associated fn: {parent_def_id:?}"),
|
||||
}
|
||||
}
|
||||
DefKind::OpaqueTy => match self.opaque_ty_origin(def_id) {
|
||||
|
|
|
|||
|
|
@ -700,12 +700,31 @@ pub struct CanonicalUserTypeAnnotation<'tcx> {
|
|||
/// Canonical user type annotation.
|
||||
pub type CanonicalUserType<'tcx> = Canonical<'tcx, UserType<'tcx>>;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)]
|
||||
#[derive(Eq, Hash, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct UserType<'tcx> {
|
||||
pub kind: UserTypeKind<'tcx>,
|
||||
pub bounds: ty::Clauses<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> UserType<'tcx> {
|
||||
pub fn new(kind: UserTypeKind<'tcx>) -> UserType<'tcx> {
|
||||
UserType { kind, bounds: ty::ListWithCachedTypeInfo::empty() }
|
||||
}
|
||||
|
||||
/// A user type annotation with additional bounds that need to be enforced.
|
||||
/// These bounds are lowered from `impl Trait` in bindings.
|
||||
pub fn new_with_bounds(kind: UserTypeKind<'tcx>, bounds: ty::Clauses<'tcx>) -> UserType<'tcx> {
|
||||
UserType { kind, bounds }
|
||||
}
|
||||
}
|
||||
|
||||
/// A user-given type annotation attached to a constant. These arise
|
||||
/// from constants that are named via paths, like `Foo::<A>::new` and
|
||||
/// so forth.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)]
|
||||
#[derive(Eq, Hash, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub enum UserType<'tcx> {
|
||||
pub enum UserTypeKind<'tcx> {
|
||||
Ty(Ty<'tcx>),
|
||||
|
||||
/// The canonical type is the result of `type_of(def_id)` with the
|
||||
|
|
@ -721,9 +740,13 @@ impl<'tcx> IsIdentity for CanonicalUserType<'tcx> {
|
|||
/// Returns `true` if this represents the generic parameters of the form `[?0, ?1, ?2]`,
|
||||
/// i.e., each thing is mapped to a canonical variable with the same index.
|
||||
fn is_identity(&self) -> bool {
|
||||
match self.value {
|
||||
UserType::Ty(_) => false,
|
||||
UserType::TypeOf(_, user_args) => {
|
||||
if !self.value.bounds.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
match self.value.kind {
|
||||
UserTypeKind::Ty(_) => false,
|
||||
UserTypeKind::TypeOf(_, user_args) => {
|
||||
if user_args.user_self_ty.is_some() {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -764,6 +787,18 @@ impl<'tcx> IsIdentity for CanonicalUserType<'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> std::fmt::Display for UserType<'tcx> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
if self.bounds.is_empty() {
|
||||
self.kind.fmt(f)
|
||||
} else {
|
||||
self.kind.fmt(f)?;
|
||||
write!(f, " + ")?;
|
||||
std::fmt::Debug::fmt(&self.bounds, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> std::fmt::Display for UserTypeKind<'tcx> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Ty(arg0) => {
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue