Skip to content

Commit 7a8636c

Browse files
committed
Auto merge of #100982 - fee1-dead-contrib:const-impl-requires-const-trait, r=oli-obk
Require `#[const_trait]` on `Trait` for `impl const Trait` r? `@oli-obk`
2 parents 626b02a + 898c76c commit 7a8636c

File tree

80 files changed

+432
-244
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

80 files changed

+432
-244
lines changed

Diff for: compiler/rustc_borrowck/src/type_check/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -428,12 +428,18 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
428428
}
429429

430430
if let ty::FnDef(def_id, substs) = *constant.literal.ty().kind() {
431+
// const_trait_impl: use a non-const param env when checking that a FnDef type is well formed.
432+
// this is because the well-formedness of the function does not need to be proved to have `const`
433+
// impls for trait bounds.
431434
let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs);
435+
let prev = self.cx.param_env;
436+
self.cx.param_env = prev.without_const();
432437
self.cx.normalize_and_prove_instantiated_predicates(
433438
def_id,
434439
instantiated_predicates,
435440
locations,
436441
);
442+
self.cx.param_env = prev;
437443
}
438444
}
439445
}

Diff for: compiler/rustc_const_eval/src/transform/check_consts/check.rs

+42-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,11 @@ use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty,
1313
use rustc_middle::ty::{Binder, TraitPredicate, TraitRef, TypeVisitable};
1414
use rustc_mir_dataflow::{self, Analysis};
1515
use rustc_span::{sym, Span, Symbol};
16-
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
17-
use rustc_trait_selection::traits::SelectionContext;
16+
use rustc_trait_selection::infer::InferCtxtExt;
17+
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
18+
use rustc_trait_selection::traits::{
19+
self, ObligationCauseCode, SelectionContext, TraitEngine, TraitEngineExt,
20+
};
1821

1922
use std::mem;
2023
use std::ops::Deref;
@@ -739,6 +742,43 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
739742
selcx.select(&obligation)
740743
});
741744

745+
// do a well-formedness check on the trait method being called. This is because typeck only does a
746+
// "non-const" check. This is required for correctness here.
747+
tcx.infer_ctxt().enter(|infcx| {
748+
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
749+
let predicates = tcx.predicates_of(callee).instantiate(tcx, substs);
750+
let hir_id = tcx
751+
.hir()
752+
.local_def_id_to_hir_id(self.body.source.def_id().expect_local());
753+
let cause = || {
754+
ObligationCause::new(
755+
terminator.source_info.span,
756+
hir_id,
757+
ObligationCauseCode::ItemObligation(callee),
758+
)
759+
};
760+
let normalized = infcx.partially_normalize_associated_types_in(
761+
cause(),
762+
param_env,
763+
predicates,
764+
);
765+
766+
for p in normalized.obligations {
767+
fulfill_cx.register_predicate_obligation(&infcx, p);
768+
}
769+
for obligation in traits::predicates_for_generics(
770+
|_, _| cause(),
771+
self.param_env,
772+
normalized.value,
773+
) {
774+
fulfill_cx.register_predicate_obligation(&infcx, obligation);
775+
}
776+
let errors = fulfill_cx.select_all_or_error(&infcx);
777+
if !errors.is_empty() {
778+
infcx.report_fulfillment_errors(&errors, None, false);
779+
}
780+
});
781+
742782
match implsrc {
743783
Ok(Some(ImplSource::Param(_, ty::BoundConstness::ConstIfConst))) => {
744784
debug!(

Diff for: compiler/rustc_feature/src/builtin_attrs.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
468468
// RFC 2632
469469
gated!(
470470
const_trait, Normal, template!(Word), WarnFollowing, const_trait_impl,
471-
"`const` is a temporary placeholder for marking a trait that is suitable for `const` \
471+
"`const_trait` is a temporary placeholder for marking a trait that is suitable for `const` \
472472
`impls` and all default bodies as `const`, which may be removed or renamed in the \
473473
future."
474474
),

Diff for: compiler/rustc_infer/src/traits/mod.rs

+8
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,14 @@ impl<'tcx> PredicateObligation<'tcx> {
6767
recursion_depth: self.recursion_depth,
6868
})
6969
}
70+
71+
pub fn without_const(mut self, tcx: TyCtxt<'tcx>) -> PredicateObligation<'tcx> {
72+
self.param_env = self.param_env.without_const();
73+
if let ty::PredicateKind::Trait(trait_pred) = self.predicate.kind().skip_binder() && trait_pred.is_const_if_const() {
74+
self.predicate = tcx.mk_predicate(self.predicate.kind().map_bound(|_| ty::PredicateKind::Trait(trait_pred.without_const())));
75+
}
76+
self
77+
}
7078
}
7179

7280
impl<'tcx> TraitObligation<'tcx> {

Diff for: compiler/rustc_middle/src/ty/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -861,6 +861,11 @@ impl<'tcx> TraitPredicate<'tcx> {
861861
(BoundConstness::ConstIfConst, hir::Constness::NotConst) => false,
862862
}
863863
}
864+
865+
pub fn without_const(mut self) -> Self {
866+
self.constness = BoundConstness::NotConst;
867+
self
868+
}
864869
}
865870

866871
impl<'tcx> PolyTraitPredicate<'tcx> {

Diff for: compiler/rustc_passes/src/check_const.rs

+22
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,28 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
192192
}
193193

194194
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
195+
let tcx = self.tcx;
196+
if let hir::ItemKind::Impl(hir::Impl {
197+
constness: hir::Constness::Const,
198+
of_trait: Some(trait_ref),
199+
..
200+
}) = item.kind
201+
{
202+
let def_id = trait_ref.trait_def_id().unwrap();
203+
let source_map = tcx.sess.source_map();
204+
if !tcx.has_attr(def_id, sym::const_trait) {
205+
tcx.sess
206+
.struct_span_err(
207+
source_map.guess_head_span(item.span),
208+
"const `impl`s must be for traits marked with `#[const_trait]`",
209+
)
210+
.span_note(
211+
source_map.guess_head_span(tcx.def_span(def_id)),
212+
"this trait must be annotated with `#[const_trait]`",
213+
)
214+
.emit();
215+
}
216+
}
195217
intravisit::walk_item(self, item);
196218
}
197219

Diff for: compiler/rustc_trait_selection/src/traits/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ pub fn predicates_for_generics<'tcx>(
129129
move |(idx, (predicate, span))| Obligation {
130130
cause: cause(idx, span),
131131
recursion_depth: 0,
132-
param_env: param_env,
132+
param_env,
133133
predicate,
134134
},
135135
)

Diff for: compiler/rustc_trait_selection/src/traits/wf.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,8 @@ impl<'tcx> WfPredicates<'tcx> {
392392
// `i32: Clone`
393393
// `i32: Copy`
394394
// ]
395-
let obligations = self.nominal_obligations(data.item_def_id, data.substs);
395+
// Projection types do not require const predicates.
396+
let obligations = self.nominal_obligations_without_const(data.item_def_id, data.substs);
396397
self.out.extend(obligations);
397398

398399
let tcx = self.tcx();

Diff for: compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs

+30-3
Original file line numberDiff line numberDiff line change
@@ -1406,23 +1406,50 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14061406
})
14071407
}
14081408

1409-
#[instrument(level = "debug", skip(self, code, span, def_id, substs))]
1409+
#[instrument(level = "debug", skip(self, code, span, substs))]
14101410
fn add_required_obligations_with_code(
14111411
&self,
14121412
span: Span,
14131413
def_id: DefId,
14141414
substs: SubstsRef<'tcx>,
14151415
code: impl Fn(usize, Span) -> ObligationCauseCode<'tcx>,
14161416
) {
1417+
let param_env = self.param_env;
1418+
1419+
let remap = match self.tcx.def_kind(def_id) {
1420+
// Associated consts have `Self: ~const Trait` bounds that should be satisfiable when
1421+
// `Self: Trait` is satisfied because it does not matter whether the impl is `const`.
1422+
// Therefore we have to remap the param env here to be non-const.
1423+
hir::def::DefKind::AssocConst => true,
1424+
hir::def::DefKind::AssocFn
1425+
if self.tcx.def_kind(self.tcx.parent(def_id)) == hir::def::DefKind::Trait =>
1426+
{
1427+
// N.B.: All callsites to this function involve checking a path expression.
1428+
//
1429+
// When instantiating a trait method as a function item, it does not actually matter whether
1430+
// the trait is `const` or not, or whether `where T: ~const Tr` needs to be satisfied as
1431+
// `const`. If we were to introduce instantiating trait methods as `const fn`s, we would
1432+
// check that after this, either via a bound `where F: ~const FnOnce` or when coercing to a
1433+
// `const fn` pointer.
1434+
//
1435+
// FIXME(fee1-dead) FIXME(const_trait_impl): update this doc when trait methods can satisfy
1436+
// `~const FnOnce` or can be coerced to `const fn` pointer.
1437+
true
1438+
}
1439+
_ => false,
1440+
};
14171441
let (bounds, _) = self.instantiate_bounds(span, def_id, &substs);
14181442

1419-
for obligation in traits::predicates_for_generics(
1443+
for mut obligation in traits::predicates_for_generics(
14201444
|idx, predicate_span| {
14211445
traits::ObligationCause::new(span, self.body_id, code(idx, predicate_span))
14221446
},
1423-
self.param_env,
1447+
param_env,
14241448
bounds,
14251449
) {
1450+
if remap {
1451+
obligation = obligation.without_const(self.tcx);
1452+
}
14261453
self.register_predicate(obligation);
14271454
}
14281455
}

Diff for: compiler/rustc_typeck/src/check/mod.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ fn typeck_with_fallback<'tcx>(
366366

367367
let typeck_results = Inherited::build(tcx, def_id).enter(|inh| {
368368
let param_env = tcx.param_env(def_id);
369-
let fcx = if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
369+
let mut fcx = if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
370370
let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() {
371371
let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
372372
<dyn AstConv<'_>>::ty_of_fn(&fcx, id, header.unsafety, header.abi, decl, None, None)
@@ -459,7 +459,11 @@ fn typeck_with_fallback<'tcx>(
459459

460460
// Closure and generator analysis may run after fallback
461461
// because they don't constrain other type variables.
462+
// Closure analysis only runs on closures. Therefore they only need to fulfill non-const predicates (as of now)
463+
let prev_constness = fcx.param_env.constness();
464+
fcx.param_env = fcx.param_env.without_const();
462465
fcx.closure_analyze(body);
466+
fcx.param_env = fcx.param_env.with_constness(prev_constness);
463467
assert!(fcx.deferred_call_resolutions.borrow().is_empty());
464468
// Before the generator analysis, temporary scopes shall be marked to provide more
465469
// precise information on types to be captured.

Diff for: library/alloc/src/boxed.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -2037,8 +2037,7 @@ impl<T: ?Sized, A: Allocator> AsMut<T> for Box<T, A> {
20372037
* could have a method to project a Pin<T> from it.
20382038
*/
20392039
#[stable(feature = "pin", since = "1.33.0")]
2040-
#[rustc_const_unstable(feature = "const_box", issue = "92521")]
2041-
impl<T: ?Sized, A: Allocator> const Unpin for Box<T, A> where A: 'static {}
2040+
impl<T: ?Sized, A: Allocator> Unpin for Box<T, A> where A: 'static {}
20422041

20432042
#[unstable(feature = "generator_trait", issue = "43122")]
20442043
impl<G: ?Sized + Generator<R> + Unpin, R, A: Allocator> Generator<R> for Box<G, A>

Diff for: library/core/src/alloc/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ impl fmt::Display for AllocError {
107107
///
108108
/// [*currently allocated*]: #currently-allocated-memory
109109
#[unstable(feature = "allocator_api", issue = "32838")]
110+
#[const_trait]
110111
pub unsafe trait Allocator {
111112
/// Attempts to allocate a block of memory.
112113
///

Diff for: library/core/src/borrow.rs

+2
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@
154154
/// [`String`]: ../../std/string/struct.String.html
155155
#[stable(feature = "rust1", since = "1.0.0")]
156156
#[rustc_diagnostic_item = "Borrow"]
157+
#[const_trait]
157158
pub trait Borrow<Borrowed: ?Sized> {
158159
/// Immutably borrows from an owned value.
159160
///
@@ -184,6 +185,7 @@ pub trait Borrow<Borrowed: ?Sized> {
184185
/// an underlying type by providing a mutable reference. See [`Borrow<T>`]
185186
/// for more information on borrowing as another type.
186187
#[stable(feature = "rust1", since = "1.0.0")]
188+
#[const_trait]
187189
pub trait BorrowMut<Borrowed: ?Sized>: Borrow<Borrowed> {
188190
/// Mutably borrows from an owned value.
189191
///

Diff for: library/core/src/cmp.rs

+8-28
Original file line numberDiff line numberDiff line change
@@ -204,20 +204,10 @@ use self::Ordering::*;
204204
#[stable(feature = "rust1", since = "1.0.0")]
205205
#[doc(alias = "==")]
206206
#[doc(alias = "!=")]
207-
#[cfg_attr(
208-
bootstrap,
209-
rustc_on_unimplemented(
210-
message = "can't compare `{Self}` with `{Rhs}`",
211-
label = "no implementation for `{Self} == {Rhs}`"
212-
)
213-
)]
214-
#[cfg_attr(
215-
not(bootstrap),
216-
rustc_on_unimplemented(
217-
message = "can't compare `{Self}` with `{Rhs}`",
218-
label = "no implementation for `{Self} == {Rhs}`",
219-
append_const_msg,
220-
)
207+
#[rustc_on_unimplemented(
208+
message = "can't compare `{Self}` with `{Rhs}`",
209+
label = "no implementation for `{Self} == {Rhs}`",
210+
append_const_msg
221211
)]
222212
#[const_trait]
223213
#[rustc_diagnostic_item = "PartialEq"]
@@ -1076,20 +1066,10 @@ impl const PartialOrd for Ordering {
10761066
#[doc(alias = "<")]
10771067
#[doc(alias = "<=")]
10781068
#[doc(alias = ">=")]
1079-
#[cfg_attr(
1080-
bootstrap,
1081-
rustc_on_unimplemented(
1082-
message = "can't compare `{Self}` with `{Rhs}`",
1083-
label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`",
1084-
)
1085-
)]
1086-
#[cfg_attr(
1087-
not(bootstrap),
1088-
rustc_on_unimplemented(
1089-
message = "can't compare `{Self}` with `{Rhs}`",
1090-
label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`",
1091-
append_const_msg,
1092-
)
1069+
#[rustc_on_unimplemented(
1070+
message = "can't compare `{Self}` with `{Rhs}`",
1071+
label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`",
1072+
append_const_msg
10931073
)]
10941074
#[const_trait]
10951075
#[rustc_diagnostic_item = "PartialOrd"]

Diff for: library/core/src/convert/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ pub const fn identity<T>(x: T) -> T {
155155
/// ```
156156
#[stable(feature = "rust1", since = "1.0.0")]
157157
#[cfg_attr(not(test), rustc_diagnostic_item = "AsRef")]
158+
#[const_trait]
158159
pub trait AsRef<T: ?Sized> {
159160
/// Converts this type into a shared reference of the (usually inferred) input type.
160161
#[stable(feature = "rust1", since = "1.0.0")]
@@ -197,6 +198,7 @@ pub trait AsRef<T: ?Sized> {
197198
/// [`Box<T>`]: ../../std/boxed/struct.Box.html
198199
#[stable(feature = "rust1", since = "1.0.0")]
199200
#[cfg_attr(not(test), rustc_diagnostic_item = "AsMut")]
201+
#[const_trait]
200202
pub trait AsMut<T: ?Sized> {
201203
/// Converts this type into a mutable reference of the (usually inferred) input type.
202204
#[stable(feature = "rust1", since = "1.0.0")]
@@ -273,6 +275,7 @@ pub trait AsMut<T: ?Sized> {
273275
/// [`Vec`]: ../../std/vec/struct.Vec.html
274276
#[rustc_diagnostic_item = "Into"]
275277
#[stable(feature = "rust1", since = "1.0.0")]
278+
#[const_trait]
276279
pub trait Into<T>: Sized {
277280
/// Converts this type into the (usually inferred) input type.
278281
#[must_use]
@@ -368,6 +371,7 @@ pub trait Into<T>: Sized {
368371
all(_Self = "&str", T = "std::string::String"),
369372
note = "to coerce a `{T}` into a `{Self}`, use `&*` as a prefix",
370373
))]
374+
#[const_trait]
371375
pub trait From<T>: Sized {
372376
/// Converts to this type from the input type.
373377
#[lang = "from"]
@@ -392,6 +396,7 @@ pub trait From<T>: Sized {
392396
/// [`Into`], see there for details.
393397
#[rustc_diagnostic_item = "TryInto"]
394398
#[stable(feature = "try_from", since = "1.34.0")]
399+
#[const_trait]
395400
pub trait TryInto<T>: Sized {
396401
/// The type returned in the event of a conversion error.
397402
#[stable(feature = "try_from", since = "1.34.0")]
@@ -468,6 +473,7 @@ pub trait TryInto<T>: Sized {
468473
/// [`try_from`]: TryFrom::try_from
469474
#[rustc_diagnostic_item = "TryFrom"]
470475
#[stable(feature = "try_from", since = "1.34.0")]
476+
#[const_trait]
471477
pub trait TryFrom<T>: Sized {
472478
/// The type returned in the event of a conversion error.
473479
#[stable(feature = "try_from", since = "1.34.0")]

Diff for: library/core/src/default.rs

+1
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@
9999
/// ```
100100
#[cfg_attr(not(test), rustc_diagnostic_item = "Default")]
101101
#[stable(feature = "rust1", since = "1.0.0")]
102+
#[cfg_attr(not(bootstrap), const_trait)]
102103
pub trait Default: Sized {
103104
/// Returns the "default value" for a type.
104105
///

Diff for: library/core/src/iter/traits/collect.rs

+1
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ pub trait FromIterator<A>: Sized {
228228
#[rustc_diagnostic_item = "IntoIterator"]
229229
#[rustc_skip_array_during_method_dispatch]
230230
#[stable(feature = "rust1", since = "1.0.0")]
231+
#[const_trait]
231232
pub trait IntoIterator {
232233
/// The type of the elements being iterated over.
233234
#[stable(feature = "rust1", since = "1.0.0")]

Diff for: library/core/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@
141141
#![feature(const_str_from_utf8_unchecked_mut)]
142142
#![feature(const_swap)]
143143
#![feature(const_trait_impl)]
144+
#![feature(const_try)]
144145
#![feature(const_type_id)]
145146
#![feature(const_type_name)]
146147
#![feature(const_default_impls)]

0 commit comments

Comments
 (0)