mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
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:
commit
5700240aff
@ -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");
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
@ -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, _) => {
|
||||||
|
@ -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() {
|
||||||
|
@ -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 {
|
||||||
|
@ -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`
|
||||||
|
// instead of having this logic here
|
||||||
|
let param_env =
|
||||||
|
self.tcx().erase_regions(self.param_env).with_reveal_all_normalized(self.tcx());
|
||||||
|
let uv = self.tcx().erase_regions(uv);
|
||||||
|
|
||||||
|
// try to resolve e.g. associated constants to their definition on an impl, and then
|
||||||
|
// evaluate the const.
|
||||||
|
let valtree = match self.infcx.tcx.const_eval_resolve_for_typeck(param_env, uv, self.span) {
|
||||||
|
Ok(Ok(c)) => c,
|
||||||
|
Err(ErrorHandled::Reported(_, _)) => {
|
||||||
// Let's tell the use where this failing const occurs.
|
// Let's tell the use where this failing const occurs.
|
||||||
self.tcx().dcx().emit_err(CouldNotEvalConstPattern { span: self.span })
|
let e = self.tcx().dcx().emit_err(CouldNotEvalConstPattern { span: self.span });
|
||||||
|
return pat_from_kind(PatKind::Error(e));
|
||||||
}
|
}
|
||||||
ErrorHandled::TooGeneric(_) => self
|
Err(ErrorHandled::TooGeneric(_)) => {
|
||||||
|
let e = self
|
||||||
.tcx()
|
.tcx()
|
||||||
.dcx()
|
.dcx()
|
||||||
.emit_err(ConstPatternDependsOnGenericParameter { span: self.span }),
|
.emit_err(ConstPatternDependsOnGenericParameter { span: self.span });
|
||||||
};
|
return pat_from_kind(PatKind::Error(e));
|
||||||
return pat_from_kind(PatKind::Error(err));
|
|
||||||
}
|
}
|
||||||
Err(Either::Left(bad_ty)) => {
|
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 });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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`!
|
||||||
|
@ -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(
|
||||||
|
@ -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)
|
||||||
|
@ -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),
|
||||||
) {
|
) {
|
||||||
|
@ -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())),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
|
||||||
let reported =
|
|
||||||
tcx.dcx().emit_err(UnableToConstructConstantValue {
|
|
||||||
span: tcx.def_span(unevaluated.def),
|
|
||||||
unevaluated,
|
unevaluated,
|
||||||
});
|
});
|
||||||
Err(ErrorHandled::Reported(reported.into(), tcx.def_span(unevaluated.def)))
|
|
||||||
}
|
|
||||||
Err(err) => Err(err),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ct
|
||||||
} else {
|
} else {
|
||||||
Ok(c)
|
Ok(c)
|
||||||
}
|
}
|
||||||
|
@ -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(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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 {
|
||||||
|
@ -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))
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
@ -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):
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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",
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
#[rustc_intrinsic]
|
||||||
pub fn volatile_load<T>(e: *const T) -> T;
|
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;
|
||||||
|
#[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(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
|
||||||
|
@ -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 {
|
||||||
|
@ -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()
|
||||||
|
@ -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();
|
||||||
|
@ -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,
|
||||||
|
@ -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,7 +54,10 @@ 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());
|
||||||
|
let is_intrinsic = attrs.by_key(&sym::rustc_intrinsic).exists()
|
||||||
|
// Keep this around for a bit until extern "rustc-intrinsic" abis are no longer used
|
||||||
|
|| (match &function_data.abi {
|
||||||
Some(abi) => *abi == sym::rust_dash_intrinsic,
|
Some(abi) => *abi == sym::rust_dash_intrinsic,
|
||||||
None => match def.lookup(self.db.upcast()).container {
|
None => match def.lookup(self.db.upcast()).container {
|
||||||
hir_def::ItemContainerId::ExternBlockId(block) => {
|
hir_def::ItemContainerId::ExternBlockId(block) => {
|
||||||
@ -64,39 +67,19 @@ impl Evaluator<'_> {
|
|||||||
}
|
}
|
||||||
_ => false,
|
_ => 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
|
||||||
|
.exec_extern_c(
|
||||||
function_data.name.as_str(),
|
function_data.name.as_str(),
|
||||||
args,
|
args,
|
||||||
generic_args,
|
generic_args,
|
||||||
destination,
|
destination,
|
||||||
locals,
|
locals,
|
||||||
span,
|
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(
|
||||||
|
@ -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
|
|
||||||
// few exceptions.
|
|
||||||
let id = block.lookup(db.upcast()).id;
|
let id = block.lookup(db.upcast()).id;
|
||||||
|
id.item_tree(db.upcast())[id.value].abi.as_ref() == Some(&sym::rust_dash_intrinsic)
|
||||||
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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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,
|
||||||
),
|
),
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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(
|
||||||
|
@ -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,
|
||||||
|
@ -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,13 +1140,11 @@ 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
|
|
||||||
}) else {
|
|
||||||
return Ok(original_completion);
|
return Ok(original_completion);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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)]
|
||||||
|
@ -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,
|
||||||
|
};
|
||||||
|
(ref_resolve_data, Some(to_value(resolve_data).unwrap()))
|
||||||
|
} else {
|
||||||
|
(None, None)
|
||||||
};
|
};
|
||||||
lsp_item.data = Some(to_value(data).unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
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(
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
@ -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:
|
||||||
|
@ -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",
|
||||||
|
@ -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": {
|
||||||
|
@ -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 {
|
||||||
|
@ -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]
|
||||||
|
@ -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() {}
|
|
@ -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;
|
|
||||||
}
|
|
@ -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`
|
||||||
|
@ -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`
|
||||||
|
@ -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`
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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`.
|
||||||
|
@ -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() {}
|
@ -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
|
||||||
|
|
@ -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>`,
|
||||||
|
}
|
@ -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`.
|
@ -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() {}
|
|
@ -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`.
|
|
@ -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`.
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
12
tests/ui/proc-macro/auxiliary/helper-attr.rs
Normal file
12
tests/ui/proc-macro/auxiliary/helper-attr.rs
Normal 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()
|
||||||
|
}
|
19
tests/ui/proc-macro/helper-attr-builtin-derive.rs
Normal file
19
tests/ui/proc-macro/helper-attr-builtin-derive.rs
Normal 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() {}
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
@ -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`.
|
|
Loading…
Reference in New Issue
Block a user