From 284c94257fbf32e62bbe3a8f9e71ecb644763df9 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 28 Sep 2022 11:13:51 -0700 Subject: [PATCH 1/8] Don't export `__wasm_init_memory` on WebAssembly. Since #72889, the Rust wasm target doesn't use --passive-segments, so remove the `--export=__wasm_init_memory`. As documented in the [tool-conventions Linking convention], `__wasm_init_memory` is not intended to be exported. [tool-conventions Linking convention]: https://github.com/WebAssembly/tool-conventions/blob/7c064f304858f67ebf22964a84b7e9658e29557a/Linking.md#shared-memory-and-passive-segments --- compiler/rustc_codegen_ssa/src/back/linker.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index e0bd7a33f73..8dd08467c08 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1180,18 +1180,12 @@ impl<'a> WasmLd<'a> { // sharing memory and instantiating the module multiple times. As a // result if it were exported then we'd just have no sharing. // - // * `--export=__wasm_init_memory` - when using `--passive-segments` the - // linker will synthesize this function, and so we need to make sure - // that our usage of `--export` below won't accidentally cause this - // function to get deleted. - // // * `--export=*tls*` - when `#[thread_local]` symbols are used these // symbols are how the TLS segments are initialized and configured. if sess.target_features.contains(&sym::atomics) { cmd.arg("--shared-memory"); cmd.arg("--max-memory=1073741824"); cmd.arg("--import-memory"); - cmd.arg("--export=__wasm_init_memory"); cmd.arg("--export=__wasm_init_tls"); cmd.arg("--export=__tls_size"); cmd.arg("--export=__tls_align"); From e5096d4cba080f94448a4e766243f0f0e8083583 Mon Sep 17 00:00:00 2001 From: Cassaundra Smith Date: Fri, 23 Sep 2022 16:26:17 -0700 Subject: [PATCH 2/8] Fix span of byte-escaped left format args brace Fix #102057. --- compiler/rustc_parse_format/src/lib.rs | 2 +- .../fmt/format-args-capture-issue-102057.rs | 19 ++++++++ .../format-args-capture-issue-102057.stderr | 45 +++++++++++++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/fmt/format-args-capture-issue-102057.rs create mode 100644 src/test/ui/fmt/format-args-capture-issue-102057.stderr diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index a9e502016aa..df22d79f82e 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -224,7 +224,7 @@ impl<'a> Iterator for Parser<'a> { '{' => { let curr_last_brace = self.last_opening_brace; let byte_pos = self.to_span_index(pos); - let lbrace_end = InnerOffset(byte_pos.0 + 1); + let lbrace_end = self.to_span_index(pos + 1); self.last_opening_brace = Some(byte_pos.to(lbrace_end)); self.cur.next(); if self.consume('{') { diff --git a/src/test/ui/fmt/format-args-capture-issue-102057.rs b/src/test/ui/fmt/format-args-capture-issue-102057.rs new file mode 100644 index 00000000000..b8089d49bcb --- /dev/null +++ b/src/test/ui/fmt/format-args-capture-issue-102057.rs @@ -0,0 +1,19 @@ +fn main() { + format!("\x7Ba}"); + //~^ ERROR cannot find value `a` in this scope + format!("\x7Ba\x7D"); + //~^ ERROR cannot find value `a` in this scope + + let a = 0; + + format!("\x7Ba} {b}"); + //~^ ERROR cannot find value `b` in this scope + format!("\x7Ba\x7D {b}"); + //~^ ERROR cannot find value `b` in this scope + format!("\x7Ba} \x7Bb}"); + //~^ ERROR cannot find value `b` in this scope + format!("\x7Ba\x7D \x7Bb}"); + //~^ ERROR cannot find value `b` in this scope + format!("\x7Ba\x7D \x7Bb\x7D"); + //~^ ERROR cannot find value `b` in this scope +} diff --git a/src/test/ui/fmt/format-args-capture-issue-102057.stderr b/src/test/ui/fmt/format-args-capture-issue-102057.stderr new file mode 100644 index 00000000000..f2d625e7f8d --- /dev/null +++ b/src/test/ui/fmt/format-args-capture-issue-102057.stderr @@ -0,0 +1,45 @@ +error[E0425]: cannot find value `a` in this scope + --> $DIR/format-args-capture-issue-102057.rs:2:18 + | +LL | format!("\x7Ba}"); + | ^ not found in this scope + +error[E0425]: cannot find value `a` in this scope + --> $DIR/format-args-capture-issue-102057.rs:4:18 + | +LL | format!("\x7Ba\x7D"); + | ^ not found in this scope + +error[E0425]: cannot find value `b` in this scope + --> $DIR/format-args-capture-issue-102057.rs:9:22 + | +LL | format!("\x7Ba} {b}"); + | ^ help: a local variable with a similar name exists: `a` + +error[E0425]: cannot find value `b` in this scope + --> $DIR/format-args-capture-issue-102057.rs:11:25 + | +LL | format!("\x7Ba\x7D {b}"); + | ^ help: a local variable with a similar name exists: `a` + +error[E0425]: cannot find value `b` in this scope + --> $DIR/format-args-capture-issue-102057.rs:13:25 + | +LL | format!("\x7Ba} \x7Bb}"); + | ^ help: a local variable with a similar name exists: `a` + +error[E0425]: cannot find value `b` in this scope + --> $DIR/format-args-capture-issue-102057.rs:15:28 + | +LL | format!("\x7Ba\x7D \x7Bb}"); + | ^ help: a local variable with a similar name exists: `a` + +error[E0425]: cannot find value `b` in this scope + --> $DIR/format-args-capture-issue-102057.rs:17:28 + | +LL | format!("\x7Ba\x7D \x7Bb\x7D"); + | ^ help: a local variable with a similar name exists: `a` + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0425`. From b707eff5cc8780b535b0d2f170fe886f927c5082 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 28 Sep 2022 14:33:56 -0700 Subject: [PATCH 3/8] rustdoc: cut margin-top from first header in docblock Fixes a regression caused by 8846c0853d8687fda0e5f23f6687b03b243980ee, where a header's top margin used to be collapsed, but isn't any more. --- src/librustdoc/html/static/css/rustdoc.css | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 0ea6d9c38b6..6e0fe9fb48e 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -138,6 +138,13 @@ h1, h2, h3, h4 { .docblock h3, .docblock h4, h5, h6 { margin: 15px 0 5px 0; } +.docblock > h2:first-child, +.docblock > h3:first-child, +.docblock > h4:first-child, +.docblock > h5:first-child, +.docblock > h6:first-child { + margin-top: 0; +} h1.fqn { margin: 0; padding: 0; From 3f21f07e72eeb8dabdcf76bfda00028d607632d5 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 28 Sep 2022 14:47:56 -0700 Subject: [PATCH 4/8] rustdoc: remove bad CSS font-weight on `.impl`, `.method`, etc This line was added in c494a06064017f307a8d9dc4797e614d2ed99143, because at the time, the headers had these classes on them. Now, the headers are children of the `
` with the class on it. This commit also adds a test case, to make sure the srclink font weight does not regress again. --- src/librustdoc/html/static/css/rustdoc.css | 1 - src/test/rustdoc-gui/anchor-navigable.goml | 2 +- src/test/rustdoc-gui/font-weight.goml | 4 ++-- src/test/rustdoc-gui/src-font-size.goml | 8 ++++---- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 0ea6d9c38b6..06d5829317c 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -187,7 +187,6 @@ h4.code-header { .impl-items .associatedtype, .methods .associatedtype { flex-basis: 100%; - font-weight: 600; position: relative; } diff --git a/src/test/rustdoc-gui/anchor-navigable.goml b/src/test/rustdoc-gui/anchor-navigable.goml index 424c312233b..14653f0bfc7 100644 --- a/src/test/rustdoc-gui/anchor-navigable.goml +++ b/src/test/rustdoc-gui/anchor-navigable.goml @@ -7,5 +7,5 @@ goto: file://|DOC_PATH|/test_docs/struct.Foo.html // We check that ".item-info" is bigger than its content. move-cursor-to: ".impl" -assert-property: (".impl > a.anchor", {"offsetWidth": "9"}) +assert-property: (".impl > a.anchor", {"offsetWidth": "8"}) assert-css: (".impl > a.anchor", {"left": "-8px"}) diff --git a/src/test/rustdoc-gui/font-weight.goml b/src/test/rustdoc-gui/font-weight.goml index 13e8ec9fb16..d5c934551a5 100644 --- a/src/test/rustdoc-gui/font-weight.goml +++ b/src/test/rustdoc-gui/font-weight.goml @@ -13,7 +13,7 @@ goto: file://|DOC_PATH|/test_docs/type.SomeType.html assert-css: (".top-doc .docblock p", {"font-weight": "400"}, ALL) goto: file://|DOC_PATH|/test_docs/struct.Foo.html -assert-css: (".impl-items .method", {"font-weight": "600"}, ALL) +assert-css: (".impl-items .method > .code-header", {"font-weight": "600"}, ALL) goto: file://|DOC_PATH|/lib2/trait.Trait.html @@ -41,4 +41,4 @@ assert-count: (".methods .associatedtype", 1) assert-css: (".methods .associatedtype", {"font-weight": "600"}) assert-count: (".methods .constant", 1) assert-css: (".methods .constant", {"font-weight": "600"}) -assert-css: (".methods .method", {"font-weight": "600"}) +assert-css: (".methods .method > .code-header", {"font-weight": "600"}) diff --git a/src/test/rustdoc-gui/src-font-size.goml b/src/test/rustdoc-gui/src-font-size.goml index 9797f196c55..ebb413b8c41 100644 --- a/src/test/rustdoc-gui/src-font-size.goml +++ b/src/test/rustdoc-gui/src-font-size.goml @@ -4,8 +4,8 @@ goto: file://|DOC_PATH|/test_docs/struct.Foo.html show-text: true // Check the impl headers. -assert-css: (".impl.has-srclink .srclink", {"font-size": "16px"}, ALL) -assert-css: (".impl.has-srclink .code-header", {"font-size": "18px"}, ALL) +assert-css: (".impl.has-srclink .srclink", {"font-size": "16px", "font-weight": 400}, ALL) +assert-css: (".impl.has-srclink .code-header", {"font-size": "18px", "font-weight": 600}, ALL) // Check the impl items. -assert-css: (".impl-items .has-srclink .srclink", {"font-size": "16px"}, ALL) -assert-css: (".impl-items .has-srclink .code-header", {"font-size": "16px"}, ALL) +assert-css: (".impl-items .has-srclink .srclink", {"font-size": "16px", "font-weight": 400}, ALL) +assert-css: (".impl-items .has-srclink .code-header", {"font-size": "16px", "font-weight": 600}, ALL) From 0b9b4b70683db6ef707755f520f139eb7b92a944 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 28 Sep 2022 17:38:25 -0700 Subject: [PATCH 5/8] rustdoc: add method spacing to trait methods More cleanup for 8846c0853d8687fda0e5f23f6687b03b243980ee, this time in trait layouts when things are collapsed. --- src/librustdoc/html/render/print_item.rs | 2 +- src/librustdoc/html/static/css/rustdoc.css | 3 ++- src/test/rustdoc/toggle-trait-fn.rs | 12 ++++++------ 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 3e324bbb069..9f6b6b52536 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -716,7 +716,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: document(&mut content, cx, m, Some(t), HeadingOffset::H5); let toggled = !content.is_empty(); if toggled { - write!(w, "
"); + write!(w, "
"); } write!(w, "
", id); render_rightside(w, cx, m, t, RenderMode::Normal); diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 0ea6d9c38b6..ebac83315bb 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -2011,7 +2011,8 @@ in storage.js plus the media query with (min-width: 701px) .method-toggle summary, .implementors-toggle summary, -.impl { +.impl, +#implementors-list > .docblock { margin-bottom: 0.75em; } diff --git a/src/test/rustdoc/toggle-trait-fn.rs b/src/test/rustdoc/toggle-trait-fn.rs index 65e8daeb066..e41422ce7c5 100644 --- a/src/test/rustdoc/toggle-trait-fn.rs +++ b/src/test/rustdoc/toggle-trait-fn.rs @@ -4,12 +4,12 @@ // summary. Trait methods with no documentation should not be wrapped. // // @has foo/trait.Foo.html -// @has - '//details[@class="rustdoc-toggle"]//summary//h4[@class="code-header"]' 'is_documented()' -// @!has - '//details[@class="rustdoc-toggle"]//summary//h4[@class="code-header"]' 'not_documented()' -// @has - '//details[@class="rustdoc-toggle"]//*[@class="docblock"]' 'is_documented is documented' -// @has - '//details[@class="rustdoc-toggle"]//summary//h4[@class="code-header"]' 'is_documented_optional()' -// @!has - '//details[@class="rustdoc-toggle"]//summary//h4[@class="code-header"]' 'not_documented_optional()' -// @has - '//details[@class="rustdoc-toggle"]//*[@class="docblock"]' 'is_documented_optional is documented' +// @has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'is_documented()' +// @!has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'not_documented()' +// @has - '//details[@class="rustdoc-toggle method-toggle"]//*[@class="docblock"]' 'is_documented is documented' +// @has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'is_documented_optional()' +// @!has - '//details[@class="rustdoc-toggle method-toggle"]//summary//h4[@class="code-header"]' 'not_documented_optional()' +// @has - '//details[@class="rustdoc-toggle method-toggle"]//*[@class="docblock"]' 'is_documented_optional is documented' pub trait Foo { fn not_documented(); From 1377bab12e13cdfda89d700641cbf09871245442 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 29 Sep 2022 13:42:57 +0200 Subject: [PATCH 6/8] make tidy dependency error less confusing --- src/tools/tidy/src/deps.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 9aab66b1d21..4f0563140d7 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -327,7 +327,7 @@ pub fn check(root: &Path, cargo: &Path, bad: &mut bool) { check_exceptions(&metadata, EXCEPTIONS, runtime_ids, bad); check_dependencies( &metadata, - "main workspace", + "rustc", PERMITTED_DEPENDENCIES, RESTRICTED_DEPENDENCY_CRATES, bad, From 79ad594488716b36305bd06feb565860812e4d6a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 29 Sep 2022 16:09:14 +0200 Subject: [PATCH 7/8] more clear function and variable names --- src/tools/tidy/src/deps.rs | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 4f0563140d7..d4733107e79 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -73,14 +73,11 @@ const EXCEPTIONS_BOOTSTRAP: &[(&str, &str)] = &[ /// these and all their dependencies *must not* be in the exception list. const RUNTIME_CRATES: &[&str] = &["std", "core", "alloc", "test", "panic_abort", "panic_unwind"]; -/// Crates whose dependencies must be explicitly permitted. -const RESTRICTED_DEPENDENCY_CRATES: &[&str] = &["rustc_driver", "rustc_codegen_llvm"]; - /// Crates rustc is allowed to depend on. Avoid adding to the list if possible. /// /// This list is here to provide a speed-bump to adding a new dependency to /// rustc. Please check with the compiler team before adding an entry. -const PERMITTED_DEPENDENCIES: &[&str] = &[ +const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "addr2line", "adler", "ahash", @@ -307,7 +304,7 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[ ]; const FORBIDDEN_TO_HAVE_DUPLICATES: &[&str] = &[ - // These two crates take quite a long time to build, so don't allow two versions of them + // This crate takes quite a long time to build, so don't allow two versions of them // to accidentally sneak into our dependency graph, in order to ensure we keep our CI times // under control. "cargo", @@ -324,12 +321,12 @@ pub fn check(root: &Path, cargo: &Path, bad: &mut bool) { .features(cargo_metadata::CargoOpt::AllFeatures); let metadata = t!(cmd.exec()); let runtime_ids = compute_runtime_crates(&metadata); - check_exceptions(&metadata, EXCEPTIONS, runtime_ids, bad); - check_dependencies( + check_license_exceptions(&metadata, EXCEPTIONS, runtime_ids, bad); + check_permitted_dependencies( &metadata, "rustc", - PERMITTED_DEPENDENCIES, - RESTRICTED_DEPENDENCY_CRATES, + PERMITTED_RUSTC_DEPENDENCIES, + &["rustc_driver", "rustc_codegen_llvm"], bad, ); check_crate_duplicate(&metadata, FORBIDDEN_TO_HAVE_DUPLICATES, bad); @@ -342,8 +339,8 @@ pub fn check(root: &Path, cargo: &Path, bad: &mut bool) { .features(cargo_metadata::CargoOpt::AllFeatures); let metadata = t!(cmd.exec()); let runtime_ids = HashSet::new(); - check_exceptions(&metadata, EXCEPTIONS_CRANELIFT, runtime_ids, bad); - check_dependencies( + check_license_exceptions(&metadata, EXCEPTIONS_CRANELIFT, runtime_ids, bad); + check_permitted_dependencies( &metadata, "cranelift", PERMITTED_CRANELIFT_DEPENDENCIES, @@ -358,13 +355,13 @@ pub fn check(root: &Path, cargo: &Path, bad: &mut bool) { .features(cargo_metadata::CargoOpt::AllFeatures); let metadata = t!(cmd.exec()); let runtime_ids = HashSet::new(); - check_exceptions(&metadata, EXCEPTIONS_BOOTSTRAP, runtime_ids, bad); + check_license_exceptions(&metadata, EXCEPTIONS_BOOTSTRAP, runtime_ids, bad); } /// Check that all licenses are in the valid list in `LICENSES`. /// -/// Packages listed in `EXCEPTIONS` are allowed for tools. -fn check_exceptions( +/// Packages listed in `exceptions` are allowed for tools. +fn check_license_exceptions( metadata: &Metadata, exceptions: &[(&str, &str)], runtime_ids: HashSet<&PackageId>, @@ -434,11 +431,11 @@ fn check_exceptions( } } -/// Checks the dependency of `RESTRICTED_DEPENDENCY_CRATES` at the given path. Changes `bad` to +/// Checks the dependency of `restricted_dependency_crates` at the given path. Changes `bad` to /// `true` if a check failed. /// -/// Specifically, this checks that the dependencies are on the `PERMITTED_DEPENDENCIES`. -fn check_dependencies( +/// Specifically, this checks that the dependencies are on the `permitted_dependencies`. +fn check_permitted_dependencies( metadata: &Metadata, descr: &str, permitted_dependencies: &[&'static str], From aa3fbf87950ed764f91222be2f7ec0fc1e9b1c91 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 29 Sep 2022 14:29:36 +0000 Subject: [PATCH 8/8] Split out the error reporting logic into a separate function --- .../rustc_hir_analysis/src/check/callee.rs | 274 +++++++++--------- 1 file changed, 140 insertions(+), 134 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/callee.rs b/compiler/rustc_hir_analysis/src/check/callee.rs index c82a31e65cf..080771844a4 100644 --- a/compiler/rustc_hir_analysis/src/check/callee.rs +++ b/compiler/rustc_hir_analysis/src/check/callee.rs @@ -394,140 +394,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } ty::FnPtr(sig) => (sig, None), _ => { - let mut unit_variant = None; - if let hir::ExprKind::Path(qpath) = &callee_expr.kind - && let Res::Def(def::DefKind::Ctor(kind, def::CtorKind::Const), _) - = self.typeck_results.borrow().qpath_res(qpath, callee_expr.hir_id) - // Only suggest removing parens if there are no arguments - && arg_exprs.is_empty() - { - let descr = match kind { - def::CtorOf::Struct => "struct", - def::CtorOf::Variant => "enum variant", - }; - let removal_span = - callee_expr.span.shrink_to_hi().to(call_expr.span.shrink_to_hi()); - unit_variant = - Some((removal_span, descr, rustc_hir_pretty::qpath_to_string(qpath))); - } - - let callee_ty = self.resolve_vars_if_possible(callee_ty); - let mut err = type_error_struct!( - self.tcx.sess, - callee_expr.span, - callee_ty, - E0618, - "expected function, found {}", - match &unit_variant { - Some((_, kind, path)) => format!("{kind} `{path}`"), - None => format!("`{callee_ty}`"), - } - ); - - self.identify_bad_closure_def_and_call( - &mut err, - call_expr.hir_id, - &callee_expr.kind, - callee_expr.span, - ); - - if let Some((removal_span, kind, path)) = &unit_variant { - err.span_suggestion_verbose( - *removal_span, - &format!( - "`{path}` is a unit {kind}, and does not take parentheses to be constructed", - ), - "", - Applicability::MachineApplicable, - ); - } - - let mut inner_callee_path = None; - let def = match callee_expr.kind { - hir::ExprKind::Path(ref qpath) => { - self.typeck_results.borrow().qpath_res(qpath, callee_expr.hir_id) - } - hir::ExprKind::Call(ref inner_callee, _) => { - // If the call spans more than one line and the callee kind is - // itself another `ExprCall`, that's a clue that we might just be - // missing a semicolon (Issue #51055) - let call_is_multiline = - self.tcx.sess.source_map().is_multiline(call_expr.span); - if call_is_multiline { - err.span_suggestion( - callee_expr.span.shrink_to_hi(), - "consider using a semicolon here", - ";", - Applicability::MaybeIncorrect, - ); - } - if let hir::ExprKind::Path(ref inner_qpath) = inner_callee.kind { - inner_callee_path = Some(inner_qpath); - self.typeck_results.borrow().qpath_res(inner_qpath, inner_callee.hir_id) - } else { - Res::Err - } - } - _ => Res::Err, - }; - - if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) { - if let Some((maybe_def, output_ty, _)) = self.extract_callable_info(callee_expr, callee_ty) - && !self.type_is_sized_modulo_regions(self.param_env, output_ty, callee_expr.span) - { - let descr = match maybe_def { - DefIdOrName::DefId(def_id) => self.tcx.def_kind(def_id).descr(def_id), - DefIdOrName::Name(name) => name, - }; - err.span_label( - callee_expr.span, - format!("this {descr} returns an unsized value `{output_ty}`, so it cannot be called") - ); - if let DefIdOrName::DefId(def_id) = maybe_def - && let Some(def_span) = self.tcx.hir().span_if_local(def_id) - { - err.span_label(def_span, "the callable type is defined here"); - } - } else { - err.span_label(call_expr.span, "call expression requires function"); - } - } - - if let Some(span) = self.tcx.hir().res_span(def) { - let callee_ty = callee_ty.to_string(); - let label = match (unit_variant, inner_callee_path) { - (Some((_, kind, path)), _) => Some(format!("{kind} `{path}` defined here")), - (_, Some(hir::QPath::Resolved(_, path))) => self - .tcx - .sess - .source_map() - .span_to_snippet(path.span) - .ok() - .map(|p| format!("`{p}` defined here returns `{callee_ty}`")), - _ => { - match def { - // Emit a different diagnostic for local variables, as they are not - // type definitions themselves, but rather variables *of* that type. - Res::Local(hir_id) => Some(format!( - "`{}` has type `{}`", - self.tcx.hir().name(hir_id), - callee_ty - )), - Res::Def(kind, def_id) if kind.ns() == Some(Namespace::ValueNS) => { - Some(format!( - "`{}` defined here", - self.tcx.def_path_str(def_id), - )) - } - _ => Some(format!("`{callee_ty}` defined here")), - } - } - }; - if let Some(label) = label { - err.span_label(span, label); - } - } - err.emit(); + self.report_invalid_callee(call_expr, callee_expr, callee_ty, arg_exprs); // This is the "default" function signature, used in case of error. // In that case, we check each argument against "error" in order to @@ -574,6 +441,145 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn_sig.output() } + fn report_invalid_callee( + &self, + call_expr: &'tcx hir::Expr<'tcx>, + callee_expr: &'tcx hir::Expr<'tcx>, + callee_ty: Ty<'tcx>, + arg_exprs: &'tcx [hir::Expr<'tcx>], + ) { + let mut unit_variant = None; + if let hir::ExprKind::Path(qpath) = &callee_expr.kind + && let Res::Def(def::DefKind::Ctor(kind, def::CtorKind::Const), _) + = self.typeck_results.borrow().qpath_res(qpath, callee_expr.hir_id) + // Only suggest removing parens if there are no arguments + && arg_exprs.is_empty() + { + let descr = match kind { + def::CtorOf::Struct => "struct", + def::CtorOf::Variant => "enum variant", + }; + let removal_span = + callee_expr.span.shrink_to_hi().to(call_expr.span.shrink_to_hi()); + unit_variant = + Some((removal_span, descr, rustc_hir_pretty::qpath_to_string(qpath))); + } + + let callee_ty = self.resolve_vars_if_possible(callee_ty); + let mut err = type_error_struct!( + self.tcx.sess, + callee_expr.span, + callee_ty, + E0618, + "expected function, found {}", + match &unit_variant { + Some((_, kind, path)) => format!("{kind} `{path}`"), + None => format!("`{callee_ty}`"), + } + ); + + self.identify_bad_closure_def_and_call( + &mut err, + call_expr.hir_id, + &callee_expr.kind, + callee_expr.span, + ); + + if let Some((removal_span, kind, path)) = &unit_variant { + err.span_suggestion_verbose( + *removal_span, + &format!( + "`{path}` is a unit {kind}, and does not take parentheses to be constructed", + ), + "", + Applicability::MachineApplicable, + ); + } + + let mut inner_callee_path = None; + let def = match callee_expr.kind { + hir::ExprKind::Path(ref qpath) => { + self.typeck_results.borrow().qpath_res(qpath, callee_expr.hir_id) + } + hir::ExprKind::Call(ref inner_callee, _) => { + // If the call spans more than one line and the callee kind is + // itself another `ExprCall`, that's a clue that we might just be + // missing a semicolon (Issue #51055) + let call_is_multiline = self.tcx.sess.source_map().is_multiline(call_expr.span); + if call_is_multiline { + err.span_suggestion( + callee_expr.span.shrink_to_hi(), + "consider using a semicolon here", + ";", + Applicability::MaybeIncorrect, + ); + } + if let hir::ExprKind::Path(ref inner_qpath) = inner_callee.kind { + inner_callee_path = Some(inner_qpath); + self.typeck_results.borrow().qpath_res(inner_qpath, inner_callee.hir_id) + } else { + Res::Err + } + } + _ => Res::Err, + }; + + if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) { + if let Some((maybe_def, output_ty, _)) = self.extract_callable_info(callee_expr, callee_ty) + && !self.type_is_sized_modulo_regions(self.param_env, output_ty, callee_expr.span) + { + let descr = match maybe_def { + DefIdOrName::DefId(def_id) => self.tcx.def_kind(def_id).descr(def_id), + DefIdOrName::Name(name) => name, + }; + err.span_label( + callee_expr.span, + format!("this {descr} returns an unsized value `{output_ty}`, so it cannot be called") + ); + if let DefIdOrName::DefId(def_id) = maybe_def + && let Some(def_span) = self.tcx.hir().span_if_local(def_id) + { + err.span_label(def_span, "the callable type is defined here"); + } + } else { + err.span_label(call_expr.span, "call expression requires function"); + } + } + + if let Some(span) = self.tcx.hir().res_span(def) { + let callee_ty = callee_ty.to_string(); + let label = match (unit_variant, inner_callee_path) { + (Some((_, kind, path)), _) => Some(format!("{kind} `{path}` defined here")), + (_, Some(hir::QPath::Resolved(_, path))) => self + .tcx + .sess + .source_map() + .span_to_snippet(path.span) + .ok() + .map(|p| format!("`{p}` defined here returns `{callee_ty}`")), + _ => { + match def { + // Emit a different diagnostic for local variables, as they are not + // type definitions themselves, but rather variables *of* that type. + Res::Local(hir_id) => Some(format!( + "`{}` has type `{}`", + self.tcx.hir().name(hir_id), + callee_ty + )), + Res::Def(kind, def_id) if kind.ns() == Some(Namespace::ValueNS) => { + Some(format!("`{}` defined here", self.tcx.def_path_str(def_id),)) + } + _ => Some(format!("`{callee_ty}` defined here")), + } + } + }; + if let Some(label) = label { + err.span_label(span, label); + } + } + err.emit(); + } + fn confirm_deferred_closure_call( &self, call_expr: &'tcx hir::Expr<'tcx>,