Skip to content

Commit

Permalink
Auto merge of rust-lang#80417 - Mark-Simulacrum:beta-next, r=Mark-Sim…
Browse files Browse the repository at this point in the history
…ulacrum

[beta] backports

This backports the following to 1.49:

*  Revert change to trait evaluation order rust-lang#80132
*  Don't allow `const` to begin a nonterminal rust-lang#80135
*  Prevent caching normalization results with a cycle rust-lang#80246

r? `@Mark-Simulacrum`
  • Loading branch information
bors committed Dec 28, 2020
2 parents b0dc3c6 + 2f925da commit 136dfc1
Show file tree
Hide file tree
Showing 16 changed files with 220 additions and 27 deletions.
16 changes: 15 additions & 1 deletion compiler/rustc_infer/src/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ impl ProjectionCacheKey<'tcx> {
pub enum ProjectionCacheEntry<'tcx> {
InProgress,
Ambiguous,
Recur,
Error,
NormalizedTy(NormalizedTy<'tcx>),
}
Expand Down Expand Up @@ -143,7 +144,12 @@ impl<'tcx> ProjectionCache<'_, 'tcx> {
"ProjectionCacheEntry::insert_ty: adding cache entry: key={:?}, value={:?}",
key, value
);
let fresh_key = self.map().insert(key, ProjectionCacheEntry::NormalizedTy(value));
let mut map = self.map();
if let Some(ProjectionCacheEntry::Recur) = map.get(&key) {
debug!("Not overwriting Recur");
return;
}
let fresh_key = map.insert(key, ProjectionCacheEntry::NormalizedTy(value));
assert!(!fresh_key, "never started projecting `{:?}`", key);
}

Expand Down Expand Up @@ -197,6 +203,14 @@ impl<'tcx> ProjectionCache<'_, 'tcx> {
assert!(!fresh, "never started projecting `{:?}`", key);
}

/// Indicates that while trying to normalize `key`, `key` was required to
/// be normalized again. Selection or evaluation should eventually report
/// an error here.
pub fn recur(&mut self, key: ProjectionCacheKey<'tcx>) {
let fresh = self.map().insert(key, ProjectionCacheEntry::Recur);
assert!(!fresh, "never started projecting `{:?}`", key);
}

/// Indicates that trying to normalize `key` resulted in
/// error.
pub fn error(&mut self, key: ProjectionCacheKey<'tcx>) {
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_parse/src/parser/nonterminal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ impl<'a> Parser<'a> {
token.can_begin_expr()
// This exception is here for backwards compatibility.
&& !token.is_keyword(kw::Let)
// This exception is here for backwards compatibility.
&& !token.is_keyword(kw::Const)
}
NonterminalKind::Ty => token.can_begin_type(),
NonterminalKind::Ident => get_macro_ident(token).is_some(),
Expand Down
23 changes: 16 additions & 7 deletions compiler/rustc_trait_selection/src/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -496,12 +496,6 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
return Ok(None);
}
Err(ProjectionCacheEntry::InProgress) => {
// If while normalized A::B, we are asked to normalize
// A::B, just return A::B itself. This is a conservative
// answer, in the sense that A::B *is* clearly equivalent
// to A::B, though there may be a better value we can
// find.

// Under lazy normalization, this can arise when
// bootstrapping. That is, imagine an environment with a
// where-clause like `A::B == u32`. Now, if we are asked
Expand All @@ -512,6 +506,14 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(

debug!("found cache entry: in-progress");

// Cache that normalizing this projection resulted in a cycle. This
// should ensure that, unless this happens within a snapshot that's
// rolled back, fulfillment or evaluation will notice the cycle.

infcx.inner.borrow_mut().projection_cache().recur(cache_key);
return Err(InProgress);
}
Err(ProjectionCacheEntry::Recur) => {
return Err(InProgress);
}
Err(ProjectionCacheEntry::NormalizedTy(ty)) => {
Expand Down Expand Up @@ -734,7 +736,14 @@ fn project_type<'cx, 'tcx>(

if !selcx.tcx().sess.recursion_limit().value_within_limit(obligation.recursion_depth) {
debug!("project: overflow!");
return Err(ProjectionTyError::TraitSelectionError(SelectionError::Overflow));
match selcx.query_mode() {
super::TraitQueryMode::Standard => {
selcx.infcx().report_overflow_error(&obligation, true);
}
super::TraitQueryMode::Canonical => {
return Err(ProjectionTyError::TraitSelectionError(SelectionError::Overflow));
}
}
}

let obligation_trait_ref = &obligation.predicate.trait_ref(selcx.tcx());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn vtable_impl(
&mut self,
impl_def_id: DefId,
mut substs: Normalized<'tcx, SubstsRef<'tcx>>,
substs: Normalized<'tcx, SubstsRef<'tcx>>,
cause: ObligationCause<'tcx>,
recursion_depth: usize,
param_env: ty::ParamEnv<'tcx>,
Expand All @@ -357,9 +357,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// relying on projections in the impl-trait-ref.
//
// e.g., `impl<U: Tr, V: Iterator<Item=U>> Foo<<U as Tr>::T> for V`
substs.obligations.append(&mut impl_obligations);
impl_obligations.extend(substs.obligations);

ImplSourceUserDefinedData { impl_def_id, substs: substs.value, nested: substs.obligations }
ImplSourceUserDefinedData { impl_def_id, substs: substs.value, nested: impl_obligations }
}

fn confirm_object_candidate(
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self.infcx.tcx
}

pub(super) fn query_mode(&self) -> TraitQueryMode {
self.query_mode
}

///////////////////////////////////////////////////////////////////////////
// Selection
//
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/associated-types/defaults-cyclic-fail-1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ impl Tr for u32 {
// ...but not in an impl that redefines one of the types.
impl Tr for bool {
type A = Box<Self::B>;
//~^ ERROR type mismatch resolving `<bool as Tr>::B == _`
//~^ ERROR overflow evaluating the requirement `<bool as Tr>::B == _`
}
// (the error is shown twice for some reason)

impl Tr for usize {
type B = &'static Self::A;
//~^ ERROR type mismatch resolving `<usize as Tr>::A == _`
//~^ ERROR overflow evaluating the requirement `<usize as Tr>::A == _`
}

fn main() {
Expand Down
10 changes: 5 additions & 5 deletions src/test/ui/associated-types/defaults-cyclic-fail-1.stderr
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
error[E0271]: type mismatch resolving `<bool as Tr>::B == _`
error[E0275]: overflow evaluating the requirement `<bool as Tr>::B == _`
--> $DIR/defaults-cyclic-fail-1.rs:26:5
|
LL | type A = Box<Self::B>;
| ^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size
| ^^^^^^^^^^^^^^^^^^^^^^

error[E0271]: type mismatch resolving `<usize as Tr>::A == _`
error[E0275]: overflow evaluating the requirement `<usize as Tr>::A == _`
--> $DIR/defaults-cyclic-fail-1.rs:32:5
|
LL | type B = &'static Self::A;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size
| ^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0271`.
For more information about this error, try `rustc --explain E0275`.
4 changes: 2 additions & 2 deletions src/test/ui/associated-types/defaults-cyclic-fail-2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ impl Tr for u32 {

impl Tr for bool {
type A = Box<Self::B>;
//~^ ERROR type mismatch resolving `<bool as Tr>::B == _`
//~^ ERROR overflow evaluating the requirement `<bool as Tr>::B == _`
}
// (the error is shown twice for some reason)

impl Tr for usize {
type B = &'static Self::A;
//~^ ERROR type mismatch resolving `<usize as Tr>::A == _`
//~^ ERROR overflow evaluating the requirement `<usize as Tr>::A == _`
}

fn main() {
Expand Down
10 changes: 5 additions & 5 deletions src/test/ui/associated-types/defaults-cyclic-fail-2.stderr
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
error[E0271]: type mismatch resolving `<bool as Tr>::B == _`
error[E0275]: overflow evaluating the requirement `<bool as Tr>::B == _`
--> $DIR/defaults-cyclic-fail-2.rs:27:5
|
LL | type A = Box<Self::B>;
| ^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size
| ^^^^^^^^^^^^^^^^^^^^^^

error[E0271]: type mismatch resolving `<usize as Tr>::A == _`
error[E0275]: overflow evaluating the requirement `<usize as Tr>::A == _`
--> $DIR/defaults-cyclic-fail-2.rs:33:5
|
LL | type B = &'static Self::A;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size
| ^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0271`.
For more information about this error, try `rustc --explain E0275`.
29 changes: 29 additions & 0 deletions src/test/ui/associated-types/impl-wf-cycle-1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Regression test for #79714

trait Baz {}
impl Baz for () {}
impl<T> Baz for (T,) {}

trait Fiz {}
impl Fiz for bool {}

trait Grault {
type A;
type B;
}

impl<T: Grault> Grault for (T,)
where
Self::A: Baz,
Self::B: Fiz,
{
type A = ();
//~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`
type B = bool;
//~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`
}
//~^^^^^^^^^^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`

fn main() {
let x: <(_,) as Grault>::A = ();
}
36 changes: 36 additions & 0 deletions src/test/ui/associated-types/impl-wf-cycle-1.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
--> $DIR/impl-wf-cycle-1.rs:15:1
|
LL | / impl<T: Grault> Grault for (T,)
LL | | where
LL | | Self::A: Baz,
LL | | Self::B: Fiz,
... |
LL | |
LL | | }
| |_^
|
= note: required because of the requirements on the impl of `Grault` for `(T,)`
= note: required because of the requirements on the impl of `Grault` for `(T,)`

error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
--> $DIR/impl-wf-cycle-1.rs:20:5
|
LL | type A = ();
| ^^^^^^^^^^^^
|
= note: required because of the requirements on the impl of `Grault` for `(T,)`
= note: required because of the requirements on the impl of `Grault` for `(T,)`

error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
--> $DIR/impl-wf-cycle-1.rs:22:5
|
LL | type B = bool;
| ^^^^^^^^^^^^^^
|
= note: required because of the requirements on the impl of `Grault` for `(T,)`
= note: required because of the requirements on the impl of `Grault` for `(T,)`

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0275`.
16 changes: 16 additions & 0 deletions src/test/ui/associated-types/impl-wf-cycle-2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Regression test for #79714

trait Grault {
type A;
}

impl<T: Grault> Grault for (T,)
where
Self::A: Copy,
{
type A = ();
//~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`
}
//~^^^^^^^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`

fn main() {}
25 changes: 25 additions & 0 deletions src/test/ui/associated-types/impl-wf-cycle-2.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
--> $DIR/impl-wf-cycle-2.rs:7:1
|
LL | / impl<T: Grault> Grault for (T,)
LL | | where
LL | | Self::A: Copy,
LL | | {
LL | | type A = ();
LL | |
LL | | }
| |_^
|
= note: required because of the requirements on the impl of `Grault` for `(T,)`

error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
--> $DIR/impl-wf-cycle-2.rs:11:5
|
LL | type A = ();
| ^^^^^^^^^^^^
|
= note: required because of the requirements on the impl of `Grault` for `(T,)`

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0275`.
20 changes: 20 additions & 0 deletions src/test/ui/inline-const/macro-with-const.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// check-pass

macro_rules! exp {
(const $n:expr) => {
$n
};
}

macro_rules! stmt {
(exp $e:expr) => {
$e
};
(exp $($t:tt)+) => {
exp!($($t)+)
};
}

fn main() {
stmt!(exp const 1);
}
3 changes: 1 addition & 2 deletions src/test/ui/issues/issue-23122-2.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<T as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: Sized`
error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<T as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next`
--> $DIR/issue-23122-2.rs:9:5
|
LL | type Next = <GetNext<T::Next> as Next>::Next;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_23122_2`)
= note: required because of the requirements on the impl of `Next` for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<T as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>`

error: aborting due to previous error

Expand Down
39 changes: 39 additions & 0 deletions src/test/ui/traits/impl-evaluation-order.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Regression test for #79902

// Check that evaluation (which is used to determine whether to copy a type in
// MIR building) evaluates bounds from normalizing an impl after evaluating
// any bounds on the impl.

// check-pass

trait A {
type B;
}
trait M {}

struct G<T, U>(*const T, *const U);

impl<T, U> Clone for G<T, U> {
fn clone(&self) -> Self {
G { ..*self }
}
}

impl<T, U> Copy for G<T, U::B>
where
T: A<B = U>,
U: A,
{
}

impl A for () {
type B = ();
}

fn is_m<T: M>(_: T) {}

fn main() {
let x = G(&(), &());
drop(x);
drop(x);
}

0 comments on commit 136dfc1

Please sign in to comment.