diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs index e67ee1cab3df2..eea8f40635d74 100644 --- a/compiler/rustc_typeck/src/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -496,7 +496,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_expr.span, call_expr, fn_sig.inputs(), - &expected_arg_tys, + expected_arg_tys, arg_exprs, fn_sig.c_variadic, TupleArgumentsFlag::DontTupleArguments, @@ -529,7 +529,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_expr.span, call_expr, fn_sig.inputs(), - &expected_arg_tys, + expected_arg_tys, arg_exprs, fn_sig.c_variadic, TupleArgumentsFlag::TupleArguments, diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 11b63a99043b7..e796fe58170d2 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -62,7 +62,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sp, expr, &err_inputs, - &[], + vec![], args_no_rcvr, false, tuple_arguments, @@ -73,7 +73,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let method = method.unwrap(); // HACK(eddyb) ignore self in the definition (see above). - let expected_arg_tys = self.expected_inputs_for_expected_output( + let expected_input_tys = self.expected_inputs_for_expected_output( sp, expected, method.sig.output(), @@ -83,7 +83,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sp, expr, &method.sig.inputs()[1..], - &expected_arg_tys[..], + expected_input_tys, args_no_rcvr, method.sig.c_variadic, tuple_arguments, @@ -96,34 +96,43 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// method calls and overloaded operators. pub(in super::super) fn check_argument_types( &self, - sp: Span, - expr: &'tcx hir::Expr<'tcx>, - fn_inputs: &[Ty<'tcx>], - expected_arg_tys: &[Ty<'tcx>], - args: &'tcx [hir::Expr<'tcx>], + // Span enclosing the call site + call_span: Span, + // Expression of the call site + call_expr: &'tcx hir::Expr<'tcx>, + // Types (as defined in the *signature* of the target function) + formal_input_tys: &[Ty<'tcx>], + // More specific expected types, after unifying with caller output types + expected_input_tys: Vec>, + // The expressions for each provided argument + provided_args: &'tcx [hir::Expr<'tcx>], + // Whether the function is variadic, for example when imported from C c_variadic: bool, + // Whether the arguments have been bundled in a tuple (ex: closures) tuple_arguments: TupleArgumentsFlag, - def_id: Option, + // The DefId for the function being called, for better error messages + fn_def_id: Option, ) { let tcx = self.tcx; // Grab the argument types, supplying fresh type variables // if the wrong number of arguments were supplied - let supplied_arg_count = if tuple_arguments == DontTupleArguments { args.len() } else { 1 }; + let supplied_arg_count = + if tuple_arguments == DontTupleArguments { provided_args.len() } else { 1 }; // All the input types from the fn signature must outlive the call // so as to validate implied bounds. - for (&fn_input_ty, arg_expr) in iter::zip(fn_inputs, args) { + for (&fn_input_ty, arg_expr) in iter::zip(formal_input_tys, provided_args) { self.register_wf_obligation(fn_input_ty.into(), arg_expr.span, traits::MiscObligation); } - let expected_arg_count = fn_inputs.len(); + let expected_arg_count = formal_input_tys.len(); let param_count_error = |expected_count: usize, arg_count: usize, error_code: &str, c_variadic: bool, sugg_unit: bool| { - let (span, start_span, args, ctor_of) = match &expr.kind { + let (span, start_span, args, ctor_of) = match &call_expr.kind { hir::ExprKind::Call( hir::Expr { span, @@ -156,14 +165,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &args[1..], // Skip the receiver. None, // methods are never ctors ), - k => span_bug!(sp, "checking argument types on a non-call: `{:?}`", k), + k => span_bug!(call_span, "checking argument types on a non-call: `{:?}`", k), }; - let arg_spans = if args.is_empty() { + let arg_spans = if provided_args.is_empty() { // foo() // ^^^-- supplied 0 arguments // | // expected 2 arguments - vec![tcx.sess.source_map().next_point(start_span).with_hi(sp.hi())] + vec![tcx.sess.source_map().next_point(start_span).with_hi(call_span.hi())] } else { // foo(1, 2, 3) // ^^^ - - - supplied 3 arguments @@ -196,7 +205,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } - if let Some(def_id) = def_id { + if let Some(def_id) = fn_def_id { if let Some(def_span) = tcx.def_ident_span(def_id) { let mut spans: MultiSpan = def_span.into(); @@ -218,7 +227,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if sugg_unit { - let sugg_span = tcx.sess.source_map().end_point(expr.span); + let sugg_span = tcx.sess.source_map().end_point(call_expr.span); // remove closing `)` from the span let sugg_span = sugg_span.shrink_to_lo(); err.span_suggestion( @@ -240,110 +249,148 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.emit(); }; - let mut expected_arg_tys = expected_arg_tys.to_vec(); - - let formal_tys = if tuple_arguments == TupleArguments { - let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]); + let (formal_input_tys, expected_input_tys) = if tuple_arguments == TupleArguments { + let tuple_type = self.structurally_resolved_type(call_span, formal_input_tys[0]); match tuple_type.kind() { - ty::Tuple(arg_types) if arg_types.len() != args.len() => { - param_count_error(arg_types.len(), args.len(), "E0057", false, false); - expected_arg_tys = vec![]; - self.err_args(args.len()) + ty::Tuple(arg_types) if arg_types.len() != provided_args.len() => { + param_count_error(arg_types.len(), provided_args.len(), "E0057", false, false); + (self.err_args(provided_args.len()), vec![]) } ty::Tuple(arg_types) => { - expected_arg_tys = match expected_arg_tys.get(0) { + let expected_input_tys = match expected_input_tys.get(0) { Some(&ty) => match ty.kind() { ty::Tuple(ref tys) => tys.iter().map(|k| k.expect_ty()).collect(), _ => vec![], }, None => vec![], }; - arg_types.iter().map(|k| k.expect_ty()).collect() + (arg_types.iter().map(|k| k.expect_ty()).collect(), expected_input_tys) } _ => { struct_span_err!( tcx.sess, - sp, + call_span, E0059, "cannot use call notation; the first type parameter \ for the function trait is neither a tuple nor unit" ) .emit(); - expected_arg_tys = vec![]; - self.err_args(args.len()) + (self.err_args(provided_args.len()), vec![]) } } } else if expected_arg_count == supplied_arg_count { - fn_inputs.to_vec() + (formal_input_tys.to_vec(), expected_input_tys) } else if c_variadic { if supplied_arg_count >= expected_arg_count { - fn_inputs.to_vec() + (formal_input_tys.to_vec(), expected_input_tys) } else { param_count_error(expected_arg_count, supplied_arg_count, "E0060", true, false); - expected_arg_tys = vec![]; - self.err_args(supplied_arg_count) + (self.err_args(supplied_arg_count), vec![]) } } else { // is the missing argument of type `()`? - let sugg_unit = if expected_arg_tys.len() == 1 && supplied_arg_count == 0 { - self.resolve_vars_if_possible(expected_arg_tys[0]).is_unit() - } else if fn_inputs.len() == 1 && supplied_arg_count == 0 { - self.resolve_vars_if_possible(fn_inputs[0]).is_unit() + let sugg_unit = if expected_input_tys.len() == 1 && supplied_arg_count == 0 { + self.resolve_vars_if_possible(expected_input_tys[0]).is_unit() + } else if formal_input_tys.len() == 1 && supplied_arg_count == 0 { + self.resolve_vars_if_possible(formal_input_tys[0]).is_unit() } else { false }; param_count_error(expected_arg_count, supplied_arg_count, "E0061", false, sugg_unit); - expected_arg_tys = vec![]; - self.err_args(supplied_arg_count) + (self.err_args(supplied_arg_count), vec![]) }; debug!( - "check_argument_types: formal_tys={:?}", - formal_tys.iter().map(|t| self.ty_to_string(*t)).collect::>() + "check_argument_types: formal_input_tys={:?}", + formal_input_tys.iter().map(|t| self.ty_to_string(*t)).collect::>() ); - // If there is no expectation, expect formal_tys. - let expected_arg_tys = - if !expected_arg_tys.is_empty() { expected_arg_tys } else { formal_tys.clone() }; + // If there is no expectation, expect formal_input_tys. + let expected_input_tys = if !expected_input_tys.is_empty() { + expected_input_tys + } else { + formal_input_tys.clone() + }; + + assert_eq!(expected_input_tys.len(), formal_input_tys.len()); + // Keep track of the fully coerced argument types let mut final_arg_types: Vec<(usize, Ty<'_>, Ty<'_>)> = vec![]; + // We introduce a helper function to demand that a given argument satisfy a given input + // This is more complicated than just checking type equality, as arguments could be coerced + // This version writes those types back so further type checking uses the narrowed types + let demand_compatible = |idx, final_arg_types: &mut Vec<(usize, Ty<'tcx>, Ty<'tcx>)>| { + let formal_input_ty: Ty<'tcx> = formal_input_tys[idx]; + let expected_input_ty: Ty<'tcx> = expected_input_tys[idx]; + let provided_arg = &provided_args[idx]; + + debug!("checking argument {}: {:?} = {:?}", idx, provided_arg, formal_input_ty); + + // The special-cased logic below has three functions: + // 1. Provide as good of an expected type as possible. + let expectation = Expectation::rvalue_hint(self, expected_input_ty); + + let checked_ty = self.check_expr_with_expectation(provided_arg, expectation); + + // 2. Coerce to the most detailed type that could be coerced + // to, which is `expected_ty` if `rvalue_hint` returns an + // `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise. + let coerced_ty = expectation.only_has_type(self).unwrap_or(formal_input_ty); + + // Keep track of these for below + final_arg_types.push((idx, checked_ty, coerced_ty)); + + // Cause selection errors caused by resolving a single argument to point at the + // argument and not the call. This is otherwise redundant with the `demand_coerce` + // call immediately after, but it lets us customize the span pointed to in the + // fulfillment error to be more accurate. + let _ = + self.resolve_vars_with_obligations_and_mutate_fulfillment(coerced_ty, |errors| { + self.point_at_type_arg_instead_of_call_if_possible(errors, call_expr); + self.point_at_arg_instead_of_call_if_possible( + errors, + &final_arg_types, + call_expr, + call_span, + provided_args, + ); + }); + + // We're processing function arguments so we definitely want to use + // two-phase borrows. + self.demand_coerce(&provided_arg, checked_ty, coerced_ty, None, AllowTwoPhase::Yes); + + // 3. Relate the expected type and the formal one, + // if the expected type was used for the coercion. + self.demand_suptype(provided_arg.span, formal_input_ty, coerced_ty); + }; + // Check the arguments. // We do this in a pretty awful way: first we type-check any arguments // that are not closures, then we type-check the closures. This is so // that we have more information about the types of arguments when we // type-check the functions. This isn't really the right way to do this. for check_closures in [false, true] { - debug!("check_closures={}", check_closures); - // More awful hacks: before we check argument types, try to do // an "opportunistic" trait resolution of any trait bounds on // the call. This helps coercions. if check_closures { self.select_obligations_where_possible(false, |errors| { - self.point_at_type_arg_instead_of_call_if_possible(errors, expr); + self.point_at_type_arg_instead_of_call_if_possible(errors, call_expr); self.point_at_arg_instead_of_call_if_possible( errors, &final_arg_types, - expr, - sp, - &args, + call_expr, + call_span, + &provided_args, ); }) } - // For C-variadic functions, we don't have a declared type for all of - // the arguments hence we only do our usual type checking with - // the arguments who's types we do know. - let t = if c_variadic { - expected_arg_count - } else if tuple_arguments == TupleArguments { - args.len() - } else { - supplied_arg_count - }; - for (i, arg) in args.iter().take(t).enumerate() { + let minimum_input_count = formal_input_tys.len(); + for (idx, arg) in provided_args.iter().enumerate() { // Warn only for the first loop (the "no closures" one). // Closure arguments themselves can't be diverging, but // a previous argument can, e.g., `foo(panic!(), || {})`. @@ -351,53 +398,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.warn_if_unreachable(arg.hir_id, arg.span, "expression"); } - let is_closure = matches!(arg.kind, ExprKind::Closure(..)); + // For C-variadic functions, we don't have a declared type for all of + // the arguments hence we only do our usual type checking with + // the arguments who's types we do know. However, we *can* check + // for unreachable expressions (see above). + // FIXME: unreachable warning current isn't emitted + if idx >= minimum_input_count { + continue; + } + let is_closure = matches!(arg.kind, ExprKind::Closure(..)); if is_closure != check_closures { continue; } - let formal_ty = formal_tys[i]; - debug!("checking argument {}: {:?} = {:?}", i, arg, formal_ty); - - // The special-cased logic below has three functions: - // 1. Provide as good of an expected type as possible. - let expected = Expectation::rvalue_hint(self, expected_arg_tys[i]); - - let checked_ty = self.check_expr_with_expectation(&arg, expected); - - // 2. Coerce to the most detailed type that could be coerced - // to, which is `expected_ty` if `rvalue_hint` returns an - // `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise. - let coerce_ty = expected.only_has_type(self).unwrap_or(formal_ty); - - final_arg_types.push((i, checked_ty, coerce_ty)); - - // Cause selection errors caused by resolving a single argument to point at the - // argument and not the call. This is otherwise redundant with the `demand_coerce` - // call immediately after, but it lets us customize the span pointed to in the - // fulfillment error to be more accurate. - let _ = self.resolve_vars_with_obligations_and_mutate_fulfillment( - coerce_ty, - |errors| { - self.point_at_type_arg_instead_of_call_if_possible(errors, expr); - self.point_at_arg_instead_of_call_if_possible( - errors, - &final_arg_types, - expr, - sp, - args, - ); - }, - ); - - // We're processing function arguments so we definitely want to use - // two-phase borrows. - self.demand_coerce(&arg, checked_ty, coerce_ty, None, AllowTwoPhase::Yes); - - // 3. Relate the expected type and the formal one, - // if the expected type was used for the coercion. - self.demand_suptype(arg.span, formal_ty, coerce_ty); + demand_compatible(idx, &mut final_arg_types); } } @@ -410,7 +425,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { MissingCastForVariadicArg { sess, span, ty, cast_ty }.diagnostic().emit() } - for arg in args.iter().skip(expected_arg_count) { + for arg in provided_args.iter().skip(expected_arg_count) { let arg_ty = self.check_expr(&arg); // There are a few types which get autopromoted when passed via varargs diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index d075658f51a3e..9d4f9af91a5e1 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -348,7 +348,6 @@ extern "Rust" { // This is the magic symbol to call the global alloc error handler. rustc generates // it to call `__rg_oom` if there is a `#[alloc_error_handler]`, or to call the // default implementations below (`__rdl_oom`) otherwise. - #[rustc_allocator_nounwind] fn __rust_alloc_error_handler(size: usize, align: usize) -> !; } @@ -367,7 +366,6 @@ extern "Rust" { #[stable(feature = "global_alloc", since = "1.28.0")] #[rustc_const_unstable(feature = "const_alloc_error", issue = "92523")] #[cfg(all(not(no_global_oom_handling), not(test)))] -#[rustc_allocator_nounwind] #[cold] pub const fn handle_alloc_error(layout: Layout) -> ! { const fn ct_error(_: Layout) -> ! { @@ -398,13 +396,13 @@ pub mod __alloc_error_handler { // if there is no `#[alloc_error_handler]` #[rustc_std_internal_symbol] - pub unsafe extern "C" fn __rdl_oom(size: usize, _align: usize) -> ! { + pub unsafe extern "C-unwind" fn __rdl_oom(size: usize, _align: usize) -> ! { panic!("memory allocation of {} bytes failed", size) } // if there is an `#[alloc_error_handler]` #[rustc_std_internal_symbol] - pub unsafe extern "C" fn __rg_oom(size: usize, align: usize) -> ! { + pub unsafe extern "C-unwind" fn __rg_oom(size: usize, align: usize) -> ! { let layout = unsafe { Layout::from_size_align_unchecked(size, align) }; extern "Rust" { #[lang = "oom"] diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 7e663fab16af5..95da9971993e0 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -168,6 +168,7 @@ #![cfg_attr(test, feature(test))] #![feature(unboxed_closures)] #![feature(unsized_fn_params)] +#![feature(c_unwind)] // // Rustdoc features: #![feature(doc_cfg)] diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 7d005666a74a6..989ec0639cd6b 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1045,6 +1045,10 @@ pub const fn discriminant(v: &T) -> Discriminant { /// return value is unspecified. Equally, if `T` is an enum with more variants than `usize::MAX` /// the return value is unspecified. Uninhabited variants will be counted. /// +/// Note that an enum may be expanded with additional variants in the future +/// as a non-breaking change, for example if it is marked `#[non_exhaustive]`, +/// which will change the result of this function. +/// /// # Examples /// /// ``` diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 5235a6b818053..7c36bb264c45e 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -13,7 +13,7 @@ import tarfile import tempfile -from time import time +from time import time, sleep # Acquire a lock on the build directory to make sure that # we don't cause a race condition while building @@ -42,8 +42,10 @@ def acquire_lock(build_dir): while True: try: curs.execute("BEGIN EXCLUSIVE") + break except sqlite3.OperationalError: pass + sleep(0.25) return curs except ImportError: print("warning: sqlite3 not available in python, skipping build directory lock") diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile index c27e42a266220..66333e2b99214 100644 --- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile @@ -17,12 +17,12 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config \ mingw-w64 -RUN curl -sL https://nodejs.org/dist/v14.4.0/node-v14.4.0-linux-x64.tar.xz | tar -xJ -ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}" +RUN curl -sL https://nodejs.org/dist/v16.9.0/node-v16.9.0-linux-x64.tar.xz | tar -xJ +ENV PATH="/node-v16.9.0-linux-x64/bin:${PATH}" # Install es-check # Pin its version to prevent unrelated CI failures due to future es-check versions. -RUN npm install es-check@5.2.3 -g -RUN npm install eslint@7.20.0 -g +RUN npm install es-check@6.1.1 -g +RUN npm install eslint@8.6.0 -g COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh @@ -40,5 +40,5 @@ ENV SCRIPT python3 ../x.py --stage 2 test src/tools/expand-yaml-anchors && \ /scripts/validate-toolstate.sh && \ /scripts/validate-error-codes.sh && \ # Runs checks to ensure that there are no ES5 issues in our JS code. - es-check es5 ../src/librustdoc/html/static/js/*.js && \ + es-check es6 ../src/librustdoc/html/static/js/*.js && \ eslint ../src/librustdoc/html/static/js/*.js diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index d82c65398b835..7c92156dec25c 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -862,18 +862,24 @@ h2.small-section-header > .anchor { display: inline-flex; width: calc(100% - 63px); } +.search-results-title { + display: inline; +} +#search-settings { + font-size: 1.5rem; + font-weight: 500; + margin-bottom: 20px; +} #crate-search { min-width: 115px; margin-top: 5px; - padding: 6px; - padding-right: 19px; - flex: none; + margin-left: 0.2em; + padding-left: 0.3em; + padding-right: 23px; border: 0; - border-right: 0; - border-radius: 4px 0 0 4px; + border-radius: 4px; outline: none; cursor: pointer; - border-right: 1px solid; -moz-appearance: none; -webkit-appearance: none; /* Removes default arrow from firefox */ diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index cf320f7b4958a..e859431e1f189 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -1085,7 +1085,7 @@ window.initSearch = function(rawSearchIndex) { return ""; } - function showResults(results, go_to_first) { + function showResults(results, go_to_first, filterCrates) { var search = searchState.outputElement(); if (go_to_first || (results.others.length === 1 && getSettingValue("go-to-only-result") === "true" @@ -1126,9 +1126,16 @@ window.initSearch = function(rawSearchIndex) { } } - var output = "

Results for " + escape(query.query) + + let crates = ``; + var output = `
+

Results for ${escape(query.query)} ` + (query.type ? " (type: " + escape(query.type) + ")" : "") + "

" + - "
" + + ` in ${crates} ` + + `
` + makeTabHeader(0, "In Names", ret_others[1]) + makeTabHeader(1, "In Parameters", ret_in_args[1]) + makeTabHeader(2, "In Return Types", ret_returned[1]) + @@ -1141,6 +1148,7 @@ window.initSearch = function(rawSearchIndex) { resultsElem.appendChild(ret_returned[0]); search.innerHTML = output; + document.getElementById("crate-search").addEventListener("input", updateCrate); search.appendChild(resultsElem); // Reset focused elements. searchState.focusedByTab = [null, null, null]; @@ -1316,7 +1324,8 @@ window.initSearch = function(rawSearchIndex) { } var filterCrates = getFilterCrates(); - showResults(execSearch(query, searchWords, filterCrates), params["go_to_first"]); + showResults(execSearch(query, searchWords, filterCrates), + params["go_to_first"], filterCrates); } function buildIndex(rawSearchIndex) { @@ -1552,19 +1561,6 @@ window.initSearch = function(rawSearchIndex) { } }); - - var selectCrate = document.getElementById("crate-search"); - if (selectCrate) { - selectCrate.onchange = function() { - updateLocalStorage("rustdoc-saved-filter-crate", selectCrate.value); - // In case you "cut" the entry from the search input, then change the crate filter - // before paste back the previous search, you get the old search results without - // the filter. To prevent this, we need to remove the previous results. - currentResults = null; - search(undefined, true); - }; - } - // Push and pop states are used to add search results to the browser // history. if (searchState.browserSupportsHistoryApi()) { @@ -1616,6 +1612,15 @@ window.initSearch = function(rawSearchIndex) { }; } + function updateCrate(ev) { + updateLocalStorage("rustdoc-saved-filter-crate", ev.target.value); + // In case you "cut" the entry from the search input, then change the crate filter + // before paste back the previous search, you get the old search results without + // the filter. To prevent this, we need to remove the previous results. + currentResults = null; + search(undefined, true); + } + searchWords = buildIndex(rawSearchIndex); registerSearchEvents(); // If there's a search term in the URL, execute the search now. diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html index 00b46b1ba918b..5cade1b1a4c73 100644 --- a/src/librustdoc/html/templates/page.html +++ b/src/librustdoc/html/templates/page.html @@ -105,11 +105,7 @@
{#- -#}
{#- -#}
{#- -#} -
{%- if layout.generate_search_filter -%} - {#- -#} - {%- endif -%} +
LinkCollector<'a, 'tcx> { }) } + /// Convert a PrimitiveType to a Ty, where possible. + /// + /// This is used for resolving trait impls for primitives + fn primitive_type_to_ty(&mut self, prim: PrimitiveType) -> Option> { + use PrimitiveType::*; + let tcx = self.cx.tcx; + + // FIXME: Only simple types are supported here, see if we can support + // other types such as Tuple, Array, Slice, etc. + // See https://github.com/rust-lang/rust/issues/90703#issuecomment-1004263455 + Some(tcx.mk_ty(match prim { + Bool => ty::Bool, + Str => ty::Str, + Char => ty::Char, + Never => ty::Never, + I8 => ty::Int(ty::IntTy::I8), + I16 => ty::Int(ty::IntTy::I16), + I32 => ty::Int(ty::IntTy::I32), + I64 => ty::Int(ty::IntTy::I64), + I128 => ty::Int(ty::IntTy::I128), + Isize => ty::Int(ty::IntTy::Isize), + F32 => ty::Float(ty::FloatTy::F32), + F64 => ty::Float(ty::FloatTy::F64), + U8 => ty::Uint(ty::UintTy::U8), + U16 => ty::Uint(ty::UintTy::U16), + U32 => ty::Uint(ty::UintTy::U32), + U64 => ty::Uint(ty::UintTy::U64), + U128 => ty::Uint(ty::UintTy::U128), + Usize => ty::Uint(ty::UintTy::Usize), + _ => return None, + })) + } + /// Returns: /// - None if no associated item was found /// - Some((_, _, Some(_))) if an item was found and should go through a side channel @@ -632,7 +665,25 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { let tcx = self.cx.tcx; match root_res { - Res::Primitive(prim) => self.resolve_primitive_associated_item(prim, ns, item_name), + Res::Primitive(prim) => { + self.resolve_primitive_associated_item(prim, ns, item_name).or_else(|| { + let assoc_item = self + .primitive_type_to_ty(prim) + .map(|ty| { + resolve_associated_trait_item(ty, module_id, item_name, ns, self.cx) + }) + .flatten(); + + assoc_item.map(|item| { + let kind = item.kind; + let fragment = UrlFragment::from_assoc_item(item_name, kind, false); + // HACK(jynelson): `clean` expects the type, not the associated item + // but the disambiguator logic expects the associated item. + // Store the kind in a side channel so that only the disambiguator logic looks at it. + (root_res, fragment, Some((kind.as_def_kind(), item.def_id))) + }) + }) + } Res::Def(DefKind::TyAlias, did) => { // Resolve the link on the type the alias points to. // FIXME: if the associated item is defined directly on the type alias, @@ -666,8 +717,13 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // To handle that properly resolve() would have to support // something like [`ambi_fn`](::ambi_fn) .or_else(|| { - let item = - resolve_associated_trait_item(did, module_id, item_name, ns, self.cx); + let item = resolve_associated_trait_item( + tcx.type_of(did), + module_id, + item_name, + ns, + self.cx, + ); debug!("got associated item {:?}", item); item }); @@ -767,12 +823,12 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { /// Given `[std::io::Error::source]`, where `source` is unresolved, this would /// find `std::error::Error::source` and return /// `::source`. -fn resolve_associated_trait_item( - did: DefId, +fn resolve_associated_trait_item<'a>( + ty: Ty<'a>, module: DefId, item_name: Symbol, ns: Namespace, - cx: &mut DocContext<'_>, + cx: &mut DocContext<'a>, ) -> Option { // FIXME: this should also consider blanket impls (`impl X for T`). Unfortunately // `get_auto_trait_and_blanket_impls` is broken because the caching behavior is wrong. In the @@ -780,7 +836,7 @@ fn resolve_associated_trait_item( // Next consider explicit impls: `impl MyTrait for MyType` // Give precedence to inherent impls. - let traits = traits_implemented_by(cx, did, module); + let traits = traits_implemented_by(cx, ty, module); debug!("considering traits {:?}", traits); let mut candidates = traits.iter().filter_map(|&trait_| { cx.tcx.associated_items(trait_).find_by_name_and_namespace( @@ -799,7 +855,11 @@ fn resolve_associated_trait_item( /// /// NOTE: this cannot be a query because more traits could be available when more crates are compiled! /// So it is not stable to serialize cross-crate. -fn traits_implemented_by(cx: &mut DocContext<'_>, type_: DefId, module: DefId) -> FxHashSet { +fn traits_implemented_by<'a>( + cx: &mut DocContext<'a>, + ty: Ty<'a>, + module: DefId, +) -> FxHashSet { let mut resolver = cx.resolver.borrow_mut(); let in_scope_traits = cx.module_trait_cache.entry(module).or_insert_with(|| { resolver.access(|resolver| { @@ -813,7 +873,6 @@ fn traits_implemented_by(cx: &mut DocContext<'_>, type_: DefId, module: DefId) - }); let tcx = cx.tcx; - let ty = tcx.type_of(type_); let iter = in_scope_traits.iter().flat_map(|&trait_| { trace!("considering explicit impl for trait {:?}", trait_); @@ -826,19 +885,10 @@ fn traits_implemented_by(cx: &mut DocContext<'_>, type_: DefId, module: DefId) - "comparing type {} with kind {:?} against type {:?}", impl_type, impl_type.kind(), - type_ + ty ); // Fast path: if this is a primitive simple `==` will work - let saw_impl = impl_type == ty - || match impl_type.kind() { - // Check if these are the same def_id - ty::Adt(def, _) => { - debug!("adt def_id: {:?}", def.did); - def.did == type_ - } - ty::Foreign(def_id) => *def_id == type_, - _ => false, - }; + let saw_impl = impl_type == ty; if saw_impl { Some(trait_) } else { None } }) diff --git a/src/test/rustdoc-gui/escape-key.goml b/src/test/rustdoc-gui/escape-key.goml index b65c398405cf5..712920b16a91b 100644 --- a/src/test/rustdoc-gui/escape-key.goml +++ b/src/test/rustdoc-gui/escape-key.goml @@ -1,7 +1,7 @@ goto: file://|DOC_PATH|/test_docs/index.html // First, we check that the search results are hidden when the Escape key is pressed. write: (".search-input", "test") -wait-for: "#search > h1" // The search element is empty before the first search +wait-for: "#search h1" // The search element is empty before the first search assert-attribute: ("#search", {"class": "content"}) assert-attribute: ("#main-content", {"class": "content hidden"}) press-key: "Escape" diff --git a/src/test/rustdoc-gui/search-filter.goml b/src/test/rustdoc-gui/search-filter.goml index 7a8f8ca5311ad..e5cdf3ea7a169 100644 --- a/src/test/rustdoc-gui/search-filter.goml +++ b/src/test/rustdoc-gui/search-filter.goml @@ -5,14 +5,12 @@ write: (".search-input", "test") wait-for: "#titles" assert-text: ("#results .externcrate", "test_docs") -goto: file://|DOC_PATH|/test_docs/index.html +wait-for: "#crate-search" // We now want to change the crate filter. click: "#crate-search" // We select "lib2" option then press enter to change the filter. press-key: "ArrowDown" press-key: "Enter" -// We now make the search again. -write: (".search-input", "test") // Waiting for the search results to appear... wait-for: "#titles" // We check that there is no more "test_docs" appearing. diff --git a/src/test/rustdoc-gui/toggle-docs-mobile.goml b/src/test/rustdoc-gui/toggle-docs-mobile.goml index b370dd012fae1..6e0ad8e0fa7fb 100644 --- a/src/test/rustdoc-gui/toggle-docs-mobile.goml +++ b/src/test/rustdoc-gui/toggle-docs-mobile.goml @@ -1,12 +1,12 @@ goto: file://|DOC_PATH|/test_docs/struct.Foo.html size: (433, 600) assert-attribute: (".top-doc", {"open": ""}) -click: (4, 280) // This is the position of the top doc comment toggle +click: (4, 240) // This is the position of the top doc comment toggle assert-attribute-false: (".top-doc", {"open": ""}) -click: (4, 280) +click: (4, 240) assert-attribute: (".top-doc", {"open": ""}) // To ensure that the toggle isn't over the text, we check that the toggle isn't clicked. -click: (3, 280) +click: (3, 240) assert-attribute: (".top-doc", {"open": ""}) // Assert the position of the toggle on the top doc block. diff --git a/src/test/rustdoc-ui/intra-doc/non-path-primitives.rs b/src/test/rustdoc-ui/intra-doc/non-path-primitives.rs index 75159979e8890..587cbad684864 100644 --- a/src/test/rustdoc-ui/intra-doc/non-path-primitives.rs +++ b/src/test/rustdoc-ui/intra-doc/non-path-primitives.rs @@ -28,7 +28,6 @@ //! [unit::eq] //~ ERROR unresolved //! [tuple::eq] //~ ERROR unresolved //! [fn::eq] //~ ERROR unresolved -//! [never::eq] //~ ERROR unresolved // FIXME(#78800): This breaks because it's a blanket impl // (I think? Might break for other reasons too.) diff --git a/src/test/rustdoc-ui/intra-doc/non-path-primitives.stderr b/src/test/rustdoc-ui/intra-doc/non-path-primitives.stderr index 610c830560527..4828a30446355 100644 --- a/src/test/rustdoc-ui/intra-doc/non-path-primitives.stderr +++ b/src/test/rustdoc-ui/intra-doc/non-path-primitives.stderr @@ -53,17 +53,11 @@ error: unresolved link to `fn::eq` LL | //! [fn::eq] | ^^^^^^ the builtin type `fn` has no associated item named `eq` -error: unresolved link to `never::eq` - --> $DIR/non-path-primitives.rs:31:6 - | -LL | //! [never::eq] - | ^^^^^^^^^ the builtin type `never` has no associated item named `eq` - error: unresolved link to `reference::deref` - --> $DIR/non-path-primitives.rs:35:6 + --> $DIR/non-path-primitives.rs:34:6 | LL | //! [reference::deref] | ^^^^^^^^^^^^^^^^ the builtin type `reference` has no associated item named `deref` -error: aborting due to 9 previous errors +error: aborting due to 8 previous errors diff --git a/src/test/rustdoc/intra-doc/prim-associated-traits.rs b/src/test/rustdoc/intra-doc/prim-associated-traits.rs new file mode 100644 index 0000000000000..8639a24f7f386 --- /dev/null +++ b/src/test/rustdoc/intra-doc/prim-associated-traits.rs @@ -0,0 +1,46 @@ +#![feature(never_type)] +use std::str::FromStr; + +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.f64.html#method.from_str"]' 'f64::from_str()' +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.f32.html#method.from_str"]' 'f32::from_str()' +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.isize.html#method.from_str"]' 'isize::from_str()' +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i8.html#method.from_str"]' 'i8::from_str()' +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i16.html#method.from_str"]' 'i16::from_str()' +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i32.html#method.from_str"]' 'i32::from_str()' +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i64.html#method.from_str"]' 'i64::from_str()' +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i128.html#method.from_str"]' 'i128::from_str()' +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.usize.html#method.from_str"]' 'usize::from_str()' +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u8.html#method.from_str"]' 'u8::from_str()' +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u16.html#method.from_str"]' 'u16::from_str()' +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u32.html#method.from_str"]' 'u32::from_str()' +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u64.html#method.from_str"]' 'u64::from_str()' +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u128.html#method.from_str"]' 'u128::from_str()' +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.char.html#method.from_str"]' 'char::from_str()' +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.bool.html#method.from_str"]' 'bool::from_str()' +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.str.html#method.eq"]' 'str::eq()' +// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.never.html#method.eq"]' 'never::eq()' +/// [`f64::from_str()`] [`f32::from_str()`] [`isize::from_str()`] [`i8::from_str()`] +/// [`i16::from_str()`] [`i32::from_str()`] [`i64::from_str()`] [`i128::from_str()`] +/// [`u16::from_str()`] [`u32::from_str()`] [`u64::from_str()`] [`u128::from_str()`] +/// [`usize::from_str()`] [`u8::from_str()`] [`char::from_str()`] [`bool::from_str()`] +/// [`str::eq()`] [`never::eq()`] +pub struct Number { + pub f_64: f64, + pub f_32: f32, + pub i_size: isize, + pub i_8: i8, + pub i_16: i16, + pub i_32: i32, + pub i_64: i64, + pub i_128: i128, + pub u_size: usize, + pub u_8: u8, + pub u_16: u16, + pub u_32: u32, + pub u_64: u64, + pub u_128: u128, + pub ch: char, + pub boolean: bool, + pub string: str, + pub n: !, +} diff --git a/src/test/ui/borrowck/issue-92015.rs b/src/test/ui/borrowck/issue-92015.rs new file mode 100644 index 0000000000000..16d651717ff2c --- /dev/null +++ b/src/test/ui/borrowck/issue-92015.rs @@ -0,0 +1,7 @@ +// Regression test for #92105. +// ICE when mutating immutable reference from last statement of a block. + +fn main() { + let foo = Some(&0).unwrap(); + *foo = 1; //~ ERROR cannot assign +} diff --git a/src/test/ui/borrowck/issue-92015.stderr b/src/test/ui/borrowck/issue-92015.stderr new file mode 100644 index 0000000000000..32a65d3b5bb0f --- /dev/null +++ b/src/test/ui/borrowck/issue-92015.stderr @@ -0,0 +1,11 @@ +error[E0594]: cannot assign to `*foo`, which is behind a `&` reference + --> $DIR/issue-92015.rs:6:5 + | +LL | let foo = Some(&0).unwrap(); + | --- help: consider changing this to be a mutable reference: `&mut i32` +LL | *foo = 1; + | ^^^^^^^^ `foo` is a `&` reference, so the data it refers to cannot be written + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/c-variadic/variadic-unreachable-arg-error.rs b/src/test/ui/c-variadic/variadic-unreachable-arg-error.rs new file mode 100644 index 0000000000000..f60f6f3e80872 --- /dev/null +++ b/src/test/ui/c-variadic/variadic-unreachable-arg-error.rs @@ -0,0 +1,14 @@ +// check-pass + +#![feature(c_variadic)] + +extern "C" { + fn foo(f: isize, x: u8, ...); +} + +fn main() { + unsafe { + // FIXME: Ideally we could give an unreachable warning + foo(1, loop {}, 1usize); + } +}