mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-01 23:12:02 +00:00
Auto merge of #106851 - matthiaskrgr:rollup-d9dz3yp, r=matthiaskrgr
Rollup of 10 pull requests Successful merges: - #106046 (Fix mir-opt tests for big-endian platforms) - #106470 (tidy: Don't include wasm32 in compiler dependency check) - #106566 (Emit a single error for contiguous sequences of unknown tokens) - #106644 (Update the wasi-libc used for the wasm32-wasi target) - #106665 (Add note when `FnPtr` vs. `FnDef` impl trait) - #106752 (Emit a hint for bad call return types due to generic arguments) - #106788 (Tweak E0599 and elaborate_predicates) - #106831 (Use GitHub yaml templates for ICE, Docs and Diagnostics tickets) - #106846 (Improve some comments and names in parser) - #106848 (Fix wrong path in triage bot autolabel for wg-trait-solver-refactor) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
4b51adf6ff
46
.github/ISSUE_TEMPLATE/diagnostics.md
vendored
46
.github/ISSUE_TEMPLATE/diagnostics.md
vendored
@ -1,46 +0,0 @@
|
||||
---
|
||||
name: Diagnostic issue
|
||||
about: Create a bug report or feature request for a change to `rustc`'s error output
|
||||
labels: A-diagnostics, T-compiler
|
||||
---
|
||||
<!--
|
||||
Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
|
||||
along with any information you feel relevant to replicating the bug.
|
||||
|
||||
If you cannot produce a minimal reproduction case (something that would work in
|
||||
isolation), please provide the steps or even link to a repository that causes
|
||||
the problematic output to occur.
|
||||
-->
|
||||
|
||||
Given the following code: <!-- Please provide a link to play.rust-lang.org -->
|
||||
|
||||
```rust
|
||||
<code>
|
||||
```
|
||||
|
||||
The current output is:
|
||||
|
||||
```
|
||||
<rustc output>
|
||||
```
|
||||
|
||||
<!-- The following is not always necessary. -->
|
||||
Ideally the output should look like:
|
||||
|
||||
```
|
||||
<proposed output>
|
||||
```
|
||||
|
||||
<!--
|
||||
If the problem is not self-explanatory, please provide a rationale for the
|
||||
change.
|
||||
-->
|
||||
|
||||
<!--
|
||||
If dramatically different output is caused by small changes, consider also
|
||||
adding them here.
|
||||
|
||||
If you're using the stable version of the compiler, you should also check if the
|
||||
bug also exists in the beta or nightly versions. The output might also be
|
||||
different depending on the Edition.
|
||||
-->
|
65
.github/ISSUE_TEMPLATE/diagnostics.yaml
vendored
Normal file
65
.github/ISSUE_TEMPLATE/diagnostics.yaml
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
name: Diagnostic issue
|
||||
description: Create a bug report or feature request for a change to `rustc`'s error output
|
||||
labels: ["A-diagnostics", "T-compiler"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thank you for filing a diagnostics bug report! 🐛
|
||||
|
||||
Please provide a short summary of the bug, along with any information you feel relevant to replicating the bug.
|
||||
|
||||
If you cannot produce a minimal reproduction case (something that would work in isolation), please provide the steps or even link to a repository that causes the problematic output to occur.
|
||||
- type: textarea
|
||||
id: code
|
||||
attributes:
|
||||
label: Code
|
||||
description: Please provide code that can reproduce the problem
|
||||
placeholder: code
|
||||
render: Rust
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: output
|
||||
attributes:
|
||||
label: Current output
|
||||
description: Please provide the `rustc` output you see
|
||||
placeholder: rustc output
|
||||
render: Shell
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: desired-output
|
||||
attributes:
|
||||
label: Desired output
|
||||
description: Please provide what the output *should* be
|
||||
placeholder: proposed output
|
||||
render: Shell
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: rationale
|
||||
attributes:
|
||||
label: Rationale and extra context
|
||||
description: If the problem is not self-explanatory, please provide a rationale for the change.
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: other-output
|
||||
attributes:
|
||||
label: Other cases
|
||||
description: If dramatically different output is caused by small changes, consider also adding them here.
|
||||
render: Rust
|
||||
validations:
|
||||
required: false
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. The output might also be different depending on the Edition.
|
||||
- type: textarea
|
||||
id: extra
|
||||
attributes:
|
||||
label: Anything else?
|
||||
description: If you have more details you want to give us to reproduce this issue, please add it here
|
||||
validations:
|
||||
required: false
|
31
.github/ISSUE_TEMPLATE/documentation.md
vendored
31
.github/ISSUE_TEMPLATE/documentation.md
vendored
@ -1,31 +0,0 @@
|
||||
---
|
||||
name: Documentation problem
|
||||
about: Create a report for a documentation problem.
|
||||
labels: A-docs
|
||||
---
|
||||
<!--
|
||||
|
||||
Thank you for finding a documentation problem! 📚
|
||||
|
||||
Documentation problems might be grammatical issues, typos, or unclear wording, please provide details regarding the documentation including where it is present.
|
||||
|
||||
Note: If your issue is for one of these, please use their dedicated issue tracker instead:
|
||||
|
||||
- The Rust Book: https://github.com/rust-lang/book/issues
|
||||
- Rust by Example: https://github.com/rust-lang/rust-by-example/issues
|
||||
- The Edition Guide: https://github.com/rust-lang/edition-guide/issues
|
||||
- The Cargo Book: https://github.com/rust-lang/cargo/issues
|
||||
- The Clippy Book: https://github.com/rust-lang/rust-clippy/issues
|
||||
- The Reference: https://github.com/rust-lang/reference/issues
|
||||
- The Rustonomicon: https://github.com/rust-lang/nomicon/issues
|
||||
- The Embedded Book: https://github.com/rust-embedded/book/issues
|
||||
|
||||
All other documentation issues should be filed here.
|
||||
|
||||
Or, if you find an issue related to rustdoc (e.g. doctest, rustdoc UI), please use the bug report or blank issue template instead.
|
||||
|
||||
-->
|
||||
|
||||
### Location
|
||||
|
||||
### Summary
|
38
.github/ISSUE_TEMPLATE/documentation.yaml
vendored
Normal file
38
.github/ISSUE_TEMPLATE/documentation.yaml
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
name: Documentation problem
|
||||
description: Create a report for a documentation problem.
|
||||
labels: ["A-docs"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thank you for finding a documentation problem! 📚
|
||||
|
||||
Documentation problems might be grammatical issues, typos, or unclear wording, please provide details regarding the documentation including where it is present.
|
||||
|
||||
Note: If your issue is for one of these, please use their dedicated issue tracker instead:
|
||||
- [The Rust Book](https://github.com/rust-lang/book/issues)
|
||||
- [Rust by Example](https://github.com/rust-lang/rust-by-example/issues)
|
||||
- [The Edition Guide](https://github.com/rust-lang/edition-guide/issues)
|
||||
- [The Cargo Book](https://github.com/rust-lang/cargo/issues)
|
||||
- [The Clippy Book](https://github.com/rust-lang/rust-clippy/issues)
|
||||
- [The Reference](https://github.com/rust-lang/reference/issues)
|
||||
- [The Rustonomicon](https://github.com/rust-lang/nomicon/issues)
|
||||
- [The Embedded Book](https://github.com/rust-embedded/book/issues)
|
||||
|
||||
All other documentation issues should be filed here.
|
||||
|
||||
Or, if you find an issue related to rustdoc (e.g. doctest, rustdoc UI), please use the bug report or blank issue template instead.
|
||||
|
||||
- type: textarea
|
||||
id: location
|
||||
attributes:
|
||||
label: Location
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: summary
|
||||
attributes:
|
||||
label: Summary
|
||||
validations:
|
||||
required: true
|
52
.github/ISSUE_TEMPLATE/ice.md
vendored
52
.github/ISSUE_TEMPLATE/ice.md
vendored
@ -1,52 +0,0 @@
|
||||
---
|
||||
name: Internal Compiler Error
|
||||
about: Create a report for an internal compiler error in rustc.
|
||||
labels: C-bug, I-ICE, T-compiler
|
||||
---
|
||||
<!--
|
||||
Thank you for finding an Internal Compiler Error! 🧊 If possible, try to provide
|
||||
a minimal verifiable example. You can read "Rust Bug Minimization Patterns" for
|
||||
how to create smaller examples.
|
||||
|
||||
http://blog.pnkfx.org/blog/2019/11/18/rust-bug-minimization-patterns/
|
||||
|
||||
-->
|
||||
|
||||
### Code
|
||||
|
||||
```Rust
|
||||
<code>
|
||||
```
|
||||
|
||||
|
||||
### Meta
|
||||
<!--
|
||||
If you're using the stable version of the compiler, you should also check if the
|
||||
bug also exists in the beta or nightly versions.
|
||||
-->
|
||||
|
||||
`rustc --version --verbose`:
|
||||
```
|
||||
<version>
|
||||
```
|
||||
|
||||
### Error output
|
||||
|
||||
```
|
||||
<output>
|
||||
```
|
||||
|
||||
<!--
|
||||
Include a backtrace in the code block by setting `RUST_BACKTRACE=1` in your
|
||||
environment. E.g. `RUST_BACKTRACE=1 cargo build`.
|
||||
-->
|
||||
<details><summary><strong>Backtrace</strong></summary>
|
||||
<p>
|
||||
|
||||
```
|
||||
<backtrace>
|
||||
```
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
82
.github/ISSUE_TEMPLATE/ice.yaml
vendored
Normal file
82
.github/ISSUE_TEMPLATE/ice.yaml
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
name: Internal Compiler Error
|
||||
description: Create a report for an internal compiler error in `rustc`
|
||||
labels: ["C-bug", "I-ICE", "T-compiler"]
|
||||
title: "[ICE]: "
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thank you for finding an Internal Compiler Error! 🧊
|
||||
|
||||
If possible, try to provide a minimal verifiable example.
|
||||
|
||||
You can read "[Rust Bug Minimization Patterns](http://blog.pnkfx.org/blog/2019/11/18/rust-bug-minimization-patterns/)" for how to create smaller examples.
|
||||
|
||||
- type: textarea
|
||||
id: code
|
||||
attributes:
|
||||
label: Code
|
||||
description: Please provide code or a link to a repository that can reproduce the problem
|
||||
placeholder: code
|
||||
render: Rust
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Affected release channels
|
||||
description: If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions
|
||||
options:
|
||||
- label: Previous Stable
|
||||
required: false
|
||||
- label: Current Stable
|
||||
required: false
|
||||
- label: Current Beta
|
||||
required: false
|
||||
- label: Current Nightly
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
id: version
|
||||
attributes:
|
||||
label: Rust Version
|
||||
description: Please provide the `rustc` version, `rustc --version --verbose`
|
||||
placeholder: |
|
||||
$ rustc --version --verbose
|
||||
rustc 1.XX.Y (SHORTHASH DATE)
|
||||
binary: rustc
|
||||
commit-hash: LONGHASHVALUE
|
||||
commit-date: DATE
|
||||
host: PLATFORMTRIPLE
|
||||
release: 1.XX.Y
|
||||
LLVM version: XX.YY.ZZ
|
||||
render: Shell
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: output
|
||||
attributes:
|
||||
label: Current error output
|
||||
description: Please provide the `rustc` output you see
|
||||
placeholder: output
|
||||
render: Shell
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
id: backtrace
|
||||
attributes:
|
||||
label: Backtrace
|
||||
description: Include a backtrace in the code block by setting `RUST_BACKTRACE=full` in your environment, e.g. `RUST_BACKTRACE=full cargo build`
|
||||
render: Shell
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: extra
|
||||
attributes:
|
||||
label: Anything else?
|
||||
description: If you have more details you want to give us to reproduce this issue, please add it here
|
||||
validations:
|
||||
required: false
|
@ -5601,6 +5601,7 @@ dependencies = [
|
||||
name = "tidy"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cargo-platform 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cargo_metadata 0.14.0",
|
||||
"ignore",
|
||||
"lazy_static",
|
||||
|
@ -85,6 +85,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
|
||||
self.check_for_range_as_method_call(err, expr, expr_ty, expected);
|
||||
self.check_for_binding_assigned_block_without_tail_expression(err, expr, expr_ty, expected);
|
||||
self.check_wrong_return_type_due_to_generic_arg(err, expr, expr_ty);
|
||||
}
|
||||
|
||||
/// Requires that the two types unify, and prints an error message if
|
||||
@ -1941,4 +1942,77 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
err.span_label(block.span, "this block is missing a tail expression");
|
||||
}
|
||||
}
|
||||
|
||||
fn check_wrong_return_type_due_to_generic_arg(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
expr: &hir::Expr<'_>,
|
||||
checked_ty: Ty<'tcx>,
|
||||
) {
|
||||
let Some(hir::Node::Expr(parent_expr)) = self.tcx.hir().find_parent(expr.hir_id) else { return; };
|
||||
enum CallableKind {
|
||||
Function,
|
||||
Method,
|
||||
Constructor,
|
||||
}
|
||||
let mut maybe_emit_help = |def_id: hir::def_id::DefId,
|
||||
callable: rustc_span::symbol::Ident,
|
||||
args: &[hir::Expr<'_>],
|
||||
kind: CallableKind| {
|
||||
let arg_idx = args.iter().position(|a| a.hir_id == expr.hir_id).unwrap();
|
||||
let fn_ty = self.tcx.bound_type_of(def_id).0;
|
||||
if !fn_ty.is_fn() {
|
||||
return;
|
||||
}
|
||||
let fn_sig = fn_ty.fn_sig(self.tcx).skip_binder();
|
||||
let Some(&arg) = fn_sig.inputs().get(arg_idx + if matches!(kind, CallableKind::Method) { 1 } else { 0 }) else { return; };
|
||||
if matches!(arg.kind(), ty::Param(_))
|
||||
&& fn_sig.output().contains(arg)
|
||||
&& self.node_ty(args[arg_idx].hir_id) == checked_ty
|
||||
{
|
||||
let mut multi_span: MultiSpan = parent_expr.span.into();
|
||||
multi_span.push_span_label(
|
||||
args[arg_idx].span,
|
||||
format!(
|
||||
"this argument influences the {} of `{}`",
|
||||
if matches!(kind, CallableKind::Constructor) {
|
||||
"type"
|
||||
} else {
|
||||
"return type"
|
||||
},
|
||||
callable
|
||||
),
|
||||
);
|
||||
err.span_help(
|
||||
multi_span,
|
||||
format!(
|
||||
"the {} `{}` due to the type of the argument passed",
|
||||
match kind {
|
||||
CallableKind::Function => "return type of this call is",
|
||||
CallableKind::Method => "return type of this call is",
|
||||
CallableKind::Constructor => "type constructed contains",
|
||||
},
|
||||
checked_ty
|
||||
),
|
||||
);
|
||||
}
|
||||
};
|
||||
match parent_expr.kind {
|
||||
hir::ExprKind::Call(fun, args) => {
|
||||
let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = fun.kind else { return; };
|
||||
let hir::def::Res::Def(kind, def_id) = path.res else { return; };
|
||||
let callable_kind = if matches!(kind, hir::def::DefKind::Ctor(_, _)) {
|
||||
CallableKind::Constructor
|
||||
} else {
|
||||
CallableKind::Function
|
||||
};
|
||||
maybe_emit_help(def_id, path.segments[0].ident, args, callable_kind);
|
||||
}
|
||||
hir::ExprKind::MethodCall(method, _receiver, args, _span) => {
|
||||
let Some(def_id) = self.typeck_results.borrow().type_dependent_def_id(parent_expr.hir_id) else { return; };
|
||||
maybe_emit_help(def_id, method.ident, args, CallableKind::Method)
|
||||
}
|
||||
_ => return,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1587,11 +1587,29 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
let o = self.resolve_vars_if_possible(o);
|
||||
if !self.predicate_may_hold(&o) {
|
||||
result = ProbeResult::NoMatch;
|
||||
possibly_unsatisfied_predicates.push((
|
||||
o.predicate,
|
||||
None,
|
||||
Some(o.cause),
|
||||
));
|
||||
let parent_o = o.clone();
|
||||
let implied_obligations =
|
||||
traits::elaborate_obligations(self.tcx, vec![o]);
|
||||
for o in implied_obligations {
|
||||
let parent = if o == parent_o {
|
||||
None
|
||||
} else {
|
||||
if o.predicate.to_opt_poly_trait_pred().map(|p| p.def_id())
|
||||
== self.tcx.lang_items().sized_trait()
|
||||
{
|
||||
// We don't care to talk about implicit `Sized` bounds.
|
||||
continue;
|
||||
}
|
||||
Some(parent_o.predicate)
|
||||
};
|
||||
if !self.predicate_may_hold(&o) {
|
||||
possibly_unsatisfied_predicates.push((
|
||||
o.predicate,
|
||||
parent,
|
||||
Some(o.cause),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -505,19 +505,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
|
||||
if let Some(g) = kind.generics() {
|
||||
let key = (
|
||||
g.tail_span_for_predicate_suggestion(),
|
||||
g.add_where_or_trailing_comma(),
|
||||
);
|
||||
type_params
|
||||
.entry(key)
|
||||
.or_insert_with(FxHashSet::default)
|
||||
.insert(obligation.to_owned());
|
||||
}
|
||||
if let Some(hir::Node::Item(hir::Item { kind, .. })) = node
|
||||
&& let Some(g) = kind.generics()
|
||||
{
|
||||
let key = (
|
||||
g.tail_span_for_predicate_suggestion(),
|
||||
g.add_where_or_trailing_comma(),
|
||||
);
|
||||
type_params
|
||||
.entry(key)
|
||||
.or_insert_with(FxHashSet::default)
|
||||
.insert(obligation.to_owned());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
};
|
||||
let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
|
||||
let msg = format!(
|
||||
@ -692,7 +694,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
"auto trait is invoked with no method error, but no error reported?",
|
||||
);
|
||||
}
|
||||
Some(_) => unreachable!(),
|
||||
Some(Node::Item(hir::Item {
|
||||
ident, kind: hir::ItemKind::Trait(..), ..
|
||||
})) => {
|
||||
skip_list.insert(p);
|
||||
let entry = spanned_predicates.entry(ident.span);
|
||||
let entry = entry.or_insert_with(|| {
|
||||
(FxHashSet::default(), FxHashSet::default(), Vec::new())
|
||||
});
|
||||
entry.0.insert(cause.span);
|
||||
entry.1.insert((ident.span, ""));
|
||||
entry.1.insert((cause.span, "unsatisfied trait bound introduced here"));
|
||||
entry.2.push(p);
|
||||
}
|
||||
Some(node) => unreachable!("encountered `{node:?}`"),
|
||||
None => (),
|
||||
}
|
||||
}
|
||||
@ -719,19 +734,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
unsatisfied_bounds = true;
|
||||
}
|
||||
|
||||
let mut suggested_bounds = FxHashSet::default();
|
||||
// The requirements that didn't have an `impl` span to show.
|
||||
let mut bound_list = unsatisfied_predicates
|
||||
.iter()
|
||||
.filter_map(|(pred, parent_pred, _cause)| {
|
||||
let mut suggested = false;
|
||||
format_pred(*pred).map(|(p, self_ty)| {
|
||||
collect_type_param_suggestions(self_ty, *pred, &p);
|
||||
if let Some(parent) = parent_pred && suggested_bounds.contains(parent) {
|
||||
// We don't suggest `PartialEq` when we already suggest `Eq`.
|
||||
} else if !suggested_bounds.contains(pred) {
|
||||
if collect_type_param_suggestions(self_ty, *pred, &p) {
|
||||
suggested = true;
|
||||
suggested_bounds.insert(pred);
|
||||
}
|
||||
}
|
||||
(
|
||||
match parent_pred {
|
||||
None => format!("`{}`", &p),
|
||||
Some(parent_pred) => match format_pred(*parent_pred) {
|
||||
None => format!("`{}`", &p),
|
||||
Some((parent_p, _)) => {
|
||||
collect_type_param_suggestions(self_ty, *parent_pred, &p);
|
||||
if !suggested
|
||||
&& !suggested_bounds.contains(pred)
|
||||
&& !suggested_bounds.contains(parent_pred)
|
||||
{
|
||||
if collect_type_param_suggestions(
|
||||
self_ty,
|
||||
*parent_pred,
|
||||
&p,
|
||||
) {
|
||||
suggested_bounds.insert(pred);
|
||||
}
|
||||
}
|
||||
format!("`{}`\nwhich is required by `{}`", p, parent_p)
|
||||
}
|
||||
},
|
||||
|
@ -1,7 +1,7 @@
|
||||
use smallvec::smallvec;
|
||||
|
||||
use crate::infer::outlives::components::{push_outlives_components, Component};
|
||||
use crate::traits::{Obligation, ObligationCause, PredicateObligation};
|
||||
use crate::traits::{self, Obligation, ObligationCause, PredicateObligation};
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
|
||||
use rustc_middle::ty::{self, ToPredicate, TyCtxt};
|
||||
use rustc_span::symbol::Ident;
|
||||
@ -145,16 +145,28 @@ impl<'tcx> Elaborator<'tcx> {
|
||||
// Get predicates declared on the trait.
|
||||
let predicates = tcx.super_predicates_of(data.def_id());
|
||||
|
||||
let obligations = predicates.predicates.iter().map(|&(mut pred, _)| {
|
||||
let obligations = predicates.predicates.iter().map(|&(mut pred, span)| {
|
||||
// when parent predicate is non-const, elaborate it to non-const predicates.
|
||||
if data.constness == ty::BoundConstness::NotConst {
|
||||
pred = pred.without_const(tcx);
|
||||
}
|
||||
|
||||
let cause = obligation.cause.clone().derived_cause(
|
||||
bound_predicate.rebind(data),
|
||||
|derived| {
|
||||
traits::ImplDerivedObligation(Box::new(
|
||||
traits::ImplDerivedObligationCause {
|
||||
derived,
|
||||
impl_def_id: data.def_id(),
|
||||
span,
|
||||
},
|
||||
))
|
||||
},
|
||||
);
|
||||
predicate_obligation(
|
||||
pred.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)),
|
||||
obligation.param_env,
|
||||
obligation.cause.clone(),
|
||||
cause,
|
||||
)
|
||||
});
|
||||
debug!(?data, ?obligations, "super_predicates");
|
||||
|
@ -79,7 +79,7 @@ impl<'a> StringReader<'a> {
|
||||
/// preceded by whitespace.
|
||||
fn next_token(&mut self) -> (Token, bool) {
|
||||
let mut preceded_by_whitespace = false;
|
||||
|
||||
let mut swallow_next_invalid = 0;
|
||||
// Skip trivial (whitespace & comments) tokens
|
||||
loop {
|
||||
let token = self.cursor.advance_token();
|
||||
@ -232,19 +232,34 @@ impl<'a> StringReader<'a> {
|
||||
rustc_lexer::TokenKind::Percent => token::BinOp(token::Percent),
|
||||
|
||||
rustc_lexer::TokenKind::Unknown | rustc_lexer::TokenKind::InvalidIdent => {
|
||||
let c = self.str_from(start).chars().next().unwrap();
|
||||
// Don't emit diagnostics for sequences of the same invalid token
|
||||
if swallow_next_invalid > 0 {
|
||||
swallow_next_invalid -= 1;
|
||||
continue;
|
||||
}
|
||||
let mut it = self.str_from_to_end(start).chars();
|
||||
let c = it.next().unwrap();
|
||||
let repeats = it.take_while(|c1| *c1 == c).count();
|
||||
let mut err =
|
||||
self.struct_err_span_char(start, self.pos, "unknown start of token", c);
|
||||
self.struct_err_span_char(start, self.pos + Pos::from_usize(repeats * c.len_utf8()), "unknown start of token", c);
|
||||
// FIXME: the lexer could be used to turn the ASCII version of unicode
|
||||
// homoglyphs, instead of keeping a table in `check_for_substitution`into the
|
||||
// token. Ideally, this should be inside `rustc_lexer`. However, we should
|
||||
// first remove compound tokens like `<<` from `rustc_lexer`, and then add
|
||||
// fancier error recovery to it, as there will be less overall work to do this
|
||||
// way.
|
||||
let token = unicode_chars::check_for_substitution(self, start, c, &mut err);
|
||||
let token = unicode_chars::check_for_substitution(self, start, c, &mut err, repeats+1);
|
||||
if c == '\x00' {
|
||||
err.help("source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used");
|
||||
}
|
||||
if repeats > 0 {
|
||||
if repeats == 1 {
|
||||
err.note(format!("character appears once more"));
|
||||
} else {
|
||||
err.note(format!("character appears {repeats} more times"));
|
||||
}
|
||||
swallow_next_invalid = repeats;
|
||||
}
|
||||
err.emit();
|
||||
if let Some(token) = token {
|
||||
token
|
||||
@ -486,6 +501,11 @@ impl<'a> StringReader<'a> {
|
||||
&self.src[self.src_index(start)..self.src_index(end)]
|
||||
}
|
||||
|
||||
/// Slice of the source text spanning from `start` until the end
|
||||
fn str_from_to_end(&self, start: BytePos) -> &str {
|
||||
&self.src[self.src_index(start)..]
|
||||
}
|
||||
|
||||
fn report_raw_str_error(&self, start: BytePos, prefix_len: u32) -> ! {
|
||||
match rustc_lexer::validate_raw_str(self.str_from(start), prefix_len) {
|
||||
Err(RawStrError::InvalidStarter { bad_char }) => {
|
||||
|
@ -337,10 +337,11 @@ pub(super) fn check_for_substitution<'a>(
|
||||
pos: BytePos,
|
||||
ch: char,
|
||||
err: &mut Diagnostic,
|
||||
count: usize,
|
||||
) -> Option<token::TokenKind> {
|
||||
let &(_u_char, u_name, ascii_char) = UNICODE_ARRAY.iter().find(|&&(c, _, _)| c == ch)?;
|
||||
|
||||
let span = Span::with_root_ctxt(pos, pos + Pos::from_usize(ch.len_utf8()));
|
||||
let span = Span::with_root_ctxt(pos, pos + Pos::from_usize(ch.len_utf8() * count));
|
||||
|
||||
let Some((_ascii_char, ascii_name, token)) = ASCII_ARRAY.iter().find(|&&(c, _, _)| c == ascii_char) else {
|
||||
let msg = format!("substitution character not found for '{}'", ch);
|
||||
@ -369,7 +370,12 @@ pub(super) fn check_for_substitution<'a>(
|
||||
"Unicode character '{}' ({}) looks like '{}' ({}), but it is not",
|
||||
ch, u_name, ascii_char, ascii_name
|
||||
);
|
||||
err.span_suggestion(span, &msg, ascii_char, Applicability::MaybeIncorrect);
|
||||
err.span_suggestion(
|
||||
span,
|
||||
&msg,
|
||||
ascii_char.to_string().repeat(count),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
token.clone()
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ macro_rules! maybe_whole_expr {
|
||||
pub(super) enum LhsExpr {
|
||||
NotYetParsed,
|
||||
AttributesParsed(AttrWrapper),
|
||||
AlreadyParsed(P<Expr>, bool), // (expr, starts_statement)
|
||||
AlreadyParsed { expr: P<Expr>, starts_statement: bool },
|
||||
}
|
||||
|
||||
impl From<Option<AttrWrapper>> for LhsExpr {
|
||||
@ -97,11 +97,11 @@ impl From<Option<AttrWrapper>> for LhsExpr {
|
||||
}
|
||||
|
||||
impl From<P<Expr>> for LhsExpr {
|
||||
/// Converts the `expr: P<Expr>` into `LhsExpr::AlreadyParsed(expr)`.
|
||||
/// Converts the `expr: P<Expr>` into `LhsExpr::AlreadyParsed { expr, starts_statement: false }`.
|
||||
///
|
||||
/// This conversion does not allocate.
|
||||
fn from(expr: P<Expr>) -> Self {
|
||||
LhsExpr::AlreadyParsed(expr, false)
|
||||
LhsExpr::AlreadyParsed { expr, starts_statement: false }
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,7 +174,7 @@ impl<'a> Parser<'a> {
|
||||
lhs: LhsExpr,
|
||||
) -> PResult<'a, P<Expr>> {
|
||||
let mut starts_stmt = false;
|
||||
let mut lhs = if let LhsExpr::AlreadyParsed(expr, starts_statement) = lhs {
|
||||
let mut lhs = if let LhsExpr::AlreadyParsed { expr, starts_statement } = lhs {
|
||||
starts_stmt = starts_statement;
|
||||
expr
|
||||
} else {
|
||||
@ -562,17 +562,23 @@ impl<'a> Parser<'a> {
|
||||
|
||||
// Note: when adding new unary operators, don't forget to adjust TokenKind::can_begin_expr()
|
||||
match this.token.uninterpolate().kind {
|
||||
token::Not => make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Not)), // `!expr`
|
||||
token::Tilde => make_it!(this, attrs, |this, _| this.recover_tilde_expr(lo)), // `~expr`
|
||||
// `!expr`
|
||||
token::Not => make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Not)),
|
||||
// `~expr`
|
||||
token::Tilde => make_it!(this, attrs, |this, _| this.recover_tilde_expr(lo)),
|
||||
// `-expr`
|
||||
token::BinOp(token::Minus) => {
|
||||
make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Neg))
|
||||
} // `-expr`
|
||||
}
|
||||
// `*expr`
|
||||
token::BinOp(token::Star) => {
|
||||
make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Deref))
|
||||
} // `*expr`
|
||||
}
|
||||
// `&expr` and `&&expr`
|
||||
token::BinOp(token::And) | token::AndAnd => {
|
||||
make_it!(this, attrs, |this, _| this.parse_borrow_expr(lo))
|
||||
}
|
||||
// `+lit`
|
||||
token::BinOp(token::Plus) if this.look_ahead(1, |tok| tok.is_numeric_lit()) => {
|
||||
let mut err =
|
||||
LeadingPlusNotSupported { span: lo, remove_plus: None, add_parentheses: None };
|
||||
@ -587,7 +593,7 @@ impl<'a> Parser<'a> {
|
||||
|
||||
this.bump();
|
||||
this.parse_prefix_expr(None)
|
||||
} // `+expr`
|
||||
}
|
||||
// Recover from `++x`:
|
||||
token::BinOp(token::Plus)
|
||||
if this.look_ahead(1, |t| *t == token::BinOp(token::Plus)) =>
|
||||
@ -624,7 +630,7 @@ impl<'a> Parser<'a> {
|
||||
Ok((span, self.mk_unary(op, expr)))
|
||||
}
|
||||
|
||||
// Recover on `!` suggesting for bitwise negation instead.
|
||||
/// Recover on `~expr` in favor of `!expr`.
|
||||
fn recover_tilde_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
|
||||
self.sess.emit_err(TildeAsUnaryOperator(lo));
|
||||
|
||||
@ -651,7 +657,6 @@ impl<'a> Parser<'a> {
|
||||
|
||||
/// Recover on `not expr` in favor of `!expr`.
|
||||
fn recover_not_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
|
||||
// Emit the error...
|
||||
let negated_token = self.look_ahead(1, |t| t.clone());
|
||||
|
||||
let sub_diag = if negated_token.is_numeric_lit() {
|
||||
@ -672,7 +677,6 @@ impl<'a> Parser<'a> {
|
||||
),
|
||||
});
|
||||
|
||||
// ...and recover!
|
||||
self.parse_unary_expr(lo, UnOp::Not)
|
||||
}
|
||||
|
||||
@ -1593,7 +1597,7 @@ impl<'a> Parser<'a> {
|
||||
vis.0
|
||||
};
|
||||
|
||||
// Suggestion involves adding a (as of time of writing this, unstable) labeled block.
|
||||
// Suggestion involves adding a labeled block.
|
||||
//
|
||||
// If there are no breaks that may use this label, suggest removing the label and
|
||||
// recover to the unmodified expression.
|
||||
|
@ -164,7 +164,10 @@ impl<'a> Parser<'a> {
|
||||
// Perform this outside of the `collect_tokens_trailing_token` closure,
|
||||
// since our outer attributes do not apply to this part of the expression
|
||||
let expr = self.with_res(Restrictions::STMT_EXPR, |this| {
|
||||
this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr, true))
|
||||
this.parse_assoc_expr_with(
|
||||
0,
|
||||
LhsExpr::AlreadyParsed { expr, starts_statement: true },
|
||||
)
|
||||
})?;
|
||||
Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Expr(expr)))
|
||||
} else {
|
||||
@ -198,7 +201,10 @@ impl<'a> Parser<'a> {
|
||||
let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac));
|
||||
let e = self.maybe_recover_from_bad_qpath(e)?;
|
||||
let e = self.parse_dot_or_call_expr_with(e, lo, attrs)?;
|
||||
let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e, false))?;
|
||||
let e = self.parse_assoc_expr_with(
|
||||
0,
|
||||
LhsExpr::AlreadyParsed { expr: e, starts_statement: false },
|
||||
)?;
|
||||
StmtKind::Expr(e)
|
||||
};
|
||||
Ok(self.mk_stmt(lo.to(hi), kind))
|
||||
|
@ -374,6 +374,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
fn report_fulfillment_errors(
|
||||
&self,
|
||||
@ -852,6 +853,29 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
let mut suggested =
|
||||
self.suggest_dereferences(&obligation, &mut err, trait_predicate);
|
||||
suggested |= self.suggest_fn_call(&obligation, &mut err, trait_predicate);
|
||||
let impl_candidates = self.find_similar_impl_candidates(trait_predicate);
|
||||
suggested = if let &[cand] = &impl_candidates[..] {
|
||||
let cand = cand.trait_ref;
|
||||
if let (ty::FnPtr(_), ty::FnDef(..)) =
|
||||
(cand.self_ty().kind(), trait_ref.self_ty().skip_binder().kind())
|
||||
{
|
||||
err.span_suggestion(
|
||||
span.shrink_to_hi(),
|
||||
format!(
|
||||
"the trait `{}` is implemented for fn pointer `{}`, try casting using `as`",
|
||||
cand.print_only_trait_path(),
|
||||
cand.self_ty(),
|
||||
),
|
||||
format!(" as {}", cand.self_ty()),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
} || suggested;
|
||||
suggested |=
|
||||
self.suggest_remove_reference(&obligation, &mut err, trait_predicate);
|
||||
suggested |= self.suggest_semicolon_removal(
|
||||
@ -1968,27 +1992,25 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
candidates.sort();
|
||||
candidates.dedup();
|
||||
let len = candidates.len();
|
||||
if candidates.len() == 0 {
|
||||
if candidates.is_empty() {
|
||||
return false;
|
||||
}
|
||||
if candidates.len() == 1 {
|
||||
let ty_desc = match candidates[0].self_ty().kind() {
|
||||
ty::FnPtr(_) => Some("fn pointer"),
|
||||
_ => None,
|
||||
};
|
||||
let the_desc = match ty_desc {
|
||||
Some(desc) => format!(" implemented for {} `", desc),
|
||||
None => " implemented for `".to_string(),
|
||||
};
|
||||
if let &[cand] = &candidates[..] {
|
||||
let (desc, mention_castable) =
|
||||
match (cand.self_ty().kind(), trait_ref.self_ty().skip_binder().kind()) {
|
||||
(ty::FnPtr(_), ty::FnDef(..)) => {
|
||||
(" implemented for fn pointer `", ", cast using `as`")
|
||||
}
|
||||
(ty::FnPtr(_), _) => (" implemented for fn pointer `", ""),
|
||||
_ => (" implemented for `", ""),
|
||||
};
|
||||
err.highlighted_help(vec![
|
||||
(
|
||||
format!("the trait `{}` ", candidates[0].print_only_trait_path()),
|
||||
Style::NoStyle,
|
||||
),
|
||||
(format!("the trait `{}` ", cand.print_only_trait_path()), Style::NoStyle),
|
||||
("is".to_string(), Style::Highlight),
|
||||
(the_desc, Style::NoStyle),
|
||||
(candidates[0].self_ty().to_string(), Style::Highlight),
|
||||
(desc.to_string(), Style::NoStyle),
|
||||
(cand.self_ty().to_string(), Style::Highlight),
|
||||
("`".to_string(), Style::NoStyle),
|
||||
(mention_castable.to_string(), Style::NoStyle),
|
||||
]);
|
||||
return true;
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ bin="$PWD/clang+llvm-15.0.6-x86_64-linux-gnu-ubuntu-18.04/bin"
|
||||
git clone https://github.com/WebAssembly/wasi-libc
|
||||
|
||||
cd wasi-libc
|
||||
git reset --hard 8b7148f69ae241a2749b3defe4606da8143b72e0
|
||||
git reset --hard 4362b1885fd369e042a7c0ecd8df3b6cd47fb4e8
|
||||
make -j$(nproc) \
|
||||
CC="$bin/clang" \
|
||||
NM="$bin/llvm-nm" \
|
||||
|
@ -6,6 +6,7 @@ autobins = false
|
||||
|
||||
[dependencies]
|
||||
cargo_metadata = "0.14"
|
||||
cargo-platform = "0.1.2"
|
||||
regex = "1"
|
||||
miropt-test-tools = { path = "../miropt-test-tools" }
|
||||
lazy_static = "1"
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! Checks the licenses of third-party dependencies.
|
||||
|
||||
use cargo_metadata::{Metadata, Package, PackageId, Resolve};
|
||||
use std::collections::{BTreeSet, HashSet};
|
||||
use cargo_metadata::{DepKindInfo, Metadata, Package, PackageId};
|
||||
use std::collections::HashSet;
|
||||
use std::path::Path;
|
||||
|
||||
/// These are licenses that are allowed for all crates, including the runtime,
|
||||
@ -98,14 +98,12 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
|
||||
"autocfg",
|
||||
"bitflags",
|
||||
"block-buffer",
|
||||
"bumpalo", // Included in Cargo's dep graph but only activated on wasm32-*-unknown.
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"chalk-derive",
|
||||
"chalk-engine",
|
||||
"chalk-ir",
|
||||
"chalk-solve",
|
||||
"chrono",
|
||||
"convert_case", // dependency of derive_more
|
||||
"compiler_builtins",
|
||||
"cpufeatures",
|
||||
@ -124,11 +122,9 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
|
||||
"dlmalloc",
|
||||
"either",
|
||||
"ena",
|
||||
"env_logger",
|
||||
"expect-test",
|
||||
"fallible-iterator", // dependency of `thorin`
|
||||
"fastrand",
|
||||
"filetime",
|
||||
"fixedbitset",
|
||||
"flate2",
|
||||
"fluent-bundle",
|
||||
@ -142,13 +138,11 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
|
||||
"gsgdt",
|
||||
"hashbrown",
|
||||
"hermit-abi",
|
||||
"humantime",
|
||||
"icu_list",
|
||||
"icu_locid",
|
||||
"icu_provider",
|
||||
"icu_provider_adapters",
|
||||
"icu_provider_macros",
|
||||
"if_chain",
|
||||
"indexmap",
|
||||
"instant",
|
||||
"intl-memoizer",
|
||||
@ -156,7 +150,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
|
||||
"itertools",
|
||||
"itoa",
|
||||
"jobserver",
|
||||
"js-sys", // Included in Cargo's dep graph but only activated on wasm32-*-unknown.
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"libloading",
|
||||
@ -171,8 +164,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
|
||||
"memmap2",
|
||||
"memoffset",
|
||||
"miniz_oxide",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"num_cpus",
|
||||
"object",
|
||||
"odht",
|
||||
@ -190,7 +181,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
|
||||
"proc-macro2",
|
||||
"psm",
|
||||
"punycode",
|
||||
"quick-error",
|
||||
"quote",
|
||||
"rand",
|
||||
"rand_chacha",
|
||||
@ -235,7 +225,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
|
||||
"thiserror-impl",
|
||||
"thorin-dwp",
|
||||
"thread_local",
|
||||
"time",
|
||||
"tinystr",
|
||||
"tinyvec",
|
||||
"tinyvec_macros",
|
||||
@ -268,13 +257,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
|
||||
"valuable",
|
||||
"version_check",
|
||||
"wasi",
|
||||
// vvv Included in Cargo's dep graph but only activated on wasm32-*-unknown.
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-macro",
|
||||
"wasm-bindgen-macro-support",
|
||||
"wasm-bindgen-shared",
|
||||
// ^^^ Included in Cargo's dep graph but only activated on wasm32-*-unknown.
|
||||
"winapi",
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-util",
|
||||
@ -485,75 +467,57 @@ fn check_permitted_dependencies(
|
||||
restricted_dependency_crates: &[&'static str],
|
||||
bad: &mut bool,
|
||||
) {
|
||||
let mut deps = HashSet::new();
|
||||
for to_check in restricted_dependency_crates {
|
||||
let to_check = pkg_from_name(metadata, to_check);
|
||||
use cargo_platform::Cfg;
|
||||
use std::str::FromStr;
|
||||
// We don't expect the compiler to ever run on wasm32, so strip
|
||||
// out those dependencies to avoid polluting the permitted list.
|
||||
deps_of_filtered(metadata, &to_check.id, &mut deps, &|dep_kinds| {
|
||||
dep_kinds.iter().any(|dep_kind| {
|
||||
dep_kind
|
||||
.target
|
||||
.as_ref()
|
||||
.map(|target| {
|
||||
!target.matches(
|
||||
"wasm32-unknown-unknown",
|
||||
&[
|
||||
Cfg::from_str("target_arch=\"wasm32\"").unwrap(),
|
||||
Cfg::from_str("target_os=\"unknown\"").unwrap(),
|
||||
],
|
||||
)
|
||||
})
|
||||
.unwrap_or(true)
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// Check that the PERMITTED_DEPENDENCIES does not have unused entries.
|
||||
for name in permitted_dependencies {
|
||||
if !metadata.packages.iter().any(|p| p.name == *name) {
|
||||
for permitted in permitted_dependencies {
|
||||
if !deps.iter().any(|dep_id| &pkg_from_id(metadata, dep_id).name == permitted) {
|
||||
tidy_error!(
|
||||
bad,
|
||||
"could not find allowed package `{}`\n\
|
||||
"could not find allowed package `{permitted}`\n\
|
||||
Remove from PERMITTED_DEPENDENCIES list if it is no longer used.",
|
||||
name
|
||||
);
|
||||
}
|
||||
}
|
||||
// Get the list in a convenient form.
|
||||
|
||||
// Get in a convenient form.
|
||||
let permitted_dependencies: HashSet<_> = permitted_dependencies.iter().cloned().collect();
|
||||
|
||||
// Check dependencies.
|
||||
let mut visited = BTreeSet::new();
|
||||
let mut unapproved = BTreeSet::new();
|
||||
for &krate in restricted_dependency_crates.iter() {
|
||||
let pkg = pkg_from_name(metadata, krate);
|
||||
let mut bad =
|
||||
check_crate_dependencies(&permitted_dependencies, metadata, &mut visited, pkg);
|
||||
unapproved.append(&mut bad);
|
||||
}
|
||||
|
||||
if !unapproved.is_empty() {
|
||||
tidy_error!(bad, "Dependencies for {} not explicitly permitted:", descr);
|
||||
for dep in unapproved {
|
||||
println!("* {dep}");
|
||||
for dep in deps {
|
||||
let dep = pkg_from_id(metadata, dep);
|
||||
// If this path is in-tree, we don't require it to be explicitly permitted.
|
||||
if dep.source.is_some() {
|
||||
if !permitted_dependencies.contains(dep.name.as_str()) {
|
||||
tidy_error!(bad, "Dependency for {descr} not explicitly permitted: {}", dep.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks the dependencies of the given crate from the given cargo metadata to see if they are on
|
||||
/// the list of permitted dependencies. Returns a list of disallowed dependencies.
|
||||
fn check_crate_dependencies<'a>(
|
||||
permitted_dependencies: &'a HashSet<&'static str>,
|
||||
metadata: &'a Metadata,
|
||||
visited: &mut BTreeSet<&'a PackageId>,
|
||||
krate: &'a Package,
|
||||
) -> BTreeSet<&'a PackageId> {
|
||||
// This will contain bad deps.
|
||||
let mut unapproved = BTreeSet::new();
|
||||
|
||||
// Check if we have already visited this crate.
|
||||
if visited.contains(&krate.id) {
|
||||
return unapproved;
|
||||
}
|
||||
|
||||
visited.insert(&krate.id);
|
||||
|
||||
// If this path is in-tree, we don't require it to be explicitly permitted.
|
||||
if krate.source.is_some() {
|
||||
// If this dependency is not on `PERMITTED_DEPENDENCIES`, add to bad set.
|
||||
if !permitted_dependencies.contains(krate.name.as_str()) {
|
||||
unapproved.insert(&krate.id);
|
||||
}
|
||||
}
|
||||
|
||||
// Do a DFS in the crate graph.
|
||||
let to_check = deps_of(metadata, &krate.id);
|
||||
|
||||
for dep in to_check {
|
||||
let mut bad = check_crate_dependencies(permitted_dependencies, metadata, visited, dep);
|
||||
unapproved.append(&mut bad);
|
||||
}
|
||||
|
||||
unapproved
|
||||
}
|
||||
|
||||
/// Prevents multiple versions of some expensive crates.
|
||||
fn check_crate_duplicate(
|
||||
metadata: &Metadata,
|
||||
@ -588,24 +552,6 @@ fn check_crate_duplicate(
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a list of dependencies for the given package.
|
||||
fn deps_of<'a>(metadata: &'a Metadata, pkg_id: &'a PackageId) -> Vec<&'a Package> {
|
||||
let resolve = metadata.resolve.as_ref().unwrap();
|
||||
let node = resolve
|
||||
.nodes
|
||||
.iter()
|
||||
.find(|n| &n.id == pkg_id)
|
||||
.unwrap_or_else(|| panic!("could not find `{pkg_id}` in resolve"));
|
||||
node.deps
|
||||
.iter()
|
||||
.map(|dep| {
|
||||
metadata.packages.iter().find(|pkg| pkg.id == dep.pkg).unwrap_or_else(|| {
|
||||
panic!("could not find dep `{}` for pkg `{}` in resolve", dep.pkg, pkg_id)
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Finds a package with the given name.
|
||||
fn pkg_from_name<'a>(metadata: &'a Metadata, name: &'static str) -> &'a Package {
|
||||
let mut i = metadata.packages.iter().filter(|p| p.name == name);
|
||||
@ -615,41 +561,57 @@ fn pkg_from_name<'a>(metadata: &'a Metadata, name: &'static str) -> &'a Package
|
||||
result
|
||||
}
|
||||
|
||||
fn pkg_from_id<'a>(metadata: &'a Metadata, id: &PackageId) -> &'a Package {
|
||||
metadata.packages.iter().find(|p| &p.id == id).unwrap()
|
||||
}
|
||||
|
||||
/// Finds all the packages that are in the rust runtime.
|
||||
fn compute_runtime_crates<'a>(metadata: &'a Metadata) -> HashSet<&'a PackageId> {
|
||||
let resolve = metadata.resolve.as_ref().unwrap();
|
||||
let mut result = HashSet::new();
|
||||
for name in RUNTIME_CRATES {
|
||||
let id = &pkg_from_name(metadata, name).id;
|
||||
normal_deps_of_r(resolve, id, &mut result);
|
||||
deps_of_filtered(metadata, id, &mut result, &|_| true);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
/// Recursively find all normal dependencies.
|
||||
fn normal_deps_of_r<'a>(
|
||||
resolve: &'a Resolve,
|
||||
/// Recursively find all dependencies.
|
||||
fn deps_of_filtered<'a>(
|
||||
metadata: &'a Metadata,
|
||||
pkg_id: &'a PackageId,
|
||||
result: &mut HashSet<&'a PackageId>,
|
||||
filter: &dyn Fn(&[DepKindInfo]) -> bool,
|
||||
) {
|
||||
if !result.insert(pkg_id) {
|
||||
return;
|
||||
}
|
||||
let node = resolve
|
||||
let node = metadata
|
||||
.resolve
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.nodes
|
||||
.iter()
|
||||
.find(|n| &n.id == pkg_id)
|
||||
.unwrap_or_else(|| panic!("could not find `{pkg_id}` in resolve"));
|
||||
for dep in &node.deps {
|
||||
normal_deps_of_r(resolve, &dep.pkg, result);
|
||||
if !filter(&dep.dep_kinds) {
|
||||
continue;
|
||||
}
|
||||
deps_of_filtered(metadata, &dep.pkg, result, filter);
|
||||
}
|
||||
}
|
||||
|
||||
fn direct_deps_of<'a>(metadata: &'a Metadata, pkg_id: &'a PackageId) -> Vec<&'a Package> {
|
||||
let resolve = metadata.resolve.as_ref().unwrap();
|
||||
let node = resolve.nodes.iter().find(|n| &n.id == pkg_id).unwrap();
|
||||
node.deps.iter().map(|dep| pkg_from_id(metadata, &dep.pkg)).collect()
|
||||
}
|
||||
|
||||
fn check_rustfix(metadata: &Metadata, bad: &mut bool) {
|
||||
let cargo = pkg_from_name(metadata, "cargo");
|
||||
let compiletest = pkg_from_name(metadata, "compiletest");
|
||||
let cargo_deps = deps_of(metadata, &cargo.id);
|
||||
let compiletest_deps = deps_of(metadata, &compiletest.id);
|
||||
let cargo_deps = direct_deps_of(metadata, &cargo.id);
|
||||
let compiletest_deps = direct_deps_of(metadata, &compiletest.id);
|
||||
let cargo_rustfix = cargo_deps.iter().find(|p| p.name == "rustfix").unwrap();
|
||||
let compiletest_rustfix = compiletest_deps.iter().find(|p| p.name == "rustfix").unwrap();
|
||||
if cargo_rustfix.version != compiletest_rustfix.version {
|
||||
|
@ -18,8 +18,8 @@ fn consts<const C: u32>() {
|
||||
})
|
||||
}
|
||||
|
||||
static S: i32 = 5;
|
||||
static mut T: i32 = 10;
|
||||
static S: i32 = 0x05050505;
|
||||
static mut T: i32 = 0x0a0a0a0a;
|
||||
// EMIT_MIR consts.statics.built.after.mir
|
||||
#[custom_mir(dialect = "built")]
|
||||
fn statics() {
|
||||
|
@ -19,9 +19,9 @@ fn statics() -> () {
|
||||
}
|
||||
|
||||
alloc2 (static: T, size: 4, align: 4) {
|
||||
0a 00 00 00 │ ....
|
||||
0a 0a 0a 0a │ ....
|
||||
}
|
||||
|
||||
alloc1 (static: S, size: 4, align: 4) {
|
||||
05 00 00 00 │ ....
|
||||
05 05 05 05 │ ....
|
||||
}
|
||||
|
@ -38,6 +38,6 @@
|
||||
}
|
||||
|
||||
alloc1 (static: STATIC, size: 4, align: 4) {
|
||||
2a 00 00 00 │ *...
|
||||
42 42 42 42 │ BBBB
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
// unit-test
|
||||
// compile-flags: -O
|
||||
|
||||
static mut STATIC: u32 = 42;
|
||||
static mut STATIC: u32 = 0x42424242;
|
||||
|
||||
// EMIT_MIR mutable_variable_no_prop.main.ConstProp.diff
|
||||
fn main() {
|
||||
|
@ -26,7 +26,7 @@
|
||||
_3 = _1; // scope 2 at $DIR/issue_75439.rs:+2:47: +2:52
|
||||
_2 = transmute::<[u8; 16], [u32; 4]>(move _3) -> bb1; // scope 2 at $DIR/issue_75439.rs:+2:37: +2:53
|
||||
// mir::Constant
|
||||
// + span: $DIR/issue_75439.rs:7:37: 7:46
|
||||
// + span: $DIR/issue_75439.rs:8:37: 8:46
|
||||
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn([u8; 16]) -> [u32; 4] {transmute::<[u8; 16], [u32; 4]>}, val: Value(<ZST>) }
|
||||
}
|
||||
|
||||
@ -49,7 +49,7 @@
|
||||
_6 = _4; // scope 4 at $DIR/issue_75439.rs:+5:33: +5:35
|
||||
_5 = transmute::<u32, [u8; 4]>(move _6) -> bb7; // scope 4 at $DIR/issue_75439.rs:+5:23: +5:36
|
||||
// mir::Constant
|
||||
// + span: $DIR/issue_75439.rs:10:23: 10:32
|
||||
// + span: $DIR/issue_75439.rs:11:23: 11:32
|
||||
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32) -> [u8; 4] {transmute::<u32, [u8; 4]>}, val: Value(<ZST>) }
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
// EMIT_MIR issue_75439.foo.MatchBranchSimplification.diff
|
||||
// ignore-endian-big
|
||||
|
||||
use std::mem::transmute;
|
||||
|
||||
|
@ -77,8 +77,6 @@ LL | /// ```
|
||||
| ^^^
|
||||
|
|
||||
= note: error from rustc: unknown start of token: `
|
||||
= note: error from rustc: unknown start of token: `
|
||||
= note: error from rustc: unknown start of token: `
|
||||
|
||||
warning: could not parse code block as Rust code
|
||||
--> $DIR/invalid-syntax.rs:64:5
|
||||
|
@ -4,6 +4,11 @@ error[E0277]: the trait bound `T: Copy` is not satisfied
|
||||
LL | type Assoc = T;
|
||||
| ^ the trait `Copy` is not implemented for `T`
|
||||
|
|
||||
note: required for `<T as Complete>::Assoc` to implement `Partial<T>`
|
||||
--> $DIR/issue-43784-associated-type.rs:1:11
|
||||
|
|
||||
LL | pub trait Partial<X: ?Sized>: Copy {
|
||||
| ^^^^^^^
|
||||
note: required by a bound in `Complete::Assoc`
|
||||
--> $DIR/issue-43784-associated-type.rs:5:17
|
||||
|
|
||||
|
@ -6,6 +6,13 @@ LL | Foo(())
|
||||
| |
|
||||
| arguments to this struct are incorrect
|
||||
|
|
||||
help: the type constructed contains `()` due to the type of the argument passed
|
||||
--> $DIR/issue-84128.rs:13:9
|
||||
|
|
||||
LL | Foo(())
|
||||
| ^^^^--^
|
||||
| |
|
||||
| this argument influences the type of `Foo`
|
||||
note: tuple struct defined here
|
||||
--> $DIR/issue-84128.rs:5:8
|
||||
|
|
||||
|
@ -6,6 +6,13 @@ LL | Ok(())
|
||||
| |
|
||||
| arguments to this enum variant are incorrect
|
||||
|
|
||||
help: the type constructed contains `()` due to the type of the argument passed
|
||||
--> $DIR/issue-87461.rs:10:5
|
||||
|
|
||||
LL | Ok(())
|
||||
| ^^^--^
|
||||
| |
|
||||
| this argument influences the type of `Ok`
|
||||
note: tuple variant defined here
|
||||
--> $SRC_DIR/core/src/result.rs:LL:COL
|
||||
|
||||
@ -17,6 +24,13 @@ LL | Ok(())
|
||||
| |
|
||||
| arguments to this enum variant are incorrect
|
||||
|
|
||||
help: the type constructed contains `()` due to the type of the argument passed
|
||||
--> $DIR/issue-87461.rs:17:5
|
||||
|
|
||||
LL | Ok(())
|
||||
| ^^^--^
|
||||
| |
|
||||
| this argument influences the type of `Ok`
|
||||
note: tuple variant defined here
|
||||
--> $SRC_DIR/core/src/result.rs:LL:COL
|
||||
|
||||
@ -28,6 +42,13 @@ LL | Ok(())
|
||||
| |
|
||||
| arguments to this enum variant are incorrect
|
||||
|
|
||||
help: the type constructed contains `()` due to the type of the argument passed
|
||||
--> $DIR/issue-87461.rs:26:9
|
||||
|
|
||||
LL | Ok(())
|
||||
| ^^^--^
|
||||
| |
|
||||
| this argument influences the type of `Ok`
|
||||
note: tuple variant defined here
|
||||
--> $SRC_DIR/core/src/result.rs:LL:COL
|
||||
|
||||
|
@ -6,12 +6,15 @@ LL | struct Value(u32);
|
||||
| |
|
||||
| doesn't satisfy `Value: Eq`
|
||||
| doesn't satisfy `Value: Hash`
|
||||
| doesn't satisfy `Value: PartialEq`
|
||||
...
|
||||
LL | hs.insert(Value(0));
|
||||
| ^^^^^^
|
||||
|
|
||||
= note: the following trait bounds were not satisfied:
|
||||
`Value: Eq`
|
||||
`Value: PartialEq`
|
||||
which is required by `Value: Eq`
|
||||
`Value: Hash`
|
||||
help: consider annotating `Value` with `#[derive(Eq, Hash, PartialEq)]`
|
||||
|
|
||||
@ -22,7 +25,10 @@ error[E0599]: the method `use_eq` exists for struct `Object<NoDerives>`, but its
|
||||
--> $DIR/issue-91550.rs:26:9
|
||||
|
|
||||
LL | pub struct NoDerives;
|
||||
| -------------------- doesn't satisfy `NoDerives: Eq`
|
||||
| --------------------
|
||||
| |
|
||||
| doesn't satisfy `NoDerives: Eq`
|
||||
| doesn't satisfy `NoDerives: PartialEq`
|
||||
LL |
|
||||
LL | struct Object<T>(T);
|
||||
| ---------------- method `use_eq` not found for this struct
|
||||
@ -37,6 +43,9 @@ LL | impl<T: Eq> Object<T> {
|
||||
| ^^ ---------
|
||||
| |
|
||||
| unsatisfied trait bound introduced here
|
||||
= note: the following trait bounds were not satisfied:
|
||||
`NoDerives: PartialEq`
|
||||
which is required by `NoDerives: Eq`
|
||||
help: consider annotating `NoDerives` with `#[derive(Eq, PartialEq)]`
|
||||
|
|
||||
LL | #[derive(Eq, PartialEq)]
|
||||
@ -46,7 +55,12 @@ error[E0599]: the method `use_ord` exists for struct `Object<NoDerives>`, but it
|
||||
--> $DIR/issue-91550.rs:27:9
|
||||
|
|
||||
LL | pub struct NoDerives;
|
||||
| -------------------- doesn't satisfy `NoDerives: Ord`
|
||||
| --------------------
|
||||
| |
|
||||
| doesn't satisfy `NoDerives: Eq`
|
||||
| doesn't satisfy `NoDerives: Ord`
|
||||
| doesn't satisfy `NoDerives: PartialEq`
|
||||
| doesn't satisfy `NoDerives: PartialOrd`
|
||||
LL |
|
||||
LL | struct Object<T>(T);
|
||||
| ---------------- method `use_ord` not found for this struct
|
||||
@ -61,6 +75,13 @@ LL | impl<T: Ord> Object<T> {
|
||||
| ^^^ ---------
|
||||
| |
|
||||
| unsatisfied trait bound introduced here
|
||||
= note: the following trait bounds were not satisfied:
|
||||
`NoDerives: PartialOrd`
|
||||
which is required by `NoDerives: Ord`
|
||||
`NoDerives: PartialEq`
|
||||
which is required by `NoDerives: Ord`
|
||||
`NoDerives: Eq`
|
||||
which is required by `NoDerives: Ord`
|
||||
help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]`
|
||||
|
|
||||
LL | #[derive(Eq, Ord, PartialEq, PartialOrd)]
|
||||
@ -72,7 +93,9 @@ error[E0599]: the method `use_ord_and_partial_ord` exists for struct `Object<NoD
|
||||
LL | pub struct NoDerives;
|
||||
| --------------------
|
||||
| |
|
||||
| doesn't satisfy `NoDerives: Eq`
|
||||
| doesn't satisfy `NoDerives: Ord`
|
||||
| doesn't satisfy `NoDerives: PartialEq`
|
||||
| doesn't satisfy `NoDerives: PartialOrd`
|
||||
LL |
|
||||
LL | struct Object<T>(T);
|
||||
@ -91,6 +114,13 @@ LL | impl<T: Ord + PartialOrd> Object<T> {
|
||||
| | |
|
||||
| | unsatisfied trait bound introduced here
|
||||
| unsatisfied trait bound introduced here
|
||||
= note: the following trait bounds were not satisfied:
|
||||
`NoDerives: PartialEq`
|
||||
which is required by `NoDerives: Ord`
|
||||
`NoDerives: Eq`
|
||||
which is required by `NoDerives: Ord`
|
||||
`NoDerives: PartialEq`
|
||||
which is required by `NoDerives: PartialOrd`
|
||||
help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]`
|
||||
|
|
||||
LL | #[derive(Eq, Ord, PartialEq, PartialOrd)]
|
||||
|
@ -17,6 +17,7 @@ LL | type Copy<T>: Copy = Box<T>;
|
||||
| ^^^^^^ the trait `Clone` is not implemented for `T`
|
||||
|
|
||||
= note: required for `Box<T>` to implement `Clone`
|
||||
= note: required for `<Self as UnsafeCopy>::Copy<T>` to implement `Copy`
|
||||
note: required by a bound in `UnsafeCopy::Copy`
|
||||
--> $DIR/issue-74824.rs:6:19
|
||||
|
|
||||
|
@ -23,6 +23,13 @@ LL | A(self.0 + rhs.0)
|
||||
|
|
||||
= note: expected type parameter `B`
|
||||
found associated type `<B as Add>::Output`
|
||||
help: the type constructed contains `<B as Add>::Output` due to the type of the argument passed
|
||||
--> $DIR/missing-bounds.rs:11:9
|
||||
|
|
||||
LL | A(self.0 + rhs.0)
|
||||
| ^^--------------^
|
||||
| |
|
||||
| this argument influences the type of `A`
|
||||
note: tuple struct defined here
|
||||
--> $DIR/missing-bounds.rs:5:8
|
||||
|
|
||||
|
@ -11,6 +11,13 @@ LL | Some(true)
|
||||
|
|
||||
= note: expected type parameter `bool` (type parameter `bool`)
|
||||
found type `bool` (`bool`)
|
||||
help: the type constructed contains `bool` due to the type of the argument passed
|
||||
--> $DIR/issue-35030.rs:9:9
|
||||
|
|
||||
LL | Some(true)
|
||||
| ^^^^^----^
|
||||
| |
|
||||
| this argument influences the type of `Some`
|
||||
note: tuple variant defined here
|
||||
--> $SRC_DIR/core/src/option.rs:LL:COL
|
||||
|
||||
|
@ -6,6 +6,8 @@ LL | this.is_subset(other)
|
||||
|
|
||||
= note: the following trait bounds were not satisfied:
|
||||
`T: Eq`
|
||||
`T: PartialEq`
|
||||
which is required by `T: Eq`
|
||||
`T: Hash`
|
||||
help: consider restricting the type parameters to satisfy the trait bounds
|
||||
|
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -2,4 +2,8 @@ fn main() {
|
||||
let y = 0;
|
||||
//~^ ERROR unknown start of token: \u{37e}
|
||||
//~^^ HELP Unicode character ';' (Greek Question Mark) looks like ';' (Semicolon), but it is not
|
||||
let x = 0;
|
||||
//~^ ERROR unknown start of token: \u{a0}
|
||||
//~^^ NOTE character appears 3 more times
|
||||
//~^^^ HELP Unicode character ' ' (No-Break Space) looks like ' ' (Space), but it is not
|
||||
}
|
||||
|
@ -9,5 +9,17 @@ help: Unicode character ';' (Greek Question Mark) looks like ';' (Semicolon), b
|
||||
LL | let y = 0;
|
||||
| ~
|
||||
|
||||
error: aborting due to previous error
|
||||
error: unknown start of token: \u{a0}
|
||||
--> $DIR/unicode-chars.rs:5:5
|
||||
|
|
||||
LL | let x = 0;
|
||||
| ^^^^
|
||||
|
|
||||
= note: character appears 3 more times
|
||||
help: Unicode character ' ' (No-Break Space) looks like ' ' (Space), but it is not
|
||||
|
|
||||
LL | let x = 0;
|
||||
| ++++
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -11,6 +11,13 @@ LL | let _: Option<(i32, bool)> = Some(1, 2);
|
||||
| ^
|
||||
= note: expected tuple `(i32, bool)`
|
||||
found type `{integer}`
|
||||
help: the type constructed contains `{integer}` due to the type of the argument passed
|
||||
--> $DIR/args-instead-of-tuple-errors.rs:6:34
|
||||
|
|
||||
LL | let _: Option<(i32, bool)> = Some(1, 2);
|
||||
| ^^^^^-^^^^
|
||||
| |
|
||||
| this argument influences the type of `Some`
|
||||
note: tuple variant defined here
|
||||
--> $SRC_DIR/core/src/option.rs:LL:COL
|
||||
help: remove the extra argument
|
||||
@ -64,6 +71,13 @@ LL | let _: Option<(i32,)> = Some(5_usize);
|
||||
|
|
||||
= note: expected tuple `(i32,)`
|
||||
found type `usize`
|
||||
help: the type constructed contains `usize` due to the type of the argument passed
|
||||
--> $DIR/args-instead-of-tuple-errors.rs:14:29
|
||||
|
|
||||
LL | let _: Option<(i32,)> = Some(5_usize);
|
||||
| ^^^^^-------^
|
||||
| |
|
||||
| this argument influences the type of `Some`
|
||||
note: tuple variant defined here
|
||||
--> $SRC_DIR/core/src/option.rs:LL:COL
|
||||
|
||||
@ -77,6 +91,13 @@ LL | let _: Option<(i32,)> = Some((5_usize));
|
||||
|
|
||||
= note: expected tuple `(i32,)`
|
||||
found type `usize`
|
||||
help: the type constructed contains `usize` due to the type of the argument passed
|
||||
--> $DIR/args-instead-of-tuple-errors.rs:17:29
|
||||
|
|
||||
LL | let _: Option<(i32,)> = Some((5_usize));
|
||||
| ^^^^^---------^
|
||||
| |
|
||||
| this argument influences the type of `Some`
|
||||
note: tuple variant defined here
|
||||
--> $SRC_DIR/core/src/option.rs:LL:COL
|
||||
|
||||
|
@ -8,6 +8,13 @@ LL | let _s = y.unwrap_or(|| x.split('.').nth(1).unwrap());
|
||||
|
|
||||
= note: expected reference `&str`
|
||||
found closure `[closure@$DIR/sugg-else-for-closure.rs:6:26: 6:28]`
|
||||
help: the return type of this call is `[closure@$DIR/sugg-else-for-closure.rs:6:26: 6:28]` due to the type of the argument passed
|
||||
--> $DIR/sugg-else-for-closure.rs:6:14
|
||||
|
|
||||
LL | let _s = y.unwrap_or(|| x.split('.').nth(1).unwrap());
|
||||
| ^^^^^^^^^^^^-------------------------------^
|
||||
| |
|
||||
| this argument influences the return type of `unwrap_or`
|
||||
note: associated function defined here
|
||||
--> $SRC_DIR/core/src/option.rs:LL:COL
|
||||
help: try calling `unwrap_or_else` instead
|
||||
|
26
tests/ui/traits/fn-trait-cast-diagnostic.rs
Normal file
26
tests/ui/traits/fn-trait-cast-diagnostic.rs
Normal file
@ -0,0 +1,26 @@
|
||||
// There are two different instances to check that even if
|
||||
// the trait is implemented for the output of a function,
|
||||
// it will still be displayed if the function itself implements a trait.
|
||||
trait Foo {}
|
||||
|
||||
impl Foo for fn() -> bool {}
|
||||
impl Foo for bool {}
|
||||
|
||||
fn example() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
trait NoOtherFoo {}
|
||||
|
||||
impl NoOtherFoo for fn() -> bool {}
|
||||
|
||||
fn do_on_foo(v: impl Foo) {}
|
||||
fn do_on_single_foo(v: impl NoOtherFoo) {}
|
||||
|
||||
fn main() {
|
||||
do_on_foo(example);
|
||||
//~^ ERROR the trait bound
|
||||
|
||||
do_on_single_foo(example);
|
||||
//~^ ERROR the trait bound
|
||||
}
|
43
tests/ui/traits/fn-trait-cast-diagnostic.stderr
Normal file
43
tests/ui/traits/fn-trait-cast-diagnostic.stderr
Normal file
@ -0,0 +1,43 @@
|
||||
error[E0277]: the trait bound `fn() -> bool {example}: Foo` is not satisfied
|
||||
--> $DIR/fn-trait-cast-diagnostic.rs:21:15
|
||||
|
|
||||
LL | do_on_foo(example);
|
||||
| --------- ^^^^^^^ the trait `Foo` is not implemented for fn item `fn() -> bool {example}`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
note: required by a bound in `do_on_foo`
|
||||
--> $DIR/fn-trait-cast-diagnostic.rs:17:22
|
||||
|
|
||||
LL | fn do_on_foo(v: impl Foo) {}
|
||||
| ^^^ required by this bound in `do_on_foo`
|
||||
help: use parentheses to call this function
|
||||
|
|
||||
LL | do_on_foo(example());
|
||||
| ++
|
||||
help: the trait `Foo` is implemented for fn pointer `fn() -> bool`, try casting using `as`
|
||||
|
|
||||
LL | do_on_foo(example as fn() -> bool);
|
||||
| +++++++++++++++
|
||||
|
||||
error[E0277]: the trait bound `fn() -> bool {example}: NoOtherFoo` is not satisfied
|
||||
--> $DIR/fn-trait-cast-diagnostic.rs:24:22
|
||||
|
|
||||
LL | do_on_single_foo(example);
|
||||
| ---------------- ^^^^^^^ the trait `NoOtherFoo` is not implemented for fn item `fn() -> bool {example}`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
note: required by a bound in `do_on_single_foo`
|
||||
--> $DIR/fn-trait-cast-diagnostic.rs:18:29
|
||||
|
|
||||
LL | fn do_on_single_foo(v: impl NoOtherFoo) {}
|
||||
| ^^^^^^^^^^ required by this bound in `do_on_single_foo`
|
||||
help: the trait `NoOtherFoo` is implemented for fn pointer `fn() -> bool`, try casting using `as`
|
||||
|
|
||||
LL | do_on_single_foo(example as fn() -> bool);
|
||||
| +++++++++++++++
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
@ -4,6 +4,11 @@ error[E0277]: the trait bound `T: Copy` is not satisfied
|
||||
LL | impl<T> Complete for T {}
|
||||
| ^ the trait `Copy` is not implemented for `T`
|
||||
|
|
||||
note: required for `T` to implement `Partial`
|
||||
--> $DIR/issue-43784-supertrait.rs:1:11
|
||||
|
|
||||
LL | pub trait Partial: Copy {
|
||||
| ^^^^^^^
|
||||
note: required by a bound in `Complete`
|
||||
--> $DIR/issue-43784-supertrait.rs:4:21
|
||||
|
|
||||
|
@ -11,6 +11,13 @@ LL | builder.push(output);
|
||||
|
|
||||
= note: expected type parameter `F`
|
||||
found struct `Class<P>`
|
||||
help: the return type of this call is `Class<P>` due to the type of the argument passed
|
||||
--> $DIR/issue-52893.rs:53:9
|
||||
|
|
||||
LL | builder.push(output);
|
||||
| ^^^^^^^^^^^^^------^
|
||||
| |
|
||||
| this argument influences the return type of `push`
|
||||
note: associated function defined here
|
||||
--> $DIR/issue-52893.rs:11:8
|
||||
|
|
||||
|
@ -6,12 +6,15 @@ LL | takes(function);
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: the trait `Trait` is implemented for fn pointer `fn(Argument) -> Return`
|
||||
note: required by a bound in `takes`
|
||||
--> $DIR/issue-99875.rs:9:18
|
||||
|
|
||||
LL | fn takes(_: impl Trait) {}
|
||||
| ^^^^^ required by this bound in `takes`
|
||||
help: the trait `Trait` is implemented for fn pointer `fn(Argument) -> Return`, try casting using `as`
|
||||
|
|
||||
LL | takes(function as fn(Argument) -> Return);
|
||||
| +++++++++++++++++++++++++
|
||||
|
||||
error[E0277]: the trait bound `[closure@$DIR/issue-99875.rs:14:11: 14:34]: Trait` is not satisfied
|
||||
--> $DIR/issue-99875.rs:14:11
|
||||
|
88
tests/ui/traits/track-obligations.rs
Normal file
88
tests/ui/traits/track-obligations.rs
Normal file
@ -0,0 +1,88 @@
|
||||
// These are simplifications of the tower traits by the same name:
|
||||
|
||||
pub trait Service<Request> {
|
||||
type Response;
|
||||
}
|
||||
|
||||
pub trait Layer<C> {
|
||||
type Service;
|
||||
}
|
||||
|
||||
// Any type will do here:
|
||||
|
||||
pub struct Req;
|
||||
pub struct Res;
|
||||
|
||||
// This is encoding a trait alias.
|
||||
|
||||
pub trait ParticularService:
|
||||
Service<Req, Response = Res> {
|
||||
}
|
||||
|
||||
impl<T> ParticularService for T
|
||||
where
|
||||
T: Service<Req, Response = Res>,
|
||||
{
|
||||
}
|
||||
|
||||
// This is also a trait alias.
|
||||
// The weird = <Self as ...> bound is there so that users of the trait do not
|
||||
// need to repeat the bounds. See https://github.com/rust-lang/rust/issues/20671
|
||||
// for context, and in particular the workaround in:
|
||||
// https://github.com/rust-lang/rust/issues/20671#issuecomment-529752828
|
||||
|
||||
pub trait ParticularServiceLayer<C>:
|
||||
Layer<C, Service = <Self as ParticularServiceLayer<C>>::Service>
|
||||
{
|
||||
type Service: ParticularService;
|
||||
}
|
||||
|
||||
impl<T, C> ParticularServiceLayer<C> for T
|
||||
where
|
||||
T: Layer<C>,
|
||||
T::Service: ParticularService,
|
||||
{
|
||||
type Service = T::Service;
|
||||
}
|
||||
|
||||
// These are types that implement the traits that the trait aliases refer to.
|
||||
// They should also implement the alias traits due to the blanket impls.
|
||||
|
||||
struct ALayer<C>(C);
|
||||
impl<C> Layer<C> for ALayer<C> {
|
||||
type Service = AService;
|
||||
}
|
||||
|
||||
struct AService;
|
||||
impl Service<Req> for AService {
|
||||
// However, AService does _not_ meet the blanket implementation,
|
||||
// since its Response type is bool, not Res as it should be.
|
||||
type Response = bool;
|
||||
}
|
||||
|
||||
// This is a wrapper type around ALayer that uses the trait alias
|
||||
// as a way to communicate the requirements of the provided types.
|
||||
struct Client<C>(C);
|
||||
|
||||
// The method and the free-standing function below both have the same bounds.
|
||||
|
||||
impl<C> Client<C>
|
||||
where
|
||||
ALayer<C>: ParticularServiceLayer<C>,
|
||||
{
|
||||
fn check(&self) {}
|
||||
}
|
||||
|
||||
fn check<C>(_: C) where ALayer<C>: ParticularServiceLayer<C> {}
|
||||
|
||||
// But, they give very different error messages.
|
||||
|
||||
fn main() {
|
||||
// This gives a very poor error message that does nothing to point the user
|
||||
// at the underlying cause of why the types involved do not meet the bounds.
|
||||
Client(()).check(); //~ ERROR E0599
|
||||
|
||||
// This gives a good(ish) error message that points the user at _why_ the
|
||||
// bound isn't met, and thus how they might fix it.
|
||||
check(()); //~ ERROR E0271
|
||||
}
|
76
tests/ui/traits/track-obligations.stderr
Normal file
76
tests/ui/traits/track-obligations.stderr
Normal file
@ -0,0 +1,76 @@
|
||||
error[E0599]: the method `check` exists for struct `Client<()>`, but its trait bounds were not satisfied
|
||||
--> $DIR/track-obligations.rs:83:16
|
||||
|
|
||||
LL | struct ALayer<C>(C);
|
||||
| ----------------
|
||||
| |
|
||||
| doesn't satisfy `<_ as Layer<()>>::Service = <ALayer<()> as ParticularServiceLayer<()>>::Service`
|
||||
| doesn't satisfy `ALayer<()>: ParticularServiceLayer<()>`
|
||||
...
|
||||
LL | struct Client<C>(C);
|
||||
| ---------------- method `check` not found for this struct
|
||||
...
|
||||
LL | Client(()).check();
|
||||
| ^^^^^ method cannot be called on `Client<()>` due to unsatisfied trait bounds
|
||||
|
|
||||
note: trait bound `<ALayer<()> as Layer<()>>::Service = <ALayer<()> as ParticularServiceLayer<()>>::Service` was not satisfied
|
||||
--> $DIR/track-obligations.rs:35:14
|
||||
|
|
||||
LL | pub trait ParticularServiceLayer<C>:
|
||||
| ----------------------
|
||||
LL | Layer<C, Service = <Self as ParticularServiceLayer<C>>::Service>
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound introduced here
|
||||
note: trait bound `ALayer<()>: ParticularServiceLayer<()>` was not satisfied
|
||||
--> $DIR/track-obligations.rs:71:16
|
||||
|
|
||||
LL | impl<C> Client<C>
|
||||
| ---------
|
||||
LL | where
|
||||
LL | ALayer<C>: ParticularServiceLayer<C>,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound introduced here
|
||||
note: the trait `ParticularServiceLayer` must be implemented
|
||||
--> $DIR/track-obligations.rs:34:1
|
||||
|
|
||||
LL | / pub trait ParticularServiceLayer<C>:
|
||||
LL | | Layer<C, Service = <Self as ParticularServiceLayer<C>>::Service>
|
||||
| |____________________________________________________________________^
|
||||
|
||||
error[E0271]: type mismatch resolving `<AService as Service<Req>>::Response == Res`
|
||||
--> $DIR/track-obligations.rs:87:11
|
||||
|
|
||||
LL | check(());
|
||||
| ----- ^^ type mismatch resolving `<AService as Service<Req>>::Response == Res`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
note: expected this to be `Res`
|
||||
--> $DIR/track-obligations.rs:60:21
|
||||
|
|
||||
LL | type Response = bool;
|
||||
| ^^^^
|
||||
note: required for `AService` to implement `ParticularService`
|
||||
--> $DIR/track-obligations.rs:22:9
|
||||
|
|
||||
LL | impl<T> ParticularService for T
|
||||
| ^^^^^^^^^^^^^^^^^ ^
|
||||
LL | where
|
||||
LL | T: Service<Req, Response = Res>,
|
||||
| -------------- unsatisfied trait bound introduced here
|
||||
note: required for `ALayer<_>` to implement `ParticularServiceLayer<_>`
|
||||
--> $DIR/track-obligations.rs:40:12
|
||||
|
|
||||
LL | impl<T, C> ParticularServiceLayer<C> for T
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ ^
|
||||
...
|
||||
LL | T::Service: ParticularService,
|
||||
| ----------------- unsatisfied trait bound introduced here
|
||||
note: required by a bound in `check`
|
||||
--> $DIR/track-obligations.rs:76:36
|
||||
|
|
||||
LL | fn check<C>(_: C) where ALayer<C>: ParticularServiceLayer<C> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0271, E0599.
|
||||
For more information about an error, try `rustc --explain E0271`.
|
28
tests/ui/type/wrong-call-return-type-due-to-generic-arg.rs
Normal file
28
tests/ui/type/wrong-call-return-type-due-to-generic-arg.rs
Normal file
@ -0,0 +1,28 @@
|
||||
fn function<T>(x: T, y: bool) -> T {
|
||||
x
|
||||
}
|
||||
|
||||
struct S {}
|
||||
impl S {
|
||||
fn method<T>(&self, x: T) -> T {
|
||||
x
|
||||
}
|
||||
}
|
||||
|
||||
fn wrong_arg_type(x: u32) -> u32 {
|
||||
x
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Should not trigger.
|
||||
let x = wrong_arg_type(0u16); //~ ERROR mismatched types
|
||||
let x: u16 = function(0, 0u8); //~ ERROR mismatched types
|
||||
|
||||
// Should trigger exactly once for the first argument.
|
||||
let x: u16 = function(0u32, 0u8); //~ ERROR arguments to this function are incorrect
|
||||
|
||||
// Should trigger.
|
||||
let x: u16 = function(0u32, true); //~ ERROR mismatched types
|
||||
let x: u16 = (S {}).method(0u32); //~ ERROR mismatched types
|
||||
function(0u32, 8u8) //~ ERROR arguments to this function are incorrect
|
||||
}
|
131
tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr
Normal file
131
tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr
Normal file
@ -0,0 +1,131 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/wrong-call-return-type-due-to-generic-arg.rs:18:28
|
||||
|
|
||||
LL | let x = wrong_arg_type(0u16);
|
||||
| -------------- ^^^^ expected `u32`, found `u16`
|
||||
| |
|
||||
| arguments to this function are incorrect
|
||||
|
|
||||
note: function defined here
|
||||
--> $DIR/wrong-call-return-type-due-to-generic-arg.rs:12:4
|
||||
|
|
||||
LL | fn wrong_arg_type(x: u32) -> u32 {
|
||||
| ^^^^^^^^^^^^^^ ------
|
||||
help: change the type of the numeric literal from `u16` to `u32`
|
||||
|
|
||||
LL | let x = wrong_arg_type(0u32);
|
||||
| ~~~
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/wrong-call-return-type-due-to-generic-arg.rs:19:30
|
||||
|
|
||||
LL | let x: u16 = function(0, 0u8);
|
||||
| -------- ^^^ expected `bool`, found `u8`
|
||||
| |
|
||||
| arguments to this function are incorrect
|
||||
|
|
||||
note: function defined here
|
||||
--> $DIR/wrong-call-return-type-due-to-generic-arg.rs:1:4
|
||||
|
|
||||
LL | fn function<T>(x: T, y: bool) -> T {
|
||||
| ^^^^^^^^ -------
|
||||
|
||||
error[E0308]: arguments to this function are incorrect
|
||||
--> $DIR/wrong-call-return-type-due-to-generic-arg.rs:22:18
|
||||
|
|
||||
LL | let x: u16 = function(0u32, 0u8);
|
||||
| ^^^^^^^^ ---- --- expected `bool`, found `u8`
|
||||
| |
|
||||
| expected `u16`, found `u32`
|
||||
|
|
||||
help: the return type of this call is `u32` due to the type of the argument passed
|
||||
--> $DIR/wrong-call-return-type-due-to-generic-arg.rs:22:18
|
||||
|
|
||||
LL | let x: u16 = function(0u32, 0u8);
|
||||
| ^^^^^^^^^----^^^^^^
|
||||
| |
|
||||
| this argument influences the return type of `function`
|
||||
note: function defined here
|
||||
--> $DIR/wrong-call-return-type-due-to-generic-arg.rs:1:4
|
||||
|
|
||||
LL | fn function<T>(x: T, y: bool) -> T {
|
||||
| ^^^^^^^^ ---- -------
|
||||
help: change the type of the numeric literal from `u32` to `u16`
|
||||
|
|
||||
LL | let x: u16 = function(0u16, 0u8);
|
||||
| ~~~
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/wrong-call-return-type-due-to-generic-arg.rs:25:27
|
||||
|
|
||||
LL | let x: u16 = function(0u32, true);
|
||||
| -------- ^^^^ expected `u16`, found `u32`
|
||||
| |
|
||||
| arguments to this function are incorrect
|
||||
|
|
||||
help: the return type of this call is `u32` due to the type of the argument passed
|
||||
--> $DIR/wrong-call-return-type-due-to-generic-arg.rs:25:18
|
||||
|
|
||||
LL | let x: u16 = function(0u32, true);
|
||||
| ^^^^^^^^^----^^^^^^^
|
||||
| |
|
||||
| this argument influences the return type of `function`
|
||||
note: function defined here
|
||||
--> $DIR/wrong-call-return-type-due-to-generic-arg.rs:1:4
|
||||
|
|
||||
LL | fn function<T>(x: T, y: bool) -> T {
|
||||
| ^^^^^^^^ ----
|
||||
help: change the type of the numeric literal from `u32` to `u16`
|
||||
|
|
||||
LL | let x: u16 = function(0u16, true);
|
||||
| ~~~
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/wrong-call-return-type-due-to-generic-arg.rs:26:32
|
||||
|
|
||||
LL | let x: u16 = (S {}).method(0u32);
|
||||
| ------ ^^^^ expected `u16`, found `u32`
|
||||
| |
|
||||
| arguments to this method are incorrect
|
||||
|
|
||||
help: the return type of this call is `u32` due to the type of the argument passed
|
||||
--> $DIR/wrong-call-return-type-due-to-generic-arg.rs:26:18
|
||||
|
|
||||
LL | let x: u16 = (S {}).method(0u32);
|
||||
| ^^^^^^^^^^^^^^----^
|
||||
| |
|
||||
| this argument influences the return type of `method`
|
||||
note: associated function defined here
|
||||
--> $DIR/wrong-call-return-type-due-to-generic-arg.rs:7:8
|
||||
|
|
||||
LL | fn method<T>(&self, x: T) -> T {
|
||||
| ^^^^^^ ----
|
||||
help: change the type of the numeric literal from `u32` to `u16`
|
||||
|
|
||||
LL | let x: u16 = (S {}).method(0u16);
|
||||
| ~~~
|
||||
|
||||
error[E0308]: arguments to this function are incorrect
|
||||
--> $DIR/wrong-call-return-type-due-to-generic-arg.rs:27:5
|
||||
|
|
||||
LL | function(0u32, 8u8)
|
||||
| ^^^^^^^^ ---- --- expected `bool`, found `u8`
|
||||
| |
|
||||
| expected `()`, found `u32`
|
||||
|
|
||||
help: the return type of this call is `u32` due to the type of the argument passed
|
||||
--> $DIR/wrong-call-return-type-due-to-generic-arg.rs:27:5
|
||||
|
|
||||
LL | function(0u32, 8u8)
|
||||
| ^^^^^^^^^----^^^^^^
|
||||
| |
|
||||
| this argument influences the return type of `function`
|
||||
note: function defined here
|
||||
--> $DIR/wrong-call-return-type-due-to-generic-arg.rs:1:4
|
||||
|
|
||||
LL | fn function<T>(x: T, y: bool) -> T {
|
||||
| ^^^^^^^^ ---- -------
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
@ -8,6 +8,13 @@ LL | fn main() { test(Ok(())); }
|
||||
|
|
||||
= note: expected enum `Option<()>`
|
||||
found unit type `()`
|
||||
help: the type constructed contains `()` due to the type of the argument passed
|
||||
--> $DIR/issue-46112.rs:9:18
|
||||
|
|
||||
LL | fn main() { test(Ok(())); }
|
||||
| ^^^--^
|
||||
| |
|
||||
| this argument influences the type of `Ok`
|
||||
note: tuple variant defined here
|
||||
--> $SRC_DIR/core/src/result.rs:LL:COL
|
||||
help: try wrapping the expression in `Some`
|
||||
|
@ -14,6 +14,13 @@ LL | <F as FnOnce(&mut u8)>::call_once(f, 1)
|
||||
|
|
||||
= note: expected tuple `(&mut u8,)`
|
||||
found type `{integer}`
|
||||
help: the return type of this call is `{integer}` due to the type of the argument passed
|
||||
--> $DIR/issue-84768.rs:7:5
|
||||
|
|
||||
LL | <F as FnOnce(&mut u8)>::call_once(f, 1)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^
|
||||
| |
|
||||
| this argument influences the return type of `FnOnce`
|
||||
note: associated function defined here
|
||||
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
|
||||
|
||||
|
@ -21,6 +21,13 @@ LL | <i32 as Add<i32>>::add(1u32, 2);
|
||||
| |
|
||||
| arguments to this function are incorrect
|
||||
|
|
||||
help: the return type of this call is `u32` due to the type of the argument passed
|
||||
--> $DIR/ufcs-qpath-self-mismatch.rs:7:5
|
||||
|
|
||||
LL | <i32 as Add<i32>>::add(1u32, 2);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^----^^^^
|
||||
| |
|
||||
| this argument influences the return type of `Add`
|
||||
note: associated function defined here
|
||||
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
|
||||
help: change the type of the numeric literal from `u32` to `i32`
|
||||
@ -36,6 +43,13 @@ LL | <i32 as Add<i32>>::add(1, 2u32);
|
||||
| |
|
||||
| arguments to this function are incorrect
|
||||
|
|
||||
help: the return type of this call is `u32` due to the type of the argument passed
|
||||
--> $DIR/ufcs-qpath-self-mismatch.rs:9:5
|
||||
|
|
||||
LL | <i32 as Add<i32>>::add(1, 2u32);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^----^
|
||||
| |
|
||||
| this argument influences the return type of `Add`
|
||||
note: associated function defined here
|
||||
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
|
||||
help: change the type of the numeric literal from `u32` to `i32`
|
||||
|
@ -251,7 +251,7 @@ new_pr = true
|
||||
|
||||
[autolabel."WG-trait-system-refactor"]
|
||||
trigger_files = [
|
||||
"compiler/rustc_trait_selection/solve"
|
||||
"compiler/rustc_trait_selection/src/solve"
|
||||
]
|
||||
|
||||
[notify-zulip."I-prioritize"]
|
||||
|
Loading…
Reference in New Issue
Block a user