diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 9b4872f5d9f7a..9e1971c9a945b 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -1499,8 +1499,8 @@ any high-order bits of `rhs` that would cause the shift to exceed the bitwidth o Note that this is *not* the same as a rotate-left; the RHS of a wrapping shift-left is restricted to the range of the type, rather than the bits shifted out of the LHS being returned to the other end. -The primitive integer types all implement a `rotate_left` function, which may be what you want -instead. +The primitive integer types all implement a `[`rotate_left`](#method.rotate_left) function, +which may be what you want instead. # Examples @@ -1531,8 +1531,8 @@ removes any high-order bits of `rhs` that would cause the shift to exceed the bi Note that this is *not* the same as a rotate-right; the RHS of a wrapping shift-right is restricted to the range of the type, rather than the bits shifted out of the LHS being returned to the other -end. The primitive integer types all implement a `rotate_right` function, which may be what you want -instead. +end. The primitive integer types all implement a [`rotate_right`](#method.rotate_right) function, +which may be what you want instead. # Examples @@ -3610,8 +3610,8 @@ Note that this is *not* the same as a rotate-left; the RHS of a wrapping shift-left is restricted to the range of the type, rather than the bits shifted out of the LHS being returned to the other end. The primitive integer -types all implement a `rotate_left` function, which may -be what you want instead. +types all implement a [`rotate_left`](#method.rotate_left) function, +which may be what you want instead. # Examples @@ -3644,8 +3644,8 @@ Note that this is *not* the same as a rotate-right; the RHS of a wrapping shift-right is restricted to the range of the type, rather than the bits shifted out of the LHS being returned to the other end. The primitive integer -types all implement a `rotate_right` function, which may -be what you want instead. +types all implement a [`rotate_right`](#method.rotate_right) function, +which may be what you want instead. # Examples diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 913ccf8e68089..6847b175e60eb 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -1138,6 +1138,16 @@ pub fn catch_fatal_errors R, R>(f: F) -> Result }) } +/// Variant of `catch_fatal_errors` for the `interface::Result` return type +/// that also computes the exit code. +pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 { + let result = catch_fatal_errors(f).and_then(|result| result); + match result { + Ok(()) => EXIT_SUCCESS, + Err(_) => EXIT_FAILURE, + } +} + lazy_static! { static ref DEFAULT_HOOK: Box) + Sync + Send + 'static> = { let hook = panic::take_hook(); @@ -1228,12 +1238,12 @@ pub fn init_rustc_env_logger() { env_logger::init_from_env("RUSTC_LOG"); } -pub fn main() { +pub fn main() -> ! { let start = Instant::now(); init_rustc_env_logger(); let mut callbacks = TimePassesCallbacks::default(); install_ice_hook(); - let result = catch_fatal_errors(|| { + let exit_code = catch_with_exit_code(|| { let args = env::args_os() .enumerate() .map(|(i, arg)| { @@ -1246,13 +1256,8 @@ pub fn main() { }) .collect::>(); run_compiler(&args, &mut callbacks, None, None) - }) - .and_then(|result| result); - let exit_code = match result { - Ok(_) => EXIT_SUCCESS, - Err(_) => EXIT_FAILURE, - }; + }); // The extra `\t` is necessary to align this label with the others. print_time_passes_entry(callbacks.time_passes, "\ttotal", start.elapsed()); - process::exit(exit_code); + process::exit(exit_code) } diff --git a/src/librustc_expand/parse/lexer/tests.rs b/src/librustc_expand/parse/lexer/tests.rs index 2cb6267e0f6aa..2932475430bbf 100644 --- a/src/librustc_expand/parse/lexer/tests.rs +++ b/src/librustc_expand/parse/lexer/tests.rs @@ -50,13 +50,13 @@ fn t1() { assert_eq!(string_reader.next_token(), token::Whitespace); // Read another token. let tok3 = string_reader.next_token(); - assert_eq!(string_reader.pos.clone(), BytePos(28)); + assert_eq!(string_reader.pos(), BytePos(28)); let tok4 = Token::new(mk_ident("main"), Span::with_root_ctxt(BytePos(24), BytePos(28))); assert_eq!(tok3.kind, tok4.kind); assert_eq!(tok3.span, tok4.span); assert_eq!(string_reader.next_token(), token::OpenDelim(token::Paren)); - assert_eq!(string_reader.pos.clone(), BytePos(29)) + assert_eq!(string_reader.pos(), BytePos(29)) }) } diff --git a/src/librustc_middle/hir/map/mod.rs b/src/librustc_middle/hir/map/mod.rs index de0373c138497..b823516d64f3b 100644 --- a/src/librustc_middle/hir/map/mod.rs +++ b/src/librustc_middle/hir/map/mod.rs @@ -390,11 +390,7 @@ impl<'hir> Map<'hir> { /// Given a `HirId`, returns the `BodyId` associated with it, /// if the node is a body owner, otherwise returns `None`. pub fn maybe_body_owned_by(&self, hir_id: HirId) -> Option { - if let Some(node) = self.find(hir_id) { - associated_body(node) - } else { - bug!("no entry for id `{}`", hir_id) - } + self.find(hir_id).map(associated_body).flatten() } /// Given a body owner's id, returns the `BodyId` associated with it. diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs index 2ceba51949420..13cf9a934b72c 100644 --- a/src/librustc_middle/query/mod.rs +++ b/src/librustc_middle/query/mod.rs @@ -1164,6 +1164,12 @@ rustc_queries! { desc { "evaluating trait selection obligation `{}`", goal.value } } + query type_implements_trait( + key: (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>, ) + ) -> bool { + desc { "evaluating `type_implements_trait` `{:?}`", key } + } + /// Do not call this query directly: part of the `Eq` type-op query type_op_ascribe_user_type( goal: CanonicalTypeOpAscribeUserTypeGoal<'tcx> diff --git a/src/librustc_middle/ty/query/keys.rs b/src/librustc_middle/ty/query/keys.rs index 239691dbd17ac..4acf766f033d8 100644 --- a/src/librustc_middle/ty/query/keys.rs +++ b/src/librustc_middle/ty/query/keys.rs @@ -295,3 +295,15 @@ impl Key for (Symbol, u32, u32) { DUMMY_SP } } + +impl<'tcx> Key for (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>) { + type CacheSelector = DefaultCacheSelector; + + fn query_crate(&self) -> CrateNum { + LOCAL_CRATE + } + + fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { + DUMMY_SP + } +} diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index e898f22ec230d..bdf2193c6af45 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -616,6 +616,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { value: OpTy<'tcx>, source_info: SourceInfo, ) { + if let Rvalue::Use(Operand::Constant(c)) = rval { + if !matches!(c.literal.val, ConstKind::Unevaluated(..)) { + trace!("skipping replace of Rvalue::Use({:?} because it is already a const", c); + return; + } + } + trace!("attepting to replace {:?} with {:?}", rval, value); if let Err(e) = self.ecx.const_validate_operand( value, diff --git a/src/librustc_parse/lexer/mod.rs b/src/librustc_parse/lexer/mod.rs index f676a34a1d12b..aa048d682c2da 100644 --- a/src/librustc_parse/lexer/mod.rs +++ b/src/librustc_parse/lexer/mod.rs @@ -31,8 +31,7 @@ pub struct StringReader<'a> { /// Initial position, read-only. start_pos: BytePos, /// The absolute offset within the source_map of the current character. - // FIXME(#64197): `pub` is needed by tests for now. - pub pos: BytePos, + pos: BytePos, /// Stop reading src at this index. end_src_index: usize, /// Source text to tokenize. @@ -436,6 +435,10 @@ impl<'a> StringReader<'a> { } } + pub fn pos(&self) -> BytePos { + self.pos + } + #[inline] fn src_index(&self, pos: BytePos) -> usize { (pos - self.start_pos).to_usize() diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index 5a63a693652ea..6bd4455e1e3fd 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -402,6 +402,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { self.suggest_remove_reference(&obligation, &mut err, &trait_ref); self.suggest_semicolon_removal(&obligation, &mut err, span, &trait_ref); self.note_version_mismatch(&mut err, &trait_ref); + self.suggest_await_before_try(&mut err, &obligation, &trait_ref, span); if self.suggest_impl_trait(&mut err, span, &obligation, &trait_ref) { err.emit(); return; diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index 5c4ba40bf38e3..503daf56b49e4 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -1,14 +1,17 @@ use super::{ EvaluationResult, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation, + SelectionContext, }; use crate::infer::InferCtxt; +use crate::traits::normalize_projection_type; use rustc_errors::{error_code, struct_span_err, Applicability, DiagnosticBuilder, Style}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; +use rustc_hir::lang_items; use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node}; use rustc_middle::ty::TypeckTables; use rustc_middle::ty::{ @@ -150,6 +153,15 @@ pub trait InferCtxtExt<'tcx> { T: fmt::Display; fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>); + + /// Suggest to await before try: future? => future.await? + fn suggest_await_before_try( + &self, + err: &mut DiagnosticBuilder<'_>, + obligation: &PredicateObligation<'tcx>, + trait_ref: &ty::Binder>, + span: Span, + ); } fn predicate_constraint(generics: &hir::Generics<'_>, pred: String) -> (Span, String) { @@ -1822,6 +1834,95 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { suggested_limit, self.tcx.crate_name, )); } + + fn suggest_await_before_try( + &self, + err: &mut DiagnosticBuilder<'_>, + obligation: &PredicateObligation<'tcx>, + trait_ref: &ty::Binder>, + span: Span, + ) { + debug!( + "suggest_await_befor_try: obligation={:?}, span={:?}, trait_ref={:?}, trait_ref_self_ty={:?}", + obligation, + span, + trait_ref, + trait_ref.self_ty() + ); + let body_hir_id = obligation.cause.body_id; + let item_id = self.tcx.hir().get_parent_node(body_hir_id); + + if let Some(body_id) = self.tcx.hir().maybe_body_owned_by(item_id) { + let body = self.tcx.hir().body(body_id); + if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind { + let future_trait = + self.tcx.require_lang_item(lang_items::FutureTraitLangItem, None); + + let self_ty = self.resolve_vars_if_possible(&trait_ref.self_ty()); + + let impls_future = self.tcx.type_implements_trait(( + future_trait, + self_ty, + ty::List::empty(), + obligation.param_env, + )); + + let item_def_id = self + .tcx + .associated_items(future_trait) + .in_definition_order() + .next() + .unwrap() + .def_id; + // `::Output` + let projection_ty = ty::ProjectionTy { + // `T` + substs: self.tcx.mk_substs_trait( + trait_ref.self_ty(), + self.fresh_substs_for_item(span, item_def_id), + ), + // `Future::Output` + item_def_id, + }; + + let mut selcx = SelectionContext::new(self); + + let mut obligations = vec![]; + let normalized_ty = normalize_projection_type( + &mut selcx, + obligation.param_env, + projection_ty, + obligation.cause.clone(), + 0, + &mut obligations, + ); + + debug!( + "suggest_await_befor_try: normalized_projection_type {:?}", + self.resolve_vars_if_possible(&normalized_ty) + ); + let try_obligation = self.mk_obligation_for_def_id( + trait_ref.def_id(), + normalized_ty, + obligation.cause.clone(), + obligation.param_env, + ); + debug!("suggest_await_befor_try: try_trait_obligation {:?}", try_obligation); + if self.predicate_may_hold(&try_obligation) && impls_future { + if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { + if snippet.ends_with('?') { + err.span_suggestion( + span, + "consider using `.await` here", + format!("{}.await?", snippet.trim_end_matches('?')), + Applicability::MaybeIncorrect, + ); + } + } + } + } + } + } } /// Collect all the returned expressions within the input expression. diff --git a/src/librustc_trait_selection/traits/mod.rs b/src/librustc_trait_selection/traits/mod.rs index 778430fc2ca9c..9592f93ce2e76 100644 --- a/src/librustc_trait_selection/traits/mod.rs +++ b/src/librustc_trait_selection/traits/mod.rs @@ -31,7 +31,9 @@ use rustc_hir::def_id::DefId; use rustc_middle::middle::region; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; -use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, WithConstness}; +use rustc_middle::ty::{ + self, GenericParamDefKind, ParamEnv, ToPredicate, Ty, TyCtxt, WithConstness, +}; use rustc_span::Span; use std::fmt::Debug; @@ -523,6 +525,43 @@ fn vtable_methods<'tcx>( })) } +/// Check whether a `ty` implements given trait(trait_def_id). +/// +/// NOTE: Always return `false` for a type which needs inference. +fn type_implements_trait<'tcx>( + tcx: TyCtxt<'tcx>, + key: ( + DefId, // trait_def_id, + Ty<'tcx>, // type + SubstsRef<'tcx>, + ParamEnv<'tcx>, + ), +) -> bool { + let (trait_def_id, ty, params, param_env) = key; + + debug!( + "type_implements_trait: trait_def_id={:?}, type={:?}, params={:?}, param_env={:?}", + trait_def_id, ty, params, param_env + ); + + // Do not check on infer_types to avoid panic in evaluate_obligation. + if ty.has_infer_types() { + return false; + } + + let ty = tcx.erase_regions(&ty); + + let trait_ref = ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(ty, params) }; + + let obligation = Obligation { + cause: ObligationCause::dummy(), + param_env, + recursion_depth: 0, + predicate: trait_ref.without_const().to_predicate(), + }; + tcx.infer_ctxt().enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation)) +} + pub fn provide(providers: &mut ty::query::Providers<'_>) { object_safety::provide(providers); *providers = ty::query::Providers { @@ -531,6 +570,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { codegen_fulfill_obligation: codegen::codegen_fulfill_obligation, vtable_methods, substitute_normalize_and_test_predicates, + type_implements_trait, ..*providers }; } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 79dde84b8b1bc..226c187e3cfdf 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5282,6 +5282,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, found: Ty<'tcx>, ) { + debug!("suggest_missing_await: expr={:?} expected={:?}, found={:?}", expr, expected, found); // `.await` is not permitted outside of `async` bodies, so don't bother to suggest if the // body isn't `async`. let item_id = self.tcx().hir().get_parent_node(self.body_id); @@ -5299,22 +5300,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .next() .unwrap() .def_id; + // `::Output` + let projection_ty = ty::ProjectionTy { + // `T` + substs: self + .tcx + .mk_substs_trait(found, self.fresh_substs_for_item(sp, item_def_id)), + // `Future::Output` + item_def_id, + }; + let predicate = ty::Predicate::Projection(ty::Binder::bind(ty::ProjectionPredicate { - // `::Output` - projection_ty: ty::ProjectionTy { - // `T` - substs: self.tcx.mk_substs_trait( - found, - self.fresh_substs_for_item(sp, item_def_id), - ), - // `Future::Output` - item_def_id, - }, + projection_ty, ty: expected, })); let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate); + debug!("suggest_missing_await: trying obligation {:?}", obligation); + if self.infcx.predicate_may_hold(&obligation) { debug!("suggest_missing_await: obligation held: {:?}", obligation); if let Ok(code) = self.sess().source_map().span_to_snippet(sp) { diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 8bf811877a6a8..381238165274d 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -643,6 +643,15 @@ impl Attributes { }) .collect() } + + pub fn get_doc_aliases(&self) -> FxHashSet { + self.other_attrs + .lists(sym::doc) + .filter(|a| a.check_name(sym::alias)) + .filter_map(|a| a.value_str().map(|s| s.to_string().replace("\"", ""))) + .filter(|v| !v.is_empty()) + .collect::>() + } } impl PartialEq for Attributes { diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 0922c8cdd1200..ea65b3905272e 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -114,7 +114,6 @@ pub fn render( window.rootPath = \"{root_path}\";\ window.currentCrate = \"{krate}\";\ \ - \ \ {static_extra_scripts}\ {extra_scripts}\ diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 00c9e46570a8f..646c663ad9ccd 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -293,7 +293,12 @@ impl Serialize for IndexItem { where S: Serializer, { - assert_eq!(self.parent.is_some(), self.parent_idx.is_some()); + assert_eq!( + self.parent.is_some(), + self.parent_idx.is_some(), + "`{}` is missing idx", + self.name + ); (self.ty, &self.name, &self.path, &self.desc, self.parent_idx, &self.search_type) .serialize(serializer) @@ -819,42 +824,6 @@ themePicker.onblur = handleThemeButtonsBlur; Ok((ret, krates)) } - fn show_item(item: &IndexItem, krate: &str) -> String { - format!( - "{{'crate':'{}','ty':{},'name':'{}','desc':'{}','p':'{}'{}}}", - krate, - item.ty as usize, - item.name, - item.desc.replace("'", "\\'"), - item.path, - if let Some(p) = item.parent_idx { format!(",'parent':{}", p) } else { String::new() } - ) - } - - let dst = cx.dst.join(&format!("aliases{}.js", cx.shared.resource_suffix)); - { - let (mut all_aliases, _) = try_err!(collect(&dst, &krate.name, "ALIASES"), &dst); - let mut output = String::with_capacity(100); - for (alias, items) in &cx.cache.aliases { - if items.is_empty() { - continue; - } - output.push_str(&format!( - "\"{}\":[{}],", - alias, - items.iter().map(|v| show_item(v, &krate.name)).collect::>().join(",") - )); - } - all_aliases.push(format!("ALIASES[\"{}\"] = {{{}}};", krate.name, output)); - all_aliases.sort(); - let mut v = Buffer::html(); - writeln!(&mut v, "var ALIASES = {{}};"); - for aliases in &all_aliases { - writeln!(&mut v, "{}", aliases); - } - cx.shared.fs.write(&dst, v.into_inner().into_bytes())?; - } - use std::ffi::OsString; #[derive(Debug)] diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs index 5b09029122718..57d385de32096 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/cache.rs @@ -120,7 +120,7 @@ crate struct Cache { /// Aliases added through `#[doc(alias = "...")]`. Since a few items can have the same alias, /// we need the alias element to have an array of items. - pub(super) aliases: FxHashMap>, + pub(super) aliases: BTreeMap>, } impl Cache { @@ -311,7 +311,7 @@ impl DocFolder for Cache { }; match parent { - (parent, Some(path)) if is_inherent_impl_item || (!self.stripped_mod) => { + (parent, Some(path)) if is_inherent_impl_item || !self.stripped_mod => { debug_assert!(!item.is_stripped()); // A crate has a module at its root, containing all items, @@ -327,6 +327,13 @@ impl DocFolder for Cache { parent_idx: None, search_type: get_index_search_type(&item), }); + + for alias in item.attrs.get_doc_aliases() { + self.aliases + .entry(alias.to_lowercase()) + .or_insert(Vec::new()) + .push(self.search_index.len() - 1); + } } } (Some(parent), None) if is_inherent_impl_item => { @@ -376,11 +383,8 @@ impl DocFolder for Cache { { self.paths.insert(item.def_id, (self.stack.clone(), item.type_())); } - self.add_aliases(&item); } - clean::PrimitiveItem(..) => { - self.add_aliases(&item); self.paths.insert(item.def_id, (self.stack.clone(), item.type_())); } @@ -488,40 +492,6 @@ impl DocFolder for Cache { } } -impl Cache { - fn add_aliases(&mut self, item: &clean::Item) { - if item.def_id.index == CRATE_DEF_INDEX { - return; - } - if let Some(ref item_name) = item.name { - let path = self - .paths - .get(&item.def_id) - .map(|p| p.0[..p.0.len() - 1].join("::")) - .unwrap_or("std".to_owned()); - for alias in item - .attrs - .lists(sym::doc) - .filter(|a| a.check_name(sym::alias)) - .filter_map(|a| a.value_str().map(|s| s.to_string().replace("\"", ""))) - .filter(|v| !v.is_empty()) - .collect::>() - .into_iter() - { - self.aliases.entry(alias).or_insert(Vec::with_capacity(1)).push(IndexItem { - ty: item.type_(), - name: item_name.to_string(), - path: path.clone(), - desc: shorten(plain_summary_line(item.doc_value())), - parent: None, - parent_idx: None, - search_type: get_index_search_type(&item), - }); - } - } - } -} - /// Attempts to find where an external crate is located, given that we're /// rendering in to the specified source destination. fn extern_location( @@ -567,7 +537,8 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { let mut crate_items = Vec::with_capacity(cache.search_index.len()); let mut crate_paths = vec![]; - let Cache { ref mut search_index, ref orphan_impl_items, ref paths, .. } = *cache; + let Cache { ref mut search_index, ref orphan_impl_items, ref paths, ref mut aliases, .. } = + *cache; // Attach all orphan items to the type's definition if the type // has since been learned. @@ -582,6 +553,12 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { parent_idx: None, search_type: get_index_search_type(&item), }); + for alias in item.attrs.get_doc_aliases() { + aliases + .entry(alias.to_lowercase()) + .or_insert(Vec::new()) + .push(search_index.len() - 1); + } } } @@ -630,6 +607,12 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { items: Vec<&'a IndexItem>, #[serde(rename = "p")] paths: Vec<(ItemType, String)>, + // The String is alias name and the vec is the list of the elements with this alias. + // + // To be noted: the `usize` elements are indexes to `items`. + #[serde(rename = "a")] + #[serde(skip_serializing_if = "BTreeMap::is_empty")] + aliases: &'a BTreeMap>, } // Collect the index into a string @@ -640,6 +623,7 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { doc: crate_doc, items: crate_items, paths: crate_paths, + aliases, }) .expect("failed serde conversion") // All these `replace` calls are because we have to go through JS string for JSON content. diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index a023d5a2d95f1..9b498d66249e2 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -531,6 +531,7 @@ function getSearchElement() { var OUTPUT_DATA = 1; var NO_TYPE_FILTER = -1; var currentResults, index, searchIndex; + var ALIASES = {}; var params = getQueryStringParams(); // Populate search bar with query string search term when provided, @@ -963,6 +964,72 @@ function getSearchElement() { return itemTypes[ty.ty] + ty.path + ty.name; } + function createAliasFromItem(item) { + return { + crate: item.crate, + name: item.name, + path: item.path, + desc: item.desc, + ty: item.ty, + parent: item.parent, + type: item.type, + is_alias: true, + }; + } + + function handleAliases(ret, query, filterCrates) { + // We separate aliases and crate aliases because we want to have current crate + // aliases to be before the others in the displayed results. + var aliases = []; + var crateAliases = []; + var i; + if (filterCrates !== undefined && + ALIASES[filterCrates] && + ALIASES[filterCrates][query.search]) { + for (i = 0; i < ALIASES[crate][query.search].length; ++i) { + aliases.push( + createAliasFromItem(searchIndex[ALIASES[filterCrates][query.search]])); + } + } else { + Object.keys(ALIASES).forEach(function(crate) { + if (ALIASES[crate][query.search]) { + var pushTo = crate === window.currentCrate ? crateAliases : aliases; + for (i = 0; i < ALIASES[crate][query.search].length; ++i) { + pushTo.push( + createAliasFromItem( + searchIndex[ALIASES[crate][query.search][i]])); + } + } + }); + } + + var sortFunc = function(aaa, bbb) { + if (aaa.path < bbb.path) { + return 1; + } else if (aaa.path === bbb.path) { + return 0; + } + return -1; + }; + crateAliases.sort(sortFunc); + aliases.sort(sortFunc); + + var pushFunc = function(alias) { + alias.alias = query.raw; + var res = buildHrefAndPath(alias); + alias.displayPath = pathSplitter(res[0]); + alias.fullPath = alias.displayPath + alias.name; + alias.href = res[1]; + + ret.others.unshift(alias); + if (ret.others.length > MAX_RESULTS) { + ret.others.pop(); + } + }; + onEach(aliases, pushFunc); + onEach(crateAliases, pushFunc); + } + // quoted values mean literal search var nSearchWords = searchWords.length; var i; @@ -1190,23 +1257,7 @@ function getSearchElement() { "returned": sortResults(results_returned, true), "others": sortResults(results), }; - if (ALIASES && ALIASES[window.currentCrate] && - ALIASES[window.currentCrate][query.raw]) { - var aliases = ALIASES[window.currentCrate][query.raw]; - for (i = 0; i < aliases.length; ++i) { - aliases[i].is_alias = true; - aliases[i].alias = query.raw; - aliases[i].path = aliases[i].p; - var res = buildHrefAndPath(aliases[i]); - aliases[i].displayPath = pathSplitter(res[0]); - aliases[i].fullPath = aliases[i].displayPath + aliases[i].name; - aliases[i].href = res[1]; - ret.others.unshift(aliases[i]); - if (ret.others.length > MAX_RESULTS) { - ret.others.pop(); - } - } - } + handleAliases(ret, query, filterCrates); return ret; } @@ -1599,13 +1650,12 @@ function getSearchElement() { "returned": mergeArrays(results.returned), "others": mergeArrays(results.others), }; - } else { - return { - "in_args": results.in_args[0], - "returned": results.returned[0], - "others": results.others[0], - }; } + return { + "in_args": results.in_args[0], + "returned": results.returned[0], + "others": results.others[0], + }; } function getFilterCrates() { @@ -1656,10 +1706,13 @@ function getSearchElement() { searchIndex = []; var searchWords = []; var i; + var currentIndex = 0; for (var crate in rawSearchIndex) { if (!rawSearchIndex.hasOwnProperty(crate)) { continue; } + var crateSize = 0; + searchWords.push(crate); searchIndex.push({ crate: crate, @@ -1669,6 +1722,7 @@ function getSearchElement() { desc: rawSearchIndex[crate].doc, type: null, }); + currentIndex += 1; // an array of [(Number) item type, // (String) name, @@ -1680,6 +1734,9 @@ function getSearchElement() { // an array of [(Number) item type, // (String) name] var paths = rawSearchIndex[crate].p; + // a array of [(String) alias name + // [Number] index to items] + var aliases = rawSearchIndex[crate].a; // convert `rawPaths` entries into object form var len = paths.length; @@ -1698,9 +1755,18 @@ function getSearchElement() { var lastPath = ""; for (i = 0; i < len; ++i) { var rawRow = items[i]; - var row = {crate: crate, ty: rawRow[0], name: rawRow[1], - path: rawRow[2] || lastPath, desc: rawRow[3], - parent: paths[rawRow[4]], type: rawRow[5]}; + if (!rawRow[2]) { + rawRow[2] = lastPath; + } + var row = { + crate: crate, + ty: rawRow[0], + name: rawRow[1], + path: rawRow[2], + desc: rawRow[3], + parent: paths[rawRow[4]], + type: rawRow[5], + }; searchIndex.push(row); if (typeof row.name === "string") { var word = row.name.toLowerCase(); @@ -1709,7 +1775,25 @@ function getSearchElement() { searchWords.push(""); } lastPath = row.path; + crateSize += 1; + } + + if (aliases) { + ALIASES[crate] = {}; + var j, local_aliases; + for (var alias_name in aliases) { + if (!aliases.hasOwnProperty(alias_name)) { continue; } + + if (!ALIASES[crate].hasOwnProperty(alias_name)) { + ALIASES[crate][alias_name] = []; + } + local_aliases = aliases[alias_name]; + for (j = 0; j < local_aliases.length; ++j) { + ALIASES[crate][alias_name].push(local_aliases[j] + currentIndex); + } + } } + currentIndex += crateSize; } return searchWords; } diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index e6da7426eb4af..56cf9be339194 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -251,6 +251,9 @@ impl HashMap { /// cause many collisions and very poor performance. Setting it /// manually using this function can expose a DoS attack vector. /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the HashMap to be useful, see its documentation for details. + /// /// # Examples /// /// ``` @@ -261,6 +264,8 @@ impl HashMap { /// let mut map = HashMap::with_hasher(s); /// map.insert(1, 2); /// ``` + /// + /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html #[inline] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] pub fn with_hasher(hash_builder: S) -> HashMap { @@ -278,6 +283,9 @@ impl HashMap { /// cause many collisions and very poor performance. Setting it /// manually using this function can expose a DoS attack vector. /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the HashMap to be useful, see its documentation for details. + /// /// # Examples /// /// ``` @@ -288,6 +296,8 @@ impl HashMap { /// let mut map = HashMap::with_capacity_and_hasher(10, s); /// map.insert(1, 2); /// ``` + /// + /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html #[inline] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> HashMap { diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index c1a57f2ce6129..ca06457291cae 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -273,6 +273,9 @@ impl HashSet { /// cause many collisions and very poor performance. Setting it /// manually using this function can expose a DoS attack vector. /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the HashMap to be useful, see its documentation for details. + /// /// # Examples /// /// ``` @@ -283,6 +286,8 @@ impl HashSet { /// let mut set = HashSet::with_hasher(s); /// set.insert(2); /// ``` + /// + /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html #[inline] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] pub fn with_hasher(hasher: S) -> HashSet { @@ -300,6 +305,9 @@ impl HashSet { /// cause many collisions and very poor performance. Setting it /// manually using this function can expose a DoS attack vector. /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the HashMap to be useful, see its documentation for details. + /// /// # Examples /// /// ``` @@ -310,6 +318,8 @@ impl HashSet { /// let mut set = HashSet::with_capacity_and_hasher(10, s); /// set.insert(1); /// ``` + /// + /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html #[inline] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashSet { diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 4fde33169733e..7a05aaf71f2c1 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -4,6 +4,7 @@ use crate::fmt; use crate::hash::{Hash, Hasher}; use crate::ops; use crate::rc::Rc; +use crate::str::FromStr; use crate::sync::Arc; use crate::sys::os_str::{Buf, Slice}; @@ -1174,6 +1175,15 @@ impl AsInner for OsStr { } } +#[stable(feature = "osstring_from_str", since = "1.45.0")] +impl FromStr for OsString { + type Err = core::convert::Infallible; + + fn from_str(s: &str) -> Result { + Ok(OsString::from(s)) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/test/mir-opt/const_prop/mutable_variable/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable/rustc.main.ConstProp.diff index c6c5b0cf72635..187c17454350a 100644 --- a/src/test/mir-opt/const_prop/mutable_variable/rustc.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/mutable_variable/rustc.main.ConstProp.diff @@ -26,8 +26,7 @@ // + ty: i32 // + val: Value(Scalar(0x00000063)) // mir::Constant -- // + span: $DIR/mutable_variable.rs:6:9: 6:11 -+ // + span: $DIR/mutable_variable.rs:6:5: 6:11 + // + span: $DIR/mutable_variable.rs:6:9: 6:11 // + literal: Const { ty: i32, val: Value(Scalar(0x00000063)) } StorageLive(_2); // scope 1 at $DIR/mutable_variable.rs:7:9: 7:10 - _2 = _1; // scope 1 at $DIR/mutable_variable.rs:7:13: 7:14 diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_aggregate/rustc.main.ConstProp.diff index 26f0250d94c0b..cf432b2acc1c5 100644 --- a/src/test/mir-opt/const_prop/mutable_variable_aggregate/rustc.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate/rustc.main.ConstProp.diff @@ -34,8 +34,7 @@ // + ty: i32 // + val: Value(Scalar(0x00000063)) // mir::Constant -- // + span: $DIR/mutable_variable_aggregate.rs:6:11: 6:13 -+ // + span: $DIR/mutable_variable_aggregate.rs:6:5: 6:13 + // + span: $DIR/mutable_variable_aggregate.rs:6:11: 6:13 // + literal: Const { ty: i32, val: Value(Scalar(0x00000063)) } StorageLive(_2); // scope 1 at $DIR/mutable_variable_aggregate.rs:7:9: 7:10 - _2 = _1; // scope 1 at $DIR/mutable_variable_aggregate.rs:7:13: 7:14 diff --git a/src/test/mir-opt/copy_propagation_arg/rustc.arg_src.CopyPropagation.diff b/src/test/mir-opt/copy_propagation_arg/rustc.arg_src.CopyPropagation.diff index b976449ca6d32..1e0271a560f65 100644 --- a/src/test/mir-opt/copy_propagation_arg/rustc.arg_src.CopyPropagation.diff +++ b/src/test/mir-opt/copy_propagation_arg/rustc.arg_src.CopyPropagation.diff @@ -17,7 +17,7 @@ // + ty: i32 // + val: Value(Scalar(0x0000007b)) // mir::Constant - // + span: $DIR/copy_propagation_arg.rs:29:5: 29:12 + // + span: $DIR/copy_propagation_arg.rs:29:9: 29:12 // + literal: Const { ty: i32, val: Value(Scalar(0x0000007b)) } _0 = _2; // scope 1 at $DIR/copy_propagation_arg.rs:30:5: 30:6 StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:31:1: 31:2 diff --git a/src/test/mir-opt/copy_propagation_arg/rustc.bar.CopyPropagation.diff b/src/test/mir-opt/copy_propagation_arg/rustc.bar.CopyPropagation.diff index 26f8068f674ef..b875bbea67bdf 100644 --- a/src/test/mir-opt/copy_propagation_arg/rustc.bar.CopyPropagation.diff +++ b/src/test/mir-opt/copy_propagation_arg/rustc.bar.CopyPropagation.diff @@ -28,7 +28,7 @@ // + ty: u8 // + val: Value(Scalar(0x05)) // mir::Constant - // + span: $DIR/copy_propagation_arg.rs:17:5: 17:10 + // + span: $DIR/copy_propagation_arg.rs:17:9: 17:10 // + literal: Const { ty: u8, val: Value(Scalar(0x05)) } _0 = const (); // scope 0 at $DIR/copy_propagation_arg.rs:15:19: 18:2 // ty::Const diff --git a/src/test/rustdoc-js-std/alias-2.js b/src/test/rustdoc-js-std/alias-2.js index f3c6713692b59..798fa29efbd2d 100644 --- a/src/test/rustdoc-js-std/alias-2.js +++ b/src/test/rustdoc-js-std/alias-2.js @@ -1,10 +1,10 @@ -// ignore-order - const QUERY = '+'; const EXPECTED = { 'others': [ { 'path': 'std::ops', 'name': 'AddAssign' }, { 'path': 'std::ops', 'name': 'Add' }, + { 'path': 'core::ops', 'name': 'AddAssign' }, + { 'path': 'core::ops', 'name': 'Add' }, ], }; diff --git a/src/test/rustdoc-js/doc-alias.js b/src/test/rustdoc-js/doc-alias.js new file mode 100644 index 0000000000000..896808d415780 --- /dev/null +++ b/src/test/rustdoc-js/doc-alias.js @@ -0,0 +1,263 @@ +// exact-check + +const QUERY = [ + 'StructItem', + 'StructFieldItem', + 'StructMethodItem', + 'ImplTraitItem', + 'ImplAssociatedConstItem', + 'ImplTraitFunction', + 'EnumItem', + 'VariantItem', + 'EnumMethodItem', + 'TypedefItem', + 'TraitItem', + 'TraitTypeItem', + 'AssociatedConstItem', + 'TraitFunctionItem', + 'FunctionItem', + 'ModuleItem', + 'ConstItem', + 'StaticItem', + 'UnionItem', + 'UnionFieldItem', + 'UnionMethodItem', + 'MacroItem', +]; + +const EXPECTED = [ + { + 'others': [ + { + 'path': 'doc_alias', + 'name': 'Struct', + 'alias': 'StructItem', + 'href': '../doc_alias/struct.Struct.html', + 'is_alias': true + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias::Struct', + 'name': 'field', + 'alias': 'StructFieldItem', + 'href': '../doc_alias/struct.Struct.html#structfield.field', + 'is_alias': true + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias::Struct', + 'name': 'method', + 'alias': 'StructMethodItem', + 'href': '../doc_alias/struct.Struct.html#method.method', + 'is_alias': true + }, + ], + }, + { + // ImplTraitItem + 'others': [], + }, + { + // ImplAssociatedConstItem + 'others': [], + }, + { + 'others': [ + { + 'path': 'doc_alias::Struct', + 'name': 'function', + 'alias': 'ImplTraitFunction', + 'href': '../doc_alias/struct.Struct.html#method.function', + 'is_alias': true + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias', + 'name': 'Enum', + 'alias': 'EnumItem', + 'href': '../doc_alias/enum.Enum.html', + 'is_alias': true + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias::Enum', + 'name': 'Variant', + 'alias': 'VariantItem', + 'href': '../doc_alias/enum.Enum.html#variant.Variant', + 'is_alias': true + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias::Enum', + 'name': 'method', + 'alias': 'EnumMethodItem', + 'href': '../doc_alias/enum.Enum.html#method.method', + 'is_alias': true + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias', + 'name': 'Typedef', + 'alias': 'TypedefItem', + 'href': '../doc_alias/type.Typedef.html', + 'is_alias': true + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias', + 'name': 'Trait', + 'alias': 'TraitItem', + 'href': '../doc_alias/trait.Trait.html', + 'is_alias': true + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias::Trait', + 'name': 'Target', + 'alias': 'TraitTypeItem', + 'href': '../doc_alias/trait.Trait.html#associatedtype.Target', + 'is_alias': true + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias::Trait', + 'name': 'AssociatedConst', + 'alias': 'AssociatedConstItem', + 'href': '../doc_alias/trait.Trait.html#associatedconstant.AssociatedConst', + 'is_alias': true + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias::Trait', + 'name': 'function', + 'alias': 'TraitFunctionItem', + 'href': '../doc_alias/trait.Trait.html#tymethod.function', + 'is_alias': true + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias', + 'name': 'function', + 'alias': 'FunctionItem', + 'href': '../doc_alias/fn.function.html', + 'is_alias': true + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias', + 'name': 'Module', + 'alias': 'ModuleItem', + 'href': '../doc_alias/Module/index.html', + 'is_alias': true + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias', + 'name': 'Const', + 'alias': 'ConstItem', + 'href': '../doc_alias/constant.Const.html', + 'is_alias': true + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias', + 'name': 'Static', + 'alias': 'StaticItem', + 'href': '../doc_alias/static.Static.html', + 'is_alias': true + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias', + 'name': 'Union', + 'alias': 'UnionItem', + 'href': '../doc_alias/union.Union.html', + 'is_alias': true + }, + // Not an alias! + { + 'path': 'doc_alias::Union', + 'name': 'union_item', + 'href': '../doc_alias/union.Union.html#structfield.union_item' + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias::Union', + 'name': 'union_item', + 'alias': 'UnionFieldItem', + 'href': '../doc_alias/union.Union.html#structfield.union_item', + 'is_alias': true + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias::Union', + 'name': 'method', + 'alias': 'UnionMethodItem', + 'href': '../doc_alias/union.Union.html#method.method', + 'is_alias': true + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias', + 'name': 'Macro', + 'alias': 'MacroItem', + 'href': '../doc_alias/macro.Macro.html', + 'is_alias': true + }, + ], + }, +]; diff --git a/src/test/rustdoc-js/doc-alias.rs b/src/test/rustdoc-js/doc-alias.rs new file mode 100644 index 0000000000000..84c638a199507 --- /dev/null +++ b/src/test/rustdoc-js/doc-alias.rs @@ -0,0 +1,79 @@ +#![feature(doc_alias)] + +#[doc(alias = "StructItem")] +pub struct Struct { + #[doc(alias = "StructFieldItem")] + pub field: u32, +} + +impl Struct { + #[doc(alias = "StructMethodItem")] + pub fn method(&self) {} +} + +impl Trait for Struct { + // Shouldn't be listed in aliases! + #[doc(alias = "ImplTraitItem")] + type Target = u32; + // Shouldn't be listed in aliases! + #[doc(alias = "ImplAssociatedConstItem")] + const AssociatedConst: i32 = 12; + + #[doc(alias = "ImplTraitFunction")] + fn function() -> Self::Target { 0 } +} + +#[doc(alias = "EnumItem")] +pub enum Enum { + #[doc(alias = "VariantItem")] + Variant, +} + +impl Enum { + #[doc(alias = "EnumMethodItem")] + pub fn method(&self) {} +} + +#[doc(alias = "TypedefItem")] +pub type Typedef = i32; + +#[doc(alias = "TraitItem")] +pub trait Trait { + #[doc(alias = "TraitTypeItem")] + type Target; + #[doc(alias = "AssociatedConstItem")] + const AssociatedConst: i32; + + #[doc(alias = "TraitFunctionItem")] + fn function() -> Self::Target; +} + +#[doc(alias = "FunctionItem")] +pub fn function() {} + +#[doc(alias = "ModuleItem")] +pub mod Module {} + +#[doc(alias = "ConstItem")] +pub const Const: u32 = 0; + +#[doc(alias = "StaticItem")] +pub static Static: u32 = 0; + +#[doc(alias = "UnionItem")] +pub union Union { + #[doc(alias = "UnionFieldItem")] + pub union_item: u32, + pub y: f32, +} + +impl Union { + #[doc(alias = "UnionMethodItem")] + pub fn method(&self) {} +} + +#[doc(alias = "MacroItem")] +#[macro_export] +macro_rules! Macro { + () => {} +} diff --git a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr index 61f2570b2ff93..96158fc0e0496 100644 --- a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr +++ b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr @@ -237,7 +237,10 @@ error[E0277]: the `?` operator can only be applied to values that implement `std --> $DIR/incorrect-syntax-suggestions.rs:16:19 | LL | let _ = await bar()?; - | ^^^^^^ the `?` operator cannot be applied to type `impl std::future::Future` + | ^^^^^^ + | | + | the `?` operator cannot be applied to type `impl std::future::Future` + | help: consider using `.await` here: `bar().await?` | = help: the trait `std::ops::Try` is not implemented for `impl std::future::Future` = note: required by `std::ops::Try::into_result` diff --git a/src/test/ui/async-await/issue-61076.rs b/src/test/ui/async-await/issue-61076.rs new file mode 100644 index 0000000000000..13b45df64eabe --- /dev/null +++ b/src/test/ui/async-await/issue-61076.rs @@ -0,0 +1,32 @@ +// edition:2018 + +use core::future::Future; +use core::pin::Pin; +use core::task::{Context, Poll}; + +struct T; + +impl Future for T { + type Output = Result<(), ()>; + + fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll { + Poll::Pending + } +} + +async fn foo() -> Result<(), ()> { + Ok(()) +} + +async fn bar() -> Result<(), ()> { + foo()?; //~ ERROR the `?` operator can only be applied to values that implement `std::ops::Try` + Ok(()) +} + +async fn baz() -> Result<(), ()> { + let t = T; + t?; //~ ERROR the `?` operator can only be applied to values that implement `std::ops::Try` + Ok(()) +} + +fn main() {} diff --git a/src/test/ui/async-await/issue-61076.stderr b/src/test/ui/async-await/issue-61076.stderr new file mode 100644 index 0000000000000..e71f4e7136dad --- /dev/null +++ b/src/test/ui/async-await/issue-61076.stderr @@ -0,0 +1,27 @@ +error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` + --> $DIR/issue-61076.rs:22:5 + | +LL | foo()?; + | ^^^^^^ + | | + | the `?` operator cannot be applied to type `impl std::future::Future` + | help: consider using `.await` here: `foo().await?` + | + = help: the trait `std::ops::Try` is not implemented for `impl std::future::Future` + = note: required by `std::ops::Try::into_result` + +error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` + --> $DIR/issue-61076.rs:28:5 + | +LL | t?; + | ^^ + | | + | the `?` operator cannot be applied to type `T` + | help: consider using `.await` here: `t.await?` + | + = help: the trait `std::ops::Try` is not implemented for `T` + = note: required by `std::ops::Try::into_result` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/try-on-option-in-async.rs b/src/test/ui/async-await/try-on-option-in-async.rs index 51ac522017cb3..c520a07abc172 100644 --- a/src/test/ui/async-await/try-on-option-in-async.rs +++ b/src/test/ui/async-await/try-on-option-in-async.rs @@ -7,7 +7,8 @@ async fn an_async_block() -> u32 { let x: Option = None; x?; //~ ERROR the `?` operator 22 - }.await + } + .await } async fn async_closure_containing_fn() -> u32 { diff --git a/src/test/ui/async-await/try-on-option-in-async.stderr b/src/test/ui/async-await/try-on-option-in-async.stderr index 46f8f41076bf5..700296d674784 100644 --- a/src/test/ui/async-await/try-on-option-in-async.stderr +++ b/src/test/ui/async-await/try-on-option-in-async.stderr @@ -7,14 +7,14 @@ LL | | let x: Option = None; LL | | x?; | | ^^ cannot use the `?` operator in an async block that returns `{integer}` LL | | 22 -LL | | }.await +LL | | } | |_____- this function should return `Result` or `Option` to accept `?` | = help: the trait `std::ops::Try` is not implemented for `{integer}` = note: required by `std::ops::Try::from_error` error[E0277]: the `?` operator can only be used in an async closure that returns `Result` or `Option` (or another type that implements `std::ops::Try`) - --> $DIR/try-on-option-in-async.rs:16:9 + --> $DIR/try-on-option-in-async.rs:17:9 | LL | let async_closure = async || { | __________________________________- @@ -29,7 +29,7 @@ LL | | }; = note: required by `std::ops::Try::from_error` error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) - --> $DIR/try-on-option-in-async.rs:25:5 + --> $DIR/try-on-option-in-async.rs:26:5 | LL | async fn an_async_function() -> u32 { | _____________________________________- diff --git a/src/test/ui/consts/miri_unleashed/ptr_arith.rs b/src/test/ui/consts/miri_unleashed/ptr_arith.rs new file mode 100644 index 0000000000000..81985f9f625a5 --- /dev/null +++ b/src/test/ui/consts/miri_unleashed/ptr_arith.rs @@ -0,0 +1,29 @@ +// compile-flags: -Zunleash-the-miri-inside-of-you +#![feature(core_intrinsics)] +#![allow(const_err)] + +// A test demonstrating that we prevent doing even trivial +// pointer arithmetic or comparison during CTFE. + +static CMP: () = { + let x = &0 as *const _; + let _v = x == x; + //~^ ERROR could not evaluate static initializer + //~| NOTE pointer arithmetic or comparison +}; + +static INT_PTR_ARITH: () = unsafe { + let x: usize = std::mem::transmute(&0); + let _v = x + 0; + //~^ ERROR could not evaluate static initializer + //~| NOTE pointer-to-integer cast +}; + +static PTR_ARITH: () = unsafe { + let x = &0 as *const _; + let _v = core::intrinsics::offset(x, 0); + //~^ ERROR could not evaluate static initializer + //~| NOTE calling intrinsic `offset` +}; + +fn main() {} diff --git a/src/test/ui/consts/miri_unleashed/ptr_arith.stderr b/src/test/ui/consts/miri_unleashed/ptr_arith.stderr new file mode 100644 index 0000000000000..5bd534a16b863 --- /dev/null +++ b/src/test/ui/consts/miri_unleashed/ptr_arith.stderr @@ -0,0 +1,39 @@ +error[E0080]: could not evaluate static initializer + --> $DIR/ptr_arith.rs:10:14 + | +LL | let _v = x == x; + | ^^^^^^ "pointer arithmetic or comparison" needs an rfc before being allowed inside constants + +error[E0080]: could not evaluate static initializer + --> $DIR/ptr_arith.rs:17:14 + | +LL | let _v = x + 0; + | ^^^^^ "pointer-to-integer cast" needs an rfc before being allowed inside constants + +error[E0080]: could not evaluate static initializer + --> $DIR/ptr_arith.rs:24:14 + | +LL | let _v = core::intrinsics::offset(x, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ "calling intrinsic `offset`" needs an rfc before being allowed inside constants + +warning: skipping const checks + | +help: skipping check for `const_compare_raw_pointers` feature + --> $DIR/ptr_arith.rs:10:14 + | +LL | let _v = x == x; + | ^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/ptr_arith.rs:16:20 + | +LL | let x: usize = std::mem::transmute(&0); + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/ptr_arith.rs:24:14 + | +LL | let _v = core::intrinsics::offset(x, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs index 3b8ef18bfab86..438a9f42ccd23 100644 --- a/src/tools/clippy/clippy_lints/src/utils/mod.rs +++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs @@ -40,15 +40,12 @@ use rustc_hir::{ use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_middle::hir::map::Map; -use rustc_middle::traits; use rustc_middle::ty::{self, layout::IntegerExt, subst::GenericArg, Binder, Ty, TyCtxt, TypeFoldable}; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::original_sp; use rustc_span::symbol::{self, kw, Symbol}; use rustc_span::{BytePos, Pos, Span, DUMMY_SP}; use rustc_target::abi::Integer; -use rustc_trait_selection::traits::predicate_for_trait_def; -use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::query::normalize::AtExt; use smallvec::SmallVec; @@ -326,19 +323,8 @@ pub fn implements_trait<'a, 'tcx>( trait_id: DefId, ty_params: &[GenericArg<'tcx>], ) -> bool { - let ty = cx.tcx.erase_regions(&ty); - let obligation = predicate_for_trait_def( - cx.tcx, - cx.param_env, - traits::ObligationCause::dummy(), - trait_id, - 0, - ty, - ty_params, - ); - cx.tcx - .infer_ctxt() - .enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation)) + let ty_params = cx.tcx.mk_substs(ty_params.iter()); + cx.tcx.type_implements_trait((trait_id, ty, ty_params, cx.param_env)) } /// Gets the `hir::TraitRef` of the trait the given method is implemented for. diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index 2c699998ea90e..1ce0300f23904 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -296,7 +296,7 @@ pub fn main() { rustc_driver::init_rustc_env_logger(); lazy_static::initialize(&ICE_HOOK); exit( - rustc_driver::catch_fatal_errors(move || { + rustc_driver::catch_with_exit_code(move || { let mut orig_args: Vec = env::args().collect(); if orig_args.iter().any(|a| a == "--version" || a == "-V") { @@ -411,7 +411,5 @@ pub fn main() { if clippy_enabled { &mut clippy } else { &mut default }; rustc_driver::run_compiler(&args, callbacks, None, None) }) - .and_then(|result| result) - .is_err() as i32, ) } diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js index 03f06fc1c6c71..1fa46ce99f5e6 100644 --- a/src/tools/rustdoc-js/tester.js +++ b/src/tools/rustdoc-js/tester.js @@ -181,7 +181,7 @@ function loadThings(thingsToLoad, kindOfLoad, funcToCall, fileContent) { for (var i = 0; i < thingsToLoad.length; ++i) { var tmp = funcToCall(fileContent, thingsToLoad[i]); if (tmp === null) { - console.error('unable to find ' + kindOfLoad + ' "' + thingsToLoad[i] + '"'); + console.log('unable to find ' + kindOfLoad + ' "' + thingsToLoad[i] + '"'); process.exit(1); } content += tmp; @@ -218,12 +218,13 @@ function lookForEntry(entry, data) { return null; } -function loadMainJsAndIndex(mainJs, aliases, searchIndex, crate) { +function loadMainJsAndIndex(mainJs, searchIndex, storageJs, crate) { if (searchIndex[searchIndex.length - 1].length === 0) { searchIndex.pop(); } searchIndex.pop(); - searchIndex = loadContent(searchIndex.join("\n") + '\nexports.searchIndex = searchIndex;'); + var fullSearchIndex = searchIndex.join("\n") + '\nexports.rawSearchIndex = searchIndex;'; + searchIndex = loadContent(fullSearchIndex); var finalJS = ""; var arraysToLoad = ["itemTypes"]; @@ -235,34 +236,28 @@ function loadMainJsAndIndex(mainJs, aliases, searchIndex, crate) { // execQuery last parameter is built in buildIndex. // buildIndex requires the hashmap from search-index. var functionsToLoad = ["buildHrefAndPath", "pathSplitter", "levenshtein", "validateResult", - "getQuery", "buildIndex", "execQuery", "execSearch"]; + "handleAliases", "getQuery", "buildIndex", "execQuery", "execSearch"]; + ALIASES = {}; finalJS += 'window = { "currentCrate": "' + crate + '" };\n'; finalJS += 'var rootPath = "../";\n'; - finalJS += aliases; + finalJS += loadThings(["onEach"], 'function', extractFunction, storageJs); finalJS += loadThings(arraysToLoad, 'array', extractArrayVariable, mainJs); finalJS += loadThings(variablesToLoad, 'variable', extractVariable, mainJs); finalJS += loadThings(functionsToLoad, 'function', extractFunction, mainJs); var loaded = loadContent(finalJS); - var index = loaded.buildIndex(searchIndex.searchIndex); + var index = loaded.buildIndex(searchIndex.rawSearchIndex); return [loaded, index]; } -function runChecks(testFile, loaded, index) { - var errors = 0; - var loadedFile = loadContent( - readFile(testFile) + 'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;'); - - const expected = loadedFile.EXPECTED; - const query = loadedFile.QUERY; +function runSearch(query, expected, index, loaded, loadedFile, queryName) { const filter_crate = loadedFile.FILTER_CRATE; const ignore_order = loadedFile.ignore_order; const exact_check = loadedFile.exact_check; - const should_fail = loadedFile.should_fail; - var results = loaded.execSearch(loaded.getQuery(query), index); + var results = loaded.execSearch(loaded.getQuery(query), index, filter_crate); var error_text = []; for (var key in expected) { @@ -278,41 +273,77 @@ function runChecks(testFile, loaded, index) { for (var i = 0; i < entry.length; ++i) { var entry_pos = lookForEntry(entry[i], results[key]); if (entry_pos === null) { - error_text.push("==> Result not found in '" + key + "': '" + + error_text.push(queryName + "==> Result not found in '" + key + "': '" + JSON.stringify(entry[i]) + "'"); } else if (exact_check === true && prev_pos + 1 !== entry_pos) { - error_text.push("==> Exact check failed at position " + (prev_pos + 1) + ": " + - "expected '" + JSON.stringify(entry[i]) + "' but found '" + + error_text.push(queryName + "==> Exact check failed at position " + (prev_pos + 1) + + ": expected '" + JSON.stringify(entry[i]) + "' but found '" + JSON.stringify(results[key][i]) + "'"); } else if (ignore_order === false && entry_pos < prev_pos) { - error_text.push("==> '" + JSON.stringify(entry[i]) + "' was supposed to be " + - " before '" + JSON.stringify(results[key][entry_pos]) + "'"); + error_text.push(queryName + "==> '" + JSON.stringify(entry[i]) + "' was supposed " + + "to be before '" + JSON.stringify(results[key][entry_pos]) + "'"); } else { prev_pos = entry_pos; } } } - if (error_text.length === 0 && should_fail === true) { - errors += 1; - console.error("FAILED"); - console.error("==> Test was supposed to fail but all items were found..."); - } else if (error_text.length !== 0 && should_fail === false) { - errors += 1; - console.error("FAILED"); - console.error(error_text.join("\n")); + return error_text; +} + +function checkResult(error_text, loadedFile, displaySuccess) { + if (error_text.length === 0 && loadedFile.should_fail === true) { + console.log("FAILED"); + console.log("==> Test was supposed to fail but all items were found..."); + } else if (error_text.length !== 0 && loadedFile.should_fail === false) { + console.log("FAILED"); + console.log(error_text.join("\n")); } else { + if (displaySuccess) { + console.log("OK"); + } + return 0; + } + return 1; +} + +function runChecks(testFile, loaded, index) { + var loadedFile = loadContent( + readFile(testFile) + 'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;'); + + const expected = loadedFile.EXPECTED; + const query = loadedFile.QUERY; + + if (Array.isArray(query)) { + if (!Array.isArray(expected)) { + console.log("FAILED"); + console.log("==> If QUERY variable is an array, EXPECTED should be an array too"); + return 1; + } else if (query.length !== expected.length) { + console.log("FAILED"); + console.log("==> QUERY variable should have the same length as EXPECTED"); + return 1; + } + for (var i = 0; i < query.length; ++i) { + var error_text = runSearch(query[i], expected[i], index, loaded, loadedFile, + "[ query `" + query[i] + "`]"); + if (checkResult(error_text, loadedFile, false) !== 0) { + return 1; + } + } console.log("OK"); + return 0; } - return errors; + var error_text = runSearch(query, expected, index, loaded, loadedFile, ""); + return checkResult(error_text, loadedFile, true); } function load_files(doc_folder, resource_suffix, crate) { var mainJs = readFile(path.join(doc_folder, "main" + resource_suffix + ".js")); - var aliases = readFile(path.join(doc_folder, "aliases" + resource_suffix + ".js")); + var storageJs = readFile(path.join(doc_folder, "storage" + resource_suffix + ".js")); var searchIndex = readFile( path.join(doc_folder, "search-index" + resource_suffix + ".js")).split("\n"); - return loadMainJsAndIndex(mainJs, aliases, searchIndex, crate); + return loadMainJsAndIndex(mainJs, searchIndex, storageJs, crate); } function showHelp() { @@ -349,7 +380,7 @@ function parseOptions(args) { || args[i] === "--crate-name") { i += 1; if (i >= args.length) { - console.error("Missing argument after `" + args[i - 1] + "` option."); + console.log("Missing argument after `" + args[i - 1] + "` option."); return null; } opts[correspondances[args[i - 1]]] = args[i]; @@ -357,17 +388,17 @@ function parseOptions(args) { showHelp(); process.exit(0); } else { - console.error("Unknown option `" + args[i] + "`."); - console.error("Use `--help` to see the list of options"); + console.log("Unknown option `" + args[i] + "`."); + console.log("Use `--help` to see the list of options"); return null; } } if (opts["doc_folder"].length < 1) { - console.error("Missing `--doc-folder` option."); + console.log("Missing `--doc-folder` option."); } else if (opts["crate_name"].length < 1) { - console.error("Missing `--crate-name` option."); + console.log("Missing `--crate-name` option."); } else if (opts["test_folder"].length < 1 && opts["test_file"].length < 1) { - console.error("At least one of `--test-folder` or `--test-file` option is required."); + console.log("At least one of `--test-folder` or `--test-file` option is required."); } else { return opts; }