Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions compiler/rustc_attr_ir/src/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1140,6 +1140,12 @@ pub enum AttributeKind {
/// Represents `#[rustc_allow_lifetime_dependent_specialization]`.
RustcAllowLifetimeDependentSpecialization,

/// Represents `#[rustc_anti_fundamental]`. This marks a trait so that it
/// cannot be implemented for non-local `#[fundamental]` types. This in particular
/// prevents the implementation of `Deref`, `DerefMut`, and `DispatchFromDyn` on
/// fundamental wrappers like `Pin` and `Box`.
RustcAntiFundamental,

/// Represents `#[rustc_as_ptr]` (used by the `dangling_pointers_from_temporaries` lint).
RustcAsPtr,

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_attr_ir/src/encode_cross_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ impl AttributeKind {
RustcAllowConstFnUnstable(..) => No,
RustcAllowIncoherentImpl(..) => No,
RustcAllowLifetimeDependentSpecialization => No,
RustcAntiFundamental => No,
RustcAsPtr => Yes,
RustcAutodiff(..) => Yes,
RustcBodyStability { .. } => No,
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_attr_parsing/src/attributes/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,14 @@ impl NoArgsAttributeParser for RustcCoinductiveParser {
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcCoinductive;
}

pub(crate) struct RustcAntiFundamentalParser;
impl NoArgsAttributeParser for RustcAntiFundamentalParser {
const PATH: &[Symbol] = &[sym::rustc_anti_fundamental];
const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
const STABILITY: AttributeStability = unstable!(rustc_attrs);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcAntiFundamental;
}

pub(crate) struct RustcAllowIncoherentImplParser;
impl NoArgsAttributeParser for RustcAllowIncoherentImplParser {
const PATH: &[Symbol] = &[sym::rustc_allow_incoherent_impl];
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ attribute_parsers!(
Single<WithoutArgs<RustcAllocatorZeroedParser>>,
Single<WithoutArgs<RustcAllowIncoherentImplParser>>,
Single<WithoutArgs<RustcAllowLifetimeDependentSpecializationParser>>,
Single<WithoutArgs<RustcAntiFundamentalParser>>,
Single<WithoutArgs<RustcAsPtrParser>>,
Single<WithoutArgs<RustcCanonicalSymbolParser>>,
Single<WithoutArgs<RustcCaptureAnalysisParser>>,
Expand Down
12 changes: 8 additions & 4 deletions compiler/rustc_borrowck/src/dataflow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ use rustc_mir_dataflow::impls::{
use rustc_mir_dataflow::{Analysis, GenKill, JoinSemiLattice};
use tracing::debug;

use crate::{BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, places_conflict};
use crate::{
AccessDepth, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, places_conflict,
};

// This analysis is different to most others. Its results aren't computed with
// `iterate_to_fixpoint`, but are instead composed from the results of three sub-analyses that are
Expand Down Expand Up @@ -432,7 +434,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {

// If the borrowed place is a local with no projections, all other borrows of this
// local must conflict. This is purely an optimization so we don't have to call
// `places_conflict` for every borrow.
// `places_conflict::borrow_conflicts_with_place` for every borrow.
if place.projection.is_empty() {
if !self.body.local_decls[place.local].is_ref_to_static() {
state.kill_all(other_borrows_of_local);
Expand All @@ -445,11 +447,13 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
// will be assured that two places being compared definitely denotes the same sets of
// locations.
let definitely_conflicting_borrows = other_borrows_of_local.filter(|&i| {
places_conflict(
places_conflict::borrow_conflicts_with_place(
self.tcx,
self.body,
self.borrow_set[i].borrowed_place,
place,
self.borrow_set[i].kind,
place.as_ref(),
AccessDepth::Deep,
PlaceConflictBias::NoOverlap,
)
});
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_borrowck/src/diagnostics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
// we'll use this to check whether it was originally from an overloaded
// operator.
match self.move_data.rev_lookup.find(deref_base) {
LookupResult::Exact(mpi) | LookupResult::Parent(Some(mpi)) => {
LookupResult::Exact(mpi) | LookupResult::Parent { mpi, .. } => {
debug!("borrowed_content_source: mpi={:?}", mpi);

for i in &self.move_data.init_path_map[mpi] {
Expand Down Expand Up @@ -597,7 +597,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
}
}
// Base is a `static` so won't be from an overloaded operator
_ => (),
LookupResult::None => (),
};

// If we didn't find an overloaded deref or index, then assume it's a
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_borrowck/src/diagnostics/move_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> {

match self.move_data.rev_lookup.find(match_place.as_ref()) {
// Error with the match place
LookupResult::Parent(_) => {
LookupResult::Parent { .. } | LookupResult::None => {
for ge in &mut *grouped_errors {
if let GroupedMoveError::MovesFromPlace { span, binds_to, .. } = ge
&& match_span == *span
Expand Down Expand Up @@ -219,7 +219,7 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> {
}
// Error with the pattern
LookupResult::Exact(_) => {
let LookupResult::Parent(Some(mpi)) =
let LookupResult::Parent { mpi, .. } =
self.move_data.rev_lookup.find(move_from.as_ref())
else {
// move_from should be a projection from match_place.
Expand Down
57 changes: 33 additions & 24 deletions compiler/rustc_borrowck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2077,15 +2077,43 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
// This code covers scenarios 1, 2, and 3.

debug!("check_if_full_path_is_moved place: {:?}", place_span.0);
let (prefix, mpi) = self.move_path_closest_to(place_span.0);
if maybe_uninits.contains(mpi) {

let uninit_mpi = match self.move_data.rev_lookup.find(place_span.0) {
// Index projections arbitrarily overlap sibling move paths, so we need to check all descendents of the parent
// Subslice and ConstantIndex projections of slices also overlap siblings,
// but the parent slice will never have a move path
// Subslice projections of arrays are specifically checked in `check_if_subslice_element_is_moved`
LookupResult::Parent { mpi, next_elem: ProjectionKind::Index(..) } => self
.move_data
.find_in_move_path_or_its_descendants(mpi, |mpi| maybe_uninits.contains(mpi)),

LookupResult::Exact(mpi)
| LookupResult::Parent {
mpi,
next_elem:
ProjectionKind::Deref
| ProjectionKind::Field(..)
| ProjectionKind::ConstantIndex { .. }
| ProjectionKind::Subslice { .. }
| ProjectionKind::Downcast(..)
| ProjectionKind::OpaqueCast(..)
| ProjectionKind::UnwrapUnsafeBinder(..)
| ProjectionKind::PhantomDeref,
} => maybe_uninits.contains(mpi).then_some(mpi),

LookupResult::None => bug!("should have move path for every Local"),
};

if let Some(mpi) = uninit_mpi {
self.report_use_of_moved_or_uninitialized(
location,
desired_action,
(prefix, place_span.0, place_span.1),
(self.move_data.move_paths[mpi].place.as_ref(), place_span.0, place_span.1),
mpi,
);
} // Only query longest prefix with a MovePath, not further
}

// Only query longest prefix with a MovePath, not further
// ancestors; dataflow recurs on children when parents
// move (to support partial (re)inits).
//
Expand Down Expand Up @@ -2207,32 +2235,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
}
}

/// Currently MoveData does not store entries for all places in
/// the input MIR. For example it will currently filter out
/// places that are Copy; thus we do not track places of shared
/// reference type. This routine will walk up a place along its
/// prefixes, searching for a foundational place that *is*
/// tracked in the MoveData.
///
/// An Err result includes a tag indicated why the search failed.
/// Currently this can only occur if the place is built off of a
/// static variable, as we do not track those in the MoveData.
fn move_path_closest_to(&mut self, place: PlaceRef<'tcx>) -> (PlaceRef<'tcx>, MovePathIndex) {
match self.move_data.rev_lookup.find(place) {
LookupResult::Parent(Some(mpi)) | LookupResult::Exact(mpi) => {
(self.move_data.move_paths[mpi].place.as_ref(), mpi)
}
LookupResult::Parent(None) => panic!("should have move path for every Local"),
}
}

fn move_path_for_place(&mut self, place: PlaceRef<'tcx>) -> Option<MovePathIndex> {
// If returns None, then there is no move path corresponding
// to a direct owner of `place` (which means there is nothing
// that borrowck tracks for its analysis).

match self.move_data.rev_lookup.find(place) {
LookupResult::Parent(_) => None,
LookupResult::Parent { .. } | LookupResult::None => None,
LookupResult::Exact(mpi) => Some(mpi),
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_borrowck/src/polonius/legacy/accesses.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ impl<'a, 'tcx> Visitor<'tcx> for AccessFactsExtractor<'a, 'tcx> {
match context {
PlaceContext::NonMutatingUse(_)
| PlaceContext::MutatingUse(MutatingUseContext::Borrow) => {
let (LookupResult::Exact(path) | LookupResult::Parent(Some(path))) =
let (LookupResult::Exact(path) | LookupResult::Parent { mpi: path, .. }) =
self.move_data.rev_lookup.find(place.as_ref())
else {
// There's no path access to emit.
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_error_codes/src/error_codes/E0224.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ Rust does not currently support this.
To solve, ensure that the trait object has at least one trait:

```
type Foo = dyn 'static + Copy;
type Foo = dyn 'static + std::fmt::Debug;
```
1 change: 1 addition & 0 deletions compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ pub static BUILTIN_ATTRIBUTES: &[Symbol] = &[
sym::rustc_never_returns_null_ptr,
sym::rustc_no_implicit_autorefs,
sym::rustc_coherence_is_core,
sym::rustc_anti_fundamental,
sym::rustc_coinductive,
sym::rustc_comptime,
sym::rustc_allow_incoherent_impl,
Expand Down
39 changes: 30 additions & 9 deletions compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,22 @@ fn check_static_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) {
}
}

fn check_function_clauses(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> {
let clauses = tcx.clauses_of(def_id);
let param_env = tcx.param_env(def_id);
enter_wf_checking_ctxt(tcx, def_id, |wfcx| {
for (clause, span) in clauses.clauses {
wfcx.register_obligation(Obligation::new(
tcx,
ObligationCause::new(*span, def_id, ObligationCauseCode::WellFormed(None)),
param_env,
*clause,
));
}
Ok(())
})
}

pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> {
let mut res = Ok(());
let generics = tcx.generics_of(def_id);
Expand Down Expand Up @@ -815,9 +831,9 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
DefKind::Fn => {
tcx.ensure_ok().generics_of(def_id);
tcx.ensure_ok().type_of(def_id);
tcx.ensure_ok().clauses_of(def_id);
tcx.ensure_ok().fn_sig(def_id);
tcx.ensure_ok().codegen_fn_attrs(def_id);
res = res.and(check_function_clauses(tcx, def_id));
if let Some(i) = tcx.intrinsic(def_id) {
intrinsic::check_intrinsic_type(
tcx,
Expand Down Expand Up @@ -985,6 +1001,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
} else {
check_type_alias_type_params_are_used(tcx, def_id);
res = res.and(enter_wf_checking_ctxt(tcx, def_id, |wfcx| {
// FIXME(fmease): Update comment.
// HACK: We sometimes incidentally check that const arguments have the correct
// type as a side effect of the anon const desugaring. To make this "consistent"
// for users we explicitly check `ConstArgHasType` clauses so that const args
Expand All @@ -995,15 +1012,19 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
//
// Changing this to normalized obligations is a breaking change:
// `type Bar = [(); panic!()];` would become an error
if let Some(unnormalized_obligations) = wfcx.unnormalized_obligations(span, ty.skip_norm_wip())
if let Some(obligations) =
wfcx.unnormalized_obligations(span, ty.skip_norm_wip())
{
let filtered_obligations =
unnormalized_obligations.into_iter().filter(|o| {
matches!(o.predicate.kind().skip_binder(),
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, _))
if matches!(ct.kind(), ty::ConstKind::Param(..)))
});
wfcx.ocx.register_obligations(filtered_obligations)
wfcx.ocx.register_obligations(obligations.into_iter().filter(|o| {
match o.predicate.kind().skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(
ct,
_,
)) => matches!(ct.kind(), ty::ConstKind::Param(..)),
ty::PredicateKind::DynCompatible(_) => true,
_ => false,
}
}))
}
Ok(())
}));
Expand Down
86 changes: 62 additions & 24 deletions compiler/rustc_hir_analysis/src/coherence/orphan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,31 +28,41 @@ pub(crate) fn orphan_check_impl(

match orphan_check(tcx, impl_def_id, OrphanCheckMode::Proper) {
Ok(()) => {}
Err(err) => match orphan_check(tcx, impl_def_id, OrphanCheckMode::Compat) {
Ok(()) => match err {
OrphanCheckErr::UncoveredTyParams(uncovered_ty_params) => {
let hir_id = tcx.local_def_id_to_hir_id(impl_def_id);

for param_def_id in uncovered_ty_params.uncovered {
let ident = tcx.item_ident(param_def_id);

tcx.emit_node_span_lint(
UNCOVERED_PARAM_IN_PROJECTION,
hir_id,
ident.span,
diagnostics::UncoveredTyParam {
param: ident,
local_ty: uncovered_ty_params.local_ty,
},
);
Err(err) => {
if tcx.trait_def(trait_ref.def_id).is_anti_fundamental {
return Err(emit_orphan_check_error(tcx, trait_ref, impl_def_id, err));
}

match orphan_check(tcx, impl_def_id, OrphanCheckMode::Compat) {
Ok(()) => match err {
OrphanCheckErr::UncoveredTyParams(uncovered_ty_params) => {
let hir_id = tcx.local_def_id_to_hir_id(impl_def_id);

for param_def_id in uncovered_ty_params.uncovered {
let ident = tcx.item_ident(param_def_id);

tcx.emit_node_span_lint(
UNCOVERED_PARAM_IN_PROJECTION,
hir_id,
ident.span,
diagnostics::UncoveredTyParam {
param: ident,
local_ty: uncovered_ty_params.local_ty,
},
);
}
}
}
OrphanCheckErr::NonLocalInputType(_) => {
bug!("orphanck: shouldn't've gotten non-local input tys in compat mode")
}
},
Err(err) => return Err(emit_orphan_check_error(tcx, trait_ref, impl_def_id, err)),
},
OrphanCheckErr::NonLocalInputType(_) => {
bug!("orphanck: shouldn't've gotten non-local input tys in compat mode")
}
OrphanCheckErr::AntiFundamentalForeignType { .. } => {
// An anti-fundamental trait should return early above and never enter compat mode.
bug!("anti-fundamental traits never enter compat mode")
}
},
Err(err) => return Err(emit_orphan_check_error(tcx, trait_ref, impl_def_id, err)),
}
}
}

let trait_def_id = trait_ref.def_id;
Expand Down Expand Up @@ -381,6 +391,24 @@ fn orphan_check<'tcx>(
});
OrphanCheckErr::NonLocalInputType(tys)
}
OrphanCheckErr::AntiFundamentalForeignType { self_ty, fundamental_ty } => {
let (self_ty, fundamental_ty) = infcx.probe(|_| {
for (arg, id_arg) in
std::iter::zip(args, ty::GenericArgs::identity_for_item(tcx, impl_def_id))
{
let _ = infcx.at(&cause, ty::ParamEnv::empty()).eq(
DefineOpaqueTypes::No,
arg,
id_arg,
);
}
(
infcx.resolve_vars_if_possible(self_ty),
infcx.resolve_vars_if_possible(fundamental_ty),
)
});
OrphanCheckErr::AntiFundamentalForeignType { self_ty, fundamental_ty }
}
})
}

Expand Down Expand Up @@ -499,6 +527,16 @@ fn emit_orphan_check_error<'tcx>(
}
guar.unwrap()
}
traits::OrphanCheckErr::AntiFundamentalForeignType { self_ty, fundamental_ty } => {
let item = tcx.hir_expect_item(impl_def_id);
let impl_ = item.expect_impl();
tcx.dcx().emit_err(diagnostics::AntiFundamentalForeignImpl {
span: impl_.self_ty.span,
trait_name: tcx.def_path_str(trait_ref.def_id),
self_ty,
fundamental_ty,
})
}
}
}

Expand Down
Loading
Loading