Auto merge of #155837 - JonathanBrouwer:rollup-aPhy30j, r=JonathanBrouwer

Rollup of 15 pull requests

Successful merges:

 - rust-lang/rust#152995 (ACP Implementation of PermissionsExt for Windows )
 - rust-lang/rust#153457 (prevent deref coercions in `pin!`)
 - rust-lang/rust#155250 (Windows: Cache the pipe filesystem handle)
 - rust-lang/rust#155574 (Move `std::io::RawOsError` to `core::io`)
 - rust-lang/rust#155757 (macro_metavar_expr_concat: explain why idents are invalid)
 - rust-lang/rust#155823 (miri subtree update)
 - rust-lang/rust#155693 (Suggest enclosing format string with `""` under special cases)
 - rust-lang/rust#155707 (Fix minor panic-unsoundness in CString::clone_into)
 - rust-lang/rust#155719 (Suggest `.iter()` for shared projections)
 - rust-lang/rust#155779 (ssa_range_prop: use `if let` guards)
 - rust-lang/rust#155789 (Cleanups to `AttributeExt`)
 - rust-lang/rust#155805 (Mention `DEPRECATED_LLVM_INTRINSIC` lint for internal use)
 - rust-lang/rust#155806 (Remove the incomplete marker from `impl` restrictions)
 - rust-lang/rust#155820 (Avoid improper spans when `...` or `..=` is recovered from non-ASCII)
 - rust-lang/rust#155822 (Add default field values to diagnostic FormatArgs)
This commit is contained in:
bors
2026-04-26 20:31:33 +00:00
82 changed files with 1582 additions and 599 deletions
+32 -37
View File
@@ -235,34 +235,6 @@ fn doc_str(&self) -> Option<Symbol> {
}
}
fn deprecation_note(&self) -> Option<Ident> {
match &self.kind {
AttrKind::Normal(normal) if normal.item.path == sym::deprecated => {
let meta = &normal.item;
// #[deprecated = "..."]
if let Some(s) = meta.value_str() {
return Some(Ident { name: s, span: meta.span() });
}
// #[deprecated(note = "...")]
if let Some(list) = meta.meta_item_list() {
for nested in list {
if let Some(mi) = nested.meta_item()
&& mi.path == sym::note
&& let Some(s) = mi.value_str()
{
return Some(Ident { name: s, span: mi.span });
}
}
}
None
}
_ => None,
}
}
fn doc_resolution_scope(&self) -> Option<AttrStyle> {
match &self.kind {
AttrKind::DocComment(..) => Some(self.style),
@@ -341,6 +313,34 @@ pub fn token_trees(&self) -> Vec<TokenTree> {
)],
}
}
pub fn deprecation_note(&self) -> Option<Ident> {
match &self.kind {
AttrKind::Normal(normal) if normal.item.path == sym::deprecated => {
let meta = &normal.item;
// #[deprecated = "..."]
if let Some(s) = meta.value_str() {
return Some(Ident { name: s, span: meta.span() });
}
// #[deprecated(note = "...")]
if let Some(list) = meta.meta_item_list() {
for nested in list {
if let Some(mi) = nested.meta_item()
&& mi.path == sym::note
&& let Some(s) = mi.value_str()
{
return Some(Ident { name: s, span: mi.span });
}
}
}
None
}
_ => None,
}
}
}
impl AttrItem {
@@ -824,19 +824,19 @@ pub fn mk_attr_name_value_str(
mk_attr(g, style, unsafety, path, args, span)
}
pub fn filter_by_name<A: AttributeExt>(attrs: &[A], name: Symbol) -> impl Iterator<Item = &A> {
pub fn filter_by_name(attrs: &[Attribute], name: Symbol) -> impl Iterator<Item = &Attribute> {
attrs.iter().filter(move |attr| attr.has_name(name))
}
pub fn find_by_name<A: AttributeExt>(attrs: &[A], name: Symbol) -> Option<&A> {
pub fn find_by_name(attrs: &[Attribute], name: Symbol) -> Option<&Attribute> {
filter_by_name(attrs, name).next()
}
pub fn first_attr_value_str_by_name(attrs: &[impl AttributeExt], name: Symbol) -> Option<Symbol> {
pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: Symbol) -> Option<Symbol> {
find_by_name(attrs, name).and_then(|attr| attr.value_str())
}
pub fn contains_name(attrs: &[impl AttributeExt], name: Symbol) -> bool {
pub fn contains_name(attrs: &[Attribute], name: Symbol) -> bool {
find_by_name(attrs, name).is_some()
}
@@ -911,11 +911,6 @@ fn has_any_name(&self, names: &[Symbol]) -> bool {
/// * `#[doc(...)]` returns `None`.
fn doc_str(&self) -> Option<Symbol>;
/// Returns the deprecation note if this is deprecation attribute.
/// * `#[deprecated = "note"]` returns `Some("note")`.
/// * `#[deprecated(note = "note", ...)]` returns `Some("note")`.
fn deprecation_note(&self) -> Option<Ident>;
/// Returns whether this attribute is any of the proc macro attributes.
/// i.e. `proc_macro`, `proc_macro_attribute` or `proc_macro_derive`.
fn is_proc_macro_attr(&self) -> bool {
@@ -1,7 +1,6 @@
use std::num::IntErrorKind;
use rustc_ast::LitKind;
use rustc_ast::attr::AttributeExt;
use rustc_ast::{LitKind, ast};
use rustc_feature::is_builtin_attr_name;
use rustc_hir::RustcVersion;
use rustc_hir::limit::Limit;
@@ -27,8 +26,8 @@ pub fn parse_version(s: Symbol) -> Option<RustcVersion> {
Some(RustcVersion { major, minor, patch })
}
pub fn is_builtin_attr(attr: &impl AttributeExt) -> bool {
attr.is_doc_comment().is_some() || attr.name().is_some_and(|name| is_builtin_attr_name(name))
pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
attr.is_doc_comment() || attr.name().is_some_and(|name| is_builtin_attr_name(name))
}
/// Parse a single integer.
@@ -156,14 +156,7 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
.collect();
generic_args.push((kw::SelfUpper, this.clone()));
let args = FormatArgs {
this,
// Unused
this_sugared: String::new(),
// Unused
item_context: "",
generic_args,
};
let args = FormatArgs { this, generic_args, .. };
let CustomDiagnostic { message, label, notes, parent_label: _ } =
directive.eval(None, &args);
+25 -1
View File
@@ -173,6 +173,16 @@ fn make_format_args(
style: fmt_style,
uncooked_symbol: uncooked_fmt_str,
} = {
// Extract snippet so that we can check cases `{}`, `{:?}` and `{:#?}` and emit help for
// them later.
let snippet = if let ExprKind::Block(b, None) = &efmt.kind
&& b.stmts.len() <= 1
{
Some(ecx.sess.source_map().span_to_snippet(unexpanded_fmt_span))
} else {
None
};
let ExpandResult::Ready(mac) = expr_to_spanned_string(ecx, efmt.clone(), msg) else {
return ExpandResult::Retry(());
};
@@ -222,12 +232,26 @@ fn make_format_args(
});
}
sugg_fmt = sugg_fmt.trim_end().to_string();
err.span_suggestion(
err.span_suggestion_verbose(
unexpanded_fmt_span.shrink_to_lo(),
"you might be missing a string literal to format with",
format!("\"{sugg_fmt}\", "),
Applicability::MaybeIncorrect,
);
if let Some(Ok(snippet)) = snippet.as_ref() {
match snippet.as_str() {
"{}" | "{:?}" | "{:#?}" => {
err.span_suggestion_verbose(
unexpanded_fmt_span,
format!("you might want to enclose `{snippet}` with `\"\"`"),
format!("\"{snippet}\""),
Applicability::MaybeIncorrect,
);
}
_ => {}
};
}
}
}
err.emit()
+43
View File
@@ -545,6 +545,49 @@ pub(crate) struct MveUnrecognizedVar {
pub span: Span,
pub key: MacroRulesNormalizedIdent,
}
#[derive(Diagnostic)]
#[diag(r#"`${"{"}concat(..){"}"}` is not generating a valid identifier"#)]
pub(crate) struct ConcatInvalidIdent {
#[primary_span]
pub span: Span,
#[subdiagnostic]
pub reason: InvalidIdentReason,
}
#[derive(Subdiagnostic)]
pub(crate) enum InvalidIdentReason {
#[note(r#"this `${"{"}concat(..){"}"}` invocation generated an empty ident"#)]
Empty,
#[note(r#"this `${"{"}concat(..){"}"}` invocation generated `{$symbol}`, but {$start} is neither '_' nor XID_Start"#)]
#[note(
"see <https://doc.rust-lang.org/reference/identifiers.html> for the definition of valid identifiers"
)]
InvalidStart { symbol: Symbol, start: char },
#[note(r#"this `${"{"}concat(..){"}"}` invocation generated `{$symbol}`, but {$not_continue} is not XID_Continue"#)]
#[note(
"see <https://doc.rust-lang.org/reference/identifiers.html> for the definition of valid identifiers"
)]
InvalidContinue { symbol: Symbol, not_continue: char },
}
impl InvalidIdentReason {
pub(crate) fn new(symbol: Symbol) -> Self {
let mut chars = symbol.as_str().chars();
if let Some(start) = chars.next() {
if rustc_lexer::is_id_start(start) {
let not_continue = chars
.find(|c| !rustc_lexer::is_id_continue(*c))
.expect("InvalidIdentReason: cannot find invalid ident reason");
InvalidIdentReason::InvalidContinue { symbol, not_continue }
} else {
InvalidIdentReason::InvalidStart { symbol, start }
}
} else {
InvalidIdentReason::Empty
}
}
}
}
#[derive(Diagnostic)]
+1
View File
@@ -1,6 +1,7 @@
// tidy-alphabetical-start
#![allow(internal_features)]
#![feature(associated_type_defaults)]
#![feature(default_field_values)]
#![feature(macro_metavar_expr)]
#![feature(proc_macro_diagnostic)]
#![feature(proc_macro_internals)]
+1 -12
View File
@@ -77,19 +77,8 @@ pub(super) fn failed_to_match_macro(
let CustomDiagnostic {
message: custom_message, label: custom_label, notes: custom_notes, ..
} = {
let macro_name = name.to_string();
on_unmatch_args
.map(|directive| {
directive.eval(
None,
&FormatArgs {
this: macro_name.clone(),
this_sugared: macro_name,
item_context: "macro invocation",
generic_args: Vec::new(),
},
)
})
.map(|directive| directive.eval(None, &FormatArgs { this: name.to_string(), .. }))
.unwrap_or_default()
};
+8 -7
View File
@@ -18,9 +18,10 @@
use smallvec::{SmallVec, smallvec};
use crate::errors::{
CountRepetitionMisplaced, MacroVarStillRepeating, MetaVarsDifSeqMatchers, MustRepeatOnce,
MveUnrecognizedVar, NoRepeatableVar, NoSyntaxVarsExprRepeat, VarNoTypo,
VarTypoSuggestionRepeatable, VarTypoSuggestionUnrepeatable, VarTypoSuggestionUnrepeatableLabel,
ConcatInvalidIdent, CountRepetitionMisplaced, InvalidIdentReason, MacroVarStillRepeating,
MetaVarsDifSeqMatchers, MustRepeatOnce, MveUnrecognizedVar, NoRepeatableVar,
NoSyntaxVarsExprRepeat, VarNoTypo, VarTypoSuggestionRepeatable, VarTypoSuggestionUnrepeatable,
VarTypoSuggestionUnrepeatableLabel,
};
use crate::mbe::macro_parser::NamedMatch;
use crate::mbe::macro_parser::NamedMatch::*;
@@ -656,10 +657,10 @@ fn metavar_expr_concat<'tx>(
let symbol = nfc_normalize(&concatenated);
let concatenated_span = tscx.visited_dspan(dspan);
if !rustc_lexer::is_ident(symbol.as_str()) {
return Err(dcx.struct_span_err(
concatenated_span,
"`${concat(..)}` is not generating a valid identifier",
));
return Err(dcx.create_err(ConcatInvalidIdent {
span: concatenated_span,
reason: InvalidIdentReason::new(symbol),
}));
}
tscx.psess.symbol_gallery.insert(symbol, concatenated_span);
+1 -1
View File
@@ -549,7 +549,7 @@ pub fn internal(&self, feature: Symbol) -> bool {
/// Target features on hexagon.
(unstable, hexagon_target_feature, "1.27.0", Some(150250)),
/// Allows `impl(crate) trait Foo` restrictions.
(incomplete, impl_restriction, "1.96.0", Some(105077)),
(unstable, impl_restriction, "CURRENT_RUSTC_VERSION", Some(105077)),
/// Allows `impl Trait` to be used inside associated types (RFC 2515).
(unstable, impl_trait_in_assoc_type, "1.70.0", Some(63063)),
/// Allows `impl Trait` in bindings (`let`).
+4 -3
View File
@@ -218,10 +218,11 @@ fn visit_params(&self, visit: &mut impl FnMut(Symbol, Span)) {
/// ```
#[derive(Debug)]
pub struct FormatArgs {
/// The name of the item the attribute is on.
pub this: String,
pub this_sugared: String,
pub item_context: &'static str,
pub generic_args: Vec<(Symbol, String)>,
pub this_sugared: String = String::new(),
pub item_context: &'static str = "",
pub generic_args: Vec<(Symbol, String)> = Vec::new(),
}
#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
-8
View File
@@ -1424,14 +1424,6 @@ fn doc_str(&self) -> Option<Symbol> {
}
}
#[inline]
fn deprecation_note(&self) -> Option<Ident> {
match &self {
Attribute::Parsed(AttributeKind::Deprecated { deprecation, .. }) => deprecation.note,
_ => None,
}
}
fn is_automatically_derived_attr(&self) -> bool {
matches!(self, Attribute::Parsed(AttributeKind::AutomaticallyDerived(..)))
}
+1
View File
@@ -7,6 +7,7 @@
#![feature(closure_track_caller)]
#![feature(const_default)]
#![feature(const_trait_impl)]
#![feature(default_field_values)]
#![feature(derive_const)]
#![feature(exhaustive_patterns)]
#![feature(never_type)]
@@ -2,7 +2,7 @@
//! normal visitor, which just walks the entire body in one shot, the
//! `ExprUseVisitor` determines how expressions are being used.
//!
//! In the compiler, this is only used for upvar inference, but there
//! In the compiler, this is only used for upvar inference and diagnostics, but there
//! are many uses within clippy.
use std::cell::{Ref, RefCell};
@@ -1855,3 +1855,27 @@ fn is_multivariant_adt(&self, ty: Ty<'tcx>, span: Span) -> bool {
}
}
}
struct ExprPlaceDelegate;
impl<'tcx> Delegate<'tcx> for ExprPlaceDelegate {
fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
fn borrow(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) {}
fn mutate(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
}
/// Categorizes `expr` as a place for diagnostic suggestions.
///
/// This should be used for diagnostics purpose only.
pub(crate) fn expr_place<'tcx>(
fcx: &FnCtxt<'_, 'tcx>,
expr: &hir::Expr<'_>,
) -> Result<PlaceWithHirId<'tcx>, ErrorGuaranteed> {
ExprUseVisitor::new(fcx, ExprPlaceDelegate).cat_expr(expr)
}
@@ -48,6 +48,7 @@
use super::probe::{AutorefOrPtrAdjustment, IsSuggestion, Mode, ProbeScope};
use super::{CandidateSource, MethodError, NoMatchData};
use crate::errors::{self, CandidateTraitNote, NoAssociatedItem};
use crate::expr_use_visitor::expr_place;
use crate::method::probe::UnsatisfiedPredicates;
use crate::{Expectation, FnCtxt};
@@ -189,6 +190,70 @@ fn predicate_bounds_generic_param<'tcx>(
false
}
// Pick the iterator method to suggest: `.into_iter()` by default, and
// `.iter()`/`.iter_mut()` for projections through references.
fn preferred_iterator_method(
&self,
source: SelfSource<'tcx>,
rcvr_ty: Ty<'tcx>,
) -> Option<Symbol> {
let SelfSource::MethodCall(rcvr_expr) = source else {
return Some(sym::into_iter);
};
let rcvr_expr = rcvr_expr.peel_drop_temps().peel_blocks();
let Ok(place_with_id) = expr_place(self, rcvr_expr) else {
return None;
};
let mut projection_mutability = None;
for pointer_ty in place_with_id.place.deref_tys() {
match self.structurally_resolve_type(rcvr_expr.span, pointer_ty).kind() {
ty::Ref(.., Mutability::Not) => {
projection_mutability = Some(Mutability::Not);
break;
}
ty::Ref(.., Mutability::Mut) => {
projection_mutability.get_or_insert(Mutability::Mut);
}
ty::RawPtr(..) => return None,
_ => {}
}
}
// Keep `.into_iter()` for receivers like `&Vec<_>`; only projections that
// dereference a reference need to switch to `iter`/`iter_mut`.
let Some(projection_mutability) = projection_mutability else {
return Some(sym::into_iter);
};
let call_expr = self.tcx.hir_expect_expr(self.tcx.parent_hir_id(rcvr_expr.hir_id));
// `IntoIterator` does not imply inherent `iter`/`iter_mut` methods.
let has_method = |method_name| {
self.lookup_probe_for_diagnostic(
Ident::with_dummy_span(method_name),
rcvr_ty,
call_expr,
ProbeScope::TraitsInScope,
None,
)
.is_ok()
};
match projection_mutability {
Mutability::Not => has_method(sym::iter).then_some(sym::iter),
Mutability::Mut => {
if has_method(sym::iter_mut) {
Some(sym::iter_mut)
} else if has_method(sym::iter) {
Some(sym::iter)
} else {
None
}
}
}
}
#[instrument(level = "debug", skip(self))]
pub(crate) fn report_method_error(
&self,
@@ -855,10 +920,12 @@ fn suggest_unsatisfied_ty_or_trait(
} else if self.impl_into_iterator_should_be_iterator(rcvr_ty, span, unsatisfied_predicates)
{
err.span_label(span, format!("`{rcvr_ty}` is not an iterator"));
if !span.in_external_macro(self.tcx.sess.source_map()) {
if !span.in_external_macro(self.tcx.sess.source_map())
&& let Some(method_name) = self.preferred_iterator_method(source, rcvr_ty)
{
err.multipart_suggestion(
"call `.into_iter()` first",
vec![(span.shrink_to_lo(), format!("into_iter()."))],
format!("call `.{method_name}()` first"),
vec![(span.shrink_to_lo(), format!("{method_name}()."))],
Applicability::MaybeIncorrect,
);
}
+6 -1
View File
@@ -5639,7 +5639,12 @@
/// LLVM periodically updates its list of intrinsics. Deprecated intrinsics are unlikely
/// to be removed, but they may optimize less well than their new versions, so it's
/// best to use the new version. Also, some deprecated intrinsics might have buggy
/// behavior
/// behavior.
///
/// This `link_llvm_intrinsics` lint is intended to be used internally only, and requires the
/// `#![feature(link_llvm_intrinsics)]` internal feature gate. For more information, see [its chapter in
/// the Unstable Book](https://doc.rust-lang.org/unstable-book/language-features/link-llvm-intrinsics.html)
/// and [its tracking issue](https://github.com/rust-lang/rust/issues/29602).
pub DEPRECATED_LLVM_INTRINSIC,
Allow,
"detects uses of deprecated LLVM intrinsics",
@@ -143,14 +143,13 @@ fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) {
fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) {
self.super_statement(statement, location);
match &statement.kind {
StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(operand)) => {
StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(operand))
if let Some(place) = operand.place()
&& self.is_ssa(place)
{
let successor = location.successor_within_block();
let range = WrappingRange { start: 1, end: 1 };
self.insert_range(place, successor, range);
}
&& self.is_ssa(place) =>
{
let successor = location.successor_within_block();
let range = WrappingRange { start: 1, end: 1 };
self.insert_range(place, successor, range);
}
_ => {}
}
@@ -159,58 +158,56 @@ fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Locatio
fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) {
self.super_terminator(terminator, location);
match &terminator.kind {
TerminatorKind::Assert { cond, expected, target, .. } => {
TerminatorKind::Assert { cond, expected, target, .. }
if let Some(place) = cond.place()
&& self.is_ssa(place) =>
{
let successor = Location { block: *target, statement_index: 0 };
if location.dominates(successor, &self.dominators) {
assert_ne!(location.block, successor.block);
let val = *expected as u128;
let range = WrappingRange { start: val, end: val };
self.insert_range(place, successor, range);
}
}
TerminatorKind::SwitchInt { discr, targets }
if let Some(place) = discr.place()
&& self.is_ssa(place)
{
let successor = Location { block: *target, statement_index: 0 };
if location.dominates(successor, &self.dominators) {
// Reduce the potential compile-time overhead.
&& targets.all_targets().len() < 16 =>
{
let mut distinct_targets: FxHashMap<BasicBlock, u64> = FxHashMap::default();
for (_, target) in targets.iter() {
let targets = distinct_targets.entry(target).or_default();
*targets += 1;
}
for (val, target) in targets.iter() {
if distinct_targets[&target] != 1 {
// FIXME: For multiple targets, the range can be the union of their values.
continue;
}
let successor = Location { block: target, statement_index: 0 };
if self.unique_predecessors.contains(successor.block) {
assert_ne!(location.block, successor.block);
let val = *expected as u128;
let range = WrappingRange { start: val, end: val };
self.insert_range(place, successor, range);
}
}
}
TerminatorKind::SwitchInt { discr, targets } => {
if let Some(place) = discr.place()
&& self.is_ssa(place)
// Reduce the potential compile-time overhead.
&& targets.all_targets().len() < 16
{
let mut distinct_targets: FxHashMap<BasicBlock, u64> = FxHashMap::default();
for (_, target) in targets.iter() {
let targets = distinct_targets.entry(target).or_default();
*targets += 1;
}
for (val, target) in targets.iter() {
if distinct_targets[&target] != 1 {
// FIXME: For multiple targets, the range can be the union of their values.
continue;
}
let successor = Location { block: target, statement_index: 0 };
if self.unique_predecessors.contains(successor.block) {
assert_ne!(location.block, successor.block);
let range = WrappingRange { start: val, end: val };
self.insert_range(place, successor, range);
}
}
// FIXME: The range for the otherwise target be extend to more types.
// For instance, `val` is within the range [4, 1) at the otherwise target of `matches!(val, 1 | 2 | 3)`.
let otherwise = Location { block: targets.otherwise(), statement_index: 0 };
if place.ty(self.local_decls, self.tcx).ty.is_bool()
&& let [val] = targets.all_values()
&& self.unique_predecessors.contains(otherwise.block)
{
assert_ne!(location.block, otherwise.block);
let range = if val.get() == 0 {
WrappingRange { start: 1, end: 1 }
} else {
WrappingRange { start: 0, end: 0 }
};
self.insert_range(place, otherwise, range);
}
// FIXME: The range for the otherwise target be extend to more types.
// For instance, `val` is within the range [4, 1) at the otherwise target of `matches!(val, 1 | 2 | 3)`.
let otherwise = Location { block: targets.otherwise(), statement_index: 0 };
if place.ty(self.local_decls, self.tcx).ty.is_bool()
&& let [val] = targets.all_values()
&& self.unique_predecessors.contains(otherwise.block)
{
assert_ne!(location.block, otherwise.block);
let range = if val.get() == 0 {
WrappingRange { start: 1, end: 1 }
} else {
WrappingRange { start: 0, end: 0 }
};
self.insert_range(place, otherwise, range);
}
}
_ => {}
+4 -6
View File
@@ -1140,14 +1140,13 @@ pub(crate) struct InclusiveRangeMatchArrow {
#[primary_span]
pub arrow: Span,
#[label("this is parsed as an inclusive range `..=`")]
pub span: Span,
#[suggestion(
"add a space between the pattern and `=>`",
style = "verbose",
code = " ",
code = ".. =",
applicability = "machine-applicable"
)]
pub after_pat: Span,
pub span: Span,
}
#[derive(Diagnostic)]
@@ -1155,14 +1154,13 @@ pub(crate) struct InclusiveRangeMatchArrow {
#[note("inclusive ranges must be bounded at the end (`..=b` or `a..=b`)")]
pub(crate) struct InclusiveRangeNoEnd {
#[primary_span]
pub span: Span,
#[suggestion(
"use `..` instead",
code = "",
code = "..",
applicability = "machine-applicable",
style = "verbose"
)]
pub suggestion: Span,
pub span: Span,
}
#[derive(Subdiagnostic)]
+4 -8
View File
@@ -1225,7 +1225,7 @@ fn parse_pat_range_begin_with(
pub(super) fn inclusive_range_with_incorrect_end(&mut self) -> ErrorGuaranteed {
let tok = &self.token;
let span = self.prev_token.span;
// If the user typed "..==" instead of "..=", we want to give them
// If the user typed "..==" or "...=" instead of "..=", we want to give them
// a specific error message telling them to use "..=".
// If they typed "..=>", suggest they use ".. =>".
// Otherwise, we assume that they meant to type a half open exclusive
@@ -1243,14 +1243,10 @@ pub(super) fn inclusive_range_with_incorrect_end(&mut self) -> ErrorGuaranteed {
self.dcx().emit_err(InclusiveRangeExtraEquals { span: span_with_eq })
}
token::Gt if no_space => {
let after_pat = span.with_hi(span.hi() - BytePos(1)).shrink_to_hi();
self.dcx().emit_err(InclusiveRangeMatchArrow { span, arrow: tok.span, after_pat })
token::Gt if self.prev_token.kind == token::DotDotEq && no_space => {
self.dcx().emit_err(InclusiveRangeMatchArrow { span, arrow: tok.span })
}
_ => self.dcx().emit_err(InclusiveRangeNoEnd {
span,
suggestion: span.with_lo(span.hi() - BytePos(1)),
}),
_ => self.dcx().emit_err(InclusiveRangeNoEnd { span }),
}
}
+1 -6
View File
@@ -886,12 +886,7 @@ fn throw_unresolved_import_error(
let args = FormatArgs {
this,
// Unused
this_sugared: String::new(),
// Unused
item_context: "",
// Unused
generic_args: Vec::new(),
..
};
let CustomDiagnostic { message, label, notes, .. } = directive.eval(None, &args);
+1 -1
View File
@@ -409,7 +409,7 @@ pub fn may_be_doc_link(link_type: LinkType) -> bool {
/// Simplified version of `preprocessed_markdown_links` from rustdoc.
/// Must return at least the same links as it, but may add some more links on top of that.
pub(crate) fn attrs_to_preprocessed_links<A: AttributeExt + Clone>(attrs: &[A]) -> Vec<Box<str>> {
pub(crate) fn attrs_to_preprocessed_links(attrs: &[ast::Attribute]) -> Vec<Box<str>> {
let (doc_fragments, other_attrs) =
attrs_to_doc_fragments(attrs.iter().map(|attr| (attr, None)), false);
let mut doc =
+11 -3
View File
@@ -1077,9 +1077,17 @@ fn to_owned(&self) -> CString {
}
fn clone_into(&self, target: &mut CString) {
let mut b = mem::take(&mut target.inner).into_vec();
self.to_bytes_with_nul().clone_into(&mut b);
target.inner = b.into_boxed_slice();
let src = self.to_bytes_with_nul();
// If the lengths match, we can reuse the existing allocation without any overhead.
if target.inner.len() == src.len() {
target.inner.copy_from_slice(src);
} else {
// Reuse the existing allocation's capacity by converting to a Vec.
// We temporarily replace `target` with a valid dummy to remain panic-safe.
let mut b = mem::replace(&mut target.inner, Box::new([0])).into_vec();
self.to_bytes_with_nul().clone_into(&mut b);
target.inner = b.into_boxed_slice();
}
}
}
+14
View File
@@ -2,6 +2,20 @@
use crate::fmt;
/// The type of raw OS error codes.
///
/// This is an [`i32`] on all currently supported platforms, but platforms
/// added in the future (such as UEFI) may use a different primitive type like
/// [`usize`]. Use `as` or [`into`] conversions where applicable to ensure maximum
/// portability.
///
/// [`into`]: Into::into
#[unstable(feature = "raw_os_error_ty", issue = "107792")]
pub type RawOsError = cfg_select! {
target_os = "uefi" => usize,
_ => i32,
};
/// A list specifying general categories of I/O error.
///
/// This list is intended to grow over time and it is not recommended to
+2
View File
@@ -7,3 +7,5 @@
pub use self::borrowed_buf::{BorrowedBuf, BorrowedCursor};
#[unstable(feature = "core_io", issue = "154046")]
pub use self::error::ErrorKind;
#[unstable(feature = "raw_os_error_ty", issue = "107792")]
pub use self::error::RawOsError;
+1
View File
@@ -157,6 +157,7 @@
#![feature(no_core)]
#![feature(optimize_attribute)]
#![feature(pattern_types)]
#![feature(pin_macro_internals)]
#![feature(prelude_import)]
#![feature(repr_simd)]
#![feature(rustc_attrs)]
+18 -3
View File
@@ -2021,14 +2021,29 @@ unsafe impl<T: PinCoerceUnsized> PinCoerceUnsized for Pin<T> {}
/// [`Box::pin`]: ../../std/boxed/struct.Box.html#method.pin
#[stable(feature = "pin_macro", since = "1.68.0")]
#[rustc_macro_transparency = "semiopaque"]
#[allow_internal_unstable(super_let)]
#[allow_internal_unstable(pin_macro_internals, super_let)]
#[rustc_diagnostic_item = "pin_macro"]
// `super` gets removed by rustfmt
#[rustfmt::skip]
pub macro pin($value:expr $(,)?) {
{
'p: {
super let mut pinned = $value;
// SAFETY: The value is pinned: it is the local above which cannot be named outside this macro.
unsafe { $crate::pin::Pin::new_unchecked(&mut pinned) }
break 'p unsafe { $crate::pin::Pin::new_unchecked(&mut pinned) };
// HACK: We need to ensure that, given `$value: T`, `pin!($value)` has type `Pin<&mut T>`.
// Otherwise, it's possible for a type annotation on the result of `pin!` to unsoundly add
// deref coercions. E.g. for `$value: &mut T`, we could get `pin!($value): Pin<&mut T>`,
// violating the pinning invariant; see <https://github.com/rust-lang/rust/issues/153438>.
#[expect(unreachable_code)]
$crate::pin::unreachable_pin_macro_type_constraint(pinned)
}
}
/// Helper for `pin!` to enforce its type signature.
/// See <https://github.com/rust-lang/rust/issues/153438>.
#[unstable(feature = "pin_macro_internals", issue = "none")]
#[doc(hidden)]
pub fn unreachable_pin_macro_type_constraint<'a, T>(_: T) -> Pin<&'a mut T> {
unreachable!()
}
+2 -11
View File
@@ -3,6 +3,8 @@
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::io::ErrorKind;
#[unstable(feature = "raw_os_error_ty", issue = "107792")]
pub use core::io::RawOsError;
// On 64-bit platforms, `io::Error` may use a bit-packed representation to
// reduce size. However, this representation assumes that error codes are
@@ -140,17 +142,6 @@ enum ErrorData<C> {
Custom(C),
}
/// The type of raw OS error codes returned by [`Error::raw_os_error`].
///
/// This is an [`i32`] on all currently supported platforms, but platforms
/// added in the future (such as UEFI) may use a different primitive type like
/// [`usize`]. Use `as`or [`into`] conversions where applicable to ensure maximum
/// portability.
///
/// [`into`]: Into::into
#[unstable(feature = "raw_os_error_ty", issue = "107792")]
pub type RawOsError = sys::io::RawOsError;
// `#[repr(align(4))]` is probably redundant, it should have that value or
// higher already. We include it just because repr_bitpacked.rs's encoding
// requires an alignment >= 4 (note that `#[repr(align)]` will not reduce the
+1
View File
@@ -364,6 +364,7 @@
#![feature(ptr_as_uninit)]
#![feature(ptr_mask)]
#![feature(random)]
#![feature(raw_os_error_ty)]
#![feature(slice_internals)]
#![feature(slice_ptr_get)]
#![feature(slice_range)]
+64 -2
View File
@@ -4,11 +4,11 @@
#![stable(feature = "rust1", since = "1.0.0")]
use crate::fs::{self, Metadata, OpenOptions};
use crate::fs::{self, Metadata, OpenOptions, Permissions};
use crate::io::BorrowedCursor;
use crate::path::Path;
use crate::sealed::Sealed;
use crate::sys::{AsInner, AsInnerMut, IntoInner};
use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner};
use crate::time::SystemTime;
use crate::{io, sys};
@@ -368,6 +368,68 @@ fn freeze_last_write_time(&mut self, freeze: bool) -> &mut Self {
}
}
/// Windows-specific extensions to [`fs::Permissions`]. This extension trait
/// provides extra utilities to shows what Windows file attributes are enabled
/// in [`Permissions`] and to manually set file attributes on [`Permissions`].
///
/// See Microsoft's [`File Attribute Constants`] page to know what file
/// attribute metadata are defined and stored on Windows files.
///
/// [`Permissions`]: fs::Permissions
/// [`File Attribute Constants`]:
/// https://learn.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
///
/// # Example
///
/// ```no_run
/// #![feature(windows_permissions_ext)]
/// use std::fs::Permissions;
/// use std::os::windows::fs::PermissionsExt;
///
/// const FILE_ATTRIBUTE_SYSTEM: u32 = 0x4;
/// const FILE_ATTRIBUTE_ARCHIVE: u32 = 0x20;
/// let my_file_attr = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE;
/// let mut permissions = Permissions::from_file_attributes(my_file_attr);
/// assert_eq!(permissions.file_attributes(), my_file_attr);
///
/// const FILE_ATTRIBUTE_HIDDEN: u32 = 0x2;
/// let new_file_attr = permissions.file_attributes() | FILE_ATTRIBUTE_HIDDEN;
/// permissions.set_file_attributes(new_file_attr);
/// assert_eq!(permissions.file_attributes(), new_file_attr);
/// ```
#[unstable(feature = "windows_permissions_ext", issue = "152956")]
pub trait PermissionsExt: Sealed {
/// Returns the file attribute bits.
#[unstable(feature = "windows_permissions_ext", issue = "152956")]
fn file_attributes(&self) -> u32;
/// Sets the file attribute bits.
#[unstable(feature = "windows_permissions_ext", issue = "152956")]
fn set_file_attributes(&mut self, mask: u32);
/// Creates a new instance from the given file attribute bits.
#[unstable(feature = "windows_permissions_ext", issue = "152956")]
fn from_file_attributes(mask: u32) -> Self;
}
#[unstable(feature = "windows_permissions_ext", issue = "152956")]
impl Sealed for fs::Permissions {}
#[unstable(feature = "windows_permissions_ext", issue = "152956")]
impl PermissionsExt for fs::Permissions {
fn file_attributes(&self) -> u32 {
self.as_inner().file_attributes()
}
fn set_file_attributes(&mut self, mask: u32) {
*self = Permissions::from_inner(FromInner::from_inner(mask));
}
fn from_file_attributes(mask: u32) -> Self {
Permissions::from_inner(FromInner::from_inner(mask))
}
}
/// Windows-specific extensions to [`fs::Metadata`].
///
/// The data members that this trait exposes correspond to the members
+10
View File
@@ -1167,6 +1167,16 @@ pub fn set_readonly(&mut self, readonly: bool) {
self.attrs &= !c::FILE_ATTRIBUTE_READONLY;
}
}
pub fn file_attributes(&self) -> u32 {
self.attrs as u32
}
}
impl FromInner<u32> for FilePermissions {
fn from_inner(attrs: u32) -> FilePermissions {
FilePermissions { attrs }
}
}
impl FileTimes {
-5
View File
@@ -48,8 +48,3 @@
pub use generic::*;
}
}
pub type RawOsError = cfg_select! {
target_os = "uefi" => usize,
_ => i32,
};
+2 -3
View File
@@ -1,7 +1,6 @@
use crate::io;
use crate::sys::io::RawOsError;
pub fn errno() -> RawOsError {
pub fn errno() -> io::RawOsError {
// Not used in Motor OS because it is ambiguous: Motor OS
// is micro-kernel-based, and I/O happens via a shared-memory
// ring buffer, so an I/O operation that on a unix is a syscall
@@ -57,7 +56,7 @@ pub fn decode_error_kind(code: io::RawOsError) -> io::ErrorKind {
}
}
pub fn error_string(errno: RawOsError) -> String {
pub fn error_string(errno: io::RawOsError) -> String {
let error: moto_rt::Error = match errno {
x if x < 0 => moto_rt::Error::Unknown,
x if x > u16::MAX.into() => moto_rt::Error::Unknown,
+1 -1
View File
@@ -62,7 +62,7 @@ mod is_terminal {
target_os = "wasi",
))]
pub use error::set_errno;
pub use error::{RawOsError, decode_error_kind, errno, error_string, is_interrupted};
pub use error::{decode_error_kind, errno, error_string, is_interrupted};
pub use io_slice::{IoSlice, IoSliceMut};
pub use is_terminal::is_terminal;
pub use kernel_copy::{CopyState, kernel_copy};
@@ -1,6 +1,8 @@
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
use crate::ops::Neg;
use crate::os::windows::prelude::*;
use crate::sync::atomic::Atomic;
use crate::sync::atomic::Ordering::Relaxed;
use crate::sys::handle::Handle;
use crate::sys::{FromInner, IntoInner, api, c};
use crate::{mem, ptr};
@@ -70,10 +72,19 @@ pub(super) fn child_pipe(ours_readable: bool, their_handle_inheritable: bool) ->
let mut object_attributes = c::OBJECT_ATTRIBUTES::default();
object_attributes.Length = size_of::<c::OBJECT_ATTRIBUTES>() as u32;
// Open a handle to the pipe filesystem (`\??\PIPE\`).
// This will be used when creating a new annon pipe.
let pipe_fs = {
let path = api::unicode_str!(r"\??\PIPE\");
// Open a handle to the pipe filesystem (`\Device\NamedPipe\`).
// This will be used when creating a new anonymous pipe.
//
// We cache the handle once so we can reuse it without needing to reopen it each time.
// NOTE: this means the handle may appear to be leaked but that's fine because
// it's only one handle and the OS will clean it up when the process exits.
static PIPE_FS: Atomic<c::HANDLE> = Atomic::<c::HANDLE>::new(ptr::null_mut());
let pipe_fs = if let handle = PIPE_FS.load(Relaxed)
&& !handle.is_null()
{
handle
} else {
let path = api::unicode_str!(r"\Device\NamedPipe\");
object_attributes.ObjectName = path.as_ptr();
let mut pipe_fs = ptr::null_mut();
let status = c::NtOpenFile(
@@ -85,7 +96,13 @@ pub(super) fn child_pipe(ours_readable: bool, their_handle_inheritable: bool) ->
c::FILE_SYNCHRONOUS_IO_NONALERT, // synchronous access
);
if c::nt_success(status) {
Handle::from_raw_handle(pipe_fs)
match PIPE_FS.compare_exchange(ptr::null_mut(), pipe_fs, Relaxed, Relaxed) {
Ok(_) => pipe_fs,
Err(existing) => {
c::CloseHandle(pipe_fs);
existing
}
}
} else {
return Err(io::Error::from_raw_os_error(c::RtlNtStatusToDosError(status) as i32));
}
@@ -104,7 +121,7 @@ pub(super) fn child_pipe(ours_readable: bool, their_handle_inheritable: bool) ->
let ours = {
// Use the pipe filesystem as the root directory.
// With no name provided, an anonymous pipe will be created.
object_attributes.RootDirectory = pipe_fs.as_raw_handle();
object_attributes.RootDirectory = pipe_fs;
// A negative timeout value is a relative time (rather than an absolute time).
// The time is given in 100's of nanoseconds so this is 50 milliseconds.
+1 -6
View File
@@ -8,7 +8,6 @@
use itertools::Either;
use rustc_abi::{ExternAbi, VariantIdx};
use rustc_ast as ast;
use rustc_ast::attr::AttributeExt;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_data_structures::thin_vec::ThinVec;
use rustc_hir as hir;
@@ -501,11 +500,7 @@ pub(crate) fn span(&self, tcx: TyCtxt<'_>) -> Option<Span> {
}
pub(crate) fn attr_span(&self, tcx: TyCtxt<'_>) -> rustc_span::Span {
let deprecation_notes = self
.attrs
.other_attrs
.iter()
.filter_map(|attr| attr.deprecation_note().map(|note| note.span));
let deprecation_notes = find_attr!(&self.attrs.other_attrs, Deprecated { deprecation, .. } => deprecation.note.map(|note| note.span)).flatten();
span_of_fragments(&self.attrs.doc_strings)
.into_iter()
+2 -2
View File
@@ -1013,9 +1013,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
[[package]]
name = "openssl-sys"
version = "0.9.111"
version = "0.9.114"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321"
checksum = "13ce1245cd07fcc4cfdb438f7507b0c7e4f3849a69fd84d52374c66d83741bb6"
dependencies = [
"cc",
"libc",
+1 -1
View File
@@ -1 +1 @@
e22c616e4e87914135c1db261a03e0437255335e
9836b06b55f5389f605ee7766eeecd9f17a86cb5
+2 -2
View File
@@ -111,8 +111,8 @@ pub enum BlockReason {
Epoll,
/// Blocked on eventfd.
Eventfd,
/// Blocked on unnamed_socket.
UnnamedSocket,
/// Blocked on virtual socket.
VirtualSocket,
/// Blocked on an IO operation.
IO,
/// Blocked for any reason related to GenMC, such as `assume` statements (GenMC mode only).
+3 -2
View File
@@ -105,8 +105,9 @@
// Resolve ambiguity.
#[doc(no_inline)]
pub use rustc_const_eval::interpret::{self, AllocMap, Provenance as _};
use rustc_log::tracing::{self, info, trace};
use rustc_middle::{bug, span_bug};
pub use rustc_data_structures::either::Either;
pub use rustc_log::tracing::{self, info, trace};
pub use rustc_middle::{bug, span_bug};
#[cfg(all(feature = "native-lib", unix))]
pub mod native_lib {
+8 -4
View File
@@ -1,6 +1,6 @@
use std::any::Any;
use std::collections::BTreeMap;
use std::fs::{File, Metadata};
use std::fs::File;
use std::io::{ErrorKind, IsTerminal, Read, Seek, SeekFrom, Write};
use std::marker::CoercePointee;
use std::ops::Deref;
@@ -209,7 +209,11 @@ fn destroy<'tcx>(
throw_unsup_format!("cannot close {}", self.name());
}
fn metadata<'tcx>(&self) -> InterpResult<'tcx, io::Result<fs::Metadata>> {
/// Returns the metadata for this FD, if available.
/// This is either host metadata, or a non-file-backed-FD type.
/// The latter is for new represented as a string storing a `libc` name so we only
/// support that kind of metadata on Unix targets.
fn metadata<'tcx>(&self) -> InterpResult<'tcx, Either<io::Result<fs::Metadata>, &'static str>> {
throw_unsup_format!("obtaining metadata is only supported on file-backed file descriptors");
}
@@ -432,8 +436,8 @@ fn destroy<'tcx>(
}
}
fn metadata<'tcx>(&self) -> InterpResult<'tcx, io::Result<Metadata>> {
interp_ok(self.file.metadata())
fn metadata<'tcx>(&self) -> InterpResult<'tcx, Either<io::Result<fs::Metadata>, &'static str>> {
interp_ok(Either::Left(self.file.metadata()))
}
fn is_tty(&self, communicate_allowed: bool) -> bool {
+60 -20
View File
@@ -229,17 +229,22 @@ fn write_stat_buf(
let (access_sec, access_nsec) = metadata.accessed.unwrap_or((0, 0));
let (created_sec, created_nsec) = metadata.created.unwrap_or((0, 0));
let (modified_sec, modified_nsec) = metadata.modified.unwrap_or((0, 0));
let mode = metadata.mode.to_uint(this.libc_ty_layout("mode_t").size)?;
// We do *not* use `deref_pointer_as` here since determining the right pointee type
// is highly non-trivial: it depends on which exact alias of the function was invoked
// (e.g. `fstat` vs `fstat64`), and then on FreeBSD it also depends on the ABI level
// which can be different between the libc used by std and the libc used by everyone else.
let buf = this.deref_pointer(buf_op)?;
// `libc::S_IF*` constants are of type `mode_t`, which varies in width across targets
// (`u16` on macOS, `u32` on Linux). Read the scalar using `mode_t`'s size on the target.
let mode_t_size = this.libc_ty_layout("mode_t").size;
let mode: u32 = metadata.mode.to_uint(mode_t_size)?.try_into().unwrap();
this.write_int_fields_named(
&[
("st_dev", metadata.dev.into()),
("st_mode", mode.try_into().unwrap()),
("st_mode", mode.into()),
("st_nlink", 0),
("st_ino", 0),
("st_uid", metadata.uid.into()),
@@ -747,13 +752,12 @@ fn linux_statx(
Err(err) => return this.set_last_error_and_return_i32(err),
};
// The `mode` field specifies the type of the file and the permissions over the file for
// the owner, its group and other users. Given that we can only provide the file type
// without using platform specific methods, we only set the bits corresponding to the file
// type. This should be an `__u16` but `libc` provides its values as `u32`.
// `statx.stx_mode` is `__u16`. `libc::S_IF*` are of type `mode_t`, which varies in
// width across targets (`u16` on macOS, `u32` on Linux). Read using `mode_t`'s size.
let mode_t_size = this.libc_ty_layout("mode_t").size;
let mode: u16 = metadata
.mode
.to_u32()?
.to_uint(mode_t_size)?
.try_into()
.unwrap_or_else(|_| bug!("libc contains bad value for constant"));
@@ -1630,6 +1634,34 @@ fn extract_sec_and_nsec<'tcx>(
}
}
fn file_type_to_mode_name(file_type: std::fs::FileType) -> &'static str {
#[cfg(unix)]
use std::os::unix::fs::FileTypeExt;
if file_type.is_file() {
"S_IFREG"
} else if file_type.is_dir() {
"S_IFDIR"
} else if file_type.is_symlink() {
"S_IFLNK"
} else {
// Certain file types are only available when the host is a Unix system.
#[cfg(unix)]
{
if file_type.is_socket() {
return "S_IFSOCK";
} else if file_type.is_fifo() {
return "S_IFIFO";
} else if file_type.is_char_device() {
return "S_IFCHR";
} else if file_type.is_block_device() {
return "S_IFBLK";
}
}
"S_IFREG"
}
}
/// Stores a file's metadata in order to avoid code duplication in the different metadata related
/// shims.
struct FileMetadata {
@@ -1662,10 +1694,27 @@ fn from_fd_num<'tcx>(
let Some(fd) = ecx.machine.fds.get(fd_num) else {
return interp_ok(Err(LibcError("EBADF")));
};
match fd.metadata()? {
Either::Left(host) => Self::from_meta(ecx, host),
Either::Right(name) => Self::synthetic(ecx, name),
}
}
let metadata = fd.metadata()?;
drop(fd);
FileMetadata::from_meta(ecx, metadata)
fn synthetic<'tcx>(
ecx: &mut MiriInterpCx<'tcx>,
mode_name: &str,
) -> InterpResult<'tcx, Result<FileMetadata, IoError>> {
let mode = ecx.eval_libc(mode_name);
interp_ok(Ok(FileMetadata {
mode,
size: 0,
created: None,
accessed: None,
modified: None,
dev: 0,
uid: 0,
gid: 0,
}))
}
fn from_meta<'tcx>(
@@ -1680,16 +1729,7 @@ fn from_meta<'tcx>(
};
let file_type = metadata.file_type();
let mode_name = if file_type.is_file() {
"S_IFREG"
} else if file_type.is_dir() {
"S_IFDIR"
} else {
"S_IFLNK"
};
let mode = ecx.eval_libc(mode_name);
let mode = ecx.eval_libc(file_type_to_mode_name(file_type));
let size = metadata.len();
@@ -119,6 +119,13 @@ fn name(&self) -> &'static str {
"epoll"
}
fn metadata<'tcx>(
&self,
) -> InterpResult<'tcx, Either<io::Result<std::fs::Metadata>, &'static str>> {
// On Linux, epoll is an "anonymous inode" reported as S_IFREG.
interp_ok(Either::Right("S_IFREG"))
}
fn destroy<'tcx>(
mut self,
self_id: FdId,
@@ -37,6 +37,13 @@ fn name(&self) -> &'static str {
"event"
}
fn metadata<'tcx>(
&self,
) -> InterpResult<'tcx, Either<io::Result<std::fs::Metadata>, &'static str>> {
// On Linux, eventfd is an "anonymous inode" reported as S_IFREG.
interp_ok(Either::Right("S_IFREG"))
}
fn destroy<'tcx>(
self,
_self_id: FdId,
+2 -2
View File
@@ -7,7 +7,7 @@
mod socket;
mod sync;
mod thread;
mod unnamed_socket;
mod virtual_socket;
mod android;
mod freebsd;
@@ -25,7 +25,7 @@
pub use self::socket::EvalContextExt as _;
pub use self::sync::EvalContextExt as _;
pub use self::thread::{EvalContextExt as _, ThreadNameResult};
pub use self::unnamed_socket::EvalContextExt as _;
pub use self::virtual_socket::EvalContextExt as _;
// Make up some constants.
const UID: u32 = 1000;
+11 -30
View File
@@ -7,7 +7,6 @@
use mio::Interest;
use mio::event::Source;
use mio::net::{TcpListener, TcpStream};
use rand::Rng;
use rustc_abi::Size;
use rustc_const_eval::interpret::{InterpResult, interp_ok};
use rustc_middle::throw_unsup_format;
@@ -168,8 +167,13 @@ fn write<'tcx>(
}
fn short_fd_operations(&self) -> bool {
// Short accesses on TCP sockets are realistic and expected to happen.
true
// Linux de-facto guarantees (or at least, applications like tokio assume [1, 2]) that
// when a read/write on a streaming socket comes back short, the kernel buffer is
// empty/full. SO we can't do short reads/writes here.
//
// [1]: https://github.com/tokio-rs/tokio/blob/6c03e03898d71eca976ee1ad8481cf112ae722ba/tokio/src/io/poll_evented.rs#L182
// [2]: https://github.com/tokio-rs/tokio/blob/6c03e03898d71eca976ee1ad8481cf112ae722ba/tokio/src/io/poll_evented.rs#L240
false
}
fn as_unix<'tcx>(&self, _ecx: &MiriInterpCx<'tcx>) -> &dyn UnixFileDescription {
@@ -652,18 +656,6 @@ fn send(
return this.set_last_error_and_return(LibcError("ENOTSOCK"), dest);
};
// Non-deterministically decide to further reduce the length, simulating a partial send.
// We avoid reducing the write size to 0: the docs seem to be entirely fine with that,
// but the standard library is not (https://github.com/rust-lang/rust/issues/145959).
let length = if this.machine.short_fd_operations
&& length >= 2
&& this.machine.rng.get_mut().random()
{
length / 2
} else {
length
};
let mut is_op_non_block = false;
// Interpret the flag. Every flag we recognize is "subtracted" from `flags`, so
@@ -774,21 +766,6 @@ fn recv(
return this.set_last_error_and_return(LibcError("ENOTSOCK"), dest);
};
// Non-deterministically decide to further reduce the length, simulating a partial receive.
// We don't simulate partial receives for lengths < 2 because the man page states that a
// return value of zero can only be returned in some special cases:
// "When a stream socket peer has performed an orderly shutdown, the return value will be 0
// (the traditional "end-of-file" return). [...] The value 0 may also be returned if the
// requested number of bytes to receive from a stream socket was 0."
let length = if this.machine.short_fd_operations
&& length >= 2
&& this.machine.rng.get_mut().random()
{
length / 2 // since `length` is at least 2, the result is still at least 1
} else {
length
};
let mut should_peek = false;
let mut is_op_non_block = false;
@@ -1502,6 +1479,8 @@ fn try_non_block_send(
// This is a *non-blocking* write.
let result = this.write_to_host(stream, length, buffer_ptr)?;
// FIXME: When the host does a short write, we should emit an epoll edge -- at least for targets for which tokio assumes no short writes:
// <https://github.com/tokio-rs/tokio/blob/6c03e03898d71eca976ee1ad8481cf112ae722ba/tokio/src/io/poll_evented.rs#L240>
match result {
Err(IoError::HostError(e)) if e.kind() == io::ErrorKind::NotConnected => {
// On Windows hosts, `send` can return WSAENOTCONN where EAGAIN or EWOULDBLOCK
@@ -1578,6 +1557,8 @@ fn try_non_block_recv(
length,
buffer_ptr,
)?;
// FIXME: When the host does a short read, we should emit an epoll edge -- at least for targets for which tokio assumes no short reads:
// <https://github.com/tokio-rs/tokio/blob/6c03e03898d71eca976ee1ad8481cf112ae722ba/tokio/src/io/poll_evented.rs#L182>
match result {
Err(IoError::HostError(e)) if e.kind() == io::ErrorKind::NotConnected => {
// On Windows hosts, `recv` can return WSAENOTCONN where EAGAIN or EWOULDBLOCK
@@ -1,6 +1,6 @@
//! This implements "anonymous" sockets, that do not correspond to anything on the host system and
//! This implements "virtual" sockets, that do not correspond to anything on the host system and
//! are entirely implemented inside Miri.
//! We also use the same infrastructure to implement unnamed pipes.
//! This is used to implement `socketpair` and `pipe`.
use std::cell::{Cell, OnceCell, RefCell};
use std::collections::VecDeque;
@@ -22,7 +22,7 @@
const MAX_SOCKETPAIR_BUFFER_CAPACITY: usize = 0x34000;
#[derive(Debug, PartialEq)]
enum AnonSocketType {
enum VirtualSocketType {
// Either end of the socketpair fd.
Socketpair,
// Read end of the pipe.
@@ -31,16 +31,16 @@ enum AnonSocketType {
PipeWrite,
}
/// One end of a pair of connected unnamed sockets.
/// One end of a pair of connected virtual sockets.
#[derive(Debug)]
struct AnonSocket {
struct VirtualSocket {
/// The buffer we are reading from, or `None` if this is the writing end of a pipe.
/// (In that case, the peer FD will be the reading end of that pipe.)
readbuf: Option<RefCell<Buffer>>,
/// The `AnonSocket` file descriptor that is our "peer", and that holds the buffer we are
/// The `VirtualSocket` file descriptor that is our "peer", and that holds the buffer we are
/// writing to. This is a weak reference because the other side may be closed before us; all
/// future writes will then trigger EPIPE.
peer_fd: OnceCell<WeakFileDescriptionRef<AnonSocket>>,
peer_fd: OnceCell<WeakFileDescriptionRef<VirtualSocket>>,
/// Indicates whether the peer has lost data when the file description is closed.
/// This flag is set to `true` if the peer's `readbuf` is non-empty at the time
/// of closure.
@@ -53,8 +53,8 @@ struct AnonSocket {
blocked_write_tid: RefCell<Vec<ThreadId>>,
/// Whether this fd is non-blocking or not.
is_nonblock: Cell<bool>,
// Differentiate between different AnonSocket fd types.
fd_type: AnonSocketType,
// Differentiate between different virtual socket fd types.
fd_type: VirtualSocketType,
}
#[derive(Debug)]
@@ -69,20 +69,30 @@ fn new() -> Self {
}
}
impl AnonSocket {
fn peer_fd(&self) -> &WeakFileDescriptionRef<AnonSocket> {
impl VirtualSocket {
fn peer_fd(&self) -> &WeakFileDescriptionRef<VirtualSocket> {
self.peer_fd.get().unwrap()
}
}
impl FileDescription for AnonSocket {
impl FileDescription for VirtualSocket {
fn name(&self) -> &'static str {
match self.fd_type {
AnonSocketType::Socketpair => "socketpair",
AnonSocketType::PipeRead | AnonSocketType::PipeWrite => "pipe",
VirtualSocketType::Socketpair => "socketpair",
VirtualSocketType::PipeRead | VirtualSocketType::PipeWrite => "pipe",
}
}
fn metadata<'tcx>(
&self,
) -> InterpResult<'tcx, Either<io::Result<std::fs::Metadata>, &'static str>> {
let mode_name = match self.fd_type {
VirtualSocketType::Socketpair => "S_IFSOCK",
VirtualSocketType::PipeRead | VirtualSocketType::PipeWrite => "S_IFIFO",
};
interp_ok(Either::Right(mode_name))
}
fn destroy<'tcx>(
self,
_self_id: FdId,
@@ -111,7 +121,7 @@ fn read<'tcx>(
ecx: &mut MiriInterpCx<'tcx>,
finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
) -> InterpResult<'tcx> {
anonsocket_read(self, ptr, len, ecx, finish)
virtual_socket_read(self, ptr, len, ecx, finish)
}
fn write<'tcx>(
@@ -122,15 +132,17 @@ fn write<'tcx>(
ecx: &mut MiriInterpCx<'tcx>,
finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
) -> InterpResult<'tcx> {
anonsocket_write(self, ptr, len, ecx, finish)
virtual_socket_write(self, ptr, len, ecx, finish)
}
fn short_fd_operations(&self) -> bool {
// Pipes guarantee that sufficiently small accesses are not broken apart:
// <https://pubs.opengroup.org/onlinepubs/9799919799/functions/write.html#tag_17_699_08>.
// For now, we don't bother checking for the size, and just entirely disable
// short accesses on pipes.
matches!(self.fd_type, AnonSocketType::Socketpair)
// Linux de-facto guarantees (or at least, applications like tokio assume [1, 2]) that
// when a read/write on a streaming socket comes back short, the kernel buffer is
// empty/full. SO we can't do short reads/writes here.
//
// [1]: https://github.com/tokio-rs/tokio/blob/6c03e03898d71eca976ee1ad8481cf112ae722ba/tokio/src/io/poll_evented.rs#L182
// [2]: https://github.com/tokio-rs/tokio/blob/6c03e03898d71eca976ee1ad8481cf112ae722ba/tokio/src/io/poll_evented.rs#L240
false
}
fn as_unix<'tcx>(&self, _ecx: &MiriInterpCx<'tcx>) -> &dyn UnixFileDescription {
@@ -145,13 +157,13 @@ fn get_flags<'tcx>(&self, ecx: &mut MiriInterpCx<'tcx>) -> InterpResult<'tcx, Sc
// fd is closed, so we need to look at the original type of this socket, not at whether
// the peer socket still exists.
match self.fd_type {
AnonSocketType::Socketpair => {
VirtualSocketType::Socketpair => {
flags |= ecx.eval_libc_i32("O_RDWR");
}
AnonSocketType::PipeRead => {
VirtualSocketType::PipeRead => {
flags |= ecx.eval_libc_i32("O_RDONLY");
}
AnonSocketType::PipeWrite => {
VirtualSocketType::PipeWrite => {
flags |= ecx.eval_libc_i32("O_WRONLY");
}
}
@@ -190,9 +202,9 @@ fn set_flags<'tcx>(
}
}
/// Write to AnonSocket based on the space available and return the written byte size.
fn anonsocket_write<'tcx>(
self_ref: FileDescriptionRef<AnonSocket>,
/// Write to VirtualSocket based on the space available and return the written byte size.
fn virtual_socket_write<'tcx>(
self_ref: FileDescriptionRef<VirtualSocket>,
ptr: Pointer,
len: usize,
ecx: &mut MiriInterpCx<'tcx>,
@@ -228,11 +240,11 @@ fn anonsocket_write<'tcx>(
// Block the current thread; only keep a weak ref for this.
let weak_self_ref = FileDescriptionRef::downgrade(&self_ref);
ecx.block_thread(
BlockReason::UnnamedSocket,
BlockReason::VirtualSocket,
None,
callback!(
@capture<'tcx> {
weak_self_ref: WeakFileDescriptionRef<AnonSocket>,
weak_self_ref: WeakFileDescriptionRef<VirtualSocket>,
ptr: Pointer,
len: usize,
finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
@@ -242,7 +254,7 @@ fn anonsocket_write<'tcx>(
// If we got unblocked, then our peer successfully upgraded its weak
// ref to us. That means we can also upgrade our weak ref.
let self_ref = weak_self_ref.upgrade().unwrap();
anonsocket_write(self_ref, ptr, len, this, finish)
virtual_socket_write(self_ref, ptr, len, this, finish)
}
),
);
@@ -266,7 +278,7 @@ fn anonsocket_write<'tcx>(
let waiting_threads = std::mem::take(&mut *peer_fd.blocked_read_tid.borrow_mut());
// FIXME: We can randomize the order of unblocking.
for thread_id in waiting_threads {
ecx.unblock_thread(thread_id, BlockReason::UnnamedSocket)?;
ecx.unblock_thread(thread_id, BlockReason::VirtualSocket)?;
}
// Notify epoll waiters: we might be no longer writable, peer might now be readable.
// The notification to the peer seems to be always sent on Linux, even if the
@@ -279,9 +291,9 @@ fn anonsocket_write<'tcx>(
interp_ok(())
}
/// Read from AnonSocket and return the number of bytes read.
fn anonsocket_read<'tcx>(
self_ref: FileDescriptionRef<AnonSocket>,
/// Read from VirtualSocket and return the number of bytes read.
fn virtual_socket_read<'tcx>(
self_ref: FileDescriptionRef<VirtualSocket>,
ptr: Pointer,
len: usize,
ecx: &mut MiriInterpCx<'tcx>,
@@ -316,11 +328,11 @@ fn anonsocket_read<'tcx>(
// Block the current thread; only keep a weak ref for this.
let weak_self_ref = FileDescriptionRef::downgrade(&self_ref);
ecx.block_thread(
BlockReason::UnnamedSocket,
BlockReason::VirtualSocket,
None,
callback!(
@capture<'tcx> {
weak_self_ref: WeakFileDescriptionRef<AnonSocket>,
weak_self_ref: WeakFileDescriptionRef<VirtualSocket>,
ptr: Pointer,
len: usize,
finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
@@ -330,7 +342,7 @@ fn anonsocket_read<'tcx>(
// If we got unblocked, then our peer successfully upgraded its weak
// ref to us. That means we can also upgrade our weak ref.
let self_ref = weak_self_ref.upgrade().unwrap();
anonsocket_read(self_ref, ptr, len, this, finish)
virtual_socket_read(self_ref, ptr, len, this, finish)
}
),
);
@@ -363,7 +375,7 @@ fn anonsocket_read<'tcx>(
let waiting_threads = std::mem::take(&mut *peer_fd.blocked_write_tid.borrow_mut());
// FIXME: We can randomize the order of unblocking.
for thread_id in waiting_threads {
ecx.unblock_thread(thread_id, BlockReason::UnnamedSocket)?;
ecx.unblock_thread(thread_id, BlockReason::VirtualSocket)?;
}
// Notify epoll waiters: peer is now writable.
// Linux seems to always notify the peer if the read buffer is now empty.
@@ -379,7 +391,7 @@ fn anonsocket_read<'tcx>(
interp_ok(())
}
impl UnixFileDescription for AnonSocket {
impl UnixFileDescription for VirtualSocket {
fn epoll_active_events<'tcx>(&self) -> InterpResult<'tcx, EpollEvents> {
// We only check the status of EPOLLIN, EPOLLOUT, EPOLLHUP and EPOLLRDHUP flags.
// If other event flags need to be supported in the future, the check should be added here.
@@ -487,23 +499,23 @@ fn socketpair(
// Generate file descriptions.
let fds = &mut this.machine.fds;
let fd0 = fds.new_ref(AnonSocket {
let fd0 = fds.new_ref(VirtualSocket {
readbuf: Some(RefCell::new(Buffer::new())),
peer_fd: OnceCell::new(),
peer_lost_data: Cell::new(false),
blocked_read_tid: RefCell::new(Vec::new()),
blocked_write_tid: RefCell::new(Vec::new()),
is_nonblock: Cell::new(is_sock_nonblock),
fd_type: AnonSocketType::Socketpair,
fd_type: VirtualSocketType::Socketpair,
});
let fd1 = fds.new_ref(AnonSocket {
let fd1 = fds.new_ref(VirtualSocket {
readbuf: Some(RefCell::new(Buffer::new())),
peer_fd: OnceCell::new(),
peer_lost_data: Cell::new(false),
blocked_read_tid: RefCell::new(Vec::new()),
blocked_write_tid: RefCell::new(Vec::new()),
is_nonblock: Cell::new(is_sock_nonblock),
fd_type: AnonSocketType::Socketpair,
fd_type: VirtualSocketType::Socketpair,
});
// Make the file descriptions point to each other.
@@ -557,23 +569,23 @@ fn pipe2(
// Generate file descriptions.
// pipefd[0] refers to the read end of the pipe.
let fds = &mut this.machine.fds;
let fd0 = fds.new_ref(AnonSocket {
let fd0 = fds.new_ref(VirtualSocket {
readbuf: Some(RefCell::new(Buffer::new())),
peer_fd: OnceCell::new(),
peer_lost_data: Cell::new(false),
blocked_read_tid: RefCell::new(Vec::new()),
blocked_write_tid: RefCell::new(Vec::new()),
is_nonblock: Cell::new(is_nonblock),
fd_type: AnonSocketType::PipeRead,
fd_type: VirtualSocketType::PipeRead,
});
let fd1 = fds.new_ref(AnonSocket {
let fd1 = fds.new_ref(VirtualSocket {
readbuf: None,
peer_fd: OnceCell::new(),
peer_lost_data: Cell::new(false),
blocked_read_tid: RefCell::new(Vec::new()),
blocked_write_tid: RefCell::new(Vec::new()),
is_nonblock: Cell::new(is_nonblock),
fd_type: AnonSocketType::PipeWrite,
fd_type: VirtualSocketType::PipeWrite,
});
// Make the file descriptions point to each other.
+14 -6
View File
@@ -22,8 +22,10 @@ fn name(&self) -> &'static str {
"directory"
}
fn metadata<'tcx>(&self) -> InterpResult<'tcx, io::Result<Metadata>> {
interp_ok(self.path.metadata())
fn metadata<'tcx>(
&self,
) -> InterpResult<'tcx, Either<io::Result<std::fs::Metadata>, &'static str>> {
interp_ok(Either::Left(self.path.metadata()))
}
fn destroy<'tcx>(
@@ -49,8 +51,10 @@ fn name(&self) -> &'static str {
"metadata-only"
}
fn metadata<'tcx>(&self) -> InterpResult<'tcx, io::Result<Metadata>> {
interp_ok(Ok(self.meta.clone()))
fn metadata<'tcx>(
&self,
) -> InterpResult<'tcx, Either<io::Result<std::fs::Metadata>, &'static str>> {
interp_ok(Either::Left(Ok(self.meta.clone())))
}
fn destroy<'tcx>(
@@ -329,11 +333,15 @@ fn GetFileInformationByHandle(
};
let metadata = match desc.metadata()? {
Ok(meta) => meta,
Err(e) => {
Either::Left(Ok(meta)) => meta,
Either::Left(Err(e)) => {
this.set_last_error(e)?;
return interp_ok(this.eval_windows("c", "FALSE"));
}
Either::Right(_mode) =>
throw_unsup_format!(
"`GetFileInformationByHandle` is not supported on non-file-backed handles"
),
};
let size = metadata.len();
+2 -2
View File
@@ -104,8 +104,8 @@ fn emulate_x86_avx512_intrinsic(
pmaddbw(this, left, right, dest)?;
}
// Used to implement the _mm512_permutexvar_epi32 function.
"permvar.si.512" => {
// Used to implement the _mm512_permutexvar_epi32/_mm512_permutexvar_epi64 functions.
"permvar.si.512" | "permvar.di.512" => {
let [left, right] =
this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
+18 -5
View File
@@ -1056,12 +1056,22 @@ fn pmaddbw<'tcx>(
interp_ok(())
}
/// Shuffle 32-bit integers in `values` across lanes using the corresponding
/// index in `indices`, and store the results in dst.
/// Shuffle elements in `values` across lanes using the corresponding index in
/// `indices`, and store the results in `dest`.
///
/// This helper is shared by both the 32-bit-lane and 64-bit-lane AVX
/// permute-by-index intrinsics. The element type is taken from `values` and
/// `dest`, while the index lanes are interpreted at their full width (`i32` or
/// `i64`, depending on the intrinsic).
///
/// For a vector with `N` lanes, only the low `log2(N)` bits of each index are
/// used. Equivalently, lane `i` of the result is copied from
/// `values[indices[i] & (N - 1)]`.
///
/// <https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_permutevar8x32_epi32>
/// <https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_permutevar8x32_ps>
/// <https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm512_permutexvar_epi32>
/// <https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm512_permutexvar_epi64>
fn permute<'tcx>(
ecx: &mut crate::MiriInterpCx<'tcx>,
values: &OpTy<'tcx>,
@@ -1075,18 +1085,21 @@ fn permute<'tcx>(
// fn permd(a: u32x8, b: u32x8) -> u32x8;
// fn permps(a: __m256, b: i32x8) -> __m256;
// fn vpermd(a: i32x16, idx: i32x16) -> i32x16;
// fn vpermq(a: i64x8, b: i64x8) -> i64x8;
assert_eq!(dest_len, values_len);
assert_eq!(dest_len, indices_len);
// Only use the lower 3 bits to index into a vector with 8 lanes,
// or the lower 4 bits when indexing into a 16-lane vector.
assert!(dest_len.is_power_of_two());
let mask = u32::try_from(dest_len).unwrap().strict_sub(1);
let mask = u128::from(dest_len).strict_sub(1);
for i in 0..dest_len {
let dest = ecx.project_index(&dest, i)?;
let index = ecx.read_scalar(&ecx.project_index(&indices, i)?)?.to_u32()?;
let element = ecx.project_index(&values, (index & mask).into())?;
let index_place = ecx.project_index(&indices, i)?;
let index = ecx.read_scalar(&index_place)?.to_uint(index_place.layout.size)?;
// `mask` is at most `dest_len - 1` which fits in a `u64`, so this cannot fail.
let element = ecx.project_index(&values, u64::try_from(index & mask).unwrap())?;
ecx.copy_op(&element, &dest)?;
}
+7 -81
View File
@@ -45,7 +45,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys 0.61.2",
"windows-sys",
]
[[package]]
@@ -281,7 +281,7 @@ checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1"
dependencies = [
"libc",
"wasi 0.11.1+wasi-snapshot-preview1",
"windows-sys 0.61.2",
"windows-sys",
]
[[package]]
@@ -298,7 +298,7 @@ dependencies = [
"page_size",
"tempfile",
"tokio",
"windows-sys 0.60.2",
"windows-sys",
]
[[package]]
@@ -383,7 +383,7 @@ dependencies = [
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.61.2",
"windows-sys",
]
[[package]]
@@ -463,7 +463,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
dependencies = [
"libc",
"windows-sys 0.61.2",
"windows-sys",
]
[[package]]
@@ -487,7 +487,7 @@ dependencies = [
"getrandom 0.4.2",
"once_cell",
"rustix",
"windows-sys 0.61.2",
"windows-sys",
]
[[package]]
@@ -503,7 +503,7 @@ dependencies = [
"signal-hook-registry",
"socket2",
"tokio-macros",
"windows-sys 0.61.2",
"windows-sys",
]
[[package]]
@@ -666,15 +666,6 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-sys"
version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-sys"
version = "0.61.2"
@@ -684,71 +675,6 @@ dependencies = [
"windows-link",
]
[[package]]
name = "windows-targets"
version = "0.53.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
dependencies = [
"windows-link",
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
[[package]]
name = "windows_aarch64_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
[[package]]
name = "windows_i686_gnu"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
[[package]]
name = "windows_i686_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
[[package]]
name = "windows_i686_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
[[package]]
name = "windows_x86_64_gnu"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
[[package]]
name = "windows_x86_64_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
[[package]]
name = "wit-bindgen"
version = "0.51.0"
+1 -1
View File
@@ -26,7 +26,7 @@ tokio = { version = "1", features = ["macros", "rt-multi-thread", "time", "net",
futures = { version = "0.3.0", default-features = false, features = ["alloc", "async-await"] }
[target.'cfg(windows)'.dependencies]
windows-sys = { version = "0.60", features = [
windows-sys = { version = "0.61", features = [
"Win32_Foundation",
"Win32_System_Threading",
"Win32_Storage_FileSystem",
@@ -0,0 +1,108 @@
//@ignore-target: windows # No libc fstat on non-file FDs on Windows
//@compile-flags: -Zmiri-disable-isolation
use std::mem::MaybeUninit;
#[path = "../../utils/libc.rs"]
mod libc_utils;
use libc_utils::errno_check;
fn main() {
test_fstat_socketpair();
test_fstat_pipe();
#[cfg(target_os = "linux")]
test_fstat_eventfd();
#[cfg(target_os = "linux")]
test_fstat_epoll();
}
/// Calls fstat and returns a reference to the result.
/// We use `assume_init_ref` rather than `assume_init` because not all fields
/// of `libc::stat` may be written by fstat (e.g. `st_lspare` on macOS).
fn do_fstat(fd: i32, buf: &mut MaybeUninit<libc::stat>) -> &libc::stat {
let res = unsafe { libc::fstat(fd, buf.as_mut_ptr()) };
assert_eq!(res, 0, "fstat failed on fd {}", fd);
unsafe { buf.assume_init_ref() }
}
fn assert_stat_fields_are_accessible(stat: &libc::stat) {
let _st_nlink = stat.st_nlink;
let _st_blksize = stat.st_blksize;
let _st_blocks = stat.st_blocks;
let _st_ino = stat.st_ino;
let _st_dev = stat.st_dev;
let _st_uid = stat.st_uid;
let _st_gid = stat.st_gid;
let _st_rdev = stat.st_rdev;
let _st_atime = stat.st_atime;
let _st_mtime = stat.st_mtime;
let _st_ctime = stat.st_ctime;
let _st_atime_nsec = stat.st_atime_nsec;
let _st_mtime_nsec = stat.st_mtime_nsec;
let _st_ctime_nsec = stat.st_ctime_nsec;
}
/// Test fstat on socketpair file descriptors.
fn test_fstat_socketpair() {
let mut fds = [0i32; 2];
errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) });
for fd in fds.iter() {
let mut buf = MaybeUninit::uninit();
let stat = do_fstat(*fd, &mut buf);
assert_eq!(
stat.st_mode & libc::S_IFMT,
libc::S_IFSOCK,
"socketpair should have S_IFSOCK mode"
);
assert_eq!(stat.st_size, 0, "socketpair should have size 0");
assert_stat_fields_are_accessible(stat);
}
errno_check(unsafe { libc::close(fds[0]) });
errno_check(unsafe { libc::close(fds[1]) });
}
/// Test fstat on pipe file descriptors.
fn test_fstat_pipe() {
let mut fds = [0i32; 2];
errno_check(unsafe { libc::pipe(fds.as_mut_ptr()) });
for fd in fds.iter() {
let mut buf = MaybeUninit::uninit();
let stat = do_fstat(*fd, &mut buf);
assert_eq!(stat.st_mode & libc::S_IFMT, libc::S_IFIFO, "pipe should have S_IFIFO mode");
assert_eq!(stat.st_size, 0, "pipe should have size 0");
assert_stat_fields_are_accessible(stat);
}
errno_check(unsafe { libc::close(fds[0]) });
errno_check(unsafe { libc::close(fds[1]) });
}
/// Test fstat on eventfd file descriptors (Linux only).
#[cfg(target_os = "linux")]
fn test_fstat_eventfd() {
let flags = libc::EFD_CLOEXEC | libc::EFD_NONBLOCK;
let fd = libc_utils::errno_result(unsafe { libc::eventfd(0, flags) }).unwrap();
let mut buf = MaybeUninit::uninit();
let stat = do_fstat(fd, &mut buf);
assert_eq!(stat.st_size, 0, "eventfd should have size 0");
assert_stat_fields_are_accessible(stat);
errno_check(unsafe { libc::close(fd) });
}
/// Test fstat on epoll file descriptors (Linux only).
#[cfg(target_os = "linux")]
fn test_fstat_epoll() {
let fd = libc_utils::errno_result(unsafe { libc::epoll_create1(libc::EPOLL_CLOEXEC) }).unwrap();
let mut buf = MaybeUninit::uninit();
let stat = do_fstat(fd, &mut buf);
assert_eq!(stat.st_size, 0, "epoll should have size 0");
assert_stat_fields_are_accessible(stat);
errno_check(unsafe { libc::close(fd) });
}
@@ -11,7 +11,6 @@
use std::time::Duration;
use libc_utils::*;
use utils::check_nondet;
const TEST_BYTES: &[u8] = b"these are some test bytes!";
@@ -36,7 +35,6 @@ fn main() {
test_accept_connect();
test_send_peek_recv();
test_partial_send_recv();
test_write_read();
test_getsockname_ipv4();
@@ -295,50 +293,6 @@ fn test_send_peek_recv() {
server_thread.join().unwrap();
}
/// Test that we actually do partial sends and partial receives for sockets.
fn test_partial_send_recv() {
let (server_sockfd, addr) = net::make_listener_ipv4().unwrap();
let client_sockfd =
unsafe { errno_result(libc::socket(libc::AF_INET, libc::SOCK_STREAM, 0)).unwrap() };
// Spawn the server thread.
let server_thread = thread::spawn(move || {
let (peerfd, _) = net::accept_ipv4(server_sockfd).unwrap();
// Yield back to client to test that we do incomplete writes.
thread::sleep(Duration::from_millis(10));
// We know the buffer contains enough bytes to test incomplete reads.
// Ensure we sometimes do incomplete reads.
check_nondet(|| {
let mut buffer = [0u8; 4];
let bytes_read =
unsafe { errno_result(libc::read(peerfd, buffer.as_mut_ptr().cast(), 4)).unwrap() };
bytes_read == 4
});
});
net::connect_ipv4(client_sockfd, addr).unwrap();
// Ensure we sometimes do incomplete writes.
check_nondet(|| {
let bytes_written =
unsafe { errno_result(libc::write(client_sockfd, [0; 4].as_ptr().cast(), 4)).unwrap() };
bytes_written == 4
});
let buffer = [0u8; 100_000];
// Write a lot of bytes into the socket such that we can test
// incomplete reads.
unsafe {
errno_result(libc_utils::write_all(client_sockfd, buffer.as_ptr().cast(), buffer.len()))
.unwrap()
};
server_thread.join().unwrap();
}
/// Test writing bytes into a connected stream and then reading them
/// from the other end.
/// We want to test this because `write` and `read` should be the same as
+3 -3
View File
@@ -185,12 +185,12 @@ fn atomic_ptr() {
}
fn weak_sometimes_fails() {
let atomic = AtomicBool::new(false);
let atomic = AtomicUsize::new(0);
let tries = 100;
for _ in 0..tries {
let cur = atomic.load(Relaxed);
// Try (weakly) to flip the flag.
if atomic.compare_exchange_weak(cur, !cur, Relaxed, Relaxed).is_err() {
// Try (weakly) to modify the flag.
if atomic.compare_exchange_weak(cur, cur + 1, Relaxed, Relaxed).is_err() {
// We failed, so return and skip the panic.
return;
}
@@ -219,6 +219,30 @@ unsafe fn test_mm512_permutexvar_epi32() {
}
test_mm512_permutexvar_epi32();
#[target_feature(enable = "avx512f")]
unsafe fn test_mm512_permutexvar_epi64() {
let a = _mm512_setr_epi64(100, 200, 300, 400, 500, 600, 700, 800);
// Mirrors stdarch's basic sanity check.
let idx = _mm512_set1_epi64(1);
let r = _mm512_permutexvar_epi64(idx, a);
let e = _mm512_set1_epi64(200);
assert_eq_m512i(r, e);
// This must permute across the full 512-bit register, not within 128-bit lanes.
let idx = _mm512_setr_epi64(7, 0, 5, 2, 6, 1, 4, 3);
let r = _mm512_permutexvar_epi64(idx, a);
let e = _mm512_setr_epi64(800, 100, 600, 300, 700, 200, 500, 400);
assert_eq_m512i(r, e);
// Only the low 3 bits of each 64-bit index are used.
let idx = _mm512_setr_epi64(8, 15, -1, i64::MIN, 0, 1, 2, 3);
let r = _mm512_permutexvar_epi64(idx, a);
let e = _mm512_setr_epi64(100, 800, 800, 100, 100, 200, 300, 400);
assert_eq_m512i(r, e);
}
test_mm512_permutexvar_epi64();
#[target_feature(enable = "avx512bw")]
unsafe fn test_mm512_shuffle_epi8() {
#[rustfmt::skip]
@@ -1,12 +1,14 @@
// Tests that the compiler suggests an `into_iter` call when an `Iterator` method
// is called on something that implements `IntoIterator`
// Tests that the compiler suggests an iterator method when an `Iterator` method
// is called on something that implements `IntoIterator`.
fn main() {
let items = items();
let other_items = items.map(|i| i + 1);
//~^ ERROR no method named `map` found for opaque type `impl IntoIterator<Item = i32>` in the current scope
//~| HELP: call `.into_iter()` first
let vec: Vec<i32> = items.collect();
//~^ ERROR no method named `collect` found for opaque type `impl IntoIterator<Item = i32>` in the current scope
//~| HELP: call `.into_iter()` first
}
fn items() -> impl IntoIterator<Item = i32> {
@@ -16,4 +18,36 @@ fn items() -> impl IntoIterator<Item = i32> {
fn process(items: impl IntoIterator<Item = String>) -> Vec<String> {
items.collect()
//~^ ERROR no method named `collect` found for type parameter `impl IntoIterator<Item = String>` in the current scope
//~| HELP: call `.into_iter()` first
}
// Regression test for https://github.com/rust-lang/rust/issues/155365
struct Demo {
contents: Vec<u32>,
}
impl Demo {
fn count_odds(&self) -> usize {
self.contents.filter(|v| *v % 2 == 1).count()
//~^ ERROR no method named `filter` found for struct `Vec<u32>` in the current scope
//~| HELP: call `.iter()` first
}
fn increment(&mut self) {
self.contents.for_each(|v| *v += 1)
//~^ ERROR no method named `for_each` found for struct `Vec<u32>` in the current scope
//~| HELP: call `.iter_mut()` first
}
}
fn count_odds_param(contents: &Vec<u32>) -> usize {
contents.filter(|v| *v % 2 == 1).count()
//~^ ERROR no method named `filter` found for reference `&Vec<u32>` in the current scope
//~| HELP: call `.into_iter()` first
}
fn count_odds_explicit_deref(contents: &Vec<u32>) -> usize {
(*contents).filter(|v| *v % 2 == 1).count()
//~^ ERROR no method named `filter` found for struct `Vec<u32>` in the current scope
//~| HELP: call `.iter()` first
}
@@ -10,7 +10,7 @@ LL | let other_items = items.into_iter().map(|i| i + 1);
| ++++++++++++
error[E0599]: no method named `collect` found for opaque type `impl IntoIterator<Item = i32>` in the current scope
--> $DIR/collect-without-into-iter-call.rs:8:31
--> $DIR/collect-without-into-iter-call.rs:9:31
|
LL | let vec: Vec<i32> = items.collect();
| ^^^^^^^ `impl IntoIterator<Item = i32>` is not an iterator
@@ -21,7 +21,7 @@ LL | let vec: Vec<i32> = items.into_iter().collect();
| ++++++++++++
error[E0599]: no method named `collect` found for type parameter `impl IntoIterator<Item = String>` in the current scope
--> $DIR/collect-without-into-iter-call.rs:17:11
--> $DIR/collect-without-into-iter-call.rs:19:11
|
LL | items.collect()
| ^^^^^^^ `impl IntoIterator<Item = String>` is not an iterator
@@ -31,6 +31,50 @@ help: call `.into_iter()` first
LL | items.into_iter().collect()
| ++++++++++++
error: aborting due to 3 previous errors
error[E0599]: no method named `filter` found for struct `Vec<u32>` in the current scope
--> $DIR/collect-without-into-iter-call.rs:31:23
|
LL | self.contents.filter(|v| *v % 2 == 1).count()
| ^^^^^^ `Vec<u32>` is not an iterator
|
help: call `.iter()` first
|
LL | self.contents.iter().filter(|v| *v % 2 == 1).count()
| +++++++
error[E0599]: no method named `for_each` found for struct `Vec<u32>` in the current scope
--> $DIR/collect-without-into-iter-call.rs:37:23
|
LL | self.contents.for_each(|v| *v += 1)
| ^^^^^^^^ `Vec<u32>` is not an iterator
|
help: call `.iter_mut()` first
|
LL | self.contents.iter_mut().for_each(|v| *v += 1)
| +++++++++++
error[E0599]: no method named `filter` found for reference `&Vec<u32>` in the current scope
--> $DIR/collect-without-into-iter-call.rs:44:14
|
LL | contents.filter(|v| *v % 2 == 1).count()
| ^^^^^^ `&Vec<u32>` is not an iterator
|
help: call `.into_iter()` first
|
LL | contents.into_iter().filter(|v| *v % 2 == 1).count()
| ++++++++++++
error[E0599]: no method named `filter` found for struct `Vec<u32>` in the current scope
--> $DIR/collect-without-into-iter-call.rs:50:17
|
LL | (*contents).filter(|v| *v % 2 == 1).count()
| ^^^^^^ `Vec<u32>` is not an iterator
|
help: call `.iter()` first
|
LL | (*contents).iter().filter(|v| *v % 2 == 1).count()
| +++++++
error: aborting due to 7 previous errors
For more information about this error, try `rustc --explain E0599`.
@@ -1,5 +1,4 @@
#![feature(impl_restriction)]
#![expect(incomplete_features)]
pub impl(crate) trait TopLevel {}
@@ -3,7 +3,6 @@
//@[with_gate] check-pass
#![cfg_attr(with_gate, feature(impl_restriction))]
#![cfg_attr(with_gate, allow(incomplete_features))]
#![feature(auto_traits, const_trait_impl)]
pub impl(crate) trait Bar {} //[without_gate]~ ERROR `impl` restrictions are experimental
@@ -1,5 +1,5 @@
error[E0658]: `impl` restrictions are experimental
--> $DIR/feature-gate-impl-restriction.rs:9:5
--> $DIR/feature-gate-impl-restriction.rs:8:5
|
LL | pub impl(crate) trait Bar {}
| ^^^^^^^^^^^
@@ -9,7 +9,7 @@ LL | pub impl(crate) trait Bar {}
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: `impl` restrictions are experimental
--> $DIR/feature-gate-impl-restriction.rs:10:5
--> $DIR/feature-gate-impl-restriction.rs:9:5
|
LL | pub impl(in crate) trait BarInCrate {}
| ^^^^^^^^^^^^^^
@@ -19,7 +19,7 @@ LL | pub impl(in crate) trait BarInCrate {}
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: `impl` restrictions are experimental
--> $DIR/feature-gate-impl-restriction.rs:13:9
--> $DIR/feature-gate-impl-restriction.rs:12:9
|
LL | pub impl(in crate::foo) trait Baz {}
| ^^^^^^^^^^^^^^^^^^^
@@ -29,7 +29,7 @@ LL | pub impl(in crate::foo) trait Baz {}
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: `impl` restrictions are experimental
--> $DIR/feature-gate-impl-restriction.rs:14:9
--> $DIR/feature-gate-impl-restriction.rs:13:9
|
LL | pub impl(super) unsafe trait BazUnsafeSuper {}
| ^^^^^^^^^^^
@@ -39,7 +39,7 @@ LL | pub impl(super) unsafe trait BazUnsafeSuper {}
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: `impl` restrictions are experimental
--> $DIR/feature-gate-impl-restriction.rs:15:9
--> $DIR/feature-gate-impl-restriction.rs:14:9
|
LL | pub impl(self) auto trait BazAutoSelf {}
| ^^^^^^^^^^
@@ -49,7 +49,7 @@ LL | pub impl(self) auto trait BazAutoSelf {}
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: `impl` restrictions are experimental
--> $DIR/feature-gate-impl-restriction.rs:16:9
--> $DIR/feature-gate-impl-restriction.rs:15:9
|
LL | pub impl(in self) const trait BazConst {}
| ^^^^^^^^^^^^^
@@ -59,7 +59,7 @@ LL | pub impl(in self) const trait BazConst {}
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: `impl` restrictions are experimental
--> $DIR/feature-gate-impl-restriction.rs:19:13
--> $DIR/feature-gate-impl-restriction.rs:18:13
|
LL | pub impl(in crate::foo::foo_inner) trait Qux {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -69,7 +69,7 @@ LL | pub impl(in crate::foo::foo_inner) trait Qux {}
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: `impl` restrictions are experimental
--> $DIR/feature-gate-impl-restriction.rs:20:13
--> $DIR/feature-gate-impl-restriction.rs:19:13
|
LL | ... pub impl(in crate::foo::foo_inner) unsafe auto trait QuxAutoUnsafe {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -79,7 +79,7 @@ LL | ... pub impl(in crate::foo::foo_inner) unsafe auto trait QuxAutoUnsafe {}
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: `impl` restrictions are experimental
--> $DIR/feature-gate-impl-restriction.rs:21:13
--> $DIR/feature-gate-impl-restriction.rs:20:13
|
LL | ... pub impl(in crate::foo::foo_inner) const unsafe trait QuxConstUnsafe {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -89,7 +89,7 @@ LL | ... pub impl(in crate::foo::foo_inner) const unsafe trait QuxConstUnsafe
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: `impl` restrictions are experimental
--> $DIR/feature-gate-impl-restriction.rs:25:9
--> $DIR/feature-gate-impl-restriction.rs:24:9
|
LL | pub impl(crate) trait Bar {}
| ^^^^^^^^^^^
@@ -99,7 +99,7 @@ LL | pub impl(crate) trait Bar {}
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: `impl` restrictions are experimental
--> $DIR/feature-gate-impl-restriction.rs:27:9
--> $DIR/feature-gate-impl-restriction.rs:26:9
|
LL | pub impl(in crate) trait BarInCrate {}
| ^^^^^^^^^^^^^^
@@ -109,7 +109,7 @@ LL | pub impl(in crate) trait BarInCrate {}
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: `impl` restrictions are experimental
--> $DIR/feature-gate-impl-restriction.rs:29:9
--> $DIR/feature-gate-impl-restriction.rs:28:9
|
LL | pub impl(self) unsafe trait BazUnsafeSelf {}
| ^^^^^^^^^^
@@ -119,7 +119,7 @@ LL | pub impl(self) unsafe trait BazUnsafeSelf {}
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: `impl` restrictions are experimental
--> $DIR/feature-gate-impl-restriction.rs:31:9
--> $DIR/feature-gate-impl-restriction.rs:30:9
|
LL | pub impl(in super) auto trait BazAutoSuper {}
| ^^^^^^^^^^^^^^
@@ -129,7 +129,7 @@ LL | pub impl(in super) auto trait BazAutoSuper {}
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: `impl` restrictions are experimental
--> $DIR/feature-gate-impl-restriction.rs:33:9
--> $DIR/feature-gate-impl-restriction.rs:32:9
|
LL | pub impl(super) const trait BazConstSuper {}
| ^^^^^^^^^^^
@@ -139,7 +139,7 @@ LL | pub impl(super) const trait BazConstSuper {}
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: `impl` restrictions are experimental
--> $DIR/feature-gate-impl-restriction.rs:37:13
--> $DIR/feature-gate-impl-restriction.rs:36:13
|
LL | pub impl(in crate::foo::cfged_out_foo) trait CfgedOutQux {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -149,7 +149,7 @@ LL | pub impl(in crate::foo::cfged_out_foo) trait CfgedOutQux {}
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: `impl` restrictions are experimental
--> $DIR/feature-gate-impl-restriction.rs:38:13
--> $DIR/feature-gate-impl-restriction.rs:37:13
|
LL | ... pub impl(in crate::foo::cfged_out_foo) unsafe auto trait CfgedOutQuxUnsafeAuto {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -159,7 +159,7 @@ LL | ... pub impl(in crate::foo::cfged_out_foo) unsafe auto trait CfgedOutQuxU
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: `impl` restrictions are experimental
--> $DIR/feature-gate-impl-restriction.rs:39:13
--> $DIR/feature-gate-impl-restriction.rs:38:13
|
LL | ... pub impl(in crate::foo::cfged_out_foo) const unsafe trait CfgedOutQuxConstUnsafe {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1,95 +1,95 @@
error: trait cannot be implemented outside `external`
--> $DIR/impl-restriction-check.rs:12:1
--> $DIR/impl-restriction-check.rs:11:1
|
LL | impl external::TopLevel for LocalType {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: trait restricted here
--> $DIR/auxiliary/external-impl-restriction.rs:4:5
--> $DIR/auxiliary/external-impl-restriction.rs:3:5
|
LL | pub impl(crate) trait TopLevel {}
| ^^^^^^^^^^^
error: trait cannot be implemented outside `external`
--> $DIR/impl-restriction-check.rs:13:1
--> $DIR/impl-restriction-check.rs:12:1
|
LL | impl external::inner::Inner for LocalType {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: trait restricted here
--> $DIR/auxiliary/external-impl-restriction.rs:7:9
--> $DIR/auxiliary/external-impl-restriction.rs:6:9
|
LL | pub impl(self) trait Inner {}
| ^^^^^^^^^^
error: trait cannot be implemented outside `foo::bar`
--> $DIR/impl-restriction-check.rs:30:5
--> $DIR/impl-restriction-check.rs:29:5
|
LL | impl bar::Foo for i8 {}
| ^^^^^^^^^^^^^^^^^^^^
|
note: trait restricted here
--> $DIR/impl-restriction-check.rs:17:20
--> $DIR/impl-restriction-check.rs:16:20
|
LL | pub(crate) impl(self) trait Foo {}
| ^^^^^^^^^^
error: trait cannot be implemented outside `foo::bar`
--> $DIR/impl-restriction-check.rs:39:1
--> $DIR/impl-restriction-check.rs:38:1
|
LL | impl foo::bar::Foo for u8 {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: trait restricted here
--> $DIR/impl-restriction-check.rs:17:20
--> $DIR/impl-restriction-check.rs:16:20
|
LL | pub(crate) impl(self) trait Foo {}
| ^^^^^^^^^^
error: trait cannot be implemented outside `foo`
--> $DIR/impl-restriction-check.rs:41:1
--> $DIR/impl-restriction-check.rs:40:1
|
LL | impl foo::bar::Bar for u8 {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: trait restricted here
--> $DIR/impl-restriction-check.rs:18:20
--> $DIR/impl-restriction-check.rs:17:20
|
LL | pub(crate) impl(super) trait Bar {}
| ^^^^^^^^^^^
error: trait cannot be implemented outside `foo::bar`
--> $DIR/impl-restriction-check.rs:34:5
--> $DIR/impl-restriction-check.rs:33:5
|
LL | impl bar::Qux for i8 {}
| ^^^^^^^^^^^^^^^^^^^^
|
note: trait restricted here
--> $DIR/impl-restriction-check.rs:20:20
--> $DIR/impl-restriction-check.rs:19:20
|
LL | pub(crate) impl(in crate::foo::bar) trait Qux {}
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: trait cannot be implemented outside `foo::bar`
--> $DIR/impl-restriction-check.rs:44:1
--> $DIR/impl-restriction-check.rs:43:1
|
LL | impl foo::bar::Qux for u8 {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: trait restricted here
--> $DIR/impl-restriction-check.rs:20:20
--> $DIR/impl-restriction-check.rs:19:20
|
LL | pub(crate) impl(in crate::foo::bar) trait Qux {}
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: trait cannot be implemented outside `foo`
--> $DIR/impl-restriction-check.rs:46:1
--> $DIR/impl-restriction-check.rs:45:1
|
LL | impl foo::bar::FooBar for u8 {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: trait restricted here
--> $DIR/impl-restriction-check.rs:21:20
--> $DIR/impl-restriction-check.rs:20:20
|
LL | pub(crate) impl(in crate::foo) trait FooBar {}
| ^^^^^^^^^^^^^^^^^^^
@@ -1,95 +1,95 @@
error: trait cannot be implemented outside `external`
--> $DIR/impl-restriction-check.rs:12:1
--> $DIR/impl-restriction-check.rs:11:1
|
LL | impl external::TopLevel for LocalType {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: trait restricted here
--> $DIR/auxiliary/external-impl-restriction.rs:4:5
--> $DIR/auxiliary/external-impl-restriction.rs:3:5
|
LL | pub impl(crate) trait TopLevel {}
| ^^^^^^^^^^^
error: trait cannot be implemented outside `external`
--> $DIR/impl-restriction-check.rs:13:1
--> $DIR/impl-restriction-check.rs:12:1
|
LL | impl external::inner::Inner for LocalType {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: trait restricted here
--> $DIR/auxiliary/external-impl-restriction.rs:7:9
--> $DIR/auxiliary/external-impl-restriction.rs:6:9
|
LL | pub impl(self) trait Inner {}
| ^^^^^^^^^^
error: trait cannot be implemented outside `crate::foo::bar`
--> $DIR/impl-restriction-check.rs:30:5
--> $DIR/impl-restriction-check.rs:29:5
|
LL | impl bar::Foo for i8 {}
| ^^^^^^^^^^^^^^^^^^^^
|
note: trait restricted here
--> $DIR/impl-restriction-check.rs:17:20
--> $DIR/impl-restriction-check.rs:16:20
|
LL | pub(crate) impl(self) trait Foo {}
| ^^^^^^^^^^
error: trait cannot be implemented outside `crate::foo::bar`
--> $DIR/impl-restriction-check.rs:39:1
--> $DIR/impl-restriction-check.rs:38:1
|
LL | impl foo::bar::Foo for u8 {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: trait restricted here
--> $DIR/impl-restriction-check.rs:17:20
--> $DIR/impl-restriction-check.rs:16:20
|
LL | pub(crate) impl(self) trait Foo {}
| ^^^^^^^^^^
error: trait cannot be implemented outside `crate::foo`
--> $DIR/impl-restriction-check.rs:41:1
--> $DIR/impl-restriction-check.rs:40:1
|
LL | impl foo::bar::Bar for u8 {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: trait restricted here
--> $DIR/impl-restriction-check.rs:18:20
--> $DIR/impl-restriction-check.rs:17:20
|
LL | pub(crate) impl(super) trait Bar {}
| ^^^^^^^^^^^
error: trait cannot be implemented outside `crate::foo::bar`
--> $DIR/impl-restriction-check.rs:34:5
--> $DIR/impl-restriction-check.rs:33:5
|
LL | impl bar::Qux for i8 {}
| ^^^^^^^^^^^^^^^^^^^^
|
note: trait restricted here
--> $DIR/impl-restriction-check.rs:20:20
--> $DIR/impl-restriction-check.rs:19:20
|
LL | pub(crate) impl(in crate::foo::bar) trait Qux {}
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: trait cannot be implemented outside `crate::foo::bar`
--> $DIR/impl-restriction-check.rs:44:1
--> $DIR/impl-restriction-check.rs:43:1
|
LL | impl foo::bar::Qux for u8 {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: trait restricted here
--> $DIR/impl-restriction-check.rs:20:20
--> $DIR/impl-restriction-check.rs:19:20
|
LL | pub(crate) impl(in crate::foo::bar) trait Qux {}
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: trait cannot be implemented outside `crate::foo`
--> $DIR/impl-restriction-check.rs:46:1
--> $DIR/impl-restriction-check.rs:45:1
|
LL | impl foo::bar::FooBar for u8 {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: trait restricted here
--> $DIR/impl-restriction-check.rs:21:20
--> $DIR/impl-restriction-check.rs:20:20
|
LL | pub(crate) impl(in crate::foo) trait FooBar {}
| ^^^^^^^^^^^^^^^^^^^
@@ -3,7 +3,6 @@
//@ [e2015] edition: 2015
//@ [e2018] edition: 2018..
#![feature(impl_restriction)]
#![expect(incomplete_features)]
extern crate external_impl_restriction as external;
@@ -1,5 +1,4 @@
#![feature(impl_restriction, auto_traits, const_trait_impl)]
#![expect(incomplete_features)]
mod foo {
pub impl(crate::foo) trait Baz {} //~ ERROR incorrect `impl` restriction
@@ -1,5 +1,5 @@
error: incorrect `impl` restriction
--> $DIR/recover-incorrect-impl-restriction.rs:5:14
--> $DIR/recover-incorrect-impl-restriction.rs:4:14
|
LL | pub impl(crate::foo) trait Baz {}
| ^^^^^^^^^^
@@ -15,7 +15,7 @@ LL | pub impl(in crate::foo) trait Baz {}
| ++
error: incorrect `impl` restriction
--> $DIR/recover-incorrect-impl-restriction.rs:6:14
--> $DIR/recover-incorrect-impl-restriction.rs:5:14
|
LL | pub impl(crate::foo) unsafe trait BazUnsafe {}
| ^^^^^^^^^^
@@ -31,7 +31,7 @@ LL | pub impl(in crate::foo) unsafe trait BazUnsafe {}
| ++
error: incorrect `impl` restriction
--> $DIR/recover-incorrect-impl-restriction.rs:7:14
--> $DIR/recover-incorrect-impl-restriction.rs:6:14
|
LL | pub impl(crate::foo) auto trait BazAuto {}
| ^^^^^^^^^^
@@ -47,7 +47,7 @@ LL | pub impl(in crate::foo) auto trait BazAuto {}
| ++
error: incorrect `impl` restriction
--> $DIR/recover-incorrect-impl-restriction.rs:8:14
--> $DIR/recover-incorrect-impl-restriction.rs:7:14
|
LL | pub impl(crate::foo) const trait BazConst {}
| ^^^^^^^^^^
@@ -63,7 +63,7 @@ LL | pub impl(in crate::foo) const trait BazConst {}
| ++
error: incorrect `impl` restriction
--> $DIR/recover-incorrect-impl-restriction.rs:9:14
--> $DIR/recover-incorrect-impl-restriction.rs:8:14
|
LL | pub impl(crate::foo) const unsafe trait BazConstUnsafe {}
| ^^^^^^^^^^
@@ -79,7 +79,7 @@ LL | pub impl(in crate::foo) const unsafe trait BazConstUnsafe {}
| ++
error: incorrect `impl` restriction
--> $DIR/recover-incorrect-impl-restriction.rs:10:14
--> $DIR/recover-incorrect-impl-restriction.rs:9:14
|
LL | pub impl(crate::foo) unsafe auto trait BazUnsafeAuto {}
| ^^^^^^^^^^
@@ -95,7 +95,7 @@ LL | pub impl(in crate::foo) unsafe auto trait BazUnsafeAuto {}
| ++
error: expected one of `for`, `where`, or `{`, found keyword `trait`
--> $DIR/recover-incorrect-impl-restriction.rs:17:33
--> $DIR/recover-incorrect-impl-restriction.rs:16:33
|
LL | pub unsafe impl(crate::foo) trait BadOrder1 {}
| ^^^^^ expected one of `for`, `where`, or `{`
@@ -1,6 +1,5 @@
//@ aux-build: external-impl-restriction.rs
#![feature(impl_restriction)]
#![expect(incomplete_features)]
extern crate external_impl_restriction as external;
@@ -1,77 +1,77 @@
error: trait implementation can only be restricted to ancestor modules
--> $DIR/restriction_resolution_errors.rs:17:21
--> $DIR/restriction_resolution_errors.rs:16:21
|
LL | pub impl(in ::std) trait T2 {}
| ^^^^^
error: trait implementation can only be restricted to ancestor modules
--> $DIR/restriction_resolution_errors.rs:19:21
--> $DIR/restriction_resolution_errors.rs:18:21
|
LL | pub impl(in self::c) trait T3 {}
| ^^^^^^^
error: trait implementation can only be restricted to ancestor modules
--> $DIR/restriction_resolution_errors.rs:21:21
--> $DIR/restriction_resolution_errors.rs:20:21
|
LL | pub impl(in super::d) trait T4 {}
| ^^^^^^^^
error[E0433]: too many leading `super` keywords
--> $DIR/restriction_resolution_errors.rs:27:35
--> $DIR/restriction_resolution_errors.rs:26:35
|
LL | pub impl(in super::super::super) trait T7 {}
| ^^^^^ there are too many leading `super` keywords
error: trait implementation can only be restricted to ancestor modules
--> $DIR/restriction_resolution_errors.rs:37:21
--> $DIR/restriction_resolution_errors.rs:36:21
|
LL | pub impl(in self::f) trait L1 {}
| ^^^^^^^
error: trait implementation can only be restricted to ancestor modules
--> $DIR/restriction_resolution_errors.rs:41:21
--> $DIR/restriction_resolution_errors.rs:40:21
|
LL | pub impl(in super::h) trait L3 {}
| ^^^^^^^^
error: trait implementation can only be restricted to ancestor modules
--> $DIR/restriction_resolution_errors.rs:50:13
--> $DIR/restriction_resolution_errors.rs:49:13
|
LL | pub impl(in crate::a) trait T13 {}
| ^^^^^^^^
error[E0433]: too many leading `super` keywords
--> $DIR/restriction_resolution_errors.rs:57:10
--> $DIR/restriction_resolution_errors.rs:56:10
|
LL | pub impl(super) trait T17 {}
| ^^^^^ there are too many leading `super` keywords
error: trait implementation can only be restricted to ancestor modules
--> $DIR/restriction_resolution_errors.rs:59:13
--> $DIR/restriction_resolution_errors.rs:58:13
|
LL | pub impl(in external) trait T18 {}
| ^^^^^^^^
error: trait implementation can only be restricted to ancestor modules
--> $DIR/restriction_resolution_errors.rs:62:13
--> $DIR/restriction_resolution_errors.rs:61:13
|
LL | pub impl(in crate::j) trait L4 {}
| ^^^^^^^^
error: trait implementation can only be restricted to ancestor modules
--> $DIR/restriction_resolution_errors.rs:78:21
--> $DIR/restriction_resolution_errors.rs:77:21
|
LL | pub impl(in crate::m2) trait U2 {}
| ^^^^^^^^^
error: trait implementation can only be restricted to ancestor modules
--> $DIR/restriction_resolution_errors.rs:80:21
--> $DIR/restriction_resolution_errors.rs:79:21
|
LL | pub impl(in m6::m5) trait U4 {}
| ^^^^^^
error[E0433]: cannot find module or crate `a` in this scope
--> $DIR/restriction_resolution_errors.rs:15:21
--> $DIR/restriction_resolution_errors.rs:14:21
|
LL | pub impl(in a::b) trait T1 {}
| ^ use of unresolved module or unlinked crate `a`
@@ -87,25 +87,25 @@ LL + use a;
|
error[E0433]: cannot find module `c` in the crate root
--> $DIR/restriction_resolution_errors.rs:23:28
--> $DIR/restriction_resolution_errors.rs:22:28
|
LL | pub impl(in crate::c) trait T5 {}
| ^ not found in the crate root
error[E0577]: expected module, found enum `super::E`
--> $DIR/restriction_resolution_errors.rs:25:21
--> $DIR/restriction_resolution_errors.rs:24:21
|
LL | pub impl(in super::E) trait T6 {}
| ^^^^^^^^ not a module
error[E0577]: expected module, found enum `super::G`
--> $DIR/restriction_resolution_errors.rs:39:21
--> $DIR/restriction_resolution_errors.rs:38:21
|
LL | pub impl(in super::G) trait L2 {}
| ^^^^^^^^ not a module
error[E0577]: expected module, found enum `crate::a::E`
--> $DIR/restriction_resolution_errors.rs:52:13
--> $DIR/restriction_resolution_errors.rs:51:13
|
LL | pub mod b {
| --------- similarly named module `b` defined here
@@ -120,7 +120,7 @@ LL + pub impl(in crate::a::b) trait T14 {}
|
error[E0577]: expected module, found enum `crate::I`
--> $DIR/restriction_resolution_errors.rs:64:13
--> $DIR/restriction_resolution_errors.rs:63:13
|
LL | pub mod a {
| --------- similarly named module `a` defined here
@@ -135,7 +135,7 @@ LL + pub impl(in crate::a) trait L5 {}
|
error[E0577]: expected module, found enum `m7`
--> $DIR/restriction_resolution_errors.rs:81:21
--> $DIR/restriction_resolution_errors.rs:80:21
|
LL | pub impl(in m7) trait U5 {}
| ^^ not a module
@@ -1,5 +1,4 @@
#![feature(impl_restriction, auto_traits, const_trait_impl, trait_alias)]
#![expect(incomplete_features)]
impl(crate) trait Alias = Copy; //~ ERROR trait aliases cannot be `impl`-restricted
impl(in crate) auto trait AutoAlias = Copy; //~ ERROR trait aliases cannot be `impl`-restricted
@@ -1,71 +1,71 @@
error: trait aliases cannot be `impl`-restricted
--> $DIR/trait-alias-cannot-be-impl-restricted.rs:4:1
--> $DIR/trait-alias-cannot-be-impl-restricted.rs:3:1
|
LL | impl(crate) trait Alias = Copy;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted
error: trait aliases cannot be `auto`
--> $DIR/trait-alias-cannot-be-impl-restricted.rs:5:1
--> $DIR/trait-alias-cannot-be-impl-restricted.rs:4:1
|
LL | impl(in crate) auto trait AutoAlias = Copy;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `auto`
error: trait aliases cannot be `impl`-restricted
--> $DIR/trait-alias-cannot-be-impl-restricted.rs:5:1
--> $DIR/trait-alias-cannot-be-impl-restricted.rs:4:1
|
LL | impl(in crate) auto trait AutoAlias = Copy;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted
error: trait aliases cannot be `unsafe`
--> $DIR/trait-alias-cannot-be-impl-restricted.rs:7:1
--> $DIR/trait-alias-cannot-be-impl-restricted.rs:6:1
|
LL | impl(self) unsafe trait UnsafeAlias = Copy;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `unsafe`
error: trait aliases cannot be `impl`-restricted
--> $DIR/trait-alias-cannot-be-impl-restricted.rs:7:1
--> $DIR/trait-alias-cannot-be-impl-restricted.rs:6:1
|
LL | impl(self) unsafe trait UnsafeAlias = Copy;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted
error: trait aliases cannot be `impl`-restricted
--> $DIR/trait-alias-cannot-be-impl-restricted.rs:9:1
--> $DIR/trait-alias-cannot-be-impl-restricted.rs:8:1
|
LL | impl(in self) const trait ConstAlias = Copy;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted
error: trait aliases cannot be `impl`-restricted
--> $DIR/trait-alias-cannot-be-impl-restricted.rs:12:5
--> $DIR/trait-alias-cannot-be-impl-restricted.rs:11:5
|
LL | impl(super) trait InnerAlias = Copy;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted
error: trait aliases cannot be `unsafe`
--> $DIR/trait-alias-cannot-be-impl-restricted.rs:13:5
--> $DIR/trait-alias-cannot-be-impl-restricted.rs:12:5
|
LL | impl(in crate::foo) const unsafe trait InnerConstUnsafeAlias = Copy;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `unsafe`
error: trait aliases cannot be `impl`-restricted
--> $DIR/trait-alias-cannot-be-impl-restricted.rs:13:5
--> $DIR/trait-alias-cannot-be-impl-restricted.rs:12:5
|
LL | impl(in crate::foo) const unsafe trait InnerConstUnsafeAlias = Copy;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted
error: trait aliases cannot be `auto`
--> $DIR/trait-alias-cannot-be-impl-restricted.rs:15:5
--> $DIR/trait-alias-cannot-be-impl-restricted.rs:14:5
|
LL | impl(in crate::foo) unsafe auto trait InnerUnsafeAutoAlias = Copy;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `auto`
error: trait aliases cannot be `unsafe`
--> $DIR/trait-alias-cannot-be-impl-restricted.rs:15:5
--> $DIR/trait-alias-cannot-be-impl-restricted.rs:14:5
|
LL | impl(in crate::foo) unsafe auto trait InnerUnsafeAutoAlias = Copy;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `unsafe`
error: trait aliases cannot be `impl`-restricted
--> $DIR/trait-alias-cannot-be-impl-restricted.rs:15:5
--> $DIR/trait-alias-cannot-be-impl-restricted.rs:14:5
|
LL | impl(in crate::foo) unsafe auto trait InnerUnsafeAutoAlias = Copy;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait aliases cannot be `impl`-restricted
@@ -27,6 +27,8 @@ fn main() {
//~^^ ERROR AsyncFnOnce()` is not satisfied
//~^^^ ERROR AsyncFnOnce()` is not satisfied
//~^^^^ ERROR AsyncFnOnce()` is not satisfied
//~^^^^^ ERROR AsyncFnOnce()` is not satisfied
//~^^^^^^ ERROR AsyncFnOnce()` is not satisfied
x.poll(&mut Context::from_waker(Waker::noop()));
//~^ ERROR AsyncFnOnce()` is not satisfied
}
@@ -49,7 +49,31 @@ LL | async fn call_async_once(f: impl AsyncFnOnce()) {
| ^^^^^^^^^^^^^ required by this bound in `call_async_once`
error[E0277]: the trait bound `{gen closure@$DIR/iter-macro-not-async-closure.rs:19:21: 19:28}: AsyncFnOnce()` is not satisfied
--> $DIR/iter-macro-not-async-closure.rs:30:5
--> $DIR/iter-macro-not-async-closure.rs:25:13
|
LL | let x = pin!(call_async_once(f));
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsyncFnOnce()` is not implemented for `{gen closure@$DIR/iter-macro-not-async-closure.rs:19:21: 19:28}`
|
note: required by a bound in `call_async_once`
--> $DIR/iter-macro-not-async-closure.rs:14:34
|
LL | async fn call_async_once(f: impl AsyncFnOnce()) {
| ^^^^^^^^^^^^^ required by this bound in `call_async_once`
error[E0277]: the trait bound `{gen closure@$DIR/iter-macro-not-async-closure.rs:19:21: 19:28}: AsyncFnOnce()` is not satisfied
--> $DIR/iter-macro-not-async-closure.rs:25:13
|
LL | let x = pin!(call_async_once(f));
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsyncFnOnce()` is not implemented for `{gen closure@$DIR/iter-macro-not-async-closure.rs:19:21: 19:28}`
|
note: required by a bound in `call_async_once`
--> $DIR/iter-macro-not-async-closure.rs:14:34
|
LL | async fn call_async_once(f: impl AsyncFnOnce()) {
| ^^^^^^^^^^^^^ required by this bound in `call_async_once`
error[E0277]: the trait bound `{gen closure@$DIR/iter-macro-not-async-closure.rs:19:21: 19:28}: AsyncFnOnce()` is not satisfied
--> $DIR/iter-macro-not-async-closure.rs:32:5
|
LL | x.poll(&mut Context::from_waker(Waker::noop()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsyncFnOnce()` is not implemented for `{gen closure@$DIR/iter-macro-not-async-closure.rs:19:21: 19:28}`
@@ -60,6 +84,6 @@ note: required by a bound in `call_async_once`
LL | async fn call_async_once(f: impl AsyncFnOnce()) {
| ^^^^^^^^^^^^^ required by this bound in `call_async_once`
error: aborting due to 5 previous errors
error: aborting due to 7 previous errors
For more information about this error, try `rustc --explain E0277`.
@@ -2,9 +2,9 @@
fn main() {
let s = "123";
println!("{:?} {} {}", {}, "sss", s);
println!("{:?} {} {}", "{}", "sss", s);
//~^ ERROR format argument must be a string literal
println!("{:?}", {});
println!("{:?}", "{}");
//~^ ERROR format argument must be a string literal
println!("{} {} {} {:?}", s, "sss", s, {});
//~^ ERROR format argument must be a string literal
@@ -8,6 +8,11 @@ help: you might be missing a string literal to format with
|
LL | println!("{:?} {} {}", {}, "sss", s);
| +++++++++++++
help: you might want to enclose `{}` with `""`
|
LL - println!({}, "sss", s);
LL + println!("{}", "sss", s);
|
error: format argument must be a string literal
--> $DIR/format-empty-block-unit-tuple-suggestion-130170.rs:7:14
@@ -19,6 +24,11 @@ help: you might be missing a string literal to format with
|
LL | println!("{:?}", {});
| +++++++
help: you might want to enclose `{}` with `""`
|
LL - println!({});
LL + println!("{}");
|
error: format argument must be a string literal
--> $DIR/format-empty-block-unit-tuple-suggestion-130170.rs:9:14
@@ -16,18 +16,28 @@ macro_rules! post_expansion {
($a:literal) => {
const _: () = ${concat("hi", $a, "bye")};
//~^ ERROR is not generating a valid identifier
//~| NOTE this `${concat(..)}` invocation generated `hi!bye`, but '!' is not XID_Continue
//~| NOTE see <https://doc.rust-lang.org/reference/identifiers.html> for the definition of valid identifiers
}
}
post_expansion!("!");
//~^ NOTE in this expansion of post_expansion!
//~| NOTE in this expansion of post_expansion!
//~| NOTE in this expansion of post_expansion!
macro_rules! post_expansion_many {
($a:ident, $b:ident, $c:ident, $d:literal, $e:ident) => {
const _: () = ${concat($a, $b, $c, $d, $e)};
//~^ ERROR is not generating a valid identifier
//~| NOTE this `${concat(..)}` invocation generated `abc.de`, but '.' is not XID_Continue
//~| NOTE see <https://doc.rust-lang.org/reference/identifiers.html> for the definition of valid identifiers
}
}
post_expansion_many!(a, b, c, ".d", e);
//~^ NOTE in this expansion of post_expansion_many!
//~| NOTE in this expansion of post_expansion_many!
//~| NOTE in this expansion of post_expansion_many!
fn main() {}
@@ -7,10 +7,12 @@ LL | const _: () = ${concat("hi", $a, "bye")};
LL | post_expansion!("!");
| -------------------- in this macro invocation
|
= note: this `${concat(..)}` invocation generated `hi!bye`, but '!' is not XID_Continue
= note: see <https://doc.rust-lang.org/reference/identifiers.html> for the definition of valid identifiers
= note: this error originates in the macro `post_expansion` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `${concat(..)}` is not generating a valid identifier
--> $DIR/concat-trace-errors.rs:26:24
--> $DIR/concat-trace-errors.rs:31:24
|
LL | const _: () = ${concat($a, $b, $c, $d, $e)};
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -18,6 +20,8 @@ LL | const _: () = ${concat($a, $b, $c, $d, $e)};
LL | post_expansion_many!(a, b, c, ".d", e);
| -------------------------------------- in this macro invocation
|
= note: this `${concat(..)}` invocation generated `abc.de`, but '.' is not XID_Continue
= note: see <https://doc.rust-lang.org/reference/identifiers.html> for the definition of valid identifiers
= note: this error originates in the macro `post_expansion_many` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 2 previous errors
@@ -1,4 +1,5 @@
//@ edition: 2021
//@ dont-require-annotations: NOTE
#![feature(macro_metavar_expr_concat)]
@@ -43,6 +44,7 @@ macro_rules! starting_number {
($ident:ident) => {{
let ${concat("1", $ident)}: () = ();
//~^ ERROR `${concat(..)}` is not generating a valid identifier
//~| NOTE this `${concat(..)}` invocation generated `1_abc`, but '1' is neither '_' nor XID_Start
}};
}
@@ -56,6 +58,8 @@ macro_rules! starting_invalid_unicode {
($ident:ident) => {{
let ${concat("\u{00BD}", $ident)}: () = ();
//~^ ERROR `${concat(..)}` is not generating a valid identifier
//~| NOTE this `${concat(..)}` invocation generated `\u{00BD}_abc`, but '\' is neither '_' nor XID_Start
//~| NOTE see <https://doc.rust-lang.org/reference/identifiers.html> for the definition of valid identifiers
}};
}
@@ -75,6 +79,7 @@ macro_rules! ending_invalid_unicode {
($ident:ident) => {{
let ${concat($ident, "\u{00BD}")}: () = ();
//~^ ERROR `${concat(..)}` is not generating a valid identifier
//~| NOTE this `${concat(..)}` invocation generated `_abc\u{00BD}`, but '\' is not XID_Continue
}};
}
@@ -82,6 +87,7 @@ macro_rules! empty {
() => {{
let ${concat("", "")}: () = ();
//~^ ERROR `${concat(..)}` is not generating a valid identifier
//~| NOTE this `${concat(..)}` invocation generated an empty ident
}};
}
@@ -130,6 +136,8 @@ macro_rules! bad_literal_string {
//~| ERROR `${concat(..)}` is not generating a valid identifier
//~| ERROR `${concat(..)}` is not generating a valid identifier
//~| ERROR `${concat(..)}` is not generating a valid identifier
//~| NOTE this `${concat(..)}` invocation generated `_foo🤷`, but '🤷' is not XID_Continue
//~| NOTE this `${concat(..)}` invocation generated `_foo-1`, but '-' is not XID_Continue
}
}
@@ -1,131 +1,131 @@
error: expected identifier or string literal
--> $DIR/concat-usage-errors.rs:7:10
--> $DIR/concat-usage-errors.rs:8:10
|
LL | ${concat()}
| ^^^^^^^^^^
error: `concat` must have at least two elements
--> $DIR/concat-usage-errors.rs:10:11
--> $DIR/concat-usage-errors.rs:11:11
|
LL | ${concat(aaaa)}
| ^^^^^^
error: expected identifier or string literal
--> $DIR/concat-usage-errors.rs:13:10
--> $DIR/concat-usage-errors.rs:14:10
|
LL | ${concat(aaaa,)}
| ^^^^^^^^^^^^^^^
error: expected comma
--> $DIR/concat-usage-errors.rs:18:10
--> $DIR/concat-usage-errors.rs:19:10
|
LL | ${concat(aaaa aaaa)}
| ^^^^^^^^^^^^^^^^^^^
error: `concat` must have at least two elements
--> $DIR/concat-usage-errors.rs:21:11
--> $DIR/concat-usage-errors.rs:22:11
|
LL | ${concat($ex)}
| ^^^^^^
error: expected comma
--> $DIR/concat-usage-errors.rs:27:10
--> $DIR/concat-usage-errors.rs:28:10
|
LL | ${concat($ex, aaaa 123)}
| ^^^^^^^^^^^^^^^^^^^^^^^
error: expected identifier or string literal
--> $DIR/concat-usage-errors.rs:30:10
--> $DIR/concat-usage-errors.rs:31:10
|
LL | ${concat($ex, aaaa,)}
| ^^^^^^^^^^^^^^^^^^^^
error: expected identifier or string literal
--> $DIR/concat-usage-errors.rs:90:26
--> $DIR/concat-usage-errors.rs:96:26
|
LL | let ${concat(_a, 'b')}: () = ();
| ^^^
error: expected identifier or string literal
--> $DIR/concat-usage-errors.rs:93:26
--> $DIR/concat-usage-errors.rs:99:26
|
LL | let ${concat(_a, 1)}: () = ();
| ^
error: expected identifier or string literal
--> $DIR/concat-usage-errors.rs:95:26
--> $DIR/concat-usage-errors.rs:101:26
|
LL | let ${concat(_a, 1.5)}: () = ();
| ^^^
error: expected identifier or string literal
--> $DIR/concat-usage-errors.rs:97:26
--> $DIR/concat-usage-errors.rs:103:26
|
LL | let ${concat(_a, c"hi")}: () = ();
| ^^^^^
error: expected identifier or string literal
--> $DIR/concat-usage-errors.rs:99:26
--> $DIR/concat-usage-errors.rs:105:26
|
LL | let ${concat(_a, b"hi")}: () = ();
| ^^^^^
error: expected identifier or string literal
--> $DIR/concat-usage-errors.rs:101:26
--> $DIR/concat-usage-errors.rs:107:26
|
LL | let ${concat(_a, b'b')}: () = ();
| ^^^^
error: expected identifier or string literal
--> $DIR/concat-usage-errors.rs:103:26
--> $DIR/concat-usage-errors.rs:109:26
|
LL | let ${concat(_a, b'b')}: () = ();
| ^^^^
error: expected identifier or string literal
--> $DIR/concat-usage-errors.rs:106:30
--> $DIR/concat-usage-errors.rs:112:30
|
LL | let ${concat($ident, 'b')}: () = ();
| ^^^
error: expected identifier or string literal
--> $DIR/concat-usage-errors.rs:108:30
--> $DIR/concat-usage-errors.rs:114:30
|
LL | let ${concat($ident, 1)}: () = ();
| ^
error: expected identifier or string literal
--> $DIR/concat-usage-errors.rs:110:30
--> $DIR/concat-usage-errors.rs:116:30
|
LL | let ${concat($ident, 1.5)}: () = ();
| ^^^
error: expected identifier or string literal
--> $DIR/concat-usage-errors.rs:112:30
--> $DIR/concat-usage-errors.rs:118:30
|
LL | let ${concat($ident, c"hi")}: () = ();
| ^^^^^
error: expected identifier or string literal
--> $DIR/concat-usage-errors.rs:114:30
--> $DIR/concat-usage-errors.rs:120:30
|
LL | let ${concat($ident, b"hi")}: () = ();
| ^^^^^
error: expected identifier or string literal
--> $DIR/concat-usage-errors.rs:116:30
--> $DIR/concat-usage-errors.rs:122:30
|
LL | let ${concat($ident, b'b')}: () = ();
| ^^^^
error: expected identifier or string literal
--> $DIR/concat-usage-errors.rs:118:30
--> $DIR/concat-usage-errors.rs:124:30
|
LL | let ${concat($ident, b'b')}: () = ();
| ^^^^
error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`
--> $DIR/concat-usage-errors.rs:24:19
--> $DIR/concat-usage-errors.rs:25:19
|
LL | ${concat($ex, aaaa)}
| ^^
@@ -133,13 +133,13 @@ LL | ${concat($ex, aaaa)}
= note: currently only string and integer literals are supported
error: variable `foo` is not recognized in meta-variable expression
--> $DIR/concat-usage-errors.rs:37:30
--> $DIR/concat-usage-errors.rs:38:30
|
LL | const ${concat(FOO, $foo)}: i32 = 2;
| ^^^
error: `${concat(..)}` is not generating a valid identifier
--> $DIR/concat-usage-errors.rs:44:14
--> $DIR/concat-usage-errors.rs:45:14
|
LL | let ${concat("1", $ident)}: () = ();
| ^^^^^^^^^^^^^^^^^^^^^
@@ -147,10 +147,12 @@ LL | let ${concat("1", $ident)}: () = ();
LL | starting_number!(_abc);
| ---------------------- in this macro invocation
|
= note: this `${concat(..)}` invocation generated `1_abc`, but '1' is neither '_' nor XID_Start
= note: see <https://doc.rust-lang.org/reference/identifiers.html> for the definition of valid identifiers
= note: this error originates in the macro `starting_number` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `${concat(..)}` is not generating a valid identifier
--> $DIR/concat-usage-errors.rs:57:14
--> $DIR/concat-usage-errors.rs:59:14
|
LL | let ${concat("\u{00BD}", $ident)}: () = ();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -158,10 +160,12 @@ LL | let ${concat("\u{00BD}", $ident)}: () = ();
LL | starting_invalid_unicode!(_abc);
| ------------------------------- in this macro invocation
|
= note: this `${concat(..)}` invocation generated `\u{00BD}_abc`, but '\' is neither '_' nor XID_Start
= note: see <https://doc.rust-lang.org/reference/identifiers.html> for the definition of valid identifiers
= note: this error originates in the macro `starting_invalid_unicode` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `${concat(..)}` is not generating a valid identifier
--> $DIR/concat-usage-errors.rs:76:14
--> $DIR/concat-usage-errors.rs:80:14
|
LL | let ${concat($ident, "\u{00BD}")}: () = ();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -169,10 +173,12 @@ LL | let ${concat($ident, "\u{00BD}")}: () = ();
LL | ending_invalid_unicode!(_abc);
| ----------------------------- in this macro invocation
|
= note: this `${concat(..)}` invocation generated `_abc\u{00BD}`, but '\' is not XID_Continue
= note: see <https://doc.rust-lang.org/reference/identifiers.html> for the definition of valid identifiers
= note: this error originates in the macro `ending_invalid_unicode` (in Nightly builds, run with -Z macro-backtrace for more info)
error: expected pattern, found `$`
--> $DIR/concat-usage-errors.rs:90:13
--> $DIR/concat-usage-errors.rs:96:13
|
LL | let ${concat(_a, 'b')}: () = ();
| ^ expected pattern
@@ -183,7 +189,7 @@ LL | unsupported_literals!(_abc);
= note: this error originates in the macro `unsupported_literals` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `${concat(..)}` is not generating a valid identifier
--> $DIR/concat-usage-errors.rs:83:14
--> $DIR/concat-usage-errors.rs:88:14
|
LL | let ${concat("", "")}: () = ();
| ^^^^^^^^^^^^^^^^
@@ -191,10 +197,11 @@ LL | let ${concat("", "")}: () = ();
LL | empty!();
| -------- in this macro invocation
|
= note: this `${concat(..)}` invocation generated an empty ident
= note: this error originates in the macro `empty` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `${concat(..)}` is not generating a valid identifier
--> $DIR/concat-usage-errors.rs:125:16
--> $DIR/concat-usage-errors.rs:131:16
|
LL | const ${concat(_foo, $literal)}: () = ();
| ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -202,10 +209,12 @@ LL | const ${concat(_foo, $literal)}: () = ();
LL | bad_literal_string!("\u{00BD}");
| ------------------------------- in this macro invocation
|
= note: this `${concat(..)}` invocation generated `_foo\u{00BD}`, but '\' is not XID_Continue
= note: see <https://doc.rust-lang.org/reference/identifiers.html> for the definition of valid identifiers
= note: this error originates in the macro `bad_literal_string` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `${concat(..)}` is not generating a valid identifier
--> $DIR/concat-usage-errors.rs:125:16
--> $DIR/concat-usage-errors.rs:131:16
|
LL | const ${concat(_foo, $literal)}: () = ();
| ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -213,10 +222,12 @@ LL | const ${concat(_foo, $literal)}: () = ();
LL | bad_literal_string!("\x41");
| --------------------------- in this macro invocation
|
= note: this `${concat(..)}` invocation generated `_foo\x41`, but '\' is not XID_Continue
= note: see <https://doc.rust-lang.org/reference/identifiers.html> for the definition of valid identifiers
= note: this error originates in the macro `bad_literal_string` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `${concat(..)}` is not generating a valid identifier
--> $DIR/concat-usage-errors.rs:125:16
--> $DIR/concat-usage-errors.rs:131:16
|
LL | const ${concat(_foo, $literal)}: () = ();
| ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -224,10 +235,12 @@ LL | const ${concat(_foo, $literal)}: () = ();
LL | bad_literal_string!("🤷");
| ------------------------- in this macro invocation
|
= note: this `${concat(..)}` invocation generated `_foo🤷`, but '🤷' is not XID_Continue
= note: see <https://doc.rust-lang.org/reference/identifiers.html> for the definition of valid identifiers
= note: this error originates in the macro `bad_literal_string` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `${concat(..)}` is not generating a valid identifier
--> $DIR/concat-usage-errors.rs:125:16
--> $DIR/concat-usage-errors.rs:131:16
|
LL | const ${concat(_foo, $literal)}: () = ();
| ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -235,10 +248,12 @@ LL | const ${concat(_foo, $literal)}: () = ();
LL | bad_literal_string!("d[-_-]b");
| ------------------------------ in this macro invocation
|
= note: this `${concat(..)}` invocation generated `_food[-_-]b`, but '[' is not XID_Continue
= note: see <https://doc.rust-lang.org/reference/identifiers.html> for the definition of valid identifiers
= note: this error originates in the macro `bad_literal_string` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `${concat(..)}` is not generating a valid identifier
--> $DIR/concat-usage-errors.rs:125:16
--> $DIR/concat-usage-errors.rs:131:16
|
LL | const ${concat(_foo, $literal)}: () = ();
| ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -246,10 +261,12 @@ LL | const ${concat(_foo, $literal)}: () = ();
LL | bad_literal_string!("-1");
| ------------------------- in this macro invocation
|
= note: this `${concat(..)}` invocation generated `_foo-1`, but '-' is not XID_Continue
= note: see <https://doc.rust-lang.org/reference/identifiers.html> for the definition of valid identifiers
= note: this error originates in the macro `bad_literal_string` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `${concat(..)}` is not generating a valid identifier
--> $DIR/concat-usage-errors.rs:125:16
--> $DIR/concat-usage-errors.rs:131:16
|
LL | const ${concat(_foo, $literal)}: () = ();
| ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -257,10 +274,12 @@ LL | const ${concat(_foo, $literal)}: () = ();
LL | bad_literal_string!("1.0");
| -------------------------- in this macro invocation
|
= note: this `${concat(..)}` invocation generated `_foo1.0`, but '.' is not XID_Continue
= note: see <https://doc.rust-lang.org/reference/identifiers.html> for the definition of valid identifiers
= note: this error originates in the macro `bad_literal_string` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `${concat(..)}` is not generating a valid identifier
--> $DIR/concat-usage-errors.rs:125:16
--> $DIR/concat-usage-errors.rs:131:16
|
LL | const ${concat(_foo, $literal)}: () = ();
| ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -268,10 +287,12 @@ LL | const ${concat(_foo, $literal)}: () = ();
LL | bad_literal_string!("'1'");
| -------------------------- in this macro invocation
|
= note: this `${concat(..)}` invocation generated `_foo'1'`, but '\'' is not XID_Continue
= note: see <https://doc.rust-lang.org/reference/identifiers.html> for the definition of valid identifiers
= note: this error originates in the macro `bad_literal_string` (in Nightly builds, run with -Z macro-backtrace for more info)
error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`
--> $DIR/concat-usage-errors.rs:138:31
--> $DIR/concat-usage-errors.rs:146:31
|
LL | const ${concat(_foo, $literal)}: () = ();
| ^^^^^^^
@@ -279,7 +300,7 @@ LL | const ${concat(_foo, $literal)}: () = ();
= note: currently only string and integer literals are supported
error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`
--> $DIR/concat-usage-errors.rs:138:31
--> $DIR/concat-usage-errors.rs:146:31
|
LL | const ${concat(_foo, $literal)}: () = ();
| ^^^^^^^
@@ -288,7 +309,7 @@ LL | const ${concat(_foo, $literal)}: () = ();
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`
--> $DIR/concat-usage-errors.rs:138:31
--> $DIR/concat-usage-errors.rs:146:31
|
LL | const ${concat(_foo, $literal)}: () = ();
| ^^^^^^^
@@ -297,7 +318,7 @@ LL | const ${concat(_foo, $literal)}: () = ();
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`
--> $DIR/concat-usage-errors.rs:138:31
--> $DIR/concat-usage-errors.rs:146:31
|
LL | const ${concat(_foo, $literal)}: () = ();
| ^^^^^^^
@@ -306,19 +327,19 @@ LL | const ${concat(_foo, $literal)}: () = ();
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: floats are not supported as metavariables of `${concat(..)}`
--> $DIR/concat-usage-errors.rs:138:31
--> $DIR/concat-usage-errors.rs:146:31
|
LL | const ${concat(_foo, $literal)}: () = ();
| ^^^^^^^
error: integer metavariables of `${concat(..)}` must not be suffixed
--> $DIR/concat-usage-errors.rs:138:31
--> $DIR/concat-usage-errors.rs:146:31
|
LL | const ${concat(_foo, $literal)}: () = ();
| ^^^^^^^
error: integer metavariables of `${concat(..)}` must not be suffixed
--> $DIR/concat-usage-errors.rs:138:31
--> $DIR/concat-usage-errors.rs:146:31
|
LL | const ${concat(_foo, $literal)}: () = ();
| ^^^^^^^
@@ -326,7 +347,7 @@ LL | const ${concat(_foo, $literal)}: () = ();
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`
--> $DIR/concat-usage-errors.rs:151:31
--> $DIR/concat-usage-errors.rs:159:31
|
LL | const ${concat(_foo, $tt)}: () = ();
| ^^
@@ -334,7 +355,7 @@ LL | const ${concat(_foo, $tt)}: () = ();
= note: currently only string and integer literals are supported
error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`
--> $DIR/concat-usage-errors.rs:151:31
--> $DIR/concat-usage-errors.rs:159:31
|
LL | const ${concat(_foo, $tt)}: () = ();
| ^^
@@ -0,0 +1,27 @@
// Suggest enclosing the format string with `""` when it is one of `{}`, `{:?}`, and `{:#?}`.
#[derive(Debug)]
enum UwU {
QwQ,
AwA,
QAQ,
}
fn main() {
println!({}, UwU::QwQ);
//~^ ERROR format argument must be a string literal
//~| HELP you might be missing a string literal to format with
//~| HELP you might want to enclose `{}` with `""`
println!({:?}, UwU::QwQ);
//~^ ERROR expected expression, found `:`
//~| ERROR format argument must be a string literal
//~| HELP you might be missing a string literal to format with
//~| HELP maybe write a path separator here
//~| HELP you might want to enclose `{:?}` with `""`
println!({:#?}, UwU::QwQ);
//~^ ERROR expected expression, found `:`
//~| ERROR format argument must be a string literal
//~| HELP you might be missing a string literal to format with
//~| HELP maybe write a path separator here
//~| HELP you might want to enclose `{:#?}` with `""`
}
@@ -0,0 +1,72 @@
error: format argument must be a string literal
--> $DIR/suggest-enclosing-format-string.rs:11:14
|
LL | println!({}, UwU::QwQ);
| ^^
|
help: you might be missing a string literal to format with
|
LL | println!("{:?} {}", {}, UwU::QwQ);
| ++++++++++
help: you might want to enclose `{}` with `""`
|
LL - println!({}, UwU::QwQ);
LL + println!("{}", UwU::QwQ);
|
error: expected expression, found `:`
--> $DIR/suggest-enclosing-format-string.rs:15:15
|
LL | println!({:?}, UwU::QwQ);
| ^ expected expression
|
help: maybe write a path separator here
|
LL | println!({::?}, UwU::QwQ);
| +
error: format argument must be a string literal
--> $DIR/suggest-enclosing-format-string.rs:15:14
|
LL | println!({:?}, UwU::QwQ);
| ^^^^
|
help: you might be missing a string literal to format with
|
LL | println!("{} {}", {:?}, UwU::QwQ);
| ++++++++
help: you might want to enclose `{:?}` with `""`
|
LL - println!({:?}, UwU::QwQ);
LL + println!("{:?}", UwU::QwQ);
|
error: expected expression, found `:`
--> $DIR/suggest-enclosing-format-string.rs:21:15
|
LL | println!({:#?}, UwU::QwQ);
| ^ expected expression
|
help: maybe write a path separator here
|
LL | println!({::#?}, UwU::QwQ);
| +
error: format argument must be a string literal
--> $DIR/suggest-enclosing-format-string.rs:21:14
|
LL | println!({:#?}, UwU::QwQ);
| ^^^^^
|
help: you might be missing a string literal to format with
|
LL | println!("{} {}", {:#?}, UwU::QwQ);
| ++++++++
help: you might want to enclose `{:#?}` with `""`
|
LL - println!({:#?}, UwU::QwQ);
LL + println!("{:#?}", UwU::QwQ);
|
error: aborting due to 5 previous errors
@@ -0,0 +1,46 @@
#![crate_type = "rlib"]
// Suggestions for range patterns should not perform span manipulations that
// assume the range token is ASCII, because it could have been recovered from
// similar-looking Unicode characters.
//
// Regression test for <https://github.com/rust-lang/rust/issues/155799>.
// These dots are U+00B7 MIDDLE DOT, not an ASCII period.
fn dot_dot_dot() { ··· }
//~^ ERROR unknown start of token
//~| ERROR unknown start of token
//~| ERROR unknown start of token
//~| ERROR unexpected token: `...`
//~| ERROR inclusive range with no end
fn dot_dot_dot_eq() { ···= }
//~^ ERROR unknown start of token
//~| ERROR unknown start of token
//~| ERROR unknown start of token
//~| ERROR unexpected token: `...`
//~| ERROR unexpected `=` after inclusive range
fn dot_dot_dot_gt() { ···> }
//~^ ERROR unknown start of token
//~| ERROR unknown start of token
//~| ERROR unknown start of token
//~| ERROR unexpected token: `...`
//~| ERROR inclusive range with no end
//~| ERROR expected one of `;` or `}`, found `>`
fn dot_dot_eq() { ··= }
//~^ ERROR unknown start of token
//~| ERROR unknown start of token
//~| ERROR inclusive range with no end
fn dot_dot_eq_eq() { ··== }
//~^ ERROR unknown start of token
//~| ERROR unknown start of token
//~| ERROR unexpected `=` after inclusive range
fn dot_dot_eq_gt() { ··=> }
//~^ ERROR unknown start of token
//~| ERROR unknown start of token
//~| ERROR unexpected `>` after inclusive range
//~| ERROR expected one of `;` or `}`, found `>`
@@ -0,0 +1,334 @@
error: unknown start of token: \u{b7}
--> $DIR/range-inclusive-suggestion-span.rs:10:20
|
LL | fn dot_dot_dot() { ··· }
| ^^^
|
= note: character appears 2 more times
help: Unicode character '·' (Middle Dot) looks like '.' (Period), but it is not
|
LL - fn dot_dot_dot() { ··· }
LL + fn dot_dot_dot() { ... }
|
error: unknown start of token: \u{b7}
--> $DIR/range-inclusive-suggestion-span.rs:10:21
|
LL | fn dot_dot_dot() { ··· }
| ^^
|
= note: character appears once more
help: Unicode character '·' (Middle Dot) looks like '.' (Period), but it is not
|
LL - fn dot_dot_dot() { ··· }
LL + fn dot_dot_dot() { ·.. }
|
error: unknown start of token: \u{b7}
--> $DIR/range-inclusive-suggestion-span.rs:10:22
|
LL | fn dot_dot_dot() { ··· }
| ^
|
help: Unicode character '·' (Middle Dot) looks like '.' (Period), but it is not
|
LL - fn dot_dot_dot() { ··· }
LL + fn dot_dot_dot() { ··. }
|
error: unknown start of token: \u{b7}
--> $DIR/range-inclusive-suggestion-span.rs:17:23
|
LL | fn dot_dot_dot_eq() { ···= }
| ^^^
|
= note: character appears 2 more times
help: Unicode character '·' (Middle Dot) looks like '.' (Period), but it is not
|
LL - fn dot_dot_dot_eq() { ···= }
LL + fn dot_dot_dot_eq() { ...= }
|
error: unknown start of token: \u{b7}
--> $DIR/range-inclusive-suggestion-span.rs:17:24
|
LL | fn dot_dot_dot_eq() { ···= }
| ^^
|
= note: character appears once more
help: Unicode character '·' (Middle Dot) looks like '.' (Period), but it is not
|
LL - fn dot_dot_dot_eq() { ···= }
LL + fn dot_dot_dot_eq() { ·..= }
|
error: unknown start of token: \u{b7}
--> $DIR/range-inclusive-suggestion-span.rs:17:25
|
LL | fn dot_dot_dot_eq() { ···= }
| ^
|
help: Unicode character '·' (Middle Dot) looks like '.' (Period), but it is not
|
LL - fn dot_dot_dot_eq() { ···= }
LL + fn dot_dot_dot_eq() { ··.= }
|
error: unknown start of token: \u{b7}
--> $DIR/range-inclusive-suggestion-span.rs:24:23
|
LL | fn dot_dot_dot_gt() { ···> }
| ^^^
|
= note: character appears 2 more times
help: Unicode character '·' (Middle Dot) looks like '.' (Period), but it is not
|
LL - fn dot_dot_dot_gt() { ···> }
LL + fn dot_dot_dot_gt() { ...> }
|
error: unknown start of token: \u{b7}
--> $DIR/range-inclusive-suggestion-span.rs:24:24
|
LL | fn dot_dot_dot_gt() { ···> }
| ^^
|
= note: character appears once more
help: Unicode character '·' (Middle Dot) looks like '.' (Period), but it is not
|
LL - fn dot_dot_dot_gt() { ···> }
LL + fn dot_dot_dot_gt() { ·..> }
|
error: unknown start of token: \u{b7}
--> $DIR/range-inclusive-suggestion-span.rs:24:25
|
LL | fn dot_dot_dot_gt() { ···> }
| ^
|
help: Unicode character '·' (Middle Dot) looks like '.' (Period), but it is not
|
LL - fn dot_dot_dot_gt() { ···> }
LL + fn dot_dot_dot_gt() { ··.> }
|
error: unknown start of token: \u{b7}
--> $DIR/range-inclusive-suggestion-span.rs:32:19
|
LL | fn dot_dot_eq() { ··= }
| ^^
|
= note: character appears once more
help: Unicode character '·' (Middle Dot) looks like '.' (Period), but it is not
|
LL - fn dot_dot_eq() { ··= }
LL + fn dot_dot_eq() { ..= }
|
error: unknown start of token: \u{b7}
--> $DIR/range-inclusive-suggestion-span.rs:32:20
|
LL | fn dot_dot_eq() { ··= }
| ^
|
help: Unicode character '·' (Middle Dot) looks like '.' (Period), but it is not
|
LL - fn dot_dot_eq() { ··= }
LL + fn dot_dot_eq() { ·.= }
|
error: unknown start of token: \u{b7}
--> $DIR/range-inclusive-suggestion-span.rs:37:22
|
LL | fn dot_dot_eq_eq() { ··== }
| ^^
|
= note: character appears once more
help: Unicode character '·' (Middle Dot) looks like '.' (Period), but it is not
|
LL - fn dot_dot_eq_eq() { ··== }
LL + fn dot_dot_eq_eq() { ..== }
|
error: unknown start of token: \u{b7}
--> $DIR/range-inclusive-suggestion-span.rs:37:23
|
LL | fn dot_dot_eq_eq() { ··== }
| ^
|
help: Unicode character '·' (Middle Dot) looks like '.' (Period), but it is not
|
LL - fn dot_dot_eq_eq() { ··== }
LL + fn dot_dot_eq_eq() { ·.== }
|
error: unknown start of token: \u{b7}
--> $DIR/range-inclusive-suggestion-span.rs:42:22
|
LL | fn dot_dot_eq_gt() { ··=> }
| ^^
|
= note: character appears once more
help: Unicode character '·' (Middle Dot) looks like '.' (Period), but it is not
|
LL - fn dot_dot_eq_gt() { ··=> }
LL + fn dot_dot_eq_gt() { ..=> }
|
error: unknown start of token: \u{b7}
--> $DIR/range-inclusive-suggestion-span.rs:42:23
|
LL | fn dot_dot_eq_gt() { ··=> }
| ^
|
help: Unicode character '·' (Middle Dot) looks like '.' (Period), but it is not
|
LL - fn dot_dot_eq_gt() { ··=> }
LL + fn dot_dot_eq_gt() { ·.=> }
|
error: unexpected token: `...`
--> $DIR/range-inclusive-suggestion-span.rs:10:20
|
LL | fn dot_dot_dot() { ··· }
| ^^^
|
help: use `..` for an exclusive range
|
LL - fn dot_dot_dot() { ··· }
LL + fn dot_dot_dot() { .. }
|
help: or `..=` for an inclusive range
|
LL - fn dot_dot_dot() { ··· }
LL + fn dot_dot_dot() { ..= }
|
error[E0586]: inclusive range with no end
--> $DIR/range-inclusive-suggestion-span.rs:10:20
|
LL | fn dot_dot_dot() { ··· }
| ^^^
|
= note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
help: use `..` instead
|
LL - fn dot_dot_dot() { ··· }
LL + fn dot_dot_dot() { .. }
|
error: unexpected token: `...`
--> $DIR/range-inclusive-suggestion-span.rs:17:23
|
LL | fn dot_dot_dot_eq() { ···= }
| ^^^
|
help: use `..` for an exclusive range
|
LL - fn dot_dot_dot_eq() { ···= }
LL + fn dot_dot_dot_eq() { ..= }
|
help: or `..=` for an inclusive range
|
LL - fn dot_dot_dot_eq() { ···= }
LL + fn dot_dot_dot_eq() { ..== }
|
error: unexpected `=` after inclusive range
--> $DIR/range-inclusive-suggestion-span.rs:17:23
|
LL | fn dot_dot_dot_eq() { ···= }
| ^^^^
|
= note: inclusive ranges end with a single equals sign (`..=`)
help: use `..=` instead
|
LL - fn dot_dot_dot_eq() { ···= }
LL + fn dot_dot_dot_eq() { ..= }
|
error: unexpected token: `...`
--> $DIR/range-inclusive-suggestion-span.rs:24:23
|
LL | fn dot_dot_dot_gt() { ···> }
| ^^^
|
help: use `..` for an exclusive range
|
LL - fn dot_dot_dot_gt() { ···> }
LL + fn dot_dot_dot_gt() { ..> }
|
help: or `..=` for an inclusive range
|
LL - fn dot_dot_dot_gt() { ···> }
LL + fn dot_dot_dot_gt() { ..=> }
|
error[E0586]: inclusive range with no end
--> $DIR/range-inclusive-suggestion-span.rs:24:23
|
LL | fn dot_dot_dot_gt() { ···> }
| ^^^
|
= note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
help: use `..` instead
|
LL - fn dot_dot_dot_gt() { ···> }
LL + fn dot_dot_dot_gt() { ..> }
|
error: expected one of `;` or `}`, found `>`
--> $DIR/range-inclusive-suggestion-span.rs:24:26
|
LL | fn dot_dot_dot_gt() { ···> }
| ^ expected one of `;` or `}`
error[E0586]: inclusive range with no end
--> $DIR/range-inclusive-suggestion-span.rs:32:19
|
LL | fn dot_dot_eq() { ··= }
| ^^^
|
= note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
help: use `..` instead
|
LL - fn dot_dot_eq() { ··= }
LL + fn dot_dot_eq() { .. }
|
error: unexpected `=` after inclusive range
--> $DIR/range-inclusive-suggestion-span.rs:37:22
|
LL | fn dot_dot_eq_eq() { ··== }
| ^^^^
|
= note: inclusive ranges end with a single equals sign (`..=`)
help: use `..=` instead
|
LL - fn dot_dot_eq_eq() { ··== }
LL + fn dot_dot_eq_eq() { ..= }
|
error: unexpected `>` after inclusive range
--> $DIR/range-inclusive-suggestion-span.rs:42:25
|
LL | fn dot_dot_eq_gt() { ··=> }
| ---^
| |
| this is parsed as an inclusive range `..=`
|
help: add a space between the pattern and `=>`
|
LL - fn dot_dot_eq_gt() { ··=> }
LL + fn dot_dot_eq_gt() { .. => }
|
error: expected one of `;` or `}`, found `>`
--> $DIR/range-inclusive-suggestion-span.rs:42:25
|
LL | fn dot_dot_eq_gt() { ··=> }
| ^ expected one of `;` or `}`
error: aborting due to 26 previous errors
For more information about this error, try `rustc --explain E0586`.
@@ -0,0 +1,13 @@
//! Regression test for <https://github.com/rust-lang/rust/issues/153438>: when there's a type
//! expectation on `pin!`'s result, make sure we don't deref-coerce the argument to
//! `Pin::new_unchecked` to get its type to match up. That violates the pinning invariant, leading
//! to unsoundness!
use std::pin::{Pin, pin};
fn wrong_pin<T>(data: &mut T, callback: impl FnOnce(Pin<&mut T>)) {
callback(pin!(data));
//~^ ERROR: mismatched types
}
fn main() {}
@@ -0,0 +1,24 @@
error[E0308]: mismatched types
--> $DIR/dont-deref-coerce-pinned-value.rs:9:14
|
LL | fn wrong_pin<T>(data: &mut T, callback: impl FnOnce(Pin<&mut T>)) {
| - expected this type parameter
LL | callback(pin!(data));
| ^^^^^^^^^^
| |
| expected type parameter `T`, found `&mut T`
| arguments to this function are incorrect
|
= note: expected type parameter `_`
found mutable reference `&mut _`
help: the return type of this call is `&mut T` due to the type of the argument passed
--> $DIR/dont-deref-coerce-pinned-value.rs:9:14
|
LL | callback(pin!(data));
| ^^^^^^^^^^ this argument influences the return type of `unreachable_pin_macro_type_constraint`
note: function defined here
--> $SRC_DIR/core/src/pin.rs:LL:COL
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0308`.