Auto merge of #132943 - matthiaskrgr:rollup-164l3ej, r=matthiaskrgr

Rollup of 8 pull requests

Successful merges:

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

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-11-12 08:15:38 +00:00
commit 5700240aff
73 changed files with 914 additions and 842 deletions

View File

@ -523,9 +523,18 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
"consider removing `for<...>`" "consider removing `for<...>`"
); );
gate_all!(more_qualified_paths, "usage of qualified paths in this context is experimental"); 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() { // yield can be enabled either by `coroutines` or `gen_blocks`
if !span.at_least_rust_2024() { if let Some(spans) = spans.get(&sym::yield_expr) {
gate!(&visitor, coroutines, span, "yield syntax is experimental"); 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"); gate_all!(gen_blocks, "gen blocks are experimental");

View File

@ -680,6 +680,12 @@ impl<'a> TraitDef<'a> {
param_clone 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(); .collect();
// and similarly for where clauses // and similarly for where clauses

View File

@ -1477,7 +1477,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
} }
} else if self.tcx.features().generic_const_exprs() { } 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 { } else {
ct ct
} }

View File

@ -316,12 +316,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.tcx .tcx
.generics_of(def_id) .generics_of(def_id)
.own_args(ty::GenericArgs::identity_for_item(self.tcx, def_id)); .own_args(ty::GenericArgs::identity_for_item(self.tcx, def_id));
let Some((index, _)) = let Some(mut index) = own_args.iter().position(|arg| *arg == param_to_point_at) else {
own_args.iter().enumerate().find(|(_, arg)| **arg == param_to_point_at)
else {
return false; 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; return false;
}; };
error.obligation.cause.span = arg error.obligation.cause.span = arg

View File

@ -25,10 +25,10 @@ use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_macros::extension; use rustc_macros::extension;
pub use rustc_macros::{TypeFoldable, TypeVisitable}; pub use rustc_macros::{TypeFoldable, TypeVisitable};
use rustc_middle::bug;
use rustc_middle::infer::canonical::{CanonicalQueryInput, CanonicalVarValues}; use rustc_middle::infer::canonical::{CanonicalQueryInput, CanonicalVarValues};
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey};
use rustc_middle::mir::ConstraintCategory; use rustc_middle::mir::ConstraintCategory;
use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
use rustc_middle::traits::select; use rustc_middle::traits::select;
pub use rustc_middle::ty::IntVarValue; pub use rustc_middle::ty::IntVarValue;
use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::error::{ExpectedFound, TypeError};
@ -40,7 +40,6 @@ use rustc_middle::ty::{
self, ConstVid, FloatVid, GenericArg, GenericArgKind, GenericArgs, GenericArgsRef, self, ConstVid, FloatVid, GenericArg, GenericArgKind, GenericArgs, GenericArgsRef,
GenericParamDefKind, InferConst, IntVid, Ty, TyCtxt, TyVid, TypingMode, GenericParamDefKind, InferConst, IntVid, Ty, TyCtxt, TyVid, TypingMode,
}; };
use rustc_middle::{bug, span_bug};
use rustc_span::Span; use rustc_span::Span;
use rustc_span::symbol::Symbol; use rustc_span::symbol::Symbol;
use rustc_type_ir::solve::Reveal; use rustc_type_ir::solve::Reveal;
@ -1279,84 +1278,6 @@ impl<'tcx> InferCtxt<'tcx> {
u 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 /// The returned function is used in a fast path. If it returns `true` the variable is
/// unchanged, `false` indicates that the status is unknown. /// unchanged, `false` indicates that the status is unknown.
#[inline] #[inline]
@ -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> { impl<'tcx> InferCtxt<'tcx> {
/// Given a [`hir::Block`], get the span of its last expression or /// Given a [`hir::Block`], get the span of its last expression or
/// statement, peeling off any inner blocks. /// statement, peeling off any inner blocks.

View File

@ -1,17 +1,17 @@
use std::fmt::{self, Debug, Display, Formatter}; use std::fmt::{self, Debug, Display, Formatter};
use either::Either;
use rustc_abi::{HasDataLayout, Size}; use rustc_abi::{HasDataLayout, Size};
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
use rustc_session::RemapFileNameExt; use rustc_session::RemapFileNameExt;
use rustc_session::config::RemapPathScopeComponents; use rustc_session::config::RemapPathScopeComponents;
use rustc_span::{DUMMY_SP, Span}; 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::interpret::{AllocId, ConstAllocation, ErrorHandled, Scalar, alloc_range};
use crate::mir::{Promoted, pretty_print_const_value}; use crate::mir::{Promoted, pretty_print_const_value};
use crate::ty::print::{pretty_print_const, with_no_trimmed_paths}; 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 /// Evaluated Constants
@ -319,15 +319,13 @@ impl<'tcx> Const<'tcx> {
) -> Result<ConstValue<'tcx>, ErrorHandled> { ) -> Result<ConstValue<'tcx>, ErrorHandled> {
match self { match self {
Const::Ty(_, c) => { Const::Ty(_, c) => {
// We want to consistently have a "clean" value for type system constants (i.e., no if c.has_non_region_param() {
// data hidden in the padding), so we always go through a valtree here. return Err(ErrorHandled::TooGeneric(span));
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 match c.kind() {
.dcx() ConstKind::Value(ty, val) => Ok(tcx.valtree_to_const_val((ty, val))),
.delayed_bug("`mir::Const::eval` called on a non-valtree-compatible type") _ => Err(tcx.dcx().delayed_bug("Unevaluated `ty::Const` in MIR body").into()),
.into()),
Err(Either::Right(e)) => Err(e),
} }
} }
Const::Unevaluated(uneval, _) => { Const::Unevaluated(uneval, _) => {

View File

@ -1,4 +1,3 @@
use either::Either;
use rustc_data_structures::intern::Interned; use rustc_data_structures::intern::Interned;
use rustc_error_messages::MultiSpan; use rustc_error_messages::MultiSpan;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
@ -9,7 +8,7 @@ use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo};
use tracing::{debug, instrument}; use tracing::{debug, instrument};
use crate::middle::resolve_bound_vars as rbv; 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}; use crate::ty::{self, GenericArgs, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
mod int; mod int;
@ -18,7 +17,7 @@ mod valtree;
pub use int::*; pub use int::*;
pub use kind::*; pub use kind::*;
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; use rustc_span::{DUMMY_SP, ErrorGuaranteed};
pub use valtree::*; pub use valtree::*;
pub type ConstKind<'tcx> = ir::ConstKind<TyCtxt<'tcx>>; pub type ConstKind<'tcx> = ir::ConstKind<TyCtxt<'tcx>>;
@ -363,60 +362,6 @@ impl<'tcx> Const<'tcx> {
Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.usize)) 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 /// Panics if self.kind != ty::ConstKind::Value
pub fn to_valtree(self) -> (ty::ValTree<'tcx>, Ty<'tcx>) { pub fn to_valtree(self) -> (ty::ValTree<'tcx>, Ty<'tcx>) {
match self.kind() { match self.kind() {

View File

@ -1,46 +1,12 @@
use std::assert_matches::assert_matches; use std::assert_matches::assert_matches;
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable, extension}; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
use super::Const; use super::Const;
use crate::mir; use crate::mir;
use crate::ty::abstract_const::CastKind; use crate::ty::abstract_const::CastKind;
use crate::ty::visit::TypeVisitableExt as _;
use crate::ty::{self, Ty, TyCtxt}; use crate::ty::{self, Ty, TyCtxt};
#[extension(pub(crate) trait UnevaluatedConstEvalExt<'tcx>)]
impl<'tcx> ty::UnevaluatedConst<'tcx> {
/// FIXME(RalfJung): I cannot explain what this does or why it makes sense, but not doing this
/// hurts performance.
#[inline]
fn prepare_for_eval(
self,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> (ty::ParamEnv<'tcx>, Self) {
// HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
// also does later, but we want to do it before checking for
// inference variables.
// Note that we erase regions *before* calling `with_reveal_all_normalized`,
// so that we don't try to invoke this query with
// any region variables.
// HACK(eddyb) when the query key would contain inference variables,
// attempt using identity args and `ParamEnv` instead, that will succeed
// when the expression doesn't depend on any parameters.
// FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
// we can call `infcx.const_eval_resolve` which handles inference variables.
if (param_env, self).has_non_region_infer() {
(tcx.param_env(self.def), ty::UnevaluatedConst {
def: self.def,
args: ty::GenericArgs::identity_for_item(tcx, self.def),
})
} else {
(tcx.erase_regions(param_env).with_reveal_all_normalized(tcx), tcx.erase_regions(self))
}
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)] #[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
pub enum ExprKind { pub enum ExprKind {

View File

@ -1,14 +1,13 @@
use either::Either;
use rustc_abi::{FieldIdx, VariantIdx}; use rustc_abi::{FieldIdx, VariantIdx};
use rustc_apfloat::Float; use rustc_apfloat::Float;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_index::Idx; use rustc_index::Idx;
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::Obligation; use rustc_infer::traits::Obligation;
use rustc_middle::mir;
use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::thir::{FieldPat, Pat, PatKind}; use rustc_middle::thir::{FieldPat, Pat, PatKind};
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypingMode, ValTree}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypingMode, ValTree};
use rustc_middle::{mir, span_bug};
use rustc_span::Span; use rustc_span::Span;
use rustc_trait_selection::traits::ObligationCause; use rustc_trait_selection::traits::ObligationCause;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
@ -40,7 +39,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
// of opaques defined in this function here. // of opaques defined in this function here.
let infcx = self.tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let infcx = self.tcx.infer_ctxt().build(TypingMode::non_body_analysis());
let mut convert = ConstToPat::new(self, id, span, infcx); let mut convert = ConstToPat::new(self, id, span, infcx);
convert.to_pat(c, ty)
match c.kind() {
ty::ConstKind::Unevaluated(uv) => convert.unevaluated_to_pat(uv, ty),
ty::ConstKind::Value(_, val) => convert.valtree_to_pat(val, ty),
_ => span_bug!(span, "Invalid `ConstKind` for `const_to_pat`: {:?}", c),
}
} }
} }
@ -81,27 +85,42 @@ impl<'tcx> ConstToPat<'tcx> {
ty.is_structural_eq_shallow(self.infcx.tcx) ty.is_structural_eq_shallow(self.infcx.tcx)
} }
fn to_pat(&mut self, c: ty::Const<'tcx>, ty: Ty<'tcx>) -> Box<Pat<'tcx>> { fn unevaluated_to_pat(
&mut self,
uv: ty::UnevaluatedConst<'tcx>,
ty: Ty<'tcx>,
) -> Box<Pat<'tcx>> {
trace!(self.treat_byte_string_as_slice); trace!(self.treat_byte_string_as_slice);
let pat_from_kind = |kind| Box::new(Pat { span: self.span, ty, kind }); let pat_from_kind = |kind| Box::new(Pat { span: self.span, ty, kind });
// Get a valtree. If that fails, this const is definitely not valid for use as a pattern. // It's not *technically* correct to be revealing opaque types here as borrowcheck has
let valtree = match c.eval_valtree(self.tcx(), self.param_env, self.span) { // not run yet. However, CTFE itself uses `Reveal::All` unconditionally even during
Ok((_, valtree)) => valtree, // typeck and not doing so has a lot of (undesirable) fallout (#101478, #119821). As a
Err(Either::Right(e)) => { // result we always use a revealed env when resolving the instance to evaluate.
let err = match e { //
ErrorHandled::Reported(..) => { // FIXME: `const_eval_resolve_for_typeck` should probably just set the env to `Reveal::All`
// Let's tell the use where this failing const occurs. // instead of having this logic here
self.tcx().dcx().emit_err(CouldNotEvalConstPattern { span: self.span }) let param_env =
} self.tcx().erase_regions(self.param_env).with_reveal_all_normalized(self.tcx());
ErrorHandled::TooGeneric(_) => self let uv = self.tcx().erase_regions(uv);
.tcx()
.dcx() // try to resolve e.g. associated constants to their definition on an impl, and then
.emit_err(ConstPatternDependsOnGenericParameter { span: self.span }), // evaluate the const.
}; let valtree = match self.infcx.tcx.const_eval_resolve_for_typeck(param_env, uv, self.span) {
return pat_from_kind(PatKind::Error(err)); Ok(Ok(c)) => c,
Err(ErrorHandled::Reported(_, _)) => {
// Let's tell the use where this failing const occurs.
let e = self.tcx().dcx().emit_err(CouldNotEvalConstPattern { span: self.span });
return pat_from_kind(PatKind::Error(e));
} }
Err(Either::Left(bad_ty)) => { Err(ErrorHandled::TooGeneric(_)) => {
let e = self
.tcx()
.dcx()
.emit_err(ConstPatternDependsOnGenericParameter { span: self.span });
return pat_from_kind(PatKind::Error(e));
}
Ok(Err(bad_ty)) => {
// The pattern cannot be turned into a valtree. // The pattern cannot be turned into a valtree.
let e = match bad_ty.kind() { let e = match bad_ty.kind() {
ty::Adt(def, ..) => { ty::Adt(def, ..) => {
@ -128,8 +147,7 @@ impl<'tcx> ConstToPat<'tcx> {
if !self.type_has_partial_eq_impl(ty) { if !self.type_has_partial_eq_impl(ty) {
let err = TypeNotPartialEq { span: self.span, non_peq_ty: ty }; let err = TypeNotPartialEq { span: self.span, non_peq_ty: ty };
let e = self.tcx().dcx().emit_err(err); let e = self.tcx().dcx().emit_err(err);
let kind = PatKind::Error(e); return pat_from_kind(PatKind::Error(e));
return Box::new(Pat { span: self.span, ty, kind });
} }
} }

View File

@ -29,10 +29,10 @@ pub trait SolverDelegate: Deref<Target = <Self as SolverDelegate>::Infcx> + Size
// FIXME: Uplift the leak check into this crate. // FIXME: Uplift the leak check into this crate.
fn leak_check(&self, max_input_universe: ty::UniverseIndex) -> Result<(), NoSolution>; fn leak_check(&self, max_input_universe: ty::UniverseIndex) -> Result<(), NoSolution>;
fn try_const_eval_resolve( fn evaluate_const(
&self, &self,
param_env: <Self::Interner as Interner>::ParamEnv, param_env: <Self::Interner as Interner>::ParamEnv,
unevaluated: ty::UnevaluatedConst<Self::Interner>, uv: ty::UnevaluatedConst<Self::Interner>,
) -> Option<<Self::Interner as Interner>::Const>; ) -> Option<<Self::Interner as Interner>::Const>;
// FIXME: This only is here because `wf::obligations` is in `rustc_trait_selection`! // FIXME: This only is here because `wf::obligations` is in `rustc_trait_selection`!

View File

@ -1001,12 +1001,12 @@ where
// Try to evaluate a const, or return `None` if the const is too generic. // Try to evaluate a const, or return `None` if the const is too generic.
// This doesn't mean the const isn't evaluatable, though, and should be treated // This doesn't mean the const isn't evaluatable, though, and should be treated
// as an ambiguity rather than no-solution. // as an ambiguity rather than no-solution.
pub(super) fn try_const_eval_resolve( pub(super) fn evaluate_const(
&self, &self,
param_env: I::ParamEnv, param_env: I::ParamEnv,
unevaluated: ty::UnevaluatedConst<I>, uv: ty::UnevaluatedConst<I>,
) -> Option<I::Const> { ) -> Option<I::Const> {
self.delegate.try_const_eval_resolve(param_env, unevaluated) self.delegate.evaluate_const(param_env, uv)
} }
pub(super) fn is_transmutable( pub(super) fn is_transmutable(

View File

@ -143,7 +143,7 @@ where
) -> QueryResult<I> { ) -> QueryResult<I> {
match ct.kind() { match ct.kind() {
ty::ConstKind::Unevaluated(uv) => { ty::ConstKind::Unevaluated(uv) => {
// We never return `NoSolution` here as `try_const_eval_resolve` emits an // We never return `NoSolution` here as `evaluate_const` emits an
// error itself when failing to evaluate, so emitting an additional fulfillment // error itself when failing to evaluate, so emitting an additional fulfillment
// error in that case is unnecessary noise. This may change in the future once // error in that case is unnecessary noise. This may change in the future once
// evaluation failures are allowed to impact selection, e.g. generic const // evaluation failures are allowed to impact selection, e.g. generic const
@ -151,7 +151,7 @@ where
// FIXME(generic_const_exprs): Implement handling for generic // FIXME(generic_const_exprs): Implement handling for generic
// const expressions here. // const expressions here.
if let Some(_normalized) = self.try_const_eval_resolve(param_env, uv) { if let Some(_normalized) = self.evaluate_const(param_env, uv) {
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
} else { } else {
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)

View File

@ -14,7 +14,7 @@ where
&mut self, &mut self,
goal: Goal<I, ty::NormalizesTo<I>>, goal: Goal<I, ty::NormalizesTo<I>>,
) -> QueryResult<I> { ) -> QueryResult<I> {
if let Some(normalized_const) = self.try_const_eval_resolve( if let Some(normalized_const) = self.evaluate_const(
goal.param_env, goal.param_env,
ty::UnevaluatedConst::new(goal.predicate.alias.def_id, goal.predicate.alias.args), ty::UnevaluatedConst::new(goal.predicate.alias.def_id, goal.predicate.alias.args),
) { ) {

View File

@ -15,7 +15,7 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
use rustc_type_ir::TypingMode; use rustc_type_ir::TypingMode;
use rustc_type_ir::solve::{Certainty, NoSolution}; use rustc_type_ir::solve::{Certainty, NoSolution};
use crate::traits::specialization_graph; use crate::traits::{EvaluateConstErr, specialization_graph};
#[repr(transparent)] #[repr(transparent)]
pub struct SolverDelegate<'tcx>(InferCtxt<'tcx>); pub struct SolverDelegate<'tcx>(InferCtxt<'tcx>);
@ -77,20 +77,19 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
self.0.leak_check(max_input_universe, None).map_err(|_| NoSolution) self.0.leak_check(max_input_universe, None).map_err(|_| NoSolution)
} }
fn try_const_eval_resolve( fn evaluate_const(
&self, &self,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
unevaluated: ty::UnevaluatedConst<'tcx>, uv: ty::UnevaluatedConst<'tcx>,
) -> Option<ty::Const<'tcx>> { ) -> Option<ty::Const<'tcx>> {
use rustc_middle::mir::interpret::ErrorHandled; let ct = ty::Const::new_unevaluated(self.tcx, uv);
match self.const_eval_resolve(param_env, unevaluated, DUMMY_SP) {
Ok(Ok(val)) => Some(ty::Const::new_value( match crate::traits::try_evaluate_const(&self.0, ct, param_env) {
self.tcx, Ok(ct) => Some(ct),
val, Err(EvaluateConstErr::EvaluationFailure(e)) => Some(ty::Const::new_error(self.tcx, e)),
self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args), Err(
)), EvaluateConstErr::InvalidConstParamTy(_) | EvaluateConstErr::HasGenericsOrInfers,
Ok(Err(_)) | Err(ErrorHandled::TooGeneric(_)) => None, ) => None,
Err(ErrorHandled::Reported(e, _)) => Some(ty::Const::new_error(self.tcx, e.into())),
} }
} }

View File

@ -7,7 +7,6 @@ use std::iter;
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet, IndexEntry}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet, IndexEntry};
use rustc_data_structures::unord::UnordSet; use rustc_data_structures::unord::UnordSet;
use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::DefineOpaqueTypes;
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::{Region, RegionVid}; use rustc_middle::ty::{Region, RegionVid};
use tracing::debug; use tracing::debug;
use ty::TypingMode; use ty::TypingMode;
@ -761,23 +760,20 @@ impl<'tcx> AutoTraitFinder<'tcx> {
ty::PredicateKind::ConstEquate(c1, c2) => { ty::PredicateKind::ConstEquate(c1, c2) => {
let evaluate = |c: ty::Const<'tcx>| { let evaluate = |c: ty::Const<'tcx>| {
if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() { if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() {
match selcx.infcx.const_eval_resolve( let ct = super::try_evaluate_const(
selcx.infcx,
c,
obligation.param_env, obligation.param_env,
unevaluated, );
obligation.cause.span,
) { if let Err(EvaluateConstErr::InvalidConstParamTy(_)) = ct {
Ok(Ok(valtree)) => Ok(ty::Const::new_value(selcx.tcx(),valtree, self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args))), self.tcx.dcx().emit_err(UnableToConstructConstantValue {
Ok(Err(_)) => { span: self.tcx.def_span(unevaluated.def),
let tcx = self.tcx; unevaluated,
let reported = });
tcx.dcx().emit_err(UnableToConstructConstantValue {
span: tcx.def_span(unevaluated.def),
unevaluated,
});
Err(ErrorHandled::Reported(reported.into(), tcx.def_span(unevaluated.def)))
}
Err(err) => Err(err),
} }
ct
} else { } else {
Ok(c) Ok(c)
} }

View File

@ -12,13 +12,13 @@
use rustc_hir::def::DefKind; use rustc_hir::def::DefKind;
use rustc_infer::infer::InferCtxt; use rustc_infer::infer::InferCtxt;
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::traits::ObligationCause; use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::{self, TyCtxt, TypeVisitable, TypeVisitableExt, TypeVisitor}; use rustc_middle::ty::{self, TyCtxt, TypeVisitable, TypeVisitableExt, TypeVisitor};
use rustc_span::{DUMMY_SP, Span}; use rustc_span::{DUMMY_SP, Span};
use tracing::{debug, instrument}; use tracing::{debug, instrument};
use super::EvaluateConstErr;
use crate::traits::ObligationCtxt; use crate::traits::ObligationCtxt;
/// Check if a given constant can be evaluated. /// Check if a given constant can be evaluated.
@ -68,16 +68,18 @@ pub fn is_const_evaluatable<'tcx>(
// here. // here.
tcx.dcx().span_bug(span, "evaluating `ConstKind::Expr` is not currently supported"); tcx.dcx().span_bug(span, "evaluating `ConstKind::Expr` is not currently supported");
} }
ty::ConstKind::Unevaluated(uv) => { ty::ConstKind::Unevaluated(_) => {
let concrete = infcx.const_eval_resolve(param_env, uv, span); match crate::traits::try_evaluate_const(infcx, unexpanded_ct, param_env) {
match concrete { Err(EvaluateConstErr::HasGenericsOrInfers) => {
Err(ErrorHandled::TooGeneric(_)) => {
Err(NotConstEvaluatable::Error(infcx.dcx().span_delayed_bug( Err(NotConstEvaluatable::Error(infcx.dcx().span_delayed_bug(
span, span,
"Missing value for constant, but no error reported?", "Missing value for constant, but no error reported?",
))) )))
} }
Err(ErrorHandled::Reported(e, _)) => Err(NotConstEvaluatable::Error(e.into())), Err(
EvaluateConstErr::EvaluationFailure(e)
| EvaluateConstErr::InvalidConstParamTy(e),
) => Err(NotConstEvaluatable::Error(e.into())),
Ok(_) => Ok(()), Ok(_) => Ok(()),
} }
} }
@ -92,16 +94,7 @@ pub fn is_const_evaluatable<'tcx>(
_ => bug!("unexpected constkind in `is_const_evalautable: {unexpanded_ct:?}`"), _ => bug!("unexpected constkind in `is_const_evalautable: {unexpanded_ct:?}`"),
}; };
// FIXME: We should only try to evaluate a given constant here if it is fully concrete match crate::traits::try_evaluate_const(infcx, unexpanded_ct, param_env) {
// as we don't want to allow things like `[u8; std::mem::size_of::<*mut T>()]`.
//
// We previously did not check this, so we only emit a future compat warning if
// const evaluation succeeds and the given constant is still polymorphic for now
// and hopefully soon change this to an error.
//
// See #74595 for more details about this.
let concrete = infcx.const_eval_resolve(param_env, uv, span);
match concrete {
// If we're evaluating a generic foreign constant, under a nightly compiler while // If we're evaluating a generic foreign constant, under a nightly compiler while
// the current crate does not enable `feature(generic_const_exprs)`, abort // the current crate does not enable `feature(generic_const_exprs)`, abort
// compilation with a useful error. // compilation with a useful error.
@ -130,7 +123,7 @@ pub fn is_const_evaluatable<'tcx>(
.emit() .emit()
} }
Err(ErrorHandled::TooGeneric(_)) => { Err(EvaluateConstErr::HasGenericsOrInfers) => {
let err = if uv.has_non_region_infer() { let err = if uv.has_non_region_infer() {
NotConstEvaluatable::MentionsInfer NotConstEvaluatable::MentionsInfer
} else if uv.has_non_region_param() { } else if uv.has_non_region_param() {
@ -145,7 +138,9 @@ pub fn is_const_evaluatable<'tcx>(
Err(err) Err(err)
} }
Err(ErrorHandled::Reported(e, _)) => Err(NotConstEvaluatable::Error(e.into())), Err(
EvaluateConstErr::EvaluationFailure(e) | EvaluateConstErr::InvalidConstParamTy(e),
) => Err(NotConstEvaluatable::Error(e.into())),
Ok(_) => Ok(()), Ok(_) => Ok(()),
} }
} }

View File

@ -10,7 +10,6 @@ use rustc_infer::traits::{
TraitEngine, TraitEngine,
}; };
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt, TypingMode}; use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt, TypingMode};
@ -26,6 +25,7 @@ use super::{
}; };
use crate::error_reporting::InferCtxtErrorExt; use crate::error_reporting::InferCtxtErrorExt;
use crate::infer::{InferCtxt, TyOrConstInferVar}; use crate::infer::{InferCtxt, TyOrConstInferVar};
use crate::traits::EvaluateConstErr;
use crate::traits::normalize::normalize_with_depth_to; use crate::traits::normalize::normalize_with_depth_to;
use crate::traits::project::{PolyProjectionObligation, ProjectionCacheKeyExt as _}; use crate::traits::project::{PolyProjectionObligation, ProjectionCacheKeyExt as _};
use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::query::evaluate_obligation::InferCtxtExt;
@ -664,23 +664,25 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
let mut evaluate = |c: Const<'tcx>| { let mut evaluate = |c: Const<'tcx>| {
if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() { if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() {
match self.selcx.infcx.try_const_eval_resolve( match super::try_evaluate_const(
self.selcx.infcx,
c,
obligation.param_env, obligation.param_env,
unevaluated,
obligation.cause.span,
) { ) {
Ok(val) => Ok(val), Ok(val) => Ok(val),
Err(e) => { e @ Err(EvaluateConstErr::HasGenericsOrInfers) => {
match e { stalled_on.extend(
ErrorHandled::TooGeneric(..) => { unevaluated
stalled_on.extend(unevaluated.args.iter().filter_map( .args
TyOrConstInferVar::maybe_from_generic_arg, .iter()
)); .filter_map(TyOrConstInferVar::maybe_from_generic_arg),
} );
_ => {} e
}
Err(e)
} }
e @ Err(
EvaluateConstErr::EvaluationFailure(_)
| EvaluateConstErr::InvalidConstParamTy(_),
) => e,
} }
} else { } else {
Ok(c) Ok(c)
@ -707,14 +709,20 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
} }
} }
} }
(Err(ErrorHandled::Reported(reported, _)), _) (Err(EvaluateConstErr::InvalidConstParamTy(e)), _)
| (_, Err(ErrorHandled::Reported(reported, _))) => ProcessResult::Error( | (_, Err(EvaluateConstErr::InvalidConstParamTy(e))) => {
FulfillmentErrorCode::Select(SelectionError::NotConstEvaluatable( ProcessResult::Error(FulfillmentErrorCode::Select(
NotConstEvaluatable::Error(reported.into()), SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(e)),
)), ))
), }
(Err(ErrorHandled::TooGeneric(_)), _) (Err(EvaluateConstErr::EvaluationFailure(e)), _)
| (_, Err(ErrorHandled::TooGeneric(_))) => { | (_, Err(EvaluateConstErr::EvaluationFailure(e))) => {
ProcessResult::Error(FulfillmentErrorCode::Select(
SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(e)),
))
}
(Err(EvaluateConstErr::HasGenericsOrInfers), _)
| (_, Err(EvaluateConstErr::HasGenericsOrInfers)) => {
if c1.has_non_region_infer() || c2.has_non_region_infer() { if c1.has_non_region_infer() || c2.has_non_region_infer() {
ProcessResult::Unchanged ProcessResult::Unchanged
} else { } else {

View File

@ -27,6 +27,7 @@ use std::fmt::Debug;
use std::ops::ControlFlow; use std::ops::ControlFlow;
use rustc_errors::ErrorGuaranteed; use rustc_errors::ErrorGuaranteed;
use rustc_hir::def::DefKind;
pub use rustc_infer::traits::*; pub use rustc_infer::traits::*;
use rustc_middle::query::Providers; use rustc_middle::query::Providers;
use rustc_middle::span_bug; use rustc_middle::span_bug;
@ -34,11 +35,11 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
use rustc_middle::ty::{ use rustc_middle::ty::{
self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFolder, TypeSuperVisitable, TypingMode, self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFolder, TypeSuperFoldable,
Upcast, TypeSuperVisitable, TypingMode, Upcast,
}; };
use rustc_span::Span;
use rustc_span::def_id::DefId; use rustc_span::def_id::DefId;
use rustc_span::{DUMMY_SP, Span};
use tracing::{debug, instrument}; use tracing::{debug, instrument};
pub use self::coherence::{ pub use self::coherence::{
@ -366,11 +367,23 @@ pub fn normalize_param_env_or_error<'tcx>(
if c.has_escaping_bound_vars() { if c.has_escaping_bound_vars() {
return ty::Const::new_misc_error(self.0); return ty::Const::new_misc_error(self.0);
} }
// While it is pretty sus to be evaluating things with an empty param env, it // While it is pretty sus to be evaluating things with an empty param env, it
// should actually be okay since without `feature(generic_const_exprs)` the only // should actually be okay since without `feature(generic_const_exprs)` the only
// const arguments that have a non-empty param env are array repeat counts. These // const arguments that have a non-empty param env are array repeat counts. These
// do not appear in the type system though. // do not appear in the type system though.
c.normalize_internal(self.0, ty::ParamEnv::empty()) if let ty::ConstKind::Unevaluated(uv) = c.kind()
&& self.0.def_kind(uv.def) == DefKind::AnonConst
{
let infcx = self.0.infer_ctxt().build(TypingMode::non_body_analysis());
let c = evaluate_const(&infcx, c, ty::ParamEnv::empty());
// We should never wind up with any `infcx` local state when normalizing anon consts
// under min const generics.
assert!(!c.has_infer() && !c.has_placeholders());
return c;
}
c
} }
} }
@ -474,6 +487,198 @@ pub fn normalize_param_env_or_error<'tcx>(
ty::ParamEnv::new(tcx.mk_clauses(&predicates), unnormalized_env.reveal()) ty::ParamEnv::new(tcx.mk_clauses(&predicates), unnormalized_env.reveal())
} }
#[derive(Debug)]
pub enum EvaluateConstErr {
/// The constant being evaluated was either a generic parameter or inference variable, *or*,
/// some unevaluated constant with either generic parameters or inference variables in its
/// generic arguments.
HasGenericsOrInfers,
/// The type this constant evalauted to is not valid for use in const generics. This should
/// always result in an error when checking the constant is correctly typed for the parameter
/// it is an argument to, so a bug is delayed when encountering this.
InvalidConstParamTy(ErrorGuaranteed),
/// CTFE failed to evaluate the constant in some unrecoverable way (e.g. encountered a `panic!`).
/// This is also used when the constant was already tainted by error.
EvaluationFailure(ErrorGuaranteed),
}
// FIXME(BoxyUwU): Private this once we `generic_const_exprs` isn't doing its own normalization routine
// FIXME(generic_const_exprs): Consider accepting a `ty::UnevaluatedConst` when we are not rolling our own
// normalization scheme
/// Evaluates a type system constant returning a `ConstKind::Error` in cases where CTFE failed and
/// returning the passed in constant if it was not fully concrete (i.e. depended on generic parameters
/// or inference variables)
///
/// You should not call this function unless you are implementing normalization itself. Prefer to use
/// `normalize_erasing_regions` or the `normalize` functions on `ObligationCtxt`/`FnCtxt`/`InferCtxt`.
pub fn evaluate_const<'tcx>(
infcx: &InferCtxt<'tcx>,
ct: ty::Const<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> ty::Const<'tcx> {
match try_evaluate_const(infcx, ct, param_env) {
Ok(ct) => ct,
Err(EvaluateConstErr::EvaluationFailure(e) | EvaluateConstErr::InvalidConstParamTy(e)) => {
ty::Const::new_error(infcx.tcx, e)
}
Err(EvaluateConstErr::HasGenericsOrInfers) => ct,
}
}
// FIXME(BoxyUwU): Private this once we `generic_const_exprs` isn't doing its own normalization routine
// FIXME(generic_const_exprs): Consider accepting a `ty::UnevaluatedConst` when we are not rolling our own
// normalization scheme
/// Evaluates a type system constant making sure to not allow constants that depend on generic parameters
/// or inference variables to succeed in evaluating.
///
/// You should not call this function unless you are implementing normalization itself. Prefer to use
/// `normalize_erasing_regions` or the `normalize` functions on `ObligationCtxt`/`FnCtxt`/`InferCtxt`.
#[instrument(level = "debug", skip(infcx), ret)]
pub fn try_evaluate_const<'tcx>(
infcx: &InferCtxt<'tcx>,
ct: ty::Const<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> Result<ty::Const<'tcx>, EvaluateConstErr> {
let tcx = infcx.tcx;
let ct = infcx.resolve_vars_if_possible(ct);
debug!(?ct);
match ct.kind() {
ty::ConstKind::Value(..) => Ok(ct),
ty::ConstKind::Error(e) => Err(EvaluateConstErr::EvaluationFailure(e)),
ty::ConstKind::Param(_)
| ty::ConstKind::Infer(_)
| ty::ConstKind::Bound(_, _)
| ty::ConstKind::Placeholder(_)
| ty::ConstKind::Expr(_) => Err(EvaluateConstErr::HasGenericsOrInfers),
ty::ConstKind::Unevaluated(uv) => {
// Postpone evaluation of constants that depend on generic parameters or inference variables.
let (args, param_env) = if tcx.features().generic_const_exprs()
&& uv.has_non_region_infer()
{
// `feature(generic_const_exprs)` causes anon consts to inherit all parent generics. This can cause
// inference variables and generic parameters to show up in `ty::Const` even though the anon const
// does not actually make use of them. We handle this case specially and attempt to evaluate anyway.
match tcx.thir_abstract_const(uv.def) {
Ok(Some(ct)) => {
let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, uv.args));
if let Err(e) = ct.error_reported() {
return Err(EvaluateConstErr::EvaluationFailure(e));
} else if ct.has_non_region_infer() || ct.has_non_region_param() {
// If the anon const *does* actually use generic parameters or inference variables from
// the generic arguments provided for it, then we should *not* attempt to evaluate it.
return Err(EvaluateConstErr::HasGenericsOrInfers);
} else {
(replace_param_and_infer_args_with_placeholder(tcx, uv.args), param_env)
}
}
Err(_) | Ok(None) => {
let args = GenericArgs::identity_for_item(tcx, uv.def);
let param_env = tcx.param_env(uv.def);
(args, param_env)
}
}
} else {
// FIXME: We don't check anything on stable as the only way we can wind up with
// an unevaluated constant containing generic parameters is through array repeat
// expression counts which have a future compat lint for usage of generic parameters
// instead of a hard error.
//
// This codepath is however also reachable by `generic_const_exprs` and some other
// feature gates which allow constants in the type system to use generic parameters.
// In theory we should be checking for generic parameters here and returning an error
// in such cases.
(uv.args, param_env)
};
let uv = ty::UnevaluatedConst::new(uv.def, args);
// It's not *technically* correct to be revealing opaque types here as we could still be
// before borrowchecking. However, CTFE itself uses `Reveal::All` unconditionally even during
// typeck and not doing so has a lot of (undesirable) fallout (#101478, #119821). As a result we
// always use a revealed env when resolving the instance to evaluate.
//
// FIXME: `const_eval_resolve_for_typeck` should probably just set the env to `Reveal::All`
// instead of having this logic here
let env = tcx.erase_regions(param_env).with_reveal_all_normalized(tcx);
let erased_uv = tcx.erase_regions(uv);
use rustc_middle::mir::interpret::ErrorHandled;
match tcx.const_eval_resolve_for_typeck(env, erased_uv, DUMMY_SP) {
Ok(Ok(val)) => Ok(ty::Const::new_value(
tcx,
val,
tcx.type_of(uv.def).instantiate(tcx, uv.args),
)),
Ok(Err(_)) => {
let e = tcx.dcx().delayed_bug(
"Type system constant with non valtree'able type evaluated but no error emitted",
);
Err(EvaluateConstErr::InvalidConstParamTy(e))
}
Err(ErrorHandled::Reported(info, _)) => {
Err(EvaluateConstErr::EvaluationFailure(info.into()))
}
Err(ErrorHandled::TooGeneric(_)) => Err(EvaluateConstErr::HasGenericsOrInfers),
}
}
}
}
/// 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 })
}
/// Normalizes the predicates and checks whether they hold in an empty environment. If this /// Normalizes the predicates and checks whether they hold in an empty environment. If this
/// returns true, then either normalize encountered an error or one of the predicates did not /// returns true, then either normalize encountered an error or one of the predicates did not
/// hold. Used when creating vtables to check for unsatisfiable methods. This should not be /// hold. Used when creating vtables to check for unsatisfiable methods. This should not be

View File

@ -418,8 +418,9 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
self.selcx.infcx, self.selcx.infcx,
&mut self.universes, &mut self.universes,
constant, constant,
|constant| constant.normalize_internal(tcx, self.param_env), |constant| super::evaluate_const(self.selcx.infcx, constant, self.param_env),
) )
.super_fold_with(self)
} }
} }

View File

@ -342,7 +342,7 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> {
self.infcx, self.infcx,
&mut self.universes, &mut self.universes,
constant, constant,
|constant| constant.normalize_internal(self.infcx.tcx, self.param_env), |constant| crate::traits::evaluate_const(&self.infcx, constant, self.param_env),
); );
debug!(?constant, ?self.param_env); debug!(?constant, ?self.param_env);
constant.try_super_fold_with(self) constant.try_super_fold_with(self)

View File

@ -403,7 +403,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let mut assume = predicate.trait_ref.args.const_at(2); let mut assume = predicate.trait_ref.args.const_at(2);
// FIXME(min_generic_const_exprs): We should shallowly normalize this. // FIXME(min_generic_const_exprs): We should shallowly normalize this.
if self.tcx().features().generic_const_exprs() { if self.tcx().features().generic_const_exprs() {
assume = assume.normalize_internal(self.tcx(), obligation.param_env); assume = crate::traits::evaluate_const(self.infcx, assume, obligation.param_env)
} }
let Some(assume) = let Some(assume) =
rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, assume) rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, assume)

View File

@ -22,7 +22,6 @@ use rustc_infer::infer::relate::TypeRelation;
use rustc_infer::traits::{PredicateObligations, TraitObligation}; use rustc_infer::traits::{PredicateObligations, TraitObligation};
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::dep_graph::{DepNodeIndex, dep_kinds}; use rustc_middle::dep_graph::{DepNodeIndex, dep_kinds};
use rustc_middle::mir::interpret::ErrorHandled;
pub use rustc_middle::traits::select::*; pub use rustc_middle::traits::select::*;
use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::error::TypeErrorToStringExt; use rustc_middle::ty::error::TypeErrorToStringExt;
@ -50,7 +49,7 @@ use crate::infer::{InferCtxt, InferOk, TypeFreshener};
use crate::solve::InferCtxtSelectExt as _; use crate::solve::InferCtxtSelectExt as _;
use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to}; use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to};
use crate::traits::project::{ProjectAndUnifyResult, ProjectionCacheKeyExt}; use crate::traits::project::{ProjectAndUnifyResult, ProjectionCacheKeyExt};
use crate::traits::{ProjectionCacheKey, Unimplemented, effects}; use crate::traits::{EvaluateConstErr, ProjectionCacheKey, Unimplemented, effects};
mod _match; mod _match;
mod candidate_assembly; mod candidate_assembly;
@ -931,11 +930,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
} }
let evaluate = |c: ty::Const<'tcx>| { let evaluate = |c: ty::Const<'tcx>| {
if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() { if let ty::ConstKind::Unevaluated(_) = c.kind() {
match self.infcx.try_const_eval_resolve( match crate::traits::try_evaluate_const(
self.infcx,
c,
obligation.param_env, obligation.param_env,
unevaluated,
obligation.cause.span,
) { ) {
Ok(val) => Ok(val), Ok(val) => Ok(val),
Err(e) => Err(e), Err(e) => Err(e),
@ -961,10 +960,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
Err(_) => Ok(EvaluatedToErr), Err(_) => Ok(EvaluatedToErr),
} }
} }
(Err(ErrorHandled::Reported(..)), _) (Err(EvaluateConstErr::InvalidConstParamTy(..)), _)
| (_, Err(ErrorHandled::Reported(..))) => Ok(EvaluatedToErr), | (_, Err(EvaluateConstErr::InvalidConstParamTy(..))) => Ok(EvaluatedToErr),
(Err(ErrorHandled::TooGeneric(..)), _) (Err(EvaluateConstErr::EvaluationFailure(..)), _)
| (_, Err(ErrorHandled::TooGeneric(..))) => { | (_, Err(EvaluateConstErr::EvaluationFailure(..))) => Ok(EvaluatedToErr),
(Err(EvaluateConstErr::HasGenericsOrInfers), _)
| (_, Err(EvaluateConstErr::HasGenericsOrInfers)) => {
if c1.has_non_region_infer() || c2.has_non_region_infer() { if c1.has_non_region_infer() || c2.has_non_region_infer() {
Ok(EvaluatedToAmbig) Ok(EvaluatedToAmbig)
} else { } else {

View File

@ -83,7 +83,7 @@ impl<'tcx> At<'_, 'tcx> {
Ok(self.infcx.resolve_vars_if_possible(new_infer_ct)) Ok(self.infcx.resolve_vars_if_possible(new_infer_ct))
} else if self.infcx.tcx.features().generic_const_exprs() { } else if self.infcx.tcx.features().generic_const_exprs() {
Ok(ct.normalize_internal(self.infcx.tcx, self.param_env)) Ok(super::evaluate_const(&self.infcx, ct, self.param_env))
} else { } else {
Ok(self.normalize(ct).into_value_registering_obligations(self.infcx, fulfill_cx)) Ok(self.normalize(ct).into_value_registering_obligations(self.infcx, fulfill_cx))
} }

View File

@ -3,8 +3,8 @@
//! Rust memory safety is based on this rule: Given an object `T`, it is only possible to //! Rust memory safety is based on this rule: Given an object `T`, it is only possible to
//! have one of the following: //! have one of the following:
//! //!
//! - Having several immutable references (`&T`) to the object (also known as **aliasing**). //! - Several immutable references (`&T`) to the object (also known as **aliasing**).
//! - Having one mutable reference (`&mut T`) to the object (also known as **mutability**). //! - One mutable reference (`&mut T`) to the object (also known as **mutability**).
//! //!
//! This is enforced by the Rust compiler. However, there are situations where this rule is not //! This is enforced by the Rust compiler. However, there are situations where this rule is not
//! flexible enough. Sometimes it is required to have multiple references to an object and yet //! flexible enough. Sometimes it is required to have multiple references to an object and yet

View File

@ -251,7 +251,7 @@ impl<T: ?Sized> NonNull<T> {
#[unstable(feature = "ptr_metadata", issue = "81513")] #[unstable(feature = "ptr_metadata", issue = "81513")]
#[inline] #[inline]
pub const fn from_raw_parts( pub const fn from_raw_parts(
data_pointer: NonNull<()>, data_pointer: NonNull<impl super::Thin>,
metadata: <T as super::Pointee>::Metadata, metadata: <T as super::Pointee>::Metadata,
) -> NonNull<T> { ) -> NonNull<T> {
// SAFETY: The result of `ptr::from::raw_parts_mut` is non-null because `data_pointer` is. // SAFETY: The result of `ptr::from::raw_parts_mut` is non-null because `data_pointer` is.

View File

@ -5,6 +5,7 @@ Run these with `x test bootstrap`, or `python -m unittest src/bootstrap/bootstra
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
import os import os
import unittest import unittest
from unittest.mock import patch
import tempfile import tempfile
import hashlib import hashlib
import sys import sys
@ -99,6 +100,52 @@ class ProgramOutOfDate(unittest.TestCase):
self.assertFalse(self.build.program_out_of_date(self.rustc_stamp_path, self.key)) self.assertFalse(self.build.program_out_of_date(self.rustc_stamp_path, self.key))
class ParseArgsInConfigure(unittest.TestCase):
"""Test if `parse_args` function in `configure.py` works properly"""
@patch("configure.err")
def test_unknown_args(self, err):
# It should be print an error message if the argument doesn't start with '--'
configure.parse_args(["enable-full-tools"])
err.assert_called_with("Option 'enable-full-tools' is not recognized")
err.reset_mock()
# It should be print an error message if the argument is not recognized
configure.parse_args(["--some-random-flag"])
err.assert_called_with("Option '--some-random-flag' is not recognized")
@patch("configure.err")
def test_need_value_args(self, err):
"""It should print an error message if a required argument value is missing"""
configure.parse_args(["--target"])
err.assert_called_with("Option '--target' needs a value (--target=val)")
@patch("configure.err")
def test_option_checking(self, err):
# Options should be checked even if `--enable-option-checking` is not passed
configure.parse_args(["--target"])
err.assert_called_with("Option '--target' needs a value (--target=val)")
err.reset_mock()
# Options should be checked if `--enable-option-checking` is passed
configure.parse_args(["--enable-option-checking", "--target"])
err.assert_called_with("Option '--target' needs a value (--target=val)")
err.reset_mock()
# Options should not be checked if `--disable-option-checking` is passed
configure.parse_args(["--disable-option-checking", "--target"])
err.assert_not_called()
@patch("configure.parse_example_config", lambda known_args, _: known_args)
def test_known_args(self):
# It should contain known and correct arguments
known_args = configure.parse_args(["--enable-full-tools"])
self.assertTrue(known_args["full-tools"][0][1])
known_args = configure.parse_args(["--disable-full-tools"])
self.assertFalse(known_args["full-tools"][0][1])
# It should contain known arguments and their values
known_args = configure.parse_args(["--target=x86_64-unknown-linux-gnu"])
self.assertEqual(known_args["target"][0][1], "x86_64-unknown-linux-gnu")
known_args = configure.parse_args(["--target", "x86_64-unknown-linux-gnu"])
self.assertEqual(known_args["target"][0][1], "x86_64-unknown-linux-gnu")
class GenerateAndParseConfig(unittest.TestCase): class GenerateAndParseConfig(unittest.TestCase):
"""Test that we can serialize and deserialize a config.toml file""" """Test that we can serialize and deserialize a config.toml file"""
def test_no_args(self): def test_no_args(self):

View File

@ -56,7 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays {
&& !item.span.from_expansion() && !item.span.from_expansion()
&& let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
&& let ty::Array(element_type, cst) = ty.kind() && let ty::Array(element_type, cst) = ty.kind()
&& let Ok((_, ty::ValTree::Leaf(element_count))) = cst.eval_valtree(cx.tcx, ParamEnv::empty(), item.span) && let Some((ty::ValTree::Leaf(element_count), _)) = cx.tcx.try_normalize_erasing_regions(ParamEnv::empty(), *cst).unwrap_or(*cst).try_to_valtree()
&& let element_count = element_count.to_target_usize(cx.tcx) && let element_count = element_count.to_target_usize(cx.tcx)
&& let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()) && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes())
&& u128::from(self.maximum_allowed_size) < u128::from(element_count) * u128::from(element_size) && u128::from(self.maximum_allowed_size) < u128::from(element_count) * u128::from(element_size)

View File

@ -53,7 +53,6 @@ jobs:
cargo workspaces rename --from project-model project_model cargo workspaces rename --from project-model project_model
cargo workspaces rename --from test-fixture test_fixture cargo workspaces rename --from test-fixture test_fixture
cargo workspaces rename --from test-utils test_utils cargo workspaces rename --from test-utils test_utils
cargo workspaces rename --from text-edit text_edit
# Remove library crates from the workspaces so we don't auto-publish them as well # Remove library crates from the workspaces so we don't auto-publish them as well
sed -i 's/ "lib\/\*",//' ./Cargo.toml sed -i 's/ "lib\/\*",//' ./Cargo.toml
cargo workspaces rename ra_ap_%n cargo workspaces rename ra_ap_%n

View File

@ -13,7 +13,6 @@ use syntax::{ast, Parse};
use triomphe::Arc; use triomphe::Arc;
use crate::{ use crate::{
attr::Attrs,
db::DefDatabase, db::DefDatabase,
expander::{Expander, Mark}, expander::{Expander, Mark},
item_tree::{self, AssocItem, FnFlags, ItemTree, ItemTreeId, MacroCall, ModItem, TreeId}, item_tree::{self, AssocItem, FnFlags, ItemTree, ItemTreeId, MacroCall, ModItem, TreeId},
@ -37,8 +36,6 @@ pub struct FunctionData {
pub name: Name, pub name: Name,
pub params: Box<[TypeRefId]>, pub params: Box<[TypeRefId]>,
pub ret_type: TypeRefId, pub ret_type: TypeRefId,
// FIXME: why are these stored here? They should be accessed via the query
pub attrs: Attrs,
pub visibility: RawVisibility, pub visibility: RawVisibility,
pub abi: Option<Symbol>, pub abi: Option<Symbol>,
pub legacy_const_generics_indices: Option<Box<Box<[u32]>>>, pub legacy_const_generics_indices: Option<Box<Box<[u32]>>>,
@ -115,7 +112,6 @@ impl FunctionData {
.filter_map(|(_, param)| param.type_ref) .filter_map(|(_, param)| param.type_ref)
.collect(), .collect(),
ret_type: func.ret_type, ret_type: func.ret_type,
attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()),
visibility, visibility,
abi: func.abi.clone(), abi: func.abi.clone(),
legacy_const_generics_indices, legacy_const_generics_indices,

View File

@ -632,6 +632,19 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_safe_intrinsic, Normal, template!(Word), WarnFollowing, rustc_safe_intrinsic, Normal, template!(Word), WarnFollowing,
"the `#[rustc_safe_intrinsic]` attribute is used internally to mark intrinsics as safe" "the `#[rustc_safe_intrinsic]` attribute is used internally to mark intrinsics as safe"
), ),
rustc_attr!(
rustc_intrinsic, Normal, template!(Word), ErrorFollowing,
"the `#[rustc_intrinsic]` attribute is used to declare intrinsics with function bodies",
),
rustc_attr!(
rustc_no_mir_inline, Normal, template!(Word), WarnFollowing,
"#[rustc_no_mir_inline] prevents the MIR inliner from inlining a function while not affecting codegen"
),
rustc_attr!(
rustc_intrinsic_must_be_overridden, Normal, template!(Word), ErrorFollowing,
"the `#[rustc_intrinsic_must_be_overridden]` attribute is used to declare intrinsics without real bodies",
),
rustc_attr!( rustc_attr!(
rustc_deprecated_safe_2024, Normal, template!(Word), WarnFollowing, rustc_deprecated_safe_2024, Normal, template!(Word), WarnFollowing,
"the `#[rustc_safe_intrinsic]` marks functions as unsafe in Rust 2024", "the `#[rustc_safe_intrinsic]` marks functions as unsafe in Rust 2024",

View File

@ -381,8 +381,9 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
TyKind::Error.intern(Interner) TyKind::Error.intern(Interner)
} }
// object safety was renamed to dyn-compatibility but still remains here in chalk.
// This will be removed since we are going to migrate to next-gen trait solver.
fn is_object_safe(&self, trait_id: chalk_ir::TraitId<Interner>) -> bool { fn is_object_safe(&self, trait_id: chalk_ir::TraitId<Interner>) -> bool {
// FIXME: When cargo is updated, change to dyn_compatibility
let trait_ = from_chalk_trait_id(trait_id); let trait_ = from_chalk_trait_id(trait_id);
crate::dyn_compatibility::dyn_compatibility(self.db, trait_).is_none() crate::dyn_compatibility::dyn_compatibility(self.db, trait_).is_none()
} }

View File

@ -4,9 +4,8 @@ use super::*;
fn size_of() { fn size_of() {
check_number( check_number(
r#" r#"
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn size_of<T>() -> usize; pub fn size_of<T>() -> usize;
}
const GOAL: usize = size_of::<i32>(); const GOAL: usize = size_of::<i32>();
"#, "#,
@ -19,9 +18,8 @@ fn size_of_val() {
check_number( check_number(
r#" r#"
//- minicore: coerce_unsized //- minicore: coerce_unsized
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
}
struct X(i32, u8); struct X(i32, u8);
@ -32,9 +30,8 @@ fn size_of_val() {
check_number( check_number(
r#" r#"
//- minicore: coerce_unsized //- minicore: coerce_unsized
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
}
const GOAL: usize = { const GOAL: usize = {
let it: &[i32] = &[1, 2, 3]; let it: &[i32] = &[1, 2, 3];
@ -48,9 +45,8 @@ fn size_of_val() {
//- minicore: coerce_unsized, transmute //- minicore: coerce_unsized, transmute
use core::mem::transmute; use core::mem::transmute;
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
}
struct X { struct X {
x: i64, x: i64,
@ -70,9 +66,8 @@ fn size_of_val() {
//- minicore: coerce_unsized, transmute //- minicore: coerce_unsized, transmute
use core::mem::transmute; use core::mem::transmute;
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
}
struct X { struct X {
x: i32, x: i32,
@ -90,9 +85,8 @@ fn size_of_val() {
check_number( check_number(
r#" r#"
//- minicore: coerce_unsized, fmt, builtin_impls, dispatch_from_dyn //- minicore: coerce_unsized, fmt, builtin_impls, dispatch_from_dyn
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
}
const GOAL: usize = { const GOAL: usize = {
let x: &i16 = &5; let x: &i16 = &5;
@ -106,9 +100,8 @@ fn size_of_val() {
check_number( check_number(
r#" r#"
//- minicore: coerce_unsized //- minicore: coerce_unsized
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
}
const GOAL: usize = { const GOAL: usize = {
size_of_val("salam") size_of_val("salam")
@ -123,9 +116,8 @@ fn min_align_of_val() {
check_number( check_number(
r#" r#"
//- minicore: coerce_unsized //- minicore: coerce_unsized
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize; pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize;
}
struct X(i32, u8); struct X(i32, u8);
@ -136,9 +128,8 @@ fn min_align_of_val() {
check_number( check_number(
r#" r#"
//- minicore: coerce_unsized //- minicore: coerce_unsized
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize; pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize;
}
const GOAL: usize = { const GOAL: usize = {
let x: &[i32] = &[1, 2, 3]; let x: &[i32] = &[1, 2, 3];
@ -153,9 +144,8 @@ fn min_align_of_val() {
fn type_name() { fn type_name() {
check_str( check_str(
r#" r#"
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn type_name<T: ?Sized>() -> &'static str; pub fn type_name<T: ?Sized>() -> &'static str;
}
const GOAL: &str = type_name::<i32>(); const GOAL: &str = type_name::<i32>();
"#, "#,
@ -163,9 +153,8 @@ fn type_name() {
); );
check_str( check_str(
r#" r#"
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn type_name<T: ?Sized>() -> &'static str; pub fn type_name<T: ?Sized>() -> &'static str;
}
mod mod1 { mod mod1 {
pub mod mod2 { pub mod mod2 {
@ -183,9 +172,8 @@ fn type_name() {
fn transmute() { fn transmute() {
check_number( check_number(
r#" r#"
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn transmute<T, U>(e: T) -> U; pub fn transmute<T, U>(e: T) -> U;
}
const GOAL: i32 = transmute((1i16, 1i16)); const GOAL: i32 = transmute((1i16, 1i16));
"#, "#,
@ -197,10 +185,10 @@ fn transmute() {
fn read_via_copy() { fn read_via_copy() {
check_number( check_number(
r#" r#"
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn read_via_copy<T>(e: *const T) -> T; pub fn read_via_copy<T>(e: *const T) -> T;
pub fn volatile_load<T>(e: *const T) -> T; #[rustc_intrinsic]
} pub fn volatile_load<T>(e: *const T) -> T;
const GOAL: i32 = { const GOAL: i32 = {
let x = 2; let x = 2;
@ -399,9 +387,14 @@ fn discriminant_value() {
fn likely() { fn likely() {
check_number( check_number(
r#" r#"
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn likely(b: bool) -> bool; pub const fn likely(b: bool) -> bool {
pub fn unlikely(b: bool) -> bool; b
}
#[rustc_intrinsic]
pub const fn unlikely(b: bool) -> bool {
b
} }
const GOAL: bool = likely(true) && unlikely(true) && !likely(false) && !unlikely(false); const GOAL: bool = likely(true) && unlikely(true) && !likely(false) && !unlikely(false);
@ -704,9 +697,8 @@ fn rotate() {
); );
check_number( check_number(
r#" r#"
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn rotate_right<T: Copy>(x: T, y: T) -> T; pub fn rotate_right<T: Copy>(x: T, y: T) -> T;
}
const GOAL: i32 = rotate_right(10006016, 1020315); const GOAL: i32 = rotate_right(10006016, 1020315);
"#, "#,
@ -721,9 +713,8 @@ fn simd() {
pub struct i8x16( pub struct i8x16(
i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8, i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,
); );
extern "platform-intrinsic" { #[rustc_intrinsic]
pub fn simd_bitmask<T, U>(x: T) -> U; pub fn simd_bitmask<T, U>(x: T) -> U;
}
const GOAL: u16 = simd_bitmask(i8x16( const GOAL: u16 = simd_bitmask(i8x16(
0, 1, 0, 0, 2, 255, 100, 0, 50, 0, 1, 1, 0, 0, 0, 0 0, 1, 0, 0, 2, 255, 100, 0, 50, 0, 1, 1, 0, 0, 0, 0
)); ));
@ -735,10 +726,10 @@ fn simd() {
pub struct i8x16( pub struct i8x16(
i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8, i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,
); );
extern "platform-intrinsic" { #[rustc_intrinsic]
pub fn simd_lt<T, U>(x: T, y: T) -> U; pub fn simd_lt<T, U>(x: T, y: T) -> U;
pub fn simd_bitmask<T, U>(x: T) -> U; #[rustc_intrinsic]
} pub fn simd_bitmask<T, U>(x: T) -> U;
const GOAL: u16 = simd_bitmask(simd_lt::<i8x16, i8x16>( const GOAL: u16 = simd_bitmask(simd_lt::<i8x16, i8x16>(
i8x16( i8x16(
-105, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 -105, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10

View File

@ -201,7 +201,7 @@ impl<'a> DeclValidator<'a> {
// Don't run the lint on extern "[not Rust]" fn items with the // Don't run the lint on extern "[not Rust]" fn items with the
// #[no_mangle] attribute. // #[no_mangle] attribute.
let no_mangle = data.attrs.by_key(&sym::no_mangle).exists(); let no_mangle = self.db.attrs(func.into()).by_key(&sym::no_mangle).exists();
if no_mangle && data.abi.as_ref().is_some_and(|abi| *abi != sym::Rust) { if no_mangle && data.abi.as_ref().is_some_and(|abi| *abi != sym::Rust) {
cov_mark::hit!(extern_func_no_mangle_ignored); cov_mark::hit!(extern_func_no_mangle_ignored);
} else { } else {

View File

@ -472,7 +472,7 @@ fn receiver_is_dispatchable(
return false; return false;
}; };
// `self: Self` can't be dispatched on, but this is already considered dyn compatible // `self: Self` can't be dispatched on, but this is already considered dyn-compatible
// See rustc's comment on https://github.com/rust-lang/rust/blob/3f121b9461cce02a703a0e7e450568849dfaa074/compiler/rustc_trait_selection/src/traits/object_safety.rs#L433-L437 // See rustc's comment on https://github.com/rust-lang/rust/blob/3f121b9461cce02a703a0e7e450568849dfaa074/compiler/rustc_trait_selection/src/traits/object_safety.rs#L433-L437
if sig if sig
.skip_binders() .skip_binders()

View File

@ -66,7 +66,7 @@ fn check_dyn_compatibility<'a>(
}); });
ControlFlow::Continue(()) ControlFlow::Continue(())
}); });
assert_eq!(osvs, expected, "Dyn Compatibility violations for `{name}` do not match;"); assert_eq!(osvs, expected, "dyn-compatibility violations for `{name}` do not match;");
} }
let remains: Vec<_> = expected.keys().collect(); let remains: Vec<_> = expected.keys().collect();

View File

@ -98,7 +98,7 @@ pub use mapping::{
}; };
pub use method_resolution::check_orphan_rules; pub use method_resolution::check_orphan_rules;
pub use traits::TraitEnvironment; pub use traits::TraitEnvironment;
pub use utils::{all_super_traits, is_fn_unsafe_to_call}; pub use utils::{all_super_traits, direct_super_traits, is_fn_unsafe_to_call};
pub use chalk_ir::{ pub use chalk_ir::{
cast::Cast, cast::Cast,

View File

@ -9,7 +9,7 @@ use hir_def::{
resolver::HasResolver, resolver::HasResolver,
}; };
use hir_expand::name::Name; use hir_expand::name::Name;
use intern::sym; use intern::{sym, Symbol};
use crate::{ use crate::{
error_lifetime, error_lifetime,
@ -54,49 +54,32 @@ impl Evaluator<'_> {
} }
let function_data = self.db.function_data(def); let function_data = self.db.function_data(def);
let is_intrinsic = match &function_data.abi { let attrs = self.db.attrs(def.into());
Some(abi) => *abi == sym::rust_dash_intrinsic, let is_intrinsic = attrs.by_key(&sym::rustc_intrinsic).exists()
None => match def.lookup(self.db.upcast()).container { // Keep this around for a bit until extern "rustc-intrinsic" abis are no longer used
hir_def::ItemContainerId::ExternBlockId(block) => { || (match &function_data.abi {
let id = block.lookup(self.db.upcast()).id; Some(abi) => *abi == sym::rust_dash_intrinsic,
id.item_tree(self.db.upcast())[id.value].abi.as_ref() None => match def.lookup(self.db.upcast()).container {
== Some(&sym::rust_dash_intrinsic) hir_def::ItemContainerId::ExternBlockId(block) => {
} let id = block.lookup(self.db.upcast()).id;
_ => false, id.item_tree(self.db.upcast())[id.value].abi.as_ref()
}, == Some(&sym::rust_dash_intrinsic)
}; }
_ => false,
},
});
if is_intrinsic { if is_intrinsic {
self.exec_intrinsic( return self.exec_intrinsic(
function_data.name.as_str(), function_data.name.as_str(),
args, args,
generic_args, generic_args,
destination, destination,
locals, locals,
span, span,
)?; !function_data.has_body()
return Ok(true); || attrs.by_key(&sym::rustc_intrinsic_must_be_overridden).exists(),
} );
let is_platform_intrinsic = match &function_data.abi {
Some(abi) => *abi == sym::platform_dash_intrinsic,
None => match def.lookup(self.db.upcast()).container {
hir_def::ItemContainerId::ExternBlockId(block) => {
let id = block.lookup(self.db.upcast()).id;
id.item_tree(self.db.upcast())[id.value].abi.as_ref()
== Some(&sym::platform_dash_intrinsic)
}
_ => false,
},
};
if is_platform_intrinsic {
self.exec_platform_intrinsic(
function_data.name.as_str(),
args,
generic_args,
destination,
locals,
span,
)?;
return Ok(true);
} }
let is_extern_c = match def.lookup(self.db.upcast()).container { let is_extern_c = match def.lookup(self.db.upcast()).container {
hir_def::ItemContainerId::ExternBlockId(block) => { hir_def::ItemContainerId::ExternBlockId(block) => {
@ -106,27 +89,25 @@ impl Evaluator<'_> {
_ => false, _ => false,
}; };
if is_extern_c { if is_extern_c {
self.exec_extern_c( return self
function_data.name.as_str(), .exec_extern_c(
args, function_data.name.as_str(),
generic_args, args,
destination, generic_args,
locals, destination,
span, locals,
)?; span,
return Ok(true); )
.map(|()| true);
} }
let alloc_fn = function_data
.attrs let alloc_fn =
.iter() attrs.iter().filter_map(|it| it.path().as_ident()).map(|it| it.symbol()).find(|it| {
.filter_map(|it| it.path().as_ident())
.map(|it| it.as_str())
.find(|it| {
[ [
"rustc_allocator", &sym::rustc_allocator,
"rustc_deallocator", &sym::rustc_deallocator,
"rustc_reallocator", &sym::rustc_reallocator,
"rustc_allocator_zeroed", &sym::rustc_allocator_zeroed,
] ]
.contains(it) .contains(it)
}); });
@ -270,12 +251,12 @@ impl Evaluator<'_> {
fn exec_alloc_fn( fn exec_alloc_fn(
&mut self, &mut self,
alloc_fn: &str, alloc_fn: &Symbol,
args: &[IntervalAndTy], args: &[IntervalAndTy],
destination: Interval, destination: Interval,
) -> Result<()> { ) -> Result<()> {
match alloc_fn { match alloc_fn {
"rustc_allocator_zeroed" | "rustc_allocator" => { _ if *alloc_fn == sym::rustc_allocator_zeroed || *alloc_fn == sym::rustc_allocator => {
let [size, align] = args else { let [size, align] = args else {
return Err(MirEvalError::InternalError( return Err(MirEvalError::InternalError(
"rustc_allocator args are not provided".into(), "rustc_allocator args are not provided".into(),
@ -286,8 +267,8 @@ impl Evaluator<'_> {
let result = self.heap_allocate(size, align)?; let result = self.heap_allocate(size, align)?;
destination.write_from_bytes(self, &result.to_bytes())?; destination.write_from_bytes(self, &result.to_bytes())?;
} }
"rustc_deallocator" => { /* no-op for now */ } _ if *alloc_fn == sym::rustc_deallocator => { /* no-op for now */ }
"rustc_reallocator" => { _ if *alloc_fn == sym::rustc_reallocator => {
let [ptr, old_size, align, new_size] = args else { let [ptr, old_size, align, new_size] = args else {
return Err(MirEvalError::InternalError( return Err(MirEvalError::InternalError(
"rustc_allocator args are not provided".into(), "rustc_allocator args are not provided".into(),
@ -603,21 +584,6 @@ impl Evaluator<'_> {
} }
} }
fn exec_platform_intrinsic(
&mut self,
name: &str,
args: &[IntervalAndTy],
generic_args: &Substitution,
destination: Interval,
locals: &Locals,
span: MirSpan,
) -> Result<()> {
if let Some(name) = name.strip_prefix("simd_") {
return self.exec_simd_intrinsic(name, args, generic_args, destination, locals, span);
}
not_supported!("unknown platform intrinsic {name}");
}
fn exec_intrinsic( fn exec_intrinsic(
&mut self, &mut self,
name: &str, name: &str,
@ -626,9 +592,17 @@ impl Evaluator<'_> {
destination: Interval, destination: Interval,
locals: &Locals, locals: &Locals,
span: MirSpan, span: MirSpan,
) -> Result<()> { needs_override: bool,
) -> Result<bool> {
if let Some(name) = name.strip_prefix("atomic_") { if let Some(name) = name.strip_prefix("atomic_") {
return self.exec_atomic_intrinsic(name, args, generic_args, destination, locals, span); return self
.exec_atomic_intrinsic(name, args, generic_args, destination, locals, span)
.map(|()| true);
}
if let Some(name) = name.strip_prefix("simd_") {
return self
.exec_simd_intrinsic(name, args, generic_args, destination, locals, span)
.map(|()| true);
} }
// FIXME(#17451): Add `f16` and `f128` intrinsics. // FIXME(#17451): Add `f16` and `f128` intrinsics.
if let Some(name) = name.strip_suffix("f64") { if let Some(name) = name.strip_suffix("f64") {
@ -701,7 +675,7 @@ impl Evaluator<'_> {
} }
_ => not_supported!("unknown f64 intrinsic {name}"), _ => not_supported!("unknown f64 intrinsic {name}"),
}; };
return destination.write_from_bytes(self, &result.to_le_bytes()); return destination.write_from_bytes(self, &result.to_le_bytes()).map(|()| true);
} }
if let Some(name) = name.strip_suffix("f32") { if let Some(name) = name.strip_suffix("f32") {
let result = match name { let result = match name {
@ -773,7 +747,7 @@ impl Evaluator<'_> {
} }
_ => not_supported!("unknown f32 intrinsic {name}"), _ => not_supported!("unknown f32 intrinsic {name}"),
}; };
return destination.write_from_bytes(self, &result.to_le_bytes()); return destination.write_from_bytes(self, &result.to_le_bytes()).map(|()| true);
} }
match name { match name {
"size_of" => { "size_of" => {
@ -1146,12 +1120,6 @@ impl Evaluator<'_> {
}; };
destination.write_from_interval(self, arg.interval) destination.write_from_interval(self, arg.interval)
} }
"likely" | "unlikely" => {
let [arg] = args else {
return Err(MirEvalError::InternalError("likely arg is not provided".into()));
};
destination.write_from_interval(self, arg.interval)
}
"ctpop" => { "ctpop" => {
let [arg] = args else { let [arg] = args else {
return Err(MirEvalError::InternalError("ctpop arg is not provided".into())); return Err(MirEvalError::InternalError("ctpop arg is not provided".into()));
@ -1296,7 +1264,7 @@ impl Evaluator<'_> {
None, None,
span, span,
)?; )?;
return Ok(()); return Ok(true);
} }
} }
not_supported!("FnOnce was not available for executing const_eval_select"); not_supported!("FnOnce was not available for executing const_eval_select");
@ -1349,8 +1317,10 @@ impl Evaluator<'_> {
self.write_memory_using_ref(dst, size)?.fill(val); self.write_memory_using_ref(dst, size)?.fill(val);
Ok(()) Ok(())
} }
_ => not_supported!("unknown intrinsic {name}"), _ if needs_override => not_supported!("intrinsic {name} is not implemented"),
_ => return Ok(false),
} }
.map(|()| true)
} }
fn size_align_of_unsized( fn size_align_of_unsized(

View File

@ -43,6 +43,17 @@ pub(crate) fn fn_traits(
.flat_map(|it| it.as_trait()) .flat_map(|it| it.as_trait())
} }
/// Returns an iterator over the direct super traits (including the trait itself).
pub fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[TraitId; 4]> {
let mut result = smallvec![trait_];
direct_super_traits_cb(db, trait_, |tt| {
if !result.contains(&tt) {
result.push(tt);
}
});
result
}
/// Returns an iterator over the whole super trait hierarchy (including the /// Returns an iterator over the whole super trait hierarchy (including the
/// trait itself). /// trait itself).
pub fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[TraitId; 4]> { pub fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[TraitId; 4]> {
@ -54,7 +65,7 @@ pub fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[Trai
while let Some(&t) = result.get(i) { while let Some(&t) = result.get(i) {
// yeah this is quadratic, but trait hierarchies should be flat // yeah this is quadratic, but trait hierarchies should be flat
// enough that this doesn't matter // enough that this doesn't matter
direct_super_traits(db, t, |tt| { direct_super_traits_cb(db, t, |tt| {
if !result.contains(&tt) { if !result.contains(&tt) {
result.push(tt); result.push(tt);
} }
@ -153,7 +164,7 @@ impl Iterator for ClauseElaborator<'_> {
} }
} }
fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(TraitId)) { fn direct_super_traits_cb(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(TraitId)) {
let resolver = trait_.resolver(db); let resolver = trait_.resolver(db);
let generic_params = db.generic_params(trait_.into()); let generic_params = db.generic_params(trait_.into());
let trait_self = generic_params.trait_self_param(); let trait_self = generic_params.trait_self_param();
@ -259,25 +270,25 @@ pub fn is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool {
return true; return true;
} }
let is_intrinsic = db.attrs(func.into()).by_key(&sym::rustc_intrinsic).exists()
|| data.abi.as_ref() == Some(&sym::rust_dash_intrinsic);
let loc = func.lookup(db.upcast()); let loc = func.lookup(db.upcast());
match loc.container { match loc.container {
hir_def::ItemContainerId::ExternBlockId(block) => { hir_def::ItemContainerId::ExternBlockId(block) => {
// Function in an `extern` block are always unsafe to call, except when if is_intrinsic || {
// it is marked as `safe` or it has `"rust-intrinsic"` ABI there are a let id = block.lookup(db.upcast()).id;
// few exceptions. id.item_tree(db.upcast())[id.value].abi.as_ref() == Some(&sym::rust_dash_intrinsic)
let id = block.lookup(db.upcast()).id; } {
let is_intrinsic =
id.item_tree(db.upcast())[id.value].abi.as_ref() == Some(&sym::rust_dash_intrinsic);
if is_intrinsic {
// Intrinsics are unsafe unless they have the rustc_safe_intrinsic attribute // Intrinsics are unsafe unless they have the rustc_safe_intrinsic attribute
!data.attrs.by_key(&sym::rustc_safe_intrinsic).exists() !db.attrs(func.into()).by_key(&sym::rustc_safe_intrinsic).exists()
} else { } else {
// Extern items without `safe` modifier are always unsafe // Function in an `extern` block are always unsafe to call, except when
// it is marked as `safe`.
!data.is_safe() !data.is_safe()
} }
} }
_ if is_intrinsic => !db.attrs(func.into()).by_key(&sym::rustc_safe_intrinsic).exists(),
_ => false, _ => false,
} }
} }

View File

@ -68,7 +68,7 @@ use hir_ty::{
all_super_traits, autoderef, check_orphan_rules, all_super_traits, autoderef, check_orphan_rules,
consteval::{try_const_usize, unknown_const_as_generic, ConstExt}, consteval::{try_const_usize, unknown_const_as_generic, ConstExt},
diagnostics::BodyValidationDiagnostic, diagnostics::BodyValidationDiagnostic,
error_lifetime, known_const_to_ast, direct_super_traits, error_lifetime, known_const_to_ast,
layout::{Layout as TyLayout, RustcEnumVariantIdx, RustcFieldIdx, TagEncoding}, layout::{Layout as TyLayout, RustcEnumVariantIdx, RustcFieldIdx, TagEncoding},
method_resolution, method_resolution,
mir::{interpret_mir, MutBorrowKind}, mir::{interpret_mir, MutBorrowKind},
@ -2246,35 +2246,33 @@ impl Function {
/// Does this function have `#[test]` attribute? /// Does this function have `#[test]` attribute?
pub fn is_test(self, db: &dyn HirDatabase) -> bool { pub fn is_test(self, db: &dyn HirDatabase) -> bool {
db.function_data(self.id).attrs.is_test() db.attrs(self.id.into()).is_test()
} }
/// is this a `fn main` or a function with an `export_name` of `main`? /// is this a `fn main` or a function with an `export_name` of `main`?
pub fn is_main(self, db: &dyn HirDatabase) -> bool { pub fn is_main(self, db: &dyn HirDatabase) -> bool {
let data = db.function_data(self.id); db.attrs(self.id.into()).export_name() == Some(&sym::main)
data.attrs.export_name() == Some(&sym::main) || self.module(db).is_crate_root() && db.function_data(self.id).name == sym::main
|| self.module(db).is_crate_root() && data.name == sym::main
} }
/// Is this a function with an `export_name` of `main`? /// Is this a function with an `export_name` of `main`?
pub fn exported_main(self, db: &dyn HirDatabase) -> bool { pub fn exported_main(self, db: &dyn HirDatabase) -> bool {
let data = db.function_data(self.id); db.attrs(self.id.into()).export_name() == Some(&sym::main)
data.attrs.export_name() == Some(&sym::main)
} }
/// Does this function have the ignore attribute? /// Does this function have the ignore attribute?
pub fn is_ignore(self, db: &dyn HirDatabase) -> bool { pub fn is_ignore(self, db: &dyn HirDatabase) -> bool {
db.function_data(self.id).attrs.is_ignore() db.attrs(self.id.into()).is_ignore()
} }
/// Does this function have `#[bench]` attribute? /// Does this function have `#[bench]` attribute?
pub fn is_bench(self, db: &dyn HirDatabase) -> bool { pub fn is_bench(self, db: &dyn HirDatabase) -> bool {
db.function_data(self.id).attrs.is_bench() db.attrs(self.id.into()).is_bench()
} }
/// Is this function marked as unstable with `#[feature]` attribute? /// Is this function marked as unstable with `#[feature]` attribute?
pub fn is_unstable(self, db: &dyn HirDatabase) -> bool { pub fn is_unstable(self, db: &dyn HirDatabase) -> bool {
db.function_data(self.id).attrs.is_unstable() db.attrs(self.id.into()).is_unstable()
} }
pub fn is_unsafe_to_call(self, db: &dyn HirDatabase) -> bool { pub fn is_unsafe_to_call(self, db: &dyn HirDatabase) -> bool {
@ -2289,8 +2287,7 @@ impl Function {
} }
pub fn as_proc_macro(self, db: &dyn HirDatabase) -> Option<Macro> { pub fn as_proc_macro(self, db: &dyn HirDatabase) -> Option<Macro> {
let function_data = db.function_data(self.id); let attrs = db.attrs(self.id.into());
let attrs = &function_data.attrs;
// FIXME: Store this in FunctionData flags? // FIXME: Store this in FunctionData flags?
if !(attrs.is_proc_macro() if !(attrs.is_proc_macro()
|| attrs.is_proc_macro_attribute() || attrs.is_proc_macro_attribute()
@ -2707,13 +2704,22 @@ impl Trait {
db.trait_data(self.id).name.clone() db.trait_data(self.id).name.clone()
} }
pub fn direct_supertraits(self, db: &dyn HirDatabase) -> Vec<Trait> {
let traits = direct_super_traits(db.upcast(), self.into());
traits.iter().map(|tr| Trait::from(*tr)).collect()
}
pub fn all_supertraits(self, db: &dyn HirDatabase) -> Vec<Trait> {
let traits = all_super_traits(db.upcast(), self.into());
traits.iter().map(|tr| Trait::from(*tr)).collect()
}
pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> { pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
db.trait_data(self.id).items.iter().map(|(_name, it)| (*it).into()).collect() db.trait_data(self.id).items.iter().map(|(_name, it)| (*it).into()).collect()
} }
pub fn items_with_supertraits(self, db: &dyn HirDatabase) -> Vec<AssocItem> { pub fn items_with_supertraits(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
let traits = all_super_traits(db.upcast(), self.into()); self.all_supertraits(db).into_iter().flat_map(|tr| tr.items(db)).collect()
traits.iter().flat_map(|tr| Trait::from(*tr).items(db)).collect()
} }
pub fn is_auto(self, db: &dyn HirDatabase) -> bool { pub fn is_auto(self, db: &dyn HirDatabase) -> bool {

View File

@ -19,6 +19,7 @@ pub struct StructureNode {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum StructureNodeKind { pub enum StructureNodeKind {
SymbolKind(SymbolKind), SymbolKind(SymbolKind),
ExternBlock,
Region, Region,
} }
@ -158,6 +159,7 @@ fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
ast::Trait(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Trait)), ast::Trait(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Trait)),
ast::TraitAlias(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::TraitAlias)), ast::TraitAlias(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::TraitAlias)),
ast::Module(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Module)), ast::Module(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Module)),
ast::Macro(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Macro)),
ast::TypeAlias(it) => decl_with_type_ref(&it, it.ty(), StructureNodeKind::SymbolKind(SymbolKind::TypeAlias)), ast::TypeAlias(it) => decl_with_type_ref(&it, it.ty(), StructureNodeKind::SymbolKind(SymbolKind::TypeAlias)),
ast::RecordField(it) => decl_with_type_ref(&it, it.ty(), StructureNodeKind::SymbolKind(SymbolKind::Field)), ast::RecordField(it) => decl_with_type_ref(&it, it.ty(), StructureNodeKind::SymbolKind(SymbolKind::Field)),
ast::Const(it) => decl_with_type_ref(&it, it.ty(), StructureNodeKind::SymbolKind(SymbolKind::Const)), ast::Const(it) => decl_with_type_ref(&it, it.ty(), StructureNodeKind::SymbolKind(SymbolKind::Const)),
@ -205,7 +207,23 @@ fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
Some(node) Some(node)
}, },
ast::Macro(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Macro)), ast::ExternBlock(it) => {
let mut label = "extern".to_owned();
let abi = it.abi()?;
if let Some(abi) = abi.string_token() {
label.push(' ');
label.push_str(abi.text());
}
Some(StructureNode {
parent: None,
label,
navigation_range: abi.syntax().text_range(),
node_range: it.syntax().text_range(),
kind: StructureNodeKind::ExternBlock,
detail: None,
deprecated: false,
})
},
_ => None, _ => None,
} }
} }
@ -327,6 +345,8 @@ fn f() {}
fn g() {} fn g() {}
} }
extern "C" {}
fn let_statements() { fn let_statements() {
let x = 42; let x = 42;
let mut y = x; let mut y = x;
@ -662,11 +682,20 @@ fn let_statements() {
), ),
deprecated: false, deprecated: false,
}, },
StructureNode {
parent: None,
label: "extern \"C\"",
navigation_range: 638..648,
node_range: 638..651,
kind: ExternBlock,
detail: None,
deprecated: false,
},
StructureNode { StructureNode {
parent: None, parent: None,
label: "let_statements", label: "let_statements",
navigation_range: 641..655, navigation_range: 656..670,
node_range: 638..798, node_range: 653..813,
kind: SymbolKind( kind: SymbolKind(
Function, Function,
), ),
@ -677,11 +706,11 @@ fn let_statements() {
}, },
StructureNode { StructureNode {
parent: Some( parent: Some(
26, 27,
), ),
label: "x", label: "x",
navigation_range: 668..669, navigation_range: 683..684,
node_range: 664..675, node_range: 679..690,
kind: SymbolKind( kind: SymbolKind(
Local, Local,
), ),
@ -690,11 +719,11 @@ fn let_statements() {
}, },
StructureNode { StructureNode {
parent: Some( parent: Some(
26, 27,
), ),
label: "mut y", label: "mut y",
navigation_range: 684..689, navigation_range: 699..704,
node_range: 680..694, node_range: 695..709,
kind: SymbolKind( kind: SymbolKind(
Local, Local,
), ),
@ -703,11 +732,11 @@ fn let_statements() {
}, },
StructureNode { StructureNode {
parent: Some( parent: Some(
26, 27,
), ),
label: "Foo { .. }", label: "Foo { .. }",
navigation_range: 703..725, navigation_range: 718..740,
node_range: 699..738, node_range: 714..753,
kind: SymbolKind( kind: SymbolKind(
Local, Local,
), ),
@ -716,11 +745,11 @@ fn let_statements() {
}, },
StructureNode { StructureNode {
parent: Some( parent: Some(
26, 27,
), ),
label: "_", label: "_",
navigation_range: 788..789, navigation_range: 803..804,
node_range: 784..796, node_range: 799..811,
kind: SymbolKind( kind: SymbolKind(
Local, Local,
), ),

View File

@ -1009,10 +1009,10 @@ fn render_dyn_compatibility(
safety: Option<DynCompatibilityViolation>, safety: Option<DynCompatibilityViolation>,
) { ) {
let Some(osv) = safety else { let Some(osv) = safety else {
buf.push_str("Is Dyn compatible"); buf.push_str("Is dyn-compatible");
return; return;
}; };
buf.push_str("Is not Dyn compatible due to "); buf.push_str("Is not dyn-compatible due to ");
match osv { match osv {
DynCompatibilityViolation::SizedSelf => { DynCompatibilityViolation::SizedSelf => {
buf.push_str("having a `Self: Sized` bound"); buf.push_str("having a `Self: Sized` bound");
@ -1055,7 +1055,7 @@ fn render_dyn_compatibility(
} }
DynCompatibilityViolation::HasNonCompatibleSuperTrait(super_trait) => { DynCompatibilityViolation::HasNonCompatibleSuperTrait(super_trait) => {
let name = hir::Trait::from(super_trait).name(db); let name = hir::Trait::from(super_trait).name(db);
format_to!(buf, "having a dyn incompatible supertrait `{}`", name.as_str()); format_to!(buf, "having a dyn-incompatible supertrait `{}`", name.as_str());
} }
} }
} }

View File

@ -9371,7 +9371,7 @@ trait Compat$0 {}
--- ---
Is Dyn compatible Is dyn-compatible
"#]], "#]],
); );
check( check(
@ -9393,7 +9393,7 @@ trait UnCompat$0 {
--- ---
Is not Dyn compatible due to having a method `f` that is not dispatchable due to missing a receiver Is not dyn-compatible due to having a method `f` that is not dispatchable due to missing a receiver
"#]], "#]],
); );
check( check(

View File

@ -392,18 +392,22 @@ define_symbols! {
rust_2024, rust_2024,
rust_analyzer, rust_analyzer,
Rust, Rust,
rustc_allocator_zeroed,
rustc_allocator,
rustc_allow_incoherent_impl, rustc_allow_incoherent_impl,
rustc_builtin_macro, rustc_builtin_macro,
rustc_coherence_is_core, rustc_coherence_is_core,
rustc_const_panic_str, rustc_const_panic_str,
rustc_deallocator,
rustc_deprecated_safe_2024, rustc_deprecated_safe_2024,
rustc_has_incoherent_inherent_impls, rustc_has_incoherent_inherent_impls,
rustc_intrinsic,
rustc_intrinsic_must_be_overridden, rustc_intrinsic_must_be_overridden,
rustc_intrinsic,
rustc_layout_scalar_valid_range_end, rustc_layout_scalar_valid_range_end,
rustc_layout_scalar_valid_range_start, rustc_layout_scalar_valid_range_start,
rustc_legacy_const_generics, rustc_legacy_const_generics,
rustc_macro_transparency, rustc_macro_transparency,
rustc_reallocator,
rustc_reservation_impl, rustc_reservation_impl,
rustc_safe_intrinsic, rustc_safe_intrinsic,
rustc_skip_array_during_method_dispatch, rustc_skip_array_during_method_dispatch,

View File

@ -1131,7 +1131,7 @@ pub(crate) fn handle_completion_resolve(
else { else {
return Ok(original_completion); return Ok(original_completion);
}; };
let resolved_completions = to_proto::completion_items( let mut resolved_completions = to_proto::completion_items(
&snap.config, &snap.config,
&forced_resolve_completions_config.fields_to_resolve, &forced_resolve_completions_config.fields_to_resolve,
&line_index, &line_index,
@ -1140,15 +1140,13 @@ pub(crate) fn handle_completion_resolve(
resolve_data.trigger_character, resolve_data.trigger_character,
resolved_completions, resolved_completions,
); );
let Some(mut resolved_completion) = resolved_completions.into_iter().find(|completion| {
completion.label == original_completion.label let mut resolved_completion =
&& completion.kind == original_completion.kind if resolved_completions.get(resolve_data.completion_item_index).is_some() {
&& completion.deprecated == original_completion.deprecated resolved_completions.swap_remove(resolve_data.completion_item_index)
&& completion.preselect == original_completion.preselect } else {
&& completion.sort_text == original_completion.sort_text return Ok(original_completion);
}) else { };
return Ok(original_completion);
};
if !resolve_data.imports.is_empty() { if !resolve_data.imports.is_empty() {
let additional_edits = snap let additional_edits = snap

View File

@ -826,6 +826,7 @@ pub struct CompletionResolveData {
pub imports: Vec<CompletionImport>, pub imports: Vec<CompletionImport>,
pub version: Option<i32>, pub version: Option<i32>,
pub trigger_character: Option<char>, pub trigger_character: Option<char>,
pub completion_item_index: usize,
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]

View File

@ -88,6 +88,7 @@ pub(crate) fn structure_node_kind(kind: StructureNodeKind) -> lsp_types::SymbolK
match kind { match kind {
StructureNodeKind::SymbolKind(symbol) => symbol_kind(symbol), StructureNodeKind::SymbolKind(symbol) => symbol_kind(symbol),
StructureNodeKind::Region => lsp_types::SymbolKind::NAMESPACE, StructureNodeKind::Region => lsp_types::SymbolKind::NAMESPACE,
StructureNodeKind::ExternBlock => lsp_types::SymbolKind::NAMESPACE,
} }
} }
@ -391,18 +392,36 @@ fn completion_item(
} else { } else {
Vec::new() Vec::new()
}; };
if something_to_resolve || !imports.is_empty() { let (ref_resolve_data, resolve_data) = if something_to_resolve || !imports.is_empty() {
let data = lsp_ext::CompletionResolveData { let mut item_index = acc.len();
let ref_resolve_data = if ref_match.is_some() {
let ref_resolve_data = lsp_ext::CompletionResolveData {
position: tdpp.clone(),
imports: Vec::new(),
version,
trigger_character: completion_trigger_character,
completion_item_index: item_index,
};
item_index += 1;
Some(to_value(ref_resolve_data).unwrap())
} else {
None
};
let resolve_data = lsp_ext::CompletionResolveData {
position: tdpp.clone(), position: tdpp.clone(),
imports, imports,
version, version,
trigger_character: completion_trigger_character, trigger_character: completion_trigger_character,
completion_item_index: item_index,
}; };
lsp_item.data = Some(to_value(data).unwrap()); (ref_resolve_data, Some(to_value(resolve_data).unwrap()))
} } else {
(None, None)
};
if let Some((label, indel, relevance)) = ref_match { if let Some((label, indel, relevance)) = ref_match {
let mut lsp_item_with_ref = lsp_types::CompletionItem { label, ..lsp_item.clone() }; let mut lsp_item_with_ref =
lsp_types::CompletionItem { label, data: ref_resolve_data, ..lsp_item.clone() };
lsp_item_with_ref lsp_item_with_ref
.additional_text_edits .additional_text_edits
.get_or_insert_with(Default::default) .get_or_insert_with(Default::default)
@ -411,6 +430,7 @@ fn completion_item(
acc.push(lsp_item_with_ref); acc.push(lsp_item_with_ref);
}; };
lsp_item.data = resolve_data;
acc.push(lsp_item); acc.push(lsp_item);
fn set_score( fn set_score(

View File

@ -370,15 +370,13 @@ pub mod mem {
// endregion:drop // endregion:drop
// region:transmute // region:transmute
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn transmute<Src, Dst>(src: Src) -> Dst; pub fn transmute<Src, Dst>(src: Src) -> Dst;
}
// endregion:transmute // endregion:transmute
// region:size_of // region:size_of
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn size_of<T>() -> usize; pub fn size_of<T>() -> usize;
}
// endregion:size_of // endregion:size_of
// region:discriminant // region:discriminant

View File

@ -47,7 +47,7 @@ https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frust-analyzer
Each triaged issue should have one of these labels. Each triaged issue should have one of these labels.
* [fun](https://github.com/rust-lang/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3Afun) * [fun](https://github.com/rust-lang/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3Afun)
is for cool, but probably hard stuff. is for cool, but probably hard stuff.
* [Design](https://github.com/rust-lang/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%Design) * [C-Architecture](https://github.com/rust-lang/rust-analyzer/issues?q=is%3Aissue%20state%3Aopen%20label%3AC-Architecture)
is for moderate/large scale architecture discussion. is for moderate/large scale architecture discussion.
Also a kind of fun. Also a kind of fun.
These issues should generally include a link to a Zulip discussion thread. These issues should generally include a link to a Zulip discussion thread.

View File

@ -1,5 +1,5 @@
<!--- <!---
lsp/ext.rs hash: 90cf7718d54fe3c2 lsp/ext.rs hash: 96f88b7a5d0080c6
If you need to change the above hash to make the test pass, please check if you If you need to change the above hash to make the test pass, please check if you
need to adjust this doc as well and ping this issue: need to adjust this doc as well and ping this issue:

View File

@ -13,12 +13,12 @@
"anser": "^2.1.1", "anser": "^2.1.1",
"d3": "^7.8.5", "d3": "^7.8.5",
"d3-graphviz": "^5.0.2", "d3-graphviz": "^5.0.2",
"vscode-languageclient": "^8.1.0" "vscode-languageclient": "^9.0.1"
}, },
"devDependencies": { "devDependencies": {
"@tsconfig/strictest": "^2.0.1", "@tsconfig/strictest": "^2.0.1",
"@types/node": "~16.11.7", "@types/node": "~16.11.7",
"@types/vscode": "~1.78.1", "@types/vscode": "~1.83",
"@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0", "@typescript-eslint/parser": "^6.0.0",
"@vscode/test-electron": "^2.3.8", "@vscode/test-electron": "^2.3.8",
@ -32,7 +32,7 @@
"typescript": "^5.6.0" "typescript": "^5.6.0"
}, },
"engines": { "engines": {
"vscode": "^1.78.0" "vscode": "^1.83.0"
} }
}, },
"node_modules/@aashutoshrathi/word-wrap": { "node_modules/@aashutoshrathi/word-wrap": {
@ -880,9 +880,9 @@
"dev": true "dev": true
}, },
"node_modules/@types/vscode": { "node_modules/@types/vscode": {
"version": "1.78.1", "version": "1.83.3",
"resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.78.1.tgz", "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.83.3.tgz",
"integrity": "sha512-wEA+54axejHu7DhcUfnFBan1IqFD1gBDxAFz8LoX06NbNDMRJv/T6OGthOs52yZccasKfN588EyffHWABkR0fg==", "integrity": "sha512-ZPp5+OQNYrCSFoT4jWOZKdcuXijj+JdN2BJNDhWH4pPbVL6PRQycG9NT8C4a94oul1tFMbkVbXXa9HasI7cLUg==",
"dev": true "dev": true
}, },
"node_modules/@typescript-eslint/eslint-plugin": { "node_modules/@typescript-eslint/eslint-plugin": {
@ -5059,24 +5059,24 @@
} }
}, },
"node_modules/vscode-jsonrpc": { "node_modules/vscode-jsonrpc": {
"version": "8.1.0", "version": "8.2.0",
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.1.0.tgz", "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz",
"integrity": "sha512-6TDy/abTQk+zDGYazgbIPc+4JoXdwC8NHU9Pbn4UJP1fehUyZmM4RHp5IthX7A6L5KS30PRui+j+tbbMMMafdw==", "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==",
"engines": { "engines": {
"node": ">=14.0.0" "node": ">=14.0.0"
} }
}, },
"node_modules/vscode-languageclient": { "node_modules/vscode-languageclient": {
"version": "8.1.0", "version": "9.0.1",
"resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-8.1.0.tgz", "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-9.0.1.tgz",
"integrity": "sha512-GL4QdbYUF/XxQlAsvYWZRV3V34kOkpRlvV60/72ghHfsYFnS/v2MANZ9P6sHmxFcZKOse8O+L9G7Czg0NUWing==", "integrity": "sha512-JZiimVdvimEuHh5olxhxkht09m3JzUGwggb5eRUkzzJhZ2KjCN0nh55VfiED9oez9DyF8/fz1g1iBV3h+0Z2EA==",
"dependencies": { "dependencies": {
"minimatch": "^5.1.0", "minimatch": "^5.1.0",
"semver": "^7.3.7", "semver": "^7.3.7",
"vscode-languageserver-protocol": "3.17.3" "vscode-languageserver-protocol": "3.17.5"
}, },
"engines": { "engines": {
"vscode": "^1.67.0" "vscode": "^1.82.0"
} }
}, },
"node_modules/vscode-languageclient/node_modules/brace-expansion": { "node_modules/vscode-languageclient/node_modules/brace-expansion": {
@ -5099,18 +5099,18 @@
} }
}, },
"node_modules/vscode-languageserver-protocol": { "node_modules/vscode-languageserver-protocol": {
"version": "3.17.3", "version": "3.17.5",
"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.3.tgz", "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz",
"integrity": "sha512-924/h0AqsMtA5yK22GgMtCYiMdCOtWTSGgUOkgEDX+wk2b0x4sAfLiO4NxBxqbiVtz7K7/1/RgVrVI0NClZwqA==", "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==",
"dependencies": { "dependencies": {
"vscode-jsonrpc": "8.1.0", "vscode-jsonrpc": "8.2.0",
"vscode-languageserver-types": "3.17.3" "vscode-languageserver-types": "3.17.5"
} }
}, },
"node_modules/vscode-languageserver-types": { "node_modules/vscode-languageserver-types": {
"version": "3.17.3", "version": "3.17.5",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.3.tgz", "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz",
"integrity": "sha512-SYU4z1dL0PyIMd4Vj8YOqFvHu7Hz/enbWtpfnVbJHU4Nd1YNYx8u0ennumc6h48GQNeOLxmwySmnADouT/AuZA==" "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg=="
}, },
"node_modules/which": { "node_modules/which": {
"version": "2.0.2", "version": "2.0.2",

View File

@ -27,7 +27,7 @@
} }
}, },
"engines": { "engines": {
"vscode": "^1.78.0" "vscode": "^1.83.0"
}, },
"enabledApiProposals": [], "enabledApiProposals": [],
"scripts": { "scripts": {
@ -49,12 +49,12 @@
"anser": "^2.1.1", "anser": "^2.1.1",
"d3": "^7.8.5", "d3": "^7.8.5",
"d3-graphviz": "^5.0.2", "d3-graphviz": "^5.0.2",
"vscode-languageclient": "^8.1.0" "vscode-languageclient": "^9.0.1"
}, },
"devDependencies": { "devDependencies": {
"@tsconfig/strictest": "^2.0.1", "@tsconfig/strictest": "^2.0.1",
"@types/node": "~16.11.7", "@types/node": "~16.11.7",
"@types/vscode": "~1.78.1", "@types/vscode": "~1.83",
"@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0", "@typescript-eslint/parser": "^6.0.0",
"@vscode/test-electron": "^2.3.8", "@vscode/test-electron": "^2.3.8",
@ -490,15 +490,19 @@
"type": "string", "type": "string",
"enum": [ "enum": [
"auto", "auto",
"llvm-vs-code-extensions.lldb-dap",
"vadimcn.vscode-lldb", "vadimcn.vscode-lldb",
"ms-vscode.cpptools" "ms-vscode.cpptools",
"webfreak.debug"
], ],
"default": "auto", "default": "auto",
"description": "Preferred debug engine.", "description": "Preferred debug engine.",
"markdownEnumDescriptions": [ "markdownEnumDescriptions": [
"First try to use [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb), if it's not installed try to use [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools).", "Use the first available extension out of [LLDB DAP](https://marketplace.visualstudio.com/items?itemName=llvm-vs-code-extensions.lldb-dap), [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb), [C/C++ for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools), and [Native Debug](https://marketplace.visualstudio.com/items?itemName=webfreak.debug).",
"Use [LLDB DAP](https://marketplace.visualstudio.com/items?itemName=llvm-vs-code-extensions.lldb-dap)",
"Use [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb)", "Use [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb)",
"Use [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools)" "Use [C/C++ for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools)",
"Use [Native Debug](https://marketplace.visualstudio.com/items?itemName=webfreak.debug)"
] ]
}, },
"rust-analyzer.debug.sourceFileMap": { "rust-analyzer.debug.sourceFileMap": {

View File

@ -350,6 +350,7 @@ class ExperimentalFeatures implements lc.StaticFeature {
_documentSelector: lc.DocumentSelector | undefined, _documentSelector: lc.DocumentSelector | undefined,
): void {} ): void {}
dispose(): void {} dispose(): void {}
clear(): void {}
} }
class OverrideFeatures implements lc.StaticFeature { class OverrideFeatures implements lc.StaticFeature {
@ -369,6 +370,7 @@ class OverrideFeatures implements lc.StaticFeature {
_documentSelector: lc.DocumentSelector | undefined, _documentSelector: lc.DocumentSelector | undefined,
): void {} ): void {}
dispose(): void {} dispose(): void {}
clear(): void {}
} }
function isCodeActionWithoutEditsAndCommands(value: any): boolean { function isCodeActionWithoutEditsAndCommands(value: any): boolean {

View File

@ -19,3 +19,5 @@ exclude_titles = [ # exclude syncs from subtree in rust-lang/rust
"sync from rust", "sync from rust",
] ]
labels = ["has-merge-commits", "S-waiting-on-author"] labels = ["has-merge-commits", "S-waiting-on-author"]
[transfer]

View File

@ -1,8 +0,0 @@
//@ known-bug: #118545
#![feature(generic_const_exprs)]
struct Checked<const F: fn()>;
fn foo() {}
const _: Checked<foo> = Checked::<foo>;
pub fn main() {}

View File

@ -1,15 +0,0 @@
//@ known-bug: #128232
#![feature(generic_const_exprs, unsized_const_params)]
fn function() {}
struct Wrapper<const F: fn()>;
impl Wrapper<{ bar() }> {
fn call() {}
}
fn main() {
Wrapper::<function>::call;
}

View File

@ -15,10 +15,10 @@ LL | for<'b> <T as X<'b, T>>::U: Clone,
| ^^^^^ required by this bound in `X` | ^^^^^ required by this bound in `X`
error[E0277]: the trait bound `str: Clone` is not satisfied error[E0277]: the trait bound `str: Clone` is not satisfied
--> $DIR/hr-associated-type-bound-param-3.rs:18:5 --> $DIR/hr-associated-type-bound-param-3.rs:18:18
| |
LL | <(i32,) as X<(i32,)>>::f("abc"); LL | <(i32,) as X<(i32,)>>::f("abc");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `str` | ^^^^^^ the trait `Clone` is not implemented for `str`
| |
= help: the trait `Clone` is implemented for `String` = help: the trait `Clone` is implemented for `String`
note: required by a bound in `X::f` note: required by a bound in `X::f`

View File

@ -15,10 +15,10 @@ LL | for<'b> <(T,) as X<'b, T>>::U: Clone,
| ^^^^^ required by this bound in `X` | ^^^^^ required by this bound in `X`
error[E0277]: the trait bound `str: Clone` is not satisfied error[E0277]: the trait bound `str: Clone` is not satisfied
--> $DIR/hr-associated-type-bound-param-4.rs:18:5 --> $DIR/hr-associated-type-bound-param-4.rs:18:18
| |
LL | <(i32,) as X<i32>>::f("abc"); LL | <(i32,) as X<i32>>::f("abc");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `str` | ^^^ the trait `Clone` is not implemented for `str`
| |
= help: the trait `Clone` is implemented for `String` = help: the trait `Clone` is implemented for `String`
note: required by a bound in `X::f` note: required by a bound in `X::f`

View File

@ -31,10 +31,10 @@ LL | for<'b> <T::Next as X<'b, T::Next>>::U: Clone,
| ^^^^^ required by this bound in `X` | ^^^^^ required by this bound in `X`
error[E0277]: the trait bound `str: Clone` is not satisfied error[E0277]: the trait bound `str: Clone` is not satisfied
--> $DIR/hr-associated-type-bound-param-5.rs:36:5 --> $DIR/hr-associated-type-bound-param-5.rs:36:15
| |
LL | <i32 as X<Box<i32>>>::f("abc"); LL | <i32 as X<Box<i32>>>::f("abc");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `str` | ^^^^^^^^ the trait `Clone` is not implemented for `str`
| |
= help: the trait `Clone` is implemented for `String` = help: the trait `Clone` is implemented for `String`
note: required by a bound in `X::f` note: required by a bound in `X::f`

View File

@ -17,5 +17,6 @@ impl<S, T> X<'_, T> for (S,) {
pub fn main() { pub fn main() {
<(i32,) as X<i32>>::f("abc"); <(i32,) as X<i32>>::f("abc");
//~^ ERROR the trait bound `for<'b> i32: X<'b, i32>` is not satisfied //~^ ERROR the trait bound `for<'b> i32: X<'b, i32>` is not satisfied
//~| ERROR the trait bound `for<'b> i32: X<'b, i32>` is not satisfied
//~| ERROR the trait bound `i32: X<'_, i32>` is not satisfied //~| ERROR the trait bound `i32: X<'_, i32>` is not satisfied
} }

View File

@ -17,6 +17,22 @@ LL | <(i32,) as X<i32>>::f("abc");
| |
= help: the trait `X<'_, T>` is implemented for `(S,)` = help: the trait `X<'_, T>` is implemented for `(S,)`
error[E0277]: the trait bound `for<'b> i32: X<'b, i32>` is not satisfied
--> $DIR/hr-associated-type-bound-param-6.rs:18:18
|
LL | <(i32,) as X<i32>>::f("abc");
| ^^^ the trait `for<'b> X<'b, i32>` is not implemented for `i32`
|
= help: the trait `X<'_, T>` is implemented for `(S,)`
note: required by a bound in `X::f`
--> $DIR/hr-associated-type-bound-param-6.rs:3:16
|
LL | for<'b> T: X<'b, T>,
| ^^^^^^^^ required by this bound in `X::f`
...
LL | fn f(x: &<T as X<'_, T>>::U) {
| - required by a bound in this associated function
error[E0277]: the trait bound `i32: X<'_, i32>` is not satisfied error[E0277]: the trait bound `i32: X<'_, i32>` is not satisfied
--> $DIR/hr-associated-type-bound-param-6.rs:18:27 --> $DIR/hr-associated-type-bound-param-6.rs:18:27
| |
@ -25,6 +41,6 @@ LL | <(i32,) as X<i32>>::f("abc");
| |
= help: the trait `X<'_, T>` is implemented for `(S,)` = help: the trait `X<'_, T>` is implemented for `(S,)`
error: aborting due to 3 previous errors error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0277`. For more information about this error, try `rustc --explain E0277`.

View File

@ -0,0 +1,12 @@
#![feature(generic_const_exprs)]
#![allow(incomplete_features)]
// Regression test for #118545
struct Checked<const F: fn()>;
//~^ ERROR: using function pointers as const generic parameters is forbidden
fn foo() {}
const _: Checked<foo> = Checked::<foo>;
pub fn main() {}

View File

@ -0,0 +1,10 @@
error: using function pointers as const generic parameters is forbidden
--> $DIR/non_valtreeable_const_arg-1.rs:6:25
|
LL | struct Checked<const F: fn()>;
| ^^^^
|
= note: the only supported types are integers, `bool`, and `char`
error: aborting due to 1 previous error

View File

@ -0,0 +1,19 @@
#![feature(generic_const_exprs, unsized_const_params)]
#![allow(incomplete_features)]
// Regression test for 128232
fn function() {}
struct Wrapper<const F: fn()>;
//~^ ERROR: using function pointers as const generic parameters is forbidden
impl Wrapper<{ bar() }> {
//~^ ERROR: cannot find function `bar` in this scope
fn call() {}
}
fn main() {
Wrapper::<function>::call;
//~^ ERROR: the function or associated item `call` exists for struct `Wrapper<function>`,
}

View File

@ -0,0 +1,39 @@
error[E0425]: cannot find function `bar` in this scope
--> $DIR/non_valtreeable_const_arg-2.rs:11:16
|
LL | impl Wrapper<{ bar() }> {
| ^^^ not found in this scope
|
help: you might be missing a const parameter
|
LL | impl<const bar: /* Type */> Wrapper<{ bar() }> {
| +++++++++++++++++++++++
error[E0741]: using function pointers as const generic parameters is forbidden
--> $DIR/non_valtreeable_const_arg-2.rs:8:25
|
LL | struct Wrapper<const F: fn()>;
| ^^^^
error[E0599]: the function or associated item `call` exists for struct `Wrapper<function>`, but its trait bounds were not satisfied
--> $DIR/non_valtreeable_const_arg-2.rs:17:26
|
LL | struct Wrapper<const F: fn()>;
| ----------------------------- function or associated item `call` not found for this struct because it doesn't satisfy `Wrapper<function>: Fn<_>`
...
LL | Wrapper::<function>::call;
| ^^^^ function or associated item cannot be called on `Wrapper<function>` due to unsatisfied trait bounds
|
= note: the following trait bounds were not satisfied:
`Wrapper<function>: Fn<_>`
which is required by `&Wrapper<function>: Fn<_>`
note: the trait `Fn` must be implemented
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `call`, perhaps you need to implement it:
candidate #1: `Fn`
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0425, E0599, E0741.
For more information about an error, try `rustc --explain E0425`.

View File

@ -1,36 +0,0 @@
//@ known-bug: #110395
//@ compile-flags: -Znext-solver
#![feature(generic_const_exprs, adt_const_params, const_trait_impl)]
#![allow(incomplete_features)]
// test `N + N` unifies with explicit function calls for non-builtin-types
#[derive(PartialEq, Eq)]
struct Foo(u8);
impl const std::ops::Add for Foo {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
self
}
}
struct Evaluatable<const N: Foo>;
fn foo<const N: Foo>(a: Evaluatable<{ N + N }>) {
bar::<{ std::ops::Add::add(N, N) }>();
}
fn bar<const N: Foo>() {}
// test that `N + N` unifies with explicit function calls for builin-types
struct Evaluatable2<const N: usize>;
fn foo2<const N: usize>(a: Evaluatable2<{ N + N }>) {
bar2::<{ std::ops::Add::add(N, N) }>();
// FIXME(generic_const_exprs) make this not an error
}
fn bar2<const N: usize>() {}
fn main() {}

View File

@ -1,93 +0,0 @@
error: `-Znext-solver=globally` and `generic_const_exprs` are incompatible, using them at the same time is not allowed
--> $DIR/unify-op-with-fn-call.rs:3:12
|
LL | #![feature(generic_const_exprs, adt_const_params, const_trait_impl)]
| ^^^^^^^^^^^^^^^^^^^
|
= help: remove one of these features
error: const `impl` for trait `Add` which is not marked with `#[const_trait]`
--> $DIR/unify-op-with-fn-call.rs:10:12
|
LL | impl const std::ops::Add for Foo {
| ^^^^^^^^^^^^^
|
= note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
= note: adding a non-const method body in the future would be a breaking change
error[E0741]: `Foo` must implement `ConstParamTy` to be used as the type of a const generic parameter
--> $DIR/unify-op-with-fn-call.rs:18:29
|
LL | struct Evaluatable<const N: Foo>;
| ^^^
|
help: add `#[derive(ConstParamTy)]` to the struct
|
LL + #[derive(ConstParamTy)]
LL | struct Foo(u8);
|
error[E0015]: cannot call non-const operator in constants
--> $DIR/unify-op-with-fn-call.rs:20:39
|
LL | fn foo<const N: Foo>(a: Evaluatable<{ N + N }>) {
| ^^^^^
|
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
error[E0741]: `Foo` must implement `ConstParamTy` to be used as the type of a const generic parameter
--> $DIR/unify-op-with-fn-call.rs:20:17
|
LL | fn foo<const N: Foo>(a: Evaluatable<{ N + N }>) {
| ^^^
|
help: add `#[derive(ConstParamTy)]` to the struct
|
LL + #[derive(ConstParamTy)]
LL | struct Foo(u8);
|
error[E0741]: `Foo` must implement `ConstParamTy` to be used as the type of a const generic parameter
--> $DIR/unify-op-with-fn-call.rs:24:17
|
LL | fn bar<const N: Foo>() {}
| ^^^
|
help: add `#[derive(ConstParamTy)]` to the struct
|
LL + #[derive(ConstParamTy)]
LL | struct Foo(u8);
|
error[E0284]: type annotations needed: cannot normalize `foo2<N>::{constant#0}`
--> $DIR/unify-op-with-fn-call.rs:29:28
|
LL | fn foo2<const N: usize>(a: Evaluatable2<{ N + N }>) {
| ^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `foo2<N>::{constant#0}`
error[E0015]: cannot call non-const fn `<Foo as Add>::add` in constants
--> $DIR/unify-op-with-fn-call.rs:21:13
|
LL | bar::<{ std::ops::Add::add(N, N) }>();
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
error[E0015]: cannot call non-const fn `<usize as Add>::add` in constants
--> $DIR/unify-op-with-fn-call.rs:30:14
|
LL | bar2::<{ std::ops::Add::add(N, N) }>();
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
error[E0284]: type annotations needed: cannot normalize `foo2<N>::{constant#0}`
--> $DIR/unify-op-with-fn-call.rs:30:12
|
LL | bar2::<{ std::ops::Add::add(N, N) }>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `foo2<N>::{constant#0}`
error: aborting due to 10 previous errors
Some errors have detailed explanations: E0015, E0284, E0741.
For more information about an error, try `rustc --explain E0015`.

View File

@ -8,6 +8,46 @@ LL | yield true;
= help: add `#![feature(coroutines)]` to the crate attributes to enable = help: add `#![feature(coroutines)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: yield syntax is experimental
--> $DIR/feature-gate-coroutines.rs:10:16
|
LL | let _ = || yield true;
| ^^^^^^^^^^
|
= note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information
= help: add `#![feature(coroutines)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: yield syntax is experimental
--> $DIR/feature-gate-coroutines.rs:18:5
|
LL | yield;
| ^^^^^
|
= note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information
= help: add `#![feature(coroutines)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: yield syntax is experimental
--> $DIR/feature-gate-coroutines.rs:19:5
|
LL | yield 0;
| ^^^^^^^
|
= note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information
= help: add `#![feature(coroutines)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: yield syntax is experimental
--> $DIR/feature-gate-coroutines.rs:5:5
|
LL | yield true;
| ^^^^^^^^^^
|
= note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information
= help: add `#![feature(coroutines)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks
--> $DIR/feature-gate-coroutines.rs:5:5 --> $DIR/feature-gate-coroutines.rs:5:5
| |
@ -46,7 +86,7 @@ error[E0627]: yield expression outside of coroutine literal
LL | yield true; LL | yield true;
| ^^^^^^^^^^ | ^^^^^^^^^^
error: aborting due to 5 previous errors error: aborting due to 9 previous errors
Some errors have detailed explanations: E0627, E0658. Some errors have detailed explanations: E0627, E0658.
For more information about an error, try `rustc --explain E0627`. For more information about an error, try `rustc --explain E0627`.

View File

@ -4,17 +4,17 @@
fn main() { fn main() {
yield true; //~ ERROR yield syntax is experimental yield true; //~ ERROR yield syntax is experimental
//~^ ERROR yield expression outside of coroutine literal //~^ ERROR yield expression outside of coroutine literal
//[none]~^^ ERROR yield syntax is experimental //~^^ ERROR yield syntax is experimental
//~^^^ ERROR `yield` can only be used //~^^^ ERROR `yield` can only be used
let _ = || yield true; //~ ERROR yield syntax is experimental let _ = || yield true; //~ ERROR yield syntax is experimental
//[none]~^ ERROR yield syntax is experimental //~^ ERROR yield syntax is experimental
//~^^ ERROR `yield` can only be used //~^^ ERROR `yield` can only be used
} }
#[cfg(FALSE)] #[cfg(FALSE)]
fn foo() { fn foo() {
// Ok in 2024 edition // Ok in 2024 edition
yield; //[none]~ ERROR yield syntax is experimental yield; //~ ERROR yield syntax is experimental
yield 0; //[none]~ ERROR yield syntax is experimental yield 0; //~ ERROR yield syntax is experimental
} }

View File

@ -1,8 +1,8 @@
error[E0277]: the trait bound `for<'a> T: Trait<'a, '_>` is not satisfied error[E0277]: the trait bound `for<'a> T: Trait<'a, '_>` is not satisfied
--> $DIR/candidate-from-env-universe-err-2.rs:15:5 --> $DIR/candidate-from-env-universe-err-2.rs:15:15
| |
LL | impl_hr::<T>(); LL | impl_hr::<T>();
| ^^^^^^^^^^^^^^ the trait `for<'a> Trait<'a, '_>` is not implemented for `T` | ^ the trait `for<'a> Trait<'a, '_>` is not implemented for `T`
| |
note: required by a bound in `impl_hr` note: required by a bound in `impl_hr`
--> $DIR/candidate-from-env-universe-err-2.rs:12:19 --> $DIR/candidate-from-env-universe-err-2.rs:12:19

View File

@ -0,0 +1,12 @@
//@ force-host
//@ no-prefer-dynamic
#![crate_type = "proc-macro"]
extern crate proc_macro;
// Doesn't do anything, but has a helper attribute.
#[proc_macro_derive(WithHelperAttr, attributes(x))]
pub fn derive(_input: proc_macro::TokenStream) -> proc_macro::TokenStream {
proc_macro::TokenStream::new()
}

View File

@ -0,0 +1,19 @@
// This test checks that helper attributes of a derive proc macro can be used together with
// other built-in derive macros.
// issue: rust-lang/rust#132561
//@ check-pass
//@ aux-build:helper-attr.rs
//@ edition:2021
#[macro_use]
extern crate helper_attr;
use helper_attr::WithHelperAttr;
#[derive(WithHelperAttr, Debug, Clone, PartialEq)]
struct MyStruct<#[x] 'a, #[x] const A: usize, #[x] B> {
#[x]
field: &'a [B; A],
}
fn main() {}

View File

@ -1,32 +0,0 @@
//@ known-bug: #110395
//@ compile-flags: -Znext-solver
// FIXME(const_trait_impl): check-pass
#![feature(const_trait_impl, generic_const_exprs)]
#![allow(incomplete_features)]
fn main() {
let _ = process::<()>([()]);
let _ = Struct::<(), 4> { field: [1, 0] };
}
fn process<T: const Trait>(input: [(); T::make(2)]) -> [(); T::make(2)] {
input
}
struct Struct<T: const Trait, const P: usize>
where
[u32; T::make(P)]:,
{
field: [u32; T::make(P)],
}
#[const_trait]
trait Trait {
fn make(input: usize) -> usize;
}
impl const Trait for () {
fn make(input: usize) -> usize {
input / 2
}
}

View File

@ -1,29 +0,0 @@
error: `-Znext-solver=globally` and `generic_const_exprs` are incompatible, using them at the same time is not allowed
--> $DIR/const-trait-bounds.rs:4:30
|
LL | #![feature(const_trait_impl, generic_const_exprs)]
| ^^^^^^^^^^^^^^^^^^^
|
= help: remove one of these features
error[E0284]: type annotations needed: cannot normalize `process<T>::{constant#0}`
--> $DIR/const-trait-bounds.rs:12:35
|
LL | fn process<T: const Trait>(input: [(); T::make(2)]) -> [(); T::make(2)] {
| ^^^^^^^^^^^^^^^^ cannot normalize `process<T>::{constant#0}`
error[E0284]: type annotations needed: cannot normalize `Struct<T, P>::field::{constant#0}`
--> $DIR/const-trait-bounds.rs:20:12
|
LL | field: [u32; T::make(P)],
| ^^^^^^^^^^^^^^^^^ cannot normalize `Struct<T, P>::field::{constant#0}`
error[E0284]: type annotations needed: cannot normalize `process<T>::{constant#1}`
--> $DIR/const-trait-bounds.rs:13:5
|
LL | input
| ^^^^^ cannot normalize `process<T>::{constant#1}`
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0284`.