Auto merge of #100810 - matthiaskrgr:rollup-xep778s, r=matthiaskrgr
Rollup of 9 pull requests Successful merges: - #97963 (net listen backlog set to negative on Linux.) - #99935 (Reenable disabled early syntax gates as future-incompatibility lints) - #100129 (add miri-test-libstd support to libstd) - #100500 (Ban references to `Self` in trait object substs for projection predicates too.) - #100636 (Revert "Revert "Allow dynamic linking for iOS/tvOS targets."") - #100718 ([rustdoc] Fix item info display) - #100769 (Suggest adding a reference to a trait assoc item) - #100777 (elaborate how revisions work with FileCheck stuff in src/test/codegen) - #100796 (Refactor: remove unnecessary string searchings) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
878aef79dc
51 changed files with 754 additions and 150 deletions
|
@ -2,10 +2,10 @@ use rustc_ast as ast;
|
||||||
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
|
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
|
||||||
use rustc_ast::{AssocConstraint, AssocConstraintKind, NodeId};
|
use rustc_ast::{AssocConstraint, AssocConstraintKind, NodeId};
|
||||||
use rustc_ast::{PatKind, RangeEnd, VariantData};
|
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::{AttributeGate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
|
||||||
use rustc_feature::{Features, GateIssue};
|
use rustc_session::parse::{feature_err, feature_warn};
|
||||||
use rustc_session::parse::{feature_err, feature_err_issue};
|
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_span::source_map::Spanned;
|
use rustc_span::source_map::Spanned;
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
|
@ -20,9 +20,7 @@ macro_rules! gate_feature_fn {
|
||||||
let has_feature: bool = has_feature(visitor.features);
|
let has_feature: bool = has_feature(visitor.features);
|
||||||
debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
|
debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
|
||||||
if !has_feature && !span.allows_unstable($name) {
|
if !has_feature && !span.allows_unstable($name) {
|
||||||
feature_err_issue(&visitor.sess.parse_sess, name, span, GateIssue::Language, explain)
|
feature_err(&visitor.sess.parse_sess, name, span, explain).help(help).emit();
|
||||||
.help(help)
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{
|
($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);
|
let has_feature: bool = has_feature(visitor.features);
|
||||||
debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
|
debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
|
||||||
if !has_feature && !span.allows_unstable($name) {
|
if !has_feature && !span.allows_unstable($name) {
|
||||||
feature_err_issue(&visitor.sess.parse_sess, name, span, GateIssue::Language, explain)
|
feature_err(&visitor.sess.parse_sess, name, span, explain).emit();
|
||||||
.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) => {
|
($visitor: expr, $feature: ident, $span: expr, $explain: expr) => {
|
||||||
gate_feature_fn!($visitor, |x: &Features| x.$feature, $span, sym::$feature, $explain)
|
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) {
|
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
|
// 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).
|
// ascription error, but the likely intention was to write a `let` statement. (#78907).
|
||||||
feature_err_issue(
|
feature_err(
|
||||||
&self.sess.parse_sess,
|
&self.sess.parse_sess,
|
||||||
sym::type_ascription,
|
sym::type_ascription,
|
||||||
lhs.span,
|
lhs.span,
|
||||||
GateIssue::Language,
|
|
||||||
"type ascription is experimental",
|
"type ascription is experimental",
|
||||||
).span_suggestion_verbose(
|
).span_suggestion_verbose(
|
||||||
lhs.span.shrink_to_lo(),
|
lhs.span.shrink_to_lo(),
|
||||||
|
@ -615,15 +626,22 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ast::ExprKind::Type(..) => {
|
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 {
|
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!(
|
gate_feature_post!(
|
||||||
&self,
|
&self,
|
||||||
type_ascription,
|
type_ascription,
|
||||||
e.span,
|
e.span,
|
||||||
"type ascription is experimental"
|
"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(_) => {
|
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,
|
// All uses of `gate_all!` below this point were added in #65742,
|
||||||
// and subsequently disabled (with the non-early gating readded).
|
// 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 {
|
macro_rules! gate_all {
|
||||||
($gate:ident, $msg:literal) => {
|
($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![]) {
|
for span in spans.get(&sym::$gate).unwrap_or(&vec![]) {
|
||||||
gate_feature_post!(&visitor, $gate, *span, $msg);
|
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!(try_blocks, "`try` blocks are unstable");
|
||||||
gate_all!(label_break_value, "labels on 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");
|
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);
|
visit::walk_crate(&mut visitor, krate);
|
||||||
}
|
}
|
||||||
|
|
|
@ -459,6 +459,7 @@ struct HandlerInner {
|
||||||
pub enum StashKey {
|
pub enum StashKey {
|
||||||
ItemNoType,
|
ItemNoType,
|
||||||
UnderscoreForArrayLengths,
|
UnderscoreForArrayLengths,
|
||||||
|
EarlySyntaxWarning,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_track_diagnostic(_: &Diagnostic) {}
|
fn default_track_diagnostic(_: &Diagnostic) {}
|
||||||
|
@ -626,19 +627,13 @@ impl Handler {
|
||||||
/// Stash a given diagnostic with the given `Span` and `StashKey` as the key for later stealing.
|
/// 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) {
|
pub fn stash_diagnostic(&self, span: Span, key: StashKey, diag: Diagnostic) {
|
||||||
let mut inner = self.inner.borrow_mut();
|
let mut inner = self.inner.borrow_mut();
|
||||||
// FIXME(Centril, #69537): Consider reintroducing panic on overwriting a stashed diagnostic
|
inner.stash((span, key), diag);
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Steal a previously stashed diagnostic with the given `Span` and `StashKey` as the key.
|
/// 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<'_, ()>> {
|
pub fn steal_diagnostic(&self, span: Span, key: StashKey) -> Option<DiagnosticBuilder<'_, ()>> {
|
||||||
self.inner
|
let mut inner = self.inner.borrow_mut();
|
||||||
.borrow_mut()
|
inner.steal((span, key)).map(|diag| DiagnosticBuilder::new_diagnostic(self, diag))
|
||||||
.stashed_diagnostics
|
|
||||||
.remove(&(span, key))
|
|
||||||
.map(|diag| DiagnosticBuilder::new_diagnostic(self, diag))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Emit all stashed diagnostics.
|
/// Emit all stashed diagnostics.
|
||||||
|
@ -1106,13 +1101,31 @@ impl HandlerInner {
|
||||||
|
|
||||||
/// Emit all stashed diagnostics.
|
/// Emit all stashed diagnostics.
|
||||||
fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> {
|
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 diags = self.stashed_diagnostics.drain(..).map(|x| x.1).collect::<Vec<_>>();
|
||||||
let mut reported = None;
|
let mut reported = None;
|
||||||
for mut diag in diags {
|
for mut diag in diags {
|
||||||
|
// Decrement the count tracking the stash; emitting will increment it.
|
||||||
if diag.is_error() {
|
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;
|
||||||
}
|
}
|
||||||
self.emit_diagnostic(&mut diag);
|
} 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let reported_this = self.emit_diagnostic(&mut diag);
|
||||||
|
reported = reported.or(reported_this);
|
||||||
}
|
}
|
||||||
reported
|
reported
|
||||||
}
|
}
|
||||||
|
@ -1302,9 +1315,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]
|
#[inline]
|
||||||
fn err_count(&self) -> usize {
|
fn err_count(&self) -> usize {
|
||||||
self.err_count + self.stashed_diagnostics.len()
|
self.err_count
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_errors(&self) -> bool {
|
fn has_errors(&self) -> bool {
|
||||||
|
|
|
@ -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! {
|
declare_lint_pass! {
|
||||||
/// Does nothing as a lint pass, but registers some `Lint`s
|
/// Does nothing as a lint pass, but registers some `Lint`s
|
||||||
/// that are used by other parts of the compiler.
|
/// that are used by other parts of the compiler.
|
||||||
|
@ -3280,6 +3330,7 @@ declare_lint_pass! {
|
||||||
POINTER_STRUCTURAL_MATCH,
|
POINTER_STRUCTURAL_MATCH,
|
||||||
NONTRIVIAL_STRUCTURAL_MATCH,
|
NONTRIVIAL_STRUCTURAL_MATCH,
|
||||||
SOFT_UNSTABLE,
|
SOFT_UNSTABLE,
|
||||||
|
UNSTABLE_SYNTAX_PRE_EXPANSION,
|
||||||
INLINE_NO_SANITIZE,
|
INLINE_NO_SANITIZE,
|
||||||
BAD_ASM_STYLE,
|
BAD_ASM_STYLE,
|
||||||
ASM_SUB_REGISTER,
|
ASM_SUB_REGISTER,
|
||||||
|
|
|
@ -2,15 +2,17 @@
|
||||||
//! It also serves as an input to the parser itself.
|
//! It also serves as an input to the parser itself.
|
||||||
|
|
||||||
use crate::config::CheckCfg;
|
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 crate::SessionDiagnostic;
|
||||||
use rustc_ast::node_id::NodeId;
|
use rustc_ast::node_id::NodeId;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
use rustc_data_structures::sync::{Lock, Lrc};
|
use rustc_data_structures::sync::{Lock, Lrc};
|
||||||
use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler};
|
use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler};
|
||||||
use rustc_errors::{
|
use rustc_errors::{
|
||||||
error_code, fallback_fluent_bundle, Applicability, Diagnostic, DiagnosticBuilder,
|
error_code, fallback_fluent_bundle, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId,
|
||||||
DiagnosticMessage, ErrorGuaranteed, MultiSpan,
|
DiagnosticMessage, ErrorGuaranteed, MultiSpan, StashKey,
|
||||||
};
|
};
|
||||||
use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures};
|
use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures};
|
||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
|
@ -101,11 +103,58 @@ pub fn feature_err_issue<'a>(
|
||||||
issue: GateIssue,
|
issue: GateIssue,
|
||||||
explain: &str,
|
explain: &str,
|
||||||
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
|
) -> 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));
|
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);
|
add_feature_diagnostics_for_issue(&mut err, sess, feature, issue);
|
||||||
err
|
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.
|
/// Adds the diagnostics for a feature to an existing error.
|
||||||
pub fn add_feature_diagnostics<'a>(err: &mut Diagnostic, sess: &'a ParseSess, feature: Symbol) {
|
pub fn add_feature_diagnostics<'a>(err: &mut Diagnostic, sess: &'a ParseSess, feature: Symbol) {
|
||||||
add_feature_diagnostics_for_issue(err, sess, feature, GateIssue::Language);
|
add_feature_diagnostics_for_issue(err, sess, feature, GateIssue::Language);
|
||||||
|
|
|
@ -65,7 +65,6 @@ pub fn opts(os: &'static str, arch: Arch) -> TargetOptions {
|
||||||
TargetOptions {
|
TargetOptions {
|
||||||
abi: target_abi(arch).into(),
|
abi: target_abi(arch).into(),
|
||||||
cpu: target_cpu(arch).into(),
|
cpu: target_cpu(arch).into(),
|
||||||
dynamic_linking: false,
|
|
||||||
link_env_remove: link_env_remove(arch),
|
link_env_remove: link_env_remove(arch),
|
||||||
has_thread_local: false,
|
has_thread_local: false,
|
||||||
..super::apple_base::opts(os, target_arch_name(arch), target_abi(arch))
|
..super::apple_base::opts(os, target_arch_name(arch), target_abi(arch))
|
||||||
|
|
|
@ -671,7 +671,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// It only make sense when suggesting dereferences for arguments
|
// 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;
|
return false;
|
||||||
};
|
};
|
||||||
let param_env = obligation.param_env;
|
let param_env = obligation.param_env;
|
||||||
|
@ -702,21 +702,24 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
Some(steps).filter(|_| self.predicate_may_hold(&obligation))
|
Some(steps).filter(|_| self.predicate_may_hold(&obligation))
|
||||||
}) {
|
}) {
|
||||||
if steps > 0 {
|
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
|
// Don't care about `&mut` because `DerefMut` is used less
|
||||||
// often and user will not expect autoderef happens.
|
// often and user will not expect autoderef happens.
|
||||||
if src.starts_with('&') && !src.starts_with("&mut ") {
|
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);
|
let derefs = "*".repeat(steps);
|
||||||
err.span_suggestion(
|
err.span_suggestion_verbose(
|
||||||
span,
|
expr.span.shrink_to_lo(),
|
||||||
"consider dereferencing here",
|
"consider dereferencing here",
|
||||||
format!("&{}{}", derefs, &src[1..]),
|
derefs,
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else if real_trait_pred != trait_pred {
|
} else if real_trait_pred != trait_pred {
|
||||||
// This branch addresses #87437.
|
// This branch addresses #87437.
|
||||||
|
|
||||||
|
@ -882,6 +885,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
obligation.cause.code()
|
obligation.cause.code()
|
||||||
{
|
{
|
||||||
&parent_code
|
&parent_code
|
||||||
|
} else if let ObligationCauseCode::ItemObligation(_) = obligation.cause.code() {
|
||||||
|
obligation.cause.code()
|
||||||
} else if let ExpnKind::Desugaring(DesugaringKind::ForLoop) =
|
} else if let ExpnKind::Desugaring(DesugaringKind::ForLoop) =
|
||||||
span.ctxt().outer_expn_data().kind
|
span.ctxt().outer_expn_data().kind
|
||||||
{
|
{
|
||||||
|
@ -930,10 +935,25 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
self.mk_trait_obligation_with_new_self_ty(param_env, trait_pred_and_new_ty);
|
self.mk_trait_obligation_with_new_self_ty(param_env, trait_pred_and_new_ty);
|
||||||
self.predicate_must_hold_modulo_regions(&obligation)
|
self.predicate_must_hold_modulo_regions(&obligation)
|
||||||
};
|
};
|
||||||
let imm_result = mk_result(trait_pred_and_imm_ref);
|
let imm_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_imm_ref);
|
||||||
let mut_result = mk_result(trait_pred_and_mut_ref);
|
let mut_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_mut_ref);
|
||||||
|
|
||||||
if imm_result || mut_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()
|
||||||
|
{
|
||||||
|
(
|
||||||
|
mk_result(old_pred.map_bound(|trait_pred| (trait_pred, *ty))),
|
||||||
|
matches!(mutability, hir::Mutability::Mut),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
(false, false)
|
||||||
|
};
|
||||||
|
|
||||||
|
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) {
|
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
|
// 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
|
// might solve the problem. In cases like this, the important part is the
|
||||||
|
@ -973,7 +993,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
// }
|
// }
|
||||||
// ```
|
// ```
|
||||||
|
|
||||||
if imm_result && mut_result {
|
if imm_ref_self_ty_satisfies_pred && mut_ref_self_ty_satisfies_pred {
|
||||||
err.span_suggestions(
|
err.span_suggestions(
|
||||||
span.shrink_to_lo(),
|
span.shrink_to_lo(),
|
||||||
"consider borrowing here",
|
"consider borrowing here",
|
||||||
|
@ -981,13 +1001,14 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_mut;
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
span.shrink_to_lo(),
|
span.shrink_to_lo(),
|
||||||
&format!(
|
&format!(
|
||||||
"consider{} borrowing here",
|
"consider{} borrowing here",
|
||||||
if mut_result { " mutably" } else { "" }
|
if is_mut { " mutably" } else { "" }
|
||||||
),
|
),
|
||||||
format!("&{}", if mut_result { "mut " } else { "" }),
|
format!("&{}", if is_mut { "mut " } else { "" }),
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1001,7 +1022,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
if let ObligationCauseCode::ImplDerivedObligation(cause) = &*code {
|
if let ObligationCauseCode::ImplDerivedObligation(cause) = &*code {
|
||||||
try_borrowing(cause.derived.parent_trait_pred, &[])
|
try_borrowing(cause.derived.parent_trait_pred, &[])
|
||||||
} else if let ObligationCauseCode::BindingObligation(_, _)
|
} else if let ObligationCauseCode::BindingObligation(_, _)
|
||||||
| ObligationCauseCode::ItemObligation(_) = code
|
| ObligationCauseCode::ItemObligation(..) = code
|
||||||
{
|
{
|
||||||
try_borrowing(poly_trait_pred, &never_suggest_borrow)
|
try_borrowing(poly_trait_pred, &never_suggest_borrow)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -35,7 +35,7 @@ use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECT
|
||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
use rustc_span::lev_distance::find_best_match_for_name;
|
use rustc_span::lev_distance::find_best_match_for_name;
|
||||||
use rustc_span::symbol::{kw, Ident, Symbol};
|
use rustc_span::symbol::{kw, Ident, Symbol};
|
||||||
use rustc_span::{Span, DUMMY_SP};
|
use rustc_span::Span;
|
||||||
use rustc_target::spec::abi;
|
use rustc_target::spec::abi;
|
||||||
use rustc_trait_selection::traits;
|
use rustc_trait_selection::traits;
|
||||||
use rustc_trait_selection::traits::astconv_object_safety_violations;
|
use rustc_trait_selection::traits::astconv_object_safety_violations;
|
||||||
|
@ -1453,21 +1453,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.skip(1) // Remove `Self` for `ExistentialPredicate`.
|
.skip(1) // Remove `Self` for `ExistentialPredicate`.
|
||||||
.map(|(index, arg)| {
|
.map(|(index, arg)| {
|
||||||
if let ty::GenericArgKind::Type(ty) = arg.unpack() {
|
if arg == dummy_self.into() {
|
||||||
debug!(?ty);
|
|
||||||
if ty == dummy_self {
|
|
||||||
let param = &generics.params[index];
|
let param = &generics.params[index];
|
||||||
missing_type_params.push(param.name);
|
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()) {
|
} else if arg.walk().any(|arg| arg == dummy_self.into()) {
|
||||||
references_self = true;
|
references_self = true;
|
||||||
tcx.ty_error().into()
|
return tcx.ty_error().into();
|
||||||
} else {
|
|
||||||
arg
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
arg
|
arg
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let substs = tcx.intern_substs(&substs[..]);
|
let substs = tcx.intern_substs(&substs[..]);
|
||||||
|
@ -1506,13 +1500,34 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
});
|
});
|
||||||
|
|
||||||
let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| {
|
let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| {
|
||||||
bound.map_bound(|b| {
|
bound.map_bound(|mut b| {
|
||||||
if b.projection_ty.self_ty() != dummy_self {
|
assert_eq!(b.projection_ty.self_ty(), dummy_self);
|
||||||
tcx.sess.delay_span_bug(
|
|
||||||
DUMMY_SP,
|
// Like for trait refs, verify that `dummy_self` did not leak inside default type
|
||||||
&format!("trait_ref_to_existential called on {:?} with non-dummy Self", b),
|
// parameters.
|
||||||
);
|
let references_self = b.projection_ty.substs.iter().skip(1).any(|arg| {
|
||||||
|
if arg.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 arg.walk().any(|arg| arg == dummy_self.into()) {
|
||||||
|
return tcx.ty_error().into();
|
||||||
|
}
|
||||||
|
arg
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
b.projection_ty.substs = tcx.intern_substs(&substs[..]);
|
||||||
|
}
|
||||||
|
|
||||||
ty::ExistentialProjection::erase_self_ty(tcx, b)
|
ty::ExistentialProjection::erase_self_ty(tcx, b)
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
|
@ -56,10 +56,6 @@
|
||||||
//! [`Rc`]: rc
|
//! [`Rc`]: rc
|
||||||
//! [`RefCell`]: core::cell
|
//! [`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)]
|
#![allow(unused_attributes)]
|
||||||
#![stable(feature = "alloc", since = "1.36.0")]
|
#![stable(feature = "alloc", since = "1.36.0")]
|
||||||
#![doc(
|
#![doc(
|
||||||
|
@ -77,6 +73,10 @@
|
||||||
))]
|
))]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![needs_allocator]
|
#![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:
|
// Lints:
|
||||||
#![deny(unsafe_op_in_unsafe_fn)]
|
#![deny(unsafe_op_in_unsafe_fn)]
|
||||||
|
|
|
@ -618,3 +618,22 @@ fn test_arc_cyclic_two_refs() {
|
||||||
assert_eq!(Arc::strong_count(&two_refs), 3);
|
assert_eq!(Arc::strong_count(&two_refs), 3);
|
||||||
assert_eq!(Arc::weak_count(&two_refs), 2);
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -268,10 +268,13 @@ fn test_lots_of_insertions() {
|
||||||
|
|
||||||
// Try this a few times to make sure we never screw up the hashmap's
|
// Try this a few times to make sure we never screw up the hashmap's
|
||||||
// internal state.
|
// internal state.
|
||||||
for _ in 0..10 {
|
let loops = if cfg!(miri) { 2 } else { 10 };
|
||||||
|
for _ in 0..loops {
|
||||||
assert!(m.is_empty());
|
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());
|
assert!(m.insert(i, i).is_none());
|
||||||
|
|
||||||
for j in 1..=i {
|
for j in 1..=i {
|
||||||
|
@ -279,42 +282,42 @@ fn test_lots_of_insertions() {
|
||||||
assert_eq!(r, Some(&j));
|
assert_eq!(r, Some(&j));
|
||||||
}
|
}
|
||||||
|
|
||||||
for j in i + 1..1001 {
|
for j in i + 1..count {
|
||||||
let r = m.get(&j);
|
let r = m.get(&j);
|
||||||
assert_eq!(r, None);
|
assert_eq!(r, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in 1001..2001 {
|
for i in count..(2 * count) {
|
||||||
assert!(!m.contains_key(&i));
|
assert!(!m.contains_key(&i));
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove forwards
|
// remove forwards
|
||||||
for i in 1..1001 {
|
for i in 1..count {
|
||||||
assert!(m.remove(&i).is_some());
|
assert!(m.remove(&i).is_some());
|
||||||
|
|
||||||
for j in 1..=i {
|
for j in 1..=i {
|
||||||
assert!(!m.contains_key(&j));
|
assert!(!m.contains_key(&j));
|
||||||
}
|
}
|
||||||
|
|
||||||
for j in i + 1..1001 {
|
for j in i + 1..count {
|
||||||
assert!(m.contains_key(&j));
|
assert!(m.contains_key(&j));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in 1..1001 {
|
for i in 1..count {
|
||||||
assert!(!m.contains_key(&i));
|
assert!(!m.contains_key(&i));
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in 1..1001 {
|
for i in 1..count {
|
||||||
assert!(m.insert(i, i).is_none());
|
assert!(m.insert(i, i).is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove backwards
|
// remove backwards
|
||||||
for i in (1..1001).rev() {
|
for i in (1..count).rev() {
|
||||||
assert!(m.remove(&i).is_some());
|
assert!(m.remove(&i).is_some());
|
||||||
|
|
||||||
for j in i..1001 {
|
for j in i..count {
|
||||||
assert!(!m.contains_key(&j));
|
assert!(!m.contains_key(&j));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -817,6 +820,7 @@ fn test_retain() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[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
|
#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
|
||||||
fn test_try_reserve() {
|
fn test_try_reserve() {
|
||||||
let mut empty_bytes: HashMap<u8, u8> = HashMap::new();
|
let mut empty_bytes: HashMap<u8, u8> = HashMap::new();
|
||||||
|
|
|
@ -94,7 +94,7 @@ fn read_to_end() {
|
||||||
assert_eq!(c.read_to_end(&mut v).unwrap(), 1);
|
assert_eq!(c.read_to_end(&mut v).unwrap(), 1);
|
||||||
assert_eq!(v, b"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 data = (0..cap).map(|i| (i / 3) as u8).collect::<Vec<_>>();
|
||||||
let mut v = Vec::new();
|
let mut v = Vec::new();
|
||||||
let (a, b) = data.split_at(data.len() / 2);
|
let (a, b) = data.split_at(data.len() / 2);
|
||||||
|
@ -309,6 +309,7 @@ fn chain_zero_length_read_is_not_eof() {
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
#[cfg_attr(target_os = "emscripten", ignore)]
|
#[cfg_attr(target_os = "emscripten", ignore)]
|
||||||
|
#[cfg_attr(miri, ignore)] // Miri isn't fast...
|
||||||
fn bench_read_to_end(b: &mut test::Bencher) {
|
fn bench_read_to_end(b: &mut test::Bencher) {
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut lr = repeat(1).take(10000000);
|
let mut lr = repeat(1).take(10000000);
|
||||||
|
|
|
@ -187,6 +187,7 @@
|
||||||
//! [rust-discord]: https://discord.gg/rust-lang
|
//! [rust-discord]: https://discord.gg/rust-lang
|
||||||
//! [array]: prim@array
|
//! [array]: prim@array
|
||||||
//! [slice]: prim@slice
|
//! [slice]: prim@slice
|
||||||
|
|
||||||
#![cfg_attr(not(feature = "restricted-std"), stable(feature = "rust1", since = "1.0.0"))]
|
#![cfg_attr(not(feature = "restricted-std"), stable(feature = "rust1", since = "1.0.0"))]
|
||||||
#![cfg_attr(feature = "restricted-std", unstable(feature = "restricted_std", issue = "none"))]
|
#![cfg_attr(feature = "restricted-std", unstable(feature = "restricted_std", issue = "none"))]
|
||||||
#![doc(
|
#![doc(
|
||||||
|
@ -201,25 +202,35 @@
|
||||||
no_global_oom_handling,
|
no_global_oom_handling,
|
||||||
not(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.
|
// Don't link to std. We are std.
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
// Tell the compiler to link to either panic_abort or panic_unwind
|
||||||
|
#![needs_panic_runtime]
|
||||||
|
//
|
||||||
|
// Lints:
|
||||||
#![warn(deprecated_in_future)]
|
#![warn(deprecated_in_future)]
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
#![warn(missing_debug_implementations)]
|
#![warn(missing_debug_implementations)]
|
||||||
#![allow(explicit_outlives_requirements)]
|
#![allow(explicit_outlives_requirements)]
|
||||||
#![allow(unused_lifetimes)]
|
#![allow(unused_lifetimes)]
|
||||||
// Tell the compiler to link to either panic_abort or panic_unwind
|
#![deny(rustc::existing_doc_keyword)]
|
||||||
#![needs_panic_runtime]
|
|
||||||
// Ensure that std can be linked against panic_abort despite compiled with `-C panic=unwind`
|
// Ensure that std can be linked against panic_abort despite compiled with `-C panic=unwind`
|
||||||
#![deny(ffi_unwind_calls)]
|
#![deny(ffi_unwind_calls)]
|
||||||
// std may use features in a platform-specific way
|
// std may use features in a platform-specific way
|
||||||
#![allow(unused_features)]
|
#![allow(unused_features)]
|
||||||
|
//
|
||||||
|
// Features:
|
||||||
#![cfg_attr(test, feature(internal_output_capture, print_internals, update_panic_count, rt))]
|
#![cfg_attr(test, feature(internal_output_capture, print_internals, update_panic_count, rt))]
|
||||||
#![cfg_attr(
|
#![cfg_attr(
|
||||||
all(target_vendor = "fortanix", target_env = "sgx"),
|
all(target_vendor = "fortanix", target_env = "sgx"),
|
||||||
feature(slice_index_methods, coerce_unsized, sgx_platform)
|
feature(slice_index_methods, coerce_unsized, sgx_platform)
|
||||||
)]
|
)]
|
||||||
#![deny(rustc::existing_doc_keyword)]
|
|
||||||
//
|
//
|
||||||
// Language features:
|
// Language features:
|
||||||
#![feature(alloc_error_handler)]
|
#![feature(alloc_error_handler)]
|
||||||
|
|
|
@ -73,9 +73,13 @@ impl UnixListener {
|
||||||
unsafe {
|
unsafe {
|
||||||
let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
|
let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
|
||||||
let (addr, len) = sockaddr_un(path.as_ref())?;
|
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::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))
|
Ok(UnixListener(inner))
|
||||||
}
|
}
|
||||||
|
@ -109,12 +113,16 @@ impl UnixListener {
|
||||||
pub fn bind_addr(socket_addr: &SocketAddr) -> io::Result<UnixListener> {
|
pub fn bind_addr(socket_addr: &SocketAddr) -> io::Result<UnixListener> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
|
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(
|
cvt(libc::bind(
|
||||||
inner.as_raw_fd(),
|
inner.as_raw_fd(),
|
||||||
&socket_addr.addr as *const _ as *const _,
|
&socket_addr.addr as *const _ as *const _,
|
||||||
socket_addr.len as _,
|
socket_addr.len as _,
|
||||||
))?;
|
))?;
|
||||||
cvt(libc::listen(inner.as_raw_fd(), 128))?;
|
cvt(libc::listen(inner.as_raw_fd(), backlog))?;
|
||||||
Ok(UnixListener(inner))
|
Ok(UnixListener(inner))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1768,6 +1768,7 @@ fn test_windows_absolute() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
#[cfg_attr(miri, ignore)] // Miri isn't fast...
|
||||||
fn bench_path_cmp_fast_path_buf_sort(b: &mut test::Bencher) {
|
fn bench_path_cmp_fast_path_buf_sort(b: &mut test::Bencher) {
|
||||||
let prefix = "my/home";
|
let prefix = "my/home";
|
||||||
let mut paths: Vec<_> =
|
let mut paths: Vec<_> =
|
||||||
|
@ -1781,6 +1782,7 @@ fn bench_path_cmp_fast_path_buf_sort(b: &mut test::Bencher) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
#[cfg_attr(miri, ignore)] // Miri isn't fast...
|
||||||
fn bench_path_cmp_fast_path_long(b: &mut test::Bencher) {
|
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 prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/";
|
||||||
let paths: Vec<_> =
|
let paths: Vec<_> =
|
||||||
|
@ -1799,6 +1801,7 @@ fn bench_path_cmp_fast_path_long(b: &mut test::Bencher) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
#[cfg_attr(miri, ignore)] // Miri isn't fast...
|
||||||
fn bench_path_cmp_fast_path_short(b: &mut test::Bencher) {
|
fn bench_path_cmp_fast_path_short(b: &mut test::Bencher) {
|
||||||
let prefix = "my/home";
|
let prefix = "my/home";
|
||||||
let paths: Vec<_> =
|
let paths: Vec<_> =
|
||||||
|
@ -1817,6 +1820,7 @@ fn bench_path_cmp_fast_path_short(b: &mut test::Bencher) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
#[cfg_attr(miri, ignore)] // Miri isn't fast...
|
||||||
fn bench_path_hashset(b: &mut test::Bencher) {
|
fn bench_path_hashset(b: &mut test::Bencher) {
|
||||||
let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/";
|
let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/";
|
||||||
let paths: Vec<_> =
|
let paths: Vec<_> =
|
||||||
|
@ -1835,6 +1839,7 @@ fn bench_path_hashset(b: &mut test::Bencher) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
#[cfg_attr(miri, ignore)] // Miri isn't fast...
|
||||||
fn bench_path_hashset_miss(b: &mut test::Bencher) {
|
fn bench_path_hashset_miss(b: &mut test::Bencher) {
|
||||||
let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/";
|
let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/";
|
||||||
let paths: Vec<_> =
|
let paths: Vec<_> =
|
||||||
|
|
|
@ -13,7 +13,7 @@ fn test_full() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test() {
|
fn test() {
|
||||||
let nthreads = 8;
|
let nthreads = 8;
|
||||||
let nmsgs = 1000;
|
let nmsgs = if cfg!(miri) { 100 } else { 1000 };
|
||||||
let q = Queue::new();
|
let q = Queue::new();
|
||||||
match q.pop() {
|
match q.pop() {
|
||||||
Empty => {}
|
Empty => {}
|
||||||
|
|
|
@ -77,12 +77,13 @@ fn stress() {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn stress_bound(bound: usize) {
|
unsafe fn stress_bound(bound: usize) {
|
||||||
|
let count = if cfg!(miri) { 1000 } else { 100000 };
|
||||||
let q = Arc::new(Queue::with_additions(bound, (), ()));
|
let q = Arc::new(Queue::with_additions(bound, (), ()));
|
||||||
|
|
||||||
let (tx, rx) = channel();
|
let (tx, rx) = channel();
|
||||||
let q2 = q.clone();
|
let q2 = q.clone();
|
||||||
let _t = thread::spawn(move || {
|
let _t = thread::spawn(move || {
|
||||||
for _ in 0..100000 {
|
for _ in 0..count {
|
||||||
loop {
|
loop {
|
||||||
match q2.pop() {
|
match q2.pop() {
|
||||||
Some(1) => break,
|
Some(1) => break,
|
||||||
|
@ -93,7 +94,7 @@ fn stress() {
|
||||||
}
|
}
|
||||||
tx.send(()).unwrap();
|
tx.send(()).unwrap();
|
||||||
});
|
});
|
||||||
for _ in 0..100000 {
|
for _ in 0..count {
|
||||||
q.push(1);
|
q.push(1);
|
||||||
}
|
}
|
||||||
rx.recv().unwrap();
|
rx.recv().unwrap();
|
||||||
|
|
|
@ -113,23 +113,25 @@ fn chan_gone_concurrent() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn stress() {
|
fn stress() {
|
||||||
|
let count = if cfg!(miri) { 100 } else { 10000 };
|
||||||
let (tx, rx) = sync_channel::<i32>(0);
|
let (tx, rx) = sync_channel::<i32>(0);
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
for _ in 0..10000 {
|
for _ in 0..count {
|
||||||
tx.send(1).unwrap();
|
tx.send(1).unwrap();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
for _ in 0..10000 {
|
for _ in 0..count {
|
||||||
assert_eq!(rx.recv().unwrap(), 1);
|
assert_eq!(rx.recv().unwrap(), 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn stress_recv_timeout_two_threads() {
|
fn stress_recv_timeout_two_threads() {
|
||||||
|
let count = if cfg!(miri) { 100 } else { 10000 };
|
||||||
let (tx, rx) = sync_channel::<i32>(0);
|
let (tx, rx) = sync_channel::<i32>(0);
|
||||||
|
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
for _ in 0..10000 {
|
for _ in 0..count {
|
||||||
tx.send(1).unwrap();
|
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]
|
#[test]
|
||||||
fn stress_recv_timeout_shared() {
|
fn stress_recv_timeout_shared() {
|
||||||
const AMT: u32 = 1000;
|
const AMT: u32 = if cfg!(miri) { 100 } else { 1000 };
|
||||||
const NTHREADS: u32 = 8;
|
const NTHREADS: u32 = 8;
|
||||||
let (tx, rx) = sync_channel::<i32>(0);
|
let (tx, rx) = sync_channel::<i32>(0);
|
||||||
let (dtx, drx) = sync_channel::<()>(0);
|
let (dtx, drx) = sync_channel::<()>(0);
|
||||||
|
@ -191,7 +193,7 @@ fn stress_recv_timeout_shared() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn stress_shared() {
|
fn stress_shared() {
|
||||||
const AMT: u32 = 1000;
|
const AMT: u32 = if cfg!(miri) { 100 } else { 1000 };
|
||||||
const NTHREADS: u32 = 8;
|
const NTHREADS: u32 = 8;
|
||||||
let (tx, rx) = sync_channel::<i32>(0);
|
let (tx, rx) = sync_channel::<i32>(0);
|
||||||
let (dtx, drx) = sync_channel::<()>(0);
|
let (dtx, drx) = sync_channel::<()>(0);
|
||||||
|
@ -438,12 +440,13 @@ fn stream_send_recv_stress() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn recv_a_lot() {
|
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
|
// Regression test that we don't run out of stack in scheduler context
|
||||||
let (tx, rx) = sync_channel(10000);
|
let (tx, rx) = sync_channel(count);
|
||||||
for _ in 0..10000 {
|
for _ in 0..count {
|
||||||
tx.send(()).unwrap();
|
tx.send(()).unwrap();
|
||||||
}
|
}
|
||||||
for _ in 0..10000 {
|
for _ in 0..count {
|
||||||
rx.recv().unwrap();
|
rx.recv().unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,13 +120,14 @@ fn chan_gone_concurrent() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn stress() {
|
fn stress() {
|
||||||
|
let count = if cfg!(miri) { 100 } else { 10000 };
|
||||||
let (tx, rx) = channel::<i32>();
|
let (tx, rx) = channel::<i32>();
|
||||||
let t = thread::spawn(move || {
|
let t = thread::spawn(move || {
|
||||||
for _ in 0..10000 {
|
for _ in 0..count {
|
||||||
tx.send(1).unwrap();
|
tx.send(1).unwrap();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
for _ in 0..10000 {
|
for _ in 0..count {
|
||||||
assert_eq!(rx.recv().unwrap(), 1);
|
assert_eq!(rx.recv().unwrap(), 1);
|
||||||
}
|
}
|
||||||
t.join().ok().expect("thread panicked");
|
t.join().ok().expect("thread panicked");
|
||||||
|
@ -134,7 +135,7 @@ fn stress() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn stress_shared() {
|
fn stress_shared() {
|
||||||
const AMT: u32 = 10000;
|
const AMT: u32 = if cfg!(miri) { 100 } else { 10000 };
|
||||||
const NTHREADS: u32 = 8;
|
const NTHREADS: u32 = 8;
|
||||||
let (tx, rx) = channel::<i32>();
|
let (tx, rx) = channel::<i32>();
|
||||||
|
|
||||||
|
@ -504,12 +505,13 @@ fn very_long_recv_timeout_wont_panic() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn recv_a_lot() {
|
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
|
// Regression test that we don't run out of stack in scheduler context
|
||||||
let (tx, rx) = channel();
|
let (tx, rx) = channel();
|
||||||
for _ in 0..10000 {
|
for _ in 0..count {
|
||||||
tx.send(()).unwrap();
|
tx.send(()).unwrap();
|
||||||
}
|
}
|
||||||
for _ in 0..10000 {
|
for _ in 0..count {
|
||||||
rx.recv().unwrap();
|
rx.recv().unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ fn smoke() {
|
||||||
#[test]
|
#[test]
|
||||||
fn frob() {
|
fn frob() {
|
||||||
const N: u32 = 10;
|
const N: u32 = 10;
|
||||||
const M: usize = 1000;
|
const M: usize = if cfg!(miri) { 100 } else { 1000 };
|
||||||
|
|
||||||
let r = Arc::new(RwLock::new(()));
|
let r = Arc::new(RwLock::new(()));
|
||||||
|
|
||||||
|
|
|
@ -829,6 +829,7 @@ impl DirEntry {
|
||||||
target_os = "fuchsia",
|
target_os = "fuchsia",
|
||||||
target_os = "redox"
|
target_os = "redox"
|
||||||
)))]
|
)))]
|
||||||
|
#[cfg_attr(miri, allow(unused))]
|
||||||
fn name_cstr(&self) -> &CStr {
|
fn name_cstr(&self) -> &CStr {
|
||||||
unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) }
|
unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) }
|
||||||
}
|
}
|
||||||
|
@ -840,6 +841,7 @@ impl DirEntry {
|
||||||
target_os = "fuchsia",
|
target_os = "fuchsia",
|
||||||
target_os = "redox"
|
target_os = "redox"
|
||||||
))]
|
))]
|
||||||
|
#[cfg_attr(miri, allow(unused))]
|
||||||
fn name_cstr(&self) -> &CStr {
|
fn name_cstr(&self) -> &CStr {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
|
@ -329,3 +329,22 @@ fn test_scoped_threads_nll() {
|
||||||
let x = 42_u8;
|
let x = 42_u8;
|
||||||
foo(&x);
|
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));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -31,7 +31,8 @@ fn instant_monotonic_concurrent() -> crate::thread::Result<()> {
|
||||||
.map(|_| {
|
.map(|_| {
|
||||||
crate::thread::spawn(|| {
|
crate::thread::spawn(|| {
|
||||||
let mut old = Instant::now();
|
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();
|
let new = Instant::now();
|
||||||
assert!(new >= old);
|
assert!(new >= old);
|
||||||
old = new;
|
old = new;
|
||||||
|
|
|
@ -569,7 +569,10 @@ fn short_item_info(
|
||||||
message.push_str(&format!(": {}", html.into_string()));
|
message.push_str(&format!(": {}", html.into_string()));
|
||||||
}
|
}
|
||||||
extra_info.push(format!(
|
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,
|
message,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -582,8 +585,9 @@ fn short_item_info(
|
||||||
.filter(|stab| stab.feature != sym::rustc_private)
|
.filter(|stab| stab.feature != sym::rustc_private)
|
||||||
.map(|stab| (stab.level, stab.feature))
|
.map(|stab| (stab.level, stab.feature))
|
||||||
{
|
{
|
||||||
let mut message =
|
let mut message = "<span class=\"emoji\">🔬</span>\
|
||||||
"<span class=\"emoji\">🔬</span> This is a nightly-only experimental API.".to_owned();
|
<span>This is a nightly-only experimental API."
|
||||||
|
.to_owned();
|
||||||
|
|
||||||
let mut feature = format!("<code>{}</code>", Escape(feature.as_str()));
|
let mut feature = format!("<code>{}</code>", Escape(feature.as_str()));
|
||||||
if let (Some(url), Some(issue)) = (&cx.shared.issue_tracker_base_url, issue) {
|
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));
|
extra_info.push(format!("<div class=\"stab unstable\">{}</div>", message));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1164,6 +1164,7 @@ so that we can apply CSS-filters to change the arrow color in themes */
|
||||||
|
|
||||||
.stab .emoji {
|
.stab .emoji {
|
||||||
font-size: 1.25rem;
|
font-size: 1.25rem;
|
||||||
|
margin-right: 0.3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Black one-pixel outline around emoji shapes */
|
/* Black one-pixel outline around emoji shapes */
|
||||||
|
|
|
@ -1,2 +1,24 @@
|
||||||
The files here use the LLVM FileCheck framework, documented at
|
The files here use the LLVM FileCheck framework, documented at
|
||||||
<https://llvm.org/docs/CommandGuide/FileCheck.html>.
|
<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
|
||||||
|
```
|
||||||
|
|
|
@ -8,20 +8,24 @@
|
||||||
// 'Experimental'
|
// 'Experimental'
|
||||||
// @matches issue_32374/index.html '//*[@class="item-right docblock-short"]/text()' 'Docs'
|
// @matches issue_32374/index.html '//*[@class="item-right docblock-short"]/text()' 'Docs'
|
||||||
|
|
||||||
// @has issue_32374/struct.T.html '//*[@class="stab deprecated"]' \
|
// @has issue_32374/struct.T.html '//*[@class="stab deprecated"]/span' '👎'
|
||||||
// '👎 Deprecated since 1.0.0: text'
|
// @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>'
|
// @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"]' \
|
// @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
|
/// Docs
|
||||||
#[deprecated(since = "1.0.0", note = "text")]
|
#[deprecated(since = "1.0.0", note = "text")]
|
||||||
#[unstable(feature = "test", issue = "32374")]
|
#[unstable(feature = "test", issue = "32374")]
|
||||||
pub struct T;
|
pub struct T;
|
||||||
|
|
||||||
|
// @has issue_32374/struct.U.html '//*[@class="stab deprecated"]' '👎'
|
||||||
// @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"]' \
|
// @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")]
|
#[deprecated(since = "1.0.0", note = "deprecated")]
|
||||||
#[unstable(feature = "test", issue = "32374", reason = "unstable")]
|
#[unstable(feature = "test", issue = "32374", reason = "unstable")]
|
||||||
pub struct U;
|
pub struct U;
|
||||||
|
|
30
src/test/ui/feature-gates/soft-syntax-gates-with-errors.rs
Normal file
30
src/test/ui/feature-gates/soft-syntax-gates-with-errors.rs
Normal file
|
@ -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() {}
|
|
@ -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`.
|
|
@ -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() {}
|
|
@ -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
|
||||||
|
|
|
@ -3,11 +3,18 @@
|
||||||
// compile-flags: --test
|
// compile-flags: --test
|
||||||
|
|
||||||
#![feature(async_closure)]
|
#![feature(async_closure)]
|
||||||
|
#![feature(box_patterns)]
|
||||||
|
#![feature(box_syntax)]
|
||||||
#![feature(const_trait_impl)]
|
#![feature(const_trait_impl)]
|
||||||
|
#![feature(decl_macro)]
|
||||||
#![feature(generators)]
|
#![feature(generators)]
|
||||||
#![feature(half_open_range_patterns)]
|
#![feature(half_open_range_patterns)]
|
||||||
|
#![feature(label_break_value)]
|
||||||
#![feature(more_qualified_paths)]
|
#![feature(more_qualified_paths)]
|
||||||
#![feature(raw_ref_op)]
|
#![feature(raw_ref_op)]
|
||||||
|
#![feature(trait_alias)]
|
||||||
|
#![feature(try_blocks)]
|
||||||
|
#![feature(type_ascription)]
|
||||||
#![deny(unused_macros)]
|
#![deny(unused_macros)]
|
||||||
|
|
||||||
macro_rules! stringify_block {
|
macro_rules! stringify_block {
|
||||||
|
|
|
@ -7,7 +7,7 @@ fn main() {}
|
||||||
|
|
||||||
// Test the `pat` macro fragment parser:
|
// Test the `pat` macro fragment parser:
|
||||||
macro_rules! accept_pat {
|
macro_rules! accept_pat {
|
||||||
($p:pat) => {}
|
($p:pat) => {};
|
||||||
}
|
}
|
||||||
|
|
||||||
accept_pat!((p | q));
|
accept_pat!((p | q));
|
||||||
|
@ -21,28 +21,28 @@ accept_pat!([p | q]);
|
||||||
#[cfg(FALSE)]
|
#[cfg(FALSE)]
|
||||||
fn or_patterns() {
|
fn or_patterns() {
|
||||||
// Top level of `let`:
|
// Top level of `let`:
|
||||||
let (| A | B);
|
let (A | B);
|
||||||
let (A | B);
|
let (A | B);
|
||||||
let (A | B): u8;
|
let (A | B): u8;
|
||||||
let (A | B) = 0;
|
let (A | B) = 0;
|
||||||
let (A | B): u8 = 0;
|
let (A | B): u8 = 0;
|
||||||
|
|
||||||
// Top level of `for`:
|
// Top level of `for`:
|
||||||
for | A | B in 0 {}
|
for A | B in 0 {}
|
||||||
for A | B in 0 {}
|
for A | B in 0 {}
|
||||||
|
|
||||||
// Top level of `while`:
|
// Top level of `while`:
|
||||||
while let | A | B = 0 {}
|
while let A | B = 0 {}
|
||||||
while let A | B = 0 {}
|
while let A | B = 0 {}
|
||||||
|
|
||||||
// Top level of `if`:
|
// Top level of `if`:
|
||||||
if let | A | B = 0 {}
|
if let A | B = 0 {}
|
||||||
if let A | B = 0 {}
|
if let A | B = 0 {}
|
||||||
|
|
||||||
// Top level of `match` arms:
|
// Top level of `match` arms:
|
||||||
match 0 {
|
match 0 {
|
||||||
| A | B => {},
|
A | B => {}
|
||||||
A | B => {},
|
A | B => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Functions:
|
// Functions:
|
||||||
|
@ -68,6 +68,8 @@ fn or_patterns() {
|
||||||
|
|
||||||
// These bind as `(prefix p) | q` as opposed to `prefix (p | q)`:
|
// 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.
|
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 (&0 | 1);
|
||||||
let (&mut 0 | 1);
|
let (&mut 0 | 1);
|
||||||
let (x @ 0 | 1);
|
let (x @ 0 | 1);
|
||||||
|
|
13
src/test/ui/or-patterns/or-patterns-syntactic-pass.stderr
Normal file
13
src/test/ui/or-patterns/or-patterns-syntactic-pass.stderr
Normal file
|
@ -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
|
||||||
|
|
|
@ -3,7 +3,11 @@
|
||||||
#[cfg(FALSE)]
|
#[cfg(FALSE)]
|
||||||
fn syntax() {
|
fn syntax() {
|
||||||
foo::<T = u8, T: Ord, String>();
|
foo::<T = u8, T: Ord, String>();
|
||||||
|
//~^ WARN associated type bounds are unstable
|
||||||
|
//~| WARN unstable syntax
|
||||||
foo::<T = u8, 'a, T: Ord>();
|
foo::<T = u8, 'a, T: Ord>();
|
||||||
|
//~^ WARN associated type bounds are unstable
|
||||||
|
//~| WARN unstable syntax
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -19,6 +19,8 @@ fn rest_patterns() {
|
||||||
|
|
||||||
// Box patterns:
|
// Box patterns:
|
||||||
let box ..;
|
let box ..;
|
||||||
|
//~^ WARN box pattern syntax is experimental
|
||||||
|
//~| WARN unstable syntax
|
||||||
|
|
||||||
// In or-patterns:
|
// In or-patterns:
|
||||||
match x {
|
match x {
|
||||||
|
@ -57,7 +59,7 @@ fn rest_patterns() {
|
||||||
.. |
|
.. |
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
box ..,
|
box .., //~ WARN box pattern syntax is experimental
|
||||||
&(..),
|
&(..),
|
||||||
&mut ..,
|
&mut ..,
|
||||||
x @ ..
|
x @ ..
|
||||||
|
@ -67,4 +69,5 @@ fn rest_patterns() {
|
||||||
ref mut x @ ..
|
ref mut x @ ..
|
||||||
=> {}
|
=> {}
|
||||||
}
|
}
|
||||||
|
//~| WARN unstable syntax
|
||||||
}
|
}
|
||||||
|
|
24
src/test/ui/pattern/rest-pat-syntactic.stderr
Normal file
24
src/test/ui/pattern/rest-pat-syntactic.stderr
Normal file
|
@ -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
|
||||||
|
|
4
src/test/ui/suggestions/many-type-ascription.rs
Normal file
4
src/test/ui/suggestions/many-type-ascription.rs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
fn main() {
|
||||||
|
let _ = 0: i32; //~ ERROR: type ascription is experimental
|
||||||
|
let _ = 0: i32; // (error only emitted once)
|
||||||
|
}
|
12
src/test/ui/suggestions/many-type-ascription.stderr
Normal file
12
src/test/ui/suggestions/many-type-ascription.stderr
Normal file
|
@ -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`.
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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`.
|
|
@ -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)
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
12
src/test/ui/traits/alias/self-in-const-generics.rs
Normal file
12
src/test/ui/traits/alias/self-in-const-generics.rs
Normal file
|
@ -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() {}
|
11
src/test/ui/traits/alias/self-in-const-generics.stderr
Normal file
11
src/test/ui/traits/alias/self-in-const-generics.stderr
Normal file
|
@ -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`.
|
|
@ -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)]
|
#![feature(trait_alias)]
|
||||||
|
|
||||||
pub trait SelfInput = Fn(&mut Self);
|
pub trait SelfInput = Fn(&mut Self);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0038]: the trait alias `SelfInput` cannot be made into an object
|
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) {}
|
LL | pub fn f(_f: &dyn SelfInput) {}
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
|
@ -2,10 +2,8 @@ error[E0277]: the trait bound `NoToSocketAddrs: ToSocketAddrs` is not satisfied
|
||||||
--> $DIR/issue-39029.rs:16:37
|
--> $DIR/issue-39029.rs:16:37
|
||||||
|
|
|
|
||||||
LL | let _errors = TcpListener::bind(&bad);
|
LL | let _errors = TcpListener::bind(&bad);
|
||||||
| ----------------- ^^^^
|
| ----------------- ^^^^ the trait `ToSocketAddrs` is not implemented for `NoToSocketAddrs`
|
||||||
| | |
|
| |
|
||||||
| | the trait `ToSocketAddrs` is not implemented for `NoToSocketAddrs`
|
|
||||||
| | help: consider dereferencing here: `&*bad`
|
|
||||||
| required by a bound introduced by this call
|
| required by a bound introduced by this call
|
||||||
|
|
|
|
||||||
= note: required for `&NoToSocketAddrs` to implement `ToSocketAddrs`
|
= note: required for `&NoToSocketAddrs` to implement `ToSocketAddrs`
|
||||||
|
@ -14,6 +12,10 @@ note: required by a bound in `TcpListener::bind`
|
||||||
|
|
|
|
||||||
LL | pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> {
|
LL | pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> {
|
||||||
| ^^^^^^^^^^^^^ required by this bound in `TcpListener::bind`
|
| ^^^^^^^^^^^^^ required by this bound in `TcpListener::bind`
|
||||||
|
help: consider dereferencing here
|
||||||
|
|
|
||||||
|
LL | let _errors = TcpListener::bind(&*bad);
|
||||||
|
| +
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,8 @@ error[E0277]: the trait bound `&String: SomeTrait` is not satisfied
|
||||||
--> $DIR/issue-62530.rs:13:26
|
--> $DIR/issue-62530.rs:13:26
|
||||||
|
|
|
|
||||||
LL | takes_type_parameter(&string); // Error
|
LL | takes_type_parameter(&string); // Error
|
||||||
| -------------------- ^^^^^^^
|
| -------------------- ^^^^^^^ the trait `SomeTrait` is not implemented for `&String`
|
||||||
| | |
|
| |
|
||||||
| | the trait `SomeTrait` is not implemented for `&String`
|
|
||||||
| | help: consider dereferencing here: `&*string`
|
|
||||||
| required by a bound introduced by this call
|
| required by a bound introduced by this call
|
||||||
|
|
|
|
||||||
note: required by a bound in `takes_type_parameter`
|
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 {}
|
LL | fn takes_type_parameter<T>(_x: T) where T: SomeTrait {}
|
||||||
| ^^^^^^^^^ required by this bound in `takes_type_parameter`
|
| ^^^^^^^^^ required by this bound in `takes_type_parameter`
|
||||||
|
help: consider dereferencing here
|
||||||
|
|
|
||||||
|
LL | takes_type_parameter(&*string); // Error
|
||||||
|
| +
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,8 @@ error[E0277]: the trait bound `&Baz: Happy` is not satisfied
|
||||||
--> $DIR/multiple-0.rs:34:9
|
--> $DIR/multiple-0.rs:34:9
|
||||||
|
|
|
|
||||||
LL | foo(&baz);
|
LL | foo(&baz);
|
||||||
| --- ^^^^
|
| --- ^^^^ the trait `Happy` is not implemented for `&Baz`
|
||||||
| | |
|
| |
|
||||||
| | the trait `Happy` is not implemented for `&Baz`
|
|
||||||
| | help: consider dereferencing here: `&***baz`
|
|
||||||
| required by a bound introduced by this call
|
| required by a bound introduced by this call
|
||||||
|
|
|
|
||||||
note: required by a bound in `foo`
|
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 {}
|
LL | fn foo<T>(_: T) where T: Happy {}
|
||||||
| ^^^^^ required by this bound in `foo`
|
| ^^^^^ required by this bound in `foo`
|
||||||
|
help: consider dereferencing here
|
||||||
|
|
|
||||||
|
LL | foo(&***baz);
|
||||||
|
| +++
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue