Skip to content

Rollup of 6 pull requests #132361

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Oct 30, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
@@ -720,6 +720,7 @@ dependencies = [
"miropt-test-tools",
"regex",
"rustfix",
"semver",
"serde",
"serde_json",
"tracing",
51 changes: 51 additions & 0 deletions compiler/rustc_error_codes/src/error_codes/E0801.md
Original file line number Diff line number Diff line change
@@ -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<R: std::ops::Deref<Target=Self>>(self: R) {}
}
```

or alternatively,

```compile_fail,E0801
struct Foo;

impl Foo {
fn foo(self: impl std::ops::Deref<Target=Self>) {}
}
```

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<Self>`. 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<Target=Self>`, for example `Rc<Self>`, `Box<Self>`, 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<Self>) {} // or some other similar
// smart pointer if you enable arbitrary self types and
// the pointer implements Deref<Target=Self>
}
```

[AST]: https://doc.rust-lang.org/unstable-book/language-features/arbitrary-self-types.html
1 change: 1 addition & 0 deletions compiler/rustc_error_codes/src/lib.rs
Original file line number Diff line number Diff line change
@@ -540,6 +540,7 @@ E0797: 0797,
E0798: 0798,
E0799: 0799,
E0800: 0800,
E0801: 0801,
);
)
}
6 changes: 6 additions & 0 deletions compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
@@ -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>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (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

61 changes: 52 additions & 9 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
@@ -904,7 +904,6 @@ 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)
}

@@ -1725,8 +1724,11 @@ fn check_method_receiver<'tcx>(
} else {
None
};
let generics = tcx.generics_of(method.def_id);

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 +1739,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 +1763,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 +1783,45 @@ 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: &ty::Generics,
) -> Result<(), ReceiverValidityError> {
if let ty::Param(param) = ty.kind() {
if (param.index as usize) >= method_generics.parent_count {
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 +1837,8 @@ fn receiver_is_valid<'tcx>(
receiver_ty: Ty<'tcx>,
self_ty: Ty<'tcx>,
arbitrary_self_types_enabled: Option<ArbitrarySelfTypesLevel>,
) -> bool {
method_generics: &ty::Generics,
) -> Result<(), ReceiverValidityError> {
let infcx = wfcx.infcx;
let tcx = wfcx.tcx();
let cause =
@@ -1811,9 +1850,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, method_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 +1871,8 @@ fn receiver_is_valid<'tcx>(
potential_self_ty, self_ty
);

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.
if let Ok(()) = wfcx.infcx.commit_if_ok(|_| {
@@ -1838,7 +1881,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 +1908,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>(
10 changes: 10 additions & 0 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
@@ -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]
3 changes: 0 additions & 3 deletions compiler/rustc_hir_typeck/src/method/confirm.rs
Original file line number Diff line number Diff line change
@@ -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(
111 changes: 58 additions & 53 deletions compiler/rustc_mir_dataflow/src/framework/graphviz.rs
Original file line number Diff line number Diff line change
@@ -32,8 +32,11 @@ pub(crate) struct Formatter<'mir, 'tcx, A>
where
A: Analysis<'tcx>,
{
body: &'mir Body<'tcx>,
results: RefCell<Option<Results<'tcx, A>>>,
// The `RefCell` is used because `<Formatter as Labeller>::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<ResultsCursor<'mir, 'tcx, A>>,
style: OutputStyle,
reachable: BitSet<BasicBlock>,
}
@@ -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()
}

@@ -90,20 +97,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<Option<_>>` 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 {
results: 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 };
let label = fmt.write_node_label(*block).unwrap();

fmt.write_node_label(&mut label, *block).unwrap();
Some(fmt.results.into_results())
});
dot::LabelText::html(String::from_utf8(label).unwrap())
}

@@ -112,20 +110,20 @@ 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>,
{
type Node = BasicBlock;
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 +132,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::<Vec<_>>()
.into()
}
@@ -147,20 +145,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>,
{
results: 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<A>,
@@ -173,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<Vec<u8>> {
use std::io::Write;

// Sample output:
// +-+-----------------------------------------------+
// A | bb4 |
@@ -200,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 <table>.

let mut v = vec![];
let w = &mut v;

let table_fmt = concat!(
" border=\"1\"",
" cellborder=\"1\"",
@@ -219,21 +222,21 @@ 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
self.write_statements_and_terminator(w, block)?;

// 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 +253,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,18 +268,18 @@ 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()
),
)
})?;
}

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 +293,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 +305,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 +320,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()
),
)
})?;
@@ -328,7 +331,9 @@ where
_ => {}
};

write!(w, "</table>")
write!(w, "</table>")?;

Ok(v)
}

fn write_block_header_simple(
@@ -407,9 +412,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 +425,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 +447,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 +497,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.
2 changes: 1 addition & 1 deletion compiler/rustc_session/src/filesearch.rs
Original file line number Diff line number Diff line change
@@ -84,7 +84,7 @@ fn current_dll_path() -> Result<PathBuf, String> {
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::<libc::ld_info>() * buffer.len()) as u32,
) >= 0
{
4 changes: 0 additions & 4 deletions src/librustdoc/doctest/runner.rs
Original file line number Diff line number Diff line change
@@ -198,10 +198,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 {
1 change: 1 addition & 0 deletions src/tools/compiletest/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"
3 changes: 2 additions & 1 deletion src/tools/compiletest/src/common.rs
Original file line number Diff line number Diff line change
@@ -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<u32>,

/// Version of LLVM
pub llvm_version: Option<u32>,
pub llvm_version: Option<Version>,

/// Is LLVM a system LLVM
pub system_llvm: bool,
112 changes: 70 additions & 42 deletions src/tools/compiletest/src/header.rs
Original file line number Diff line number Diff line change
@@ -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,34 +1114,47 @@ fn parse_normalize_rule(header: &str) -> Option<(String, String)> {
Some((regex, replacement))
}

pub fn extract_llvm_version(version: &str) -> Option<u32> {
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<u32> = version_without_suffix

let components: Vec<u64> = 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<u32> {
pub fn extract_llvm_version_from_binary(binary_path: &str) -> Option<Version> {
let output = Command::new(binary_path).arg("--version").output().ok()?;
if !output.status.success() {
return None;
}
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 `"<version1> [- <version2>]"`,
/// returns the numeric representation of `<version1>` and `<version2>` as
/// tuple: `(<version1> as u32, <version2> as u32)`.
/// Takes a directive of the form `"<version1> [- <version2>]"`, returns the numeric representation
/// of `<version1>` and `<version2>` as tuple: `(<version1>, <version2>)`.
///
/// If the `<version2>` part is omitted, the second component of the tuple
/// is the same as `<version1>`.
fn extract_version_range<F>(line: &str, parse: F) -> Option<(u32, u32)>
/// If the `<version2>` part is omitted, the second component of the tuple is the same as
/// `<version1>`.
fn extract_version_range<'a, F, VersionTy: Clone>(
line: &'a str,
parse: F,
) -> Option<(VersionTy, VersionTy)>
where
F: Fn(&str) -> Option<u32>,
F: Fn(&'a str) -> Option<VersionTy>,
{
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: <version1> [- <version2>]"
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}"
),
};
}
}
78 changes: 65 additions & 13 deletions src/tools/compiletest/src/header/tests.rs
Original file line number Diff line number Diff line change
@@ -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<R: Read>(
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]
2 changes: 1 addition & 1 deletion src/tools/compiletest/src/lib.rs
Original file line number Diff line number Diff line change
@@ -228,7 +228,7 @@ pub fn parse_config(args: Vec<String>) -> 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")?),
);

13 changes: 0 additions & 13 deletions src/tools/compiletest/src/tests.rs
Original file line number Diff line number Diff line change
@@ -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));
}
1 change: 0 additions & 1 deletion src/tools/tidy/src/issues.txt
Original file line number Diff line number Diff line change
@@ -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
15 changes: 15 additions & 0 deletions tests/rustdoc-ui/doctest/dead-code-2024.rs
Original file line number Diff line number Diff line change
@@ -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() {}
29 changes: 29 additions & 0 deletions tests/rustdoc-ui/doctest/dead-code-2024.stdout
Original file line number Diff line number Diff line change
@@ -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

15 changes: 15 additions & 0 deletions tests/rustdoc-ui/doctest/dead-code.rs
Original file line number Diff line number Diff line change
@@ -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() {}
29 changes: 29 additions & 0 deletions tests/rustdoc-ui/doctest/dead-code.stdout
Original file line number Diff line number Diff line change
@@ -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

2 changes: 1 addition & 1 deletion tests/ui/self/arbitrary-self-from-method-substs-ice.rs
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ use std::ops::Deref;
struct Foo(u32);
impl Foo {
const fn get<R: Deref<Target = Self>>(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 `<R as Deref>::deref` in constant function
10 changes: 4 additions & 6 deletions tests/ui/self/arbitrary-self-from-method-substs-ice.stderr
Original file line number Diff line number Diff line change
@@ -15,18 +15,16 @@ LL | const fn get<R: Deref<Target = Self>>(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<R: Deref<Target = Self>>(self: R) -> u32 {
| ^
|
= note: see issue #44874 <https://github.com/rust-lang/rust/issues/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>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (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>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (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`.
162 changes: 158 additions & 4 deletions tests/ui/self/arbitrary-self-from-method-substs.default.stderr
Original file line number Diff line number Diff line change
@@ -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<R: Deref<Target = Self>>(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>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (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<R: Deref<Target = Self>>(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>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (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<R: Deref<Target = Self>>(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>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (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:21:44
|
LL | fn get3<R: Deref<Target = Self>>(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>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (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:25:44
|
LL | fn get4<R: Deref<Target = Self>>(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>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (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<R: Deref<Target = Self>>(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>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)

error[E0658]: `<FR as FindReceiver>::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<FR: FindReceiver>(self: FR::Receiver, other: FR) -> u32 {
| ^^^^^^^^^^^^
|
= note: see issue #44874 <https://github.com/rust-lang/rust/issues/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>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (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 <https://github.com/rust-lang/rust/issues/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>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)

error[E0271]: type mismatch resolving `<Silly as FindReceiver>::Receiver == Foo`
--> $DIR/arbitrary-self-from-method-substs.rs:92:9
|
LL | foo.get6(Silly);
| ^^^^ type mismatch resolving `<Silly as FindReceiver>::Receiver == Foo`
|
note: expected this to be `Foo`
--> $DIR/arbitrary-self-from-method-substs.rs:71:21
|
LL | type Receiver = std::rc::Rc<Foo>;
| ^^^^^^^^^^^^^^^^
= note: expected struct `Foo`
found struct `Rc<Foo>`

error[E0271]: type mismatch resolving `<Silly as FindReceiver>::Receiver == &Foo`
--> $DIR/arbitrary-self-from-method-substs.rs:96:9
|
LL | foo.get6(Silly);
| ^^^^ type mismatch resolving `<Silly as FindReceiver>::Receiver == &Foo`
|
note: expected this to be `&Foo`
--> $DIR/arbitrary-self-from-method-substs.rs:71:21
|
LL | type Receiver = std::rc::Rc<Foo>;
| ^^^^^^^^^^^^^^^^
= note: expected reference `&Foo`
found struct `Rc<Foo>`

error[E0599]: the method `get` exists for struct `Rc<Bar<_>>`, but its trait bounds were not satisfied
--> $DIR/arbitrary-self-from-method-substs.rs:100:7
|
LL | struct Bar<R>(std::marker::PhantomData<R>);
| ------------- doesn't satisfy `Bar<_>: Deref`
...
LL | t.get();
| ^^^ method cannot be called on `Rc<Bar<_>>` due to unsatisfied trait bounds
|
note: the following trait bounds were not satisfied:
`<&Bar<_> as Deref>::Target = Bar<&Bar<_>>`
`<&Rc<Bar<_>> as Deref>::Target = Bar<&Rc<Bar<_>>>`
`<&mut Bar<_> as Deref>::Target = Bar<&mut Bar<_>>`
`<&mut Rc<Bar<_>> as Deref>::Target = Bar<&mut Rc<Bar<_>>>`
`<Rc<Bar<_>> as Deref>::Target = Bar<Rc<Bar<_>>>`
`Bar<_>: Deref`
--> $DIR/arbitrary-self-from-method-substs.rs:60:9
|
LL | impl<R: std::ops::Deref<Target = Self>> Bar<R> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------
| | |
| | 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<Bar<_>>`, but its trait bounds were not satisfied
--> $DIR/arbitrary-self-from-method-substs.rs:108:7
|
LL | struct Bar<R>(std::marker::PhantomData<R>);
| ------------- doesn't satisfy `Bar<_>: Deref`
...
LL | t.get();
| ^^^ method cannot be called on `&Rc<Bar<_>>` due to unsatisfied trait bounds
|
note: the following trait bounds were not satisfied:
`<&&Rc<Bar<_>> as Deref>::Target = Bar<&&Rc<Bar<_>>>`
`<&Bar<_> as Deref>::Target = Bar<&Bar<_>>`
`<&Rc<Bar<_>> as Deref>::Target = Bar<&Rc<Bar<_>>>`
`<&mut &Rc<Bar<_>> as Deref>::Target = Bar<&mut &Rc<Bar<_>>>`
`<&mut Bar<_> as Deref>::Target = Bar<&mut Bar<_>>`
`<&mut Rc<Bar<_>> as Deref>::Target = Bar<&mut Rc<Bar<_>>>`
`<Rc<Bar<_>> as Deref>::Target = Bar<Rc<Bar<_>>>`
`Bar<_>: Deref`
--> $DIR/arbitrary-self-from-method-substs.rs:60:9
|
LL | impl<R: std::ops::Deref<Target = Self>> Bar<R> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------
| | |
| | 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`.
176 changes: 173 additions & 3 deletions tests/ui/self/arbitrary-self-from-method-substs.feature.stderr
Original file line number Diff line number Diff line change
@@ -1,9 +1,179 @@
error[E0801]: invalid generic `self` parameter type: `R`
--> $DIR/arbitrary-self-from-method-substs.rs:9:43
|
LL | fn get<R: Deref<Target = Self>>(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>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (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<R: Deref<Target = Self>>(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>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (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<R: Deref<Target = Self>>(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>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (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:21:44
|
LL | fn get3<R: Deref<Target = Self>>(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>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (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:25:44
|
LL | fn get4<R: Deref<Target = Self>>(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>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (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<R: Deref<Target = Self>>(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>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (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::<std::rc::Rc<Foo>>();
| ^^^ expected `Rc<Foo>`, found `Foo`
|
= note: expected struct `Rc<Foo>`
found struct `Foo`

error[E0308]: mismatched types
--> $DIR/arbitrary-self-from-method-substs.rs:84:5
|
LL | smart_ptr.get::<SmartPtr2<Foo>>();
| ^^^^^^^^^ 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 `<Silly as FindReceiver>::Receiver == Foo`
--> $DIR/arbitrary-self-from-method-substs.rs:92:9
|
LL | foo.get6(Silly);
| ^^^^ type mismatch resolving `<Silly as FindReceiver>::Receiver == Foo`
|
note: expected this to be `Foo`
--> $DIR/arbitrary-self-from-method-substs.rs:71:21
|
LL | type Receiver = std::rc::Rc<Foo>;
| ^^^^^^^^^^^^^^^^
= note: expected struct `Foo`
found struct `Rc<Foo>`

error[E0271]: type mismatch resolving `<Silly as FindReceiver>::Receiver == &Foo`
--> $DIR/arbitrary-self-from-method-substs.rs:96:9
|
LL | foo.get6(Silly);
| ^^^^ type mismatch resolving `<Silly as FindReceiver>::Receiver == &Foo`
|
note: expected this to be `&Foo`
--> $DIR/arbitrary-self-from-method-substs.rs:71:21
|
LL | type Receiver = std::rc::Rc<Foo>;
| ^^^^^^^^^^^^^^^^
= note: expected reference `&Foo`
found struct `Rc<Foo>`

error[E0599]: the method `get` exists for struct `Rc<Bar<_>>`, but its trait bounds were not satisfied
--> $DIR/arbitrary-self-from-method-substs.rs:100:7
|
LL | struct Bar<R>(std::marker::PhantomData<R>);
| ------------- doesn't satisfy `Bar<_>: Deref`
...
LL | t.get();
| ^^^ method cannot be called on `Rc<Bar<_>>` due to unsatisfied trait bounds
|
note: the following trait bounds were not satisfied:
`<&Bar<_> as Deref>::Target = Bar<&Bar<_>>`
`<&Rc<Bar<_>> as Deref>::Target = Bar<&Rc<Bar<_>>>`
`<&mut Bar<_> as Deref>::Target = Bar<&mut Bar<_>>`
`<&mut Rc<Bar<_>> as Deref>::Target = Bar<&mut Rc<Bar<_>>>`
`<Rc<Bar<_>> as Deref>::Target = Bar<Rc<Bar<_>>>`
`Bar<_>: Deref`
--> $DIR/arbitrary-self-from-method-substs.rs:60:9
|
LL | impl<R: std::ops::Deref<Target = Self>> Bar<R> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------
| | |
| | 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<Bar<_>>`, but its trait bounds were not satisfied
--> $DIR/arbitrary-self-from-method-substs.rs:108:7
|
LL | struct Bar<R>(std::marker::PhantomData<R>);
| ------------- doesn't satisfy `Bar<_>: Deref`
...
LL | t.get();
| ^^^ method cannot be called on `&Rc<Bar<_>>` due to unsatisfied trait bounds
|
note: the following trait bounds were not satisfied:
`<&&Rc<Bar<_>> as Deref>::Target = Bar<&&Rc<Bar<_>>>`
`<&Bar<_> as Deref>::Target = Bar<&Bar<_>>`
`<&Rc<Bar<_>> as Deref>::Target = Bar<&Rc<Bar<_>>>`
`<&mut &Rc<Bar<_>> as Deref>::Target = Bar<&mut &Rc<Bar<_>>>`
`<&mut Bar<_> as Deref>::Target = Bar<&mut Bar<_>>`
`<&mut Rc<Bar<_>> as Deref>::Target = Bar<&mut Rc<Bar<_>>>`
`<Rc<Bar<_>> as Deref>::Target = Bar<Rc<Bar<_>>>`
`Bar<_>: Deref`
--> $DIR/arbitrary-self-from-method-substs.rs:60:9
|
LL | impl<R: std::ops::Deref<Target = Self>> Bar<R> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------
| | |
| | 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`.
94 changes: 93 additions & 1 deletion tests/ui/self/arbitrary-self-from-method-substs.rs
Original file line number Diff line number Diff line change
@@ -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<R: Deref<Target = Self>>(self: R) -> u32 {
//[default]~^ ERROR: `R` cannot be used as the type of `self`
//~^ ERROR: invalid generic `self` parameter type
self.0
}
fn get1<R: Deref<Target = Self>>(self: &R) -> u32 {
//~^ ERROR: invalid generic `self` parameter type
self.0
}
fn get2<R: Deref<Target = Self>>(self: &mut R) -> u32 {
//~^ ERROR: invalid generic `self` parameter type
self.0
}
fn get3<R: Deref<Target = Self>>(self: std::rc::Rc<R>) -> u32 {
//~^ ERROR: invalid generic `self` parameter type
self.0
}
fn get4<R: Deref<Target = Self>>(self: &std::rc::Rc<R>) -> u32 {
//~^ ERROR: invalid generic `self` parameter type
self.0
}
fn get5<R: Deref<Target = Self>>(self: std::rc::Rc<&R>) -> u32 {
//~^ ERROR: invalid generic `self` parameter type
self.0
}
fn get6<FR: FindReceiver>(self: FR::Receiver, other: FR) -> u32 {
//[default]~^ ERROR: `<FR as FindReceiver>::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<R>(std::marker::PhantomData<R>);

impl<R: std::ops::Deref<Target = Self>> Bar<R> {
fn get(self: R) {}
//[default]~^ ERROR: `R` cannot be used as the type of `self`
}

trait FindReceiver {
type Receiver: Deref<Target = Foo>;
}

struct Silly;
impl FindReceiver for Silly {
type Receiver = std::rc::Rc<Foo>;
}

fn main() {
let mut foo = Foo(1);
foo.get::<&Foo>();
//[feature]~^ ERROR mismatched types
foo.get::<std::rc::Rc<Foo>>();
//[feature]~^ ERROR mismatched types

let smart_ptr = SmartPtr(&foo);
let smart_ptr2 = SmartPtr2(&foo);
smart_ptr.get(); // this compiles
smart_ptr.get::<SmartPtr2<Foo>>();
//[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<Rc<Target=Self>> 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
}
21 changes: 0 additions & 21 deletions tests/ui/type-alias-impl-trait/issue-57700.rs

This file was deleted.

8 changes: 0 additions & 8 deletions tests/ui/type-alias-impl-trait/issue-57700.stderr

This file was deleted.

1 change: 0 additions & 1 deletion triagebot.toml
Original file line number Diff line number Diff line change
@@ -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",