Auto merge of #107642 - Dylan-DPC:rollup-edcqhm5, r=Dylan-DPC
Rollup of 6 pull requests Successful merges: - #107082 (Autotrait bounds on dyn-safe trait methods) - #107427 (Add candidates for DiscriminantKind builtin) - #107539 (Emit warnings on unused parens in index expressions) - #107544 (Improve `TokenCursor`.) - #107585 (Don't cause a cycle when formatting query description that references a FnDef) - #107633 (Fix suggestion for coercing Option<&String> to Option<&str>) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
658fad6c55
33 changed files with 686 additions and 204 deletions
|
@ -41,7 +41,8 @@ use std::{fmt, iter};
|
||||||
/// Nothing special happens to misnamed or misplaced `SubstNt`s.
|
/// Nothing special happens to misnamed or misplaced `SubstNt`s.
|
||||||
#[derive(Debug, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]
|
#[derive(Debug, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]
|
||||||
pub enum TokenTree {
|
pub enum TokenTree {
|
||||||
/// A single token.
|
/// A single token. Should never be `OpenDelim` or `CloseDelim`, because
|
||||||
|
/// delimiters are implicitly represented by `Delimited`.
|
||||||
Token(Token, Spacing),
|
Token(Token, Spacing),
|
||||||
/// A delimited sequence of token trees.
|
/// A delimited sequence of token trees.
|
||||||
Delimited(DelimSpan, Delimiter, TokenStream),
|
Delimited(DelimSpan, Delimiter, TokenStream),
|
||||||
|
@ -388,12 +389,12 @@ impl TokenStream {
|
||||||
self.0.len()
|
self.0.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trees(&self) -> CursorRef<'_> {
|
pub fn trees(&self) -> RefTokenTreeCursor<'_> {
|
||||||
CursorRef::new(self)
|
RefTokenTreeCursor::new(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_trees(self) -> Cursor {
|
pub fn into_trees(self) -> TokenTreeCursor {
|
||||||
Cursor::new(self)
|
TokenTreeCursor::new(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compares two `TokenStream`s, checking equality without regarding span information.
|
/// Compares two `TokenStream`s, checking equality without regarding span information.
|
||||||
|
@ -551,16 +552,17 @@ impl TokenStream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// By-reference iterator over a [`TokenStream`].
|
/// By-reference iterator over a [`TokenStream`], that produces `&TokenTree`
|
||||||
|
/// items.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct CursorRef<'t> {
|
pub struct RefTokenTreeCursor<'t> {
|
||||||
stream: &'t TokenStream,
|
stream: &'t TokenStream,
|
||||||
index: usize,
|
index: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'t> CursorRef<'t> {
|
impl<'t> RefTokenTreeCursor<'t> {
|
||||||
fn new(stream: &'t TokenStream) -> Self {
|
fn new(stream: &'t TokenStream) -> Self {
|
||||||
CursorRef { stream, index: 0 }
|
RefTokenTreeCursor { stream, index: 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn look_ahead(&self, n: usize) -> Option<&TokenTree> {
|
pub fn look_ahead(&self, n: usize) -> Option<&TokenTree> {
|
||||||
|
@ -568,7 +570,7 @@ impl<'t> CursorRef<'t> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'t> Iterator for CursorRef<'t> {
|
impl<'t> Iterator for RefTokenTreeCursor<'t> {
|
||||||
type Item = &'t TokenTree;
|
type Item = &'t TokenTree;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<&'t TokenTree> {
|
fn next(&mut self) -> Option<&'t TokenTree> {
|
||||||
|
@ -579,15 +581,16 @@ impl<'t> Iterator for CursorRef<'t> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Owning by-value iterator over a [`TokenStream`].
|
/// Owning by-value iterator over a [`TokenStream`], that produces `TokenTree`
|
||||||
|
/// items.
|
||||||
// FIXME: Many uses of this can be replaced with by-reference iterator to avoid clones.
|
// FIXME: Many uses of this can be replaced with by-reference iterator to avoid clones.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Cursor {
|
pub struct TokenTreeCursor {
|
||||||
pub stream: TokenStream,
|
pub stream: TokenStream,
|
||||||
index: usize,
|
index: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Iterator for Cursor {
|
impl Iterator for TokenTreeCursor {
|
||||||
type Item = TokenTree;
|
type Item = TokenTree;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<TokenTree> {
|
fn next(&mut self) -> Option<TokenTree> {
|
||||||
|
@ -598,9 +601,9 @@ impl Iterator for Cursor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cursor {
|
impl TokenTreeCursor {
|
||||||
fn new(stream: TokenStream) -> Self {
|
fn new(stream: TokenStream) -> Self {
|
||||||
Cursor { stream, index: 0 }
|
TokenTreeCursor { stream, index: 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -614,6 +617,15 @@ impl Cursor {
|
||||||
pub fn look_ahead(&self, n: usize) -> Option<&TokenTree> {
|
pub fn look_ahead(&self, n: usize) -> Option<&TokenTree> {
|
||||||
self.stream.0.get(self.index + n)
|
self.stream.0.get(self.index + n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Replace the previously obtained token tree with `tts`, and rewind to
|
||||||
|
// just before them.
|
||||||
|
pub fn replace_prev_and_rewind(&mut self, tts: Vec<TokenTree>) {
|
||||||
|
assert!(self.index > 0);
|
||||||
|
self.index -= 1;
|
||||||
|
let stream = Lrc::make_mut(&mut self.stream.0);
|
||||||
|
stream.splice(self.index..self.index + 1, tts);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]
|
#[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]
|
||||||
|
|
|
@ -31,8 +31,8 @@ cfg_if! {
|
||||||
pub auto trait Send {}
|
pub auto trait Send {}
|
||||||
pub auto trait Sync {}
|
pub auto trait Sync {}
|
||||||
|
|
||||||
impl<T: ?Sized> Send for T {}
|
impl<T> Send for T {}
|
||||||
impl<T: ?Sized> Sync for T {}
|
impl<T> Sync for T {}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! rustc_erase_owner {
|
macro_rules! rustc_erase_owner {
|
||||||
|
|
|
@ -61,3 +61,5 @@ hir_typeck_lang_start_incorrect_ret_ty = the return type of the `start` lang ite
|
||||||
hir_typeck_help_set_edition_cargo = set `edition = "{$edition}"` in `Cargo.toml`
|
hir_typeck_help_set_edition_cargo = set `edition = "{$edition}"` in `Cargo.toml`
|
||||||
hir_typeck_help_set_edition_standalone = pass `--edition {$edition}` to `rustc`
|
hir_typeck_help_set_edition_standalone = pass `--edition {$edition}` to `rustc`
|
||||||
hir_typeck_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide
|
hir_typeck_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide
|
||||||
|
|
||||||
|
hir_typeck_convert_to_str = try converting the passed type into a `&str`
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use rustc_ast::token::{self, Delimiter};
|
use rustc_ast::token::{self, Delimiter};
|
||||||
use rustc_ast::tokenstream::{CursorRef, TokenStream, TokenTree};
|
use rustc_ast::tokenstream::{RefTokenTreeCursor, TokenStream, TokenTree};
|
||||||
use rustc_ast::{LitIntType, LitKind};
|
use rustc_ast::{LitIntType, LitKind};
|
||||||
use rustc_ast_pretty::pprust;
|
use rustc_ast_pretty::pprust;
|
||||||
use rustc_errors::{Applicability, PResult};
|
use rustc_errors::{Applicability, PResult};
|
||||||
|
@ -72,7 +72,7 @@ impl MetaVarExpr {
|
||||||
|
|
||||||
// Checks if there are any remaining tokens. For example, `${ignore(ident ... a b c ...)}`
|
// Checks if there are any remaining tokens. For example, `${ignore(ident ... a b c ...)}`
|
||||||
fn check_trailing_token<'sess>(
|
fn check_trailing_token<'sess>(
|
||||||
iter: &mut CursorRef<'_>,
|
iter: &mut RefTokenTreeCursor<'_>,
|
||||||
sess: &'sess ParseSess,
|
sess: &'sess ParseSess,
|
||||||
) -> PResult<'sess, ()> {
|
) -> PResult<'sess, ()> {
|
||||||
if let Some(tt) = iter.next() {
|
if let Some(tt) = iter.next() {
|
||||||
|
@ -88,7 +88,7 @@ fn check_trailing_token<'sess>(
|
||||||
|
|
||||||
/// Parse a meta-variable `count` expression: `count(ident[, depth])`
|
/// Parse a meta-variable `count` expression: `count(ident[, depth])`
|
||||||
fn parse_count<'sess>(
|
fn parse_count<'sess>(
|
||||||
iter: &mut CursorRef<'_>,
|
iter: &mut RefTokenTreeCursor<'_>,
|
||||||
sess: &'sess ParseSess,
|
sess: &'sess ParseSess,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> PResult<'sess, MetaVarExpr> {
|
) -> PResult<'sess, MetaVarExpr> {
|
||||||
|
@ -99,7 +99,7 @@ fn parse_count<'sess>(
|
||||||
|
|
||||||
/// Parses the depth used by index(depth) and length(depth).
|
/// Parses the depth used by index(depth) and length(depth).
|
||||||
fn parse_depth<'sess>(
|
fn parse_depth<'sess>(
|
||||||
iter: &mut CursorRef<'_>,
|
iter: &mut RefTokenTreeCursor<'_>,
|
||||||
sess: &'sess ParseSess,
|
sess: &'sess ParseSess,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> PResult<'sess, usize> {
|
) -> PResult<'sess, usize> {
|
||||||
|
@ -126,7 +126,7 @@ fn parse_depth<'sess>(
|
||||||
|
|
||||||
/// Parses an generic ident
|
/// Parses an generic ident
|
||||||
fn parse_ident<'sess>(
|
fn parse_ident<'sess>(
|
||||||
iter: &mut CursorRef<'_>,
|
iter: &mut RefTokenTreeCursor<'_>,
|
||||||
sess: &'sess ParseSess,
|
sess: &'sess ParseSess,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> PResult<'sess, Ident> {
|
) -> PResult<'sess, Ident> {
|
||||||
|
@ -152,7 +152,7 @@ fn parse_ident<'sess>(
|
||||||
|
|
||||||
/// Tries to move the iterator forward returning `true` if there is a comma. If not, then the
|
/// Tries to move the iterator forward returning `true` if there is a comma. If not, then the
|
||||||
/// iterator is not modified and the result is `false`.
|
/// iterator is not modified and the result is `false`.
|
||||||
fn try_eat_comma(iter: &mut CursorRef<'_>) -> bool {
|
fn try_eat_comma(iter: &mut RefTokenTreeCursor<'_>) -> bool {
|
||||||
if let Some(TokenTree::Token(token::Token { kind: token::Comma, .. }, _)) = iter.look_ahead(0) {
|
if let Some(TokenTree::Token(token::Token { kind: token::Comma, .. }, _)) = iter.look_ahead(0) {
|
||||||
let _ = iter.next();
|
let _ = iter.next();
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -8,7 +8,7 @@ use rustc_hir as hir;
|
||||||
use rustc_middle::ty::subst::InternalSubsts;
|
use rustc_middle::ty::subst::InternalSubsts;
|
||||||
use rustc_middle::ty::util::IgnoreRegions;
|
use rustc_middle::ty::util::IgnoreRegions;
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, ImplPolarity, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
|
self, AliasKind, ImplPolarity, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
|
||||||
};
|
};
|
||||||
use rustc_session::lint;
|
use rustc_session::lint;
|
||||||
use rustc_span::def_id::{DefId, LocalDefId};
|
use rustc_span::def_id::{DefId, LocalDefId};
|
||||||
|
@ -86,7 +86,7 @@ fn do_orphan_check_impl<'tcx>(
|
||||||
// struct B { }
|
// struct B { }
|
||||||
// impl Foo for A { }
|
// impl Foo for A { }
|
||||||
// impl Foo for B { }
|
// impl Foo for B { }
|
||||||
// impl !Send for (A, B) { }
|
// impl !Foo for (A, B) { }
|
||||||
// ```
|
// ```
|
||||||
//
|
//
|
||||||
// This final impl is legal according to the orphan
|
// This final impl is legal according to the orphan
|
||||||
|
@ -99,24 +99,170 @@ fn do_orphan_check_impl<'tcx>(
|
||||||
tcx.trait_is_auto(trait_def_id)
|
tcx.trait_is_auto(trait_def_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
if tcx.trait_is_auto(trait_def_id) && !trait_def_id.is_local() {
|
if tcx.trait_is_auto(trait_def_id) {
|
||||||
let self_ty = trait_ref.self_ty();
|
let self_ty = trait_ref.self_ty();
|
||||||
let opt_self_def_id = match *self_ty.kind() {
|
|
||||||
ty::Adt(self_def, _) => Some(self_def.did()),
|
// If the impl is in the same crate as the auto-trait, almost anything
|
||||||
ty::Foreign(did) => Some(did),
|
// goes.
|
||||||
_ => None,
|
//
|
||||||
|
// impl MyAuto for Rc<Something> {} // okay
|
||||||
|
// impl<T> !MyAuto for *const T {} // okay
|
||||||
|
// impl<T> MyAuto for T {} // okay
|
||||||
|
//
|
||||||
|
// But there is one important exception: implementing for a trait object
|
||||||
|
// is not allowed.
|
||||||
|
//
|
||||||
|
// impl MyAuto for dyn Trait {} // NOT OKAY
|
||||||
|
// impl<T: ?Sized> MyAuto for T {} // NOT OKAY
|
||||||
|
//
|
||||||
|
// With this restriction, it's guaranteed that an auto-trait is
|
||||||
|
// implemented for a trait object if and only if the auto-trait is one
|
||||||
|
// of the trait object's trait bounds (or a supertrait of a bound). In
|
||||||
|
// other words `dyn Trait + AutoTrait` always implements AutoTrait,
|
||||||
|
// while `dyn Trait` never implements AutoTrait.
|
||||||
|
//
|
||||||
|
// This is necessary in order for autotrait bounds on methods of trait
|
||||||
|
// objects to be sound.
|
||||||
|
//
|
||||||
|
// auto trait AutoTrait {}
|
||||||
|
//
|
||||||
|
// trait ObjectSafeTrait {
|
||||||
|
// fn f(&self) where Self: AutoTrait;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// We can allow f to be called on `dyn ObjectSafeTrait + AutoTrait`.
|
||||||
|
//
|
||||||
|
// If we didn't deny `impl AutoTrait for dyn Trait`, it would be unsound
|
||||||
|
// for the ObjectSafeTrait shown above to be object safe because someone
|
||||||
|
// could take some type implementing ObjectSafeTrait but not AutoTrait,
|
||||||
|
// unsize it to `dyn ObjectSafeTrait`, and call .f() which has no
|
||||||
|
// concrete implementation (issue #50781).
|
||||||
|
enum LocalImpl {
|
||||||
|
Allow,
|
||||||
|
Disallow { problematic_kind: &'static str },
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the auto-trait is from a dependency, it must only be getting
|
||||||
|
// implemented for a nominal type, and specifically one local to the
|
||||||
|
// current crate.
|
||||||
|
//
|
||||||
|
// impl<T> Sync for MyStruct<T> {} // okay
|
||||||
|
//
|
||||||
|
// impl Sync for Rc<MyStruct> {} // NOT OKAY
|
||||||
|
enum NonlocalImpl {
|
||||||
|
Allow,
|
||||||
|
DisallowBecauseNonlocal,
|
||||||
|
DisallowOther,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exhaustive match considering that this logic is essential for
|
||||||
|
// soundness.
|
||||||
|
let (local_impl, nonlocal_impl) = match self_ty.kind() {
|
||||||
|
// struct Struct<T>;
|
||||||
|
// impl AutoTrait for Struct<Foo> {}
|
||||||
|
ty::Adt(self_def, _) => (
|
||||||
|
LocalImpl::Allow,
|
||||||
|
if self_def.did().is_local() {
|
||||||
|
NonlocalImpl::Allow
|
||||||
|
} else {
|
||||||
|
NonlocalImpl::DisallowBecauseNonlocal
|
||||||
|
},
|
||||||
|
),
|
||||||
|
|
||||||
|
// extern { type OpaqueType; }
|
||||||
|
// impl AutoTrait for OpaqueType {}
|
||||||
|
ty::Foreign(did) => (
|
||||||
|
LocalImpl::Allow,
|
||||||
|
if did.is_local() {
|
||||||
|
NonlocalImpl::Allow
|
||||||
|
} else {
|
||||||
|
NonlocalImpl::DisallowBecauseNonlocal
|
||||||
|
},
|
||||||
|
),
|
||||||
|
|
||||||
|
// impl AutoTrait for dyn Trait {}
|
||||||
|
ty::Dynamic(..) => (
|
||||||
|
LocalImpl::Disallow { problematic_kind: "trait object" },
|
||||||
|
NonlocalImpl::DisallowOther,
|
||||||
|
),
|
||||||
|
|
||||||
|
// impl<T> AutoTrait for T {}
|
||||||
|
// impl<T: ?Sized> AutoTrait for T {}
|
||||||
|
ty::Param(..) => (
|
||||||
|
if self_ty.is_sized(tcx, tcx.param_env(def_id)) {
|
||||||
|
LocalImpl::Allow
|
||||||
|
} else {
|
||||||
|
LocalImpl::Disallow { problematic_kind: "generic type" }
|
||||||
|
},
|
||||||
|
NonlocalImpl::DisallowOther,
|
||||||
|
),
|
||||||
|
|
||||||
|
// trait Id { type This: ?Sized; }
|
||||||
|
// impl<T: ?Sized> Id for T {
|
||||||
|
// type This = T;
|
||||||
|
// }
|
||||||
|
// impl<T: ?Sized> AutoTrait for <T as Id>::This {}
|
||||||
|
ty::Alias(AliasKind::Projection, _) => (
|
||||||
|
LocalImpl::Disallow { problematic_kind: "associated type" },
|
||||||
|
NonlocalImpl::DisallowOther,
|
||||||
|
),
|
||||||
|
|
||||||
|
// type Opaque = impl Trait;
|
||||||
|
// impl AutoTrait for Opaque {}
|
||||||
|
ty::Alias(AliasKind::Opaque, _) => (
|
||||||
|
LocalImpl::Disallow { problematic_kind: "opaque type" },
|
||||||
|
NonlocalImpl::DisallowOther,
|
||||||
|
),
|
||||||
|
|
||||||
|
ty::Bool
|
||||||
|
| ty::Char
|
||||||
|
| ty::Int(..)
|
||||||
|
| ty::Uint(..)
|
||||||
|
| ty::Float(..)
|
||||||
|
| ty::Str
|
||||||
|
| ty::Array(..)
|
||||||
|
| ty::Slice(..)
|
||||||
|
| ty::RawPtr(..)
|
||||||
|
| ty::Ref(..)
|
||||||
|
| ty::FnDef(..)
|
||||||
|
| ty::FnPtr(..)
|
||||||
|
| ty::Never
|
||||||
|
| ty::Tuple(..) => (LocalImpl::Allow, NonlocalImpl::DisallowOther),
|
||||||
|
|
||||||
|
ty::Closure(..)
|
||||||
|
| ty::Generator(..)
|
||||||
|
| ty::GeneratorWitness(..)
|
||||||
|
| ty::GeneratorWitnessMIR(..)
|
||||||
|
| ty::Bound(..)
|
||||||
|
| ty::Placeholder(..)
|
||||||
|
| ty::Infer(..) => span_bug!(sp, "weird self type for autotrait impl"),
|
||||||
|
|
||||||
|
ty::Error(..) => (LocalImpl::Allow, NonlocalImpl::Allow),
|
||||||
};
|
};
|
||||||
|
|
||||||
let msg = match opt_self_def_id {
|
if trait_def_id.is_local() {
|
||||||
// We only want to permit nominal types, but not *all* nominal types.
|
match local_impl {
|
||||||
// They must be local to the current crate, so that people
|
LocalImpl::Allow => {}
|
||||||
// can't do `unsafe impl Send for Rc<SomethingLocal>` or
|
LocalImpl::Disallow { problematic_kind } => {
|
||||||
// `impl !Send for Box<SomethingLocalAndSend>`.
|
let msg = format!(
|
||||||
Some(self_def_id) => {
|
"traits with a default impl, like `{trait}`, \
|
||||||
if self_def_id.is_local() {
|
cannot be implemented for {problematic_kind} `{self_ty}`",
|
||||||
None
|
trait = tcx.def_path_str(trait_def_id),
|
||||||
|
);
|
||||||
|
let label = format!(
|
||||||
|
"a trait object implements `{trait}` if and only if `{trait}` \
|
||||||
|
is one of the trait object's trait bounds",
|
||||||
|
trait = tcx.def_path_str(trait_def_id),
|
||||||
|
);
|
||||||
|
let reported =
|
||||||
|
struct_span_err!(tcx.sess, sp, E0321, "{}", msg).note(label).emit();
|
||||||
|
return Err(reported);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Some((
|
if let Some((msg, label)) = match nonlocal_impl {
|
||||||
|
NonlocalImpl::Allow => None,
|
||||||
|
NonlocalImpl::DisallowBecauseNonlocal => Some((
|
||||||
format!(
|
format!(
|
||||||
"cross-crate traits with a default impl, like `{}`, \
|
"cross-crate traits with a default impl, like `{}`, \
|
||||||
can only be implemented for a struct/enum type \
|
can only be implemented for a struct/enum type \
|
||||||
|
@ -124,10 +270,8 @@ fn do_orphan_check_impl<'tcx>(
|
||||||
tcx.def_path_str(trait_def_id)
|
tcx.def_path_str(trait_def_id)
|
||||||
),
|
),
|
||||||
"can't implement cross-crate trait for type in another crate",
|
"can't implement cross-crate trait for type in another crate",
|
||||||
))
|
)),
|
||||||
}
|
NonlocalImpl::DisallowOther => Some((
|
||||||
}
|
|
||||||
_ => Some((
|
|
||||||
format!(
|
format!(
|
||||||
"cross-crate traits with a default impl, like `{}`, can \
|
"cross-crate traits with a default impl, like `{}`, can \
|
||||||
only be implemented for a struct/enum type, not `{}`",
|
only be implemented for a struct/enum type, not `{}`",
|
||||||
|
@ -137,14 +281,13 @@ fn do_orphan_check_impl<'tcx>(
|
||||||
"can't implement cross-crate trait with a default impl for \
|
"can't implement cross-crate trait with a default impl for \
|
||||||
non-struct/enum type",
|
non-struct/enum type",
|
||||||
)),
|
)),
|
||||||
};
|
} {
|
||||||
|
|
||||||
if let Some((msg, label)) = msg {
|
|
||||||
let reported =
|
let reported =
|
||||||
struct_span_err!(tcx.sess, sp, E0321, "{}", msg).span_label(sp, label).emit();
|
struct_span_err!(tcx.sess, sp, E0321, "{}", msg).span_label(sp, label).emit();
|
||||||
return Err(reported);
|
return Err(reported);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use super::FnCtxt;
|
||||||
use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel};
|
use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel};
|
||||||
use crate::method::probe::{IsSuggestion, Mode, ProbeScope};
|
use crate::method::probe::{IsSuggestion, Mode, ProbeScope};
|
||||||
use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX};
|
use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX};
|
||||||
use rustc_errors::{Applicability, Diagnostic, MultiSpan};
|
use rustc_errors::{fluent, Applicability, Diagnostic, MultiSpan};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind};
|
use rustc_hir::def::{CtorKind, CtorOf, DefKind};
|
||||||
use rustc_hir::lang_items::LangItem;
|
use rustc_hir::lang_items::LangItem;
|
||||||
|
@ -414,11 +414,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
if let ty::Adt(adt, _) = peeled.kind()
|
if let ty::Adt(adt, _) = peeled.kind()
|
||||||
&& Some(adt.did()) == self.tcx.lang_items().string()
|
&& Some(adt.did()) == self.tcx.lang_items().string()
|
||||||
{
|
{
|
||||||
|
let sugg = if ref_cnt == 0 {
|
||||||
|
".as_deref()"
|
||||||
|
} else {
|
||||||
|
".map(|x| x.as_str())"
|
||||||
|
};
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
expr.span.shrink_to_hi(),
|
expr.span.shrink_to_hi(),
|
||||||
"try converting the passed type into a `&str`",
|
fluent::hir_typeck_convert_to_str,
|
||||||
format!(".map(|x| &*{}x)", "*".repeat(ref_cnt)),
|
sugg,
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -495,6 +495,7 @@ enum UnusedDelimsCtx {
|
||||||
ArrayLenExpr,
|
ArrayLenExpr,
|
||||||
AnonConst,
|
AnonConst,
|
||||||
MatchArmExpr,
|
MatchArmExpr,
|
||||||
|
IndexExpr,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<UnusedDelimsCtx> for &'static str {
|
impl From<UnusedDelimsCtx> for &'static str {
|
||||||
|
@ -514,6 +515,7 @@ impl From<UnusedDelimsCtx> for &'static str {
|
||||||
UnusedDelimsCtx::LetScrutineeExpr => "`let` scrutinee expression",
|
UnusedDelimsCtx::LetScrutineeExpr => "`let` scrutinee expression",
|
||||||
UnusedDelimsCtx::ArrayLenExpr | UnusedDelimsCtx::AnonConst => "const expression",
|
UnusedDelimsCtx::ArrayLenExpr | UnusedDelimsCtx::AnonConst => "const expression",
|
||||||
UnusedDelimsCtx::MatchArmExpr => "match arm expression",
|
UnusedDelimsCtx::MatchArmExpr => "match arm expression",
|
||||||
|
UnusedDelimsCtx::IndexExpr => "index expression",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -733,6 +735,8 @@ trait UnusedDelimLint {
|
||||||
(value, UnusedDelimsCtx::ReturnValue, false, Some(left), None)
|
(value, UnusedDelimsCtx::ReturnValue, false, Some(left), None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Index(_, ref value) => (value, UnusedDelimsCtx::IndexExpr, false, None, None),
|
||||||
|
|
||||||
Assign(_, ref value, _) | AssignOp(.., ref value) => {
|
Assign(_, ref value, _) | AssignOp(.., ref value) => {
|
||||||
(value, UnusedDelimsCtx::AssignedValue, false, None, None)
|
(value, UnusedDelimsCtx::AssignedValue, false, None, None)
|
||||||
}
|
}
|
||||||
|
|
|
@ -675,9 +675,13 @@ pub trait PrettyPrinter<'tcx>:
|
||||||
p!(")")
|
p!(")")
|
||||||
}
|
}
|
||||||
ty::FnDef(def_id, substs) => {
|
ty::FnDef(def_id, substs) => {
|
||||||
|
if NO_QUERIES.with(|q| q.get()) {
|
||||||
|
p!(print_def_path(def_id, substs));
|
||||||
|
} else {
|
||||||
let sig = self.tcx().fn_sig(def_id).subst(self.tcx(), substs);
|
let sig = self.tcx().fn_sig(def_id).subst(self.tcx(), substs);
|
||||||
p!(print(sig), " {{", print_value_path(def_id, substs), "}}");
|
p!(print(sig), " {{", print_value_path(def_id, substs), "}}");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
ty::FnPtr(ref bare_fn) => p!(print(bare_fn)),
|
ty::FnPtr(ref bare_fn) => p!(print(bare_fn)),
|
||||||
ty::Infer(infer_ty) => {
|
ty::Infer(infer_ty) => {
|
||||||
let verbose = self.should_print_verbose();
|
let verbose = self.should_print_verbose();
|
||||||
|
@ -734,13 +738,13 @@ pub trait PrettyPrinter<'tcx>:
|
||||||
}
|
}
|
||||||
ty::Placeholder(placeholder) => p!(write("Placeholder({:?})", placeholder)),
|
ty::Placeholder(placeholder) => p!(write("Placeholder({:?})", placeholder)),
|
||||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
|
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
|
||||||
// FIXME(eddyb) print this with `print_def_path`.
|
|
||||||
// We use verbose printing in 'NO_QUERIES' mode, to
|
// We use verbose printing in 'NO_QUERIES' mode, to
|
||||||
// avoid needing to call `predicates_of`. This should
|
// avoid needing to call `predicates_of`. This should
|
||||||
// only affect certain debug messages (e.g. messages printed
|
// only affect certain debug messages (e.g. messages printed
|
||||||
// from `rustc_middle::ty` during the computation of `tcx.predicates_of`),
|
// from `rustc_middle::ty` during the computation of `tcx.predicates_of`),
|
||||||
// and should have no effect on any compiler output.
|
// and should have no effect on any compiler output.
|
||||||
if self.should_print_verbose() || NO_QUERIES.with(|q| q.get()) {
|
if self.should_print_verbose() {
|
||||||
|
// FIXME(eddyb) print this with `print_def_path`.
|
||||||
p!(write("Opaque({:?}, {:?})", def_id, substs));
|
p!(write("Opaque({:?}, {:?})", def_id, substs));
|
||||||
return Ok(self);
|
return Ok(self);
|
||||||
}
|
}
|
||||||
|
@ -748,6 +752,8 @@ pub trait PrettyPrinter<'tcx>:
|
||||||
let parent = self.tcx().parent(def_id);
|
let parent = self.tcx().parent(def_id);
|
||||||
match self.tcx().def_kind(parent) {
|
match self.tcx().def_kind(parent) {
|
||||||
DefKind::TyAlias | DefKind::AssocTy => {
|
DefKind::TyAlias | DefKind::AssocTy => {
|
||||||
|
// NOTE: I know we should check for NO_QUERIES here, but it's alright.
|
||||||
|
// `type_of` on a type alias or assoc type should never cause a cycle.
|
||||||
if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: d, .. }) =
|
if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: d, .. }) =
|
||||||
*self.tcx().type_of(parent).kind()
|
*self.tcx().type_of(parent).kind()
|
||||||
{
|
{
|
||||||
|
@ -762,7 +768,14 @@ pub trait PrettyPrinter<'tcx>:
|
||||||
p!(print_def_path(def_id, substs));
|
p!(print_def_path(def_id, substs));
|
||||||
return Ok(self);
|
return Ok(self);
|
||||||
}
|
}
|
||||||
_ => return self.pretty_print_opaque_impl_type(def_id, substs),
|
_ => {
|
||||||
|
if NO_QUERIES.with(|q| q.get()) {
|
||||||
|
p!(print_def_path(def_id, &[]));
|
||||||
|
return Ok(self);
|
||||||
|
} else {
|
||||||
|
return self.pretty_print_opaque_impl_type(def_id, substs);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::Str => p!("str"),
|
ty::Str => p!("str"),
|
||||||
|
|
|
@ -469,6 +469,6 @@ mod size_asserts {
|
||||||
use rustc_data_structures::static_assert_size;
|
use rustc_data_structures::static_assert_size;
|
||||||
// tidy-alphabetical-start
|
// tidy-alphabetical-start
|
||||||
static_assert_size!(AttrWrapper, 16);
|
static_assert_size!(AttrWrapper, 16);
|
||||||
static_assert_size!(LazyAttrTokenStreamImpl, 144);
|
static_assert_size!(LazyAttrTokenStreamImpl, 120);
|
||||||
// tidy-alphabetical-end
|
// tidy-alphabetical-end
|
||||||
}
|
}
|
||||||
|
|
|
@ -2141,7 +2141,7 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.token.kind == TokenKind::Semi
|
if self.token.kind == TokenKind::Semi
|
||||||
&& matches!(self.token_cursor.frame.delim_sp, Some((Delimiter::Parenthesis, _)))
|
&& matches!(self.token_cursor.stack.last(), Some((_, Delimiter::Parenthesis, _)))
|
||||||
&& self.may_recover()
|
&& self.may_recover()
|
||||||
{
|
{
|
||||||
// It is likely that the closure body is a block but where the
|
// It is likely that the closure body is a block but where the
|
||||||
|
|
|
@ -19,9 +19,8 @@ pub use path::PathStyle;
|
||||||
|
|
||||||
use rustc_ast::ptr::P;
|
use rustc_ast::ptr::P;
|
||||||
use rustc_ast::token::{self, Delimiter, Nonterminal, Token, TokenKind};
|
use rustc_ast::token::{self, Delimiter, Nonterminal, Token, TokenKind};
|
||||||
use rustc_ast::tokenstream::AttributesData;
|
use rustc_ast::tokenstream::{AttributesData, DelimSpan, Spacing};
|
||||||
use rustc_ast::tokenstream::{self, DelimSpan, Spacing};
|
use rustc_ast::tokenstream::{TokenStream, TokenTree, TokenTreeCursor};
|
||||||
use rustc_ast::tokenstream::{TokenStream, TokenTree};
|
|
||||||
use rustc_ast::util::case::Case;
|
use rustc_ast::util::case::Case;
|
||||||
use rustc_ast::AttrId;
|
use rustc_ast::AttrId;
|
||||||
use rustc_ast::DUMMY_NODE_ID;
|
use rustc_ast::DUMMY_NODE_ID;
|
||||||
|
@ -168,7 +167,7 @@ pub struct Parser<'a> {
|
||||||
// This type is used a lot, e.g. it's cloned when matching many declarative macro rules with nonterminals. Make sure
|
// This type is used a lot, e.g. it's cloned when matching many declarative macro rules with nonterminals. Make sure
|
||||||
// it doesn't unintentionally get bigger.
|
// it doesn't unintentionally get bigger.
|
||||||
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
||||||
rustc_data_structures::static_assert_size!(Parser<'_>, 336);
|
rustc_data_structures::static_assert_size!(Parser<'_>, 312);
|
||||||
|
|
||||||
/// Stores span information about a closure.
|
/// Stores span information about a closure.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -221,18 +220,27 @@ impl<'a> Drop for Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Iterator over a `TokenStream` that produces `Token`s. It's a bit odd that
|
||||||
|
/// we (a) lex tokens into a nice tree structure (`TokenStream`), and then (b)
|
||||||
|
/// use this type to emit them as a linear sequence. But a linear sequence is
|
||||||
|
/// what the parser expects, for the most part.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct TokenCursor {
|
struct TokenCursor {
|
||||||
// The current (innermost) frame. `frame` and `stack` could be combined,
|
// Cursor for the current (innermost) token stream. The delimiters for this
|
||||||
// but it's faster to have them separately to access `frame` directly
|
// token stream are found in `self.stack.last()`; when that is `None` then
|
||||||
// rather than via something like `stack.last().unwrap()` or
|
// we are in the outermost token stream which never has delimiters.
|
||||||
// `stack[stack.len() - 1]`.
|
tree_cursor: TokenTreeCursor,
|
||||||
frame: TokenCursorFrame,
|
|
||||||
// Additional frames that enclose `frame`.
|
// Token streams surrounding the current one. The delimiters for stack[n]'s
|
||||||
stack: Vec<TokenCursorFrame>,
|
// tokens are in `stack[n-1]`. `stack[0]` (when present) has no delimiters
|
||||||
|
// because it's the outermost token stream which never has delimiters.
|
||||||
|
stack: Vec<(TokenTreeCursor, Delimiter, DelimSpan)>,
|
||||||
|
|
||||||
desugar_doc_comments: bool,
|
desugar_doc_comments: bool,
|
||||||
|
|
||||||
// Counts the number of calls to `{,inlined_}next`.
|
// Counts the number of calls to `{,inlined_}next`.
|
||||||
num_next_calls: usize,
|
num_next_calls: usize,
|
||||||
|
|
||||||
// During parsing, we may sometimes need to 'unglue' a
|
// During parsing, we may sometimes need to 'unglue' a
|
||||||
// glued token into two component tokens
|
// glued token into two component tokens
|
||||||
// (e.g. '>>' into '>' and '>), so that the parser
|
// (e.g. '>>' into '>' and '>), so that the parser
|
||||||
|
@ -257,18 +265,6 @@ struct TokenCursor {
|
||||||
break_last_token: bool,
|
break_last_token: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct TokenCursorFrame {
|
|
||||||
delim_sp: Option<(Delimiter, DelimSpan)>,
|
|
||||||
tree_cursor: tokenstream::Cursor,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TokenCursorFrame {
|
|
||||||
fn new(delim_sp: Option<(Delimiter, DelimSpan)>, tts: TokenStream) -> Self {
|
|
||||||
TokenCursorFrame { delim_sp, tree_cursor: tts.into_trees() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TokenCursor {
|
impl TokenCursor {
|
||||||
fn next(&mut self, desugar_doc_comments: bool) -> (Token, Spacing) {
|
fn next(&mut self, desugar_doc_comments: bool) -> (Token, Spacing) {
|
||||||
self.inlined_next(desugar_doc_comments)
|
self.inlined_next(desugar_doc_comments)
|
||||||
|
@ -281,38 +277,47 @@ impl TokenCursor {
|
||||||
// FIXME: we currently don't return `Delimiter` open/close delims. To fix #67062 we will
|
// FIXME: we currently don't return `Delimiter` open/close delims. To fix #67062 we will
|
||||||
// need to, whereupon the `delim != Delimiter::Invisible` conditions below can be
|
// need to, whereupon the `delim != Delimiter::Invisible` conditions below can be
|
||||||
// removed.
|
// removed.
|
||||||
if let Some(tree) = self.frame.tree_cursor.next_ref() {
|
if let Some(tree) = self.tree_cursor.next_ref() {
|
||||||
match tree {
|
match tree {
|
||||||
&TokenTree::Token(ref token, spacing) => match (desugar_doc_comments, token) {
|
&TokenTree::Token(ref token, spacing) => match (desugar_doc_comments, token) {
|
||||||
(true, &Token { kind: token::DocComment(_, attr_style, data), span }) => {
|
(true, &Token { kind: token::DocComment(_, attr_style, data), span }) => {
|
||||||
return self.desugar(attr_style, data, span);
|
let desugared = self.desugar(attr_style, data, span);
|
||||||
|
self.tree_cursor.replace_prev_and_rewind(desugared);
|
||||||
|
// Continue to get the first token of the desugared doc comment.
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
debug_assert!(!matches!(
|
||||||
|
token.kind,
|
||||||
|
token::OpenDelim(_) | token::CloseDelim(_)
|
||||||
|
));
|
||||||
|
return (token.clone(), spacing);
|
||||||
}
|
}
|
||||||
_ => return (token.clone(), spacing),
|
|
||||||
},
|
},
|
||||||
&TokenTree::Delimited(sp, delim, ref tts) => {
|
&TokenTree::Delimited(sp, delim, ref tts) => {
|
||||||
// Set `open_delim` to true here because we deal with it immediately.
|
let trees = tts.clone().into_trees();
|
||||||
let frame = TokenCursorFrame::new(Some((delim, sp)), tts.clone());
|
self.stack.push((mem::replace(&mut self.tree_cursor, trees), delim, sp));
|
||||||
self.stack.push(mem::replace(&mut self.frame, frame));
|
|
||||||
if delim != Delimiter::Invisible {
|
if delim != Delimiter::Invisible {
|
||||||
return (Token::new(token::OpenDelim(delim), sp.open), Spacing::Alone);
|
return (Token::new(token::OpenDelim(delim), sp.open), Spacing::Alone);
|
||||||
}
|
}
|
||||||
// No open delimiter to return; continue on to the next iteration.
|
// No open delimiter to return; continue on to the next iteration.
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} else if let Some(frame) = self.stack.pop() {
|
} else if let Some((tree_cursor, delim, span)) = self.stack.pop() {
|
||||||
if let Some((delim, span)) = self.frame.delim_sp && delim != Delimiter::Invisible {
|
// We have exhausted this token stream. Move back to its parent token stream.
|
||||||
self.frame = frame;
|
self.tree_cursor = tree_cursor;
|
||||||
|
if delim != Delimiter::Invisible {
|
||||||
return (Token::new(token::CloseDelim(delim), span.close), Spacing::Alone);
|
return (Token::new(token::CloseDelim(delim), span.close), Spacing::Alone);
|
||||||
}
|
}
|
||||||
self.frame = frame;
|
|
||||||
// No close delimiter to return; continue on to the next iteration.
|
// No close delimiter to return; continue on to the next iteration.
|
||||||
} else {
|
} else {
|
||||||
|
// We have exhausted the outermost token stream.
|
||||||
return (Token::new(token::Eof, DUMMY_SP), Spacing::Alone);
|
return (Token::new(token::Eof, DUMMY_SP), Spacing::Alone);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn desugar(&mut self, attr_style: AttrStyle, data: Symbol, span: Span) -> (Token, Spacing) {
|
// Desugar a doc comment into something like `#[doc = r"foo"]`.
|
||||||
|
fn desugar(&mut self, attr_style: AttrStyle, data: Symbol, span: Span) -> Vec<TokenTree> {
|
||||||
// Searches for the occurrences of `"#*` and returns the minimum number of `#`s
|
// Searches for the occurrences of `"#*` and returns the minimum number of `#`s
|
||||||
// required to wrap the text. E.g.
|
// required to wrap the text. E.g.
|
||||||
// - `abc d` is wrapped as `r"abc d"` (num_of_hashes = 0)
|
// - `abc d` is wrapped as `r"abc d"` (num_of_hashes = 0)
|
||||||
|
@ -346,27 +351,15 @@ impl TokenCursor {
|
||||||
.collect::<TokenStream>(),
|
.collect::<TokenStream>(),
|
||||||
);
|
);
|
||||||
|
|
||||||
self.stack.push(mem::replace(
|
|
||||||
&mut self.frame,
|
|
||||||
TokenCursorFrame::new(
|
|
||||||
None,
|
|
||||||
if attr_style == AttrStyle::Inner {
|
if attr_style == AttrStyle::Inner {
|
||||||
[
|
vec![
|
||||||
TokenTree::token_alone(token::Pound, span),
|
TokenTree::token_alone(token::Pound, span),
|
||||||
TokenTree::token_alone(token::Not, span),
|
TokenTree::token_alone(token::Not, span),
|
||||||
body,
|
body,
|
||||||
]
|
]
|
||||||
.into_iter()
|
|
||||||
.collect::<TokenStream>()
|
|
||||||
} else {
|
} else {
|
||||||
[TokenTree::token_alone(token::Pound, span), body]
|
vec![TokenTree::token_alone(token::Pound, span), body]
|
||||||
.into_iter()
|
}
|
||||||
.collect::<TokenStream>()
|
|
||||||
},
|
|
||||||
),
|
|
||||||
));
|
|
||||||
|
|
||||||
self.next(/* desugar_doc_comments */ false)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -475,7 +468,7 @@ impl<'a> Parser<'a> {
|
||||||
restrictions: Restrictions::empty(),
|
restrictions: Restrictions::empty(),
|
||||||
expected_tokens: Vec::new(),
|
expected_tokens: Vec::new(),
|
||||||
token_cursor: TokenCursor {
|
token_cursor: TokenCursor {
|
||||||
frame: TokenCursorFrame::new(None, tokens),
|
tree_cursor: tokens.into_trees(),
|
||||||
stack: Vec::new(),
|
stack: Vec::new(),
|
||||||
num_next_calls: 0,
|
num_next_calls: 0,
|
||||||
desugar_doc_comments,
|
desugar_doc_comments,
|
||||||
|
@ -1142,14 +1135,16 @@ impl<'a> Parser<'a> {
|
||||||
return looker(&self.token);
|
return looker(&self.token);
|
||||||
}
|
}
|
||||||
|
|
||||||
let frame = &self.token_cursor.frame;
|
let tree_cursor = &self.token_cursor.tree_cursor;
|
||||||
if let Some((delim, span)) = frame.delim_sp && delim != Delimiter::Invisible {
|
if let Some(&(_, delim, span)) = self.token_cursor.stack.last()
|
||||||
|
&& delim != Delimiter::Invisible
|
||||||
|
{
|
||||||
let all_normal = (0..dist).all(|i| {
|
let all_normal = (0..dist).all(|i| {
|
||||||
let token = frame.tree_cursor.look_ahead(i);
|
let token = tree_cursor.look_ahead(i);
|
||||||
!matches!(token, Some(TokenTree::Delimited(_, Delimiter::Invisible, _)))
|
!matches!(token, Some(TokenTree::Delimited(_, Delimiter::Invisible, _)))
|
||||||
});
|
});
|
||||||
if all_normal {
|
if all_normal {
|
||||||
return match frame.tree_cursor.look_ahead(dist - 1) {
|
return match tree_cursor.look_ahead(dist - 1) {
|
||||||
Some(tree) => match tree {
|
Some(tree) => match tree {
|
||||||
TokenTree::Token(token, _) => looker(token),
|
TokenTree::Token(token, _) => looker(token),
|
||||||
TokenTree::Delimited(dspan, delim, _) => {
|
TokenTree::Delimited(dspan, delim, _) => {
|
||||||
|
@ -1310,10 +1305,10 @@ impl<'a> Parser<'a> {
|
||||||
pub(crate) fn parse_token_tree(&mut self) -> TokenTree {
|
pub(crate) fn parse_token_tree(&mut self) -> TokenTree {
|
||||||
match self.token.kind {
|
match self.token.kind {
|
||||||
token::OpenDelim(..) => {
|
token::OpenDelim(..) => {
|
||||||
// Grab the tokens from this frame.
|
// Grab the tokens within the delimiters.
|
||||||
let frame = &self.token_cursor.frame;
|
let tree_cursor = &self.token_cursor.tree_cursor;
|
||||||
let stream = frame.tree_cursor.stream.clone();
|
let stream = tree_cursor.stream.clone();
|
||||||
let (delim, span) = frame.delim_sp.unwrap();
|
let (_, delim, span) = *self.token_cursor.stack.last().unwrap();
|
||||||
|
|
||||||
// Advance the token cursor through the entire delimited
|
// Advance the token cursor through the entire delimited
|
||||||
// sequence. After getting the `OpenDelim` we are *within* the
|
// sequence. After getting the `OpenDelim` we are *within* the
|
||||||
|
|
|
@ -314,11 +314,14 @@ pub(crate) fn create_query_frame<
|
||||||
kind: DepKind,
|
kind: DepKind,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
) -> QueryStackFrame<DepKind> {
|
) -> QueryStackFrame<DepKind> {
|
||||||
|
// Avoid calling queries while formatting the description
|
||||||
|
let description = ty::print::with_no_queries!(
|
||||||
// Disable visible paths printing for performance reasons.
|
// Disable visible paths printing for performance reasons.
|
||||||
// Showing visible path instead of any path is not that important in production.
|
// Showing visible path instead of any path is not that important in production.
|
||||||
let description = ty::print::with_no_visible_paths!(
|
ty::print::with_no_visible_paths!(
|
||||||
// Force filename-line mode to avoid invoking `type_of` query.
|
// Force filename-line mode to avoid invoking `type_of` query.
|
||||||
ty::print::with_forced_impl_filename_line!(do_describe(tcx.tcx, key))
|
ty::print::with_forced_impl_filename_line!(do_describe(tcx.tcx, key))
|
||||||
|
)
|
||||||
);
|
);
|
||||||
let description =
|
let description =
|
||||||
if tcx.sess.verbose() { format!("{description} [{name:?}]") } else { description };
|
if tcx.sess.verbose() { format!("{description} [{name:?}]") } else { description };
|
||||||
|
|
|
@ -81,6 +81,7 @@ pub(super) enum CandidateSource {
|
||||||
AliasBound,
|
AliasBound,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Methods used to assemble candidates for either trait or projection goals.
|
||||||
pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy + Eq {
|
pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy + Eq {
|
||||||
fn self_ty(self) -> Ty<'tcx>;
|
fn self_ty(self) -> Ty<'tcx>;
|
||||||
|
|
||||||
|
@ -188,6 +189,11 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy + Eq {
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> Vec<CanonicalResponse<'tcx>>;
|
) -> Vec<CanonicalResponse<'tcx>>;
|
||||||
|
|
||||||
|
fn consider_builtin_discriminant_kind_candidate(
|
||||||
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
|
goal: Goal<'tcx, Self>,
|
||||||
|
) -> QueryResult<'tcx>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
|
@ -320,6 +326,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
G::consider_builtin_generator_candidate(self, goal)
|
G::consider_builtin_generator_candidate(self, goal)
|
||||||
} else if lang_items.unsize_trait() == Some(trait_def_id) {
|
} else if lang_items.unsize_trait() == Some(trait_def_id) {
|
||||||
G::consider_builtin_unsize_candidate(self, goal)
|
G::consider_builtin_unsize_candidate(self, goal)
|
||||||
|
} else if lang_items.discriminant_kind_trait() == Some(trait_def_id) {
|
||||||
|
G::consider_builtin_discriminant_kind_candidate(self, goal)
|
||||||
} else {
|
} else {
|
||||||
Err(NoSolution)
|
Err(NoSolution)
|
||||||
};
|
};
|
||||||
|
|
|
@ -581,6 +581,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
|
||||||
) -> Vec<super::CanonicalResponse<'tcx>> {
|
) -> Vec<super::CanonicalResponse<'tcx>> {
|
||||||
bug!("`Unsize` does not have an associated type: {:?}", goal);
|
bug!("`Unsize` does not have an associated type: {:?}", goal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn consider_builtin_discriminant_kind_candidate(
|
||||||
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
|
goal: Goal<'tcx, Self>,
|
||||||
|
) -> QueryResult<'tcx> {
|
||||||
|
let discriminant = goal.predicate.self_ty().discriminant_ty(ecx.tcx());
|
||||||
|
ecx.infcx
|
||||||
|
.probe(|_| ecx.eq_term_and_make_canonical_response(goal, Certainty::Yes, discriminant))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code.
|
/// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code.
|
||||||
|
|
|
@ -439,6 +439,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||||
|
|
||||||
responses
|
responses
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn consider_builtin_discriminant_kind_candidate(
|
||||||
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
|
_goal: Goal<'tcx, Self>,
|
||||||
|
) -> QueryResult<'tcx> {
|
||||||
|
// `DiscriminantKind` is automatically implemented for every type.
|
||||||
|
ecx.make_canonical_response(Certainty::Yes)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
|
|
|
@ -547,16 +547,56 @@ fn virtual_call_violation_for_method<'tcx>(
|
||||||
|
|
||||||
// NOTE: This check happens last, because it results in a lint, and not a
|
// NOTE: This check happens last, because it results in a lint, and not a
|
||||||
// hard error.
|
// hard error.
|
||||||
if tcx
|
if tcx.predicates_of(method.def_id).predicates.iter().any(|&(pred, span)| {
|
||||||
.predicates_of(method.def_id)
|
// dyn Trait is okay:
|
||||||
.predicates
|
//
|
||||||
.iter()
|
// trait Trait {
|
||||||
// A trait object can't claim to live more than the concrete type,
|
// fn f(&self) where Self: 'static;
|
||||||
// so outlives predicates will always hold.
|
// }
|
||||||
.cloned()
|
//
|
||||||
.filter(|(p, _)| p.to_opt_type_outlives().is_none())
|
// because a trait object can't claim to live longer than the concrete
|
||||||
.any(|pred| contains_illegal_self_type_reference(tcx, trait_def_id, pred))
|
// type. If the lifetime bound holds on dyn Trait then it's guaranteed
|
||||||
|
// to hold as well on the concrete type.
|
||||||
|
if pred.to_opt_type_outlives().is_some() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// dyn Trait is okay:
|
||||||
|
//
|
||||||
|
// auto trait AutoTrait {}
|
||||||
|
//
|
||||||
|
// trait Trait {
|
||||||
|
// fn f(&self) where Self: AutoTrait;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// because `impl AutoTrait for dyn Trait` is disallowed by coherence.
|
||||||
|
// Traits with a default impl are implemented for a trait object if and
|
||||||
|
// only if the autotrait is one of the trait object's trait bounds, like
|
||||||
|
// in `dyn Trait + AutoTrait`. This guarantees that trait objects only
|
||||||
|
// implement auto traits if the underlying type does as well.
|
||||||
|
if let ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate {
|
||||||
|
trait_ref: pred_trait_ref,
|
||||||
|
constness: ty::BoundConstness::NotConst,
|
||||||
|
polarity: ty::ImplPolarity::Positive,
|
||||||
|
})) = pred.kind().skip_binder()
|
||||||
|
&& pred_trait_ref.self_ty() == tcx.types.self_param
|
||||||
|
&& tcx.trait_is_auto(pred_trait_ref.def_id)
|
||||||
{
|
{
|
||||||
|
// Consider bounds like `Self: Bound<Self>`. Auto traits are not
|
||||||
|
// allowed to have generic parameters so `auto trait Bound<T> {}`
|
||||||
|
// would already have reported an error at the definition of the
|
||||||
|
// auto trait.
|
||||||
|
if pred_trait_ref.substs.len() != 1 {
|
||||||
|
tcx.sess.diagnostic().delay_span_bug(
|
||||||
|
span,
|
||||||
|
"auto traits cannot have generic parameters",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
contains_illegal_self_type_reference(tcx, trait_def_id, pred.clone())
|
||||||
|
}) {
|
||||||
return Some(MethodViolationCode::WhereClauseReferencesSelf);
|
return Some(MethodViolationCode::WhereClauseReferencesSelf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ use std::collections::HashMap;
|
||||||
use std::panic::{catch_unwind, AssertUnwindSafe};
|
use std::panic::{catch_unwind, AssertUnwindSafe};
|
||||||
|
|
||||||
use rustc_ast::token::{BinOpToken, Delimiter, Token, TokenKind};
|
use rustc_ast::token::{BinOpToken, Delimiter, Token, TokenKind};
|
||||||
use rustc_ast::tokenstream::{Cursor, TokenStream, TokenTree};
|
use rustc_ast::tokenstream::{TokenStream, TokenTree, TokenTreeCursor};
|
||||||
use rustc_ast::{ast, ptr};
|
use rustc_ast::{ast, ptr};
|
||||||
use rustc_ast_pretty::pprust;
|
use rustc_ast_pretty::pprust;
|
||||||
use rustc_span::{
|
use rustc_span::{
|
||||||
|
@ -736,7 +736,7 @@ impl MacroArgParser {
|
||||||
self.buf.clear();
|
self.buf.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_meta_variable(&mut self, iter: &mut Cursor) -> Option<()> {
|
fn add_meta_variable(&mut self, iter: &mut TokenTreeCursor) -> Option<()> {
|
||||||
match iter.next() {
|
match iter.next() {
|
||||||
Some(TokenTree::Token(
|
Some(TokenTree::Token(
|
||||||
Token {
|
Token {
|
||||||
|
@ -768,7 +768,7 @@ impl MacroArgParser {
|
||||||
&mut self,
|
&mut self,
|
||||||
inner: Vec<ParsedMacroArg>,
|
inner: Vec<ParsedMacroArg>,
|
||||||
delim: Delimiter,
|
delim: Delimiter,
|
||||||
iter: &mut Cursor,
|
iter: &mut TokenTreeCursor,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
let mut buffer = String::new();
|
let mut buffer = String::new();
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
|
@ -1121,7 +1121,7 @@ pub(crate) fn macro_style(mac: &ast::MacCall, context: &RewriteContext<'_>) -> D
|
||||||
// Currently we do not attempt to parse any further than that.
|
// Currently we do not attempt to parse any further than that.
|
||||||
#[derive(new)]
|
#[derive(new)]
|
||||||
struct MacroParser {
|
struct MacroParser {
|
||||||
toks: Cursor,
|
toks: TokenTreeCursor,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MacroParser {
|
impl MacroParser {
|
||||||
|
|
|
@ -28,8 +28,8 @@ note: ...which requires const checking `x`...
|
||||||
|
|
|
|
||||||
LL | pub const async fn x() {}
|
LL | pub const async fn x() {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
= note: ...which requires computing whether `impl core::future::future::Future<Output = ()>` is freeze...
|
= note: ...which requires computing whether `x::{opaque#0}` is freeze...
|
||||||
= note: ...which requires evaluating trait selection obligation `impl core::future::future::Future<Output = ()>: core::marker::Freeze`...
|
= note: ...which requires evaluating trait selection obligation `x::{opaque#0}: core::marker::Freeze`...
|
||||||
= note: ...which again requires computing type of `x::{opaque#0}`, completing the cycle
|
= note: ...which again requires computing type of `x::{opaque#0}`, completing the cycle
|
||||||
note: cycle used when checking item types in top-level module
|
note: cycle used when checking item types in top-level module
|
||||||
--> $DIR/no-const-async.rs:4:1
|
--> $DIR/no-const-async.rs:4:1
|
||||||
|
|
|
@ -13,18 +13,25 @@ trait Object: Marker1 {}
|
||||||
|
|
||||||
// A supertrait marker is illegal...
|
// A supertrait marker is illegal...
|
||||||
impl !Marker1 for dyn Object + Marker2 {} //~ ERROR E0371
|
impl !Marker1 for dyn Object + Marker2 {} //~ ERROR E0371
|
||||||
|
//~^ ERROR 0321
|
||||||
// ...and also a direct component.
|
// ...and also a direct component.
|
||||||
impl !Marker2 for dyn Object + Marker2 {} //~ ERROR E0371
|
impl !Marker2 for dyn Object + Marker2 {} //~ ERROR E0371
|
||||||
|
//~^ ERROR 0321
|
||||||
// But implementing a marker if it is not present is OK.
|
|
||||||
impl !Marker2 for dyn Object {} // OK
|
|
||||||
|
|
||||||
// A non-principal trait-object type is orphan even in its crate.
|
// A non-principal trait-object type is orphan even in its crate.
|
||||||
impl !Send for dyn Marker2 {} //~ ERROR E0117
|
impl !Send for dyn Marker2 {} //~ ERROR E0117
|
||||||
|
|
||||||
// And impl'ing a remote marker for a local trait object is forbidden
|
// Implementing a marker for a local trait object is forbidden by a special
|
||||||
// by one of these special orphan-like rules.
|
// orphan-like rule.
|
||||||
|
impl !Marker2 for dyn Object {} //~ ERROR E0321
|
||||||
impl !Send for dyn Object {} //~ ERROR E0321
|
impl !Send for dyn Object {} //~ ERROR E0321
|
||||||
impl !Send for dyn Object + Marker2 {} //~ ERROR E0321
|
impl !Send for dyn Object + Marker2 {} //~ ERROR E0321
|
||||||
|
|
||||||
|
// Blanket impl that applies to dyn Object is equally problematic.
|
||||||
|
auto trait Marker3 {}
|
||||||
|
impl<T: ?Sized> !Marker3 for T {} //~ ERROR E0321
|
||||||
|
|
||||||
|
auto trait Marker4 {}
|
||||||
|
impl<T> !Marker4 for T {} // okay
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -4,14 +4,38 @@ error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically i
|
||||||
LL | impl !Marker1 for dyn Object + Marker2 {}
|
LL | impl !Marker1 for dyn Object + Marker2 {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1`
|
||||||
|
|
||||||
|
error[E0321]: traits with a default impl, like `Marker1`, cannot be implemented for trait object `(dyn Object + Marker2 + 'static)`
|
||||||
|
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:15:1
|
||||||
|
|
|
||||||
|
LL | impl !Marker1 for dyn Object + Marker2 {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: a trait object implements `Marker1` if and only if `Marker1` is one of the trait object's trait bounds
|
||||||
|
|
||||||
error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker2`
|
error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker2`
|
||||||
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:17:1
|
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:18:1
|
||||||
|
|
|
|
||||||
LL | impl !Marker2 for dyn Object + Marker2 {}
|
LL | impl !Marker2 for dyn Object + Marker2 {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker2`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker2`
|
||||||
|
|
||||||
|
error[E0321]: traits with a default impl, like `Marker2`, cannot be implemented for trait object `(dyn Object + Marker2 + 'static)`
|
||||||
|
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:18:1
|
||||||
|
|
|
||||||
|
LL | impl !Marker2 for dyn Object + Marker2 {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: a trait object implements `Marker2` if and only if `Marker2` is one of the trait object's trait bounds
|
||||||
|
|
||||||
|
error[E0321]: traits with a default impl, like `Marker2`, cannot be implemented for trait object `(dyn Object + 'static)`
|
||||||
|
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:26:1
|
||||||
|
|
|
||||||
|
LL | impl !Marker2 for dyn Object {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: a trait object implements `Marker2` if and only if `Marker2` is one of the trait object's trait bounds
|
||||||
|
|
||||||
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
|
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
|
||||||
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:23:1
|
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:22:1
|
||||||
|
|
|
|
||||||
LL | impl !Send for dyn Marker2 {}
|
LL | impl !Send for dyn Marker2 {}
|
||||||
| ^^^^^^^^^^^^^^^-----------
|
| ^^^^^^^^^^^^^^^-----------
|
||||||
|
@ -33,7 +57,15 @@ error[E0321]: cross-crate traits with a default impl, like `Send`, can only be i
|
||||||
LL | impl !Send for dyn Object + Marker2 {}
|
LL | impl !Send for dyn Object + Marker2 {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type
|
||||||
|
|
||||||
error: aborting due to 5 previous errors
|
error[E0321]: traits with a default impl, like `Marker3`, cannot be implemented for generic type `T`
|
||||||
|
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:32:1
|
||||||
|
|
|
||||||
|
LL | impl<T: ?Sized> !Marker3 for T {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: a trait object implements `Marker3` if and only if `Marker3` is one of the trait object's trait bounds
|
||||||
|
|
||||||
|
error: aborting due to 9 previous errors
|
||||||
|
|
||||||
Some errors have detailed explanations: E0117, E0321, E0371.
|
Some errors have detailed explanations: E0117, E0321, E0371.
|
||||||
For more information about an error, try `rustc --explain E0117`.
|
For more information about an error, try `rustc --explain E0117`.
|
||||||
|
|
|
@ -13,18 +13,25 @@ trait Object: Marker1 {}
|
||||||
|
|
||||||
// A supertrait marker is illegal...
|
// A supertrait marker is illegal...
|
||||||
impl Marker1 for dyn Object + Marker2 {} //~ ERROR E0371
|
impl Marker1 for dyn Object + Marker2 {} //~ ERROR E0371
|
||||||
|
//~^ ERROR E0321
|
||||||
// ...and also a direct component.
|
// ...and also a direct component.
|
||||||
impl Marker2 for dyn Object + Marker2 {} //~ ERROR E0371
|
impl Marker2 for dyn Object + Marker2 {} //~ ERROR E0371
|
||||||
|
//~^ ERROR E0321
|
||||||
// But implementing a marker if it is not present is OK.
|
|
||||||
impl Marker2 for dyn Object {} // OK
|
|
||||||
|
|
||||||
// A non-principal trait-object type is orphan even in its crate.
|
// A non-principal trait-object type is orphan even in its crate.
|
||||||
unsafe impl Send for dyn Marker2 {} //~ ERROR E0117
|
unsafe impl Send for dyn Marker2 {} //~ ERROR E0117
|
||||||
|
|
||||||
// And impl'ing a remote marker for a local trait object is forbidden
|
// Implementing a marker for a local trait object is forbidden by a special
|
||||||
// by one of these special orphan-like rules.
|
// orphan-like rule.
|
||||||
|
impl Marker2 for dyn Object {} //~ ERROR E0321
|
||||||
unsafe impl Send for dyn Object {} //~ ERROR E0321
|
unsafe impl Send for dyn Object {} //~ ERROR E0321
|
||||||
unsafe impl Send for dyn Object + Marker2 {} //~ ERROR E0321
|
unsafe impl Send for dyn Object + Marker2 {} //~ ERROR E0321
|
||||||
|
|
||||||
|
// Blanket impl that applies to dyn Object is equally problematic.
|
||||||
|
auto trait Marker3 {}
|
||||||
|
impl<T: ?Sized> Marker3 for T {} //~ ERROR E0321
|
||||||
|
|
||||||
|
auto trait Marker4 {}
|
||||||
|
impl<T> Marker4 for T {} // okay
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -4,14 +4,38 @@ error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically i
|
||||||
LL | impl Marker1 for dyn Object + Marker2 {}
|
LL | impl Marker1 for dyn Object + Marker2 {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1`
|
||||||
|
|
||||||
|
error[E0321]: traits with a default impl, like `Marker1`, cannot be implemented for trait object `(dyn Object + Marker2 + 'static)`
|
||||||
|
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:15:1
|
||||||
|
|
|
||||||
|
LL | impl Marker1 for dyn Object + Marker2 {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: a trait object implements `Marker1` if and only if `Marker1` is one of the trait object's trait bounds
|
||||||
|
|
||||||
error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker2`
|
error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker2`
|
||||||
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:17:1
|
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:18:1
|
||||||
|
|
|
|
||||||
LL | impl Marker2 for dyn Object + Marker2 {}
|
LL | impl Marker2 for dyn Object + Marker2 {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker2`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker2`
|
||||||
|
|
||||||
|
error[E0321]: traits with a default impl, like `Marker2`, cannot be implemented for trait object `(dyn Object + Marker2 + 'static)`
|
||||||
|
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:18:1
|
||||||
|
|
|
||||||
|
LL | impl Marker2 for dyn Object + Marker2 {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: a trait object implements `Marker2` if and only if `Marker2` is one of the trait object's trait bounds
|
||||||
|
|
||||||
|
error[E0321]: traits with a default impl, like `Marker2`, cannot be implemented for trait object `(dyn Object + 'static)`
|
||||||
|
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:26:1
|
||||||
|
|
|
||||||
|
LL | impl Marker2 for dyn Object {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: a trait object implements `Marker2` if and only if `Marker2` is one of the trait object's trait bounds
|
||||||
|
|
||||||
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
|
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
|
||||||
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:23:1
|
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:22:1
|
||||||
|
|
|
|
||||||
LL | unsafe impl Send for dyn Marker2 {}
|
LL | unsafe impl Send for dyn Marker2 {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^-----------
|
| ^^^^^^^^^^^^^^^^^^^^^-----------
|
||||||
|
@ -33,7 +57,15 @@ error[E0321]: cross-crate traits with a default impl, like `Send`, can only be i
|
||||||
LL | unsafe impl Send for dyn Object + Marker2 {}
|
LL | unsafe impl Send for dyn Object + Marker2 {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type
|
||||||
|
|
||||||
error: aborting due to 5 previous errors
|
error[E0321]: traits with a default impl, like `Marker3`, cannot be implemented for generic type `T`
|
||||||
|
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:32:1
|
||||||
|
|
|
||||||
|
LL | impl<T: ?Sized> Marker3 for T {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: a trait object implements `Marker3` if and only if `Marker3` is one of the trait object's trait bounds
|
||||||
|
|
||||||
|
error: aborting due to 9 previous errors
|
||||||
|
|
||||||
Some errors have detailed explanations: E0117, E0321, E0371.
|
Some errors have detailed explanations: E0117, E0321, E0371.
|
||||||
For more information about an error, try `rustc --explain E0117`.
|
For more information about an error, try `rustc --explain E0117`.
|
||||||
|
|
|
@ -39,7 +39,7 @@ note: ...which requires type-checking `cycle1`...
|
||||||
|
|
|
|
||||||
LL | send(cycle2().clone());
|
LL | send(cycle2().clone());
|
||||||
| ^^^^
|
| ^^^^
|
||||||
= note: ...which requires evaluating trait selection obligation `impl core::clone::Clone: core::marker::Send`...
|
= note: ...which requires evaluating trait selection obligation `cycle2::{opaque#0}: core::marker::Send`...
|
||||||
note: ...which requires computing type of `cycle2::{opaque#0}`...
|
note: ...which requires computing type of `cycle2::{opaque#0}`...
|
||||||
--> $DIR/auto-trait-leak.rs:19:16
|
--> $DIR/auto-trait-leak.rs:19:16
|
||||||
|
|
|
|
||||||
|
@ -80,7 +80,7 @@ note: ...which requires type-checking `cycle2`...
|
||||||
|
|
|
|
||||||
LL | send(cycle1().clone());
|
LL | send(cycle1().clone());
|
||||||
| ^^^^
|
| ^^^^
|
||||||
= note: ...which requires evaluating trait selection obligation `impl core::clone::Clone: core::marker::Send`...
|
= note: ...which requires evaluating trait selection obligation `cycle1::{opaque#0}: core::marker::Send`...
|
||||||
= note: ...which again requires computing type of `cycle1::{opaque#0}`, completing the cycle
|
= note: ...which again requires computing type of `cycle1::{opaque#0}`, completing the cycle
|
||||||
note: cycle used when checking item types in top-level module
|
note: cycle used when checking item types in top-level module
|
||||||
--> $DIR/auto-trait-leak.rs:1:1
|
--> $DIR/auto-trait-leak.rs:1:1
|
||||||
|
|
8
tests/ui/lint/unused/issue-96606.rs
Normal file
8
tests/ui/lint/unused/issue-96606.rs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#[deny(unused)]
|
||||||
|
fn main() {
|
||||||
|
let arr = [0; 10];
|
||||||
|
let _ = arr[(0)]; //~ ERROR unnecessary parentheses around index expression
|
||||||
|
let _ = arr[{0}]; //~ ERROR unnecessary braces around index expression
|
||||||
|
let _ = arr[1 + (0)];
|
||||||
|
let _ = arr[{ let x = 0; x }];
|
||||||
|
}
|
33
tests/ui/lint/unused/issue-96606.stderr
Normal file
33
tests/ui/lint/unused/issue-96606.stderr
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
error: unnecessary parentheses around index expression
|
||||||
|
--> $DIR/issue-96606.rs:4:17
|
||||||
|
|
|
||||||
|
LL | let _ = arr[(0)];
|
||||||
|
| ^ ^
|
||||||
|
|
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/issue-96606.rs:1:8
|
||||||
|
|
|
||||||
|
LL | #[deny(unused)]
|
||||||
|
| ^^^^^^
|
||||||
|
= note: `#[deny(unused_parens)]` implied by `#[deny(unused)]`
|
||||||
|
help: remove these parentheses
|
||||||
|
|
|
||||||
|
LL - let _ = arr[(0)];
|
||||||
|
LL + let _ = arr[0];
|
||||||
|
|
|
||||||
|
|
||||||
|
error: unnecessary braces around index expression
|
||||||
|
--> $DIR/issue-96606.rs:5:17
|
||||||
|
|
|
||||||
|
LL | let _ = arr[{0}];
|
||||||
|
| ^ ^
|
||||||
|
|
|
||||||
|
= note: `#[deny(unused_braces)]` implied by `#[deny(unused)]`
|
||||||
|
help: remove these braces
|
||||||
|
|
|
||||||
|
LL - let _ = arr[{0}];
|
||||||
|
LL + let _ = arr[0];
|
||||||
|
|
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
|
@ -209,8 +209,8 @@ note: ...which requires const checking `main::ff5`...
|
||||||
|
|
|
|
||||||
LL | const async unsafe extern "C" fn ff5() {}
|
LL | const async unsafe extern "C" fn ff5() {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
= note: ...which requires computing whether `impl core::future::future::Future<Output = ()>` is freeze...
|
= note: ...which requires computing whether `main::ff5::{opaque#0}` is freeze...
|
||||||
= note: ...which requires evaluating trait selection obligation `impl core::future::future::Future<Output = ()>: core::marker::Freeze`...
|
= note: ...which requires evaluating trait selection obligation `main::ff5::{opaque#0}: core::marker::Freeze`...
|
||||||
= note: ...which again requires computing type of `main::ff5::{opaque#0}`, completing the cycle
|
= note: ...which again requires computing type of `main::ff5::{opaque#0}`, completing the cycle
|
||||||
note: cycle used when checking item types in top-level module
|
note: cycle used when checking item types in top-level module
|
||||||
--> $DIR/fn-header-semantic-fail.rs:5:1
|
--> $DIR/fn-header-semantic-fail.rs:5:1
|
||||||
|
@ -245,8 +245,8 @@ note: ...which requires const checking `main::<impl at $DIR/fn-header-semantic-f
|
||||||
|
|
|
|
||||||
LL | const async unsafe extern "C" fn ft5() {}
|
LL | const async unsafe extern "C" fn ft5() {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
= note: ...which requires computing whether `impl core::future::future::Future<Output = ()>` is freeze...
|
= note: ...which requires computing whether `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 28:17>::ft5::{opaque#0}` is freeze...
|
||||||
= note: ...which requires evaluating trait selection obligation `impl core::future::future::Future<Output = ()>: core::marker::Freeze`...
|
= note: ...which requires evaluating trait selection obligation `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 28:17>::ft5::{opaque#0}: core::marker::Freeze`...
|
||||||
= note: ...which again requires computing type of `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 28:17>::ft5::{opaque#0}`, completing the cycle
|
= note: ...which again requires computing type of `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 28:17>::ft5::{opaque#0}`, completing the cycle
|
||||||
note: cycle used when checking item types in top-level module
|
note: cycle used when checking item types in top-level module
|
||||||
--> $DIR/fn-header-semantic-fail.rs:5:1
|
--> $DIR/fn-header-semantic-fail.rs:5:1
|
||||||
|
@ -281,8 +281,8 @@ note: ...which requires const checking `main::<impl at $DIR/fn-header-semantic-f
|
||||||
|
|
|
|
||||||
LL | const async unsafe extern "C" fn fi5() {}
|
LL | const async unsafe extern "C" fn fi5() {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
= note: ...which requires computing whether `impl core::future::future::Future<Output = ()>` is freeze...
|
= note: ...which requires computing whether `main::<impl at $DIR/fn-header-semantic-fail.rs:40:5: 40:11>::fi5::{opaque#0}` is freeze...
|
||||||
= note: ...which requires evaluating trait selection obligation `impl core::future::future::Future<Output = ()>: core::marker::Freeze`...
|
= note: ...which requires evaluating trait selection obligation `main::<impl at $DIR/fn-header-semantic-fail.rs:40:5: 40:11>::fi5::{opaque#0}: core::marker::Freeze`...
|
||||||
= note: ...which again requires computing type of `main::<impl at $DIR/fn-header-semantic-fail.rs:40:5: 40:11>::fi5::{opaque#0}`, completing the cycle
|
= note: ...which again requires computing type of `main::<impl at $DIR/fn-header-semantic-fail.rs:40:5: 40:11>::fi5::{opaque#0}`, completing the cycle
|
||||||
note: cycle used when checking item types in top-level module
|
note: cycle used when checking item types in top-level module
|
||||||
--> $DIR/fn-header-semantic-fail.rs:5:1
|
--> $DIR/fn-header-semantic-fail.rs:5:1
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
fn a() -> _ {
|
||||||
|
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
|
||||||
|
&a
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,9 @@
|
||||||
|
error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
|
||||||
|
--> $DIR/no-query-in-printing-during-query-descr.rs:1:11
|
||||||
|
|
|
||||||
|
LL | fn a() -> _ {
|
||||||
|
| ^ not allowed in type signatures
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0121`.
|
18
tests/ui/typeck/issue-89856.fixed
Normal file
18
tests/ui/typeck/issue-89856.fixed
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
fn take_str_maybe(_: Option<&str>) { }
|
||||||
|
fn main() {
|
||||||
|
let string = String::from("Hello, world");
|
||||||
|
|
||||||
|
let option: Option<String> = Some(string.clone());
|
||||||
|
take_str_maybe(option.as_deref());
|
||||||
|
//~^ ERROR: mismatched types [E0308]
|
||||||
|
|
||||||
|
let option_ref = Some(&string);
|
||||||
|
take_str_maybe(option_ref.map(|x| x.as_str()));
|
||||||
|
//~^ ERROR: mismatched types [E0308]
|
||||||
|
|
||||||
|
let option_ref_ref = option_ref.as_ref();
|
||||||
|
take_str_maybe(option_ref_ref.map(|x| x.as_str()));
|
||||||
|
//~^ ERROR: mismatched types [E0308]
|
||||||
|
}
|
|
@ -1,8 +1,18 @@
|
||||||
fn take_str_maybe(x: Option<&str>) -> Option<&str> { None }
|
// run-rustfix
|
||||||
|
|
||||||
|
fn take_str_maybe(_: Option<&str>) { }
|
||||||
fn main() {
|
fn main() {
|
||||||
let string = String::from("Hello, world");
|
let string = String::from("Hello, world");
|
||||||
let option = Some(&string);
|
|
||||||
|
let option: Option<String> = Some(string.clone());
|
||||||
take_str_maybe(option);
|
take_str_maybe(option);
|
||||||
//~^ ERROR: mismatched types [E0308]
|
//~^ ERROR: mismatched types [E0308]
|
||||||
|
|
||||||
|
let option_ref = Some(&string);
|
||||||
|
take_str_maybe(option_ref);
|
||||||
|
//~^ ERROR: mismatched types [E0308]
|
||||||
|
|
||||||
|
let option_ref_ref = option_ref.as_ref();
|
||||||
|
take_str_maybe(option_ref_ref);
|
||||||
|
//~^ ERROR: mismatched types [E0308]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,63 @@
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/issue-89856.rs:6:20
|
--> $DIR/issue-89856.rs:8:20
|
||||||
|
|
|
|
||||||
LL | take_str_maybe(option);
|
LL | take_str_maybe(option);
|
||||||
| -------------- ^^^^^^ expected `Option<&str>`, found `Option<&String>`
|
| -------------- ^^^^^^ expected `Option<&str>`, found `Option<String>`
|
||||||
|
| |
|
||||||
|
| arguments to this function are incorrect
|
||||||
|
|
|
||||||
|
= note: expected enum `Option<&str>`
|
||||||
|
found enum `Option<String>`
|
||||||
|
note: function defined here
|
||||||
|
--> $DIR/issue-89856.rs:3:4
|
||||||
|
|
|
||||||
|
LL | fn take_str_maybe(_: Option<&str>) { }
|
||||||
|
| ^^^^^^^^^^^^^^ ---------------
|
||||||
|
help: try converting the passed type into a `&str`
|
||||||
|
|
|
||||||
|
LL | take_str_maybe(option.as_deref());
|
||||||
|
| +++++++++++
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/issue-89856.rs:12:20
|
||||||
|
|
|
||||||
|
LL | take_str_maybe(option_ref);
|
||||||
|
| -------------- ^^^^^^^^^^ expected `Option<&str>`, found `Option<&String>`
|
||||||
| |
|
| |
|
||||||
| arguments to this function are incorrect
|
| arguments to this function are incorrect
|
||||||
|
|
|
|
||||||
= note: expected enum `Option<&str>`
|
= note: expected enum `Option<&str>`
|
||||||
found enum `Option<&String>`
|
found enum `Option<&String>`
|
||||||
note: function defined here
|
note: function defined here
|
||||||
--> $DIR/issue-89856.rs:1:4
|
--> $DIR/issue-89856.rs:3:4
|
||||||
|
|
|
|
||||||
LL | fn take_str_maybe(x: Option<&str>) -> Option<&str> { None }
|
LL | fn take_str_maybe(_: Option<&str>) { }
|
||||||
| ^^^^^^^^^^^^^^ ---------------
|
| ^^^^^^^^^^^^^^ ---------------
|
||||||
help: try converting the passed type into a `&str`
|
help: try converting the passed type into a `&str`
|
||||||
|
|
|
|
||||||
LL | take_str_maybe(option.map(|x| &**x));
|
LL | take_str_maybe(option_ref.map(|x| x.as_str()));
|
||||||
| ++++++++++++++
|
| ++++++++++++++++++++
|
||||||
|
|
||||||
error: aborting due to previous error
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/issue-89856.rs:16:20
|
||||||
|
|
|
||||||
|
LL | take_str_maybe(option_ref_ref);
|
||||||
|
| -------------- ^^^^^^^^^^^^^^ expected `Option<&str>`, found `Option<&&String>`
|
||||||
|
| |
|
||||||
|
| arguments to this function are incorrect
|
||||||
|
|
|
||||||
|
= note: expected enum `Option<&str>`
|
||||||
|
found enum `Option<&&String>`
|
||||||
|
note: function defined here
|
||||||
|
--> $DIR/issue-89856.rs:3:4
|
||||||
|
|
|
||||||
|
LL | fn take_str_maybe(_: Option<&str>) { }
|
||||||
|
| ^^^^^^^^^^^^^^ ---------------
|
||||||
|
help: try converting the passed type into a `&str`
|
||||||
|
|
|
||||||
|
LL | take_str_maybe(option_ref_ref.map(|x| x.as_str()));
|
||||||
|
| ++++++++++++++++++++
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0308`.
|
For more information about this error, try `rustc --explain E0308`.
|
||||||
|
|
23
tests/ui/where-clauses/self-in-where-clause-allowed.rs
Normal file
23
tests/ui/where-clauses/self-in-where-clause-allowed.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
// check-fail
|
||||||
|
|
||||||
|
#![feature(auto_traits)]
|
||||||
|
#![deny(where_clauses_object_safety)]
|
||||||
|
|
||||||
|
auto trait AutoTrait {}
|
||||||
|
|
||||||
|
trait Trait {
|
||||||
|
fn static_lifetime_bound(&self) where Self: 'static {}
|
||||||
|
|
||||||
|
fn arg_lifetime_bound<'a>(&self, _arg: &'a ()) where Self: 'a {}
|
||||||
|
|
||||||
|
fn autotrait_bound(&self) where Self: AutoTrait {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Trait for () {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let trait_object = &() as &dyn Trait;
|
||||||
|
trait_object.static_lifetime_bound();
|
||||||
|
trait_object.arg_lifetime_bound(&());
|
||||||
|
trait_object.autotrait_bound(); //~ ERROR: the trait bound `dyn Trait: AutoTrait` is not satisfied
|
||||||
|
}
|
15
tests/ui/where-clauses/self-in-where-clause-allowed.stderr
Normal file
15
tests/ui/where-clauses/self-in-where-clause-allowed.stderr
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
error[E0277]: the trait bound `dyn Trait: AutoTrait` is not satisfied
|
||||||
|
--> $DIR/self-in-where-clause-allowed.rs:22:18
|
||||||
|
|
|
||||||
|
LL | trait_object.autotrait_bound();
|
||||||
|
| ^^^^^^^^^^^^^^^ the trait `AutoTrait` is not implemented for `dyn Trait`
|
||||||
|
|
|
||||||
|
note: required by a bound in `Trait::autotrait_bound`
|
||||||
|
--> $DIR/self-in-where-clause-allowed.rs:13:43
|
||||||
|
|
|
||||||
|
LL | fn autotrait_bound(&self) where Self: AutoTrait {}
|
||||||
|
| ^^^^^^^^^ required by this bound in `Trait::autotrait_bound`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
Loading…
Add table
Add a link
Reference in a new issue