Skip to content

Commit 9ea8d67

Browse files
committed
Auto merge of #148167 - Zalathar:rollup-njf167h, r=Zalathar
Rollup of 4 pull requests Successful merges: - #145939 (const `select_unpredictable`) - #147478 (More intuitive error when using self to instantiate tuple struct with private field) - #147866 (Add built-in `const` impls for `Clone` and `Copy`) - #148153 (Fix duplicate 'the the' typos in comments) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 4b53279 + 791165c commit 9ea8d67

File tree

15 files changed

+259
-70
lines changed

15 files changed

+259
-70
lines changed

compiler/rustc_hir_typeck/src/writeback.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -798,7 +798,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
798798
} else {
799799
let predicate = self.tcx().erase_and_anonymize_regions(predicate);
800800
if cause.has_infer() || cause.has_placeholders() {
801-
// We can't use the the obligation cause as it references
801+
// We can't use the obligation cause as it references
802802
// information local to this query.
803803
cause = self.fcx.misc(cause.span);
804804
}

compiler/rustc_next_trait_solver/src/solve/effect_goals.rs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -211,10 +211,32 @@ where
211211
}
212212

213213
fn consider_builtin_copy_clone_candidate(
214-
_ecx: &mut EvalCtxt<'_, D>,
215-
_goal: Goal<I, Self>,
214+
ecx: &mut EvalCtxt<'_, D>,
215+
goal: Goal<I, Self>,
216216
) -> Result<Candidate<I>, NoSolution> {
217-
Err(NoSolution)
217+
let cx = ecx.cx();
218+
219+
let self_ty = goal.predicate.self_ty();
220+
let constituent_tys =
221+
structural_traits::instantiate_constituent_tys_for_copy_clone_trait(ecx, self_ty)?;
222+
223+
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
224+
ecx.enter_forall(constituent_tys, |ecx, tys| {
225+
ecx.add_goals(
226+
GoalSource::ImplWhereBound,
227+
tys.into_iter().map(|ty| {
228+
goal.with(
229+
cx,
230+
ty::ClauseKind::HostEffect(
231+
goal.predicate.with_replaced_self_ty(cx, ty),
232+
),
233+
)
234+
}),
235+
);
236+
});
237+
238+
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
239+
})
218240
}
219241

220242
fn consider_builtin_fn_ptr_trait_candidate(

compiler/rustc_resolve/src/late/diagnostics.rs

Lines changed: 57 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
180180
let mut expected = source.descr_expected();
181181
let path_str = Segment::names_to_string(path);
182182
let item_str = path.last().unwrap().ident;
183+
183184
if let Some(res) = res {
184185
BaseError {
185186
msg: format!("expected {}, found {} `{}`", expected, res.descr(), path_str),
@@ -821,12 +822,18 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
821822
args_snippet = snippet;
822823
}
823824

824-
err.span_suggestion(
825-
call_span,
826-
format!("try calling `{ident}` as a method"),
827-
format!("self.{path_str}({args_snippet})"),
828-
Applicability::MachineApplicable,
829-
);
825+
if let Some(Res::Def(DefKind::Struct, def_id)) = res {
826+
self.update_err_for_private_tuple_struct_fields(err, &source, def_id);
827+
err.note("constructor is not visible here due to private fields");
828+
} else {
829+
err.span_suggestion(
830+
call_span,
831+
format!("try calling `{ident}` as a method"),
832+
format!("self.{path_str}({args_snippet})"),
833+
Applicability::MachineApplicable,
834+
);
835+
}
836+
830837
return (true, suggested_candidates, candidates);
831838
}
832839
}
@@ -1611,6 +1618,47 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
16111618
}
16121619
}
16131620

1621+
fn update_err_for_private_tuple_struct_fields(
1622+
&mut self,
1623+
err: &mut Diag<'_>,
1624+
source: &PathSource<'_, '_, '_>,
1625+
def_id: DefId,
1626+
) -> Option<Vec<Span>> {
1627+
match source {
1628+
// e.g. `if let Enum::TupleVariant(field1, field2) = _`
1629+
PathSource::TupleStruct(_, pattern_spans) => {
1630+
err.primary_message(
1631+
"cannot match against a tuple struct which contains private fields",
1632+
);
1633+
1634+
// Use spans of the tuple struct pattern.
1635+
Some(Vec::from(*pattern_spans))
1636+
}
1637+
// e.g. `let _ = Enum::TupleVariant(field1, field2);`
1638+
PathSource::Expr(Some(Expr {
1639+
kind: ExprKind::Call(path, args),
1640+
span: call_span,
1641+
..
1642+
})) => {
1643+
err.primary_message(
1644+
"cannot initialize a tuple struct which contains private fields",
1645+
);
1646+
self.suggest_alternative_construction_methods(
1647+
def_id,
1648+
err,
1649+
path.span,
1650+
*call_span,
1651+
&args[..],
1652+
);
1653+
// Use spans of the tuple struct definition.
1654+
self.r
1655+
.field_idents(def_id)
1656+
.map(|fields| fields.iter().map(|f| f.span).collect::<Vec<_>>())
1657+
}
1658+
_ => None,
1659+
}
1660+
}
1661+
16141662
/// Provides context-dependent help for errors reported by the `smart_resolve_path_fragment`
16151663
/// function.
16161664
/// Returns `true` if able to provide context-dependent help.
@@ -1942,42 +1990,6 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
19421990
return true;
19431991
};
19441992

1945-
let update_message =
1946-
|this: &mut Self, err: &mut Diag<'_>, source: &PathSource<'_, '_, '_>| {
1947-
match source {
1948-
// e.g. `if let Enum::TupleVariant(field1, field2) = _`
1949-
PathSource::TupleStruct(_, pattern_spans) => {
1950-
err.primary_message(
1951-
"cannot match against a tuple struct which contains private fields",
1952-
);
1953-
1954-
// Use spans of the tuple struct pattern.
1955-
Some(Vec::from(*pattern_spans))
1956-
}
1957-
// e.g. `let _ = Enum::TupleVariant(field1, field2);`
1958-
PathSource::Expr(Some(Expr {
1959-
kind: ExprKind::Call(path, args),
1960-
span: call_span,
1961-
..
1962-
})) => {
1963-
err.primary_message(
1964-
"cannot initialize a tuple struct which contains private fields",
1965-
);
1966-
this.suggest_alternative_construction_methods(
1967-
def_id,
1968-
err,
1969-
path.span,
1970-
*call_span,
1971-
&args[..],
1972-
);
1973-
// Use spans of the tuple struct definition.
1974-
this.r
1975-
.field_idents(def_id)
1976-
.map(|fields| fields.iter().map(|f| f.span).collect::<Vec<_>>())
1977-
}
1978-
_ => None,
1979-
}
1980-
};
19811993
let is_accessible = self.r.is_accessible_from(ctor_vis, self.parent_scope.module);
19821994
if let Some(use_span) = self.r.inaccessible_ctor_reexport.get(&span)
19831995
&& is_accessible
@@ -2006,13 +2018,14 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
20062018
Applicability::MachineApplicable,
20072019
);
20082020
}
2009-
update_message(self, err, &source);
2021+
self.update_err_for_private_tuple_struct_fields(err, &source, def_id);
20102022
}
20112023
if !is_expected(ctor_def) || is_accessible {
20122024
return true;
20132025
}
20142026

2015-
let field_spans = update_message(self, err, &source);
2027+
let field_spans =
2028+
self.update_err_for_private_tuple_struct_fields(err, &source, def_id);
20162029

20172030
if let Some(spans) =
20182031
field_spans.filter(|spans| spans.len() > 0 && fields.len() == spans.len())

compiler/rustc_trait_selection/src/traits/effects.rs

Lines changed: 98 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_middle::span_bug;
88
use rustc_middle::traits::query::NoSolution;
99
use rustc_middle::ty::elaborate::elaborate;
1010
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
11-
use rustc_middle::ty::{self, TypingMode};
11+
use rustc_middle::ty::{self, Ty, TypingMode};
1212
use thin_vec::{ThinVec, thin_vec};
1313

1414
use super::SelectionContext;
@@ -303,6 +303,9 @@ fn evaluate_host_effect_from_builtin_impls<'tcx>(
303303
obligation: &HostEffectObligation<'tcx>,
304304
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
305305
match selcx.tcx().as_lang_item(obligation.predicate.def_id()) {
306+
Some(LangItem::Copy | LangItem::Clone) => {
307+
evaluate_host_effect_for_copy_clone_goal(selcx, obligation)
308+
}
306309
Some(LangItem::Destruct) => evaluate_host_effect_for_destruct_goal(selcx, obligation),
307310
Some(LangItem::Fn | LangItem::FnMut | LangItem::FnOnce) => {
308311
evaluate_host_effect_for_fn_goal(selcx, obligation)
@@ -311,6 +314,100 @@ fn evaluate_host_effect_from_builtin_impls<'tcx>(
311314
}
312315
}
313316

317+
fn evaluate_host_effect_for_copy_clone_goal<'tcx>(
318+
selcx: &mut SelectionContext<'_, 'tcx>,
319+
obligation: &HostEffectObligation<'tcx>,
320+
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
321+
let tcx = selcx.tcx();
322+
let self_ty = obligation.predicate.self_ty();
323+
let constituent_tys = match *self_ty.kind() {
324+
// impl Copy/Clone for FnDef, FnPtr
325+
ty::FnDef(..) | ty::FnPtr(..) | ty::Error(_) => Ok(ty::Binder::dummy(vec![])),
326+
327+
// Implementations are provided in core
328+
ty::Uint(_)
329+
| ty::Int(_)
330+
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
331+
| ty::Bool
332+
| ty::Float(_)
333+
| ty::Char
334+
| ty::RawPtr(..)
335+
| ty::Never
336+
| ty::Ref(_, _, ty::Mutability::Not)
337+
| ty::Array(..) => Err(EvaluationFailure::NoSolution),
338+
339+
// Cannot implement in core, as we can't be generic over patterns yet,
340+
// so we'd have to list all patterns and type combinations.
341+
ty::Pat(ty, ..) => Ok(ty::Binder::dummy(vec![ty])),
342+
343+
ty::Dynamic(..)
344+
| ty::Str
345+
| ty::Slice(_)
346+
| ty::Foreign(..)
347+
| ty::Ref(_, _, ty::Mutability::Mut)
348+
| ty::Adt(_, _)
349+
| ty::Alias(_, _)
350+
| ty::Param(_)
351+
| ty::Placeholder(..) => Err(EvaluationFailure::NoSolution),
352+
353+
ty::Bound(..)
354+
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
355+
panic!("unexpected type `{self_ty:?}`")
356+
}
357+
358+
// impl Copy/Clone for (T1, T2, .., Tn) where T1: Copy/Clone, T2: Copy/Clone, .. Tn: Copy/Clone
359+
ty::Tuple(tys) => Ok(ty::Binder::dummy(tys.to_vec())),
360+
361+
// impl Copy/Clone for Closure where Self::TupledUpvars: Copy/Clone
362+
ty::Closure(_, args) => Ok(ty::Binder::dummy(vec![args.as_closure().tupled_upvars_ty()])),
363+
364+
// impl Copy/Clone for CoroutineClosure where Self::TupledUpvars: Copy/Clone
365+
ty::CoroutineClosure(_, args) => {
366+
Ok(ty::Binder::dummy(vec![args.as_coroutine_closure().tupled_upvars_ty()]))
367+
}
368+
369+
// only when `coroutine_clone` is enabled and the coroutine is movable
370+
// impl Copy/Clone for Coroutine where T: Copy/Clone forall T in (upvars, witnesses)
371+
ty::Coroutine(def_id, args) => {
372+
if selcx.should_stall_coroutine(def_id) {
373+
return Err(EvaluationFailure::Ambiguous);
374+
}
375+
match tcx.coroutine_movability(def_id) {
376+
ty::Movability::Static => Err(EvaluationFailure::NoSolution),
377+
ty::Movability::Movable => {
378+
if tcx.features().coroutine_clone() {
379+
Ok(ty::Binder::dummy(vec![
380+
args.as_coroutine().tupled_upvars_ty(),
381+
Ty::new_coroutine_witness_for_coroutine(tcx, def_id, args),
382+
]))
383+
} else {
384+
Err(EvaluationFailure::NoSolution)
385+
}
386+
}
387+
}
388+
}
389+
390+
ty::UnsafeBinder(_) => Err(EvaluationFailure::NoSolution),
391+
392+
// impl Copy/Clone for CoroutineWitness where T: Copy/Clone forall T in coroutine_hidden_types
393+
ty::CoroutineWitness(def_id, args) => Ok(tcx
394+
.coroutine_hidden_types(def_id)
395+
.instantiate(tcx, args)
396+
.map_bound(|bound| bound.types.to_vec())),
397+
}?;
398+
399+
Ok(constituent_tys
400+
.iter()
401+
.map(|ty| {
402+
obligation.with(
403+
tcx,
404+
ty.map_bound(|ty| ty::TraitRef::new(tcx, obligation.predicate.def_id(), [ty]))
405+
.to_host_effect_clause(tcx, obligation.predicate.constness),
406+
)
407+
})
408+
.collect())
409+
}
410+
314411
// NOTE: Keep this in sync with `const_conditions_for_destruct` in the new solver.
315412
fn evaluate_host_effect_for_destruct_goal<'tcx>(
316413
selcx: &mut SelectionContext<'_, 'tcx>,

compiler/rustc_trait_selection/src/traits/select/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2877,7 +2877,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
28772877
obligations
28782878
}
28792879

2880-
fn should_stall_coroutine(&self, def_id: DefId) -> bool {
2880+
pub(super) fn should_stall_coroutine(&self, def_id: DefId) -> bool {
28812881
match self.infcx.typing_mode() {
28822882
TypingMode::Analysis { defining_opaque_types_and_generators: stalled_generators } => {
28832883
def_id.as_local().is_some_and(|def_id| stalled_generators.contains(&def_id))

compiler/rustc_type_ir/src/search_graph/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -924,7 +924,7 @@ enum RebaseReason<X: Cx> {
924924
///
925925
/// This either happens in the first evaluation step for the cycle head.
926926
/// In this case the used provisional result depends on the cycle `PathKind`.
927-
/// We store this path kind to check whether the the provisional cache entry
927+
/// We store this path kind to check whether the provisional cache entry
928928
/// we're rebasing relied on the same cycles.
929929
///
930930
/// In later iterations cycles always return `stack_entry.provisional_result`

library/core/src/hint.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
//!
55
//! Hints may be compile time or runtime.
66
7+
use crate::marker::Destruct;
78
use crate::mem::MaybeUninit;
89
use crate::{intrinsics, ub_checks};
910

@@ -771,7 +772,11 @@ pub const fn cold_path() {
771772
/// ```
772773
#[inline(always)]
773774
#[stable(feature = "select_unpredictable", since = "1.88.0")]
774-
pub fn select_unpredictable<T>(condition: bool, true_val: T, false_val: T) -> T {
775+
#[rustc_const_unstable(feature = "const_select_unpredictable", issue = "145938")]
776+
pub const fn select_unpredictable<T>(condition: bool, true_val: T, false_val: T) -> T
777+
where
778+
T: [const] Destruct,
779+
{
775780
// FIXME(https://github.com/rust-lang/unsafe-code-guidelines/issues/245):
776781
// Change this to use ManuallyDrop instead.
777782
let mut true_val = MaybeUninit::new(true_val);

library/core/src/intrinsics/mod.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
#![allow(missing_docs)]
5656

5757
use crate::ffi::va_list::{VaArgSafe, VaListImpl};
58-
use crate::marker::{ConstParamTy, DiscriminantKind, PointeeSized, Tuple};
58+
use crate::marker::{ConstParamTy, Destruct, DiscriminantKind, PointeeSized, Tuple};
5959
use crate::ptr;
6060

6161
mod bounds;
@@ -477,11 +477,15 @@ pub const fn unlikely(b: bool) -> bool {
477477
/// However unlike the public form, the intrinsic will not drop the value that
478478
/// is not selected.
479479
#[unstable(feature = "core_intrinsics", issue = "none")]
480+
#[rustc_const_unstable(feature = "const_select_unpredictable", issue = "145938")]
480481
#[rustc_intrinsic]
481482
#[rustc_nounwind]
482483
#[miri::intrinsic_fallback_is_spec]
483484
#[inline]
484-
pub fn select_unpredictable<T>(b: bool, true_val: T, false_val: T) -> T {
485+
pub const fn select_unpredictable<T>(b: bool, true_val: T, false_val: T) -> T
486+
where
487+
T: [const] Destruct,
488+
{
485489
if b { true_val } else { false_val }
486490
}
487491

library/core/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@
106106
#![feature(const_cmp)]
107107
#![feature(const_destruct)]
108108
#![feature(const_eval_select)]
109+
#![feature(const_select_unpredictable)]
109110
#![feature(core_intrinsics)]
110111
#![feature(coverage_attribute)]
111112
#![feature(disjoint_bitor)]

0 commit comments

Comments
 (0)