Auto merge of #148167 - Zalathar:rollup-njf167h, r=Zalathar
Rollup of 4 pull requests Successful merges: - rust-lang/rust#145939 (const `select_unpredictable`) - rust-lang/rust#147478 (More intuitive error when using self to instantiate tuple struct with private field) - rust-lang/rust#147866 (Add built-in `const` impls for `Clone` and `Copy`) - rust-lang/rust#148153 (Fix duplicate 'the the' typos in comments) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
@@ -798,7 +798,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||||||
} else {
|
} else {
|
||||||
let predicate = self.tcx().erase_and_anonymize_regions(predicate);
|
let predicate = self.tcx().erase_and_anonymize_regions(predicate);
|
||||||
if cause.has_infer() || cause.has_placeholders() {
|
if cause.has_infer() || cause.has_placeholders() {
|
||||||
// We can't use the the obligation cause as it references
|
// We can't use the obligation cause as it references
|
||||||
// information local to this query.
|
// information local to this query.
|
||||||
cause = self.fcx.misc(cause.span);
|
cause = self.fcx.misc(cause.span);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -211,10 +211,32 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn consider_builtin_copy_clone_candidate(
|
fn consider_builtin_copy_clone_candidate(
|
||||||
_ecx: &mut EvalCtxt<'_, D>,
|
ecx: &mut EvalCtxt<'_, D>,
|
||||||
_goal: Goal<I, Self>,
|
goal: Goal<I, Self>,
|
||||||
) -> Result<Candidate<I>, NoSolution> {
|
) -> Result<Candidate<I>, NoSolution> {
|
||||||
Err(NoSolution)
|
let cx = ecx.cx();
|
||||||
|
|
||||||
|
let self_ty = goal.predicate.self_ty();
|
||||||
|
let constituent_tys =
|
||||||
|
structural_traits::instantiate_constituent_tys_for_copy_clone_trait(ecx, self_ty)?;
|
||||||
|
|
||||||
|
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
|
||||||
|
ecx.enter_forall(constituent_tys, |ecx, tys| {
|
||||||
|
ecx.add_goals(
|
||||||
|
GoalSource::ImplWhereBound,
|
||||||
|
tys.into_iter().map(|ty| {
|
||||||
|
goal.with(
|
||||||
|
cx,
|
||||||
|
ty::ClauseKind::HostEffect(
|
||||||
|
goal.predicate.with_replaced_self_ty(cx, ty),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consider_builtin_fn_ptr_trait_candidate(
|
fn consider_builtin_fn_ptr_trait_candidate(
|
||||||
|
|||||||
@@ -180,6 +180,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||||||
let mut expected = source.descr_expected();
|
let mut expected = source.descr_expected();
|
||||||
let path_str = Segment::names_to_string(path);
|
let path_str = Segment::names_to_string(path);
|
||||||
let item_str = path.last().unwrap().ident;
|
let item_str = path.last().unwrap().ident;
|
||||||
|
|
||||||
if let Some(res) = res {
|
if let Some(res) = res {
|
||||||
BaseError {
|
BaseError {
|
||||||
msg: format!("expected {}, found {} `{}`", expected, res.descr(), path_str),
|
msg: format!("expected {}, found {} `{}`", expected, res.descr(), path_str),
|
||||||
@@ -821,12 +822,18 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||||||
args_snippet = snippet;
|
args_snippet = snippet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(Res::Def(DefKind::Struct, def_id)) = res {
|
||||||
|
self.update_err_for_private_tuple_struct_fields(err, &source, def_id);
|
||||||
|
err.note("constructor is not visible here due to private fields");
|
||||||
|
} else {
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
call_span,
|
call_span,
|
||||||
format!("try calling `{ident}` as a method"),
|
format!("try calling `{ident}` as a method"),
|
||||||
format!("self.{path_str}({args_snippet})"),
|
format!("self.{path_str}({args_snippet})"),
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (true, suggested_candidates, candidates);
|
return (true, suggested_candidates, candidates);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1611,6 +1618,47 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_err_for_private_tuple_struct_fields(
|
||||||
|
&mut self,
|
||||||
|
err: &mut Diag<'_>,
|
||||||
|
source: &PathSource<'_, '_, '_>,
|
||||||
|
def_id: DefId,
|
||||||
|
) -> Option<Vec<Span>> {
|
||||||
|
match source {
|
||||||
|
// e.g. `if let Enum::TupleVariant(field1, field2) = _`
|
||||||
|
PathSource::TupleStruct(_, pattern_spans) => {
|
||||||
|
err.primary_message(
|
||||||
|
"cannot match against a tuple struct which contains private fields",
|
||||||
|
);
|
||||||
|
|
||||||
|
// Use spans of the tuple struct pattern.
|
||||||
|
Some(Vec::from(*pattern_spans))
|
||||||
|
}
|
||||||
|
// e.g. `let _ = Enum::TupleVariant(field1, field2);`
|
||||||
|
PathSource::Expr(Some(Expr {
|
||||||
|
kind: ExprKind::Call(path, args),
|
||||||
|
span: call_span,
|
||||||
|
..
|
||||||
|
})) => {
|
||||||
|
err.primary_message(
|
||||||
|
"cannot initialize a tuple struct which contains private fields",
|
||||||
|
);
|
||||||
|
self.suggest_alternative_construction_methods(
|
||||||
|
def_id,
|
||||||
|
err,
|
||||||
|
path.span,
|
||||||
|
*call_span,
|
||||||
|
&args[..],
|
||||||
|
);
|
||||||
|
// Use spans of the tuple struct definition.
|
||||||
|
self.r
|
||||||
|
.field_idents(def_id)
|
||||||
|
.map(|fields| fields.iter().map(|f| f.span).collect::<Vec<_>>())
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Provides context-dependent help for errors reported by the `smart_resolve_path_fragment`
|
/// Provides context-dependent help for errors reported by the `smart_resolve_path_fragment`
|
||||||
/// function.
|
/// function.
|
||||||
/// Returns `true` if able to provide context-dependent help.
|
/// Returns `true` if able to provide context-dependent help.
|
||||||
@@ -1942,42 +1990,6 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
let update_message =
|
|
||||||
|this: &mut Self, err: &mut Diag<'_>, source: &PathSource<'_, '_, '_>| {
|
|
||||||
match source {
|
|
||||||
// e.g. `if let Enum::TupleVariant(field1, field2) = _`
|
|
||||||
PathSource::TupleStruct(_, pattern_spans) => {
|
|
||||||
err.primary_message(
|
|
||||||
"cannot match against a tuple struct which contains private fields",
|
|
||||||
);
|
|
||||||
|
|
||||||
// Use spans of the tuple struct pattern.
|
|
||||||
Some(Vec::from(*pattern_spans))
|
|
||||||
}
|
|
||||||
// e.g. `let _ = Enum::TupleVariant(field1, field2);`
|
|
||||||
PathSource::Expr(Some(Expr {
|
|
||||||
kind: ExprKind::Call(path, args),
|
|
||||||
span: call_span,
|
|
||||||
..
|
|
||||||
})) => {
|
|
||||||
err.primary_message(
|
|
||||||
"cannot initialize a tuple struct which contains private fields",
|
|
||||||
);
|
|
||||||
this.suggest_alternative_construction_methods(
|
|
||||||
def_id,
|
|
||||||
err,
|
|
||||||
path.span,
|
|
||||||
*call_span,
|
|
||||||
&args[..],
|
|
||||||
);
|
|
||||||
// Use spans of the tuple struct definition.
|
|
||||||
this.r
|
|
||||||
.field_idents(def_id)
|
|
||||||
.map(|fields| fields.iter().map(|f| f.span).collect::<Vec<_>>())
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let is_accessible = self.r.is_accessible_from(ctor_vis, self.parent_scope.module);
|
let is_accessible = self.r.is_accessible_from(ctor_vis, self.parent_scope.module);
|
||||||
if let Some(use_span) = self.r.inaccessible_ctor_reexport.get(&span)
|
if let Some(use_span) = self.r.inaccessible_ctor_reexport.get(&span)
|
||||||
&& is_accessible
|
&& is_accessible
|
||||||
@@ -2006,13 +2018,14 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
update_message(self, err, &source);
|
self.update_err_for_private_tuple_struct_fields(err, &source, def_id);
|
||||||
}
|
}
|
||||||
if !is_expected(ctor_def) || is_accessible {
|
if !is_expected(ctor_def) || is_accessible {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let field_spans = update_message(self, err, &source);
|
let field_spans =
|
||||||
|
self.update_err_for_private_tuple_struct_fields(err, &source, def_id);
|
||||||
|
|
||||||
if let Some(spans) =
|
if let Some(spans) =
|
||||||
field_spans.filter(|spans| spans.len() > 0 && fields.len() == spans.len())
|
field_spans.filter(|spans| spans.len() > 0 && fields.len() == spans.len())
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use rustc_middle::span_bug;
|
|||||||
use rustc_middle::traits::query::NoSolution;
|
use rustc_middle::traits::query::NoSolution;
|
||||||
use rustc_middle::ty::elaborate::elaborate;
|
use rustc_middle::ty::elaborate::elaborate;
|
||||||
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
|
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
|
||||||
use rustc_middle::ty::{self, TypingMode};
|
use rustc_middle::ty::{self, Ty, TypingMode};
|
||||||
use thin_vec::{ThinVec, thin_vec};
|
use thin_vec::{ThinVec, thin_vec};
|
||||||
|
|
||||||
use super::SelectionContext;
|
use super::SelectionContext;
|
||||||
@@ -303,6 +303,9 @@ fn evaluate_host_effect_from_builtin_impls<'tcx>(
|
|||||||
obligation: &HostEffectObligation<'tcx>,
|
obligation: &HostEffectObligation<'tcx>,
|
||||||
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
|
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
|
||||||
match selcx.tcx().as_lang_item(obligation.predicate.def_id()) {
|
match selcx.tcx().as_lang_item(obligation.predicate.def_id()) {
|
||||||
|
Some(LangItem::Copy | LangItem::Clone) => {
|
||||||
|
evaluate_host_effect_for_copy_clone_goal(selcx, obligation)
|
||||||
|
}
|
||||||
Some(LangItem::Destruct) => evaluate_host_effect_for_destruct_goal(selcx, obligation),
|
Some(LangItem::Destruct) => evaluate_host_effect_for_destruct_goal(selcx, obligation),
|
||||||
Some(LangItem::Fn | LangItem::FnMut | LangItem::FnOnce) => {
|
Some(LangItem::Fn | LangItem::FnMut | LangItem::FnOnce) => {
|
||||||
evaluate_host_effect_for_fn_goal(selcx, obligation)
|
evaluate_host_effect_for_fn_goal(selcx, obligation)
|
||||||
@@ -311,6 +314,100 @@ fn evaluate_host_effect_from_builtin_impls<'tcx>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn evaluate_host_effect_for_copy_clone_goal<'tcx>(
|
||||||
|
selcx: &mut SelectionContext<'_, 'tcx>,
|
||||||
|
obligation: &HostEffectObligation<'tcx>,
|
||||||
|
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
|
||||||
|
let tcx = selcx.tcx();
|
||||||
|
let self_ty = obligation.predicate.self_ty();
|
||||||
|
let constituent_tys = match *self_ty.kind() {
|
||||||
|
// impl Copy/Clone for FnDef, FnPtr
|
||||||
|
ty::FnDef(..) | ty::FnPtr(..) | ty::Error(_) => Ok(ty::Binder::dummy(vec![])),
|
||||||
|
|
||||||
|
// Implementations are provided in core
|
||||||
|
ty::Uint(_)
|
||||||
|
| ty::Int(_)
|
||||||
|
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
|
||||||
|
| ty::Bool
|
||||||
|
| ty::Float(_)
|
||||||
|
| ty::Char
|
||||||
|
| ty::RawPtr(..)
|
||||||
|
| ty::Never
|
||||||
|
| ty::Ref(_, _, ty::Mutability::Not)
|
||||||
|
| ty::Array(..) => Err(EvaluationFailure::NoSolution),
|
||||||
|
|
||||||
|
// Cannot implement in core, as we can't be generic over patterns yet,
|
||||||
|
// so we'd have to list all patterns and type combinations.
|
||||||
|
ty::Pat(ty, ..) => Ok(ty::Binder::dummy(vec![ty])),
|
||||||
|
|
||||||
|
ty::Dynamic(..)
|
||||||
|
| ty::Str
|
||||||
|
| ty::Slice(_)
|
||||||
|
| ty::Foreign(..)
|
||||||
|
| ty::Ref(_, _, ty::Mutability::Mut)
|
||||||
|
| ty::Adt(_, _)
|
||||||
|
| ty::Alias(_, _)
|
||||||
|
| ty::Param(_)
|
||||||
|
| ty::Placeholder(..) => Err(EvaluationFailure::NoSolution),
|
||||||
|
|
||||||
|
ty::Bound(..)
|
||||||
|
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
|
||||||
|
panic!("unexpected type `{self_ty:?}`")
|
||||||
|
}
|
||||||
|
|
||||||
|
// impl Copy/Clone for (T1, T2, .., Tn) where T1: Copy/Clone, T2: Copy/Clone, .. Tn: Copy/Clone
|
||||||
|
ty::Tuple(tys) => Ok(ty::Binder::dummy(tys.to_vec())),
|
||||||
|
|
||||||
|
// impl Copy/Clone for Closure where Self::TupledUpvars: Copy/Clone
|
||||||
|
ty::Closure(_, args) => Ok(ty::Binder::dummy(vec![args.as_closure().tupled_upvars_ty()])),
|
||||||
|
|
||||||
|
// impl Copy/Clone for CoroutineClosure where Self::TupledUpvars: Copy/Clone
|
||||||
|
ty::CoroutineClosure(_, args) => {
|
||||||
|
Ok(ty::Binder::dummy(vec![args.as_coroutine_closure().tupled_upvars_ty()]))
|
||||||
|
}
|
||||||
|
|
||||||
|
// only when `coroutine_clone` is enabled and the coroutine is movable
|
||||||
|
// impl Copy/Clone for Coroutine where T: Copy/Clone forall T in (upvars, witnesses)
|
||||||
|
ty::Coroutine(def_id, args) => {
|
||||||
|
if selcx.should_stall_coroutine(def_id) {
|
||||||
|
return Err(EvaluationFailure::Ambiguous);
|
||||||
|
}
|
||||||
|
match tcx.coroutine_movability(def_id) {
|
||||||
|
ty::Movability::Static => Err(EvaluationFailure::NoSolution),
|
||||||
|
ty::Movability::Movable => {
|
||||||
|
if tcx.features().coroutine_clone() {
|
||||||
|
Ok(ty::Binder::dummy(vec![
|
||||||
|
args.as_coroutine().tupled_upvars_ty(),
|
||||||
|
Ty::new_coroutine_witness_for_coroutine(tcx, def_id, args),
|
||||||
|
]))
|
||||||
|
} else {
|
||||||
|
Err(EvaluationFailure::NoSolution)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::UnsafeBinder(_) => Err(EvaluationFailure::NoSolution),
|
||||||
|
|
||||||
|
// impl Copy/Clone for CoroutineWitness where T: Copy/Clone forall T in coroutine_hidden_types
|
||||||
|
ty::CoroutineWitness(def_id, args) => Ok(tcx
|
||||||
|
.coroutine_hidden_types(def_id)
|
||||||
|
.instantiate(tcx, args)
|
||||||
|
.map_bound(|bound| bound.types.to_vec())),
|
||||||
|
}?;
|
||||||
|
|
||||||
|
Ok(constituent_tys
|
||||||
|
.iter()
|
||||||
|
.map(|ty| {
|
||||||
|
obligation.with(
|
||||||
|
tcx,
|
||||||
|
ty.map_bound(|ty| ty::TraitRef::new(tcx, obligation.predicate.def_id(), [ty]))
|
||||||
|
.to_host_effect_clause(tcx, obligation.predicate.constness),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: Keep this in sync with `const_conditions_for_destruct` in the new solver.
|
// NOTE: Keep this in sync with `const_conditions_for_destruct` in the new solver.
|
||||||
fn evaluate_host_effect_for_destruct_goal<'tcx>(
|
fn evaluate_host_effect_for_destruct_goal<'tcx>(
|
||||||
selcx: &mut SelectionContext<'_, 'tcx>,
|
selcx: &mut SelectionContext<'_, 'tcx>,
|
||||||
|
|||||||
@@ -2877,7 +2877,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
|||||||
obligations
|
obligations
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_stall_coroutine(&self, def_id: DefId) -> bool {
|
pub(super) fn should_stall_coroutine(&self, def_id: DefId) -> bool {
|
||||||
match self.infcx.typing_mode() {
|
match self.infcx.typing_mode() {
|
||||||
TypingMode::Analysis { defining_opaque_types_and_generators: stalled_generators } => {
|
TypingMode::Analysis { defining_opaque_types_and_generators: stalled_generators } => {
|
||||||
def_id.as_local().is_some_and(|def_id| stalled_generators.contains(&def_id))
|
def_id.as_local().is_some_and(|def_id| stalled_generators.contains(&def_id))
|
||||||
|
|||||||
@@ -924,7 +924,7 @@ enum RebaseReason<X: Cx> {
|
|||||||
///
|
///
|
||||||
/// This either happens in the first evaluation step for the cycle head.
|
/// This either happens in the first evaluation step for the cycle head.
|
||||||
/// In this case the used provisional result depends on the cycle `PathKind`.
|
/// In this case the used provisional result depends on the cycle `PathKind`.
|
||||||
/// We store this path kind to check whether the the provisional cache entry
|
/// We store this path kind to check whether the provisional cache entry
|
||||||
/// we're rebasing relied on the same cycles.
|
/// we're rebasing relied on the same cycles.
|
||||||
///
|
///
|
||||||
/// In later iterations cycles always return `stack_entry.provisional_result`
|
/// In later iterations cycles always return `stack_entry.provisional_result`
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
//!
|
//!
|
||||||
//! Hints may be compile time or runtime.
|
//! Hints may be compile time or runtime.
|
||||||
|
|
||||||
|
use crate::marker::Destruct;
|
||||||
use crate::mem::MaybeUninit;
|
use crate::mem::MaybeUninit;
|
||||||
use crate::{intrinsics, ub_checks};
|
use crate::{intrinsics, ub_checks};
|
||||||
|
|
||||||
@@ -771,7 +772,11 @@ pub const fn cold_path() {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[stable(feature = "select_unpredictable", since = "1.88.0")]
|
#[stable(feature = "select_unpredictable", since = "1.88.0")]
|
||||||
pub fn select_unpredictable<T>(condition: bool, true_val: T, false_val: T) -> T {
|
#[rustc_const_unstable(feature = "const_select_unpredictable", issue = "145938")]
|
||||||
|
pub const fn select_unpredictable<T>(condition: bool, true_val: T, false_val: T) -> T
|
||||||
|
where
|
||||||
|
T: [const] Destruct,
|
||||||
|
{
|
||||||
// FIXME(https://github.com/rust-lang/unsafe-code-guidelines/issues/245):
|
// FIXME(https://github.com/rust-lang/unsafe-code-guidelines/issues/245):
|
||||||
// Change this to use ManuallyDrop instead.
|
// Change this to use ManuallyDrop instead.
|
||||||
let mut true_val = MaybeUninit::new(true_val);
|
let mut true_val = MaybeUninit::new(true_val);
|
||||||
|
|||||||
@@ -55,7 +55,7 @@
|
|||||||
#![allow(missing_docs)]
|
#![allow(missing_docs)]
|
||||||
|
|
||||||
use crate::ffi::va_list::{VaArgSafe, VaListImpl};
|
use crate::ffi::va_list::{VaArgSafe, VaListImpl};
|
||||||
use crate::marker::{ConstParamTy, DiscriminantKind, PointeeSized, Tuple};
|
use crate::marker::{ConstParamTy, Destruct, DiscriminantKind, PointeeSized, Tuple};
|
||||||
use crate::ptr;
|
use crate::ptr;
|
||||||
|
|
||||||
mod bounds;
|
mod bounds;
|
||||||
@@ -477,11 +477,15 @@ pub const fn unlikely(b: bool) -> bool {
|
|||||||
/// However unlike the public form, the intrinsic will not drop the value that
|
/// However unlike the public form, the intrinsic will not drop the value that
|
||||||
/// is not selected.
|
/// is not selected.
|
||||||
#[unstable(feature = "core_intrinsics", issue = "none")]
|
#[unstable(feature = "core_intrinsics", issue = "none")]
|
||||||
|
#[rustc_const_unstable(feature = "const_select_unpredictable", issue = "145938")]
|
||||||
#[rustc_intrinsic]
|
#[rustc_intrinsic]
|
||||||
#[rustc_nounwind]
|
#[rustc_nounwind]
|
||||||
#[miri::intrinsic_fallback_is_spec]
|
#[miri::intrinsic_fallback_is_spec]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn select_unpredictable<T>(b: bool, true_val: T, false_val: T) -> T {
|
pub const fn select_unpredictable<T>(b: bool, true_val: T, false_val: T) -> T
|
||||||
|
where
|
||||||
|
T: [const] Destruct,
|
||||||
|
{
|
||||||
if b { true_val } else { false_val }
|
if b { true_val } else { false_val }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -106,6 +106,7 @@
|
|||||||
#![feature(const_cmp)]
|
#![feature(const_cmp)]
|
||||||
#![feature(const_destruct)]
|
#![feature(const_destruct)]
|
||||||
#![feature(const_eval_select)]
|
#![feature(const_eval_select)]
|
||||||
|
#![feature(const_select_unpredictable)]
|
||||||
#![feature(core_intrinsics)]
|
#![feature(core_intrinsics)]
|
||||||
#![feature(coverage_attribute)]
|
#![feature(coverage_attribute)]
|
||||||
#![feature(disjoint_bitor)]
|
#![feature(disjoint_bitor)]
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
#[test]
|
#[test]
|
||||||
fn select_unpredictable_drop() {
|
fn select_unpredictable_drop() {
|
||||||
use core::cell::Cell;
|
use core::cell::Cell;
|
||||||
|
|
||||||
struct X<'a>(&'a Cell<bool>);
|
struct X<'a>(&'a Cell<bool>);
|
||||||
impl Drop for X<'_> {
|
impl const Drop for X<'_> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.0.set(true);
|
self.0.set(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fn do_test() {
|
||||||
let a_dropped = Cell::new(false);
|
let a_dropped = Cell::new(false);
|
||||||
let b_dropped = Cell::new(false);
|
let b_dropped = Cell::new(false);
|
||||||
let a = X(&a_dropped);
|
let a = X(&a_dropped);
|
||||||
@@ -22,6 +24,12 @@ fn select_unpredictable_drop() {
|
|||||||
assert!(b_dropped.get());
|
assert!(b_dropped.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
do_test();
|
||||||
|
const {
|
||||||
|
do_test();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic = "message canary"]
|
#[should_panic = "message canary"]
|
||||||
fn select_unpredictable_drop_on_panic() {
|
fn select_unpredictable_drop_on_panic() {
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
#![feature(const_option_ops)]
|
#![feature(const_option_ops)]
|
||||||
#![feature(const_ref_cell)]
|
#![feature(const_ref_cell)]
|
||||||
#![feature(const_result_trait_fn)]
|
#![feature(const_result_trait_fn)]
|
||||||
|
#![feature(const_select_unpredictable)]
|
||||||
#![feature(const_trait_impl)]
|
#![feature(const_trait_impl)]
|
||||||
#![feature(control_flow_ok)]
|
#![feature(control_flow_ok)]
|
||||||
#![feature(core_float_math)]
|
#![feature(core_float_math)]
|
||||||
|
|||||||
16
tests/ui/resolve/private-constructor-self-issue-147343.rs
Normal file
16
tests/ui/resolve/private-constructor-self-issue-147343.rs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
mod m {
|
||||||
|
pub struct S(crate::P);
|
||||||
|
}
|
||||||
|
|
||||||
|
use m::S;
|
||||||
|
|
||||||
|
struct P;
|
||||||
|
|
||||||
|
impl P {
|
||||||
|
fn foo(self) {
|
||||||
|
S(self);
|
||||||
|
//~^ ERROR cannot initialize a tuple struct which contains private fields [E0423]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
error[E0423]: cannot initialize a tuple struct which contains private fields
|
||||||
|
--> $DIR/private-constructor-self-issue-147343.rs:11:9
|
||||||
|
|
|
||||||
|
LL | S(self);
|
||||||
|
| ^
|
||||||
|
|
|
||||||
|
= note: constructor is not visible here due to private fields
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0423`.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
//@ run-pass
|
//@ check-pass
|
||||||
#![feature(const_trait_impl, const_default)]
|
#![feature(const_trait_impl, const_default)]
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
// alloc::string
|
// alloc::string
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
//@ run-pass
|
//@ check-pass
|
||||||
#![feature(
|
#![feature(
|
||||||
const_trait_impl, const_default, ptr_alignment_type, ascii_char, f16, f128, sync_unsafe_cell,
|
const_clone,
|
||||||
|
const_default,
|
||||||
|
const_trait_impl,
|
||||||
|
ptr_alignment_type,
|
||||||
|
ascii_char,
|
||||||
|
f16,
|
||||||
|
f128,
|
||||||
|
sync_unsafe_cell,
|
||||||
)]
|
)]
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
// core::default
|
// core::default
|
||||||
@@ -43,4 +50,8 @@ const REF_CELL: std::cell::RefCell<()> = Default::default();
|
|||||||
const UNSAFE_CELL: std::cell::UnsafeCell<()> = Default::default();
|
const UNSAFE_CELL: std::cell::UnsafeCell<()> = Default::default();
|
||||||
const SYNC_UNSAFE_CELL: std::cell::SyncUnsafeCell<()> = Default::default();
|
const SYNC_UNSAFE_CELL: std::cell::SyncUnsafeCell<()> = Default::default();
|
||||||
|
|
||||||
|
// `Clone` for tuples
|
||||||
|
const BUILTIN_CLONE: () = ().clone();
|
||||||
|
const BUILTIN_CLONE_2: (u32, i32) = (42, 100).clone();
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|||||||
Reference in New Issue
Block a user