Skip to content

Commit 5d79e8c

Browse files
committed
reserve impl<T> From<!> for T
this is necessary for never-type stabilization
1 parent 6ef275e commit 5d79e8c

File tree

8 files changed

+87
-26
lines changed

8 files changed

+87
-26
lines changed

src/libcore/convert.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,12 @@ impl<T> From<T> for T {
554554
fn from(t: T) -> T { t }
555555
}
556556

557+
#[stable(feature = "convert_infallible", since = "1.34.0")]
558+
#[cfg(not(boostrap_stdarch_ignore_this))]
559+
#[rustc_reservation_impl]
560+
impl<T> From<!> for T {
561+
fn from(t: !) -> T { t }
562+
}
557563

558564
// TryFrom implies TryInto
559565
#[stable(feature = "try_from", since = "1.34.0")]

src/librustc/traits/select.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ use std::iter;
5050
use std::rc::Rc;
5151
use crate::util::nodemap::{FxHashMap, FxHashSet};
5252

53+
use syntax::symbol::sym;
54+
5355
pub struct SelectionContext<'cx, 'tcx> {
5456
infcx: &'cx InferCtxt<'cx, 'tcx>,
5557

@@ -1326,8 +1328,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
13261328
(result, dep_node)
13271329
}
13281330

1329-
// Treat negative impls as unimplemented
1330-
fn filter_negative_impls(
1331+
// Treat negative impls as unimplemented, and reservation impls as Ok(None)
1332+
fn filter_negative_and_reservation_impls(
13311333
&self,
13321334
candidate: SelectionCandidate<'tcx>,
13331335
) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
@@ -1337,6 +1339,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
13371339
{
13381340
return Err(Unimplemented);
13391341
}
1342+
1343+
if self.tcx().has_attr(def_id, sym::rustc_reservation_impl) {
1344+
return Ok(None);
1345+
}
13401346
}
13411347
Ok(Some(candidate))
13421348
}
@@ -1453,7 +1459,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
14531459
// Instead, we select the right impl now but report `Bar does
14541460
// not implement Clone`.
14551461
if candidates.len() == 1 {
1456-
return self.filter_negative_impls(candidates.pop().unwrap());
1462+
return self.filter_negative_and_reservation_impls(candidates.pop().unwrap());
14571463
}
14581464

14591465
// Winnow, but record the exact outcome of evaluation, which
@@ -1528,7 +1534,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
15281534
}
15291535

15301536
// Just one candidate left.
1531-
self.filter_negative_impls(candidates.pop().unwrap().candidate)
1537+
self.filter_negative_and_reservation_impls(candidates.pop().unwrap().candidate)
15321538
}
15331539

15341540
fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Option<Conflict> {
@@ -3728,6 +3734,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
37283734
return Err(());
37293735
}
37303736

3737+
if self.intercrate.is_none() &&
3738+
self.tcx().has_attr(impl_def_id, sym::rustc_reservation_impl)
3739+
{
3740+
debug!("match_impl: reservation impls only apply in intercrate mode");
3741+
return Err(());
3742+
}
3743+
37313744
debug!("match_impl: success impl_substs={:?}", impl_substs);
37323745
Ok(Normalized {
37333746
value: impl_substs,

src/librustc/ty/mod.rs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2911,7 +2911,13 @@ impl<'tcx> TyCtxt<'tcx> {
29112911
return Some(ImplOverlapKind::Permitted);
29122912
}
29132913

2914-
let is_legit = if self.features().overlapping_marker_traits {
2914+
if self.impl_polarity(def_id1) != self.impl_polarity(def_id2) {
2915+
debug!("impls_are_allowed_to_overlap({:?}, {:?}) - different polarities, None",
2916+
def_id1, def_id2);
2917+
return None;
2918+
}
2919+
2920+
let is_marker_overlap = if self.features().overlapping_marker_traits {
29152921
let trait1_is_empty = self.impl_trait_ref(def_id1)
29162922
.map_or(false, |trait_ref| {
29172923
self.associated_item_def_ids(trait_ref.def_id).is_empty()
@@ -2920,22 +2926,24 @@ impl<'tcx> TyCtxt<'tcx> {
29202926
.map_or(false, |trait_ref| {
29212927
self.associated_item_def_ids(trait_ref.def_id).is_empty()
29222928
});
2923-
self.impl_polarity(def_id1) == self.impl_polarity(def_id2)
2924-
&& trait1_is_empty
2925-
&& trait2_is_empty
2929+
trait1_is_empty && trait2_is_empty
29262930
} else {
29272931
let is_marker_impl = |def_id: DefId| -> bool {
29282932
let trait_ref = self.impl_trait_ref(def_id);
29292933
trait_ref.map_or(false, |tr| self.trait_def(tr.def_id).is_marker)
29302934
};
2931-
self.impl_polarity(def_id1) == self.impl_polarity(def_id2)
2932-
&& is_marker_impl(def_id1)
2933-
&& is_marker_impl(def_id2)
2935+
is_marker_impl(def_id1) && is_marker_impl(def_id2)
29342936
};
29352937

2936-
if is_legit {
2937-
debug!("impls_are_allowed_to_overlap({:?}, {:?}) = Some(Permitted)",
2938-
def_id1, def_id2);
2938+
// `#[rustc_reservation_impl]` impls don't overlap with anything
2939+
let is_reserve_overlap = {
2940+
self.has_attr(def_id1, sym::rustc_reservation_impl) ||
2941+
self.has_attr(def_id2, sym::rustc_reservation_impl)
2942+
};
2943+
2944+
if is_marker_overlap || is_reserve_overlap {
2945+
debug!("impls_are_allowed_to_overlap({:?}, {:?}) = Some(Permitted) ({:?}/{:?})",
2946+
def_id1, def_id2, is_marker_overlap, is_reserve_overlap);
29392947
Some(ImplOverlapKind::Permitted)
29402948
} else {
29412949
if let Some(self_ty1) = self.issue33140_self_ty(def_id1) {

src/librustc_typeck/check/wfcheck.rs

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -398,18 +398,23 @@ fn check_impl<'tcx>(
398398

399399
match *ast_trait_ref {
400400
Some(ref ast_trait_ref) => {
401-
let trait_ref = fcx.tcx.impl_trait_ref(item_def_id).unwrap();
402-
let trait_ref =
403-
fcx.normalize_associated_types_in(
404-
ast_trait_ref.path.span, &trait_ref);
405-
let obligations =
406-
ty::wf::trait_obligations(fcx,
407-
fcx.param_env,
408-
fcx.body_id,
409-
&trait_ref,
410-
ast_trait_ref.path.span);
411-
for obligation in obligations {
412-
fcx.register_predicate(obligation);
401+
// `#[rustc_reservation_impl]` impls are not real impls and
402+
// therefore don't need to be WF (the trait's `Self: Trait` predicate
403+
// won't hold).
404+
if !fcx.tcx.has_attr(item_def_id, sym::rustc_reservation_impl) {
405+
let trait_ref = fcx.tcx.impl_trait_ref(item_def_id).unwrap();
406+
let trait_ref =
407+
fcx.normalize_associated_types_in(
408+
ast_trait_ref.path.span, &trait_ref);
409+
let obligations =
410+
ty::wf::trait_obligations(fcx,
411+
fcx.param_env,
412+
fcx.body_id,
413+
&trait_ref,
414+
ast_trait_ref.path.span);
415+
for obligation in obligations {
416+
fcx.register_predicate(obligation);
417+
}
413418
}
414419
}
415420
None => {

src/libsyntax/feature_gate/builtin_attrs.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
498498
overflow checking behavior of several libcore functions that are inlined \
499499
across crates and will never be stable",
500500
),
501+
rustc_attr!(rustc_reservation_impl, Normal, template!(Word),
502+
"the `#[rustc_reservation_impl]` attribute is internally used \
503+
for reserving for `for<T> From<!> for T` impl"
504+
),
501505
rustc_attr!(
502506
rustc_test_marker, Normal, template!(Word),
503507
"the `#[rustc_test_marker]` attribute is used internally to track tests",

src/libsyntax_pos/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,7 @@ symbols! {
606606
rustc_std_internal_symbol,
607607
rustc_symbol_name,
608608
rustc_synthetic,
609+
rustc_reservation_impl,
609610
rustc_test_marker,
610611
rustc_then_this_would_need,
611612
rustc_variance,

src/test/ui/never-impl-is-reserved.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// check that the `for<T> T: From<!>` impl is reserved
2+
3+
#![feature(never_type)]
4+
5+
pub struct MyFoo;
6+
pub trait MyTrait {}
7+
8+
impl MyTrait for MyFoo {}
9+
// This will conflict with the first impl if we impl `for<T> T: From<!>`.
10+
impl<T> MyTrait for T where T: From<!> {} //~ ERROR conflicting implementation
11+
12+
fn main() {}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0119]: conflicting implementations of trait `MyTrait` for type `MyFoo`:
2+
--> $DIR/never-impl-is-reserved.rs:10:1
3+
|
4+
LL | impl MyTrait for MyFoo {}
5+
| ---------------------- first implementation here
6+
LL | // This will conflict with the first impl if we impl `for<T> T: From<!>`.
7+
LL | impl<T> MyTrait for T where T: From<!> {}
8+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `MyFoo`
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0119`.

0 commit comments

Comments
 (0)