Skip to content

Commit

Permalink
Auto merge of #135519 - workingjubilee:rollup-xq9yryh, r=workingjubilee
Browse files Browse the repository at this point in the history
Rollup of 11 pull requests

Successful merges:

 - #134913 (bootstrap: do not rely on LIBRARY_PATH env variable)
 - #134940 (Make sure to scrape region constraints from deeply normalizing type outlives assumptions in borrowck)
 - #135228 (Improve `DispatchFromDyn` and `CoerceUnsized` impl validation)
 - #135264 (Consider more erroneous layouts as `LayoutError::ReferencesError` to suppress spurious errors)
 - #135302 (for purely return-type based searches, deprioritize clone-like functions)
 - #135353 (re-add --disable-minification to rustdoc)
 - #135380 (Make sure we can produce `ConstArgHasWrongType` errors for valtree consts)
 - #135423 (Enforce syntactical stability of const traits in HIR)
 - #135425 (Do not consider traits that have unsatisfied const conditions to be conditionally const)
 - #135499 (fix underlining of hovered intra-doc links.)
 - #135505 (Fix clippy lints in rustdoc)

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Jan 15, 2025
2 parents 93ba568 + 4f25a31 commit 00ded39
Show file tree
Hide file tree
Showing 59 changed files with 871 additions and 162 deletions.
67 changes: 48 additions & 19 deletions compiler/rustc_borrowck/src/type_check/free_region_relations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ use rustc_infer::infer::canonical::QueryRegionConstraints;
use rustc_infer::infer::outlives::env::RegionBoundPairs;
use rustc_infer::infer::region_constraints::GenericKind;
use rustc_infer::infer::{InferCtxt, outlives};
use rustc_infer::traits::ScrubbedTraitError;
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::traits::ObligationCause;
use rustc_middle::traits::query::OutlivesBound;
use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt};
use rustc_span::{ErrorGuaranteed, Span};
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
use rustc_trait_selection::solve::deeply_normalize;
use rustc_trait_selection::solve::NoSolution;
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
use tracing::{debug, instrument};
use type_op::TypeOpOutput;
Expand Down Expand Up @@ -229,24 +230,14 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
let mut constraints = vec![];
let mut known_type_outlives_obligations = vec![];
for bound in param_env.caller_bounds() {
let Some(mut outlives) = bound.as_type_outlives_clause() else { continue };

// In the new solver, normalize the type-outlives obligation assumptions.
if self.infcx.next_trait_solver() {
match deeply_normalize(
self.infcx.at(&ObligationCause::misc(span, defining_ty_def_id), param_env),
if let Some(outlives) = bound.as_type_outlives_clause() {
self.normalize_and_push_type_outlives_obligation(
outlives,
) {
Ok(normalized_outlives) => {
outlives = normalized_outlives;
}
Err(e) => {
self.infcx.err_ctxt().report_fulfillment_errors(e);
}
}
}

known_type_outlives_obligations.push(outlives);
span,
&mut known_type_outlives_obligations,
&mut constraints,
);
};
}

let unnormalized_input_output_tys = self
Expand Down Expand Up @@ -356,6 +347,44 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
}
}

fn normalize_and_push_type_outlives_obligation(
&self,
mut outlives: ty::PolyTypeOutlivesPredicate<'tcx>,
span: Span,
known_type_outlives_obligations: &mut Vec<ty::PolyTypeOutlivesPredicate<'tcx>>,
constraints: &mut Vec<&QueryRegionConstraints<'tcx>>,
) {
// In the new solver, normalize the type-outlives obligation assumptions.
if self.infcx.next_trait_solver() {
let Ok(TypeOpOutput {
output: normalized_outlives,
constraints: constraints_normalize,
error_info: _,
}) = CustomTypeOp::new(
|ocx| {
ocx.deeply_normalize(
&ObligationCause::dummy_with_span(span),
self.param_env,
outlives,
)
.map_err(|_: Vec<ScrubbedTraitError<'tcx>>| NoSolution)
},
"normalize type outlives obligation",
)
.fully_perform(self.infcx, span)
else {
self.infcx.dcx().delayed_bug(format!("could not normalize {outlives:?}"));
return;
};
outlives = normalized_outlives;
if let Some(c) = constraints_normalize {
constraints.push(c);
}
}

known_type_outlives_obligations.push(outlives);
}

/// Update the type of a single local, which should represent
/// either the return type of the MIR or one of its arguments. At
/// the same time, compute and add any implied bounds that come
Expand Down
26 changes: 18 additions & 8 deletions compiler/rustc_const_eval/src/check_consts/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ use crate::errors;
type QualifResults<'mir, 'tcx, Q> =
rustc_mir_dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'mir, 'mir, 'tcx, Q>>;

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
enum ConstConditionsHold {
Yes,
No,
}

#[derive(Default)]
pub(crate) struct Qualifs<'mir, 'tcx> {
has_mut_interior: Option<QualifResults<'mir, 'tcx, HasMutInterior>>,
Expand Down Expand Up @@ -376,15 +382,15 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
callee: DefId,
callee_args: ty::GenericArgsRef<'tcx>,
call_span: Span,
) -> bool {
) -> Option<ConstConditionsHold> {
let tcx = self.tcx;
if !tcx.is_conditionally_const(callee) {
return false;
return None;
}

let const_conditions = tcx.const_conditions(callee).instantiate(tcx, callee_args);
if const_conditions.is_empty() {
return false;
return None;
}

let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(self.body.typing_env(tcx));
Expand Down Expand Up @@ -413,12 +419,13 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
}));

let errors = ocx.select_all_or_error();
if !errors.is_empty() {
if errors.is_empty() {
Some(ConstConditionsHold::Yes)
} else {
tcx.dcx()
.span_delayed_bug(call_span, "this should have reported a ~const error in HIR");
Some(ConstConditionsHold::No)
}

true
}

pub fn check_drop_terminator(
Expand Down Expand Up @@ -706,7 +713,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
trace!("attempting to call a trait method");
let trait_is_const = tcx.is_const_trait(trait_did);

if trait_is_const {
// Only consider a trait to be const if the const conditions hold.
// Otherwise, it's really misleading to call something "conditionally"
// const when it's very obviously not conditionally const.
if trait_is_const && has_const_conditions == Some(ConstConditionsHold::Yes) {
// Trait calls are always conditionally-const.
self.check_op(ops::ConditionallyConstCall {
callee,
Expand All @@ -730,7 +740,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
}

// Even if we know the callee, ensure we can use conditionally-const calls.
if has_const_conditions {
if has_const_conditions.is_some() {
self.check_op(ops::ConditionallyConstCall {
callee,
args: fn_args,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ hir_analysis_dispatch_from_dyn_multi = implementing the `DispatchFromDyn` trait
hir_analysis_dispatch_from_dyn_repr = structs implementing `DispatchFromDyn` may not have `#[repr(packed)]` or `#[repr(C)]`
hir_analysis_dispatch_from_dyn_zst = the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment, and nothing else
hir_analysis_dispatch_from_dyn_zst = the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment that don't mention type/const generics, and nothing else
.note = extra field `{$name}` of type `{$ty}` is not allowed
hir_analysis_drop_impl_negative = negative `Drop` impls are not supported
Expand Down
42 changes: 34 additions & 8 deletions compiler/rustc_hir_analysis/src/coherence/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,19 +259,37 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
let coerced_fields = fields
.iter()
.filter(|field| {
// Ignore PhantomData fields
let unnormalized_ty = tcx.type_of(field.did).instantiate_identity();
if tcx
.try_normalize_erasing_regions(
ty::TypingEnv::non_body_analysis(tcx, def_a.did()),
unnormalized_ty,
)
.unwrap_or(unnormalized_ty)
.is_phantom_data()
{
return false;
}

let ty_a = field.ty(tcx, args_a);
let ty_b = field.ty(tcx, args_b);

if let Ok(layout) =
tcx.layout_of(infcx.typing_env(param_env).as_query_input(ty_a))
{
if layout.is_1zst() {
// FIXME: We could do normalization here, but is it really worth it?
if ty_a == ty_b {
// Allow 1-ZSTs that don't mention type params.
//
// Allowing type params here would allow us to possibly transmute
// between ZSTs, which may be used to create library unsoundness.
if let Ok(layout) =
tcx.layout_of(infcx.typing_env(param_env).as_query_input(ty_a))
&& layout.is_1zst()
&& !ty_a.has_non_region_param()
{
// ignore 1-ZST fields
return false;
}
}

if ty_a == ty_b {
res = Err(tcx.dcx().emit_err(errors::DispatchFromDynZST {
span,
name: field.name,
Expand Down Expand Up @@ -460,8 +478,16 @@ pub(crate) fn coerce_unsized_info<'tcx>(
.filter_map(|(i, f)| {
let (a, b) = (f.ty(tcx, args_a), f.ty(tcx, args_b));

if tcx.type_of(f.did).instantiate_identity().is_phantom_data() {
// Ignore PhantomData fields
// Ignore PhantomData fields
let unnormalized_ty = tcx.type_of(f.did).instantiate_identity();
if tcx
.try_normalize_erasing_regions(
ty::TypingEnv::non_body_analysis(tcx, def_a.did()),
unnormalized_ty,
)
.unwrap_or(unnormalized_ty)
.is_phantom_data()
{
return None;
}

Expand Down
89 changes: 87 additions & 2 deletions compiler/rustc_middle/src/middle/stability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ pub enum StabilityLevel {
Stable,
}

#[derive(Copy, Clone)]
pub enum UnstableKind {
/// Enforcing regular stability of an item
Regular,
/// Enforcing const stability of an item
Const(Span),
}

/// An entry in the `depr_map`.
#[derive(Copy, Clone, HashStable, Debug, Encodable, Decodable)]
pub struct DeprecationEntry {
Expand Down Expand Up @@ -108,10 +116,16 @@ pub fn report_unstable(
is_soft: bool,
span: Span,
soft_handler: impl FnOnce(&'static Lint, Span, String),
kind: UnstableKind,
) {
let qual = match kind {
UnstableKind::Regular => "",
UnstableKind::Const(_) => " const",
};

let msg = match reason {
Some(r) => format!("use of unstable library feature `{feature}`: {r}"),
None => format!("use of unstable library feature `{feature}`"),
Some(r) => format!("use of unstable{qual} library feature `{feature}`: {r}"),
None => format!("use of unstable{qual} library feature `{feature}`"),
};

if is_soft {
Expand All @@ -121,6 +135,9 @@ pub fn report_unstable(
if let Some((inner_types, msg, sugg, applicability)) = suggestion {
err.span_suggestion(inner_types, msg, sugg, applicability);
}
if let UnstableKind::Const(kw) = kind {
err.span_label(kw, "trait is not stable as const yet");
}
err.emit();
}
}
Expand Down Expand Up @@ -587,13 +604,81 @@ impl<'tcx> TyCtxt<'tcx> {
is_soft,
span,
soft_handler,
UnstableKind::Regular,
),
EvalResult::Unmarked => unmarked(span, def_id),
}

is_allowed
}

/// This function is analogous to `check_optional_stability` but with the logic in
/// `eval_stability_allow_unstable` inlined, and which operating on const stability
/// instead of regular stability.
///
/// This enforces *syntactical* const stability of const traits. In other words,
/// it enforces the ability to name `~const`/`const` traits in trait bounds in various
/// syntax positions in HIR (including in the trait of an impl header).
pub fn check_const_stability(self, def_id: DefId, span: Span, const_kw_span: Span) {
let is_staged_api = self.lookup_stability(def_id.krate.as_def_id()).is_some();
if !is_staged_api {
return;
}

// Only the cross-crate scenario matters when checking unstable APIs
let cross_crate = !def_id.is_local();
if !cross_crate {
return;
}

let stability = self.lookup_const_stability(def_id);
debug!(
"stability: \
inspecting def_id={:?} span={:?} of stability={:?}",
def_id, span, stability
);

match stability {
Some(ConstStability {
level: attr::StabilityLevel::Unstable { reason, issue, is_soft, implied_by, .. },
feature,
..
}) => {
assert!(!is_soft);

if span.allows_unstable(feature) {
debug!("body stability: skipping span={:?} since it is internal", span);
return;
}
if self.features().enabled(feature) {
return;
}

// If this item was previously part of a now-stabilized feature which is still
// enabled (i.e. the user hasn't removed the attribute for the stabilized feature
// yet) then allow use of this item.
if let Some(implied_by) = implied_by
&& self.features().enabled(implied_by)
{
return;
}

report_unstable(
self.sess,
feature,
reason.to_opt_reason(),
issue,
None,
false,
span,
|_, _, _| {},
UnstableKind::Const(const_kw_span),
);
}
Some(_) | None => {}
}
}

pub fn lookup_deprecation(self, id: DefId) -> Option<Deprecation> {
self.lookup_deprecation_entry(id).map(|depr| depr.attr)
}
Expand Down
Loading

0 comments on commit 00ded39

Please sign in to comment.