Skip to content

Commit

Permalink
Auto merge of rust-lang#132943 - matthiaskrgr:rollup-164l3ej, r=matth…
Browse files Browse the repository at this point in the history
…iaskrgr

Rollup of 8 pull requests

Successful merges:

 - rust-lang#132651 (Remove attributes from generics in built-in derive macros)
 - rust-lang#132668 (Feature gate yield expressions not in 2024)
 - rust-lang#132771 (test(configure): cover `parse_args` in `src/bootstrap/configure.py`)
 - rust-lang#132895 (Generalize `NonNull::from_raw_parts` per ACP362)
 - rust-lang#132914 (Update grammar in std::cell docs.)
 - rust-lang#132927 (Consolidate type system const evaluation under `traits::evaluate_const`)
 - rust-lang#132935 (Make sure to ignore elided lifetimes when pointing at args for fulfillment errors)
 - rust-lang#132941 (Subtree update of `rust-analyzer`)

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Nov 12, 2024
2 parents 9a9dadd + 38c2db4 commit 5700240
Show file tree
Hide file tree
Showing 73 changed files with 914 additions and 842 deletions.
15 changes: 12 additions & 3 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -523,9 +523,18 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
"consider removing `for<...>`"
);
gate_all!(more_qualified_paths, "usage of qualified paths in this context is experimental");
for &span in spans.get(&sym::yield_expr).iter().copied().flatten() {
if !span.at_least_rust_2024() {
gate!(&visitor, coroutines, span, "yield syntax is experimental");
// yield can be enabled either by `coroutines` or `gen_blocks`
if let Some(spans) = spans.get(&sym::yield_expr) {
for span in spans {
if (!visitor.features.coroutines() && !span.allows_unstable(sym::coroutines))
&& (!visitor.features.gen_blocks() && !span.allows_unstable(sym::gen_blocks))
{
#[allow(rustc::untranslatable_diagnostic)]
// Don't know which of the two features to include in the
// error message, so I am arbitrarily picking one.
feature_err(&visitor.sess, sym::coroutines, *span, "yield syntax is experimental")
.emit();
}
}
}
gate_all!(gen_blocks, "gen blocks are experimental");
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,12 @@ impl<'a> TraitDef<'a> {
param_clone
}
})
.map(|mut param| {
// Remove all attributes, because there might be helper attributes
// from other macros that will not be valid in the expanded implementation.
param.attrs.clear();
param
})
.collect();

// and similarly for where clauses
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1477,7 +1477,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
} else if self.tcx.features().generic_const_exprs() {
ct.normalize_internal(self.tcx, self.param_env)
rustc_trait_selection::traits::evaluate_const(&self.infcx, ct, self.param_env)
} else {
ct
}
Expand Down
20 changes: 16 additions & 4 deletions compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,12 +316,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.tcx
.generics_of(def_id)
.own_args(ty::GenericArgs::identity_for_item(self.tcx, def_id));
let Some((index, _)) =
own_args.iter().enumerate().find(|(_, arg)| **arg == param_to_point_at)
else {
let Some(mut index) = own_args.iter().position(|arg| *arg == param_to_point_at) else {
return false;
};
let Some(arg) = segment.args().args.get(index) else {
// SUBTLE: We may or may not turbofish lifetime arguments, which will
// otherwise be elided. if our "own args" starts with a lifetime, but
// the args list does not, then we should chop off all of the lifetimes,
// since they're all elided.
let segment_args = segment.args().args;
if matches!(own_args[0].unpack(), ty::GenericArgKind::Lifetime(_))
&& segment_args.first().is_some_and(|arg| arg.is_ty_or_const())
&& let Some(offset) = own_args.iter().position(|arg| {
matches!(arg.unpack(), ty::GenericArgKind::Type(_) | ty::GenericArgKind::Const(_))
})
&& let Some(new_index) = index.checked_sub(offset)
{
index = new_index;
}
let Some(arg) = segment_args.get(index) else {
return false;
};
error.obligation.cause.span = arg
Expand Down
136 changes: 1 addition & 135 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_macros::extension;
pub use rustc_macros::{TypeFoldable, TypeVisitable};
use rustc_middle::bug;
use rustc_middle::infer::canonical::{CanonicalQueryInput, CanonicalVarValues};
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey};
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
use rustc_middle::traits::select;
pub use rustc_middle::ty::IntVarValue;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
Expand All @@ -40,7 +40,6 @@ use rustc_middle::ty::{
self, ConstVid, FloatVid, GenericArg, GenericArgKind, GenericArgs, GenericArgsRef,
GenericParamDefKind, InferConst, IntVid, Ty, TyCtxt, TyVid, TypingMode,
};
use rustc_middle::{bug, span_bug};
use rustc_span::Span;
use rustc_span::symbol::Symbol;
use rustc_type_ir::solve::Reveal;
Expand Down Expand Up @@ -1279,84 +1278,6 @@ impl<'tcx> InferCtxt<'tcx> {
u
}

pub fn try_const_eval_resolve(
&self,
param_env: ty::ParamEnv<'tcx>,
unevaluated: ty::UnevaluatedConst<'tcx>,
span: Span,
) -> Result<ty::Const<'tcx>, ErrorHandled> {
match self.const_eval_resolve(param_env, unevaluated, span) {
Ok(Ok(val)) => Ok(ty::Const::new_value(
self.tcx,
val,
self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args),
)),
Ok(Err(bad_ty)) => {
let tcx = self.tcx;
let def_id = unevaluated.def;
span_bug!(
tcx.def_span(def_id),
"unable to construct a valtree for the unevaluated constant {:?}: type {bad_ty} is not valtree-compatible",
unevaluated
);
}
Err(err) => Err(err),
}
}

/// Resolves and evaluates a constant.
///
/// The constant can be located on a trait like `<A as B>::C`, in which case the given
/// generic parameters and environment are used to resolve the constant. Alternatively if the
/// constant has generic parameters in scope the instantiations are used to evaluate the value
/// of the constant. For example in `fn foo<T>() { let _ = [0; bar::<T>()]; }` the repeat count
/// constant `bar::<T>()` requires a instantiation for `T`, if the instantiation for `T` is
/// still too generic for the constant to be evaluated then `Err(ErrorHandled::TooGeneric)` is
/// returned.
///
/// This handles inferences variables within both `param_env` and `args` by
/// performing the operation on their respective canonical forms.
#[instrument(skip(self), level = "debug")]
pub fn const_eval_resolve(
&self,
mut param_env: ty::ParamEnv<'tcx>,
unevaluated: ty::UnevaluatedConst<'tcx>,
span: Span,
) -> EvalToValTreeResult<'tcx> {
let mut args = self.resolve_vars_if_possible(unevaluated.args);
debug!(?args);

// Postpone the evaluation of constants whose args depend on inference
// variables
let tcx = self.tcx;
if args.has_non_region_infer() {
if let Some(ct) = tcx.thir_abstract_const(unevaluated.def)? {
let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, args));
if let Err(e) = ct.error_reported() {
return Err(ErrorHandled::Reported(e.into(), span));
} else if ct.has_non_region_infer() || ct.has_non_region_param() {
return Err(ErrorHandled::TooGeneric(span));
} else {
args = replace_param_and_infer_args_with_placeholder(tcx, args);
}
} else {
args = GenericArgs::identity_for_item(tcx, unevaluated.def);
param_env = tcx.param_env(unevaluated.def);
}
}

let param_env_erased = tcx.erase_regions(param_env);
let args_erased = tcx.erase_regions(args);
debug!(?param_env_erased);
debug!(?args_erased);

let unevaluated = ty::UnevaluatedConst { def: unevaluated.def, args: args_erased };

// The return value is the evaluated value which doesn't contain any reference to inference
// variables, thus we don't need to instantiate back the original values.
tcx.const_eval_resolve_for_typeck(param_env_erased, unevaluated, span)
}

/// The returned function is used in a fast path. If it returns `true` the variable is
/// unchanged, `false` indicates that the status is unknown.
#[inline]
Expand Down Expand Up @@ -1622,61 +1543,6 @@ impl RegionVariableOrigin {
}
}

/// Replaces args that reference param or infer variables with suitable
/// placeholders. This function is meant to remove these param and infer
/// args when they're not actually needed to evaluate a constant.
fn replace_param_and_infer_args_with_placeholder<'tcx>(
tcx: TyCtxt<'tcx>,
args: GenericArgsRef<'tcx>,
) -> GenericArgsRef<'tcx> {
struct ReplaceParamAndInferWithPlaceholder<'tcx> {
tcx: TyCtxt<'tcx>,
idx: u32,
}

impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceParamAndInferWithPlaceholder<'tcx> {
fn cx(&self) -> TyCtxt<'tcx> {
self.tcx
}

fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
if let ty::Infer(_) = t.kind() {
let idx = {
let idx = self.idx;
self.idx += 1;
idx
};
Ty::new_placeholder(self.tcx, ty::PlaceholderType {
universe: ty::UniverseIndex::ROOT,
bound: ty::BoundTy {
var: ty::BoundVar::from_u32(idx),
kind: ty::BoundTyKind::Anon,
},
})
} else {
t.super_fold_with(self)
}
}

fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
if let ty::ConstKind::Infer(_) = c.kind() {
ty::Const::new_placeholder(self.tcx, ty::PlaceholderConst {
universe: ty::UniverseIndex::ROOT,
bound: ty::BoundVar::from_u32({
let idx = self.idx;
self.idx += 1;
idx
}),
})
} else {
c.super_fold_with(self)
}
}
}

args.fold_with(&mut ReplaceParamAndInferWithPlaceholder { tcx, idx: 0 })
}

impl<'tcx> InferCtxt<'tcx> {
/// Given a [`hir::Block`], get the span of its last expression or
/// statement, peeling off any inner blocks.
Expand Down
20 changes: 9 additions & 11 deletions compiler/rustc_middle/src/mir/consts.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
use std::fmt::{self, Debug, Display, Formatter};

use either::Either;
use rustc_abi::{HasDataLayout, Size};
use rustc_hir::def_id::DefId;
use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
use rustc_session::RemapFileNameExt;
use rustc_session::config::RemapPathScopeComponents;
use rustc_span::{DUMMY_SP, Span};
use rustc_type_ir::visit::TypeVisitableExt;

use crate::mir::interpret::{AllocId, ConstAllocation, ErrorHandled, Scalar, alloc_range};
use crate::mir::{Promoted, pretty_print_const_value};
use crate::ty::print::{pretty_print_const, with_no_trimmed_paths};
use crate::ty::{self, GenericArgsRef, ScalarInt, Ty, TyCtxt};
use crate::ty::{self, ConstKind, GenericArgsRef, ScalarInt, Ty, TyCtxt};

///////////////////////////////////////////////////////////////////////////
/// Evaluated Constants
Expand Down Expand Up @@ -319,15 +319,13 @@ impl<'tcx> Const<'tcx> {
) -> Result<ConstValue<'tcx>, ErrorHandled> {
match self {
Const::Ty(_, c) => {
// We want to consistently have a "clean" value for type system constants (i.e., no
// data hidden in the padding), so we always go through a valtree here.
match c.eval_valtree(tcx, param_env, span) {
Ok((ty, val)) => Ok(tcx.valtree_to_const_val((ty, val))),
Err(Either::Left(_bad_ty)) => Err(tcx
.dcx()
.delayed_bug("`mir::Const::eval` called on a non-valtree-compatible type")
.into()),
Err(Either::Right(e)) => Err(e),
if c.has_non_region_param() {
return Err(ErrorHandled::TooGeneric(span));
}

match c.kind() {
ConstKind::Value(ty, val) => Ok(tcx.valtree_to_const_val((ty, val))),
_ => Err(tcx.dcx().delayed_bug("Unevaluated `ty::Const` in MIR body").into()),
}
}
Const::Unevaluated(uneval, _) => {
Expand Down
59 changes: 2 additions & 57 deletions compiler/rustc_middle/src/ty/consts.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use either::Either;
use rustc_data_structures::intern::Interned;
use rustc_error_messages::MultiSpan;
use rustc_hir::def::{DefKind, Res};
Expand All @@ -9,7 +8,7 @@ use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo};
use tracing::{debug, instrument};

use crate::middle::resolve_bound_vars as rbv;
use crate::mir::interpret::{ErrorHandled, LitToConstInput, Scalar};
use crate::mir::interpret::{LitToConstInput, Scalar};
use crate::ty::{self, GenericArgs, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};

mod int;
Expand All @@ -18,7 +17,7 @@ mod valtree;

pub use int::*;
pub use kind::*;
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
use rustc_span::{DUMMY_SP, ErrorGuaranteed};
pub use valtree::*;

pub type ConstKind<'tcx> = ir::ConstKind<TyCtxt<'tcx>>;
Expand Down Expand Up @@ -363,60 +362,6 @@ impl<'tcx> Const<'tcx> {
Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.usize))
}

/// Returns the evaluated constant as a valtree;
/// if that fails due to a valtree-incompatible type, indicate which type that is
/// by returning `Err(Left(bad_type))`.
#[inline]
pub fn eval_valtree(
self,
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
span: Span,
) -> Result<(Ty<'tcx>, ValTree<'tcx>), Either<Ty<'tcx>, ErrorHandled>> {
assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}");
match self.kind() {
ConstKind::Unevaluated(unevaluated) => {
// FIXME(eddyb) maybe the `const_eval_*` methods should take
// `ty::ParamEnvAnd` instead of having them separate.
let (param_env, unevaluated) = unevaluated.prepare_for_eval(tcx, param_env);
// try to resolve e.g. associated constants to their definition on an impl, and then
// evaluate the const.
match tcx.const_eval_resolve_for_typeck(param_env, unevaluated, span) {
Ok(Ok(c)) => {
Ok((tcx.type_of(unevaluated.def).instantiate(tcx, unevaluated.args), c))
}
Ok(Err(bad_ty)) => Err(Either::Left(bad_ty)),
Err(err) => Err(Either::Right(err)),
}
}
ConstKind::Value(ty, val) => Ok((ty, val)),
ConstKind::Error(g) => Err(Either::Right(g.into())),
ConstKind::Param(_)
| ConstKind::Infer(_)
| ConstKind::Bound(_, _)
| ConstKind::Placeholder(_)
| ConstKind::Expr(_) => Err(Either::Right(ErrorHandled::TooGeneric(span))),
}
}

/// Normalizes the constant to a value or an error if possible.
#[inline]
pub fn normalize_internal(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
match self.eval_valtree(tcx, param_env, DUMMY_SP) {
Ok((ty, val)) => Self::new_value(tcx, val, ty),
Err(Either::Left(_bad_ty)) => {
// This can happen when we run on ill-typed code.
Self::new_error(
tcx,
tcx.dcx()
.delayed_bug("`ty::Const::eval` called on a non-valtree-compatible type"),
)
}
Err(Either::Right(ErrorHandled::Reported(r, _span))) => Self::new_error(tcx, r.into()),
Err(Either::Right(ErrorHandled::TooGeneric(_span))) => self,
}
}

/// Panics if self.kind != ty::ConstKind::Value
pub fn to_valtree(self) -> (ty::ValTree<'tcx>, Ty<'tcx>) {
match self.kind() {
Expand Down
Loading

0 comments on commit 5700240

Please sign in to comment.