mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
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:
@@ -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);
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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,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)]
|
||||
|
||||
@@ -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()
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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`).
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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(..)))
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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 }),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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!()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -48,8 +48,3 @@
|
||||
pub use generic::*;
|
||||
}
|
||||
}
|
||||
|
||||
pub type RawOsError = cfg_select! {
|
||||
target_os = "uefi" => usize,
|
||||
_ => i32,
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 @@
|
||||
e22c616e4e87914135c1db261a03e0437255335e
|
||||
9836b06b55f5389f605ee7766eeecd9f17a86cb5
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
+59
-47
@@ -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.
|
||||
@@ -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();
|
||||
|
||||
@@ -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)?;
|
||||
|
||||
|
||||
@@ -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)?;
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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`.
|
||||
Reference in New Issue
Block a user