From cdbe8e5d281dfecaa3621dc32b1507b4901aef58 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 1 Oct 2024 17:07:33 +0200 Subject: [PATCH 01/10] Remove usage of `allow(unused)` attribute on `no_run` doctests --- src/librustdoc/doctest/runner.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/librustdoc/doctest/runner.rs b/src/librustdoc/doctest/runner.rs index 326ca4ee1e68f..3d0db4d11eb7a 100644 --- a/src/librustdoc/doctest/runner.rs +++ b/src/librustdoc/doctest/runner.rs @@ -208,10 +208,6 @@ fn generate_mergeable_doctest( } else { writeln!(output, "mod {test_id} {{\n{}{}", doctest.crates, doctest.maybe_crate_attrs) .unwrap(); - if scraped_test.langstr.no_run { - // To prevent having warnings about unused items since they're not called. - writeln!(output, "#![allow(unused)]").unwrap(); - } if doctest.has_main_fn { output.push_str(&doctest.everything_else); } else { From b073ddcce51aafde86e888d27c640f6d506e0d9d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 1 Oct 2024 17:08:01 +0200 Subject: [PATCH 02/10] Add regression tests for #130681 --- tests/rustdoc-ui/doctest/dead-code-2024.rs | 15 ++++++++++ .../rustdoc-ui/doctest/dead-code-2024.stdout | 29 +++++++++++++++++++ tests/rustdoc-ui/doctest/dead-code.rs | 15 ++++++++++ tests/rustdoc-ui/doctest/dead-code.stdout | 29 +++++++++++++++++++ 4 files changed, 88 insertions(+) create mode 100644 tests/rustdoc-ui/doctest/dead-code-2024.rs create mode 100644 tests/rustdoc-ui/doctest/dead-code-2024.stdout create mode 100644 tests/rustdoc-ui/doctest/dead-code.rs create mode 100644 tests/rustdoc-ui/doctest/dead-code.stdout diff --git a/tests/rustdoc-ui/doctest/dead-code-2024.rs b/tests/rustdoc-ui/doctest/dead-code-2024.rs new file mode 100644 index 0000000000000..4c77112e61a6b --- /dev/null +++ b/tests/rustdoc-ui/doctest/dead-code-2024.rs @@ -0,0 +1,15 @@ +// This test ensures that the 2024 edition merged doctest will not use `#[allow(unused)]`. + +//@ compile-flags:--test -Zunstable-options --edition 2024 +//@ normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout-test: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ failure-status: 101 + +#![doc(test(attr(allow(unused_variables), deny(warnings))))] + +/// Example +/// +/// ```rust,no_run +/// trait T { fn f(); } +/// ``` +pub fn f() {} diff --git a/tests/rustdoc-ui/doctest/dead-code-2024.stdout b/tests/rustdoc-ui/doctest/dead-code-2024.stdout new file mode 100644 index 0000000000000..69dd4e2ede1ac --- /dev/null +++ b/tests/rustdoc-ui/doctest/dead-code-2024.stdout @@ -0,0 +1,29 @@ + +running 1 test +test $DIR/dead-code-2024.rs - f (line 12) - compile ... FAILED + +failures: + +---- $DIR/dead-code-2024.rs - f (line 12) stdout ---- +error: trait `T` is never used + --> $DIR/dead-code-2024.rs:13:7 + | +LL | trait T { fn f(); } + | ^ + | +note: the lint level is defined here + --> $DIR/dead-code-2024.rs:11:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(dead_code)]` implied by `#[deny(warnings)]` + +error: aborting due to 1 previous error + +Couldn't compile the test. + +failures: + $DIR/dead-code-2024.rs - f (line 12) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/doctest/dead-code.rs b/tests/rustdoc-ui/doctest/dead-code.rs new file mode 100644 index 0000000000000..cb9b4c28f6ce5 --- /dev/null +++ b/tests/rustdoc-ui/doctest/dead-code.rs @@ -0,0 +1,15 @@ +// This test ensures that the doctest will not use `#[allow(unused)]`. + +//@ compile-flags:--test +//@ normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout-test: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ failure-status: 101 + +#![doc(test(attr(allow(unused_variables), deny(warnings))))] + +/// Example +/// +/// ```rust,no_run +/// trait T { fn f(); } +/// ``` +pub fn f() {} diff --git a/tests/rustdoc-ui/doctest/dead-code.stdout b/tests/rustdoc-ui/doctest/dead-code.stdout new file mode 100644 index 0000000000000..38d15d5c1bc6f --- /dev/null +++ b/tests/rustdoc-ui/doctest/dead-code.stdout @@ -0,0 +1,29 @@ + +running 1 test +test $DIR/dead-code.rs - f (line 12) - compile ... FAILED + +failures: + +---- $DIR/dead-code.rs - f (line 12) stdout ---- +error: trait `T` is never used + --> $DIR/dead-code.rs:13:7 + | +LL | trait T { fn f(); } + | ^ + | +note: the lint level is defined here + --> $DIR/dead-code.rs:11:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(dead_code)]` implied by `#[deny(warnings)]` + +error: aborting due to 1 previous error + +Couldn't compile the test. + +failures: + $DIR/dead-code.rs - f (line 12) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + From 744eb2f9372dfe9c4de9faeac27c986fb5c5fb10 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 30 Oct 2024 13:12:03 +1100 Subject: [PATCH 03/10] Rename `BlockFormatter::results` as `BlockFormatter::cursor`. Because it's a `ResultsCursor`, not a `Results`. I find this easier to read and understand. --- .../src/framework/graphviz.rs | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index 96a70f4fa5b0c..58bec4b8bb21f 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -96,13 +96,13 @@ where // the value with `None`, move it into the results cursor, move it // back out, and return it to the refcell wrapped in `Some`. let mut fmt = BlockFormatter { - results: results.take().unwrap().into_results_cursor(self.body), + cursor: results.take().unwrap().into_results_cursor(self.body), style: self.style, bg: Background::Light, }; fmt.write_node_label(&mut label, *block).unwrap(); - Some(fmt.results.into_results()) + Some(fmt.cursor.into_results()) }); dot::LabelText::html(String::from_utf8(label).unwrap()) } @@ -155,7 +155,7 @@ struct BlockFormatter<'mir, 'tcx, A> where A: Analysis<'tcx>, { - results: ResultsCursor<'mir, 'tcx, A>, + cursor: ResultsCursor<'mir, 'tcx, A>, bg: Background, style: OutputStyle, } @@ -219,8 +219,8 @@ where // C: State at start of block self.bg = Background::Light; - self.results.seek_to_block_start(block); - let block_start_state = self.results.get().clone(); + self.cursor.seek_to_block_start(block); + let block_start_state = self.cursor.get().clone(); self.write_row_with_full_state(w, "", "(on start)")?; // D + E: Statement and terminator transfer functions @@ -228,12 +228,12 @@ where // F: State at end of block - let terminator = self.results.body()[block].terminator(); + let terminator = self.cursor.body()[block].terminator(); // Write the full dataflow state immediately after the terminator if it differs from the // state at block entry. - self.results.seek_to_block_end(block); - if self.results.get() != &block_start_state || A::Direction::IS_BACKWARD { + self.cursor.seek_to_block_end(block); + if self.cursor.get() != &block_start_state || A::Direction::IS_BACKWARD { let after_terminator_name = match terminator.kind { mir::TerminatorKind::Call { target: Some(_), .. } => "(on unwind)", _ => "(on end)", @@ -250,8 +250,8 @@ where match terminator.kind { mir::TerminatorKind::Call { destination, .. } => { self.write_row(w, "", "(on successful return)", |this, w, fmt| { - let state_on_unwind = this.results.get().clone(); - this.results.apply_custom_effect(|analysis, state| { + let state_on_unwind = this.cursor.get().clone(); + this.cursor.apply_custom_effect(|analysis, state| { analysis.apply_call_return_effect( state, block, @@ -265,9 +265,9 @@ where colspan = this.style.num_state_columns(), fmt = fmt, diff = diff_pretty( - this.results.get(), + this.cursor.get(), &state_on_unwind, - this.results.analysis() + this.cursor.analysis() ), ) })?; @@ -275,8 +275,8 @@ where mir::TerminatorKind::Yield { resume, resume_arg, .. } => { self.write_row(w, "", "(on yield resume)", |this, w, fmt| { - let state_on_coroutine_drop = this.results.get().clone(); - this.results.apply_custom_effect(|analysis, state| { + let state_on_coroutine_drop = this.cursor.get().clone(); + this.cursor.apply_custom_effect(|analysis, state| { analysis.apply_call_return_effect( state, resume, @@ -290,9 +290,9 @@ where colspan = this.style.num_state_columns(), fmt = fmt, diff = diff_pretty( - this.results.get(), + this.cursor.get(), &state_on_coroutine_drop, - this.results.analysis() + this.cursor.analysis() ), ) })?; @@ -302,8 +302,8 @@ where if !targets.is_empty() => { self.write_row(w, "", "(on successful return)", |this, w, fmt| { - let state_on_unwind = this.results.get().clone(); - this.results.apply_custom_effect(|analysis, state| { + let state_on_unwind = this.cursor.get().clone(); + this.cursor.apply_custom_effect(|analysis, state| { analysis.apply_call_return_effect( state, block, @@ -317,9 +317,9 @@ where colspan = this.style.num_state_columns(), fmt = fmt, diff = diff_pretty( - this.results.get(), + this.cursor.get(), &state_on_unwind, - this.results.analysis() + this.cursor.analysis() ), ) })?; @@ -407,9 +407,9 @@ where block: BasicBlock, ) -> io::Result<()> { let diffs = StateDiffCollector::run( - self.results.body(), + self.cursor.body(), block, - self.results.mut_results(), + self.cursor.mut_results(), self.style, ); @@ -420,7 +420,7 @@ where if A::Direction::IS_FORWARD { it.next().unwrap() } else { it.next_back().unwrap() } }; - for (i, statement) in self.results.body()[block].statements.iter().enumerate() { + for (i, statement) in self.cursor.body()[block].statements.iter().enumerate() { let statement_str = format!("{statement:?}"); let index_str = format!("{i}"); @@ -442,7 +442,7 @@ where assert!(diffs_after.is_empty()); assert!(diffs_before.as_ref().map_or(true, ExactSizeIterator::is_empty)); - let terminator = self.results.body()[block].terminator(); + let terminator = self.cursor.body()[block].terminator(); let mut terminator_str = String::new(); terminator.kind.fmt_head(&mut terminator_str).unwrap(); @@ -492,8 +492,8 @@ where mir: &str, ) -> io::Result<()> { self.write_row(w, i, mir, |this, w, fmt| { - let state = this.results.get(); - let analysis = this.results.analysis(); + let state = this.cursor.get(); + let analysis = this.cursor.analysis(); // FIXME: The full state vector can be quite long. It would be nice to split on commas // and use some text wrapping algorithm. From a8ce44f7d9921f4ae1e620016c22f2a0ac6d8753 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 30 Oct 2024 13:12:25 +1100 Subject: [PATCH 04/10] Simplify `graphviz::Formatter`. `Formatter` currently has a `RefCell>` field. This is so the `Results` can be temporarily taken and put into a `ResultsCursor` that is used by `BlockFormatter`, and then put back, which is messy. This commit changes `Formatter` to have a `RefCell` and `BlockFormatter` to have a `&mut ResultsCursor`, which greatly simplifies the code at the `Formatter`/`BlockFormatter` interaction point in `Formatter::node_label`. It also means we construct a `ResultsCursor` once per `Formatter`, instead of once per `node_label` call. The commit also: - documents the reason for the `RefCell`; - adds a `Formatter::body` method, replacing the `Formatter::body` field. --- .../src/framework/graphviz.rs | 53 +++++++++---------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index 58bec4b8bb21f..5785964de21f4 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -32,8 +32,11 @@ pub(crate) struct Formatter<'mir, 'tcx, A> where A: Analysis<'tcx>, { - body: &'mir Body<'tcx>, - results: RefCell>>, + // The `RefCell` is used because `::node_label` + // takes `&self`, but it needs to modify the cursor. This is also the + // reason for the `Formatter`/`BlockFormatter` split; `BlockFormatter` has + // the operations that involve the mutation, i.e. within the `borrow_mut`. + cursor: RefCell>, style: OutputStyle, reachable: BitSet, } @@ -48,11 +51,15 @@ where style: OutputStyle, ) -> Self { let reachable = mir::traversal::reachable_as_bitset(body); - Formatter { body, results: Some(results).into(), style, reachable } + Formatter { cursor: results.into_results_cursor(body).into(), style, reachable } + } + + fn body(&self) -> &'mir Body<'tcx> { + self.cursor.borrow().body() } pub(crate) fn into_results(self) -> Results<'tcx, A> { - self.results.into_inner().unwrap() + self.cursor.into_inner().into_results() } } @@ -81,7 +88,7 @@ where type Edge = CfgEdge; fn graph_id(&self) -> dot::Id<'_> { - let name = graphviz_safe_def_name(self.body.source.def_id()); + let name = graphviz_safe_def_name(self.body().source.def_id()); dot::Id::new(format!("graph_for_def_id_{name}")).unwrap() } @@ -91,19 +98,11 @@ where fn node_label(&self, block: &Self::Node) -> dot::LabelText<'_> { let mut label = Vec::new(); - self.results.replace_with(|results| { - // `Formatter::result` is a `RefCell>` so we can replace - // the value with `None`, move it into the results cursor, move it - // back out, and return it to the refcell wrapped in `Some`. - let mut fmt = BlockFormatter { - cursor: results.take().unwrap().into_results_cursor(self.body), - style: self.style, - bg: Background::Light, - }; + let mut cursor = self.cursor.borrow_mut(); + let mut fmt = + BlockFormatter { cursor: &mut cursor, style: self.style, bg: Background::Light }; + fmt.write_node_label(&mut label, *block).unwrap(); - fmt.write_node_label(&mut label, *block).unwrap(); - Some(fmt.cursor.into_results()) - }); dot::LabelText::html(String::from_utf8(label).unwrap()) } @@ -112,12 +111,12 @@ where } fn edge_label(&self, e: &Self::Edge) -> dot::LabelText<'_> { - let label = &self.body[e.source].terminator().kind.fmt_successor_labels()[e.index]; + let label = &self.body()[e.source].terminator().kind.fmt_successor_labels()[e.index]; dot::LabelText::label(label.clone()) } } -impl<'mir, 'tcx, A> dot::GraphWalk<'mir> for Formatter<'mir, 'tcx, A> +impl<'tcx, A> dot::GraphWalk<'_> for Formatter<'_, 'tcx, A> where A: Analysis<'tcx>, { @@ -125,7 +124,7 @@ where type Edge = CfgEdge; fn nodes(&self) -> dot::Nodes<'_, Self::Node> { - self.body + self.body() .basic_blocks .indices() .filter(|&idx| self.reachable.contains(idx)) @@ -134,10 +133,10 @@ where } fn edges(&self) -> dot::Edges<'_, Self::Edge> { - self.body - .basic_blocks + let body = self.body(); + body.basic_blocks .indices() - .flat_map(|bb| dataflow_successors(self.body, bb)) + .flat_map(|bb| dataflow_successors(body, bb)) .collect::>() .into() } @@ -147,20 +146,20 @@ where } fn target(&self, edge: &Self::Edge) -> Self::Node { - self.body[edge.source].terminator().successors().nth(edge.index).unwrap() + self.body()[edge.source].terminator().successors().nth(edge.index).unwrap() } } -struct BlockFormatter<'mir, 'tcx, A> +struct BlockFormatter<'a, 'mir, 'tcx, A> where A: Analysis<'tcx>, { - cursor: ResultsCursor<'mir, 'tcx, A>, + cursor: &'a mut ResultsCursor<'mir, 'tcx, A>, bg: Background, style: OutputStyle, } -impl<'mir, 'tcx, A> BlockFormatter<'mir, 'tcx, A> +impl<'tcx, A> BlockFormatter<'_, '_, 'tcx, A> where A: Analysis<'tcx>, A::Domain: DebugWithContext, From d921be92a459b41f0ba2d5b97e32397902f37294 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 30 Oct 2024 13:21:32 +1100 Subject: [PATCH 05/10] Return label from `write_node_label`. Instead of appending an empty label. Because it's conceptually simpler. --- .../rustc_mir_dataflow/src/framework/graphviz.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index 5785964de21f4..bac75b972f9b1 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -97,11 +97,10 @@ where } fn node_label(&self, block: &Self::Node) -> dot::LabelText<'_> { - let mut label = Vec::new(); let mut cursor = self.cursor.borrow_mut(); let mut fmt = BlockFormatter { cursor: &mut cursor, style: self.style, bg: Background::Light }; - fmt.write_node_label(&mut label, *block).unwrap(); + let label = fmt.write_node_label(*block).unwrap(); dot::LabelText::html(String::from_utf8(label).unwrap()) } @@ -172,7 +171,9 @@ where bg } - fn write_node_label(&mut self, w: &mut impl io::Write, block: BasicBlock) -> io::Result<()> { + fn write_node_label(&mut self, block: BasicBlock) -> io::Result> { + use std::io::Write; + // Sample output: // +-+-----------------------------------------------+ // A | bb4 | @@ -199,6 +200,9 @@ where // attributes. Make sure to test the output before trying to remove the redundancy. // Notably, `align` was found to have no effect when applied only to . + let mut v = vec![]; + let w = &mut v; + let table_fmt = concat!( " border=\"1\"", " cellborder=\"1\"", @@ -327,7 +331,9 @@ where _ => {} }; - write!(w, "
") + write!(w, "")?; + + Ok(v) } fn write_block_header_simple( From e419b3d1ec234d428a00c9d6a8527ec4f6dc7e1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= <39484203+jieyouxu@users.noreply.github.com> Date: Tue, 29 Oct 2024 16:10:05 +0800 Subject: [PATCH 06/10] compiletest: improve robustness of LLVM version handling --- Cargo.lock | 1 + src/tools/compiletest/Cargo.toml | 1 + src/tools/compiletest/src/common.rs | 3 +- src/tools/compiletest/src/header.rs | 112 ++++++++++++++-------- src/tools/compiletest/src/header/tests.rs | 78 ++++++++++++--- src/tools/compiletest/src/lib.rs | 2 +- src/tools/compiletest/src/tests.rs | 13 --- 7 files changed, 140 insertions(+), 70 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 22b3e8280d620..fc16ccf0a6793 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -720,6 +720,7 @@ dependencies = [ "miropt-test-tools", "regex", "rustfix", + "semver", "serde", "serde_json", "tracing", diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index b6a89dd49e615..cef6b525a7bc5 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -18,6 +18,7 @@ build_helper = { path = "../build_helper" } tracing = "0.1" tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] } regex = "1.0" +semver = { version = "1.0.23", features = ["serde"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" rustfix = "0.8.1" diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 69ac4644941d9..e82b88eef7985 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -7,6 +7,7 @@ use std::sync::OnceLock; use std::{fmt, iter}; use build_helper::git::GitConfig; +use semver::Version; use serde::de::{Deserialize, Deserializer, Error as _}; use test::{ColorConfig, OutputFormat}; @@ -298,7 +299,7 @@ pub struct Config { pub lldb_version: Option, /// Version of LLVM - pub llvm_version: Option, + pub llvm_version: Option, /// Is LLVM a system LLVM pub system_llvm: bool, diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index a3bf36c0e9085..bfcdd747eb444 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -6,6 +6,7 @@ use std::io::prelude::*; use std::path::{Path, PathBuf}; use std::process::Command; +use semver::Version; use tracing::*; use crate::common::{Config, Debugger, FailMode, Mode, PassMode}; @@ -1113,26 +1114,39 @@ fn parse_normalize_rule(header: &str) -> Option<(String, String)> { Some((regex, replacement)) } -pub fn extract_llvm_version(version: &str) -> Option { - let pat = |c: char| !c.is_ascii_digit() && c != '.'; - let version_without_suffix = match version.find(pat) { - Some(pos) => &version[..pos], +/// Given an llvm version string that looks like `1.2.3-rc1`, extract as semver. Note that this +/// accepts more than just strict `semver` syntax (as in `major.minor.patch`); this permits omitting +/// minor and patch version components so users can write e.g. `//@ min-llvm-version: 19` instead of +/// having to write `//@ min-llvm-version: 19.0.0`. +/// +/// Currently panics if the input string is malformed, though we really should not use panic as an +/// error handling strategy. +/// +/// FIXME(jieyouxu): improve error handling +pub fn extract_llvm_version(version: &str) -> Version { + // The version substring we're interested in usually looks like the `1.2.3`, without any of the + // fancy suffix like `-rc1` or `meow`. + let version = version.trim(); + let uninterested = |c: char| !c.is_ascii_digit() && c != '.'; + let version_without_suffix = match version.split_once(uninterested) { + Some((prefix, _suffix)) => prefix, None => version, }; - let components: Vec = version_without_suffix + + let components: Vec = version_without_suffix .split('.') - .map(|s| s.parse().expect("Malformed version component")) + .map(|s| s.parse().expect("llvm version component should consist of only digits")) .collect(); - let version = match *components { - [a] => a * 10_000, - [a, b] => a * 10_000 + b * 100, - [a, b, c] => a * 10_000 + b * 100 + c, - _ => panic!("Malformed version"), - }; - Some(version) + + match &components[..] { + [major] => Version::new(*major, 0, 0), + [major, minor] => Version::new(*major, *minor, 0), + [major, minor, patch] => Version::new(*major, *minor, *patch), + _ => panic!("malformed llvm version string, expected only 1-3 components: {version}"), + } } -pub fn extract_llvm_version_from_binary(binary_path: &str) -> Option { +pub fn extract_llvm_version_from_binary(binary_path: &str) -> Option { let output = Command::new(binary_path).arg("--version").output().ok()?; if !output.status.success() { return None; @@ -1140,7 +1154,7 @@ pub fn extract_llvm_version_from_binary(binary_path: &str) -> Option { let version = String::from_utf8(output.stdout).ok()?; for line in version.lines() { if let Some(version) = line.split("LLVM version ").nth(1) { - return extract_llvm_version(version); + return Some(extract_llvm_version(version)); } } None @@ -1247,15 +1261,17 @@ pub fn llvm_has_libzstd(config: &Config) -> bool { false } -/// Takes a directive of the form `" [- ]"`, -/// returns the numeric representation of `` and `` as -/// tuple: `( as u32, as u32)`. +/// Takes a directive of the form `" [- ]"`, returns the numeric representation +/// of `` and `` as tuple: `(, )`. /// -/// If the `` part is omitted, the second component of the tuple -/// is the same as ``. -fn extract_version_range(line: &str, parse: F) -> Option<(u32, u32)> +/// If the `` part is omitted, the second component of the tuple is the same as +/// ``. +fn extract_version_range<'a, F, VersionTy: Clone>( + line: &'a str, + parse: F, +) -> Option<(VersionTy, VersionTy)> where - F: Fn(&str) -> Option, + F: Fn(&'a str) -> Option, { let mut splits = line.splitn(2, "- ").map(str::trim); let min = splits.next().unwrap(); @@ -1273,7 +1289,7 @@ where let max = match max { Some("") => return None, Some(max) => parse(max)?, - _ => min, + _ => min.clone(), }; Some((min, max)) @@ -1489,43 +1505,55 @@ fn ignore_llvm(config: &Config, line: &str) -> IgnoreDecision { }; } } - if let Some(actual_version) = config.llvm_version { - if let Some(rest) = line.strip_prefix("min-llvm-version:").map(str::trim) { - let min_version = extract_llvm_version(rest).unwrap(); - // Ignore if actual version is smaller the minimum required - // version - if actual_version < min_version { + if let Some(actual_version) = &config.llvm_version { + // Note that these `min` versions will check for not just major versions. + + if let Some(version_string) = config.parse_name_value_directive(line, "min-llvm-version") { + let min_version = extract_llvm_version(&version_string); + // Ignore if actual version is smaller than the minimum required version. + if *actual_version < min_version { return IgnoreDecision::Ignore { - reason: format!("ignored when the LLVM version is older than {rest}"), + reason: format!( + "ignored when the LLVM version {actual_version} is older than {min_version}" + ), }; } - } else if let Some(rest) = line.strip_prefix("min-system-llvm-version:").map(str::trim) { - let min_version = extract_llvm_version(rest).unwrap(); + } else if let Some(version_string) = + config.parse_name_value_directive(line, "min-system-llvm-version") + { + let min_version = extract_llvm_version(&version_string); // Ignore if using system LLVM and actual version // is smaller the minimum required version - if config.system_llvm && actual_version < min_version { + if config.system_llvm && *actual_version < min_version { return IgnoreDecision::Ignore { - reason: format!("ignored when the system LLVM version is older than {rest}"), + reason: format!( + "ignored when the system LLVM version {actual_version} is older than {min_version}" + ), }; } - } else if let Some(rest) = line.strip_prefix("ignore-llvm-version:").map(str::trim) { + } else if let Some(version_range) = + config.parse_name_value_directive(line, "ignore-llvm-version") + { // Syntax is: "ignore-llvm-version: [- ]" let (v_min, v_max) = - extract_version_range(rest, extract_llvm_version).unwrap_or_else(|| { - panic!("couldn't parse version range: {:?}", rest); - }); + extract_version_range(&version_range, |s| Some(extract_llvm_version(s))) + .unwrap_or_else(|| { + panic!("couldn't parse version range: \"{version_range}\""); + }); if v_max < v_min { - panic!("Malformed LLVM version range: max < min") + panic!("malformed LLVM version range where {v_max} < {v_min}") } // Ignore if version lies inside of range. - if actual_version >= v_min && actual_version <= v_max { + if *actual_version >= v_min && *actual_version <= v_max { if v_min == v_max { return IgnoreDecision::Ignore { - reason: format!("ignored when the LLVM version is {rest}"), + reason: format!("ignored when the LLVM version is {actual_version}"), }; } else { return IgnoreDecision::Ignore { - reason: format!("ignored when the LLVM version is between {rest}"), + reason: format!( + "ignored when the LLVM version is between {v_min} and {v_max}" + ), }; } } diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index c3c9496c4d2d9..2e6effcab9868 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -1,9 +1,13 @@ use std::io::Read; use std::path::Path; -use super::iter_header; +use semver::Version; + +use super::{ + EarlyProps, HeadersCache, extract_llvm_version, extract_version_range, iter_header, + parse_normalize_rule, +}; use crate::common::{Config, Debugger, Mode}; -use crate::header::{EarlyProps, HeadersCache, parse_normalize_rule}; fn make_test_description( config: &Config, @@ -407,19 +411,67 @@ fn channel() { assert!(!check_ignore(&config, "//@ ignore-stable")); } +#[test] +fn test_extract_llvm_version() { + // Note: officially, semver *requires* that versions at the minimum have all three + // `major.minor.patch` numbers, though for test-writer's convenience we allow omitting the minor + // and patch numbers (which will be stubbed out as 0). + assert_eq!(extract_llvm_version("0"), Version::new(0, 0, 0)); + assert_eq!(extract_llvm_version("0.0"), Version::new(0, 0, 0)); + assert_eq!(extract_llvm_version("0.0.0"), Version::new(0, 0, 0)); + assert_eq!(extract_llvm_version("1"), Version::new(1, 0, 0)); + assert_eq!(extract_llvm_version("1.2"), Version::new(1, 2, 0)); + assert_eq!(extract_llvm_version("1.2.3"), Version::new(1, 2, 3)); + assert_eq!(extract_llvm_version("4.5.6git"), Version::new(4, 5, 6)); + assert_eq!(extract_llvm_version("4.5.6-rc1"), Version::new(4, 5, 6)); + assert_eq!(extract_llvm_version("123.456.789-rc1"), Version::new(123, 456, 789)); + assert_eq!(extract_llvm_version("8.1.2-rust"), Version::new(8, 1, 2)); + assert_eq!(extract_llvm_version("9.0.1-rust-1.43.0-dev"), Version::new(9, 0, 1)); + assert_eq!(extract_llvm_version("9.3.1-rust-1.43.0-dev"), Version::new(9, 3, 1)); + assert_eq!(extract_llvm_version("10.0.0-rust"), Version::new(10, 0, 0)); + assert_eq!(extract_llvm_version("11.1.0"), Version::new(11, 1, 0)); + assert_eq!(extract_llvm_version("12.0.0libcxx"), Version::new(12, 0, 0)); + assert_eq!(extract_llvm_version("12.0.0-rc3"), Version::new(12, 0, 0)); + assert_eq!(extract_llvm_version("13.0.0git"), Version::new(13, 0, 0)); +} + +#[test] +#[should_panic] +fn test_llvm_version_invalid_components() { + extract_llvm_version("4.x.6"); +} + +#[test] +#[should_panic] +fn test_llvm_version_invalid_prefix() { + extract_llvm_version("meow4.5.6"); +} + +#[test] +#[should_panic] +fn test_llvm_version_too_many_components() { + extract_llvm_version("4.5.6.7"); +} + #[test] fn test_extract_version_range() { - use super::{extract_llvm_version, extract_version_range}; - - assert_eq!(extract_version_range("1.2.3 - 4.5.6", extract_llvm_version), Some((10203, 40506))); - assert_eq!(extract_version_range("0 - 4.5.6", extract_llvm_version), Some((0, 40506))); - assert_eq!(extract_version_range("1.2.3 -", extract_llvm_version), None); - assert_eq!(extract_version_range("1.2.3 - ", extract_llvm_version), None); - assert_eq!(extract_version_range("- 4.5.6", extract_llvm_version), None); - assert_eq!(extract_version_range("-", extract_llvm_version), None); - assert_eq!(extract_version_range(" - 4.5.6", extract_llvm_version), None); - assert_eq!(extract_version_range(" - 4.5.6", extract_llvm_version), None); - assert_eq!(extract_version_range("0 -", extract_llvm_version), None); + let wrapped_extract = |s: &str| Some(extract_llvm_version(s)); + + assert_eq!( + extract_version_range("1.2.3 - 4.5.6", wrapped_extract), + Some((Version::new(1, 2, 3), Version::new(4, 5, 6))) + ); + assert_eq!( + extract_version_range("0 - 4.5.6", wrapped_extract), + Some((Version::new(0, 0, 0), Version::new(4, 5, 6))) + ); + assert_eq!(extract_version_range("1.2.3 -", wrapped_extract), None); + assert_eq!(extract_version_range("1.2.3 - ", wrapped_extract), None); + assert_eq!(extract_version_range("- 4.5.6", wrapped_extract), None); + assert_eq!(extract_version_range("-", wrapped_extract), None); + assert_eq!(extract_version_range(" - 4.5.6", wrapped_extract), None); + assert_eq!(extract_version_range(" - 4.5.6", wrapped_extract), None); + assert_eq!(extract_version_range("0 -", wrapped_extract), None); } #[test] diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 490df31322854..ccf8057bf5c57 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -228,7 +228,7 @@ pub fn parse_config(args: Vec) -> Config { Some(x) => panic!("argument for --color must be auto, always, or never, but found `{}`", x), }; let llvm_version = - matches.opt_str("llvm-version").as_deref().and_then(header::extract_llvm_version).or_else( + matches.opt_str("llvm-version").as_deref().map(header::extract_llvm_version).or_else( || header::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?), ); diff --git a/src/tools/compiletest/src/tests.rs b/src/tools/compiletest/src/tests.rs index 680579c59aec5..fec746904dedf 100644 --- a/src/tools/compiletest/src/tests.rs +++ b/src/tools/compiletest/src/tests.rs @@ -1,7 +1,6 @@ use std::ffi::OsString; use crate::debuggers::{extract_gdb_version, extract_lldb_version}; -use crate::header::extract_llvm_version; use crate::is_test; #[test] @@ -67,15 +66,3 @@ fn is_test_test() { assert!(!is_test(&OsString::from("#a_dog_gif"))); assert!(!is_test(&OsString::from("~a_temp_file"))); } - -#[test] -fn test_extract_llvm_version() { - assert_eq!(extract_llvm_version("8.1.2-rust"), Some(80102)); - assert_eq!(extract_llvm_version("9.0.1-rust-1.43.0-dev"), Some(90001)); - assert_eq!(extract_llvm_version("9.3.1-rust-1.43.0-dev"), Some(90301)); - assert_eq!(extract_llvm_version("10.0.0-rust"), Some(100000)); - assert_eq!(extract_llvm_version("11.1.0"), Some(110100)); - assert_eq!(extract_llvm_version("12.0.0libcxx"), Some(120000)); - assert_eq!(extract_llvm_version("12.0.0-rc3"), Some(120000)); - assert_eq!(extract_llvm_version("13.0.0git"), Some(130000)); -} From 6d8d79595e93c74a545d60b181febc0e351851db Mon Sep 17 00:00:00 2001 From: Adrian Taylor Date: Mon, 2 Sep 2024 12:52:39 +0000 Subject: [PATCH 07/10] Reject generic self types. The RFC for arbitrary self types v2 declares that we should reject "generic" self types. This commit does so. The definition of "generic" was unclear in the RFC, but has been explored in https://github.com/rust-lang/rust/issues/129147 and the conclusion is that "generic" means any `self` type which is a type parameter defined on the method itself, or references to such a type. This approach was chosen because other definitions of "generic" don't work. Specifically, * we can't filter out generic type _arguments_, because that would filter out Rc and all the other types of smart pointer we want to support; * we can't filter out all type params, because Self itself is a type param, and because existing Rust code depends on other type params declared on the type (as opposed to the method). This PR decides to make a new error code for this case, instead of reusing the existing E0307 error. This makes the code a bit more complex, but it seems we have an opportunity to provide specific diagnostics for this case so we should do so. This PR filters out generic self types whether or not the 'arbitrary self types' feature is enabled. However, it's believed that it can't have any effect on code which uses stable Rust, since there are no stable traits which can be used to indicate a valid generic receiver type, and thus it would have been impossible to write code which could trigger this new error case. It is however possible that this could break existing code which uses either of the unstable `arbitrary_self_types` or `receiver_trait` features. This breakage is intentional; as we move arbitrary self types towards stabilization we don't want to continue to support generic such types. This PR adds lots of extra tests to arbitrary-self-from-method-substs. Most of these are ways to trigger a "type mismatch" error which https://github.com/rust-lang/rust/blob/9b82580c7347f800c2550e6719e4218a60a80b28/compiler/rustc_hir_typeck/src/method/confirm.rs#L519 hopes can be minimized by filtering out generics in this way. We remove a FIXME from confirm.rs suggesting that we make this change. It's still possible to cause type mismatch errors, and a subsequent PR may be able to improve diagnostics in this area, but it's harder to cause these errors without contrived uses of the turbofish. This is a part of the arbitrary self types v2 project, https://github.com/rust-lang/rfcs/pull/3519 https://github.com/rust-lang/rust/issues/44874 r? @wesleywiser --- .../src/error_codes/E0801.md | 51 +++++ compiler/rustc_error_codes/src/lib.rs | 1 + compiler/rustc_hir_analysis/messages.ftl | 6 + .../rustc_hir_analysis/src/check/wfcheck.rs | 86 +++++++-- compiler/rustc_hir_analysis/src/errors.rs | 10 + .../rustc_hir_typeck/src/method/confirm.rs | 3 - src/tools/tidy/src/issues.txt | 1 - .../arbitrary-self-from-method-substs-ice.rs | 2 +- ...bitrary-self-from-method-substs-ice.stderr | 10 +- ...ary-self-from-method-substs.default.stderr | 162 +++++++++++++++- ...ary-self-from-method-substs.feature.stderr | 176 +++++++++++++++++- .../self/arbitrary-self-from-method-substs.rs | 94 +++++++++- tests/ui/type-alias-impl-trait/issue-57700.rs | 21 --- .../type-alias-impl-trait/issue-57700.stderr | 8 - 14 files changed, 570 insertions(+), 61 deletions(-) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0801.md delete mode 100644 tests/ui/type-alias-impl-trait/issue-57700.rs delete mode 100644 tests/ui/type-alias-impl-trait/issue-57700.stderr diff --git a/compiler/rustc_error_codes/src/error_codes/E0801.md b/compiler/rustc_error_codes/src/error_codes/E0801.md new file mode 100644 index 0000000000000..c89feb9b30800 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0801.md @@ -0,0 +1,51 @@ +The `self` parameter in a method has an invalid generic "receiver type". + +Erroneous code example: + +```compile_fail,E0801 +struct Foo; + +impl Foo { + fn foo>(self: R) {} +} +``` + +or alternatively, + +```compile_fail,E0801 +struct Foo; + +impl Foo { + fn foo(self: impl std::ops::Deref) {} +} +``` + +Methods take a special first parameter, termed `self`. It's normal to +use `self`, `&self` or `&mut self`, which are syntactic sugar for +`self: Self`, `self: &Self`, and `self: &mut Self` respectively. +But it's also possible to use more sophisticated types of `self` +parameter, for instance `std::rc::Rc`. The set of allowable +`Self` types is extensible using the nightly feature +[Arbitrary self types][AST]. +This will extend the valid set of `Self` types to anything which implements +`std::ops::Deref`, for example `Rc`, `Box`, or +your own smart pointers that do the same. + +However, even with that feature, the `self` type must be concrete. +Generic `self` types are not permitted. Specifically, a `self` type will +be rejected if it is a type parameter defined on the method. + +These are OK: + +``` +struct Foo; + +impl Foo { + fn foo(self) {} + fn foo2(self: std::rc::Rc) {} // or some other similar + // smart pointer if you enable arbitrary self types and + // the pointer implements Deref +} +``` + +[AST]: https://doc.rust-lang.org/unstable-book/language-features/arbitrary-self-types.html diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index 27a34d6003dbe..29f3277d3997e 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -540,6 +540,7 @@ E0797: 0797, E0798: 0798, E0799: 0799, E0800: 0800, +E0801: 0801, ); ) } diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 7191c7240614f..38b11aa40179d 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -234,6 +234,12 @@ hir_analysis_inherent_ty_outside_relevant = cannot define inherent `impl` for a .help = consider moving this inherent impl into the crate defining the type if possible .span_help = alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items +hir_analysis_invalid_generic_receiver_ty = invalid generic `self` parameter type: `{$receiver_ty}` + .note = type of `self` must not be a method generic parameter type + +hir_analysis_invalid_generic_receiver_ty_help = + use a concrete type such as `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + hir_analysis_invalid_receiver_ty = invalid `self` parameter type: `{$receiver_ty}` .note = type of `self` must be `Self` or a type that dereferences to it diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 12ed7b89f68be..5bc320b12b0a8 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -2,13 +2,14 @@ use std::cell::LazyCell; use std::ops::{ControlFlow, Deref}; use hir::intravisit::{self, Visitor}; +use itertools::Itertools; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err}; -use rustc_hir::ItemKind; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::lang_items::LangItem; +use rustc_hir::{GenericParamKind, ItemKind}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; use rustc_macros::LintDiagnostic; @@ -378,7 +379,7 @@ fn check_trait_item<'tcx>( _ => (None, trait_item.span), }; check_dyn_incompatible_self_trait_by_name(tcx, trait_item); - let mut res = check_associated_item(tcx, def_id, span, method_sig); + let mut res = check_associated_item(tcx, def_id, span, method_sig, None); if matches!(trait_item.kind, hir::TraitItemKind::Fn(..)) { for &assoc_ty_def_id in tcx.associated_types_for_impl_traits_in_associated_fn(def_id) { @@ -387,6 +388,7 @@ fn check_trait_item<'tcx>( assoc_ty_def_id.expect_local(), tcx.def_span(assoc_ty_def_id), None, + None, )); } } @@ -904,8 +906,13 @@ fn check_impl_item<'tcx>( hir::ImplItemKind::Type(ty) if ty.span != DUMMY_SP => (None, ty.span), _ => (None, impl_item.span), }; - - check_associated_item(tcx, impl_item.owner_id.def_id, span, method_sig) + check_associated_item( + tcx, + impl_item.owner_id.def_id, + span, + method_sig, + Some(impl_item.generics), + ) } fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), ErrorGuaranteed> { @@ -1038,6 +1045,7 @@ fn check_associated_item( item_id: LocalDefId, span: Span, sig_if_method: Option<&hir::FnSig<'_>>, + generics: Option<&hir::Generics<'_>>, ) -> Result<(), ErrorGuaranteed> { let loc = Some(WellFormedLoc::Ty(item_id)); enter_wf_checking_ctxt(tcx, span, item_id, |wfcx| { @@ -1070,7 +1078,7 @@ fn check_associated_item( hir_sig.decl, item.def_id.expect_local(), ); - check_method_receiver(wfcx, hir_sig, item, self_ty) + check_method_receiver(wfcx, hir_sig, item, self_ty, generics) } ty::AssocKind::Type => { if let ty::AssocItemContainer::TraitContainer = item.container { @@ -1692,6 +1700,7 @@ fn check_method_receiver<'tcx>( fn_sig: &hir::FnSig<'_>, method: ty::AssocItem, self_ty: Ty<'tcx>, + generics: Option<&hir::Generics<'_>>, ) -> Result<(), ErrorGuaranteed> { let tcx = wfcx.tcx(); @@ -1726,7 +1735,9 @@ fn check_method_receiver<'tcx>( None }; - if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, arbitrary_self_types_level) { + let receiver_validity = + receiver_is_valid(wfcx, span, receiver_ty, self_ty, arbitrary_self_types_level, generics); + if let Err(receiver_validity_err) = receiver_validity { return Err(match arbitrary_self_types_level { // Wherever possible, emit a message advising folks that the features // `arbitrary_self_types` or `arbitrary_self_types_pointers` might @@ -1737,7 +1748,9 @@ fn check_method_receiver<'tcx>( receiver_ty, self_ty, Some(ArbitrarySelfTypesLevel::Basic), - ) => + generics, + ) + .is_ok() => { // Report error; would have worked with `arbitrary_self_types`. feature_err( @@ -1759,7 +1772,9 @@ fn check_method_receiver<'tcx>( receiver_ty, self_ty, Some(ArbitrarySelfTypesLevel::WithPointers), - ) => + generics, + ) + .is_ok() => { // Report error; would have worked with `arbitrary_self_types_pointers`. feature_err( @@ -1777,13 +1792,53 @@ fn check_method_receiver<'tcx>( _ => // Report error; would not have worked with `arbitrary_self_types[_pointers]`. { - tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty }) + match receiver_validity_err { + ReceiverValidityError::DoesNotDeref => { + tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty }) + } + ReceiverValidityError::MethodGenericParamUsed => { + tcx.dcx().emit_err(errors::InvalidGenericReceiverTy { span, receiver_ty }) + } + } } }); } Ok(()) } +/// Error cases which may be returned from `receiver_is_valid`. These error +/// cases are generated in this function as they may be unearthed as we explore +/// the `autoderef` chain, but they're converted to diagnostics in the caller. +enum ReceiverValidityError { + /// The self type does not get to the receiver type by following the + /// autoderef chain. + DoesNotDeref, + /// A type was found which is a method type parameter, and that's not allowed. + MethodGenericParamUsed, +} + +/// Confirms that a type is not a type parameter referring to one of the +/// method's type params. +fn confirm_type_is_not_a_method_generic_param( + ty: Ty<'_>, + method_generics: Option<&hir::Generics<'_>>, +) -> Result<(), ReceiverValidityError> { + if let ty::Param(param) = ty.kind() { + if let Some(generics) = method_generics { + if generics + .params + .iter() + .filter(|g| matches!(g.kind, GenericParamKind::Type { .. })) + .map(|g| g.name.ident().name) + .contains(¶m.name) + { + return Err(ReceiverValidityError::MethodGenericParamUsed); + } + } + } + Ok(()) +} + /// Returns whether `receiver_ty` would be considered a valid receiver type for `self_ty`. If /// `arbitrary_self_types` is enabled, `receiver_ty` must transitively deref to `self_ty`, possibly /// through a `*const/mut T` raw pointer if `arbitrary_self_types_pointers` is also enabled. @@ -1799,7 +1854,8 @@ fn receiver_is_valid<'tcx>( receiver_ty: Ty<'tcx>, self_ty: Ty<'tcx>, arbitrary_self_types_enabled: Option, -) -> bool { + generics: Option<&hir::Generics<'_>>, +) -> Result<(), ReceiverValidityError> { let infcx = wfcx.infcx; let tcx = wfcx.tcx(); let cause = @@ -1811,9 +1867,11 @@ fn receiver_is_valid<'tcx>( ocx.eq(&cause, wfcx.param_env, self_ty, receiver_ty)?; if ocx.select_all_or_error().is_empty() { Ok(()) } else { Err(NoSolution) } }) { - return true; + return Ok(()); } + confirm_type_is_not_a_method_generic_param(receiver_ty, generics)?; + let mut autoderef = Autoderef::new(infcx, wfcx.param_env, wfcx.body_def_id, span, receiver_ty); // The `arbitrary_self_types_pointers` feature allows raw pointer receivers like `self: *const Self`. @@ -1830,6 +1888,8 @@ fn receiver_is_valid<'tcx>( potential_self_ty, self_ty ); + confirm_type_is_not_a_method_generic_param(potential_self_ty, generics)?; + // Check if the self type unifies. If it does, then commit the result // since it may have region side-effects. if let Ok(()) = wfcx.infcx.commit_if_ok(|_| { @@ -1838,7 +1898,7 @@ fn receiver_is_valid<'tcx>( if ocx.select_all_or_error().is_empty() { Ok(()) } else { Err(NoSolution) } }) { wfcx.register_obligations(autoderef.into_obligations()); - return true; + return Ok(()); } // Without `feature(arbitrary_self_types)`, we require that each step in the @@ -1865,7 +1925,7 @@ fn receiver_is_valid<'tcx>( } debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`", receiver_ty, self_ty); - false + Err(ReceiverValidityError::DoesNotDeref) } fn receiver_is_implemented<'tcx>( diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 7fa9dfe346d78..a92a5e4278c56 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1623,6 +1623,16 @@ pub(crate) struct InvalidReceiverTy<'tcx> { pub receiver_ty: Ty<'tcx>, } +#[derive(Diagnostic)] +#[diag(hir_analysis_invalid_generic_receiver_ty, code = E0801)] +#[note] +#[help(hir_analysis_invalid_generic_receiver_ty_help)] +pub(crate) struct InvalidGenericReceiverTy<'tcx> { + #[primary_span] + pub span: Span, + pub receiver_ty: Ty<'tcx>, +} + #[derive(Diagnostic)] #[diag(hir_analysis_cmse_inputs_stack_spill, code = E0798)] #[note] diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index f2b55d3aa4e1b..92b504d10bc09 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -533,9 +533,6 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self.register_predicates(obligations); } Err(terr) => { - // FIXME(arbitrary_self_types): We probably should limit the - // situations where this can occur by adding additional restrictions - // to the feature, like the self type can't reference method args. if self.tcx.features().arbitrary_self_types() { self.err_ctxt() .report_mismatched_types( diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 94f8d23c1586a..932a58788e04e 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -4102,7 +4102,6 @@ ui/type-alias-impl-trait/issue-53678-coroutine-and-const-fn.rs ui/type-alias-impl-trait/issue-55099-lifetime-inference.rs ui/type-alias-impl-trait/issue-57188-associate-impl-capture.rs ui/type-alias-impl-trait/issue-57611-trait-alias.rs -ui/type-alias-impl-trait/issue-57700.rs ui/type-alias-impl-trait/issue-57807-associated-type.rs ui/type-alias-impl-trait/issue-57961.rs ui/type-alias-impl-trait/issue-58662-coroutine-with-lifetime.rs diff --git a/tests/ui/self/arbitrary-self-from-method-substs-ice.rs b/tests/ui/self/arbitrary-self-from-method-substs-ice.rs index a544c8ea0d154..d121a194be6bb 100644 --- a/tests/ui/self/arbitrary-self-from-method-substs-ice.rs +++ b/tests/ui/self/arbitrary-self-from-method-substs-ice.rs @@ -8,7 +8,7 @@ use std::ops::Deref; struct Foo(u32); impl Foo { const fn get>(self: R) -> u32 { - //~^ ERROR: `R` cannot be used as the type of `self` + //~^ ERROR invalid generic `self` parameter type //~| ERROR destructor of `R` cannot be evaluated at compile-time self.0 //~^ ERROR cannot call non-const fn `::deref` in constant function diff --git a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr index 6ae60e7af47d8..7252b5890fdbf 100644 --- a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr +++ b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr @@ -15,18 +15,16 @@ LL | const fn get>(self: R) -> u32 { LL | } | - value is dropped here -error[E0658]: `R` cannot be used as the type of `self` without the `arbitrary_self_types` feature +error[E0801]: invalid generic `self` parameter type: `R` --> $DIR/arbitrary-self-from-method-substs-ice.rs:10:49 | LL | const fn get>(self: R) -> u32 { | ^ | - = note: see issue #44874 for more information - = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) error: aborting due to 3 previous errors -Some errors have detailed explanations: E0015, E0493, E0658. +Some errors have detailed explanations: E0015, E0493, E0801. For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/self/arbitrary-self-from-method-substs.default.stderr b/tests/ui/self/arbitrary-self-from-method-substs.default.stderr index 4cc69666b8876..5dc3a0b023472 100644 --- a/tests/ui/self/arbitrary-self-from-method-substs.default.stderr +++ b/tests/ui/self/arbitrary-self-from-method-substs.default.stderr @@ -1,14 +1,168 @@ -error[E0658]: `R` cannot be used as the type of `self` without the `arbitrary_self_types` feature - --> $DIR/arbitrary-self-from-method-substs.rs:8:43 +error[E0801]: invalid generic `self` parameter type: `R` + --> $DIR/arbitrary-self-from-method-substs.rs:9:43 | LL | fn get>(self: R) -> u32 { | ^ | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error[E0801]: invalid generic `self` parameter type: `&R` + --> $DIR/arbitrary-self-from-method-substs.rs:13:44 + | +LL | fn get1>(self: &R) -> u32 { + | ^^ + | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error[E0801]: invalid generic `self` parameter type: `&mut R` + --> $DIR/arbitrary-self-from-method-substs.rs:17:44 + | +LL | fn get2>(self: &mut R) -> u32 { + | ^^^^^^ + | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error[E0801]: invalid generic `self` parameter type: `Rc` + --> $DIR/arbitrary-self-from-method-substs.rs:21:44 + | +LL | fn get3>(self: std::rc::Rc) -> u32 { + | ^^^^^^^^^^^^^^ + | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error[E0801]: invalid generic `self` parameter type: `&Rc` + --> $DIR/arbitrary-self-from-method-substs.rs:25:44 + | +LL | fn get4>(self: &std::rc::Rc) -> u32 { + | ^^^^^^^^^^^^^^^ + | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error[E0801]: invalid generic `self` parameter type: `Rc<&R>` + --> $DIR/arbitrary-self-from-method-substs.rs:29:44 + | +LL | fn get5>(self: std::rc::Rc<&R>) -> u32 { + | ^^^^^^^^^^^^^^^ + | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error[E0658]: `::Receiver` cannot be used as the type of `self` without the `arbitrary_self_types` feature + --> $DIR/arbitrary-self-from-method-substs.rs:33:37 + | +LL | fn get6(self: FR::Receiver, other: FR) -> u32 { + | ^^^^^^^^^^^^ + | = note: see issue #44874 for more information = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) -error: aborting due to 1 previous error +error[E0658]: `R` cannot be used as the type of `self` without the `arbitrary_self_types` feature + --> $DIR/arbitrary-self-from-method-substs.rs:61:18 + | +LL | fn get(self: R) {} + | ^ + | + = note: see issue #44874 for more information + = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error[E0271]: type mismatch resolving `::Receiver == Foo` + --> $DIR/arbitrary-self-from-method-substs.rs:92:9 + | +LL | foo.get6(Silly); + | ^^^^ type mismatch resolving `::Receiver == Foo` + | +note: expected this to be `Foo` + --> $DIR/arbitrary-self-from-method-substs.rs:71:21 + | +LL | type Receiver = std::rc::Rc; + | ^^^^^^^^^^^^^^^^ + = note: expected struct `Foo` + found struct `Rc` + +error[E0271]: type mismatch resolving `::Receiver == &Foo` + --> $DIR/arbitrary-self-from-method-substs.rs:96:9 + | +LL | foo.get6(Silly); + | ^^^^ type mismatch resolving `::Receiver == &Foo` + | +note: expected this to be `&Foo` + --> $DIR/arbitrary-self-from-method-substs.rs:71:21 + | +LL | type Receiver = std::rc::Rc; + | ^^^^^^^^^^^^^^^^ + = note: expected reference `&Foo` + found struct `Rc` + +error[E0599]: the method `get` exists for struct `Rc>`, but its trait bounds were not satisfied + --> $DIR/arbitrary-self-from-method-substs.rs:100:7 + | +LL | struct Bar(std::marker::PhantomData); + | ------------- doesn't satisfy `Bar<_>: Deref` +... +LL | t.get(); + | ^^^ method cannot be called on `Rc>` due to unsatisfied trait bounds + | +note: the following trait bounds were not satisfied: + `<&Bar<_> as Deref>::Target = Bar<&Bar<_>>` + `<&Rc> as Deref>::Target = Bar<&Rc>>` + `<&mut Bar<_> as Deref>::Target = Bar<&mut Bar<_>>` + `<&mut Rc> as Deref>::Target = Bar<&mut Rc>>` + `> as Deref>::Target = Bar>>` + `Bar<_>: Deref` + --> $DIR/arbitrary-self-from-method-substs.rs:60:9 + | +LL | impl> Bar { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------ + | | | + | | unsatisfied trait bound introduced here + | unsatisfied trait bound introduced here +note: the trait `Deref` must be implemented + --> $SRC_DIR/core/src/ops/deref.rs:LL:COL + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `get`, perhaps you need to implement it: + candidate #1: `SliceIndex` + +error[E0599]: the method `get` exists for reference `&Rc>`, but its trait bounds were not satisfied + --> $DIR/arbitrary-self-from-method-substs.rs:108:7 + | +LL | struct Bar(std::marker::PhantomData); + | ------------- doesn't satisfy `Bar<_>: Deref` +... +LL | t.get(); + | ^^^ method cannot be called on `&Rc>` due to unsatisfied trait bounds + | +note: the following trait bounds were not satisfied: + `<&&Rc> as Deref>::Target = Bar<&&Rc>>` + `<&Bar<_> as Deref>::Target = Bar<&Bar<_>>` + `<&Rc> as Deref>::Target = Bar<&Rc>>` + `<&mut &Rc> as Deref>::Target = Bar<&mut &Rc>>` + `<&mut Bar<_> as Deref>::Target = Bar<&mut Bar<_>>` + `<&mut Rc> as Deref>::Target = Bar<&mut Rc>>` + `> as Deref>::Target = Bar>>` + `Bar<_>: Deref` + --> $DIR/arbitrary-self-from-method-substs.rs:60:9 + | +LL | impl> Bar { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------ + | | | + | | unsatisfied trait bound introduced here + | unsatisfied trait bound introduced here +note: the trait `Deref` must be implemented + --> $SRC_DIR/core/src/ops/deref.rs:LL:COL + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `get`, perhaps you need to implement it: + candidate #1: `SliceIndex` + +error: aborting due to 12 previous errors -For more information about this error, try `rustc --explain E0658`. +Some errors have detailed explanations: E0271, E0599, E0658, E0801. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/self/arbitrary-self-from-method-substs.feature.stderr b/tests/ui/self/arbitrary-self-from-method-substs.feature.stderr index 44e553f1a06ca..6e864f44aa348 100644 --- a/tests/ui/self/arbitrary-self-from-method-substs.feature.stderr +++ b/tests/ui/self/arbitrary-self-from-method-substs.feature.stderr @@ -1,9 +1,179 @@ +error[E0801]: invalid generic `self` parameter type: `R` + --> $DIR/arbitrary-self-from-method-substs.rs:9:43 + | +LL | fn get>(self: R) -> u32 { + | ^ + | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error[E0801]: invalid generic `self` parameter type: `&R` + --> $DIR/arbitrary-self-from-method-substs.rs:13:44 + | +LL | fn get1>(self: &R) -> u32 { + | ^^ + | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error[E0801]: invalid generic `self` parameter type: `&mut R` + --> $DIR/arbitrary-self-from-method-substs.rs:17:44 + | +LL | fn get2>(self: &mut R) -> u32 { + | ^^^^^^ + | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error[E0801]: invalid generic `self` parameter type: `Rc` + --> $DIR/arbitrary-self-from-method-substs.rs:21:44 + | +LL | fn get3>(self: std::rc::Rc) -> u32 { + | ^^^^^^^^^^^^^^ + | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error[E0801]: invalid generic `self` parameter type: `&Rc` + --> $DIR/arbitrary-self-from-method-substs.rs:25:44 + | +LL | fn get4>(self: &std::rc::Rc) -> u32 { + | ^^^^^^^^^^^^^^^ + | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error[E0801]: invalid generic `self` parameter type: `Rc<&R>` + --> $DIR/arbitrary-self-from-method-substs.rs:29:44 + | +LL | fn get5>(self: std::rc::Rc<&R>) -> u32 { + | ^^^^^^^^^^^^^^^ + | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + error[E0308]: mismatched types - --> $DIR/arbitrary-self-from-method-substs.rs:16:5 + --> $DIR/arbitrary-self-from-method-substs.rs:76:5 | LL | foo.get::<&Foo>(); | ^^^ expected `&Foo`, found `Foo` -error: aborting due to 1 previous error +error[E0308]: mismatched types + --> $DIR/arbitrary-self-from-method-substs.rs:78:5 + | +LL | foo.get::>(); + | ^^^ expected `Rc`, found `Foo` + | + = note: expected struct `Rc` + found struct `Foo` + +error[E0308]: mismatched types + --> $DIR/arbitrary-self-from-method-substs.rs:84:5 + | +LL | smart_ptr.get::>(); + | ^^^^^^^^^ expected `SmartPtr2<'_, Foo>`, found `SmartPtr<'_, Foo>` + | + = note: expected struct `SmartPtr2<'_, Foo>` + found struct `SmartPtr<'_, Foo>` + +error[E0308]: mismatched types + --> $DIR/arbitrary-self-from-method-substs.rs:86:5 + | +LL | smart_ptr.get::<&Foo>(); + | ^^^^^^^^^ expected `&Foo`, found `SmartPtr<'_, Foo>` + | + = note: expected reference `&Foo` + found struct `SmartPtr<'_, Foo, >` + +error[E0271]: type mismatch resolving `::Receiver == Foo` + --> $DIR/arbitrary-self-from-method-substs.rs:92:9 + | +LL | foo.get6(Silly); + | ^^^^ type mismatch resolving `::Receiver == Foo` + | +note: expected this to be `Foo` + --> $DIR/arbitrary-self-from-method-substs.rs:71:21 + | +LL | type Receiver = std::rc::Rc; + | ^^^^^^^^^^^^^^^^ + = note: expected struct `Foo` + found struct `Rc` + +error[E0271]: type mismatch resolving `::Receiver == &Foo` + --> $DIR/arbitrary-self-from-method-substs.rs:96:9 + | +LL | foo.get6(Silly); + | ^^^^ type mismatch resolving `::Receiver == &Foo` + | +note: expected this to be `&Foo` + --> $DIR/arbitrary-self-from-method-substs.rs:71:21 + | +LL | type Receiver = std::rc::Rc; + | ^^^^^^^^^^^^^^^^ + = note: expected reference `&Foo` + found struct `Rc` + +error[E0599]: the method `get` exists for struct `Rc>`, but its trait bounds were not satisfied + --> $DIR/arbitrary-self-from-method-substs.rs:100:7 + | +LL | struct Bar(std::marker::PhantomData); + | ------------- doesn't satisfy `Bar<_>: Deref` +... +LL | t.get(); + | ^^^ method cannot be called on `Rc>` due to unsatisfied trait bounds + | +note: the following trait bounds were not satisfied: + `<&Bar<_> as Deref>::Target = Bar<&Bar<_>>` + `<&Rc> as Deref>::Target = Bar<&Rc>>` + `<&mut Bar<_> as Deref>::Target = Bar<&mut Bar<_>>` + `<&mut Rc> as Deref>::Target = Bar<&mut Rc>>` + `> as Deref>::Target = Bar>>` + `Bar<_>: Deref` + --> $DIR/arbitrary-self-from-method-substs.rs:60:9 + | +LL | impl> Bar { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------ + | | | + | | unsatisfied trait bound introduced here + | unsatisfied trait bound introduced here +note: the trait `Deref` must be implemented + --> $SRC_DIR/core/src/ops/deref.rs:LL:COL + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `get`, perhaps you need to implement it: + candidate #1: `SliceIndex` + +error[E0599]: the method `get` exists for reference `&Rc>`, but its trait bounds were not satisfied + --> $DIR/arbitrary-self-from-method-substs.rs:108:7 + | +LL | struct Bar(std::marker::PhantomData); + | ------------- doesn't satisfy `Bar<_>: Deref` +... +LL | t.get(); + | ^^^ method cannot be called on `&Rc>` due to unsatisfied trait bounds + | +note: the following trait bounds were not satisfied: + `<&&Rc> as Deref>::Target = Bar<&&Rc>>` + `<&Bar<_> as Deref>::Target = Bar<&Bar<_>>` + `<&Rc> as Deref>::Target = Bar<&Rc>>` + `<&mut &Rc> as Deref>::Target = Bar<&mut &Rc>>` + `<&mut Bar<_> as Deref>::Target = Bar<&mut Bar<_>>` + `<&mut Rc> as Deref>::Target = Bar<&mut Rc>>` + `> as Deref>::Target = Bar>>` + `Bar<_>: Deref` + --> $DIR/arbitrary-self-from-method-substs.rs:60:9 + | +LL | impl> Bar { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------ + | | | + | | unsatisfied trait bound introduced here + | unsatisfied trait bound introduced here +note: the trait `Deref` must be implemented + --> $SRC_DIR/core/src/ops/deref.rs:LL:COL + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `get`, perhaps you need to implement it: + candidate #1: `SliceIndex` + +error: aborting due to 14 previous errors -For more information about this error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0271, E0308, E0599, E0801. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/self/arbitrary-self-from-method-substs.rs b/tests/ui/self/arbitrary-self-from-method-substs.rs index 99977ed9b8c51..f2d6585961517 100644 --- a/tests/ui/self/arbitrary-self-from-method-substs.rs +++ b/tests/ui/self/arbitrary-self-from-method-substs.rs @@ -2,17 +2,109 @@ #![cfg_attr(feature, feature(arbitrary_self_types))] use std::ops::Deref; +use std::marker::PhantomData; struct Foo(u32); impl Foo { fn get>(self: R) -> u32 { - //[default]~^ ERROR: `R` cannot be used as the type of `self` + //~^ ERROR: invalid generic `self` parameter type self.0 } + fn get1>(self: &R) -> u32 { + //~^ ERROR: invalid generic `self` parameter type + self.0 + } + fn get2>(self: &mut R) -> u32 { + //~^ ERROR: invalid generic `self` parameter type + self.0 + } + fn get3>(self: std::rc::Rc) -> u32 { + //~^ ERROR: invalid generic `self` parameter type + self.0 + } + fn get4>(self: &std::rc::Rc) -> u32 { + //~^ ERROR: invalid generic `self` parameter type + self.0 + } + fn get5>(self: std::rc::Rc<&R>) -> u32 { + //~^ ERROR: invalid generic `self` parameter type + self.0 + } + fn get6(self: FR::Receiver, other: FR) -> u32 { + //[default]~^ ERROR: `::Receiver` cannot be used as the type of `self` + 42 + } +} + + +struct SmartPtr<'a, T: ?Sized>(&'a T); + +impl<'a, T: ?Sized> Deref for SmartPtr<'a, T> { + type Target = T; + fn deref(&self) -> &Self::Target { + unimplemented!() + } +} + +struct SmartPtr2<'a, T: ?Sized>(&'a T); + +impl<'a, T: ?Sized> Deref for SmartPtr2<'a, T> { + type Target = T; + fn deref(&self) -> &Self::Target { + unimplemented!() + } +} + +struct Bar(std::marker::PhantomData); + +impl> Bar { + fn get(self: R) {} + //[default]~^ ERROR: `R` cannot be used as the type of `self` +} + +trait FindReceiver { + type Receiver: Deref; +} + +struct Silly; +impl FindReceiver for Silly { + type Receiver = std::rc::Rc; } fn main() { let mut foo = Foo(1); foo.get::<&Foo>(); //[feature]~^ ERROR mismatched types + foo.get::>(); + //[feature]~^ ERROR mismatched types + + let smart_ptr = SmartPtr(&foo); + let smart_ptr2 = SmartPtr2(&foo); + smart_ptr.get(); // this compiles + smart_ptr.get::>(); + //[feature]~^ ERROR mismatched types + smart_ptr.get::<&Foo>(); + //[feature]~^ ERROR mismatched types + + let mut foo = Foo(1); + // This test is slightly contrived in an attempt to generate a mismatched types + // error for the self type below, without using the turbofish. + foo.get6(Silly); + //~^ ERROR type mismatch + let mut foo = Foo(1); + let foo = &foo; + foo.get6(Silly); + //~^ ERROR type mismatch + + let t = std::rc::Rc::new(Bar(std::marker::PhantomData)); + t.get(); + //~^ ERROR its trait bounds were not satisfied + let t = &t; + // This is a further attempt at triggering 'type mismatch' errors + // from arbitrary self types without resorting to the turbofish. + // Ideally, here, t is Thing> while we're going to call + // it with a &t method receiver. However, this doesn't work since that + // type of t becomes recursive and trait bounds can't be satisfied. + t.get(); + //~^ ERROR its trait bounds were not satisfied } diff --git a/tests/ui/type-alias-impl-trait/issue-57700.rs b/tests/ui/type-alias-impl-trait/issue-57700.rs deleted file mode 100644 index 8746545ecc9ef..0000000000000 --- a/tests/ui/type-alias-impl-trait/issue-57700.rs +++ /dev/null @@ -1,21 +0,0 @@ -#![feature(arbitrary_self_types)] -#![feature(impl_trait_in_assoc_type)] - -use std::ops::Deref; - -trait Foo { - type Bar: Foo; - - fn foo(self: impl Deref) -> Self::Bar; -} - -impl Foo for C { - type Bar = impl Foo; - - fn foo(self: impl Deref) -> Self::Bar { - self - //~^ Error type parameter `impl Deref` is part of concrete type but not used in parameter list for the `impl Trait` type alias - } -} - -fn main() {} diff --git a/tests/ui/type-alias-impl-trait/issue-57700.stderr b/tests/ui/type-alias-impl-trait/issue-57700.stderr deleted file mode 100644 index 7efb05f40b079..0000000000000 --- a/tests/ui/type-alias-impl-trait/issue-57700.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: type parameter `impl Deref` is part of concrete type but not used in parameter list for the `impl Trait` type alias - --> $DIR/issue-57700.rs:16:9 - | -LL | self - | ^^^^ - -error: aborting due to 1 previous error - From 86af0f9b7eccf3f8807cc0205a46d67ce31d9cf7 Mon Sep 17 00:00:00 2001 From: Adrian Taylor Date: Thu, 24 Oct 2024 16:25:02 +0000 Subject: [PATCH 08/10] Switch to comparing indices instead of names. --- .../rustc_hir_analysis/src/check/wfcheck.rs | 39 ++++++------------- 1 file changed, 11 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 5bc320b12b0a8..b20fa49eadb87 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -2,14 +2,13 @@ use std::cell::LazyCell; use std::ops::{ControlFlow, Deref}; use hir::intravisit::{self, Visitor}; -use itertools::Itertools; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err}; +use rustc_hir::ItemKind; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::lang_items::LangItem; -use rustc_hir::{GenericParamKind, ItemKind}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; use rustc_macros::LintDiagnostic; @@ -379,7 +378,7 @@ fn check_trait_item<'tcx>( _ => (None, trait_item.span), }; check_dyn_incompatible_self_trait_by_name(tcx, trait_item); - let mut res = check_associated_item(tcx, def_id, span, method_sig, None); + let mut res = check_associated_item(tcx, def_id, span, method_sig); if matches!(trait_item.kind, hir::TraitItemKind::Fn(..)) { for &assoc_ty_def_id in tcx.associated_types_for_impl_traits_in_associated_fn(def_id) { @@ -388,7 +387,6 @@ fn check_trait_item<'tcx>( assoc_ty_def_id.expect_local(), tcx.def_span(assoc_ty_def_id), None, - None, )); } } @@ -906,13 +904,7 @@ fn check_impl_item<'tcx>( hir::ImplItemKind::Type(ty) if ty.span != DUMMY_SP => (None, ty.span), _ => (None, impl_item.span), }; - check_associated_item( - tcx, - impl_item.owner_id.def_id, - span, - method_sig, - Some(impl_item.generics), - ) + check_associated_item(tcx, impl_item.owner_id.def_id, span, method_sig) } fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), ErrorGuaranteed> { @@ -1045,7 +1037,6 @@ fn check_associated_item( item_id: LocalDefId, span: Span, sig_if_method: Option<&hir::FnSig<'_>>, - generics: Option<&hir::Generics<'_>>, ) -> Result<(), ErrorGuaranteed> { let loc = Some(WellFormedLoc::Ty(item_id)); enter_wf_checking_ctxt(tcx, span, item_id, |wfcx| { @@ -1078,7 +1069,7 @@ fn check_associated_item( hir_sig.decl, item.def_id.expect_local(), ); - check_method_receiver(wfcx, hir_sig, item, self_ty, generics) + check_method_receiver(wfcx, hir_sig, item, self_ty) } ty::AssocKind::Type => { if let ty::AssocItemContainer::TraitContainer = item.container { @@ -1700,7 +1691,6 @@ fn check_method_receiver<'tcx>( fn_sig: &hir::FnSig<'_>, method: ty::AssocItem, self_ty: Ty<'tcx>, - generics: Option<&hir::Generics<'_>>, ) -> Result<(), ErrorGuaranteed> { let tcx = wfcx.tcx(); @@ -1734,6 +1724,7 @@ fn check_method_receiver<'tcx>( } else { None }; + let generics = tcx.generics_of(method.def_id); let receiver_validity = receiver_is_valid(wfcx, span, receiver_ty, self_ty, arbitrary_self_types_level, generics); @@ -1821,19 +1812,11 @@ enum ReceiverValidityError { /// method's type params. fn confirm_type_is_not_a_method_generic_param( ty: Ty<'_>, - method_generics: Option<&hir::Generics<'_>>, + method_generics: &ty::Generics, ) -> Result<(), ReceiverValidityError> { if let ty::Param(param) = ty.kind() { - if let Some(generics) = method_generics { - if generics - .params - .iter() - .filter(|g| matches!(g.kind, GenericParamKind::Type { .. })) - .map(|g| g.name.ident().name) - .contains(¶m.name) - { - return Err(ReceiverValidityError::MethodGenericParamUsed); - } + if (param.index as usize) >= method_generics.parent_count { + return Err(ReceiverValidityError::MethodGenericParamUsed); } } Ok(()) @@ -1854,7 +1837,7 @@ fn receiver_is_valid<'tcx>( receiver_ty: Ty<'tcx>, self_ty: Ty<'tcx>, arbitrary_self_types_enabled: Option, - generics: Option<&hir::Generics<'_>>, + method_generics: &ty::Generics, ) -> Result<(), ReceiverValidityError> { let infcx = wfcx.infcx; let tcx = wfcx.tcx(); @@ -1870,7 +1853,7 @@ fn receiver_is_valid<'tcx>( return Ok(()); } - confirm_type_is_not_a_method_generic_param(receiver_ty, generics)?; + confirm_type_is_not_a_method_generic_param(receiver_ty, method_generics)?; let mut autoderef = Autoderef::new(infcx, wfcx.param_env, wfcx.body_def_id, span, receiver_ty); @@ -1888,7 +1871,7 @@ fn receiver_is_valid<'tcx>( potential_self_ty, self_ty ); - confirm_type_is_not_a_method_generic_param(potential_self_ty, generics)?; + confirm_type_is_not_a_method_generic_param(potential_self_ty, method_generics)?; // Check if the self type unifies. If it does, then commit the result // since it may have region side-effects. From a43a37c706890aa6d7e1a01a021e8e5b3d6341b8 Mon Sep 17 00:00:00 2001 From: Henry Jiang Date: Wed, 30 Oct 2024 09:17:44 -0400 Subject: [PATCH 09/10] fix libc call from i8 to u8 --- compiler/rustc_session/src/filesearch.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index 4aae2649843b6..b3e3381d986b7 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -84,7 +84,7 @@ fn current_dll_path() -> Result { loop { if libc::loadquery( libc::L_GETINFO, - buffer.as_mut_ptr() as *mut i8, + buffer.as_mut_ptr() as *mut u8, (std::mem::size_of::() * buffer.len()) as u32, ) >= 0 { From 0900a1bd8037bc2042eb926b129123e942f00d33 Mon Sep 17 00:00:00 2001 From: Boxy Date: Wed, 30 Oct 2024 13:29:05 +0000 Subject: [PATCH 10/10] the unvacationer --- triagebot.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index 6fa92b4af0547..7f4def6a11ba4 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -966,7 +966,6 @@ cc = ["@kobzol"] warn_non_default_branch = true contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" users_on_vacation = [ - "BoxyUwU", "fmease", "jyn514", "oli-obk",