diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index cad5a87bb1346..0c4bcbf495a55 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -813,7 +813,7 @@ fn usage(verbose: bool, include_unstable_options: bool, nightly_build: bool) { } else { "\n --help -v Print the full set of options rustc accepts" }; - let at_path = if verbose && nightly_build { + let at_path = if verbose { " @path Read newline separated options from `path`\n" } else { "" diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 7f27325f7f96f..f5e9cc1efcc45 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -1074,13 +1074,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let last_expr_ty = self.node_ty(last_expr.hir_id); let needs_box = match (last_expr_ty.kind(), expected_ty.kind()) { + (ty::Opaque(last_def_id, _), ty::Opaque(exp_def_id, _)) + if last_def_id == exp_def_id => + { + StatementAsExpression::CorrectType + } (ty::Opaque(last_def_id, last_bounds), ty::Opaque(exp_def_id, exp_bounds)) => { debug!( "both opaque, likely future {:?} {:?} {:?} {:?}", last_def_id, last_bounds, exp_def_id, exp_bounds ); - let last_hir_id = self.tcx.hir().local_def_id_to_hir_id(last_def_id.expect_local()); - let exp_hir_id = self.tcx.hir().local_def_id_to_hir_id(exp_def_id.expect_local()); + + let (last_local_id, exp_local_id) = + match (last_def_id.as_local(), exp_def_id.as_local()) { + (Some(last_hir_id), Some(exp_hir_id)) => (last_hir_id, exp_hir_id), + (_, _) => return None, + }; + + let last_hir_id = self.tcx.hir().local_def_id_to_hir_id(last_local_id); + let exp_hir_id = self.tcx.hir().local_def_id_to_hir_id(exp_local_id); + match ( &self.tcx.hir().expect_item(last_hir_id).kind, &self.tcx.hir().expect_item(exp_hir_id).kind, diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index e736bf19e8f93..d1f9049c8fabb 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -251,8 +251,8 @@ pub struct Stdin { /// let mut buffer = String::new(); /// let stdin = io::stdin(); // We get `Stdin` here. /// { -/// let mut stdin_lock = stdin.lock(); // We get `StdinLock` here. -/// stdin_lock.read_to_string(&mut buffer)?; +/// let mut handle = stdin.lock(); // We get `StdinLock` here. +/// handle.read_to_string(&mut buffer)?; /// } // `StdinLock` is dropped here. /// Ok(()) /// } diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index d43378081ce58..711b0298565d7 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -29,6 +29,107 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { AutoTraitFinder { cx } } + fn generate_for_trait( + &mut self, + ty: Ty<'tcx>, + trait_def_id: DefId, + param_env: ty::ParamEnv<'tcx>, + param_env_def_id: DefId, + f: &auto_trait::AutoTraitFinder<'tcx>, + // If this is set, show only negative trait implementations, not positive ones. + discard_positive_impl: bool, + ) -> Option { + let tcx = self.cx.tcx; + let trait_ref = ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(ty, &[]) }; + if !self.cx.generated_synthetics.borrow_mut().insert((ty, trait_def_id)) { + debug!("get_auto_trait_impl_for({:?}): already generated, aborting", trait_ref); + return None; + } + + let result = f.find_auto_trait_generics(ty, param_env, trait_def_id, |infcx, info| { + let region_data = info.region_data; + + let names_map = tcx + .generics_of(param_env_def_id) + .params + .iter() + .filter_map(|param| match param.kind { + ty::GenericParamDefKind::Lifetime => Some(param.name), + _ => None, + }) + .map(|name| (name, Lifetime(name))) + .collect(); + let lifetime_predicates = Self::handle_lifetimes(®ion_data, &names_map); + let new_generics = self.param_env_to_generics( + infcx.tcx, + param_env_def_id, + info.full_user_env, + lifetime_predicates, + info.vid_to_region, + ); + + debug!( + "find_auto_trait_generics(param_env_def_id={:?}, trait_def_id={:?}): \ + finished with {:?}", + param_env_def_id, trait_def_id, new_generics + ); + + new_generics + }); + + let negative_polarity; + let new_generics = match result { + AutoTraitResult::PositiveImpl(new_generics) => { + negative_polarity = false; + if discard_positive_impl { + return None; + } + new_generics + } + AutoTraitResult::NegativeImpl => { + negative_polarity = true; + + // For negative impls, we use the generic params, but *not* the predicates, + // from the original type. Otherwise, the displayed impl appears to be a + // conditional negative impl, when it's really unconditional. + // + // For example, consider the struct Foo(*mut T). Using + // the original predicates in our impl would cause us to generate + // `impl !Send for Foo`, which makes it appear that Foo + // implements Send where T is not copy. + // + // Instead, we generate `impl !Send for Foo`, which better + // expresses the fact that `Foo` never implements `Send`, + // regardless of the choice of `T`. + let params = (tcx.generics_of(param_env_def_id), ty::GenericPredicates::default()) + .clean(self.cx) + .params; + + Generics { params, where_predicates: Vec::new() } + } + AutoTraitResult::ExplicitImpl => return None, + }; + + Some(Item { + source: Span::dummy(), + name: None, + attrs: Default::default(), + visibility: Inherited, + def_id: self.cx.next_def_id(param_env_def_id.krate), + kind: box ImplItem(Impl { + unsafety: hir::Unsafety::Normal, + generics: new_generics, + provided_trait_methods: Default::default(), + trait_: Some(trait_ref.clean(self.cx).get_trait_type().unwrap()), + for_: ty.clean(self.cx), + items: Vec::new(), + negative_polarity, + synthetic: true, + blanket_impl: None, + }), + }) + } + // FIXME(eddyb) figure out a better way to pass information about // parametrization of `ty` than `param_env_def_id`. crate fn get_auto_trait_impls(&mut self, ty: Ty<'tcx>, param_env_def_id: DefId) -> Vec { @@ -38,99 +139,22 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { debug!("get_auto_trait_impls({:?})", ty); let auto_traits: Vec<_> = self.cx.auto_traits.iter().cloned().collect(); - auto_traits + let mut auto_traits: Vec = auto_traits .into_iter() .filter_map(|trait_def_id| { - let trait_ref = - ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(ty, &[]) }; - if !self.cx.generated_synthetics.borrow_mut().insert((ty, trait_def_id)) { - debug!("get_auto_trait_impl_for({:?}): already generated, aborting", trait_ref); - return None; - } - - let result = - f.find_auto_trait_generics(ty, param_env, trait_def_id, |infcx, info| { - let region_data = info.region_data; - - let names_map = tcx - .generics_of(param_env_def_id) - .params - .iter() - .filter_map(|param| match param.kind { - ty::GenericParamDefKind::Lifetime => Some(param.name), - _ => None, - }) - .map(|name| (name, Lifetime(name))) - .collect(); - let lifetime_predicates = Self::handle_lifetimes(®ion_data, &names_map); - let new_generics = self.param_env_to_generics( - infcx.tcx, - param_env_def_id, - info.full_user_env, - lifetime_predicates, - info.vid_to_region, - ); - - debug!( - "find_auto_trait_generics(param_env_def_id={:?}, trait_def_id={:?}): \ - finished with {:?}", - param_env_def_id, trait_def_id, new_generics - ); - - new_generics - }); - - let negative_polarity; - let new_generics = match result { - AutoTraitResult::PositiveImpl(new_generics) => { - negative_polarity = false; - new_generics - } - AutoTraitResult::NegativeImpl => { - negative_polarity = true; - - // For negative impls, we use the generic params, but *not* the predicates, - // from the original type. Otherwise, the displayed impl appears to be a - // conditional negative impl, when it's really unconditional. - // - // For example, consider the struct Foo(*mut T). Using - // the original predicates in our impl would cause us to generate - // `impl !Send for Foo`, which makes it appear that Foo - // implements Send where T is not copy. - // - // Instead, we generate `impl !Send for Foo`, which better - // expresses the fact that `Foo` never implements `Send`, - // regardless of the choice of `T`. - let params = - (tcx.generics_of(param_env_def_id), ty::GenericPredicates::default()) - .clean(self.cx) - .params; - - Generics { params, where_predicates: Vec::new() } - } - AutoTraitResult::ExplicitImpl => return None, - }; - - Some(Item { - source: Span::dummy(), - name: None, - attrs: Default::default(), - visibility: Inherited, - def_id: self.cx.next_def_id(param_env_def_id.krate), - kind: box ImplItem(Impl { - unsafety: hir::Unsafety::Normal, - generics: new_generics, - provided_trait_methods: Default::default(), - trait_: Some(trait_ref.clean(self.cx).get_trait_type().unwrap()), - for_: ty.clean(self.cx), - items: Vec::new(), - negative_polarity, - synthetic: true, - blanket_impl: None, - }), - }) + self.generate_for_trait(ty, trait_def_id, param_env, param_env_def_id, &f, false) }) - .collect() + .collect(); + // We are only interested in case the type *doesn't* implement the Sized trait. + if !ty.is_sized(self.cx.tcx.at(rustc_span::DUMMY_SP), param_env) { + // In case `#![no_core]` is used, `sized_trait` returns nothing. + if let Some(item) = self.cx.tcx.lang_items().sized_trait().and_then(|sized_trait_did| { + self.generate_for_trait(ty, sized_trait_did, param_env, param_env_def_id, &f, true) + }) { + auto_traits.push(item); + } + } + auto_traits } fn get_lifetime(region: Region<'_>, names_map: &FxHashMap) -> Lifetime { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 4517eda9b333f..1c2d2ad626c5a 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -32,6 +32,7 @@ use std::{ }; use crate::clean; +use crate::clean::inline::build_external_trait; use crate::clean::{AttributesExt, MAX_DEF_IDX}; use crate::config::{Options as RustdocOptions, RenderOptions}; use crate::config::{OutputFormat, RenderInfo}; @@ -530,6 +531,16 @@ crate fn run_global_ctxt( module_trait_cache: RefCell::new(FxHashMap::default()), cache: Cache::default(), }; + + // Small hack to force the Sized trait to be present. + // + // Note that in case of `#![no_core]`, the trait is not available. + if let Some(sized_trait_did) = ctxt.tcx.lang_items().sized_trait() { + let mut sized_trait = build_external_trait(&mut ctxt, sized_trait_did); + sized_trait.is_auto = true; + ctxt.external_traits.borrow_mut().insert(sized_trait_did, sized_trait); + } + debug!("crate: {:?}", tcx.hir().krate()); let mut krate = tcx.sess.time("clean_crate", || clean::krate(&mut ctxt)); diff --git a/src/test/rustdoc/sized_trait.rs b/src/test/rustdoc/sized_trait.rs new file mode 100644 index 0000000000000..26d12817afca1 --- /dev/null +++ b/src/test/rustdoc/sized_trait.rs @@ -0,0 +1,17 @@ +#![crate_name = "foo"] + +// @has foo/struct.Bar.html +// @!has - '//h3[@id="impl-Sized"]' +pub struct Bar { + a: u16, +} + +// @has foo/struct.Foo.html +// @!has - '//h3[@id="impl-Sized"]' +pub struct Foo(T); + +// @has foo/struct.Unsized.html +// @has - '//h3[@id="impl-Sized"]/code' 'impl !Sized for Unsized' +pub struct Unsized { + data: [u8], +} diff --git a/src/test/ui/suggestions/auxiliary/issue-81839.rs b/src/test/ui/suggestions/auxiliary/issue-81839.rs new file mode 100644 index 0000000000000..5683c45adf26d --- /dev/null +++ b/src/test/ui/suggestions/auxiliary/issue-81839.rs @@ -0,0 +1,9 @@ +// edition:2018 + +pub struct Test {} + +impl Test { + pub async fn answer_str(&self, _s: &str) -> Test { + Test {} + } +} diff --git a/src/test/ui/suggestions/issue-81839.rs b/src/test/ui/suggestions/issue-81839.rs new file mode 100644 index 0000000000000..0b9b7aefe735d --- /dev/null +++ b/src/test/ui/suggestions/issue-81839.rs @@ -0,0 +1,17 @@ +// aux-build:issue-81839.rs +// edition:2018 + +extern crate issue_81839; + +async fn test(ans: &str, num: i32, cx: &issue_81839::Test) -> u32 { + match num { + 1 => { + cx.answer_str("hi"); + } + _ => cx.answer_str("hi"), //~ `match` arms have incompatible types + } + + 1 +} + +fn main() {} diff --git a/src/test/ui/suggestions/issue-81839.stderr b/src/test/ui/suggestions/issue-81839.stderr new file mode 100644 index 0000000000000..1a289d39e4467 --- /dev/null +++ b/src/test/ui/suggestions/issue-81839.stderr @@ -0,0 +1,27 @@ +error[E0308]: `match` arms have incompatible types + --> $DIR/issue-81839.rs:11:14 + | +LL | / match num { +LL | | 1 => { +LL | | cx.answer_str("hi"); + | | -------------------- + | | | | + | | | help: consider removing this semicolon + | | this is found to be of type `()` +LL | | } +LL | | _ => cx.answer_str("hi"), + | | ^^^^^^^^^^^^^^^^^^^ expected `()`, found opaque type +LL | | } + | |_____- `match` arms have incompatible types + | + ::: $DIR/auxiliary/issue-81839.rs:6:49 + | +LL | pub async fn answer_str(&self, _s: &str) -> Test { + | ---- the `Output` of this `async fn`'s found opaque type + | + = note: expected type `()` + found opaque type `impl Future` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr b/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr index e9803a78f94b3..fae0c498b440a 100644 --- a/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr +++ b/src/test/ui/suggestions/match-prev-arm-needing-semi.stderr @@ -24,13 +24,10 @@ help: consider `await`ing on the `Future` | LL | false => async_dummy().await, | ^^^^^^ -help: consider removing this semicolon and boxing the expressions - | -LL | Box::new(async_dummy()) -LL | -LL | } -LL | false => Box::new(async_dummy()), +help: consider removing this semicolon | +LL | async_dummy() + | -- error[E0308]: `match` arms have incompatible types --> $DIR/match-prev-arm-needing-semi.rs:39:18