From 5454bca1b4b14706529e496ae6df8069682d24ae Mon Sep 17 00:00:00 2001
From: David Carlier <devnexen@gmail.com>
Date: Fri, 10 Jun 2022 19:54:53 +0100
Subject: [PATCH 01/19] net listen backlog set to negative on Linux.
it will be 4076 (from 5.4) or 128.
---
library/std/src/os/unix/net/listener.rs | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs
index 8e11d32f13071..3b31c000f252a 100644
--- a/library/std/src/os/unix/net/listener.rs
+++ b/library/std/src/os/unix/net/listener.rs
@@ -73,9 +73,13 @@ impl UnixListener {
unsafe {
let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
let (addr, len) = sockaddr_un(path.as_ref())?;
+ #[cfg(target_os = "linux")]
+ const backlog: libc::c_int = -1;
+ #[cfg(not(target_os = "linux"))]
+ const backlog: libc::c_int = 128;
cvt(libc::bind(inner.as_inner().as_raw_fd(), &addr as *const _ as *const _, len as _))?;
- cvt(libc::listen(inner.as_inner().as_raw_fd(), 128))?;
+ cvt(libc::listen(inner.as_inner().as_raw_fd(), backlog))?;
Ok(UnixListener(inner))
}
@@ -109,12 +113,16 @@ impl UnixListener {
pub fn bind_addr(socket_addr: &SocketAddr) -> io::Result<UnixListener> {
unsafe {
let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
+ #[cfg(target_os = "linux")]
+ const backlog: libc::c_int = -1;
+ #[cfg(not(target_os = "linux"))]
+ const backlog: libc::c_int = 128;
cvt(libc::bind(
inner.as_raw_fd(),
&socket_addr.addr as *const _ as *const _,
socket_addr.len as _,
))?;
- cvt(libc::listen(inner.as_raw_fd(), 128))?;
+ cvt(libc::listen(inner.as_raw_fd(), backlog))?;
Ok(UnixListener(inner))
}
}
From 4b162141631e900f760752eacdd6d5e510ac4e42 Mon Sep 17 00:00:00 2001
From: Camille GILLOT <gillot.camille@gmail.com>
Date: Sat, 13 Aug 2022 18:39:30 +0200
Subject: [PATCH 02/19] Ban references to `Self` in trait object substs for
projection predicates too.
---
compiler/rustc_typeck/src/astconv/mod.rs | 46 +++++++++++++------
src/test/ui/traits/alias/self-in-generics.rs | 7 +++
.../ui/traits/alias/self-in-generics.stderr | 2 +-
3 files changed, 41 insertions(+), 14 deletions(-)
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 1e6cb53f3eeae..ff81747cafe6f 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -35,7 +35,7 @@ use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECT
use rustc_span::edition::Edition;
use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::symbol::{kw, Ident, Symbol};
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::Span;
use rustc_target::spec::abi;
use rustc_trait_selection::traits;
use rustc_trait_selection::traits::astconv_object_safety_violations;
@@ -1458,16 +1458,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
if ty == dummy_self {
let param = &generics.params[index];
missing_type_params.push(param.name);
- tcx.ty_error().into()
+ return tcx.ty_error().into();
} else if ty.walk().any(|arg| arg == dummy_self.into()) {
references_self = true;
- tcx.ty_error().into()
- } else {
- arg
+ return tcx.ty_error().into();
}
- } else {
- arg
}
+ arg
})
.collect();
let substs = tcx.intern_substs(&substs[..]);
@@ -1506,13 +1503,36 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
});
let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| {
- bound.map_bound(|b| {
- if b.projection_ty.self_ty() != dummy_self {
- tcx.sess.delay_span_bug(
- DUMMY_SP,
- &format!("trait_ref_to_existential called on {:?} with non-dummy Self", b),
- );
+ bound.map_bound(|mut b| {
+ assert_eq!(b.projection_ty.self_ty(), dummy_self);
+
+ // Like for trait refs, verify that `dummy_self` did not leak inside default type
+ // parameters.
+ let references_self = b.projection_ty.substs.iter().skip(1).any(|arg| {
+ if let ty::GenericArgKind::Type(ty) = arg.unpack() {
+ if ty == dummy_self || ty.walk().any(|arg| arg == dummy_self.into()) {
+ return true;
+ }
+ }
+ false
+ });
+ if references_self {
+ tcx.sess
+ .delay_span_bug(span, "trait object projection bounds reference `Self`");
+ let substs: Vec<_> = b
+ .projection_ty
+ .substs
+ .iter()
+ .map(|arg| {
+ if let ty::GenericArgKind::Type(_) = arg.unpack() {
+ return tcx.ty_error().into();
+ }
+ arg
+ })
+ .collect();
+ b.projection_ty.substs = tcx.intern_substs(&substs[..]);
}
+
ty::ExistentialProjection::erase_self_ty(tcx, b)
})
});
diff --git a/src/test/ui/traits/alias/self-in-generics.rs b/src/test/ui/traits/alias/self-in-generics.rs
index 6b99431f5bbcf..0bb6335f91e4b 100644
--- a/src/test/ui/traits/alias/self-in-generics.rs
+++ b/src/test/ui/traits/alias/self-in-generics.rs
@@ -1,3 +1,10 @@
+// astconv uses `FreshTy(0)` as a dummy `Self` type when instanciating trait objects.
+// This `FreshTy(0)` can leak into substs, causing ICEs in several places.
+// Using `save-analysis` triggers type-checking `f` that would be normally skipped
+// as `type_of` emitted an error.
+//
+// compile-flags: -Zsave-analysis
+
#![feature(trait_alias)]
pub trait SelfInput = Fn(&mut Self);
diff --git a/src/test/ui/traits/alias/self-in-generics.stderr b/src/test/ui/traits/alias/self-in-generics.stderr
index a1056872ea641..110d60e6e9116 100644
--- a/src/test/ui/traits/alias/self-in-generics.stderr
+++ b/src/test/ui/traits/alias/self-in-generics.stderr
@@ -1,5 +1,5 @@
error[E0038]: the trait alias `SelfInput` cannot be made into an object
- --> $DIR/self-in-generics.rs:5:19
+ --> $DIR/self-in-generics.rs:12:19
|
LL | pub fn f(_f: &dyn SelfInput) {}
| ^^^^^^^^^
From 9233298e71f08404838a1051a5b211255de4b79d Mon Sep 17 00:00:00 2001
From: Tim van Elsloo <tim@glacyr.com>
Date: Tue, 16 Aug 2022 17:36:25 +0200
Subject: [PATCH 03/19] Revert "Revert "Allow dynamic linking for iOS/tvOS
targets.""
This reverts commit 16e10bf81ee73f61cf813acef3d5dbbce4f66da2.
# Conflicts:
# compiler/rustc_target/src/spec/apple_sdk_base.rs
---
compiler/rustc_target/src/spec/apple_sdk_base.rs | 1 -
1 file changed, 1 deletion(-)
diff --git a/compiler/rustc_target/src/spec/apple_sdk_base.rs b/compiler/rustc_target/src/spec/apple_sdk_base.rs
index bf3ebaa2840f6..49e302676a7b1 100644
--- a/compiler/rustc_target/src/spec/apple_sdk_base.rs
+++ b/compiler/rustc_target/src/spec/apple_sdk_base.rs
@@ -65,7 +65,6 @@ pub fn opts(os: &'static str, arch: Arch) -> TargetOptions {
TargetOptions {
abi: target_abi(arch).into(),
cpu: target_cpu(arch).into(),
- dynamic_linking: false,
link_env_remove: link_env_remove(arch),
has_thread_local: false,
..super::apple_base::opts(os, target_arch_name(arch), target_abi(arch))
From e9e46c95ce60469f596b8188c439dc278dff6bc4 Mon Sep 17 00:00:00 2001
From: Christopher Durham <cad97@cad97.com>
Date: Wed, 17 Aug 2022 06:07:33 -0500
Subject: [PATCH 04/19] Don't treat stashed warnings as errors
---
compiler/rustc_errors/src/lib.rs | 74 ++++++++++++++++++++++++++------
1 file changed, 62 insertions(+), 12 deletions(-)
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 395bf5aad01b6..fe2afdf5a20b8 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -625,19 +625,13 @@ impl Handler {
/// Stash a given diagnostic with the given `Span` and `StashKey` as the key for later stealing.
pub fn stash_diagnostic(&self, span: Span, key: StashKey, diag: Diagnostic) {
let mut inner = self.inner.borrow_mut();
- // FIXME(Centril, #69537): Consider reintroducing panic on overwriting a stashed diagnostic
- // if/when we have a more robust macro-friendly replacement for `(span, key)` as a key.
- // See the PR for a discussion.
- inner.stashed_diagnostics.insert((span, key), diag);
+ inner.stash((span, key), diag);
}
/// Steal a previously stashed diagnostic with the given `Span` and `StashKey` as the key.
pub fn steal_diagnostic(&self, span: Span, key: StashKey) -> Option<DiagnosticBuilder<'_, ()>> {
- self.inner
- .borrow_mut()
- .stashed_diagnostics
- .remove(&(span, key))
- .map(|diag| DiagnosticBuilder::new_diagnostic(self, diag))
+ let mut inner = self.inner.borrow_mut();
+ inner.steal((span, key)).map(|diag| DiagnosticBuilder::new_diagnostic(self, diag))
}
/// Emit all stashed diagnostics.
@@ -1105,13 +1099,31 @@ impl HandlerInner {
/// Emit all stashed diagnostics.
fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> {
+ let has_errors = self.has_errors();
let diags = self.stashed_diagnostics.drain(..).map(|x| x.1).collect::<Vec<_>>();
let mut reported = None;
for mut diag in diags {
+ // Decrement the count tracking the stash; emitting will increment it.
if diag.is_error() {
- reported = Some(ErrorGuaranteed(()));
+ if matches!(diag.level, Level::Error { lint: true }) {
+ self.lint_err_count -= 1;
+ } else {
+ self.err_count -= 1;
+ }
+ } else {
+ if diag.is_force_warn() {
+ self.warn_count -= 1;
+ } else {
+ // Unless they're forced, don't flush stashed warnings when
+ // there are errors, to avoid causing warning overload. The
+ // stash would've been stolen already if it were important.
+ if has_errors {
+ continue;
+ }
+ }
}
- self.emit_diagnostic(&mut diag);
+ let reported_this = self.emit_diagnostic(&mut diag);
+ reported = reported.or(reported_this);
}
reported
}
@@ -1301,9 +1313,47 @@ impl HandlerInner {
}
}
+ fn stash(&mut self, key: (Span, StashKey), diagnostic: Diagnostic) {
+ // Track the diagnostic for counts, but don't panic-if-treat-err-as-bug
+ // yet; that happens when we actually emit the diagnostic.
+ if diagnostic.is_error() {
+ if matches!(diagnostic.level, Level::Error { lint: true }) {
+ self.lint_err_count += 1;
+ } else {
+ self.err_count += 1;
+ }
+ } else {
+ // Warnings are only automatically flushed if they're forced.
+ if diagnostic.is_force_warn() {
+ self.warn_count += 1;
+ }
+ }
+
+ // FIXME(Centril, #69537): Consider reintroducing panic on overwriting a stashed diagnostic
+ // if/when we have a more robust macro-friendly replacement for `(span, key)` as a key.
+ // See the PR for a discussion.
+ self.stashed_diagnostics.insert(key, diagnostic);
+ }
+
+ fn steal(&mut self, key: (Span, StashKey)) -> Option<Diagnostic> {
+ let diagnostic = self.stashed_diagnostics.remove(&key)?;
+ if diagnostic.is_error() {
+ if matches!(diagnostic.level, Level::Error { lint: true }) {
+ self.lint_err_count -= 1;
+ } else {
+ self.err_count -= 1;
+ }
+ } else {
+ if diagnostic.is_force_warn() {
+ self.warn_count -= 1;
+ }
+ }
+ Some(diagnostic)
+ }
+
#[inline]
fn err_count(&self) -> usize {
- self.err_count + self.stashed_diagnostics.len()
+ self.err_count
}
fn has_errors(&self) -> bool {
From 767239f7403a3808e534da02ca388632eac2bc18 Mon Sep 17 00:00:00 2001
From: Christopher Durham <cad97@cad97.com>
Date: Wed, 17 Aug 2022 06:52:47 -0500
Subject: [PATCH 05/19] Reenable early feature-gates as future-compat warnings
---
compiler/rustc_ast_passes/src/feature_gate.rs | 58 +++++++++++--------
compiler/rustc_errors/src/lib.rs | 1 +
compiler/rustc_lint_defs/src/builtin.rs | 51 ++++++++++++++++
compiler/rustc_session/src/parse.rs | 55 +++++++++++++++++-
src/test/ui/macros/stringify.rs | 7 +++
.../or-patterns/or-patterns-syntactic-pass.rs | 16 ++---
.../or-patterns-syntactic-pass.stderr | 13 +++++
...ints-before-generic-args-syntactic-pass.rs | 4 ++
...-before-generic-args-syntactic-pass.stderr | 24 ++++++++
src/test/ui/pattern/rest-pat-syntactic.rs | 5 +-
src/test/ui/pattern/rest-pat-syntactic.stderr | 24 ++++++++
11 files changed, 224 insertions(+), 34 deletions(-)
create mode 100644 src/test/ui/or-patterns/or-patterns-syntactic-pass.stderr
create mode 100644 src/test/ui/parser/constraints-before-generic-args-syntactic-pass.stderr
create mode 100644 src/test/ui/pattern/rest-pat-syntactic.stderr
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 97eee56f94807..68fca08101891 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -2,10 +2,10 @@ use rustc_ast as ast;
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
use rustc_ast::{AssocConstraint, AssocConstraintKind, NodeId};
use rustc_ast::{PatKind, RangeEnd, VariantData};
-use rustc_errors::{struct_span_err, Applicability};
+use rustc_errors::{struct_span_err, Applicability, StashKey};
+use rustc_feature::Features;
use rustc_feature::{AttributeGate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
-use rustc_feature::{Features, GateIssue};
-use rustc_session::parse::{feature_err, feature_err_issue};
+use rustc_session::parse::{feature_err, feature_warn};
use rustc_session::Session;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::sym;
@@ -20,9 +20,7 @@ macro_rules! gate_feature_fn {
let has_feature: bool = has_feature(visitor.features);
debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
if !has_feature && !span.allows_unstable($name) {
- feature_err_issue(&visitor.sess.parse_sess, name, span, GateIssue::Language, explain)
- .help(help)
- .emit();
+ feature_err(&visitor.sess.parse_sess, name, span, explain).help(help).emit();
}
}};
($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{
@@ -31,8 +29,19 @@ macro_rules! gate_feature_fn {
let has_feature: bool = has_feature(visitor.features);
debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
if !has_feature && !span.allows_unstable($name) {
- feature_err_issue(&visitor.sess.parse_sess, name, span, GateIssue::Language, explain)
- .emit();
+ feature_err(&visitor.sess.parse_sess, name, span, explain).emit();
+ }
+ }};
+ (future_incompatible; $visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{
+ let (visitor, has_feature, span, name, explain) =
+ (&*$visitor, $has_feature, $span, $name, $explain);
+ let has_feature: bool = has_feature(visitor.features);
+ debug!(
+ "gate_feature(feature = {:?}, span = {:?}); has? {} (future_incompatible)",
+ name, span, has_feature
+ );
+ if !has_feature && !span.allows_unstable($name) {
+ feature_warn(&visitor.sess.parse_sess, name, span, explain);
}
}};
}
@@ -44,6 +53,9 @@ macro_rules! gate_feature_post {
($visitor: expr, $feature: ident, $span: expr, $explain: expr) => {
gate_feature_fn!($visitor, |x: &Features| x.$feature, $span, sym::$feature, $explain)
};
+ (future_incompatible; $visitor: expr, $feature: ident, $span: expr, $explain: expr) => {
+ gate_feature_fn!(future_incompatible; $visitor, |x: &Features| x.$feature, $span, sym::$feature, $explain)
+ };
}
pub fn check_attribute(attr: &ast::Attribute, sess: &Session, features: &Features) {
@@ -588,11 +600,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
{
// When we encounter a statement of the form `foo: Ty = val;`, this will emit a type
// ascription error, but the likely intention was to write a `let` statement. (#78907).
- feature_err_issue(
+ feature_err(
&self.sess.parse_sess,
sym::type_ascription,
lhs.span,
- GateIssue::Language,
"type ascription is experimental",
).span_suggestion_verbose(
lhs.span.shrink_to_lo(),
@@ -615,15 +626,22 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
);
}
ast::ExprKind::Type(..) => {
- // To avoid noise about type ascription in common syntax errors, only emit if it
- // is the *only* error.
if self.sess.parse_sess.span_diagnostic.err_count() == 0 {
+ // To avoid noise about type ascription in common syntax errors,
+ // only emit if it is the *only* error.
gate_feature_post!(
&self,
type_ascription,
e.span,
"type ascription is experimental"
);
+ } else {
+ // And if it isn't, cancel the early-pass warning.
+ self.sess
+ .parse_sess
+ .span_diagnostic
+ .steal_diagnostic(e.span, StashKey::EarlySyntaxWarning)
+ .map(|err| err.cancel());
}
}
ast::ExprKind::TryBlock(_) => {
@@ -789,14 +807,12 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
// All uses of `gate_all!` below this point were added in #65742,
// and subsequently disabled (with the non-early gating readded).
+ // We emit an early future-incompatible warning for these.
+ // New syntax gates should go above here to get a hard error gate.
macro_rules! gate_all {
($gate:ident, $msg:literal) => {
- // FIXME(eddyb) do something more useful than always
- // disabling these uses of early feature-gatings.
- if false {
- for span in spans.get(&sym::$gate).unwrap_or(&vec![]) {
- gate_feature_post!(&visitor, $gate, *span, $msg);
- }
+ for span in spans.get(&sym::$gate).unwrap_or(&vec![]) {
+ gate_feature_post!(future_incompatible; &visitor, $gate, *span, $msg);
}
};
}
@@ -809,11 +825,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
gate_all!(try_blocks, "`try` blocks are unstable");
gate_all!(label_break_value, "labels on blocks are unstable");
gate_all!(box_syntax, "box expression syntax is experimental; you can call `Box::new` instead");
- // To avoid noise about type ascription in common syntax errors,
- // only emit if it is the *only* error. (Also check it last.)
- if sess.parse_sess.span_diagnostic.err_count() == 0 {
- gate_all!(type_ascription, "type ascription is experimental");
- }
+ gate_all!(type_ascription, "type ascription is experimental");
visit::walk_crate(&mut visitor, krate);
}
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index fe2afdf5a20b8..43b8288d8b627 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -458,6 +458,7 @@ struct HandlerInner {
pub enum StashKey {
ItemNoType,
UnderscoreForArrayLengths,
+ EarlySyntaxWarning,
}
fn default_track_diagnostic(_: &Diagnostic) {}
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index f00165cd3b370..95e34da734d6a 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -3212,6 +3212,56 @@ declare_lint! {
};
}
+declare_lint! {
+ /// The `unstable_syntax_pre_expansion` lint detects the use of unstable
+ /// syntax that is discarded during attribute expansion.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// #[cfg(FALSE)]
+ /// macro foo() {}
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// The input to active attributes such as `#[cfg]` or procedural macro
+ /// attributes is required to be valid syntax. Previously, the compiler only
+ /// gated the use of unstable syntax features after resolving `#[cfg]` gates
+ /// and expanding procedural macros.
+ ///
+ /// To avoid relying on unstable syntax, move the use of unstable syntax
+ /// into a position where the compiler does not parse the syntax, such as a
+ /// functionlike macro.
+ ///
+ /// ```rust
+ /// # #![deny(unstable_syntax_pre_expansion)]
+ ///
+ /// macro_rules! identity {
+ /// ( $($tokens:tt)* ) => { $($tokens)* }
+ /// }
+ ///
+ /// #[cfg(FALSE)]
+ /// identity! {
+ /// macro foo() {}
+ /// }
+ /// ```
+ ///
+ /// This is a [future-incompatible] lint to transition this
+ /// to a hard error in the future. See [issue #65860] for more details.
+ ///
+ /// [issue #65860]: https://github.com/rust-lang/rust/issues/65860
+ /// [future-incompatible]: ../index.md#future-incompatible-lints
+ pub UNSTABLE_SYNTAX_PRE_EXPANSION,
+ Warn,
+ "unstable syntax can change at any point in the future, causing a hard error!",
+ @future_incompatible = FutureIncompatibleInfo {
+ reference: "issue #65860 <https://github.com/rust-lang/rust/issues/65860>",
+ };
+}
+
declare_lint_pass! {
/// Does nothing as a lint pass, but registers some `Lint`s
/// that are used by other parts of the compiler.
@@ -3280,6 +3330,7 @@ declare_lint_pass! {
POINTER_STRUCTURAL_MATCH,
NONTRIVIAL_STRUCTURAL_MATCH,
SOFT_UNSTABLE,
+ UNSTABLE_SYNTAX_PRE_EXPANSION,
INLINE_NO_SANITIZE,
BAD_ASM_STYLE,
ASM_SUB_REGISTER,
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index f31d52147b47b..9f0886cb2089c 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -2,15 +2,17 @@
//! It also serves as an input to the parser itself.
use crate::config::CheckCfg;
-use crate::lint::{BufferedEarlyLint, BuiltinLintDiagnostics, Lint, LintId};
+use crate::lint::{
+ builtin::UNSTABLE_SYNTAX_PRE_EXPANSION, BufferedEarlyLint, BuiltinLintDiagnostics, Lint, LintId,
+};
use crate::SessionDiagnostic;
use rustc_ast::node_id::NodeId;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::{Lock, Lrc};
use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler};
use rustc_errors::{
- error_code, fallback_fluent_bundle, Applicability, Diagnostic, DiagnosticBuilder,
- DiagnosticMessage, ErrorGuaranteed, MultiSpan,
+ error_code, fallback_fluent_bundle, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId,
+ DiagnosticMessage, ErrorGuaranteed, MultiSpan, StashKey,
};
use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures};
use rustc_span::edition::Edition;
@@ -101,11 +103,58 @@ pub fn feature_err_issue<'a>(
issue: GateIssue,
explain: &str,
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
+ let span = span.into();
+
+ // Cancel an earlier warning for this same error, if it exists.
+ if let Some(span) = span.primary_span() {
+ sess.span_diagnostic
+ .steal_diagnostic(span, StashKey::EarlySyntaxWarning)
+ .map(|err| err.cancel());
+ }
+
let mut err = sess.span_diagnostic.struct_span_err_with_code(span, explain, error_code!(E0658));
add_feature_diagnostics_for_issue(&mut err, sess, feature, issue);
err
}
+/// Construct a future incompatibility diagnostic for a feature gate.
+///
+/// This diagnostic is only a warning and *does not cause compilation to fail*.
+pub fn feature_warn<'a>(sess: &'a ParseSess, feature: Symbol, span: Span, explain: &str) {
+ feature_warn_issue(sess, feature, span, GateIssue::Language, explain);
+}
+
+/// Construct a future incompatibility diagnostic for a feature gate.
+///
+/// This diagnostic is only a warning and *does not cause compilation to fail*.
+///
+/// This variant allows you to control whether it is a library or language feature.
+/// Almost always, you want to use this for a language feature. If so, prefer `feature_warn`.
+pub fn feature_warn_issue<'a>(
+ sess: &'a ParseSess,
+ feature: Symbol,
+ span: Span,
+ issue: GateIssue,
+ explain: &str,
+) {
+ let mut err = sess.span_diagnostic.struct_span_warn(span, explain);
+ add_feature_diagnostics_for_issue(&mut err, sess, feature, issue);
+
+ // Decorate this as a future-incompatibility lint as in rustc_middle::lint::struct_lint_level
+ let lint = UNSTABLE_SYNTAX_PRE_EXPANSION;
+ let future_incompatible = lint.future_incompatible.as_ref().unwrap();
+ err.code(DiagnosticId::Lint {
+ name: lint.name_lower(),
+ has_future_breakage: false,
+ is_force_warn: false,
+ });
+ err.warn(lint.desc);
+ err.note(format!("for more information, see {}", future_incompatible.reference));
+
+ // A later feature_err call can steal and cancel this warning.
+ err.stash(span, StashKey::EarlySyntaxWarning);
+}
+
/// Adds the diagnostics for a feature to an existing error.
pub fn add_feature_diagnostics<'a>(err: &mut Diagnostic, sess: &'a ParseSess, feature: Symbol) {
add_feature_diagnostics_for_issue(err, sess, feature, GateIssue::Language);
diff --git a/src/test/ui/macros/stringify.rs b/src/test/ui/macros/stringify.rs
index 8e71ed7c1120f..082c1abb8f2f4 100644
--- a/src/test/ui/macros/stringify.rs
+++ b/src/test/ui/macros/stringify.rs
@@ -3,11 +3,18 @@
// compile-flags: --test
#![feature(async_closure)]
+#![feature(box_patterns)]
+#![feature(box_syntax)]
#![feature(const_trait_impl)]
+#![feature(decl_macro)]
#![feature(generators)]
#![feature(half_open_range_patterns)]
+#![feature(label_break_value)]
#![feature(more_qualified_paths)]
#![feature(raw_ref_op)]
+#![feature(trait_alias)]
+#![feature(try_blocks)]
+#![feature(type_ascription)]
#![deny(unused_macros)]
macro_rules! stringify_block {
diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-pass.rs b/src/test/ui/or-patterns/or-patterns-syntactic-pass.rs
index 6f9a631b092a7..dda5c0bb59d23 100644
--- a/src/test/ui/or-patterns/or-patterns-syntactic-pass.rs
+++ b/src/test/ui/or-patterns/or-patterns-syntactic-pass.rs
@@ -7,7 +7,7 @@ fn main() {}
// Test the `pat` macro fragment parser:
macro_rules! accept_pat {
- ($p:pat) => {}
+ ($p:pat) => {};
}
accept_pat!((p | q));
@@ -21,28 +21,28 @@ accept_pat!([p | q]);
#[cfg(FALSE)]
fn or_patterns() {
// Top level of `let`:
- let (| A | B);
+ let (A | B);
let (A | B);
let (A | B): u8;
let (A | B) = 0;
let (A | B): u8 = 0;
// Top level of `for`:
- for | A | B in 0 {}
+ for A | B in 0 {}
for A | B in 0 {}
// Top level of `while`:
- while let | A | B = 0 {}
+ while let A | B = 0 {}
while let A | B = 0 {}
// Top level of `if`:
- if let | A | B = 0 {}
+ if let A | B = 0 {}
if let A | B = 0 {}
// Top level of `match` arms:
match 0 {
- | A | B => {},
- A | B => {},
+ A | B => {}
+ A | B => {}
}
// Functions:
@@ -68,6 +68,8 @@ fn or_patterns() {
// These bind as `(prefix p) | q` as opposed to `prefix (p | q)`:
let (box 0 | 1); // Unstable; we *can* change the precedence if we want.
+ //~^ WARN box pattern syntax is experimental
+ //~| WARN unstable syntax
let (&0 | 1);
let (&mut 0 | 1);
let (x @ 0 | 1);
diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-pass.stderr b/src/test/ui/or-patterns/or-patterns-syntactic-pass.stderr
new file mode 100644
index 0000000000000..c43fe192a73b8
--- /dev/null
+++ b/src/test/ui/or-patterns/or-patterns-syntactic-pass.stderr
@@ -0,0 +1,13 @@
+warning: box pattern syntax is experimental
+ --> $DIR/or-patterns-syntactic-pass.rs:70:10
+ |
+LL | let (box 0 | 1); // Unstable; we *can* change the precedence if we want.
+ | ^^^^^
+ |
+ = note: see issue #29641 <https://github.com/rust-lang/rust/issues/29641> for more information
+ = help: add `#![feature(box_patterns)]` to the crate attributes to enable
+ = warning: unstable syntax can change at any point in the future, causing a hard error!
+ = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/parser/constraints-before-generic-args-syntactic-pass.rs b/src/test/ui/parser/constraints-before-generic-args-syntactic-pass.rs
index afbd13e6fd9a8..d8346653c25aa 100644
--- a/src/test/ui/parser/constraints-before-generic-args-syntactic-pass.rs
+++ b/src/test/ui/parser/constraints-before-generic-args-syntactic-pass.rs
@@ -3,7 +3,11 @@
#[cfg(FALSE)]
fn syntax() {
foo::<T = u8, T: Ord, String>();
+ //~^ WARN associated type bounds are unstable
+ //~| WARN unstable syntax
foo::<T = u8, 'a, T: Ord>();
+ //~^ WARN associated type bounds are unstable
+ //~| WARN unstable syntax
}
fn main() {}
diff --git a/src/test/ui/parser/constraints-before-generic-args-syntactic-pass.stderr b/src/test/ui/parser/constraints-before-generic-args-syntactic-pass.stderr
new file mode 100644
index 0000000000000..7e843c7f4d006
--- /dev/null
+++ b/src/test/ui/parser/constraints-before-generic-args-syntactic-pass.stderr
@@ -0,0 +1,24 @@
+warning: associated type bounds are unstable
+ --> $DIR/constraints-before-generic-args-syntactic-pass.rs:5:19
+ |
+LL | foo::<T = u8, T: Ord, String>();
+ | ^^^^^^
+ |
+ = note: see issue #52662 <https://github.com/rust-lang/rust/issues/52662> for more information
+ = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
+ = warning: unstable syntax can change at any point in the future, causing a hard error!
+ = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+
+warning: associated type bounds are unstable
+ --> $DIR/constraints-before-generic-args-syntactic-pass.rs:8:23
+ |
+LL | foo::<T = u8, 'a, T: Ord>();
+ | ^^^^^^
+ |
+ = note: see issue #52662 <https://github.com/rust-lang/rust/issues/52662> for more information
+ = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
+ = warning: unstable syntax can change at any point in the future, causing a hard error!
+ = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+
+warning: 2 warnings emitted
+
diff --git a/src/test/ui/pattern/rest-pat-syntactic.rs b/src/test/ui/pattern/rest-pat-syntactic.rs
index 9656a0b5de9ce..4da5a2db76743 100644
--- a/src/test/ui/pattern/rest-pat-syntactic.rs
+++ b/src/test/ui/pattern/rest-pat-syntactic.rs
@@ -19,6 +19,8 @@ fn rest_patterns() {
// Box patterns:
let box ..;
+ //~^ WARN box pattern syntax is experimental
+ //~| WARN unstable syntax
// In or-patterns:
match x {
@@ -57,7 +59,7 @@ fn rest_patterns() {
.. |
[
(
- box ..,
+ box .., //~ WARN box pattern syntax is experimental
&(..),
&mut ..,
x @ ..
@@ -67,4 +69,5 @@ fn rest_patterns() {
ref mut x @ ..
=> {}
}
+ //~| WARN unstable syntax
}
diff --git a/src/test/ui/pattern/rest-pat-syntactic.stderr b/src/test/ui/pattern/rest-pat-syntactic.stderr
new file mode 100644
index 0000000000000..37019b7d5ba7a
--- /dev/null
+++ b/src/test/ui/pattern/rest-pat-syntactic.stderr
@@ -0,0 +1,24 @@
+warning: box pattern syntax is experimental
+ --> $DIR/rest-pat-syntactic.rs:21:9
+ |
+LL | let box ..;
+ | ^^^^^^
+ |
+ = note: see issue #29641 <https://github.com/rust-lang/rust/issues/29641> for more information
+ = help: add `#![feature(box_patterns)]` to the crate attributes to enable
+ = warning: unstable syntax can change at any point in the future, causing a hard error!
+ = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+
+warning: box pattern syntax is experimental
+ --> $DIR/rest-pat-syntactic.rs:62:17
+ |
+LL | box ..,
+ | ^^^^^^
+ |
+ = note: see issue #29641 <https://github.com/rust-lang/rust/issues/29641> for more information
+ = help: add `#![feature(box_patterns)]` to the crate attributes to enable
+ = warning: unstable syntax can change at any point in the future, causing a hard error!
+ = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+
+warning: 2 warnings emitted
+
From 944c6b6d760d392552fc60ec4e3ba3ad84598350 Mon Sep 17 00:00:00 2001
From: Christopher Durham <cad97@cad97.com>
Date: Wed, 17 Aug 2022 06:59:46 -0500
Subject: [PATCH 06/19] New ui tests for new soft feature gates
---
.../soft-syntax-gates-with-errors.rs | 30 +++++++++++++++++++
.../soft-syntax-gates-with-errors.stderr | 21 +++++++++++++
.../soft-syntax-gates-without-errors.rs | 26 ++++++++++++++++
.../soft-syntax-gates-without-errors.stderr | 24 +++++++++++++++
.../ui/suggestions/many-type-ascription.rs | 4 +++
.../suggestions/many-type-ascription.stderr | 12 ++++++++
.../type-ascription-and-other-error.rs | 6 ++++
.../type-ascription-and-other-error.stderr | 8 +++++
8 files changed, 131 insertions(+)
create mode 100644 src/test/ui/feature-gates/soft-syntax-gates-with-errors.rs
create mode 100644 src/test/ui/feature-gates/soft-syntax-gates-with-errors.stderr
create mode 100644 src/test/ui/feature-gates/soft-syntax-gates-without-errors.rs
create mode 100644 src/test/ui/feature-gates/soft-syntax-gates-without-errors.stderr
create mode 100644 src/test/ui/suggestions/many-type-ascription.rs
create mode 100644 src/test/ui/suggestions/many-type-ascription.stderr
create mode 100644 src/test/ui/suggestions/type-ascription-and-other-error.rs
create mode 100644 src/test/ui/suggestions/type-ascription-and-other-error.stderr
diff --git a/src/test/ui/feature-gates/soft-syntax-gates-with-errors.rs b/src/test/ui/feature-gates/soft-syntax-gates-with-errors.rs
new file mode 100644
index 0000000000000..49f1cba7151ef
--- /dev/null
+++ b/src/test/ui/feature-gates/soft-syntax-gates-with-errors.rs
@@ -0,0 +1,30 @@
+// check-fail
+// This file is used to test the behavior of the early-pass syntax warnings.
+// If macro syntax is stabilized, replace with a different unstable syntax.
+
+macro a() {}
+//~^ ERROR: `macro` is experimental
+
+#[cfg(FALSE)]
+macro b() {}
+
+macro_rules! identity {
+ ($($x:tt)*) => ($($x)*);
+}
+
+identity! {
+ macro c() {}
+ //~^ ERROR: `macro` is experimental
+}
+
+#[cfg(FALSE)]
+identity! {
+ macro d() {} // No error
+}
+
+identity! {
+ #[cfg(FALSE)]
+ macro e() {}
+}
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/soft-syntax-gates-with-errors.stderr b/src/test/ui/feature-gates/soft-syntax-gates-with-errors.stderr
new file mode 100644
index 0000000000000..49550d811ba52
--- /dev/null
+++ b/src/test/ui/feature-gates/soft-syntax-gates-with-errors.stderr
@@ -0,0 +1,21 @@
+error[E0658]: `macro` is experimental
+ --> $DIR/soft-syntax-gates-with-errors.rs:5:1
+ |
+LL | macro a() {}
+ | ^^^^^^^^^^^^
+ |
+ = note: see issue #39412 <https://github.com/rust-lang/rust/issues/39412> for more information
+ = help: add `#![feature(decl_macro)]` to the crate attributes to enable
+
+error[E0658]: `macro` is experimental
+ --> $DIR/soft-syntax-gates-with-errors.rs:16:5
+ |
+LL | macro c() {}
+ | ^^^^^^^^^^^^
+ |
+ = note: see issue #39412 <https://github.com/rust-lang/rust/issues/39412> for more information
+ = help: add `#![feature(decl_macro)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/soft-syntax-gates-without-errors.rs b/src/test/ui/feature-gates/soft-syntax-gates-without-errors.rs
new file mode 100644
index 0000000000000..ca4ad2320f657
--- /dev/null
+++ b/src/test/ui/feature-gates/soft-syntax-gates-without-errors.rs
@@ -0,0 +1,26 @@
+// check-pass
+// This file is used to test the behavior of the early-pass syntax warnings.
+// If macro syntax is stabilized, replace with a different unstable syntax.
+
+#[cfg(FALSE)]
+macro b() {}
+//~^ WARN: `macro` is experimental
+//~| WARN: unstable syntax
+
+macro_rules! identity {
+ ($($x:tt)*) => ($($x)*);
+}
+
+#[cfg(FALSE)]
+identity! {
+ macro d() {} // No error
+}
+
+identity! {
+ #[cfg(FALSE)]
+ macro e() {}
+ //~^ WARN: `macro` is experimental
+ //~| WARN: unstable syntax
+}
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/soft-syntax-gates-without-errors.stderr b/src/test/ui/feature-gates/soft-syntax-gates-without-errors.stderr
new file mode 100644
index 0000000000000..3d9c22e548710
--- /dev/null
+++ b/src/test/ui/feature-gates/soft-syntax-gates-without-errors.stderr
@@ -0,0 +1,24 @@
+warning: `macro` is experimental
+ --> $DIR/soft-syntax-gates-without-errors.rs:6:1
+ |
+LL | macro b() {}
+ | ^^^^^^^^^^^^
+ |
+ = note: see issue #39412 <https://github.com/rust-lang/rust/issues/39412> for more information
+ = help: add `#![feature(decl_macro)]` to the crate attributes to enable
+ = warning: unstable syntax can change at any point in the future, causing a hard error!
+ = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+
+warning: `macro` is experimental
+ --> $DIR/soft-syntax-gates-without-errors.rs:21:5
+ |
+LL | macro e() {}
+ | ^^^^^^^^^^^^
+ |
+ = note: see issue #39412 <https://github.com/rust-lang/rust/issues/39412> for more information
+ = help: add `#![feature(decl_macro)]` to the crate attributes to enable
+ = warning: unstable syntax can change at any point in the future, causing a hard error!
+ = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+
+warning: 2 warnings emitted
+
diff --git a/src/test/ui/suggestions/many-type-ascription.rs b/src/test/ui/suggestions/many-type-ascription.rs
new file mode 100644
index 0000000000000..31ac556b9447c
--- /dev/null
+++ b/src/test/ui/suggestions/many-type-ascription.rs
@@ -0,0 +1,4 @@
+fn main() {
+ let _ = 0: i32; //~ ERROR: type ascription is experimental
+ let _ = 0: i32; // (error only emitted once)
+}
diff --git a/src/test/ui/suggestions/many-type-ascription.stderr b/src/test/ui/suggestions/many-type-ascription.stderr
new file mode 100644
index 0000000000000..3706bbae9df9f
--- /dev/null
+++ b/src/test/ui/suggestions/many-type-ascription.stderr
@@ -0,0 +1,12 @@
+error[E0658]: type ascription is experimental
+ --> $DIR/many-type-ascription.rs:2:13
+ |
+LL | let _ = 0: i32;
+ | ^^^^^^
+ |
+ = note: see issue #23416 <https://github.com/rust-lang/rust/issues/23416> for more information
+ = help: add `#![feature(type_ascription)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/suggestions/type-ascription-and-other-error.rs b/src/test/ui/suggestions/type-ascription-and-other-error.rs
new file mode 100644
index 0000000000000..99ab2f3c858b9
--- /dev/null
+++ b/src/test/ui/suggestions/type-ascription-and-other-error.rs
@@ -0,0 +1,6 @@
+fn main() {
+ not rust; //~ ERROR
+ let _ = 0: i32; // (error hidden by existing error)
+ #[cfg(FALSE)]
+ let _ = 0: i32; // (warning hidden by existing error)
+}
diff --git a/src/test/ui/suggestions/type-ascription-and-other-error.stderr b/src/test/ui/suggestions/type-ascription-and-other-error.stderr
new file mode 100644
index 0000000000000..eadf634bb14fd
--- /dev/null
+++ b/src/test/ui/suggestions/type-ascription-and-other-error.stderr
@@ -0,0 +1,8 @@
+error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `rust`
+ --> $DIR/type-ascription-and-other-error.rs:2:9
+ |
+LL | not rust;
+ | ^^^^ expected one of 8 possible tokens
+
+error: aborting due to previous error
+
From be2641a61f2d34fe4f937a49dacfcb82bf0b9075 Mon Sep 17 00:00:00 2001
From: Camille GILLOT <gillot.camille@gmail.com>
Date: Wed, 17 Aug 2022 20:22:52 +0200
Subject: [PATCH 07/19] Fortify check for const generics.
---
compiler/rustc_typeck/src/astconv/mod.rs | 25 ++++++++++--------------
1 file changed, 10 insertions(+), 15 deletions(-)
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index ff81747cafe6f..5bb02bc246caf 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -1453,16 +1453,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.enumerate()
.skip(1) // Remove `Self` for `ExistentialPredicate`.
.map(|(index, arg)| {
- if let ty::GenericArgKind::Type(ty) = arg.unpack() {
- debug!(?ty);
- if ty == dummy_self {
- let param = &generics.params[index];
- missing_type_params.push(param.name);
- return tcx.ty_error().into();
- } else if ty.walk().any(|arg| arg == dummy_self.into()) {
- references_self = true;
- return tcx.ty_error().into();
- }
+ if arg == dummy_self.into() {
+ let param = &generics.params[index];
+ missing_type_params.push(param.name);
+ return tcx.ty_error().into();
+ } else if arg.walk().any(|arg| arg == dummy_self.into()) {
+ references_self = true;
+ return tcx.ty_error().into();
}
arg
})
@@ -1509,10 +1506,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// Like for trait refs, verify that `dummy_self` did not leak inside default type
// parameters.
let references_self = b.projection_ty.substs.iter().skip(1).any(|arg| {
- if let ty::GenericArgKind::Type(ty) = arg.unpack() {
- if ty == dummy_self || ty.walk().any(|arg| arg == dummy_self.into()) {
- return true;
- }
+ if arg.walk().any(|arg| arg == dummy_self.into()) {
+ return true;
}
false
});
@@ -1524,7 +1519,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.substs
.iter()
.map(|arg| {
- if let ty::GenericArgKind::Type(_) = arg.unpack() {
+ if arg.walk().any(|arg| arg == dummy_self.into()) {
return tcx.ty_error().into();
}
arg
From 72acd94117e784d4e7425e827c60d6a6748d7a88 Mon Sep 17 00:00:00 2001
From: Camille GILLOT <gillot.camille@gmail.com>
Date: Wed, 17 Aug 2022 21:50:59 +0200
Subject: [PATCH 08/19] Add const-generics test.
---
src/test/ui/traits/alias/self-in-const-generics.rs | 12 ++++++++++++
.../ui/traits/alias/self-in-const-generics.stderr | 11 +++++++++++
2 files changed, 23 insertions(+)
create mode 100644 src/test/ui/traits/alias/self-in-const-generics.rs
create mode 100644 src/test/ui/traits/alias/self-in-const-generics.stderr
diff --git a/src/test/ui/traits/alias/self-in-const-generics.rs b/src/test/ui/traits/alias/self-in-const-generics.rs
new file mode 100644
index 0000000000000..b0de8ccd67847
--- /dev/null
+++ b/src/test/ui/traits/alias/self-in-const-generics.rs
@@ -0,0 +1,12 @@
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+#![feature(trait_alias)]
+
+trait Bar<const N: usize> {}
+
+trait BB = Bar<{ 2 + 1 }>;
+
+fn foo(x: &dyn BB) {}
+//~^ ERROR the trait alias `BB` cannot be made into an object [E0038]
+
+fn main() {}
diff --git a/src/test/ui/traits/alias/self-in-const-generics.stderr b/src/test/ui/traits/alias/self-in-const-generics.stderr
new file mode 100644
index 0000000000000..61cc217cfbce6
--- /dev/null
+++ b/src/test/ui/traits/alias/self-in-const-generics.stderr
@@ -0,0 +1,11 @@
+error[E0038]: the trait alias `BB` cannot be made into an object
+ --> $DIR/self-in-const-generics.rs:9:16
+ |
+LL | fn foo(x: &dyn BB) {}
+ | ^^
+ |
+ = note: it cannot use `Self` as a type parameter in a supertrait or `where`-clause
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0038`.
From fe6956b7be4d619d98154a5ade5b5c21cb128732 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume.gomez@huawei.com>
Date: Thu, 18 Aug 2022 15:47:39 +0200
Subject: [PATCH 09/19] Fix item-info display
---
src/librustdoc/html/render/mod.rs | 12 ++++++++----
src/librustdoc/html/static/css/rustdoc.css | 1 +
2 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 5ed5299e09bc0..13d955c618a4f 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -569,7 +569,10 @@ fn short_item_info(
message.push_str(&format!(": {}", html.into_string()));
}
extra_info.push(format!(
- "<div class=\"stab deprecated\"><span class=\"emoji\">👎</span> {}</div>",
+ "<div class=\"stab deprecated\">\
+ <span class=\"emoji\">👎</span>\
+ <span>{}</span>\
+ </div>",
message,
));
}
@@ -582,8 +585,9 @@ fn short_item_info(
.filter(|stab| stab.feature != sym::rustc_private)
.map(|stab| (stab.level, stab.feature))
{
- let mut message =
- "<span class=\"emoji\">🔬</span> This is a nightly-only experimental API.".to_owned();
+ let mut message = "<span class=\"emoji\">🔬</span>\
+ <span>This is a nightly-only experimental API."
+ .to_owned();
let mut feature = format!("<code>{}</code>", Escape(feature.as_str()));
if let (Some(url), Some(issue)) = (&cx.shared.issue_tracker_base_url, issue) {
@@ -594,7 +598,7 @@ fn short_item_info(
));
}
- message.push_str(&format!(" ({})", feature));
+ message.push_str(&format!(" ({})</span>", feature));
extra_info.push(format!("<div class=\"stab unstable\">{}</div>", message));
}
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 710ca3ee7c7e7..52a7d04458409 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -1172,6 +1172,7 @@ so that we can apply CSS-filters to change the arrow color in themes */
.stab .emoji {
font-size: 1.25rem;
+ margin-right: 0.3rem;
}
/* Black one-pixel outline around emoji shapes */
From 0df1c690231c108fcfaa3ba3e22be37fa4fb8fc4 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume.gomez@huawei.com>
Date: Thu, 18 Aug 2022 17:47:40 +0200
Subject: [PATCH 10/19] Update rustdoc test
---
src/test/rustdoc/issue-32374.rs | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/src/test/rustdoc/issue-32374.rs b/src/test/rustdoc/issue-32374.rs
index 9c585497d354f..8d2c27cf3d77d 100644
--- a/src/test/rustdoc/issue-32374.rs
+++ b/src/test/rustdoc/issue-32374.rs
@@ -8,20 +8,24 @@
// 'Experimental'
// @matches issue_32374/index.html '//*[@class="item-right docblock-short"]/text()' 'Docs'
-// @has issue_32374/struct.T.html '//*[@class="stab deprecated"]' \
-// '👎 Deprecated since 1.0.0: text'
+// @has issue_32374/struct.T.html '//*[@class="stab deprecated"]/span' '👎'
+// @has issue_32374/struct.T.html '//*[@class="stab deprecated"]/span' \
+// 'Deprecated since 1.0.0: text'
// @hasraw - '<code>test</code> <a href="https://issue_url/32374">#32374</a>'
+// @matches issue_32374/struct.T.html '//*[@class="stab unstable"]' '🔬'
// @matches issue_32374/struct.T.html '//*[@class="stab unstable"]' \
-// '🔬 This is a nightly-only experimental API. \(test\s#32374\)$'
+// 'This is a nightly-only experimental API. \(test\s#32374\)$'
/// Docs
#[deprecated(since = "1.0.0", note = "text")]
#[unstable(feature = "test", issue = "32374")]
pub struct T;
+// @has issue_32374/struct.U.html '//*[@class="stab deprecated"]' '👎'
// @has issue_32374/struct.U.html '//*[@class="stab deprecated"]' \
-// '👎 Deprecated since 1.0.0: deprecated'
+// 'Deprecated since 1.0.0: deprecated'
+// @has issue_32374/struct.U.html '//*[@class="stab unstable"]' '🔬'
// @has issue_32374/struct.U.html '//*[@class="stab unstable"]' \
-// '🔬 This is a nightly-only experimental API. (test #32374)'
+// 'This is a nightly-only experimental API. (test #32374)'
#[deprecated(since = "1.0.0", note = "deprecated")]
#[unstable(feature = "test", issue = "32374", reason = "unstable")]
pub struct U;
From ac66baad1a9787f60ff86fac125da8176e053dbc Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Wed, 3 Aug 2022 22:48:12 -0400
Subject: [PATCH 11/19] add miri-test-libstd support to libstd
---
library/alloc/src/lib.rs | 1 +
library/std/src/lib.rs | 8 ++++++++
2 files changed, 9 insertions(+)
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 8b6f4054851dd..a6f3593addc10 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -60,6 +60,7 @@
// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
// rustc itself never sets the feature, so this line has no affect there.
#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
+//
#![allow(unused_attributes)]
#![stable(feature = "alloc", since = "1.36.0")]
#![doc(
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index a8d6645794ae5..bbd7041c50bd0 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -187,6 +187,14 @@
//! [rust-discord]: https://discord.gg/rust-lang
//! [array]: prim@array
//! [slice]: prim@slice
+
+// To run libstd tests without x.py without ending up with two copies of libstd, Miri needs to be
+// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
+// rustc itself never sets the feature, so this line has no affect there.
+#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
+// miri-test-libstd also prefers to make std use the sysroot versions of the dependencies.
+#![cfg_attr(feature = "miri-test-libstd", feature(rustc_private))]
+//
#![cfg_attr(not(feature = "restricted-std"), stable(feature = "rust1", since = "1.0.0"))]
#![cfg_attr(feature = "restricted-std", unstable(feature = "restricted_std", issue = "none"))]
#![doc(
From 27b044433367d7305f71bcf67dd9b5be0a0bd65a Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Thu, 4 Aug 2022 09:01:00 -0400
Subject: [PATCH 12/19] add some Miri-only tests
---
library/alloc/src/sync/tests.rs | 19 +++++++++++++++++++
library/std/src/thread/tests.rs | 19 +++++++++++++++++++
2 files changed, 38 insertions(+)
diff --git a/library/alloc/src/sync/tests.rs b/library/alloc/src/sync/tests.rs
index 202d0e7f02057..0fae8953aa2c7 100644
--- a/library/alloc/src/sync/tests.rs
+++ b/library/alloc/src/sync/tests.rs
@@ -618,3 +618,22 @@ fn test_arc_cyclic_two_refs() {
assert_eq!(Arc::strong_count(&two_refs), 3);
assert_eq!(Arc::weak_count(&two_refs), 2);
}
+
+/// Test for Arc::drop bug (https://github.com/rust-lang/rust/issues/55005)
+#[test]
+#[cfg(miri)] // relies on Stacked Borrows in Miri
+fn arc_drop_dereferenceable_race() {
+ // The bug seems to take up to 700 iterations to reproduce with most seeds (tested 0-9).
+ for _ in 0..750 {
+ let arc_1 = Arc::new(());
+ let arc_2 = arc_1.clone();
+ let thread = thread::spawn(|| drop(arc_2));
+ // Spin a bit; makes the race more likely to appear
+ let mut i = 0;
+ while i < 256 {
+ i += 1;
+ }
+ drop(arc_1);
+ thread.join().unwrap();
+ }
+}
diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs
index ec68b52918802..130e47c8d44f0 100644
--- a/library/std/src/thread/tests.rs
+++ b/library/std/src/thread/tests.rs
@@ -329,3 +329,22 @@ fn test_scoped_threads_nll() {
let x = 42_u8;
foo(&x);
}
+
+// Regression test for https://github.com/rust-lang/rust/issues/98498.
+#[test]
+#[cfg(miri)] // relies on Miri's data race detector
+fn scope_join_race() {
+ for _ in 0..100 {
+ let a_bool = AtomicBool::new(false);
+
+ thread::scope(|s| {
+ for _ in 0..5 {
+ s.spawn(|| a_bool.load(Ordering::Relaxed));
+ }
+
+ for _ in 0..5 {
+ s.spawn(|| a_bool.load(Ordering::Relaxed));
+ }
+ });
+ }
+}
From 8c8dc125b1bfca49ac8f064b365cb72a658e7cba Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Thu, 4 Aug 2022 09:16:42 -0400
Subject: [PATCH 13/19] make many std tests work in Miri
---
library/std/src/collections/hash/map/tests.rs | 24 +++++++++++--------
library/std/src/io/tests.rs | 3 ++-
library/std/src/path/tests.rs | 5 ++++
library/std/src/sync/mpsc/mpsc_queue/tests.rs | 2 +-
library/std/src/sync/mpsc/spsc_queue/tests.rs | 5 ++--
library/std/src/sync/mpsc/sync_tests.rs | 21 +++++++++-------
library/std/src/sync/mpsc/tests.rs | 12 ++++++----
library/std/src/sync/rwlock/tests.rs | 2 +-
library/std/src/time/tests.rs | 3 ++-
9 files changed, 47 insertions(+), 30 deletions(-)
diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs
index 7ebc41588b3df..cb3032719fa64 100644
--- a/library/std/src/collections/hash/map/tests.rs
+++ b/library/std/src/collections/hash/map/tests.rs
@@ -268,10 +268,13 @@ fn test_lots_of_insertions() {
// Try this a few times to make sure we never screw up the hashmap's
// internal state.
- for _ in 0..10 {
+ let loops = if cfg!(miri) { 2 } else { 10 };
+ for _ in 0..loops {
assert!(m.is_empty());
- for i in 1..1001 {
+ let count = if cfg!(miri) { 101 } else { 1001 };
+
+ for i in 1..count {
assert!(m.insert(i, i).is_none());
for j in 1..=i {
@@ -279,42 +282,42 @@ fn test_lots_of_insertions() {
assert_eq!(r, Some(&j));
}
- for j in i + 1..1001 {
+ for j in i + 1..count {
let r = m.get(&j);
assert_eq!(r, None);
}
}
- for i in 1001..2001 {
+ for i in count..(2 * count) {
assert!(!m.contains_key(&i));
}
// remove forwards
- for i in 1..1001 {
+ for i in 1..count {
assert!(m.remove(&i).is_some());
for j in 1..=i {
assert!(!m.contains_key(&j));
}
- for j in i + 1..1001 {
+ for j in i + 1..count {
assert!(m.contains_key(&j));
}
}
- for i in 1..1001 {
+ for i in 1..count {
assert!(!m.contains_key(&i));
}
- for i in 1..1001 {
+ for i in 1..count {
assert!(m.insert(i, i).is_none());
}
// remove backwards
- for i in (1..1001).rev() {
+ for i in (1..count).rev() {
assert!(m.remove(&i).is_some());
- for j in i..1001 {
+ for j in i..count {
assert!(!m.contains_key(&j));
}
@@ -817,6 +820,7 @@ fn test_retain() {
}
#[test]
+#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
fn test_try_reserve() {
let mut empty_bytes: HashMap<u8, u8> = HashMap::new();
diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs
index f357f33ec52c5..68a19eccc0e7c 100644
--- a/library/std/src/io/tests.rs
+++ b/library/std/src/io/tests.rs
@@ -94,7 +94,7 @@ fn read_to_end() {
assert_eq!(c.read_to_end(&mut v).unwrap(), 1);
assert_eq!(v, b"1");
- let cap = 1024 * 1024;
+ let cap = if cfg!(miri) { 1024 } else { 1024 * 1024 };
let data = (0..cap).map(|i| (i / 3) as u8).collect::<Vec<_>>();
let mut v = Vec::new();
let (a, b) = data.split_at(data.len() / 2);
@@ -309,6 +309,7 @@ fn chain_zero_length_read_is_not_eof() {
#[bench]
#[cfg_attr(target_os = "emscripten", ignore)]
+#[cfg_attr(miri, ignore)] // Miri isn't fast...
fn bench_read_to_end(b: &mut test::Bencher) {
b.iter(|| {
let mut lr = repeat(1).take(10000000);
diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs
index 351cf698810f1..dd307022c6d05 100644
--- a/library/std/src/path/tests.rs
+++ b/library/std/src/path/tests.rs
@@ -1768,6 +1768,7 @@ fn test_windows_absolute() {
}
#[bench]
+#[cfg_attr(miri, ignore)] // Miri isn't fast...
fn bench_path_cmp_fast_path_buf_sort(b: &mut test::Bencher) {
let prefix = "my/home";
let mut paths: Vec<_> =
@@ -1781,6 +1782,7 @@ fn bench_path_cmp_fast_path_buf_sort(b: &mut test::Bencher) {
}
#[bench]
+#[cfg_attr(miri, ignore)] // Miri isn't fast...
fn bench_path_cmp_fast_path_long(b: &mut test::Bencher) {
let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/";
let paths: Vec<_> =
@@ -1799,6 +1801,7 @@ fn bench_path_cmp_fast_path_long(b: &mut test::Bencher) {
}
#[bench]
+#[cfg_attr(miri, ignore)] // Miri isn't fast...
fn bench_path_cmp_fast_path_short(b: &mut test::Bencher) {
let prefix = "my/home";
let paths: Vec<_> =
@@ -1817,6 +1820,7 @@ fn bench_path_cmp_fast_path_short(b: &mut test::Bencher) {
}
#[bench]
+#[cfg_attr(miri, ignore)] // Miri isn't fast...
fn bench_path_hashset(b: &mut test::Bencher) {
let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/";
let paths: Vec<_> =
@@ -1835,6 +1839,7 @@ fn bench_path_hashset(b: &mut test::Bencher) {
}
#[bench]
+#[cfg_attr(miri, ignore)] // Miri isn't fast...
fn bench_path_hashset_miss(b: &mut test::Bencher) {
let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/";
let paths: Vec<_> =
diff --git a/library/std/src/sync/mpsc/mpsc_queue/tests.rs b/library/std/src/sync/mpsc/mpsc_queue/tests.rs
index 9f4f31ed05145..34b2a9a98ac36 100644
--- a/library/std/src/sync/mpsc/mpsc_queue/tests.rs
+++ b/library/std/src/sync/mpsc/mpsc_queue/tests.rs
@@ -13,7 +13,7 @@ fn test_full() {
#[test]
fn test() {
let nthreads = 8;
- let nmsgs = 1000;
+ let nmsgs = if cfg!(miri) { 100 } else { 1000 };
let q = Queue::new();
match q.pop() {
Empty => {}
diff --git a/library/std/src/sync/mpsc/spsc_queue/tests.rs b/library/std/src/sync/mpsc/spsc_queue/tests.rs
index 467ef3dbdcbbd..eb6d5c2cf66d8 100644
--- a/library/std/src/sync/mpsc/spsc_queue/tests.rs
+++ b/library/std/src/sync/mpsc/spsc_queue/tests.rs
@@ -77,12 +77,13 @@ fn stress() {
}
unsafe fn stress_bound(bound: usize) {
+ let count = if cfg!(miri) { 1000 } else { 100000 };
let q = Arc::new(Queue::with_additions(bound, (), ()));
let (tx, rx) = channel();
let q2 = q.clone();
let _t = thread::spawn(move || {
- for _ in 0..100000 {
+ for _ in 0..count {
loop {
match q2.pop() {
Some(1) => break,
@@ -93,7 +94,7 @@ fn stress() {
}
tx.send(()).unwrap();
});
- for _ in 0..100000 {
+ for _ in 0..count {
q.push(1);
}
rx.recv().unwrap();
diff --git a/library/std/src/sync/mpsc/sync_tests.rs b/library/std/src/sync/mpsc/sync_tests.rs
index e58649bab6e42..63c79436974d5 100644
--- a/library/std/src/sync/mpsc/sync_tests.rs
+++ b/library/std/src/sync/mpsc/sync_tests.rs
@@ -113,23 +113,25 @@ fn chan_gone_concurrent() {
#[test]
fn stress() {
+ let count = if cfg!(miri) { 100 } else { 10000 };
let (tx, rx) = sync_channel::<i32>(0);
thread::spawn(move || {
- for _ in 0..10000 {
+ for _ in 0..count {
tx.send(1).unwrap();
}
});
- for _ in 0..10000 {
+ for _ in 0..count {
assert_eq!(rx.recv().unwrap(), 1);
}
}
#[test]
fn stress_recv_timeout_two_threads() {
+ let count = if cfg!(miri) { 100 } else { 10000 };
let (tx, rx) = sync_channel::<i32>(0);
thread::spawn(move || {
- for _ in 0..10000 {
+ for _ in 0..count {
tx.send(1).unwrap();
}
});
@@ -146,12 +148,12 @@ fn stress_recv_timeout_two_threads() {
}
}
- assert_eq!(recv_count, 10000);
+ assert_eq!(recv_count, count);
}
#[test]
fn stress_recv_timeout_shared() {
- const AMT: u32 = 1000;
+ const AMT: u32 = if cfg!(miri) { 100 } else { 1000 };
const NTHREADS: u32 = 8;
let (tx, rx) = sync_channel::<i32>(0);
let (dtx, drx) = sync_channel::<()>(0);
@@ -191,7 +193,7 @@ fn stress_recv_timeout_shared() {
#[test]
fn stress_shared() {
- const AMT: u32 = 1000;
+ const AMT: u32 = if cfg!(miri) { 100 } else { 1000 };
const NTHREADS: u32 = 8;
let (tx, rx) = sync_channel::<i32>(0);
let (dtx, drx) = sync_channel::<()>(0);
@@ -438,12 +440,13 @@ fn stream_send_recv_stress() {
#[test]
fn recv_a_lot() {
+ let count = if cfg!(miri) { 1000 } else { 10000 };
// Regression test that we don't run out of stack in scheduler context
- let (tx, rx) = sync_channel(10000);
- for _ in 0..10000 {
+ let (tx, rx) = sync_channel(count);
+ for _ in 0..count {
tx.send(()).unwrap();
}
- for _ in 0..10000 {
+ for _ in 0..count {
rx.recv().unwrap();
}
}
diff --git a/library/std/src/sync/mpsc/tests.rs b/library/std/src/sync/mpsc/tests.rs
index 4deb3e5961577..f6d0796f604fa 100644
--- a/library/std/src/sync/mpsc/tests.rs
+++ b/library/std/src/sync/mpsc/tests.rs
@@ -120,13 +120,14 @@ fn chan_gone_concurrent() {
#[test]
fn stress() {
+ let count = if cfg!(miri) { 100 } else { 10000 };
let (tx, rx) = channel::<i32>();
let t = thread::spawn(move || {
- for _ in 0..10000 {
+ for _ in 0..count {
tx.send(1).unwrap();
}
});
- for _ in 0..10000 {
+ for _ in 0..count {
assert_eq!(rx.recv().unwrap(), 1);
}
t.join().ok().expect("thread panicked");
@@ -134,7 +135,7 @@ fn stress() {
#[test]
fn stress_shared() {
- const AMT: u32 = 10000;
+ const AMT: u32 = if cfg!(miri) { 100 } else { 10000 };
const NTHREADS: u32 = 8;
let (tx, rx) = channel::<i32>();
@@ -504,12 +505,13 @@ fn very_long_recv_timeout_wont_panic() {
#[test]
fn recv_a_lot() {
+ let count = if cfg!(miri) { 1000 } else { 10000 };
// Regression test that we don't run out of stack in scheduler context
let (tx, rx) = channel();
- for _ in 0..10000 {
+ for _ in 0..count {
tx.send(()).unwrap();
}
- for _ in 0..10000 {
+ for _ in 0..count {
rx.recv().unwrap();
}
}
diff --git a/library/std/src/sync/rwlock/tests.rs b/library/std/src/sync/rwlock/tests.rs
index 08255c985f5eb..b5b3ad9898edb 100644
--- a/library/std/src/sync/rwlock/tests.rs
+++ b/library/std/src/sync/rwlock/tests.rs
@@ -19,7 +19,7 @@ fn smoke() {
#[test]
fn frob() {
const N: u32 = 10;
- const M: usize = 1000;
+ const M: usize = if cfg!(miri) { 100 } else { 1000 };
let r = Arc::new(RwLock::new(()));
diff --git a/library/std/src/time/tests.rs b/library/std/src/time/tests.rs
index d710a574465ce..6229556c85fee 100644
--- a/library/std/src/time/tests.rs
+++ b/library/std/src/time/tests.rs
@@ -31,7 +31,8 @@ fn instant_monotonic_concurrent() -> crate::thread::Result<()> {
.map(|_| {
crate::thread::spawn(|| {
let mut old = Instant::now();
- for _ in 0..5_000_000 {
+ let count = if cfg!(miri) { 1_000 } else { 5_000_000 };
+ for _ in 0..count {
let new = Instant::now();
assert!(new >= old);
old = new;
From 438e49c1cba71d7ff8a138a1b96058c2d9a9d217 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Sat, 6 Aug 2022 14:46:30 -0400
Subject: [PATCH 14/19] silence some unused-fn warnings in miri std builds
---
library/std/src/sys/unix/fs.rs | 2 ++
1 file changed, 2 insertions(+)
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index 7778033eaa98c..f38d2fd3d704e 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -829,6 +829,7 @@ impl DirEntry {
target_os = "fuchsia",
target_os = "redox"
)))]
+ #[cfg_attr(miri, allow(unused))]
fn name_cstr(&self) -> &CStr {
unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) }
}
@@ -840,6 +841,7 @@ impl DirEntry {
target_os = "fuchsia",
target_os = "redox"
))]
+ #[cfg_attr(miri, allow(unused))]
fn name_cstr(&self) -> &CStr {
&self.name
}
From fbcdf2a383f6b17f80d8c285af3fa9739aaf223c Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Thu, 18 Aug 2022 18:07:35 -0400
Subject: [PATCH 15/19] clarify lib.rs attribute structure
---
library/alloc/src/lib.rs | 9 ++++-----
library/std/src/lib.rs | 23 +++++++++++++----------
2 files changed, 17 insertions(+), 15 deletions(-)
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index a6f3593addc10..aea84ac90c1bc 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -56,11 +56,6 @@
//! [`Rc`]: rc
//! [`RefCell`]: core::cell
-// To run liballoc tests without x.py without ending up with two copies of liballoc, Miri needs to be
-// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
-// rustc itself never sets the feature, so this line has no affect there.
-#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
-//
#![allow(unused_attributes)]
#![stable(feature = "alloc", since = "1.36.0")]
#![doc(
@@ -78,6 +73,10 @@
))]
#![no_std]
#![needs_allocator]
+// To run liballoc tests without x.py without ending up with two copies of liballoc, Miri needs to be
+// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
+// rustc itself never sets the feature, so this line has no affect there.
+#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
//
// Lints:
#![deny(unsafe_op_in_unsafe_fn)]
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index bbd7041c50bd0..ead06f40d87c4 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -188,13 +188,6 @@
//! [array]: prim@array
//! [slice]: prim@slice
-// To run libstd tests without x.py without ending up with two copies of libstd, Miri needs to be
-// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
-// rustc itself never sets the feature, so this line has no affect there.
-#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
-// miri-test-libstd also prefers to make std use the sysroot versions of the dependencies.
-#![cfg_attr(feature = "miri-test-libstd", feature(rustc_private))]
-//
#![cfg_attr(not(feature = "restricted-std"), stable(feature = "rust1", since = "1.0.0"))]
#![cfg_attr(feature = "restricted-std", unstable(feature = "restricted_std", issue = "none"))]
#![doc(
@@ -209,25 +202,35 @@
no_global_oom_handling,
not(no_global_oom_handling)
))]
+// To run libstd tests without x.py without ending up with two copies of libstd, Miri needs to be
+// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
+// rustc itself never sets the feature, so this line has no affect there.
+#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
+// miri-test-libstd also prefers to make std use the sysroot versions of the dependencies.
+#![cfg_attr(feature = "miri-test-libstd", feature(rustc_private))]
// Don't link to std. We are std.
#![no_std]
+// Tell the compiler to link to either panic_abort or panic_unwind
+#![needs_panic_runtime]
+//
+// Lints:
#![warn(deprecated_in_future)]
#![warn(missing_docs)]
#![warn(missing_debug_implementations)]
#![allow(explicit_outlives_requirements)]
#![allow(unused_lifetimes)]
-// Tell the compiler to link to either panic_abort or panic_unwind
-#![needs_panic_runtime]
+#![deny(rustc::existing_doc_keyword)]
// Ensure that std can be linked against panic_abort despite compiled with `-C panic=unwind`
#![deny(ffi_unwind_calls)]
// std may use features in a platform-specific way
#![allow(unused_features)]
+//
+// Features:
#![cfg_attr(test, feature(internal_output_capture, print_internals, update_panic_count, rt))]
#![cfg_attr(
all(target_vendor = "fortanix", target_env = "sgx"),
feature(slice_index_methods, coerce_unsized, sgx_platform)
)]
-#![deny(rustc::existing_doc_keyword)]
//
// Language features:
#![feature(alloc_error_handler)]
From 64b3e4af2031fb2faf3330ab01c27ae084412079 Mon Sep 17 00:00:00 2001
From: Takayuki Maeda <takoyaki0316@gmail.com>
Date: Sat, 20 Aug 2022 02:51:20 +0900
Subject: [PATCH 16/19] suggest adding a reference to a trait assoc item
---
.../src/traits/error_reporting/suggestions.rs | 186 ++++++++++--------
...adding-reference-to-trait-assoc-item.fixed | 15 ++
...st-adding-reference-to-trait-assoc-item.rs | 15 ++
...dding-reference-to-trait-assoc-item.stderr | 25 +++
4 files changed, 156 insertions(+), 85 deletions(-)
create mode 100644 src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.fixed
create mode 100644 src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.rs
create mode 100644 src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.stderr
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 219413121d812..28b3d886b50b5 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -882,6 +882,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
obligation.cause.code()
{
&parent_code
+ } else if let ObligationCauseCode::ItemObligation(_) = obligation.cause.code() {
+ obligation.cause.code()
} else if let ExpnKind::Desugaring(DesugaringKind::ForLoop) =
span.ctxt().outer_expn_data().kind
{
@@ -906,102 +908,116 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
let param_env = obligation.param_env;
// Try to apply the original trait binding obligation by borrowing.
- let mut try_borrowing =
- |old_pred: ty::PolyTraitPredicate<'tcx>, blacklist: &[DefId]| -> bool {
- if blacklist.contains(&old_pred.def_id()) {
- return false;
- }
- // We map bounds to `&T` and `&mut T`
- let trait_pred_and_imm_ref = old_pred.map_bound(|trait_pred| {
- (
- trait_pred,
- self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()),
- )
- });
- let trait_pred_and_mut_ref = old_pred.map_bound(|trait_pred| {
- (
- trait_pred,
- self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()),
- )
- });
+ let mut try_borrowing = |old_pred: ty::PolyTraitPredicate<'tcx>,
+ blacklist: &[DefId]|
+ -> bool {
+ if blacklist.contains(&old_pred.def_id()) {
+ return false;
+ }
+ // We map bounds to `&T` and `&mut T`
+ let trait_pred_and_imm_ref = old_pred.map_bound(|trait_pred| {
+ (
+ trait_pred,
+ self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()),
+ )
+ });
+ let trait_pred_and_mut_ref = old_pred.map_bound(|trait_pred| {
+ (
+ trait_pred,
+ self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()),
+ )
+ });
- let mk_result = |trait_pred_and_new_ty| {
- let obligation =
- self.mk_trait_obligation_with_new_self_ty(param_env, trait_pred_and_new_ty);
- self.predicate_must_hold_modulo_regions(&obligation)
+ let mk_result = |trait_pred_and_new_ty| {
+ let obligation =
+ self.mk_trait_obligation_with_new_self_ty(param_env, trait_pred_and_new_ty);
+ self.predicate_must_hold_modulo_regions(&obligation)
+ };
+ let imm_result = mk_result(trait_pred_and_imm_ref);
+ let mut_result = mk_result(trait_pred_and_mut_ref);
+
+ let ref_inner_ty_result =
+ if let ObligationCauseCode::ItemObligation(_) = obligation.cause.code()
+ && let ty::Ref(_, ty, mutability) = old_pred.self_ty().skip_binder().kind()
+ {
+ Some((mk_result(old_pred.map_bound(|trait_pred| (trait_pred, *ty))), mutability))
+ } else {
+ None
};
- let imm_result = mk_result(trait_pred_and_imm_ref);
- let mut_result = mk_result(trait_pred_and_mut_ref);
-
- if imm_result || mut_result {
- if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
- // We have a very specific type of error, where just borrowing this argument
- // might solve the problem. In cases like this, the important part is the
- // original type obligation, not the last one that failed, which is arbitrary.
- // Because of this, we modify the error to refer to the original obligation and
- // return early in the caller.
-
- let msg = format!("the trait bound `{}` is not satisfied", old_pred);
- if has_custom_message {
- err.note(&msg);
- } else {
- err.message =
- vec![(rustc_errors::DiagnosticMessage::Str(msg), Style::NoStyle)];
- }
- if snippet.starts_with('&') {
- // This is already a literal borrow and the obligation is failing
- // somewhere else in the obligation chain. Do not suggest non-sense.
- return false;
- }
- err.span_label(
- span,
- &format!(
- "expected an implementor of trait `{}`",
- old_pred.print_modifiers_and_trait_path(),
- ),
- );
- // This if is to prevent a special edge-case
- if matches!(
- span.ctxt().outer_expn_data().kind,
- ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop)
- ) {
- // We don't want a borrowing suggestion on the fields in structs,
- // ```
- // struct Foo {
- // the_foos: Vec<Foo>
- // }
- // ```
+ if imm_result || mut_result || ref_inner_ty_result.map_or(false, |(result, _)| result) {
+ if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
+ // We have a very specific type of error, where just borrowing this argument
+ // might solve the problem. In cases like this, the important part is the
+ // original type obligation, not the last one that failed, which is arbitrary.
+ // Because of this, we modify the error to refer to the original obligation and
+ // return early in the caller.
+
+ let msg = format!("the trait bound `{}` is not satisfied", old_pred);
+ if has_custom_message {
+ err.note(&msg);
+ } else {
+ err.message =
+ vec![(rustc_errors::DiagnosticMessage::Str(msg), Style::NoStyle)];
+ }
+ if snippet.starts_with('&') {
+ // This is already a literal borrow and the obligation is failing
+ // somewhere else in the obligation chain. Do not suggest non-sense.
+ return false;
+ }
+ err.span_label(
+ span,
+ &format!(
+ "expected an implementor of trait `{}`",
+ old_pred.print_modifiers_and_trait_path(),
+ ),
+ );
- if imm_result && mut_result {
- err.span_suggestions(
- span.shrink_to_lo(),
- "consider borrowing here",
- ["&".to_string(), "&mut ".to_string()].into_iter(),
- Applicability::MaybeIncorrect,
- );
- } else {
- err.span_suggestion_verbose(
- span.shrink_to_lo(),
- &format!(
- "consider{} borrowing here",
- if mut_result { " mutably" } else { "" }
- ),
- format!("&{}", if mut_result { "mut " } else { "" }),
- Applicability::MaybeIncorrect,
- );
- }
+ // This if is to prevent a special edge-case
+ if matches!(
+ span.ctxt().outer_expn_data().kind,
+ ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop)
+ ) {
+ // We don't want a borrowing suggestion on the fields in structs,
+ // ```
+ // struct Foo {
+ // the_foos: Vec<Foo>
+ // }
+ // ```
+
+ if imm_result && mut_result {
+ err.span_suggestions(
+ span.shrink_to_lo(),
+ "consider borrowing here",
+ ["&".to_string(), "&mut ".to_string()].into_iter(),
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ let is_mut = mut_result
+ || ref_inner_ty_result.map_or(false, |(_, mutabl)| {
+ matches!(mutabl, hir::Mutability::Mut)
+ });
+ err.span_suggestion_verbose(
+ span.shrink_to_lo(),
+ &format!(
+ "consider{} borrowing here",
+ if is_mut { " mutably" } else { "" }
+ ),
+ format!("&{}", if is_mut { "mut " } else { "" }),
+ Applicability::MaybeIncorrect,
+ );
}
- return true;
}
+ return true;
}
- return false;
- };
+ }
+ return false;
+ };
if let ObligationCauseCode::ImplDerivedObligation(cause) = &*code {
try_borrowing(cause.derived.parent_trait_pred, &[])
} else if let ObligationCauseCode::BindingObligation(_, _)
- | ObligationCauseCode::ItemObligation(_) = code
+ | ObligationCauseCode::ItemObligation(..) = code
{
try_borrowing(poly_trait_pred, &never_suggest_borrow)
} else {
diff --git a/src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.fixed b/src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.fixed
new file mode 100644
index 0000000000000..e9b8a9caa484a
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.fixed
@@ -0,0 +1,15 @@
+// run-rustfix
+#![allow(unused_variables)]
+
+fn foo(foo: &mut usize) {
+ todo!()
+}
+
+fn bar(bar: &usize) {
+ todo!()
+}
+
+fn main() {
+ foo(&mut Default::default()); //~ the trait bound `&mut usize: Default` is not satisfied
+ bar(&Default::default()); //~ the trait bound `&usize: Default` is not satisfied
+}
diff --git a/src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.rs b/src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.rs
new file mode 100644
index 0000000000000..5fae21cccef23
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.rs
@@ -0,0 +1,15 @@
+// run-rustfix
+#![allow(unused_variables)]
+
+fn foo(foo: &mut usize) {
+ todo!()
+}
+
+fn bar(bar: &usize) {
+ todo!()
+}
+
+fn main() {
+ foo(Default::default()); //~ the trait bound `&mut usize: Default` is not satisfied
+ bar(Default::default()); //~ the trait bound `&usize: Default` is not satisfied
+}
diff --git a/src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.stderr b/src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.stderr
new file mode 100644
index 0000000000000..b930d22a3915e
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.stderr
@@ -0,0 +1,25 @@
+error[E0277]: the trait bound `&mut usize: Default` is not satisfied
+ --> $DIR/suggest-adding-reference-to-trait-assoc-item.rs:13:9
+ |
+LL | foo(Default::default());
+ | ^^^^^^^^^^^^^^^^ expected an implementor of trait `Default`
+ |
+help: consider mutably borrowing here
+ |
+LL | foo(&mut Default::default());
+ | ++++
+
+error[E0277]: the trait bound `&usize: Default` is not satisfied
+ --> $DIR/suggest-adding-reference-to-trait-assoc-item.rs:14:9
+ |
+LL | bar(Default::default());
+ | ^^^^^^^^^^^^^^^^ expected an implementor of trait `Default`
+ |
+help: consider borrowing here
+ |
+LL | bar(&Default::default());
+ | +
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
From f47b61d19e1c17bac9fff34e9b304bad4f132ffe Mon Sep 17 00:00:00 2001
From: "Felix S. Klock II" <pnkfelix@pnkfx.org>
Date: Fri, 19 Aug 2022 16:40:26 -0400
Subject: [PATCH 17/19] elaborate how revisions work with FileCheck stuff in
src/test/codegen
---
src/test/codegen/README.md | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/src/test/codegen/README.md b/src/test/codegen/README.md
index 00de55eeab1f4..8f2daaafcc77a 100644
--- a/src/test/codegen/README.md
+++ b/src/test/codegen/README.md
@@ -1,2 +1,24 @@
The files here use the LLVM FileCheck framework, documented at
<https://llvm.org/docs/CommandGuide/FileCheck.html>.
+
+One extension worth noting is the use of revisions as custom prefixes for
+FileCheck. If your codegen test has different behavior based on the chosen
+target or different compiler flags that you want to exercise, you can use a
+revisions annotation, like so:
+
+```rust
+// revisions: aaa bbb
+// [bbb] compile-flags: --flags-for-bbb
+```
+
+After specifying those variations, you can write different expected, or
+explicitly *unexpected* output by using `<prefix>-SAME:` and `<prefix>-NOT:`,
+like so:
+
+```rust
+// CHECK: expected code
+// aaa-SAME: emitted-only-for-aaa
+// aaa-NOT: emitted-only-for-bbb
+// bbb-NOT: emitted-only-for-aaa
+// bbb-SAME: emitted-only-for-bbb
+```
From 973510749d955d72a8bf6f27775df3a5f8d652f2 Mon Sep 17 00:00:00 2001
From: Takayuki Maeda <takoyaki0316@gmail.com>
Date: Sat, 20 Aug 2022 15:54:39 +0900
Subject: [PATCH 18/19] remove unnecessary string searchings
remove unnecessary string searchings for checking if function arguments have `&` and `&mut`
---
.../src/traits/error_reporting/suggestions.rs | 31 ++++++++++---------
.../suggest-deferences/issue-39029.stderr | 10 +++---
.../suggest-deferences/issue-62530.stderr | 10 +++---
.../suggest-deferences/multiple-0.stderr | 10 +++---
4 files changed, 35 insertions(+), 26 deletions(-)
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 219413121d812..168834159e705 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -671,7 +671,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> bool {
// It only make sense when suggesting dereferences for arguments
- let ObligationCauseCode::FunctionArgumentObligation { .. } = obligation.cause.code() else {
+ let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = obligation.cause.code() else {
return false;
};
let param_env = obligation.param_env;
@@ -702,19 +702,22 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
Some(steps).filter(|_| self.predicate_may_hold(&obligation))
}) {
if steps > 0 {
- if let Ok(src) = self.tcx.sess.source_map().span_to_snippet(span) {
- // Don't care about `&mut` because `DerefMut` is used less
- // often and user will not expect autoderef happens.
- if src.starts_with('&') && !src.starts_with("&mut ") {
- let derefs = "*".repeat(steps);
- err.span_suggestion(
- span,
- "consider dereferencing here",
- format!("&{}{}", derefs, &src[1..]),
- Applicability::MachineApplicable,
- );
- return true;
- }
+ // Don't care about `&mut` because `DerefMut` is used less
+ // often and user will not expect autoderef happens.
+ if let Some(hir::Node::Expr(hir::Expr {
+ kind:
+ hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, expr),
+ ..
+ })) = self.tcx.hir().find(*arg_hir_id)
+ {
+ let derefs = "*".repeat(steps);
+ err.span_suggestion_verbose(
+ expr.span.shrink_to_lo(),
+ "consider dereferencing here",
+ derefs,
+ Applicability::MachineApplicable,
+ );
+ return true;
}
}
} else if real_trait_pred != trait_pred {
diff --git a/src/test/ui/traits/suggest-deferences/issue-39029.stderr b/src/test/ui/traits/suggest-deferences/issue-39029.stderr
index 5c324cd38a3ab..d256431c4cca8 100644
--- a/src/test/ui/traits/suggest-deferences/issue-39029.stderr
+++ b/src/test/ui/traits/suggest-deferences/issue-39029.stderr
@@ -2,10 +2,8 @@ error[E0277]: the trait bound `NoToSocketAddrs: ToSocketAddrs` is not satisfied
--> $DIR/issue-39029.rs:16:37
|
LL | let _errors = TcpListener::bind(&bad);
- | ----------------- ^^^^
- | | |
- | | the trait `ToSocketAddrs` is not implemented for `NoToSocketAddrs`
- | | help: consider dereferencing here: `&*bad`
+ | ----------------- ^^^^ the trait `ToSocketAddrs` is not implemented for `NoToSocketAddrs`
+ | |
| required by a bound introduced by this call
|
= note: required because of the requirements on the impl of `ToSocketAddrs` for `&NoToSocketAddrs`
@@ -14,6 +12,10 @@ note: required by a bound in `TcpListener::bind`
|
LL | pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> {
| ^^^^^^^^^^^^^ required by this bound in `TcpListener::bind`
+help: consider dereferencing here
+ |
+LL | let _errors = TcpListener::bind(&*bad);
+ | +
error: aborting due to previous error
diff --git a/src/test/ui/traits/suggest-deferences/issue-62530.stderr b/src/test/ui/traits/suggest-deferences/issue-62530.stderr
index d129328dae8ef..e47ae0b65af0e 100644
--- a/src/test/ui/traits/suggest-deferences/issue-62530.stderr
+++ b/src/test/ui/traits/suggest-deferences/issue-62530.stderr
@@ -2,10 +2,8 @@ error[E0277]: the trait bound `&String: SomeTrait` is not satisfied
--> $DIR/issue-62530.rs:13:26
|
LL | takes_type_parameter(&string); // Error
- | -------------------- ^^^^^^^
- | | |
- | | the trait `SomeTrait` is not implemented for `&String`
- | | help: consider dereferencing here: `&*string`
+ | -------------------- ^^^^^^^ the trait `SomeTrait` is not implemented for `&String`
+ | |
| required by a bound introduced by this call
|
note: required by a bound in `takes_type_parameter`
@@ -13,6 +11,10 @@ note: required by a bound in `takes_type_parameter`
|
LL | fn takes_type_parameter<T>(_x: T) where T: SomeTrait {}
| ^^^^^^^^^ required by this bound in `takes_type_parameter`
+help: consider dereferencing here
+ |
+LL | takes_type_parameter(&*string); // Error
+ | +
error: aborting due to previous error
diff --git a/src/test/ui/traits/suggest-deferences/multiple-0.stderr b/src/test/ui/traits/suggest-deferences/multiple-0.stderr
index efb3c7d123f70..6a4d4b8d5212f 100644
--- a/src/test/ui/traits/suggest-deferences/multiple-0.stderr
+++ b/src/test/ui/traits/suggest-deferences/multiple-0.stderr
@@ -2,10 +2,8 @@ error[E0277]: the trait bound `&Baz: Happy` is not satisfied
--> $DIR/multiple-0.rs:34:9
|
LL | foo(&baz);
- | --- ^^^^
- | | |
- | | the trait `Happy` is not implemented for `&Baz`
- | | help: consider dereferencing here: `&***baz`
+ | --- ^^^^ the trait `Happy` is not implemented for `&Baz`
+ | |
| required by a bound introduced by this call
|
note: required by a bound in `foo`
@@ -13,6 +11,10 @@ note: required by a bound in `foo`
|
LL | fn foo<T>(_: T) where T: Happy {}
| ^^^^^ required by this bound in `foo`
+help: consider dereferencing here
+ |
+LL | foo(&***baz);
+ | +++
error: aborting due to previous error
From a311b8a4c5ed3dfbf80a94c48768fda2e6785e52 Mon Sep 17 00:00:00 2001
From: Takayuki Maeda <takoyaki0316@gmail.com>
Date: Sat, 20 Aug 2022 19:35:17 +0900
Subject: [PATCH 19/19] use more descriptive names
---
.../src/traits/error_reporting/suggestions.rs | 188 +++++++++---------
1 file changed, 95 insertions(+), 93 deletions(-)
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 28b3d886b50b5..ffc4f8cf3d3b3 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -908,111 +908,113 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
let param_env = obligation.param_env;
// Try to apply the original trait binding obligation by borrowing.
- let mut try_borrowing = |old_pred: ty::PolyTraitPredicate<'tcx>,
- blacklist: &[DefId]|
- -> bool {
- if blacklist.contains(&old_pred.def_id()) {
- return false;
- }
- // We map bounds to `&T` and `&mut T`
- let trait_pred_and_imm_ref = old_pred.map_bound(|trait_pred| {
- (
- trait_pred,
- self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()),
- )
- });
- let trait_pred_and_mut_ref = old_pred.map_bound(|trait_pred| {
- (
- trait_pred,
- self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()),
- )
- });
+ let mut try_borrowing =
+ |old_pred: ty::PolyTraitPredicate<'tcx>, blacklist: &[DefId]| -> bool {
+ if blacklist.contains(&old_pred.def_id()) {
+ return false;
+ }
+ // We map bounds to `&T` and `&mut T`
+ let trait_pred_and_imm_ref = old_pred.map_bound(|trait_pred| {
+ (
+ trait_pred,
+ self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()),
+ )
+ });
+ let trait_pred_and_mut_ref = old_pred.map_bound(|trait_pred| {
+ (
+ trait_pred,
+ self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()),
+ )
+ });
- let mk_result = |trait_pred_and_new_ty| {
- let obligation =
- self.mk_trait_obligation_with_new_self_ty(param_env, trait_pred_and_new_ty);
- self.predicate_must_hold_modulo_regions(&obligation)
- };
- let imm_result = mk_result(trait_pred_and_imm_ref);
- let mut_result = mk_result(trait_pred_and_mut_ref);
+ let mk_result = |trait_pred_and_new_ty| {
+ let obligation =
+ self.mk_trait_obligation_with_new_self_ty(param_env, trait_pred_and_new_ty);
+ self.predicate_must_hold_modulo_regions(&obligation)
+ };
+ let imm_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_imm_ref);
+ let mut_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_mut_ref);
- let ref_inner_ty_result =
+ let (ref_inner_ty_satisfies_pred, ref_inner_ty_mut) =
if let ObligationCauseCode::ItemObligation(_) = obligation.cause.code()
&& let ty::Ref(_, ty, mutability) = old_pred.self_ty().skip_binder().kind()
{
- Some((mk_result(old_pred.map_bound(|trait_pred| (trait_pred, *ty))), mutability))
+ (
+ mk_result(old_pred.map_bound(|trait_pred| (trait_pred, *ty))),
+ matches!(mutability, hir::Mutability::Mut),
+ )
} else {
- None
+ (false, false)
};
- if imm_result || mut_result || ref_inner_ty_result.map_or(false, |(result, _)| result) {
- if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
- // We have a very specific type of error, where just borrowing this argument
- // might solve the problem. In cases like this, the important part is the
- // original type obligation, not the last one that failed, which is arbitrary.
- // Because of this, we modify the error to refer to the original obligation and
- // return early in the caller.
-
- let msg = format!("the trait bound `{}` is not satisfied", old_pred);
- if has_custom_message {
- err.note(&msg);
- } else {
- err.message =
- vec![(rustc_errors::DiagnosticMessage::Str(msg), Style::NoStyle)];
- }
- if snippet.starts_with('&') {
- // This is already a literal borrow and the obligation is failing
- // somewhere else in the obligation chain. Do not suggest non-sense.
- return false;
- }
- err.span_label(
- span,
- &format!(
- "expected an implementor of trait `{}`",
- old_pred.print_modifiers_and_trait_path(),
- ),
- );
-
- // This if is to prevent a special edge-case
- if matches!(
- span.ctxt().outer_expn_data().kind,
- ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop)
- ) {
- // We don't want a borrowing suggestion on the fields in structs,
- // ```
- // struct Foo {
- // the_foos: Vec<Foo>
- // }
- // ```
-
- if imm_result && mut_result {
- err.span_suggestions(
- span.shrink_to_lo(),
- "consider borrowing here",
- ["&".to_string(), "&mut ".to_string()].into_iter(),
- Applicability::MaybeIncorrect,
- );
+ if imm_ref_self_ty_satisfies_pred
+ || mut_ref_self_ty_satisfies_pred
+ || ref_inner_ty_satisfies_pred
+ {
+ if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
+ // We have a very specific type of error, where just borrowing this argument
+ // might solve the problem. In cases like this, the important part is the
+ // original type obligation, not the last one that failed, which is arbitrary.
+ // Because of this, we modify the error to refer to the original obligation and
+ // return early in the caller.
+
+ let msg = format!("the trait bound `{}` is not satisfied", old_pred);
+ if has_custom_message {
+ err.note(&msg);
} else {
- let is_mut = mut_result
- || ref_inner_ty_result.map_or(false, |(_, mutabl)| {
- matches!(mutabl, hir::Mutability::Mut)
- });
- err.span_suggestion_verbose(
- span.shrink_to_lo(),
- &format!(
- "consider{} borrowing here",
- if is_mut { " mutably" } else { "" }
- ),
- format!("&{}", if is_mut { "mut " } else { "" }),
- Applicability::MaybeIncorrect,
- );
+ err.message =
+ vec![(rustc_errors::DiagnosticMessage::Str(msg), Style::NoStyle)];
}
+ if snippet.starts_with('&') {
+ // This is already a literal borrow and the obligation is failing
+ // somewhere else in the obligation chain. Do not suggest non-sense.
+ return false;
+ }
+ err.span_label(
+ span,
+ &format!(
+ "expected an implementor of trait `{}`",
+ old_pred.print_modifiers_and_trait_path(),
+ ),
+ );
+
+ // This if is to prevent a special edge-case
+ if matches!(
+ span.ctxt().outer_expn_data().kind,
+ ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop)
+ ) {
+ // We don't want a borrowing suggestion on the fields in structs,
+ // ```
+ // struct Foo {
+ // the_foos: Vec<Foo>
+ // }
+ // ```
+
+ if imm_ref_self_ty_satisfies_pred && mut_ref_self_ty_satisfies_pred {
+ err.span_suggestions(
+ span.shrink_to_lo(),
+ "consider borrowing here",
+ ["&".to_string(), "&mut ".to_string()].into_iter(),
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_mut;
+ err.span_suggestion_verbose(
+ span.shrink_to_lo(),
+ &format!(
+ "consider{} borrowing here",
+ if is_mut { " mutably" } else { "" }
+ ),
+ format!("&{}", if is_mut { "mut " } else { "" }),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ return true;
}
- return true;
}
- }
- return false;
- };
+ return false;
+ };
if let ObligationCauseCode::ImplDerivedObligation(cause) = &*code {
try_borrowing(cause.derived.parent_trait_pred, &[])