Skip to content

Commit 5560b8c

Browse files
committed
reserve impl<T> From<!> for T
this is necessary for never-type stabilization
1 parent d727071 commit 5560b8c

File tree

8 files changed

+91
-26
lines changed

8 files changed

+91
-26
lines changed

src/libcore/convert.rs

+6
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,12 @@ impl<T> From<T> for T {
551551
fn from(t: T) -> T { t }
552552
}
553553

554+
#[stable(feature = "convert_infallible", since = "1.34.0")]
555+
#[cfg(not(bootstrap))]
556+
#[rustc_reservation_impl]
557+
impl<T> From<!> for T {
558+
fn from(t: !) -> T { t }
559+
}
554560

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

src/librustc/traits/select.rs

+17-4
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

@@ -1325,8 +1327,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
13251327
(result, dep_node)
13261328
}
13271329

1328-
// Treat negative impls as unimplemented
1329-
fn filter_negative_impls(
1330+
// Treat negative impls as unimplemented, and reservation impls as Ok(None)
1331+
fn filter_negative_and_reservation_impls(
13301332
&self,
13311333
candidate: SelectionCandidate<'tcx>,
13321334
) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
@@ -1336,6 +1338,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
13361338
{
13371339
return Err(Unimplemented);
13381340
}
1341+
1342+
if self.tcx().has_attr(def_id, sym::rustc_reservation_impl) {
1343+
return Ok(None);
1344+
}
13391345
}
13401346
Ok(Some(candidate))
13411347
}
@@ -1452,7 +1458,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
14521458
// Instead, we select the right impl now but report `Bar does
14531459
// not implement Clone`.
14541460
if candidates.len() == 1 {
1455-
return self.filter_negative_impls(candidates.pop().unwrap());
1461+
return self.filter_negative_and_reservation_impls(candidates.pop().unwrap());
14561462
}
14571463

14581464
// Winnow, but record the exact outcome of evaluation, which
@@ -1527,7 +1533,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
15271533
}
15281534

15291535
// Just one candidate left.
1530-
self.filter_negative_impls(candidates.pop().unwrap().candidate)
1536+
self.filter_negative_and_reservation_impls(candidates.pop().unwrap().candidate)
15311537
}
15321538

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

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

src/librustc/ty/mod.rs

+18-10
Original file line numberDiff line numberDiff line change
@@ -2892,7 +2892,13 @@ impl<'tcx> TyCtxt<'tcx> {
28922892
pub fn impls_are_allowed_to_overlap(self, def_id1: DefId, def_id2: DefId)
28932893
-> Option<ImplOverlapKind>
28942894
{
2895-
let is_legit = if self.features().overlapping_marker_traits {
2895+
if self.impl_polarity(def_id1) != self.impl_polarity(def_id2) {
2896+
debug!("impls_are_allowed_to_overlap({:?}, {:?}) - different polarities, None",
2897+
def_id1, def_id2);
2898+
return None;
2899+
}
2900+
2901+
let is_marker_overlap = if self.features().overlapping_marker_traits {
28962902
let trait1_is_empty = self.impl_trait_ref(def_id1)
28972903
.map_or(false, |trait_ref| {
28982904
self.associated_item_def_ids(trait_ref.def_id).is_empty()
@@ -2901,22 +2907,24 @@ impl<'tcx> TyCtxt<'tcx> {
29012907
.map_or(false, |trait_ref| {
29022908
self.associated_item_def_ids(trait_ref.def_id).is_empty()
29032909
});
2904-
self.impl_polarity(def_id1) == self.impl_polarity(def_id2)
2905-
&& trait1_is_empty
2906-
&& trait2_is_empty
2910+
trait1_is_empty && trait2_is_empty
29072911
} else {
29082912
let is_marker_impl = |def_id: DefId| -> bool {
29092913
let trait_ref = self.impl_trait_ref(def_id);
29102914
trait_ref.map_or(false, |tr| self.trait_def(tr.def_id).is_marker)
29112915
};
2912-
self.impl_polarity(def_id1) == self.impl_polarity(def_id2)
2913-
&& is_marker_impl(def_id1)
2914-
&& is_marker_impl(def_id2)
2916+
is_marker_impl(def_id1) && is_marker_impl(def_id2)
29152917
};
29162918

2917-
if is_legit {
2918-
debug!("impls_are_allowed_to_overlap({:?}, {:?}) = Some(Permitted)",
2919-
def_id1, def_id2);
2919+
// `#[rustc_reservation_impl]` impls don't overlap with anything
2920+
let is_reserve_overlap = {
2921+
self.has_attr(def_id1, sym::rustc_reservation_impl) ||
2922+
self.has_attr(def_id2, sym::rustc_reservation_impl)
2923+
};
2924+
2925+
if is_marker_overlap || is_reserve_overlap {
2926+
debug!("impls_are_allowed_to_overlap({:?}, {:?}) = Some(Permitted) ({:?}/{:?})",
2927+
def_id1, def_id2, is_marker_overlap, is_reserve_overlap);
29202928
Some(ImplOverlapKind::Permitted)
29212929
} else {
29222930
if let Some(self_ty1) = self.issue33140_self_ty(def_id1) {

src/librustc_typeck/check/wfcheck.rs

+17-12
Original file line numberDiff line numberDiff line change
@@ -399,18 +399,23 @@ fn check_impl<'tcx>(
399399

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

src/libsyntax/feature_gate.rs

+5
Original file line numberDiff line numberDiff line change
@@ -1276,6 +1276,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
12761276
attribute is just used for rustc unit \
12771277
tests and will never be stable",
12781278
cfg_fn!(rustc_attrs))),
1279+
(sym::rustc_reservation_impl, Normal, template!(Word), Gated(Stability::Unstable,
1280+
sym::rustc_attrs,
1281+
"internal rustc attributes \
1282+
will never be stable",
1283+
cfg_fn!(rustc_attrs))),
12791284
(sym::rustc_test_marker, Normal, template!(Word), Gated(Stability::Unstable,
12801285
sym::rustc_attrs,
12811286
"the `#[rustc_test_marker]` attribute \

src/libsyntax_pos/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,7 @@ symbols! {
602602
rustc_std_internal_symbol,
603603
rustc_symbol_name,
604604
rustc_synthetic,
605+
rustc_reservation_impl,
605606
rustc_test_marker,
606607
rustc_then_this_would_need,
607608
rustc_variance,

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

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
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
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error[E0601]: `main` function not found in crate `never_impl_is_reserved`
2+
|
3+
= note: consider adding a `main` function to `$DIR/never-impl-is-reserved.rs`
4+
5+
error[E0119]: conflicting implementations of trait `MyTrait` for type `MyFoo`:
6+
--> $DIR/never-impl-is-reserved.rs:10:1
7+
|
8+
LL | impl MyTrait for MyFoo {}
9+
| ---------------------- first implementation here
10+
LL | // This will conflict with the first impl if we impl `for<T> T: From<!>`.
11+
LL | impl<T> MyTrait for T where T: From<!> {}
12+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `MyFoo`
13+
14+
error: aborting due to 2 previous errors
15+
16+
Some errors have detailed explanations: E0119, E0601.
17+
For more information about an error, try `rustc --explain E0119`.

0 commit comments

Comments
 (0)