"pretty_assertions 0.7.2",
"serde",
"serde_json",
+ "sysinfo",
"tar",
"toml",
"winapi",
[[package]]
name = "compiler_builtins"
-version = "0.1.71"
+version = "0.1.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "163437f05ca8f29d7e9128ea728dedf5eb620e445fbca273641d3a3050305f23"
+checksum = "71b72fde1d7792ca3bd654f7c3ea4508f9e4d0c826e24179eabb7fcc97a90bc3"
dependencies = [
"cc",
"rustc-std-workspace-core",
"rustc_span",
"rustc_symbol_mangling",
"rustc_target",
+ "serde_json",
"smallvec",
"snap",
"tempfile",
"rustc_span",
"rustc_target",
"rustc_typeck",
+ "serde_json",
"tracing",
"winapi",
]
"rustc_macros",
"rustc_serialize",
"rustc_span",
+ "serde",
+ "serde_json",
"termcolor",
"termize",
"tracing",
"rustc_serialize",
"rustc_span",
"rustc_target",
+ "serde",
]
[[package]]
"rustc_macros",
"rustc_serialize",
"rustc_span",
+ "serde_json",
"tracing",
]
"unicode-xid",
]
+[[package]]
+name = "sysinfo"
+version = "0.24.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6a8e71535da31837213ac114531d31def75d7aebd133264e420a3451fa7f703"
+dependencies = [
+ "cfg-if 1.0.0",
+ "core-foundation-sys",
+ "libc",
+ "ntapi",
+ "once_cell",
+ "rayon",
+ "winapi",
+]
+
[[package]]
name = "tar"
version = "0.4.37"
"pretty_assertions 1.2.1",
"regex",
"rustc_version",
+ "serde",
+ "serde_json",
]
[[package]]
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+This is a Windows application manifest file.
+See: https://docs.microsoft.com/en-us/windows/win32/sbscs/application-manifests
+-->
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
+ <!-- Versions rustc supports as compiler hosts -->
+ <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+ <application>
+ <!-- Windows 7 --><supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+ <!-- Windows 8 --><supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+ <!-- Windows 8.1 --><supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+ <!-- Windows 10 and 11 --><supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+ </application>
+ </compatibility>
+ <!-- Use UTF-8 code page -->
+ <asmv3:application>
+ <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">
+ <activeCodePage>UTF-8</activeCodePage>
+ </asmv3:windowsSettings>
+ </asmv3:application>
+ <!-- Remove (most) legacy path limits -->
+ <asmv3:application>
+ <asmv3:windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
+ <ws2:longPathAware>true</ws2:longPathAware>
+ </asmv3:windowsSettings>
+ </asmv3:application>
+</assembly>
--- /dev/null
+use std::env;
+
+fn main() {
+ let target_os = env::var("CARGO_CFG_TARGET_OS");
+ let target_env = env::var("CARGO_CFG_TARGET_ENV");
+ if Ok("windows") == target_os.as_deref() && Ok("msvc") == target_env.as_deref() {
+ set_windows_exe_options();
+ }
+}
+
+// Add a manifest file to rustc.exe.
+fn set_windows_exe_options() {
+ static WINDOWS_MANIFEST_FILE: &str = "Windows Manifest.xml";
+
+ let mut manifest = env::current_dir().unwrap();
+ manifest.push(WINDOWS_MANIFEST_FILE);
+
+ println!("cargo:rerun-if-changed={}", WINDOWS_MANIFEST_FILE);
+ // Embed the Windows application manifest file.
+ println!("cargo:rustc-link-arg-bin=rustc-main=/MANIFEST:EMBED");
+ println!("cargo:rustc-link-arg-bin=rustc-main=/MANIFESTINPUT:{}", manifest.to_str().unwrap());
+ // Turn linker warnings into errors.
+ println!("cargo:rustc-link-arg-bin=rustc-main=/WX");
+}
use std::fmt;
use std::mem;
-#[cfg(test)]
-mod tests;
-
/// A "Label" is an identifier of some point in sources,
/// e.g. in the following code:
///
}
impl<S: Encoder> rustc_serialize::Encodable<S> for AttrId {
- fn encode(&self, s: &mut S) -> Result<(), S::Error> {
- s.emit_unit()
+ fn encode(&self, _s: &mut S) -> Result<(), S::Error> {
+ Ok(())
}
}
+++ /dev/null
-use super::*;
-
-// Are ASTs encodable?
-#[test]
-fn check_asts_encodable() {
- fn assert_encodable<
- T: for<'a> rustc_serialize::Encodable<rustc_serialize::json::Encoder<'a>>,
- >() {
- }
- assert_encodable::<Crate>();
-}
Brace,
/// `[ ... ]`
Bracket,
- /// `/*«*/ ... /*»*/`
+ /// `Ø ... Ø`
/// An invisible delimiter, that may, for example, appear around tokens coming from a
/// "macro variable" `$var`. It is important to preserve operator priorities in cases like
/// `$var * 3` where `$var` is `1 + 2`.
- /// Invisible delimiters are not directly writable in normal Rust code except as comments.
- /// Therefore, they might not survive a roundtrip of a token stream through a string.
+ /// Invisible delimiters might not survive roundtrip of a token stream through a string.
Invisible,
}
}
ExprKind::Tup(ref elts) => hir::ExprKind::Tup(self.lower_exprs(elts)),
ExprKind::Call(ref f, ref args) => {
- if let Some(legacy_args) = self.resolver.legacy_const_generic_args(f) {
+ if e.attrs.get(0).map_or(false, |a| a.has_name(sym::rustc_box)) {
+ if let [inner] = &args[..] && e.attrs.len() == 1 {
+ let kind = hir::ExprKind::Box(self.lower_expr(&inner));
+ let hir_id = self.lower_node_id(e.id);
+ return hir::Expr { hir_id, kind, span: self.lower_span(e.span) };
+ } else {
+ self.sess
+ .struct_span_err(
+ e.span,
+ "#[rustc_box] requires precisely one argument \
+ and no other attributes are allowed",
+ )
+ .emit();
+ hir::ExprKind::Err
+ }
+ } else if let Some(legacy_args) = self.resolver.legacy_const_generic_args(f) {
self.lower_legacy_const_generics((**f).clone(), args.clone(), &legacy_args)
} else {
let f = self.lower_expr(f);
task_context: None,
current_item: None,
captured_lifetimes: None,
+ impl_trait_defs: Vec::new(),
+ impl_trait_bounds: Vec::new(),
allow_try_trait: Some([sym::try_trait_v2, sym::yeet_desugar_details][..].into()),
allow_gen_future: Some([sym::gen_future][..].into()),
allow_into_future: Some([sym::into_future][..].into()),
let body_id =
this.lower_maybe_async_body(span, &decl, asyncness, body.as_deref());
- let (generics, decl) =
- this.add_implicit_generics(generics, id, |this, idty, idpb| {
- let ret_id = asyncness.opt_return_id();
- this.lower_fn_decl(
- &decl,
- Some((id, idty, idpb)),
- FnDeclKind::Fn,
- ret_id,
- )
- });
+ let itctx = ImplTraitContext::Universal;
+ let (generics, decl) = this.lower_generics(generics, id, itctx, |this| {
+ let ret_id = asyncness.opt_return_id();
+ this.lower_fn_decl(&decl, Some(id), FnDeclKind::Fn, ret_id)
+ });
let sig = hir::FnSig {
decl,
header: this.lower_fn_header(header),
//
// type Foo = Foo1
// opaque type Foo1: Trait
- let ty = self.lower_ty(ty, ImplTraitContext::TypeAliasesOpaqueTy);
let mut generics = generics.clone();
add_ty_alias_where_clause(&mut generics, where_clauses, true);
- let generics = self.lower_generics(
+ let (generics, ty) = self.lower_generics(
&generics,
+ id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ |this| this.lower_ty(ty, ImplTraitContext::TypeAliasesOpaqueTy),
);
hir::ItemKind::TyAlias(ty, generics)
}
ItemKind::TyAlias(box TyAlias {
ref generics, ref where_clauses, ty: None, ..
}) => {
- let ty = self.arena.alloc(self.ty(span, hir::TyKind::Err));
let mut generics = generics.clone();
add_ty_alias_where_clause(&mut generics, *where_clauses, true);
- let generics = self.lower_generics(
+ let (generics, ty) = self.lower_generics(
&generics,
+ id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ |this| this.arena.alloc(this.ty(span, hir::TyKind::Err)),
);
hir::ItemKind::TyAlias(ty, generics)
}
- ItemKind::Enum(ref enum_definition, ref generics) => hir::ItemKind::Enum(
- hir::EnumDef {
- variants: self.arena.alloc_from_iter(
- enum_definition.variants.iter().map(|x| self.lower_variant(x)),
- ),
- },
- self.lower_generics(
+ ItemKind::Enum(ref enum_definition, ref generics) => {
+ let (generics, variants) = self.lower_generics(
generics,
+ id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
- ),
- ),
+ |this| {
+ this.arena.alloc_from_iter(
+ enum_definition.variants.iter().map(|x| this.lower_variant(x)),
+ )
+ },
+ );
+ hir::ItemKind::Enum(hir::EnumDef { variants }, generics)
+ }
ItemKind::Struct(ref struct_def, ref generics) => {
- let struct_def = self.lower_variant_data(hir_id, struct_def);
- hir::ItemKind::Struct(
- struct_def,
- self.lower_generics(
- generics,
- ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
- ),
- )
+ let (generics, struct_def) = self.lower_generics(
+ generics,
+ id,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ |this| this.lower_variant_data(hir_id, struct_def),
+ );
+ hir::ItemKind::Struct(struct_def, generics)
}
ItemKind::Union(ref vdata, ref generics) => {
- let vdata = self.lower_variant_data(hir_id, vdata);
- hir::ItemKind::Union(
- vdata,
- self.lower_generics(
- generics,
- ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
- ),
- )
+ let (generics, vdata) = self.lower_generics(
+ generics,
+ id,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ |this| this.lower_variant_data(hir_id, vdata),
+ );
+ hir::ItemKind::Union(vdata, generics)
}
ItemKind::Impl(box Impl {
unsafety,
// method, it will not be considered an in-band
// lifetime to be added, but rather a reference to a
// parent lifetime.
+ let itctx = ImplTraitContext::Universal;
let (generics, (trait_ref, lowered_ty)) =
- self.add_implicit_generics(ast_generics, id, |this, _, _| {
+ self.lower_generics(ast_generics, id, itctx, |this| {
let trait_ref = trait_ref.as_ref().map(|trait_ref| {
this.lower_trait_ref(
trait_ref,
ref bounds,
ref items,
}) => {
- let bounds = self.lower_param_bounds(
- bounds,
- ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+ let (generics, (unsafety, items, bounds)) = self.lower_generics(
+ generics,
+ id,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ |this| {
+ let bounds = this.lower_param_bounds(
+ bounds,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+ );
+ let items = this.arena.alloc_from_iter(
+ items.iter().map(|item| this.lower_trait_item_ref(item)),
+ );
+ let unsafety = this.lower_unsafety(unsafety);
+ (unsafety, items, bounds)
+ },
);
- let items = self
- .arena
- .alloc_from_iter(items.iter().map(|item| self.lower_trait_item_ref(item)));
- hir::ItemKind::Trait(
- is_auto,
- self.lower_unsafety(unsafety),
- self.lower_generics(
- generics,
- ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
- ),
- bounds,
- items,
- )
+ hir::ItemKind::Trait(is_auto, unsafety, generics, bounds, items)
}
- ItemKind::TraitAlias(ref generics, ref bounds) => hir::ItemKind::TraitAlias(
- self.lower_generics(
+ ItemKind::TraitAlias(ref generics, ref bounds) => {
+ let (generics, bounds) = self.lower_generics(
generics,
+ id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
- ),
- self.lower_param_bounds(
- bounds,
- ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
- ),
- ),
+ |this| {
+ this.lower_param_bounds(
+ bounds,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+ )
+ },
+ );
+ hir::ItemKind::TraitAlias(generics, bounds)
+ }
ItemKind::MacroDef(MacroDef { ref body, macro_rules }) => {
let body = P(self.lower_mac_args(body));
let macro_kind = self.resolver.decl_macro_kind(self.resolver.local_def_id(id));
kind: match i.kind {
ForeignItemKind::Fn(box Fn { ref sig, ref generics, .. }) => {
let fdec = &sig.decl;
+ let itctx = ImplTraitContext::Universal;
let (generics, (fn_dec, fn_args)) =
- self.add_implicit_generics(generics, i.id, |this, _, _| {
+ self.lower_generics(generics, i.id, itctx, |this| {
(
// Disallow `impl Trait` in foreign items.
this.lower_fn_decl(fdec, None, FnDeclKind::ExternFn, None),
ref ty,
..
}) => {
- let ty = ty.as_ref().map(|x| {
- self.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Type))
- });
let mut generics = generics.clone();
add_ty_alias_where_clause(&mut generics, where_clauses, false);
- let generics = self.lower_generics(
+ self.lower_generics(
&generics,
+ i.id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
- );
- let kind = hir::TraitItemKind::Type(
- self.lower_param_bounds(
- bounds,
- ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
- ),
- ty,
- );
-
- (generics, kind)
+ |this| {
+ let ty = ty.as_ref().map(|x| {
+ this.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Type))
+ });
+ hir::TraitItemKind::Type(
+ this.lower_param_bounds(
+ bounds,
+ ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+ ),
+ ty,
+ )
+ },
+ )
}
AssocItemKind::MacCall(..) => panic!("macro item shouldn't exist at this point"),
};
AssocItemKind::TyAlias(box TyAlias { generics, where_clauses, ty, .. }) => {
let mut generics = generics.clone();
add_ty_alias_where_clause(&mut generics, *where_clauses, false);
- let generics = self.lower_generics(
+ self.lower_generics(
&generics,
+ i.id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
- );
- let kind = match ty {
- None => {
- let ty = self.arena.alloc(self.ty(i.span, hir::TyKind::Err));
- hir::ImplItemKind::TyAlias(ty)
- }
- Some(ty) => {
- let ty = self.lower_ty(ty, ImplTraitContext::TypeAliasesOpaqueTy);
- hir::ImplItemKind::TyAlias(ty)
- }
- };
- (generics, kind)
+ |this| match ty {
+ None => {
+ let ty = this.arena.alloc(this.ty(i.span, hir::TyKind::Err));
+ hir::ImplItemKind::TyAlias(ty)
+ }
+ Some(ty) => {
+ let ty = this.lower_ty(ty, ImplTraitContext::TypeAliasesOpaqueTy);
+ hir::ImplItemKind::TyAlias(ty)
+ }
+ },
+ )
}
AssocItemKind::MacCall(..) => panic!("`TyMac` should have been expanded by now"),
};
is_async: Option<NodeId>,
) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) {
let header = self.lower_fn_header(sig.header);
- let (generics, decl) = self.add_implicit_generics(generics, id, |this, idty, idpb| {
- this.lower_fn_decl(&sig.decl, Some((id, idty, idpb)), kind, is_async)
+ let itctx = ImplTraitContext::Universal;
+ let (generics, decl) = self.lower_generics(generics, id, itctx, |this| {
+ this.lower_fn_decl(&sig.decl, Some(id), kind, is_async)
});
(generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
}
}
}
- pub(super) fn lower_generics_mut(
+ /// Return the pair of the lowered `generics` as `hir::Generics` and the evaluation of `f` with
+ /// the carried impl trait definitions and bounds.
+ fn lower_generics<T>(
&mut self,
generics: &Generics,
- mut itctx: ImplTraitContext<'_, 'hir>,
- ) -> GenericsCtor<'hir> {
+ parent_node_id: NodeId,
+ itctx: ImplTraitContext,
+ f: impl FnOnce(&mut Self) -> T,
+ ) -> (&'hir hir::Generics<'hir>, T) {
+ debug_assert!(self.impl_trait_defs.is_empty());
+ debug_assert!(self.impl_trait_bounds.is_empty());
+
// Error if `?Trait` bounds in where clauses don't refer directly to type parameters.
// Note: we used to clone these bounds directly onto the type parameter (and avoid lowering
// these into hir when we lower thee where clauses), but this makes it quite difficult to
}
}
- let mut predicates = SmallVec::new();
+ let mut predicates: SmallVec<[hir::WherePredicate<'hir>; 4]> = SmallVec::new();
predicates.extend(generics.params.iter().filter_map(|param| {
- let bounds = self.lower_param_bounds(¶m.bounds, itctx.reborrow());
+ let bounds = self.lower_param_bounds(¶m.bounds, itctx);
self.lower_generic_bound_predicate(
param.ident,
param.id,
.map(|predicate| self.lower_where_predicate(predicate)),
);
- GenericsCtor {
- params: self.lower_generic_params_mut(&generics.params).collect(),
- predicates,
- has_where_clause: !generics.where_clause.predicates.is_empty(),
- where_clause_span: self.lower_span(generics.where_clause.span),
- span: self.lower_span(generics.span),
- }
- }
+ let mut params: SmallVec<[hir::GenericParam<'hir>; 4]> =
+ self.lower_generic_params_mut(&generics.params).collect();
+ let has_where_clause = !generics.where_clause.predicates.is_empty();
+ let where_clause_span = self.lower_span(generics.where_clause.span);
+ let span = self.lower_span(generics.span);
+ let res = f(self);
+
+ let extra_lifetimes = self.resolver.take_extra_lifetime_params(parent_node_id);
+ let impl_trait_defs = std::mem::take(&mut self.impl_trait_defs);
+ params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| {
+ self.lifetime_res_to_generic_param(ident, node_id, res)
+ }));
+ params.extend(impl_trait_defs.into_iter());
- pub(super) fn lower_generics(
- &mut self,
- generics: &Generics,
- itctx: ImplTraitContext<'_, 'hir>,
- ) -> &'hir hir::Generics<'hir> {
- let generics_ctor = self.lower_generics_mut(generics, itctx);
- generics_ctor.into_generics(self.arena)
+ let impl_trait_bounds = std::mem::take(&mut self.impl_trait_bounds);
+ predicates.extend(impl_trait_bounds.into_iter());
+
+ let lowered_generics = self.arena.alloc(hir::Generics {
+ params: self.arena.alloc_from_iter(params),
+ predicates: self.arena.alloc_from_iter(predicates),
+ has_where_clause,
+ where_clause_span,
+ span,
+ });
+
+ (lowered_generics, res)
}
pub(super) fn lower_generic_bound_predicate(
}
}
}
-
-/// Helper struct for delayed construction of Generics.
-pub(super) struct GenericsCtor<'hir> {
- pub(super) params: SmallVec<[hir::GenericParam<'hir>; 4]>,
- pub(super) predicates: SmallVec<[hir::WherePredicate<'hir>; 4]>,
- has_where_clause: bool,
- where_clause_span: Span,
- span: Span,
-}
-
-impl<'hir> GenericsCtor<'hir> {
- pub(super) fn into_generics(self, arena: &'hir Arena<'hir>) -> &'hir hir::Generics<'hir> {
- arena.alloc(hir::Generics {
- params: arena.alloc_from_iter(self.params),
- predicates: arena.alloc_from_iter(self.predicates),
- has_where_clause: self.has_where_clause,
- where_clause_span: self.where_clause_span,
- span: self.span,
- })
- }
-}
use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::Lrc;
-use rustc_errors::struct_span_err;
+use rustc_errors::{struct_span_err, Applicability};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Namespace, PartialRes, PerNS, Res};
use rustc_hir::def_id::{DefId, DefPathHash, LocalDefId, CRATE_DEF_ID};
local_id_to_def_id: SortedMap<ItemLocalId, LocalDefId>,
trait_map: FxHashMap<ItemLocalId, Box<[TraitCandidate]>>,
+ impl_trait_defs: Vec<hir::GenericParam<'hir>>,
+ impl_trait_bounds: Vec<hir::WherePredicate<'hir>>,
+
/// NodeIds that are lowered inside the current HIR owner.
node_id_to_local_id: FxHashMap<NodeId, hir::ItemLocalId>,
/// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree,
/// and if so, what meaning it has.
-#[derive(Debug)]
-enum ImplTraitContext<'b, 'a> {
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+enum ImplTraitContext {
/// Treat `impl Trait` as shorthand for a new universal generic parameter.
/// Example: `fn foo(x: impl Debug)`, where `impl Debug` is conceptually
/// equivalent to a fresh universal parameter like `fn foo<T: Debug>(x: T)`.
///
/// Newly generated parameters should be inserted into the given `Vec`.
- Universal(&'b mut Vec<hir::GenericParam<'a>>, &'b mut Vec<hir::WherePredicate<'a>>, LocalDefId),
+ Universal,
/// Treat `impl Trait` as shorthand for a new opaque type.
/// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually
ImplReturn,
}
-impl<'a> ImplTraitContext<'_, 'a> {
- fn reborrow<'this>(&'this mut self) -> ImplTraitContext<'this, 'a> {
- use self::ImplTraitContext::*;
- match self {
- Universal(params, bounds, parent) => Universal(params, bounds, *parent),
- ReturnPositionOpaqueTy { origin } => ReturnPositionOpaqueTy { origin: *origin },
- TypeAliasesOpaqueTy => TypeAliasesOpaqueTy,
- Disallowed(pos) => Disallowed(*pos),
- }
- }
-}
-
impl std::fmt::Display for ImplTraitPosition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let name = match self {
let current_owner = std::mem::replace(&mut self.current_hir_id_owner, def_id);
let current_local_counter =
std::mem::replace(&mut self.item_local_id_counter, hir::ItemLocalId::new(1));
+ let current_impl_trait_defs = std::mem::take(&mut self.impl_trait_defs);
+ let current_impl_trait_bounds = std::mem::take(&mut self.impl_trait_bounds);
// Always allocate the first `HirId` for the owner itself.
let _old = self.node_id_to_local_id.insert(owner, hir::ItemLocalId::new(0));
let item = f(self);
debug_assert_eq!(def_id, item.def_id());
+ // `f` should have consumed all the elements in these vectors when constructing `item`.
+ debug_assert!(self.impl_trait_defs.is_empty());
+ debug_assert!(self.impl_trait_bounds.is_empty());
let info = self.make_owner_info(item);
self.attrs = current_attrs;
self.trait_map = current_trait_map;
self.current_hir_id_owner = current_owner;
self.item_local_id_counter = current_local_counter;
+ self.impl_trait_defs = current_impl_trait_defs;
+ self.impl_trait_bounds = current_impl_trait_bounds;
let _old = self.children.insert(def_id, hir::MaybeOwner::Owner(info));
debug_assert!(_old.is_none())
LifetimeRes::Param { .. } => {
(hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit)
}
- LifetimeRes::Fresh { param, .. } => {
- (hir::ParamName::Fresh(param), hir::LifetimeParamKind::Elided)
- }
+ LifetimeRes::Fresh { .. } => (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided),
LifetimeRes::Static | LifetimeRes::Error => return None,
res => panic!(
"Unexpected lifetime resolution {:?} for {:?} at {:?}",
})
}
- /// Creates a new `hir::GenericParam` for every new `Fresh` lifetime and
- /// universal `impl Trait` type parameter encountered while evaluating `f`.
- /// Definitions are created with the provided `parent_def_id`.
- fn add_implicit_generics<T>(
- &mut self,
- generics: &Generics,
- parent_node_id: NodeId,
- f: impl FnOnce(
- &mut Self,
- &mut Vec<hir::GenericParam<'hir>>,
- &mut Vec<hir::WherePredicate<'hir>>,
- ) -> T,
- ) -> (&'hir hir::Generics<'hir>, T) {
- let mut impl_trait_defs = Vec::new();
- let mut impl_trait_bounds = Vec::new();
- let mut lowered_generics = self.lower_generics_mut(
- generics,
- ImplTraitContext::Universal(
- &mut impl_trait_defs,
- &mut impl_trait_bounds,
- self.current_hir_id_owner,
- ),
- );
- let res = f(self, &mut impl_trait_defs, &mut impl_trait_bounds);
-
- let extra_lifetimes = self.resolver.take_extra_lifetime_params(parent_node_id);
- lowered_generics.params.extend(
- extra_lifetimes
- .into_iter()
- .filter_map(|(ident, node_id, res)| {
- self.lifetime_res_to_generic_param(ident, node_id, res)
- })
- .chain(impl_trait_defs),
- );
- lowered_generics.predicates.extend(impl_trait_bounds);
-
- let lowered_generics = lowered_generics.into_generics(self.arena);
- (lowered_generics, res)
- }
-
/// Setup lifetime capture for and impl-trait.
/// The captures will be added to `captures`.
fn while_capturing_lifetimes<T>(
fn lower_assoc_ty_constraint(
&mut self,
constraint: &AssocConstraint,
- mut itctx: ImplTraitContext<'_, 'hir>,
+ itctx: ImplTraitContext,
) -> hir::TypeBinding<'hir> {
debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx);
-
// lower generic arguments of identifier in constraint
let gen_args = if let Some(ref gen_args) = constraint.gen_args {
let gen_args_ctor = match gen_args {
GenericArgs::AngleBracketed(ref data) => {
- self.lower_angle_bracketed_parameter_data(
- data,
- ParamMode::Explicit,
- itctx.reborrow(),
- )
- .0
+ self.lower_angle_bracketed_parameter_data(data, ParamMode::Explicit, itctx).0
}
GenericArgs::Parenthesized(ref data) => {
- let mut err = self.sess.struct_span_err(
- gen_args.span(),
- "parenthesized generic arguments cannot be used in associated type constraints"
- );
- // FIXME: try to write a suggestion here
- err.emit();
+ self.assoc_ty_contraint_param_error_emit(data);
self.lower_angle_bracketed_parameter_data(
&data.as_angle_bracketed_args(),
ParamMode::Explicit,
- itctx.reborrow(),
+ itctx,
)
.0
}
hir::TypeBindingKind::Equality { term }
}
AssocConstraintKind::Bound { ref bounds } => {
- let mut parent_def_id = self.current_hir_id_owner;
// Piggy-back on the `impl Trait` context to figure out the correct behavior.
let (desugar_to_impl_trait, itctx) = match itctx {
// We are in the return position:
// so desugar to
//
// fn foo(x: dyn Iterator<Item = impl Debug>)
- ImplTraitContext::Universal(_, _, parent) if self.is_in_dyn_type => {
- parent_def_id = parent;
- (true, itctx)
- }
+ ImplTraitContext::Universal if self.is_in_dyn_type => (true, itctx),
// In `type Foo = dyn Iterator<Item: Debug>` we desugar to
// `type Foo = dyn Iterator<Item = impl Debug>` but we have to override the
// Desugar `AssocTy: Bounds` into `AssocTy = impl Bounds`. We do this by
// constructing the HIR for `impl bounds...` and then lowering that.
+ let parent_def_id = self.current_hir_id_owner;
let impl_trait_node_id = self.resolver.next_node_id();
self.resolver.create_def(
parent_def_id,
}
}
+ fn assoc_ty_contraint_param_error_emit(&self, data: &ParenthesizedArgs) -> () {
+ let mut err = self.sess.struct_span_err(
+ data.span,
+ "parenthesized generic arguments cannot be used in associated type constraints",
+ );
+ // Suggest removing empty parentheses: "Trait()" -> "Trait"
+ if data.inputs.is_empty() {
+ let parentheses_span =
+ data.inputs_span.shrink_to_lo().to(data.inputs_span.shrink_to_hi());
+ err.multipart_suggestion(
+ "remove these parentheses",
+ vec![(parentheses_span, String::new())],
+ Applicability::MaybeIncorrect,
+ );
+ }
+ // Suggest replacing parentheses with angle brackets `Trait(params...)` to `Trait<params...>`
+ else {
+ // Start of parameters to the 1st argument
+ let open_param = data.inputs_span.shrink_to_lo().to(data
+ .inputs
+ .first()
+ .unwrap()
+ .span
+ .shrink_to_lo());
+ // End of last argument to end of parameters
+ let close_param =
+ data.inputs.last().unwrap().span.shrink_to_hi().to(data.inputs_span.shrink_to_hi());
+ err.multipart_suggestion(
+ &format!("use angle brackets instead",),
+ vec![(open_param, String::from("<")), (close_param, String::from(">"))],
+ Applicability::MaybeIncorrect,
+ );
+ }
+ err.emit();
+ }
+
fn lower_generic_arg(
&mut self,
arg: &ast::GenericArg,
- itctx: ImplTraitContext<'_, 'hir>,
+ itctx: ImplTraitContext,
) -> hir::GenericArg<'hir> {
match arg {
ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(<)),
}
}
- fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext<'_, 'hir>) -> &'hir hir::Ty<'hir> {
+ fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> &'hir hir::Ty<'hir> {
self.arena.alloc(self.lower_ty_direct(t, itctx))
}
qself: &Option<QSelf>,
path: &Path,
param_mode: ParamMode,
- itctx: ImplTraitContext<'_, 'hir>,
+ itctx: ImplTraitContext,
) -> hir::Ty<'hir> {
let id = self.lower_node_id(t.id);
let qpath = self.lower_qpath(t.id, qself, path, param_mode, itctx);
self.ty(span, hir::TyKind::Tup(tys))
}
- fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_, 'hir>) -> hir::Ty<'hir> {
+ fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> {
let kind = match t.kind {
TyKind::Infer => hir::TyKind::Infer,
TyKind::Err => hir::TyKind::Err,
}))
}),
TyKind::Never => hir::TyKind::Never,
- TyKind::Tup(ref tys) => {
- hir::TyKind::Tup(self.arena.alloc_from_iter(
- tys.iter().map(|ty| self.lower_ty_direct(ty, itctx.reborrow())),
- ))
- }
+ TyKind::Tup(ref tys) => hir::TyKind::Tup(
+ self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty_direct(ty, itctx))),
+ ),
TyKind::Paren(ref ty) => {
return self.lower_ty_direct(ty, itctx);
}
GenericBound::Trait(
ref ty,
TraitBoundModifier::None | TraitBoundModifier::MaybeConst,
- ) => Some(this.lower_poly_trait_ref(ty, itctx.reborrow())),
+ ) => Some(this.lower_poly_trait_ref(ty, itctx)),
// `~const ?Bound` will cause an error during AST validation
// anyways, so treat it like `?Bound` as compilation proceeds.
GenericBound::Trait(
|this| this.lower_param_bounds(bounds, nested_itctx),
)
}
- ImplTraitContext::Universal(
- in_band_ty_params,
- in_band_ty_bounds,
- parent_def_id,
- ) => {
+ ImplTraitContext::Universal => {
// Add a definition for the in-band `Param`.
let def_id = self.resolver.local_def_id(def_node_id);
- let hir_bounds = self.lower_param_bounds(
- bounds,
- ImplTraitContext::Universal(
- in_band_ty_params,
- in_band_ty_bounds,
- parent_def_id,
- ),
- );
+ let hir_bounds =
+ self.lower_param_bounds(bounds, ImplTraitContext::Universal);
// Set the name to `impl Bound1 + Bound2`.
let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span);
- in_band_ty_params.push(hir::GenericParam {
+ let param = hir::GenericParam {
hir_id: self.lower_node_id(def_node_id),
name: ParamName::Plain(self.lower_ident(ident)),
pure_wrt_drop: false,
span: self.lower_span(span),
kind: hir::GenericParamKind::Type { default: None, synthetic: true },
colon_span: None,
- });
+ };
+ self.impl_trait_defs.push(param);
+
if let Some(preds) = self.lower_generic_bound_predicate(
ident,
def_node_id,
hir_bounds,
hir::PredicateOrigin::ImplTrait,
) {
- in_band_ty_bounds.push(preds)
+ self.impl_trait_bounds.push(preds)
}
hir::TyKind::Path(hir::QPath::Resolved(
// `make_ret_async`: if `Some`, converts `-> T` into `-> impl Future<Output = T>` in the
// return type. This is used for `async fn` declarations. The `NodeId` is the ID of the
// return type `impl Trait` item.
+ #[tracing::instrument(level = "debug", skip(self))]
fn lower_fn_decl(
&mut self,
decl: &FnDecl,
- mut in_band_ty_params: Option<(
- NodeId,
- &mut Vec<hir::GenericParam<'hir>>,
- &mut Vec<hir::WherePredicate<'hir>>,
- )>,
+ fn_node_id: Option<NodeId>,
kind: FnDeclKind,
make_ret_async: Option<NodeId>,
) -> &'hir hir::FnDecl<'hir> {
- debug!(
- "lower_fn_decl(\
- fn_decl: {:?}, \
- in_band_ty_params: {:?}, \
- kind: {:?}, \
- make_ret_async: {:?})",
- decl, in_band_ty_params, kind, make_ret_async,
- );
-
let c_variadic = decl.c_variadic();
// Skip the `...` (`CVarArgs`) trailing arguments from the AST,
inputs = &inputs[..inputs.len() - 1];
}
let inputs = self.arena.alloc_from_iter(inputs.iter().map(|param| {
- if let Some((_, ibty, ibpb)) = &mut in_band_ty_params {
- self.lower_ty_direct(
- ¶m.ty,
- ImplTraitContext::Universal(ibty, ibpb, self.current_hir_id_owner),
- )
+ if fn_node_id.is_some() {
+ self.lower_ty_direct(¶m.ty, ImplTraitContext::Universal)
} else {
self.lower_ty_direct(
¶m.ty,
let output = if let Some(ret_id) = make_ret_async {
self.lower_async_fn_ret_ty(
&decl.output,
- in_band_ty_params.expect("`make_ret_async` but no `fn_def_id`").0,
+ fn_node_id.expect("`make_ret_async` but no `fn_def_id`"),
ret_id,
)
} else {
match decl.output {
FnRetTy::Ty(ref ty) => {
- let context = match in_band_ty_params {
- Some((node_id, _, _)) if kind.impl_trait_return_allowed() => {
- let fn_def_id = self.resolver.local_def_id(node_id);
+ let context = match fn_node_id {
+ Some(fn_node_id) if kind.impl_trait_return_allowed() => {
+ let fn_def_id = self.resolver.local_def_id(fn_node_id);
ImplTraitContext::ReturnPositionOpaqueTy {
origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
}
(hir::ParamName::Plain(ident), LifetimeRes::Param { param, binder: fn_node_id })
}
// Input lifetime like `'1`:
- LifetimeRes::Fresh { param, .. } => (
- hir::ParamName::Fresh(outer_def_id),
- LifetimeRes::Fresh { param, binder: fn_node_id },
- ),
+ LifetimeRes::Fresh { param, .. } => {
+ (hir::ParamName::Fresh, LifetimeRes::Fresh { param, binder: fn_node_id })
+ }
LifetimeRes::Static | LifetimeRes::Error => continue,
res => {
panic!("Unexpected lifetime resolution {:?} for {:?} at {:?}", res, ident, span)
fn lower_param_bound(
&mut self,
tpb: &GenericBound,
- itctx: ImplTraitContext<'_, 'hir>,
+ itctx: ImplTraitContext,
) -> hir::GenericBound<'hir> {
match tpb {
GenericBound::Trait(p, modifier) => hir::GenericBound::Trait(
) -> hir::Lifetime {
debug!(?self.captured_lifetimes);
let name = match res {
- LifetimeRes::Param { param, binder } => {
+ LifetimeRes::Param { mut param, binder } => {
debug_assert_ne!(ident.name, kw::UnderscoreLifetime);
let p_name = ParamName::Plain(ident);
if let Some(LifetimeCaptureContext { parent_def_id, captures, binders_to_ignore }) =
&& !binders_to_ignore.contains(&binder)
{
match captures.entry(param) {
- Entry::Occupied(_) => {}
+ Entry::Occupied(o) => param = self.resolver.local_def_id(o.get().1),
Entry::Vacant(v) => {
let p_id = self.resolver.next_node_id();
- self.resolver.create_def(
+ let p_def_id = self.resolver.create_def(
*parent_def_id,
p_id,
DefPathData::LifetimeNs(p_name.ident().name),
);
v.insert((span, p_id, p_name, res));
+ param = p_def_id;
}
}
}
- hir::LifetimeName::Param(p_name)
+ hir::LifetimeName::Param(param, p_name)
}
LifetimeRes::Fresh { mut param, binder } => {
debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
span.with_parent(None),
);
- let p_name = ParamName::Fresh(param);
- v.insert((span, p_id, p_name, res));
+ v.insert((span, p_id, ParamName::Fresh, res));
param = p_def_id;
}
}
}
- let p_name = ParamName::Fresh(param);
- hir::LifetimeName::Param(p_name)
+ hir::LifetimeName::Param(param, ParamName::Fresh)
}
LifetimeRes::Anonymous { binder, elided } => {
- let l_name = if elided {
- hir::LifetimeName::Implicit
- } else {
- hir::LifetimeName::Underscore
- };
if let Some(LifetimeCaptureContext { parent_def_id, captures, binders_to_ignore }) =
&mut self.captured_lifetimes
&& !binders_to_ignore.contains(&binder)
ExpnId::root(),
span.with_parent(None),
);
- let p_name = ParamName::Fresh(p_def_id);
- captures.insert(p_def_id, (span, p_id, p_name, res));
- hir::LifetimeName::Param(p_name)
+ captures.insert(p_def_id, (span, p_id, ParamName::Fresh, res));
+ hir::LifetimeName::Param(p_def_id, ParamName::Fresh)
+ } else if elided {
+ hir::LifetimeName::Implicit
} else {
- l_name
+ hir::LifetimeName::Underscore
}
}
LifetimeRes::Static => hir::LifetimeName::Static,
res => panic!("Unexpected lifetime resolution {:?} for {:?} at {:?}", res, ident, span),
};
debug!(?self.captured_lifetimes);
+ debug!(?name);
hir::Lifetime { hir_id: self.lower_node_id(id), span: self.lower_span(span), name }
}
fn lower_generic_param(&mut self, param: &GenericParam) -> hir::GenericParam<'hir> {
let (name, kind) = match param.kind {
GenericParamKind::Lifetime => {
- let param_name = if param.ident.name == kw::StaticLifetime
- || param.ident.name == kw::UnderscoreLifetime
- {
- ParamName::Error
- } else {
- let ident = self.lower_ident(param.ident);
- ParamName::Plain(ident)
- };
+ // AST resolution emitted an error on those parameters, so we lower them using
+ // `ParamName::Error`.
+ let param_name =
+ if let Some(LifetimeRes::Error) = self.resolver.get_lifetime_res(param.id) {
+ ParamName::Error
+ } else {
+ let ident = self.lower_ident(param.ident);
+ ParamName::Plain(ident)
+ };
let kind =
hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit };
)
}
};
- let name = match name {
- hir::ParamName::Plain(ident) => hir::ParamName::Plain(self.lower_ident(ident)),
- name => name,
- };
let hir_id = self.lower_node_id(param.id);
self.lower_attrs(hir_id, ¶m.attrs);
}
}
- fn lower_trait_ref(
- &mut self,
- p: &TraitRef,
- itctx: ImplTraitContext<'_, 'hir>,
- ) -> hir::TraitRef<'hir> {
+ fn lower_trait_ref(&mut self, p: &TraitRef, itctx: ImplTraitContext) -> hir::TraitRef<'hir> {
let path = match self.lower_qpath(p.ref_id, &None, &p.path, ParamMode::Explicit, itctx) {
hir::QPath::Resolved(None, path) => path,
qpath => panic!("lower_trait_ref: unexpected QPath `{:?}`", qpath),
fn lower_poly_trait_ref(
&mut self,
p: &PolyTraitRef,
- mut itctx: ImplTraitContext<'_, 'hir>,
+ itctx: ImplTraitContext,
) -> hir::PolyTraitRef<'hir> {
let bound_generic_params = self.lower_generic_params(&p.bound_generic_params);
let trait_ref = self.with_lifetime_binder(p.trait_ref.ref_id, |this| {
- this.lower_trait_ref(&p.trait_ref, itctx.reborrow())
+ this.lower_trait_ref(&p.trait_ref, itctx)
});
hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) }
}
- fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext<'_, 'hir>) -> hir::MutTy<'hir> {
+ fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> {
hir::MutTy { ty: self.lower_ty(&mt.ty, itctx), mutbl: mt.mutbl }
}
fn lower_param_bounds(
&mut self,
bounds: &[GenericBound],
- itctx: ImplTraitContext<'_, 'hir>,
+ itctx: ImplTraitContext,
) -> hir::GenericBounds<'hir> {
self.arena.alloc_from_iter(self.lower_param_bounds_mut(bounds, itctx))
}
fn lower_param_bounds_mut<'s>(
&'s mut self,
bounds: &'s [GenericBound],
- mut itctx: ImplTraitContext<'s, 'hir>,
+ itctx: ImplTraitContext,
) -> impl Iterator<Item = hir::GenericBound<'hir>> + Captures<'s> + Captures<'a> {
- bounds.iter().map(move |bound| self.lower_param_bound(bound, itctx.reborrow()))
+ bounds.iter().map(move |bound| self.lower_param_bound(bound, itctx))
}
/// Lowers a block directly to an expression, presuming that it
qself: &Option<QSelf>,
p: &Path,
param_mode: ParamMode,
- mut itctx: ImplTraitContext<'_, 'hir>,
+ itctx: ImplTraitContext,
) -> hir::QPath<'hir> {
debug!("lower_qpath(id: {:?}, qself: {:?}, p: {:?})", id, qself, p);
let qself_position = qself.as_ref().map(|q| q.position);
- let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx.reborrow()));
+ let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx));
let partial_res =
self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err));
segment,
param_mode,
parenthesized_generic_args,
- itctx.reborrow(),
+ itctx,
)
},
)),
segment,
param_mode,
ParenthesizedGenericArgs::Err,
- itctx.reborrow(),
+ itctx,
));
let qpath = hir::QPath::TypeRelative(ty, hir_segment);
segment: &PathSegment,
param_mode: ParamMode,
parenthesized_generic_args: ParenthesizedGenericArgs,
- itctx: ImplTraitContext<'_, 'hir>,
+ itctx: ImplTraitContext,
) -> hir::PathSegment<'hir> {
debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment,);
let (mut generic_args, infer_args) = if let Some(ref generic_args) = segment.args {
&mut self,
data: &AngleBracketedArgs,
param_mode: ParamMode,
- mut itctx: ImplTraitContext<'_, 'hir>,
+ itctx: ImplTraitContext,
) -> (GenericArgsCtor<'hir>, bool) {
let has_non_lt_args = data.args.iter().any(|arg| match arg {
AngleBracketedArg::Arg(ast::GenericArg::Lifetime(_))
.args
.iter()
.filter_map(|arg| match arg {
- AngleBracketedArg::Arg(arg) => Some(self.lower_generic_arg(arg, itctx.reborrow())),
+ AngleBracketedArg::Arg(arg) => Some(self.lower_generic_arg(arg, itctx)),
AngleBracketedArg::Constraint(_) => None,
})
.collect();
let bindings = self.arena.alloc_from_iter(data.args.iter().filter_map(|arg| match arg {
- AngleBracketedArg::Constraint(c) => {
- Some(self.lower_assoc_ty_constraint(c, itctx.reborrow()))
- }
+ AngleBracketedArg::Constraint(c) => Some(self.lower_assoc_ty_constraint(c, itctx)),
AngleBracketedArg::Arg(_) => None,
}));
let ctor = GenericArgsCtor { args, bindings, parenthesized: false, span: data.span };
.iter()
.flat_map(|i| i.attrs.as_ref())
.filter(|attr| {
- let arr = [sym::allow, sym::cfg, sym::cfg_attr, sym::deny, sym::forbid, sym::warn];
+ let arr = [
+ sym::allow,
+ sym::cfg,
+ sym::cfg_attr,
+ sym::deny,
+ sym::expect,
+ sym::forbid,
+ sym::warn,
+ ];
!arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(attr)
})
.for_each(|attr| {
} else {
self.err_handler().span_err(
attr.span,
- "allow, cfg, cfg_attr, deny, \
+ "allow, cfg, cfg_attr, deny, expect, \
forbid, and warn are the only allowed built-in attributes in function parameters",
);
}
self.nbsp();
}
self.word("{");
- let empty = tts.is_empty();
- if !empty {
+ if !tts.is_empty() {
self.space();
}
self.ibox(0);
self.print_tts(tts, convert_dollar_crate);
self.end();
- self.bclose(span, empty);
- }
- Some(Delimiter::Invisible) => {
- self.word("/*«*/");
let empty = tts.is_empty();
- if !empty {
- self.space();
- }
- self.ibox(0);
- self.print_tts(tts, convert_dollar_crate);
- self.end();
- if !empty {
- self.space();
- }
- self.word("/*»*/");
+ self.bclose(span, empty);
}
Some(delim) => {
let token_str = self.token_kind_to_string(&token::OpenDelim(delim));
token::CloseDelim(Delimiter::Bracket) => "]".into(),
token::OpenDelim(Delimiter::Brace) => "{".into(),
token::CloseDelim(Delimiter::Brace) => "}".into(),
- token::OpenDelim(Delimiter::Invisible) => "/*«*/".into(),
- token::CloseDelim(Delimiter::Invisible) => "/*»*/".into(),
+ token::OpenDelim(Delimiter::Invisible) | token::CloseDelim(Delimiter::Invisible) => {
+ "".into()
+ }
token::Pound => "#".into(),
token::Dollar => "$".into(),
token::Question => "?".into(),
let lifetime =
self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?;
match lifetime.name {
- hir::LifetimeName::Param(_)
+ hir::LifetimeName::Param(_, hir::ParamName::Plain(_) | hir::ParamName::Error)
| hir::LifetimeName::Error
- | hir::LifetimeName::Static
- | hir::LifetimeName::Underscore => {
+ | hir::LifetimeName::Static => {
let lifetime_span = lifetime.span;
Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span))
}
- hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit => {
+ hir::LifetimeName::Param(_, hir::ParamName::Fresh)
+ | hir::LifetimeName::ImplicitObjectLifetimeDefault
+ | hir::LifetimeName::Implicit
+ | hir::LifetimeName::Underscore => {
// In this case, the user left off the lifetime; so
// they wrote something like:
//
}
}
- CastKind::Misc => {
+ CastKind::PointerExposeAddress => {
let ty_from = op.ty(body, tcx);
let cast_ty_from = CastTy::from_ty(ty_from);
let cast_ty_to = CastTy::from_ty(*ty);
match (cast_ty_from, cast_ty_to) {
- (None, _)
- | (_, None | Some(CastTy::FnPtr))
- | (Some(CastTy::Float), Some(CastTy::Ptr(_)))
- | (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Float)) => {
- span_mirbug!(self, rvalue, "Invalid cast {:?} -> {:?}", ty_from, ty,)
+ (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => (),
+ _ => {
+ span_mirbug!(
+ self,
+ rvalue,
+ "Invalid PointerExposeAddress cast {:?} -> {:?}",
+ ty_from,
+ ty
+ )
}
+ }
+ }
+
+ CastKind::PointerFromExposedAddress => {
+ let ty_from = op.ty(body, tcx);
+ let cast_ty_from = CastTy::from_ty(ty_from);
+ let cast_ty_to = CastTy::from_ty(*ty);
+ match (cast_ty_from, cast_ty_to) {
+ (Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => (),
+ _ => {
+ span_mirbug!(
+ self,
+ rvalue,
+ "Invalid PointerFromExposedAddress cast {:?} -> {:?}",
+ ty_from,
+ ty
+ )
+ }
+ }
+ }
+
+ CastKind::Misc => {
+ let ty_from = op.ty(body, tcx);
+ let cast_ty_from = CastTy::from_ty(ty_from);
+ let cast_ty_to = CastTy::from_ty(*ty);
+ // Misc casts are either between floats and ints, or one ptr type to another.
+ match (cast_ty_from, cast_ty_to) {
(
- Some(CastTy::Int(_)),
- Some(CastTy::Int(_) | CastTy::Float | CastTy::Ptr(_)),
+ Some(CastTy::Int(_) | CastTy::Float),
+ Some(CastTy::Int(_) | CastTy::Float),
)
- | (Some(CastTy::Float), Some(CastTy::Int(_) | CastTy::Float))
- | (Some(CastTy::Ptr(_)), Some(CastTy::Int(_) | CastTy::Ptr(_)))
- | (Some(CastTy::FnPtr), Some(CastTy::Int(_) | CastTy::Ptr(_))) => (),
+ | (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Ptr(_))) => (),
+ _ => {
+ span_mirbug!(
+ self,
+ rvalue,
+ "Invalid Misc cast {:?} -> {:?}",
+ ty_from,
+ ty,
+ )
+ }
}
}
}
fn_def_id: DefId,
mut f: impl FnMut(ty::Region<'tcx>),
) {
- if let Some((owner, late_bounds)) = tcx.is_late_bound_map(fn_def_id.expect_local()) {
+ if let Some(late_bounds) = tcx.is_late_bound_map(fn_def_id.expect_local()) {
for ®ion_def_id in late_bounds.iter() {
let name = tcx.item_name(region_def_id.to_def_id());
let liberated_region = tcx.mk_region(ty::ReFree(ty::FreeRegion {
- scope: owner.to_def_id(),
+ scope: fn_def_id,
bound_region: ty::BoundRegionKind::BrNamed(region_def_id.to_def_id(), name),
}));
f(liberated_region);
+mod context;
+
use crate::edition_panic::use_panic_2021;
use rustc_ast::ptr::P;
use rustc_ast::token;
use rustc_ast::tokenstream::{DelimSpan, TokenStream};
-use rustc_ast::{self as ast, *};
+use rustc_ast::{Expr, ExprKind, MacArgs, MacCall, MacDelimiter, Path, PathSegment, UnOp};
use rustc_ast_pretty::pprust;
use rustc_errors::{Applicability, PResult};
-use rustc_expand::base::*;
+use rustc_expand::base::{DummyResult, ExtCtxt, MacEager, MacResult};
use rustc_parse::parser::Parser;
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
// `core::panic` and `std::panic` are different macros, so we use call-site
// context to pick up whichever is currently in scope.
- let sp = cx.with_call_site_ctxt(span);
+ let call_site_span = cx.with_call_site_ctxt(span);
- let panic_call = if let Some(tokens) = custom_message {
- let path = if use_panic_2021(span) {
+ let panic_path = || {
+ if use_panic_2021(span) {
// On edition 2021, we always call `$crate::panic::panic_2021!()`.
Path {
- span: sp,
+ span: call_site_span,
segments: cx
.std_path(&[sym::panic, sym::panic_2021])
.into_iter()
} else {
// Before edition 2021, we call `panic!()` unqualified,
// such that it calls either `std::panic!()` or `core::panic!()`.
- Path::from_ident(Ident::new(sym::panic, sp))
- };
- // Pass the custom message to panic!().
- cx.expr(
- sp,
+ Path::from_ident(Ident::new(sym::panic, call_site_span))
+ }
+ };
+
+ // Simply uses the user provided message instead of generating custom outputs
+ let expr = if let Some(tokens) = custom_message {
+ let then = cx.expr(
+ call_site_span,
ExprKind::MacCall(MacCall {
- path,
+ path: panic_path(),
args: P(MacArgs::Delimited(
- DelimSpan::from_single(sp),
+ DelimSpan::from_single(call_site_span),
MacDelimiter::Parenthesis,
tokens,
)),
prior_type_ascription: None,
}),
- )
- } else {
+ );
+ expr_if_not(cx, call_site_span, cond_expr, then, None)
+ }
+ // If `generic_assert` is enabled, generates rich captured outputs
+ //
+ // FIXME(c410-f3r) See https://github.com/rust-lang/rust/issues/96949
+ else if let Some(features) = cx.ecfg.features && features.generic_assert {
+ context::Context::new(cx, call_site_span).build(cond_expr, panic_path())
+ }
+ // If `generic_assert` is not enabled, only outputs a literal "assertion failed: ..."
+ // string
+ else {
// Pass our own message directly to $crate::panicking::panic(),
// because it might contain `{` and `}` that should always be
// passed literally.
- cx.expr_call_global(
- sp,
+ let then = cx.expr_call_global(
+ call_site_span,
cx.std_path(&[sym::panicking, sym::panic]),
vec![cx.expr_str(
DUMMY_SP,
pprust::expr_to_string(&cond_expr).escape_debug()
)),
)],
- )
+ );
+ expr_if_not(cx, call_site_span, cond_expr, then, None)
};
- let if_expr =
- cx.expr_if(sp, cx.expr(sp, ExprKind::Unary(UnOp::Not, cond_expr)), panic_call, None);
- MacEager::expr(if_expr)
+
+ MacEager::expr(expr)
}
struct Assert {
- cond_expr: P<ast::Expr>,
+ cond_expr: P<Expr>,
custom_message: Option<TokenStream>,
}
+// if !{ ... } { ... } else { ... }
+fn expr_if_not(
+ cx: &ExtCtxt<'_>,
+ span: Span,
+ cond: P<Expr>,
+ then: P<Expr>,
+ els: Option<P<Expr>>,
+) -> P<Expr> {
+ cx.expr_if(span, cx.expr(span, ExprKind::Unary(UnOp::Not, cond)), then, els)
+}
+
fn parse_assert<'a>(cx: &mut ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PResult<'a, Assert> {
let mut parser = cx.new_parser_from_tts(stream);
--- /dev/null
+use rustc_ast::{ptr::P, Expr, Path};
+use rustc_expand::base::ExtCtxt;
+use rustc_span::Span;
+
+pub(super) struct Context<'cx, 'a> {
+ cx: &'cx ExtCtxt<'a>,
+ span: Span,
+}
+
+impl<'cx, 'a> Context<'cx, 'a> {
+ pub(super) fn new(cx: &'cx ExtCtxt<'a>, span: Span) -> Self {
+ Self { cx, span }
+ }
+
+ /// Builds the whole `assert!` expression.
+ ///
+ /// {
+ /// use ::core::asserting::{ ... };
+ ///
+ /// let mut __capture0 = Capture::new();
+ /// ...
+ /// ...
+ /// ...
+ ///
+ /// if !{
+ /// ...
+ /// ...
+ /// ...
+ /// } {
+ /// panic!(
+ /// "Assertion failed: ... \n With expansion: ...",
+ /// __capture0,
+ /// ...
+ /// ...
+ /// ...
+ /// );
+ /// }
+ /// }
+ pub(super) fn build(self, _cond_expr: P<Expr>, _panic_path: Path) -> P<Expr> {
+ let Self { cx, span, .. } = self;
+ let stmts = Vec::new();
+ cx.expr_block(cx.block(span, stmts))
+ }
+}
//! This crate contains implementations of built-in macros and other code generating facilities
//! injecting code into the crate before it is lowered to HIR.
+#![allow(rustc::potential_query_instability)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(array_windows)]
#![feature(box_patterns)]
#![feature(decl_macro)]
#![feature(is_sorted)]
-#![feature(nll)]
+#![feature(let_chains)]
#![feature(let_else)]
+#![feature(nll)]
#![feature(proc_macro_internals)]
#![feature(proc_macro_quote)]
#![recursion_limit = "256"]
-#![allow(rustc::potential_query_instability)]
extern crate proc_macro;
let operand = codegen_operand(fx, operand);
lval.write_cvalue(fx, operand.cast_pointer_to(to_layout));
}
- Rvalue::Cast(CastKind::Misc, ref operand, to_ty) => {
+ Rvalue::Cast(
+ CastKind::Misc
+ | CastKind::PointerExposeAddress
+ | CastKind::PointerFromExposedAddress,
+ ref operand,
+ to_ty,
+ ) => {
let operand = codegen_operand(fx, operand);
let from_ty = operand.layout().ty;
let to_ty = fx.monomorphize(to_ty);
tempfile = "3.2"
thorin-dwp = "0.2"
pathdiff = "0.2.0"
+serde_json = "1.0.59"
snap = "1"
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
regex = "1.4"
use rustc_middle::middle::dependency_format::Linkage;
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, SymbolExportKind};
use rustc_middle::ty::TyCtxt;
-use rustc_serialize::{json, Encoder};
use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip};
use rustc_session::Session;
use rustc_span::symbol::Symbol;
self.cmd.arg("-s");
let mut arg = OsString::from("EXPORTED_FUNCTIONS=");
- let mut encoded = String::new();
-
- {
- let mut encoder = json::Encoder::new(&mut encoded);
- let res = encoder.emit_seq(symbols.len(), |encoder| {
- for (i, sym) in symbols.iter().enumerate() {
- encoder.emit_seq_elt(i, |encoder| encoder.emit_str(&("_".to_owned() + sym)))?;
- }
- Ok(())
- });
- if let Err(e) = res {
- self.sess.fatal(&format!("failed to encode exported symbols: {}", e));
- }
- }
+ let encoded = serde_json::to_string(
+ &symbols.iter().map(|sym| "_".to_owned() + sym).collect::<Vec<_>>(),
+ )
+ .unwrap();
debug!("{}", encoded);
+
arg.push(encoded);
self.cmd.arg(arg);
let cast = bx.cx().layout_of(self.monomorphize(mir_cast_ty));
let val = match *kind {
+ mir::CastKind::PointerExposeAddress => {
+ assert!(bx.cx().is_backend_immediate(cast));
+ let llptr = operand.immediate();
+ let llcast_ty = bx.cx().immediate_backend_type(cast);
+ let lladdr = bx.ptrtoint(llptr, llcast_ty);
+ OperandValue::Immediate(lladdr)
+ }
mir::CastKind::Pointer(PointerCast::ReifyFnPointer) => {
match *operand.layout.ty.kind() {
ty::FnDef(def_id, substs) => {
mir::CastKind::Pointer(
PointerCast::MutToConstPointer | PointerCast::ArrayToPointer,
)
- | mir::CastKind::Misc => {
+ | mir::CastKind::Misc
+ // Since int2ptr can have arbitrary integer types as input (so we have to do
+ // sign extension and all that), it is currently best handled in the same code
+ // path as the other integer-to-X casts.
+ | mir::CastKind::PointerFromExposedAddress => {
assert!(bx.cx().is_backend_immediate(cast));
let ll_t_out = bx.cx().immediate_backend_type(cast);
if operand.layout.abi.is_uninhabited() {
(CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Ptr(_)) => {
bx.pointercast(llval, ll_t_out)
}
- (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) => {
- bx.ptrtoint(llval, ll_t_out)
- }
(CastTy::Int(_), CastTy::Ptr(_)) => {
let usize_llval = bx.intcast(llval, bx.cx().type_isize(), signed);
bx.inttoptr(usize_llval, ll_t_out)
+use std::assert_matches::assert_matches;
use std::convert::TryFrom;
use rustc_apfloat::ieee::{Double, Single};
self.unsize_into(src, cast_ty, dest)?;
}
+ PointerExposeAddress => {
+ let src = self.read_immediate(src)?;
+ let res = self.pointer_expose_address_cast(&src, cast_ty)?;
+ self.write_immediate(res, dest)?;
+ }
+
+ PointerFromExposedAddress => {
+ let src = self.read_immediate(src)?;
+ let res = self.pointer_from_exposed_address_cast(&src, cast_ty)?;
+ self.write_immediate(res, dest)?;
+ }
+
Misc => {
let src = self.read_immediate(src)?;
let res = self.misc_cast(&src, cast_ty)?;
// # The remaining source values are scalar and "int-like".
let scalar = src.to_scalar()?;
+ Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into())
+ }
- // If we are casting from a pointer to something
- // that is not a pointer, mark the pointer as exposed
- if src.layout.ty.is_any_ptr() && !cast_ty.is_any_ptr() {
- let ptr = self.scalar_to_ptr(scalar)?;
-
- match ptr.into_pointer_or_addr() {
- Ok(ptr) => {
- M::expose_ptr(self, ptr)?;
- }
- Err(_) => {
- // do nothing, exposing an invalid pointer
- // has no meaning
- }
- };
- }
+ pub fn pointer_expose_address_cast(
+ &mut self,
+ src: &ImmTy<'tcx, M::PointerTag>,
+ cast_ty: Ty<'tcx>,
+ ) -> InterpResult<'tcx, Immediate<M::PointerTag>> {
+ assert_matches!(src.layout.ty.kind(), ty::RawPtr(_) | ty::FnPtr(_));
+ assert!(cast_ty.is_integral());
+ let scalar = src.to_scalar()?;
+ let ptr = self.scalar_to_ptr(scalar)?;
+ match ptr.into_pointer_or_addr() {
+ Ok(ptr) => M::expose_ptr(self, ptr)?,
+ Err(_) => {} // do nothing, exposing an invalid pointer has no meaning
+ };
Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into())
}
+ pub fn pointer_from_exposed_address_cast(
+ &mut self,
+ src: &ImmTy<'tcx, M::PointerTag>,
+ cast_ty: Ty<'tcx>,
+ ) -> InterpResult<'tcx, Immediate<M::PointerTag>> {
+ assert!(src.layout.ty.is_integral());
+ assert_matches!(cast_ty.kind(), ty::RawPtr(_));
+
+ // First cast to usize.
+ let scalar = src.to_scalar()?;
+ let addr = self.cast_from_int_like(scalar, src.layout, self.tcx.types.usize)?;
+ let addr = addr.to_machine_usize(self)?;
+
+ // Then turn address into pointer.
+ let ptr = M::ptr_from_addr_cast(&self, addr);
+ Ok(Scalar::from_maybe_pointer(ptr, self).into())
+ }
+
pub fn cast_from_int_like(
&self,
scalar: Scalar<M::PointerTag>, // input value (there is no ScalarTy so we separate data+layout)
Scalar::from_uint(v, size)
}
- RawPtr(_) => {
- assert!(src_layout.ty.is_integral());
-
- let size = self.pointer_size();
- let addr = u64::try_from(size.truncate(v)).unwrap();
-
- let ptr = M::ptr_from_addr_cast(&self, addr);
- Scalar::from_maybe_pointer(ptr, self)
- }
-
Float(FloatTy::F32) if signed => Scalar::from_f32(Single::from_i128(v as i128).value),
Float(FloatTy::F64) if signed => Scalar::from_f64(Double::from_i128(v as i128).value),
Float(FloatTy::F32) => Scalar::from_f32(Single::from_u128(v).value),
msg,
})
}
+ // Ensure we never consider the null pointer dereferencable.
+ if M::PointerTag::OFFSET_IS_ADDR {
+ assert_ne!(ptr.addr(), Size::ZERO);
+ }
// Test align. Check this last; if both bounds and alignment are violated
// we want the error to be about the bounds.
if let Some(align) = align {
Ok(src_val) => {
assert!(!src.layout.is_unsized(), "cannot have unsized immediates");
// Yay, we got a value that we can write directly.
- // FIXME: Add a check to make sure that if `src` is indirect,
- // it does not overlap with `dest`.
return self.write_immediate_no_validate(*src_val, dest);
}
Err(mplace) => mplace,
});
assert_eq!(src.meta, dest.meta, "Can only copy between equally-sized instances");
- self.mem_copy(src.ptr, src.align, dest.ptr, dest.align, size, /*nonoverlapping*/ true)
+ self.mem_copy(src.ptr, src.align, dest.ptr, dest.align, size, /*nonoverlapping*/ false)
}
/// Copies the data from an operand to a place. The layouts may disagree, but they must
place: mir::Place<'tcx>,
) -> InterpResult<'tcx> {
let dest = self.eval_place(place)?;
+ // FIXME: ensure some kind of non-aliasing between LHS and RHS?
+ // Also see https://github.com/rust-lang/rust/issues/68364.
use rustc_middle::mir::Rvalue::*;
match *rvalue {
use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
-use rustc_middle::ty::cast::CastTy;
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt};
use rustc_middle::ty::{Binder, TraitPredicate, TraitRef, TypeFoldable};
}
}
- Rvalue::Cast(
- CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer),
- _,
- _,
- ) => {}
-
Rvalue::Cast(
CastKind::Pointer(
- PointerCast::UnsafeFnPointer
+ PointerCast::MutToConstPointer
+ | PointerCast::ArrayToPointer
+ | PointerCast::UnsafeFnPointer
| PointerCast::ClosureFnPointer(_)
| PointerCast::ReifyFnPointer,
),
_,
_,
) => {
- // Nothing to do here. Function pointer casts are allowed now.
+ // These are all okay; they only change the type, not the data.
}
Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), _, _) => {
- // Nothing to check here (`check_local_or_return_ty` ensures no trait objects occur
- // in the type of any local, which also excludes casts).
+ // Unsizing is implemented for CTFE.
}
- Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => {
- let operand_ty = operand.ty(self.body, self.tcx);
- let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
- let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
-
- if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) {
- self.check_op(ops::RawPtrToIntCast);
- }
+ Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => {
+ self.check_op(ops::RawPtrToIntCast);
}
+ Rvalue::Cast(CastKind::PointerFromExposedAddress, _, _) => {
+ // Since no pointer can ever get exposed (rejected above), this is easy to support.
+ }
+
+ Rvalue::Cast(CastKind::Misc, _, _) => {}
Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {}
Rvalue::ShallowInitBox(_, _) => {}
use rustc_middle::mir::traversal::ReversePostorderIter;
use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
-use rustc_middle::ty::cast::CastTy;
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::{self, List, TyCtxt, TypeFoldable};
use rustc_span::Span;
Rvalue::ThreadLocalRef(_) => return Err(Unpromotable),
- Rvalue::Cast(kind, operand, cast_ty) => {
- if matches!(kind, CastKind::Misc) {
- let operand_ty = operand.ty(self.body, self.tcx);
- let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
- let cast_out = CastTy::from_ty(*cast_ty).expect("bad output type for cast");
- if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) {
- // ptr-to-int casts are not possible in consts and thus not promotable
- return Err(Unpromotable);
- }
- // int-to-ptr casts are fine, they just use the integer value at pointer type.
- }
+ // ptr-to-int casts are not possible in consts and thus not promotable
+ Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => return Err(Unpromotable),
+ // all other casts including int-to-ptr casts are fine, they just use the integer value
+ // at pointer type.
+ Rvalue::Cast(_, operand, _) => {
self.validate_operand(operand)?;
}
test(u64::MAX as u128, base);
test(u128::MAX, base);
- for i in 0..1_000 {
+ const N: u128 = if cfg!(miri) { 10 } else { 1000 };
+
+ for i in 0..N {
test(i * 983, base);
}
}
v
…
*/
+ #[cfg(not(miri))]
const NR_NODES: usize = 1 << 14;
+ #[cfg(miri)]
+ const NR_NODES: usize = 1 << 3;
let mut nodes = vec![];
for i in 1..NR_NODES {
nodes.push((i - 1, i));
+// FIXME: owning_ref is not sound under stacked borrows. Preferably, get rid of it.
+#[cfg(not(miri))]
mod owning_ref {
use super::super::OwningRef;
use super::super::{BoxRef, Erased, ErasedBoxRef, RcRef};
}
}
+// FIXME: owning_ref is not sound under stacked borrows. Preferably, get rid of it.
+#[cfg(not(miri))]
mod owning_ref_mut {
use super::super::BoxRef;
use super::super::{BoxRefMut, Erased, ErasedBoxRefMut, OwningRefMut};
// elements from spill (at most LEN - 1 bytes could have overflowed
// into the spill). The memcpy call is optimized away because the size
// is known. And the whole copy is optimized away for LEN == 1.
+ let dst = self.buf.as_mut_ptr() as *mut u8;
let src = self.buf.get_unchecked(BUFFER_SPILL_INDEX) as *const _ as *const u8;
- ptr::copy_nonoverlapping(src, self.buf.as_mut_ptr() as *mut u8, LEN - 1);
+ ptr::copy_nonoverlapping(src, dst, LEN - 1);
// This function should only be called when the write fills the buffer.
// Therefore, when LEN == 1, the new `self.nbuf` must be zero.
/// Adds a value to the set.
///
- /// If the set did not have this value present, `true` is returned.
+ /// Returns whether the value was newly inserted. That is:
///
- /// If the set did have this value present, `false` is returned.
+ /// - If the set did not previously contain this value, `true` is returned.
+ /// - If the set already contained this value, `false` is returned.
#[inline]
pub fn insert(&mut self, elem: T) -> bool {
self.map.insert(elem, ()).is_none()
[dependencies]
libc = "0.2"
tracing = { version = "0.1.28" }
+serde_json = "1.0.59"
rustc_log = { path = "../rustc_log" }
rustc_middle = { path = "../rustc_middle" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
use rustc_metadata::locator;
use rustc_save_analysis as save;
use rustc_save_analysis::DumpHandler;
-use rustc_serialize::json::ToJson;
use rustc_session::config::{nightly_options, CG_OPTIONS, DB_OPTIONS};
use rustc_session::config::{ErrorOutputType, Input, OutputType, PrintRequest, TrimmedDefPaths};
use rustc_session::cstore::MetadataLoader;
use rustc_session::{early_error, early_error_no_abort, early_warn};
use rustc_span::source_map::{FileLoader, FileName};
use rustc_span::symbol::sym;
+use rustc_target::json::ToJson;
use std::borrow::Cow;
use std::cmp::max;
return early_exit();
}
- if sess.opts.debugging_opts.parse_only
- || sess.opts.debugging_opts.show_span.is_some()
- || sess.opts.debugging_opts.ast_json_noexpand
- {
+ if sess.opts.debugging_opts.parse_only || sess.opts.debugging_opts.show_span.is_some() {
return early_exit();
}
queries.global_ctxt()?;
- if sess.opts.debugging_opts.no_analysis || sess.opts.debugging_opts.ast_json {
+ if sess.opts.debugging_opts.no_analysis {
return early_exit();
}
}
Sysroot => println!("{}", sess.sysroot.display()),
TargetLibdir => println!("{}", sess.target_tlib_path.dir.display()),
- TargetSpec => println!("{}", sess.target.to_json().pretty()),
+ TargetSpec => {
+ println!("{}", serde_json::to_string_pretty(&sess.target.to_json()).unwrap());
+ }
FileNames | CrateName => {
let input = input.unwrap_or_else(|| {
early_error(ErrorOutputType::default(), "no input file provided")
+#### Note: this error code is no longer emitted by the compiler.
+
A lifetime was declared more than once in the same scope.
Erroneous code example:
-```compile_fail,E0263
+```compile_fail,E0403
fn foo<'a, 'b, 'a>(x: &'a str, y: &'b str, z: &'a str) { // error!
}
```
parser-forgot-paren = perhaps you forgot parentheses?
parser-expect-path = expected a path
+
+parser-maybe-recover-from-bad-qpath-stage-2 =
+ missing angle brackets in associated item path
+ .suggestion = try: `{$ty}`
+
+parser-incorrect-semicolon =
+ expected item, found `;`
+ .suggestion = remove this semicolon
+ .help = {$name} declarations are not followed by a semicolon
+
+parser-incorrect-use-of-await =
+ incorrect use of `await`
+ .parentheses-suggestion = `await` is not a method call, remove the parentheses
+ .postfix-suggestion = `await` is a postfix operation
+
+parser-in-in-typo =
+ expected iterable, found keyword `in`
+ .suggestion = remove the duplicated `in`
termcolor = "1.0"
annotate-snippets = "0.8.0"
termize = "0.1.1"
+serde = { version = "1.0.125", features = ["derive"] }
+serde_json = "1.0.59"
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["handleapi", "synchapi", "winbase"] }
fn emit_suggestion_default(
&mut self,
+ span: &MultiSpan,
suggestion: &CodeSuggestion,
args: &FluentArgs<'_>,
level: &Level,
None,
}
+ if let Some(span) = span.primary_span() {
+ // Compare the primary span of the diagnostic with the span of the suggestion
+ // being emitted. If they belong to the same file, we don't *need* to show the
+ // file name, saving in verbosity, but if it *isn't* we do need it, otherwise we're
+ // telling users to make a change but not clarifying *where*.
+ let loc = sm.lookup_char_pos(parts[0].span.lo());
+ if loc.file.name != sm.span_to_filename(span) && loc.file.name.is_real() {
+ buffer.puts(row_num - 1, 0, "--> ", Style::LineNumber);
+ buffer.append(
+ row_num - 1,
+ &format!(
+ "{}:{}:{}",
+ sm.filename_for_diagnostics(&loc.file.name),
+ sm.doctest_offset_line(&loc.file.name, loc.line),
+ loc.col.0 + 1,
+ ),
+ Style::LineAndColumn,
+ );
+ for _ in 0..max_line_num_len {
+ buffer.prepend(row_num - 1, " ", Style::NoStyle);
+ }
+ row_num += 1;
+ }
+ }
let show_code_change = if has_deletion && !is_multiline {
DisplaySuggestion::Diff
} else if (parts.len() != 1 || parts[0].snippet.trim() != complete.trim())
assert!(!file_lines.lines.is_empty() || parts[0].span.is_dummy());
let line_start = sm.lookup_char_pos(parts[0].span.lo()).line;
- draw_col_separator_no_space(&mut buffer, 1, max_line_num_len + 1);
+ draw_col_separator_no_space(&mut buffer, row_num - 1, max_line_num_len + 1);
let mut lines = complete.lines();
if lines.clone().next().is_none() {
// Account for a suggestion to completely remove a line(s) with whitespace (#94192).
) {
panic!("failed to emit error: {}", e);
}
- } else if let Err(e) =
- self.emit_suggestion_default(sugg, args, &Level::Help, max_line_num_len)
- {
+ } else if let Err(e) = self.emit_suggestion_default(
+ span,
+ sugg,
+ args,
+ &Level::Help,
+ max_line_num_len,
+ ) {
panic!("failed to emit error: {}", e);
};
}
use std::sync::{Arc, Mutex};
use std::vec;
-use rustc_serialize::json::{as_json, as_pretty_json};
+use serde::Serialize;
#[cfg(test)]
mod tests;
fn emit_diagnostic(&mut self, diag: &crate::Diagnostic) {
let data = Diagnostic::from_errors_diagnostic(diag, self);
let result = if self.pretty {
- writeln!(&mut self.dst, "{}", as_pretty_json(&data))
+ writeln!(&mut self.dst, "{}", serde_json::to_string_pretty(&data).unwrap())
} else {
- writeln!(&mut self.dst, "{}", as_json(&data))
+ writeln!(&mut self.dst, "{}", serde_json::to_string(&data).unwrap())
}
.and_then(|_| self.dst.flush());
if let Err(e) = result {
fn emit_artifact_notification(&mut self, path: &Path, artifact_type: &str) {
let data = ArtifactNotification { artifact: path, emit: artifact_type };
let result = if self.pretty {
- writeln!(&mut self.dst, "{}", as_pretty_json(&data))
+ writeln!(&mut self.dst, "{}", serde_json::to_string_pretty(&data).unwrap())
} else {
- writeln!(&mut self.dst, "{}", as_json(&data))
+ writeln!(&mut self.dst, "{}", serde_json::to_string(&data).unwrap())
}
.and_then(|_| self.dst.flush());
if let Err(e) = result {
.collect();
let report = FutureIncompatReport { future_incompat_report: data };
let result = if self.pretty {
- writeln!(&mut self.dst, "{}", as_pretty_json(&report))
+ writeln!(&mut self.dst, "{}", serde_json::to_string_pretty(&report).unwrap())
} else {
- writeln!(&mut self.dst, "{}", as_json(&report))
+ writeln!(&mut self.dst, "{}", serde_json::to_string(&report).unwrap())
}
.and_then(|_| self.dst.flush());
if let Err(e) = result {
let lint_level = lint_level.as_str();
let data = UnusedExterns { lint_level, unused_extern_names: unused_externs };
let result = if self.pretty {
- writeln!(&mut self.dst, "{}", as_pretty_json(&data))
+ writeln!(&mut self.dst, "{}", serde_json::to_string_pretty(&data).unwrap())
} else {
- writeln!(&mut self.dst, "{}", as_json(&data))
+ writeln!(&mut self.dst, "{}", serde_json::to_string(&data).unwrap())
}
.and_then(|_| self.dst.flush());
if let Err(e) = result {
// The following data types are provided just for serialisation.
-#[derive(Encodable)]
+#[derive(Serialize)]
struct Diagnostic {
/// The primary error message.
message: String,
rendered: Option<String>,
}
-#[derive(Encodable)]
+#[derive(Serialize)]
struct DiagnosticSpan {
file_name: String,
byte_start: u32,
expansion: Option<Box<DiagnosticSpanMacroExpansion>>,
}
-#[derive(Encodable)]
+#[derive(Serialize)]
struct DiagnosticSpanLine {
text: String,
highlight_end: usize,
}
-#[derive(Encodable)]
+#[derive(Serialize)]
struct DiagnosticSpanMacroExpansion {
/// span where macro was applied to generate this code; note that
/// this may itself derive from a macro (if
def_site_span: DiagnosticSpan,
}
-#[derive(Encodable)]
+#[derive(Serialize)]
struct DiagnosticCode {
/// The code itself.
code: String,
explanation: Option<&'static str>,
}
-#[derive(Encodable)]
+#[derive(Serialize)]
struct ArtifactNotification<'a> {
/// The path of the artifact.
artifact: &'a Path,
emit: &'a str,
}
-#[derive(Encodable)]
+#[derive(Serialize)]
struct FutureBreakageItem {
diagnostic: Diagnostic,
}
-#[derive(Encodable)]
+#[derive(Serialize)]
struct FutureIncompatReport {
future_incompat_report: Vec<FutureBreakageItem>,
}
// doctest component (as well as cargo).
// We could unify this struct the one in rustdoc but they have different
// ownership semantics, so doing so would create wasteful allocations.
-#[derive(Encodable)]
+#[derive(Serialize)]
struct UnusedExterns<'a, 'b, 'c> {
/// The severity level of the unused dependencies lint
lint_level: &'a str,
use crate::emitter::{ColorConfig, HumanReadableErrorType};
use crate::Handler;
-use rustc_serialize::json;
use rustc_span::{BytePos, Span};
use std::str;
-#[derive(Debug, PartialEq, Eq)]
+use serde::Deserialize;
+
+#[derive(Deserialize, Debug, PartialEq, Eq)]
+struct TestData {
+ spans: Vec<SpanTestData>,
+}
+
+#[derive(Deserialize, Debug, PartialEq, Eq)]
struct SpanTestData {
pub byte_start: u32,
pub byte_end: u32,
let bytes = output.lock().unwrap();
let actual_output = str::from_utf8(&bytes).unwrap();
- let actual_output = json::from_str(&actual_output).unwrap();
- let spans = actual_output["spans"].as_array().unwrap();
+ let actual_output: TestData = serde_json::from_str(actual_output).unwrap();
+ let spans = actual_output.spans;
assert_eq!(spans.len(), 1);
- let obj = &spans[0];
- let actual_output = SpanTestData {
- byte_start: obj["byte_start"].as_u64().unwrap() as u32,
- byte_end: obj["byte_end"].as_u64().unwrap() as u32,
- line_start: obj["line_start"].as_u64().unwrap() as u32,
- line_end: obj["line_end"].as_u64().unwrap() as u32,
- column_start: obj["column_start"].as_u64().unwrap() as u32,
- column_end: obj["column_end"].as_u64().unwrap() as u32,
- };
- assert_eq!(expected_output, actual_output);
+
+ assert_eq!(expected_output, spans[0])
})
}
attrs: AttrVec::new(),
tokens: None,
});
- ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span: sp }
+ self.stmt_local(local, sp)
}
// Generates `let _: Type;`, which is usually used for type assertions.
attrs: AttrVec::new(),
tokens: None,
});
+ self.stmt_local(local, span)
+ }
+
+ pub fn stmt_local(&self, local: P<ast::Local>, span: Span) -> ast::Stmt {
ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span }
}
(active, allow_internal_unstable, "1.0.0", None, None),
/// Allows identifying the `compiler_builtins` crate.
(active, compiler_builtins, "1.13.0", None, None),
+ /// Outputs useful `assert!` messages
+ (active, generic_assert, "1.63.0", None, None),
/// Allows using the `rust-intrinsic`'s "ABI".
(active, intrinsics, "1.0.0", None, None),
/// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic.
"#[rustc_has_incoherent_inherent_impls] allows the addition of incoherent inherent impls for \
the given type by annotating all impl items with #[rustc_allow_incoherent_impl]."
),
+ rustc_attr!(
+ rustc_box, AttributeType::Normal, template!(Word), ErrorFollowing,
+ "#[rustc_box] allows creating boxes \
+ and it is only intended to be used in `alloc`."
+ ),
+
BuiltinAttribute {
name: sym::rustc_diagnostic_item,
// FIXME: This can be `true` once we always use `tcx.is_diagnostic_item`.
#[track_caller]
pub fn expect_non_local<OtherId>(self) -> Res<OtherId> {
- self.map_id(|_| panic!("unexpected `Res::Local`"))
+ self.map_id(
+ #[track_caller]
+ |_| panic!("unexpected `Res::Local`"),
+ )
}
pub fn macro_kind(self) -> Option<MacroKind> {
use smallvec::SmallVec;
use std::fmt;
-#[derive(Copy, Clone, Encodable, HashStable_Generic)]
+#[derive(Debug, Copy, Clone, Encodable, HashStable_Generic)]
pub struct Lifetime {
pub hir_id: HirId,
pub span: Span,
/// ```
/// where `'f` is something like `Fresh(0)`. The indices are
/// unique per impl, but not necessarily continuous.
- Fresh(LocalDefId),
+ Fresh,
/// Indicates an illegal name was given and an error has been
/// reported (so we should squelch other derived errors). Occurs
pub fn ident(&self) -> Ident {
match *self {
ParamName::Plain(ident) => ident,
- ParamName::Fresh(_) | ParamName::Error => {
- Ident::with_dummy_span(kw::UnderscoreLifetime)
- }
+ ParamName::Fresh | ParamName::Error => Ident::with_dummy_span(kw::UnderscoreLifetime),
}
}
#[derive(HashStable_Generic)]
pub enum LifetimeName {
/// User-given names or fresh (synthetic) names.
- Param(ParamName),
+ Param(LocalDefId, ParamName),
/// User wrote nothing (e.g., the lifetime in `&u32`).
Implicit,
| LifetimeName::Error => Ident::empty(),
LifetimeName::Underscore => Ident::with_dummy_span(kw::UnderscoreLifetime),
LifetimeName::Static => Ident::with_dummy_span(kw::StaticLifetime),
- LifetimeName::Param(param_name) => param_name.ident(),
+ LifetimeName::Param(_, param_name) => param_name.ident(),
+ }
+ }
+
+ pub fn is_anonymous(&self) -> bool {
+ match *self {
+ LifetimeName::ImplicitObjectLifetimeDefault
+ | LifetimeName::Implicit
+ | LifetimeName::Underscore
+ | LifetimeName::Param(_, ParamName::Fresh)
+ | LifetimeName::Error => true,
+ LifetimeName::Static | LifetimeName::Param(..) => false,
}
}
| LifetimeName::Implicit
| LifetimeName::Underscore => true,
- // It might seem surprising that `Fresh(_)` counts as
+ // It might seem surprising that `Fresh` counts as
// *not* elided -- but this is because, as far as the code
- // in the compiler is concerned -- `Fresh(_)` variants act
+ // in the compiler is concerned -- `Fresh` variants act
// equivalently to "some fresh name". They correspond to
// early-bound regions on an impl, in other words.
- LifetimeName::Error | LifetimeName::Param(_) | LifetimeName::Static => false,
+ LifetimeName::Error | LifetimeName::Param(..) | LifetimeName::Static => false,
}
}
pub fn normalize_to_macros_2_0(&self) -> LifetimeName {
match *self {
- LifetimeName::Param(param_name) => {
- LifetimeName::Param(param_name.normalize_to_macros_2_0())
+ LifetimeName::Param(def_id, param_name) => {
+ LifetimeName::Param(def_id, param_name.normalize_to_macros_2_0())
}
lifetime_name => lifetime_name,
}
}
}
-impl fmt::Debug for Lifetime {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "lifetime({}: {})", self.hir_id, self.name.ident())
- }
-}
-
impl Lifetime {
pub fn is_elided(&self) -> bool {
self.name.is_elided()
})
}
+ pub fn outlives_for_param(
+ &self,
+ param_def_id: LocalDefId,
+ ) -> impl Iterator<Item = &WhereRegionPredicate<'_>> {
+ self.predicates.iter().filter_map(move |pred| match pred {
+ WherePredicate::RegionPredicate(rp) if rp.is_param_bound(param_def_id) => Some(rp),
+ _ => None,
+ })
+ }
+
pub fn bounds_span_for_suggestions(&self, param_def_id: LocalDefId) -> Option<Span> {
self.bounds_for_param(param_def_id).flat_map(|bp| bp.bounds.iter().rev()).find_map(
|bound| {
pub bounds: GenericBounds<'hir>,
}
+impl<'hir> WhereRegionPredicate<'hir> {
+ /// Returns `true` if `param_def_id` matches the `lifetime` of this predicate.
+ pub fn is_param_bound(&self, param_def_id: LocalDefId) -> bool {
+ match self.lifetime.name {
+ LifetimeName::Param(id, _) => id == param_def_id,
+ _ => false,
+ }
+ }
+}
+
/// An equality predicate (e.g., `T = int`); currently unsupported.
#[derive(Debug, HashStable_Generic)]
pub struct WhereEqPredicate<'hir> {
Some(match *self {
ItemKind::Fn(_, ref generics, _)
| ItemKind::TyAlias(_, ref generics)
- | ItemKind::OpaqueTy(OpaqueTy {
- ref generics, origin: OpaqueTyOrigin::TyAlias, ..
- })
+ | ItemKind::OpaqueTy(OpaqueTy { ref generics, .. })
| ItemKind::Enum(_, ref generics)
| ItemKind::Struct(_, ref generics)
| ItemKind::Union(_, ref generics)
| ItemKind::Trait(_, _, ref generics, _, _)
+ | ItemKind::TraitAlias(ref generics, _)
| ItemKind::Impl(Impl { ref generics, .. }) => generics,
_ => return None,
})
}
}
- pub fn generics(&self) -> Option<&'hir Generics<'hir>> {
- match self {
- OwnerNode::TraitItem(TraitItem { generics, .. })
- | OwnerNode::ImplItem(ImplItem { generics, .. }) => Some(generics),
- OwnerNode::Item(item) => item.kind.generics(),
- _ => None,
- }
+ pub fn generics(self) -> Option<&'hir Generics<'hir>> {
+ Node::generics(self.into())
}
pub fn def_id(self) -> LocalDefId {
}
}
- pub fn generics(&self) -> Option<&'hir Generics<'hir>> {
+ pub fn generics(self) -> Option<&'hir Generics<'hir>> {
match self {
- Node::TraitItem(TraitItem { generics, .. })
+ Node::ForeignItem(ForeignItem {
+ kind: ForeignItemKind::Fn(_, _, generics), ..
+ })
+ | Node::TraitItem(TraitItem { generics, .. })
| Node::ImplItem(ImplItem { generics, .. }) => Some(generics),
Node::Item(item) => item.kind.generics(),
_ => None,
pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) {
visitor.visit_id(lifetime.hir_id);
match lifetime.name {
- LifetimeName::Param(ParamName::Plain(ident)) => {
+ LifetimeName::Param(_, ParamName::Plain(ident)) => {
visitor.visit_ident(ident);
}
- LifetimeName::Param(ParamName::Fresh(_))
- | LifetimeName::Param(ParamName::Error)
+ LifetimeName::Param(_, ParamName::Fresh)
+ | LifetimeName::Param(_, ParamName::Error)
| LifetimeName::Static
| LifetimeName::Error
| LifetimeName::Implicit
visitor.visit_id(param.hir_id);
match param.name {
ParamName::Plain(ident) => visitor.visit_ident(ident),
- ParamName::Error | ParamName::Fresh(_) => {}
+ ParamName::Error | ParamName::Fresh => {}
}
match param.kind {
GenericParamKind::Lifetime { .. } => {}
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
#![feature(associated_type_defaults)]
+#![feature(closure_track_caller)]
#![feature(const_btree_new)]
#![feature(let_else)]
#![feature(once_cell)]
subst::{GenericArgKind, Subst, SubstsRef},
Binder, EarlyBinder, List, Region, Ty, TyCtxt, TypeFoldable,
};
-use rustc_span::{sym, BytePos, DesugaringKind, Pos, Span};
+use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span};
use rustc_target::spec::abi;
use std::ops::ControlFlow;
use std::{cmp, fmt, iter};
{
sp = param.span;
}
- (format!("the lifetime `{}` as defined here", br.name), sp)
+ let text = if br.has_name() {
+ format!("the lifetime `{}` as defined here", br.name)
+ } else {
+ format!("the anonymous lifetime as defined here")
+ };
+ (text, sp)
}
- ty::ReFree(ty::FreeRegion {
- bound_region: ty::BoundRegionKind::BrNamed(_, name), ..
- }) => {
- let mut sp = sm.guess_head_span(tcx.def_span(scope));
- if let Some(param) =
- tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name))
+ ty::ReFree(ref fr) => {
+ if !fr.bound_region.is_named()
+ && let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region)
{
- sp = param.span;
- }
- (format!("the lifetime `{}` as defined here", name), sp)
- }
- ty::ReFree(ref fr) => match fr.bound_region {
- ty::BrAnon(idx) => {
- if let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region) {
- ("the anonymous lifetime defined here".to_string(), ty.span)
- } else {
- (
+ ("the anonymous lifetime defined here".to_string(), ty.span)
+ } else {
+ match fr.bound_region {
+ ty::BoundRegionKind::BrNamed(_, name) => {
+ let mut sp = sm.guess_head_span(tcx.def_span(scope));
+ if let Some(param) =
+ tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name))
+ {
+ sp = param.span;
+ }
+ let text = if name == kw::UnderscoreLifetime {
+ format!("the anonymous lifetime as defined here")
+ } else {
+ format!("the lifetime `{}` as defined here", name)
+ };
+ (text, sp)
+ }
+ ty::BrAnon(idx) => (
format!("the anonymous lifetime #{} defined here", idx + 1),
- tcx.def_span(scope),
- )
+ tcx.def_span(scope)
+ ),
+ _ => (
+ format!("the lifetime `{}` as defined here", region),
+ sm.guess_head_span(tcx.def_span(scope)),
+ ),
}
}
- _ => (
- format!("the lifetime `{}` as defined here", region),
- sm.guess_head_span(tcx.def_span(scope)),
- ),
- },
+ }
_ => bug!(),
}
}
ty::ReEarlyBound(ty::EarlyBoundRegion { name, .. })
| ty::ReFree(ty::FreeRegion { bound_region: ty::BrNamed(_, name), .. }),
_,
- ) => {
+ ) if name != kw::UnderscoreLifetime => {
// Does the required lifetime have a nice name we can print?
let mut err = struct_span_err!(
self.tcx.sess,
use crate::infer::type_variable::TypeVariableOriginKind;
-use crate::infer::{InferCtxt, Symbol};
-use rustc_errors::{
- pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
-};
+use crate::infer::InferCtxt;
+use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Namespace};
+use rustc_hir::def::{CtorOf, DefKind, Namespace};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, MatchSource, Pat};
+use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource};
use rustc_middle::hir::nested_filter;
use rustc_middle::infer::unify_key::ConstVariableOriginKind;
-use rustc_middle::ty::print::Print;
-use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
-use rustc_middle::ty::{self, Const, DefIdTree, InferConst, Ty, TyCtxt, TypeFoldable, TypeFolder};
-use rustc_span::symbol::kw;
-use rustc_span::{sym, Span};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
+use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer};
+use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
+use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, InferConst};
+use rustc_middle::ty::{Ty, TyCtxt, TypeckResults};
+use rustc_span::symbol::{kw, Ident};
+use rustc_span::{BytePos, Span};
use std::borrow::Cow;
-
-struct FindHirNodeVisitor<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
- target: GenericArg<'tcx>,
- target_span: Span,
- found_node_ty: Option<Ty<'tcx>>,
- found_local_pattern: Option<&'tcx Pat<'tcx>>,
- found_arg_pattern: Option<&'tcx Pat<'tcx>>,
- found_closure: Option<&'tcx Expr<'tcx>>,
- found_method_call: Option<&'tcx Expr<'tcx>>,
- found_exact_method_call: Option<&'tcx Expr<'tcx>>,
- found_for_loop_iter: Option<&'tcx Expr<'tcx>>,
- found_use_diagnostic: Option<UseDiagnostic<'tcx>>,
-}
-
-impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> {
- fn new(infcx: &'a InferCtxt<'a, 'tcx>, target: GenericArg<'tcx>, target_span: Span) -> Self {
- Self {
- infcx,
- target,
- target_span,
- found_node_ty: None,
- found_local_pattern: None,
- found_arg_pattern: None,
- found_closure: None,
- found_method_call: None,
- found_exact_method_call: None,
- found_for_loop_iter: None,
- found_use_diagnostic: None,
- }
- }
-
- fn node_type_opt(&self, hir_id: HirId) -> Option<Ty<'tcx>> {
- self.infcx.in_progress_typeck_results?.borrow().node_type_opt(hir_id)
- }
-
- fn node_ty_contains_target(&self, hir_id: HirId) -> Option<Ty<'tcx>> {
- self.node_type_opt(hir_id).map(|ty| self.infcx.resolve_vars_if_possible(ty)).filter(|ty| {
- ty.walk().any(|inner| {
- inner == self.target
- || match (inner.unpack(), self.target.unpack()) {
- (GenericArgKind::Type(inner_ty), GenericArgKind::Type(target_ty)) => {
- use ty::{Infer, TyVar};
- match (inner_ty.kind(), target_ty.kind()) {
- (&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => self
- .infcx
- .inner
- .borrow_mut()
- .type_variables()
- .sub_unified(a_vid, b_vid),
- _ => false,
- }
- }
- _ => false,
- }
- })
- })
- }
-
- /// Determine whether the expression, assumed to be the callee within a `Call`,
- /// corresponds to the `From::from` emitted in desugaring of the `?` operator.
- fn is_try_conversion(&self, callee: &Expr<'tcx>) -> bool {
- self.infcx
- .trait_def_from_hir_fn(callee.hir_id)
- .map_or(false, |def_id| self.infcx.is_try_conversion(callee.span, def_id))
- }
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for FindHirNodeVisitor<'a, 'tcx> {
- type NestedFilter = nested_filter::OnlyBodies;
-
- fn nested_visit_map(&mut self) -> Self::Map {
- self.infcx.tcx.hir()
- }
-
- fn visit_local(&mut self, local: &'tcx Local<'tcx>) {
- if let (None, Some(ty)) =
- (self.found_local_pattern, self.node_ty_contains_target(local.hir_id))
- {
- self.found_local_pattern = Some(&*local.pat);
- self.found_node_ty = Some(ty);
- }
- intravisit::walk_local(self, local);
- }
-
- fn visit_body(&mut self, body: &'tcx Body<'tcx>) {
- for param in body.params {
- if let (None, Some(ty)) =
- (self.found_arg_pattern, self.node_ty_contains_target(param.hir_id))
- {
- self.found_arg_pattern = Some(&*param.pat);
- self.found_node_ty = Some(ty);
- }
- }
- intravisit::walk_body(self, body);
- }
-
- fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
- if let ExprKind::Match(scrutinee, [_, arm], MatchSource::ForLoopDesugar) = expr.kind
- && let Some(pat) = arm.pat.for_loop_some()
- && let Some(ty) = self.node_ty_contains_target(pat.hir_id)
- {
- self.found_for_loop_iter = Some(scrutinee);
- self.found_node_ty = Some(ty);
- return;
- }
- if let ExprKind::MethodCall(segment, exprs, _) = expr.kind
- && segment.ident.span == self.target_span
- && Some(self.target) == self.infcx.in_progress_typeck_results.and_then(|typeck_results| {
- typeck_results
- .borrow()
- .node_type_opt(exprs.first().unwrap().hir_id)
- .map(Into::into)
- })
- {
- self.found_exact_method_call = Some(&expr);
- return;
- }
-
- // FIXME(const_generics): Currently, any uninferred `const` generics arguments
- // are handled specially, but instead they should be handled in `annotate_method_call`,
- // which currently doesn't work because this evaluates to `false` for const arguments.
- // See https://github.com/rust-lang/rust/pull/77758 for more details.
- if let Some(ty) = self.node_ty_contains_target(expr.hir_id) {
- match expr.kind {
- ExprKind::Closure(..) => self.found_closure = Some(&expr),
- ExprKind::MethodCall(..) => self.found_method_call = Some(&expr),
-
- // If the given expression falls within the target span and is a
- // `From::from(e)` call emitted during desugaring of the `?` operator,
- // extract the types inferred before and after the call
- ExprKind::Call(callee, [arg])
- if self.target_span.contains(expr.span)
- && self.found_use_diagnostic.is_none()
- && self.is_try_conversion(callee) =>
- {
- self.found_use_diagnostic = self.node_type_opt(arg.hir_id).map(|pre_ty| {
- UseDiagnostic::TryConversion { pre_ty, post_ty: ty, span: callee.span }
- });
- }
- _ => {}
- }
- }
- intravisit::walk_expr(self, expr);
- }
-}
-
-/// An observation about the use site of a type to be emitted as an additional
-/// note in an inference failure error.
-enum UseDiagnostic<'tcx> {
- /// Records the types inferred before and after `From::from` is called on the
- /// error value within the desugaring of the `?` operator.
- TryConversion { pre_ty: Ty<'tcx>, post_ty: Ty<'tcx>, span: Span },
-}
-
-impl UseDiagnostic<'_> {
- /// Return a descriptor of the value at the use site
- fn descr(&self) -> &'static str {
- match self {
- Self::TryConversion { .. } => "error for `?` operator",
- }
- }
-
- /// Return a descriptor of the type at the use site
- fn type_descr(&self) -> &'static str {
- match self {
- Self::TryConversion { .. } => "error type for `?` operator",
- }
- }
-
- fn applies_to(&self, span: Span) -> bool {
- match *self {
- // In some cases the span for an inference failure due to try
- // conversion contains the antecedent expression as well as the `?`
- Self::TryConversion { span: s, .. } => span.contains(s) && span.hi() == s.hi(),
- }
- }
-
- fn attach_note(&self, err: &mut Diagnostic) {
- match *self {
- Self::TryConversion { pre_ty, post_ty, .. } => {
- let intro = "`?` implicitly converts the error value";
-
- let msg = match (pre_ty.is_ty_infer(), post_ty.is_ty_infer()) {
- (true, true) => format!("{} using the `From` trait", intro),
- (false, true) => {
- format!("{} into a type implementing `From<{}>`", intro, pre_ty)
- }
- (true, false) => {
- format!("{} into `{}` using the `From` trait", intro, post_ty)
- }
- (false, false) => {
- format!(
- "{} into `{}` using its implementation of `From<{}>`",
- intro, post_ty, pre_ty
- )
- }
- };
-
- err.note(&msg);
- }
- }
- }
-}
-
-/// Suggest giving an appropriate return type to a closure expression.
-fn closure_return_type_suggestion(
- err: &mut Diagnostic,
- output: &FnRetTy<'_>,
- body: &Body<'_>,
- ret: &str,
-) {
- let (arrow, post) = match output {
- FnRetTy::DefaultReturn(_) => ("-> ", " "),
- _ => ("", ""),
- };
- let suggestion = match body.value.kind {
- ExprKind::Block(..) => vec![(output.span(), format!("{}{}{}", arrow, ret, post))],
- _ => vec![
- (output.span(), format!("{}{}{}{{ ", arrow, ret, post)),
- (body.value.span.shrink_to_hi(), " }".to_string()),
- ],
- };
- err.multipart_suggestion(
- "give this closure an explicit return type without `_` placeholders",
- suggestion,
- Applicability::HasPlaceholders,
- );
-}
-
-/// Given a closure signature, return a `String` containing a list of all its argument types.
-fn closure_args(fn_sig: &ty::PolyFnSig<'_>) -> String {
- fn_sig
- .inputs()
- .skip_binder()
- .iter()
- .next()
- .map(|args| {
- args.tuple_fields().iter().map(|arg| arg.to_string()).collect::<Vec<_>>().join(", ")
- })
- .unwrap_or_default()
-}
+use std::iter;
pub enum TypeAnnotationNeeded {
/// ```compile_fail,E0282
/// Data on the parent definition where a generic argument was declared.
pub struct InferenceDiagnosticsParentData {
- pub prefix: &'static str,
- pub name: String,
- pub def_id: DefId,
+ prefix: &'static str,
+ name: String,
}
pub enum UnderspecifiedArgKind {
Const { is_parameter: bool },
}
-impl UnderspecifiedArgKind {
- fn descr(&self) -> &'static str {
- match self {
- Self::Type { .. } => "type",
- Self::Const { .. } => "const",
- }
- }
-}
-
impl InferenceDiagnosticsData {
/// Generate a label for a generic argument which can't be inferred. When not
/// much is known about the argument, `use_diag` may be used to describe the
/// labeled value.
- fn cannot_infer_msg(&self, use_diag: Option<&UseDiagnostic<'_>>) -> String {
+ fn cannot_infer_msg(&self) -> String {
if self.name == "_" && matches!(self.kind, UnderspecifiedArgKind::Type { .. }) {
- if let Some(use_diag) = use_diag {
- return format!("cannot infer type of {}", use_diag.descr());
- }
-
return "cannot infer type".to_string();
}
- let suffix = match (&self.parent, use_diag) {
- (Some(parent), _) => format!(" declared on the {} `{}`", parent.prefix, parent.name),
- (None, Some(use_diag)) => format!(" in {}", use_diag.type_descr()),
- (None, None) => String::new(),
+ let suffix = match &self.parent {
+ Some(parent) => parent.suffix_string(),
+ None => String::new(),
};
// For example: "cannot infer type for type parameter `T`"
format!("cannot infer {} `{}`{}", self.kind.prefix_string(), self.name, suffix)
}
+
+ fn where_x_is_specified(&self, in_type: Ty<'_>) -> String {
+ if in_type.is_ty_infer() {
+ String::new()
+ } else if self.name == "_" {
+ // FIXME: Consider specializing this message if there is a single `_`
+ // in the type.
+ ", where the placeholders `_` are specified".to_string()
+ } else {
+ format!(", where the {} `{}` is specified", self.kind.prefix_string(), self.name)
+ }
+ }
}
impl InferenceDiagnosticsParentData {
- fn for_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<InferenceDiagnosticsParentData> {
- let parent_def_id = tcx.parent(def_id);
-
+ fn for_parent_def_id(
+ tcx: TyCtxt<'_>,
+ parent_def_id: DefId,
+ ) -> Option<InferenceDiagnosticsParentData> {
let parent_name =
tcx.def_key(parent_def_id).disambiguated_data.data.get_opt_name()?.to_string();
Some(InferenceDiagnosticsParentData {
prefix: tcx.def_kind(parent_def_id).descr(parent_def_id),
name: parent_name,
- def_id: parent_def_id,
})
}
+
+ fn for_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<InferenceDiagnosticsParentData> {
+ Self::for_parent_def_id(tcx, tcx.parent(def_id))
+ }
+
+ fn suffix_string(&self) -> String {
+ format!(" declared on the {} `{}`", self.prefix, self.name)
+ }
}
impl UnderspecifiedArgKind {
}
}
+fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'_, 'tcx>, ns: Namespace) -> FmtPrinter<'a, 'tcx> {
+ let mut printer = FmtPrinter::new(infcx.tcx, ns);
+ let ty_getter = move |ty_vid| {
+ if infcx.probe_ty_var(ty_vid).is_ok() {
+ warn!("resolved ty var in error message");
+ }
+ if let TypeVariableOriginKind::TypeParameterDefinition(name, _) =
+ infcx.inner.borrow_mut().type_variables().var_origin(ty_vid).kind
+ {
+ Some(name.to_string())
+ } else {
+ None
+ }
+ };
+ printer.ty_infer_name_resolver = Some(Box::new(ty_getter));
+ let const_getter = move |ct_vid| {
+ if infcx.probe_const_var(ct_vid).is_ok() {
+ warn!("resolved const var in error message");
+ }
+ if let ConstVariableOriginKind::ConstParameterDefinition(name, _) =
+ infcx.inner.borrow_mut().const_unification_table().probe_value(ct_vid).origin.kind
+ {
+ return Some(name.to_string());
+ } else {
+ None
+ }
+ };
+ printer.const_infer_name_resolver = Some(Box::new(const_getter));
+ printer
+}
+
+fn ty_to_string<'tcx>(infcx: &InferCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> String {
+ let printer = fmt_printer(infcx, Namespace::TypeNS);
+ let ty = infcx.resolve_vars_if_possible(ty);
+ match ty.kind() {
+ // We don't want the regular output for `fn`s because it includes its path in
+ // invalid pseudo-syntax, we want the `fn`-pointer output instead.
+ ty::FnDef(..) => ty.fn_sig(infcx.tcx).print(printer).unwrap().into_buffer(),
+ // FIXME: The same thing for closures, but this only works when the closure
+ // does not capture anything.
+ //
+ // We do have to hide the `extern "rust-call"` ABI in that case though,
+ // which is too much of a bother for now.
+ _ => ty.print(printer).unwrap().into_buffer(),
+ }
+}
+
+/// We don't want to directly use `ty_to_string` for closures as their type isn't really
+/// something users are familar with. Directly printing the `fn_sig` of closures also
+/// doesn't work as they actually use the "rust-call" API.
+fn closure_as_fn_str<'tcx>(infcx: &InferCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> String {
+ let ty::Closure(_, substs) = ty.kind() else { unreachable!() };
+ let fn_sig = substs.as_closure().sig();
+ let args = fn_sig
+ .inputs()
+ .skip_binder()
+ .iter()
+ .next()
+ .map(|args| {
+ args.tuple_fields()
+ .iter()
+ .map(|arg| ty_to_string(infcx, arg))
+ .collect::<Vec<_>>()
+ .join(", ")
+ })
+ .unwrap_or_default();
+ let ret = if fn_sig.output().skip_binder().is_unit() {
+ String::new()
+ } else {
+ format!(" -> {}", ty_to_string(infcx, fn_sig.output().skip_binder()))
+ };
+ format!("fn({}){}", args, ret)
+}
+
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// Extracts data used by diagnostic for either types or constants
/// which were stuck during inference.
if let Some(highlight) = highlight {
printer.region_highlight_mode = highlight;
}
- let name = ty.print(printer).unwrap().into_buffer();
InferenceDiagnosticsData {
- name,
+ name: ty.print(printer).unwrap().into_buffer(),
span: None,
kind: UnderspecifiedArgKind::Type { prefix: ty.prefix_string(self.tcx) },
parent: None,
}
}
GenericArgKind::Const(ct) => {
- match ct.val() {
- ty::ConstKind::Infer(InferConst::Var(vid)) => {
- let origin = self
- .inner
- .borrow_mut()
- .const_unification_table()
- .probe_value(vid)
- .origin;
- if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) =
- origin.kind
- {
- return InferenceDiagnosticsData {
- name: name.to_string(),
- span: Some(origin.span),
- kind: UnderspecifiedArgKind::Const { is_parameter: true },
- parent: InferenceDiagnosticsParentData::for_def_id(
- self.tcx, def_id,
- ),
- };
- }
-
- debug_assert!(!origin.span.is_dummy());
- let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::ValueNS);
- if let Some(highlight) = highlight {
- printer.region_highlight_mode = highlight;
- }
- let name = ct.print(printer).unwrap().into_buffer();
- InferenceDiagnosticsData {
- name,
+ if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val() {
+ let origin =
+ self.inner.borrow_mut().const_unification_table().probe_value(vid).origin;
+ if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) =
+ origin.kind
+ {
+ return InferenceDiagnosticsData {
+ name: name.to_string(),
span: Some(origin.span),
- kind: UnderspecifiedArgKind::Const { is_parameter: false },
- parent: None,
- }
+ kind: UnderspecifiedArgKind::Const { is_parameter: true },
+ parent: InferenceDiagnosticsParentData::for_def_id(self.tcx, def_id),
+ };
}
- ty::ConstKind::Unevaluated(ty::Unevaluated { substs, .. }) => {
- assert!(substs.has_infer_types_or_consts());
-
- // FIXME: We only use the first inference variable we encounter in
- // `substs` here, this gives insufficiently informative diagnostics
- // in case there are multiple inference variables
- for s in substs.iter() {
- match s.unpack() {
- GenericArgKind::Type(t) => match t.kind() {
- ty::Infer(_) => {
- return self.extract_inference_diagnostics_data(s, None);
- }
- _ => {}
- },
- GenericArgKind::Const(c) => match c.val() {
- ty::ConstKind::Infer(InferConst::Var(_)) => {
- return self.extract_inference_diagnostics_data(s, None);
- }
- _ => {}
- },
- _ => {}
- }
- }
- bug!(
- "expected an inference variable in substs of unevaluated const {:?}",
- ct
- );
+
+ debug_assert!(!origin.span.is_dummy());
+ let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::ValueNS);
+ if let Some(highlight) = highlight {
+ printer.region_highlight_mode = highlight;
+ }
+ InferenceDiagnosticsData {
+ name: ct.print(printer).unwrap().into_buffer(),
+ span: Some(origin.span),
+ kind: UnderspecifiedArgKind::Const { is_parameter: false },
+ parent: None,
+ }
+ } else {
+ // If we end up here the `FindInferSourceVisitor`
+ // won't work, as its expected argument isn't an inference variable.
+ //
+ // FIXME: Ideally we should look into the generic constant
+ // to figure out which inference var is actually unresolved so that
+ // this path is unreachable.
+ let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::ValueNS);
+ if let Some(highlight) = highlight {
+ printer.region_highlight_mode = highlight;
}
- _ => {
- bug!("unexpect const: {:?}", ct);
+ InferenceDiagnosticsData {
+ name: ct.print(printer).unwrap().into_buffer(),
+ span: None,
+ kind: UnderspecifiedArgKind::Const { is_parameter: false },
+ parent: None,
}
}
}
}
}
+ /// Used as a fallback in [InferCtxt::emit_inference_failure_err]
+ /// in case we weren't able to get a better error.
+ fn bad_inference_failure_err(
+ &self,
+ span: Span,
+ arg_data: InferenceDiagnosticsData,
+ error_code: TypeAnnotationNeeded,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+ let error_code = error_code.into();
+ let mut err = self.tcx.sess.struct_span_err_with_code(
+ span,
+ &format!("type annotations needed"),
+ error_code,
+ );
+ err.span_label(span, arg_data.cannot_infer_msg());
+ err
+ }
+
pub fn emit_inference_failure_err(
&self,
body_id: Option<hir::BodyId>,
span: Span,
arg: GenericArg<'tcx>,
- impl_candidates: Vec<ty::TraitRef<'tcx>>,
+ // FIXME(#94483): Either use this or remove it.
+ _impl_candidates: Vec<ty::TraitRef<'tcx>>,
error_code: TypeAnnotationNeeded,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let arg = self.resolve_vars_if_possible(arg);
let arg_data = self.extract_inference_diagnostics_data(arg, None);
- let mut local_visitor = FindHirNodeVisitor::new(&self, arg, span);
- let ty_to_string = |ty: Ty<'tcx>| -> String {
- let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS);
- let ty_getter = move |ty_vid| {
- if let TypeVariableOriginKind::TypeParameterDefinition(name, _) =
- self.inner.borrow_mut().type_variables().var_origin(ty_vid).kind
- {
- Some(name.to_string())
- } else {
- None
- }
- };
- printer.ty_infer_name_resolver = Some(Box::new(ty_getter));
- let const_getter = move |ct_vid| {
- if let ConstVariableOriginKind::ConstParameterDefinition(name, _) = self
- .inner
- .borrow_mut()
- .const_unification_table()
- .probe_value(ct_vid)
- .origin
- .kind
- {
- return Some(name.to_string());
- } else {
- None
- }
- };
- printer.const_infer_name_resolver = Some(Box::new(const_getter));
-
- if let ty::FnDef(..) = ty.kind() {
- // We don't want the regular output for `fn`s because it includes its path in
- // invalid pseudo-syntax, we want the `fn`-pointer output instead.
- ty.fn_sig(self.tcx).print(printer).unwrap().into_buffer()
- } else {
- ty.print(printer).unwrap().into_buffer()
- }
+ let Some(typeck_results) = self.in_progress_typeck_results else {
+ // If we don't have any typeck results we're outside
+ // of a body, so we won't be able to get better info
+ // here.
+ return self.bad_inference_failure_err(span, arg_data, error_code);
};
+ let typeck_results = typeck_results.borrow();
+ let typeck_results = &typeck_results;
+ let mut local_visitor = FindInferSourceVisitor::new(&self, typeck_results, arg);
if let Some(body_id) = body_id {
let expr = self.tcx.hir().expect_expr(body_id.hir_id);
+ debug!(?expr);
local_visitor.visit_expr(expr);
}
- let err_span = if let Some(pattern) = local_visitor.found_arg_pattern {
- pattern.span
- } else if let Some(span) = arg_data.span {
- // `span` here lets us point at `sum` instead of the entire right hand side expr:
- // error[E0282]: type annotations needed
- // --> file2.rs:3:15
- // |
- // 3 | let _ = x.sum() as f64;
- // | ^^^ cannot infer type for `S`
- span
- } else if let Some(ExprKind::MethodCall(segment, ..)) =
- local_visitor.found_method_call.map(|e| &e.kind)
- {
- // Point at the call instead of the whole expression:
- // error[E0284]: type annotations needed
- // --> file.rs:2:5
- // |
- // 2 | [Ok(2)].into_iter().collect()?;
- // | ^^^^^^^ cannot infer type
- // |
- // = note: cannot resolve `<_ as std::ops::Try>::Ok == _`
- if span.contains(segment.ident.span) { segment.ident.span } else { span }
- } else {
- span
- };
- let is_named_and_not_impl_trait =
- |ty: Ty<'_>| &ty.to_string() != "_" && !ty.is_impl_trait();
-
- let ty_msg = match (local_visitor.found_node_ty, local_visitor.found_exact_method_call) {
- (_, Some(_)) => String::new(),
- (Some(ty), _) if ty.is_closure() => {
- let ty::Closure(_, substs) = *ty.kind() else { unreachable!() };
- let fn_sig = substs.as_closure().sig();
- let args = closure_args(&fn_sig);
- let ret = fn_sig.output().skip_binder().to_string();
- format!(" for the closure `fn({}) -> {}`", args, ret)
- }
- (Some(ty), _) if is_named_and_not_impl_trait(ty) => {
- let ty = ty_to_string(ty);
- format!(" for `{}`", ty)
- }
- _ => String::new(),
+ let Some(InferSource { span, kind }) = local_visitor.infer_source else {
+ return self.bad_inference_failure_err(span, arg_data, error_code)
};
- // When `arg_data.name` corresponds to a type argument, show the path of the full type we're
- // trying to infer. In the following example, `ty_msg` contains
- // " for `std::result::Result<i32, E>`":
- // ```
- // error[E0282]: type annotations needed for `std::result::Result<i32, E>`
- // --> file.rs:L:CC
- // |
- // L | let b = Ok(4);
- // | - ^^ cannot infer type for `E` in `std::result::Result<i32, E>`
- // | |
- // | consider giving `b` the explicit type `std::result::Result<i32, E>`, where
- // | the type parameter `E` is specified
- // ```
let error_code = error_code.into();
let mut err = self.tcx.sess.struct_span_err_with_code(
- err_span,
- &format!("type annotations needed{}", ty_msg),
+ span,
+ &format!("type annotations needed{}", kind.ty_msg(self)),
error_code,
);
-
- let use_diag = local_visitor.found_use_diagnostic.as_ref();
- if let Some(use_diag) = use_diag && use_diag.applies_to(err_span) {
- use_diag.attach_note(&mut err);
- }
-
- let param_type = arg_data.kind.descr();
- let suffix = match local_visitor.found_node_ty {
- Some(ty) if ty.is_closure() => {
- let ty::Closure(_, substs) = *ty.kind() else { unreachable!() };
- let fn_sig = substs.as_closure().sig();
- let ret = fn_sig.output().skip_binder().to_string();
-
- let closure_decl_and_body_id =
- local_visitor.found_closure.and_then(|closure| match &closure.kind {
- ExprKind::Closure(_, decl, body_id, ..) => Some((decl, *body_id)),
- _ => None,
- });
-
- if let Some((decl, body_id)) = closure_decl_and_body_id {
- closure_return_type_suggestion(
- &mut err,
- &decl.output,
- self.tcx.hir().body(body_id),
- &ret,
- );
- // We don't want to give the other suggestions when the problem is the
- // closure return type.
- err.span_label(
- span,
- arg_data.cannot_infer_msg(use_diag.filter(|d| d.applies_to(span))),
- );
- return err;
- }
-
- // This shouldn't be reachable, but just in case we leave a reasonable fallback.
- let args = closure_args(&fn_sig);
- // This suggestion is incomplete, as the user will get further type inference
- // errors due to the `_` placeholders and the introduction of `Box`, but it does
- // nudge them in the right direction.
- format!("a boxed closure type like `Box<dyn Fn({}) -> {}>`", args, ret)
+ match kind {
+ InferSourceKind::LetBinding { insert_span, pattern_name, ty } => {
+ let suggestion_msg = if let Some(name) = pattern_name {
+ format!(
+ "consider giving `{}` an explicit type{}",
+ name,
+ arg_data.where_x_is_specified(ty)
+ )
+ } else {
+ format!(
+ "consider giving this pattern a type{}",
+ arg_data.where_x_is_specified(ty)
+ )
+ };
+ err.span_suggestion_verbose(
+ insert_span,
+ &suggestion_msg,
+ format!(": {}", ty_to_string(self, ty)),
+ Applicability::HasPlaceholders,
+ );
}
- Some(ty) if is_named_and_not_impl_trait(ty) && arg_data.name == "_" => {
- let ty = ty_to_string(ty);
- format!("the explicit type `{}`, with the {} parameters specified", ty, param_type)
+ InferSourceKind::ClosureArg { insert_span, ty } => {
+ err.span_suggestion_verbose(
+ insert_span,
+ &format!(
+ "consider giving this closure parameter an explicit type{}",
+ arg_data.where_x_is_specified(ty)
+ ),
+ format!(": {}", ty_to_string(self, ty)),
+ Applicability::HasPlaceholders,
+ );
}
- Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != arg_data.name => {
- let ty = ResolvedTypeParamEraser::new(self.tcx).fold_ty(ty);
- let ty = ErrTypeParamEraser(self.tcx).fold_ty(ty);
- let ty = ty_to_string(ty);
- format!(
- "the explicit type `{}`, where the {} parameter `{}` is specified",
- ty, param_type, arg_data.name,
- )
+ InferSourceKind::GenericArg {
+ insert_span,
+ argument_index,
+ generics_def_id,
+ def_id: _,
+ generic_args,
+ } => {
+ let generics = self.tcx.generics_of(generics_def_id);
+ let is_type = matches!(arg.unpack(), GenericArgKind::Type(_));
+
+ let cannot_infer_msg = format!(
+ "cannot infer {} of the {} parameter `{}`{}",
+ if is_type { "type" } else { "the value" },
+ if is_type { "type" } else { "const" },
+ generics.params[argument_index].name,
+ // We use the `generics_def_id` here, as even when suggesting `None::<T>`,
+ // the type parameter `T` was still declared on the enum, not on the
+ // variant.
+ InferenceDiagnosticsParentData::for_parent_def_id(self.tcx, generics_def_id)
+ .map_or(String::new(), |parent| parent.suffix_string()),
+ );
+
+ err.span_label(span, cannot_infer_msg);
+
+ let printer = fmt_printer(self, Namespace::TypeNS);
+ let args = printer.comma_sep(generic_args.iter().copied()).unwrap().into_buffer();
+ err.span_suggestion_verbose(
+ insert_span,
+ &format!("consider specifying the generic argument{}", pluralize!(args.len()),),
+ format!("::<{}>", args),
+ Applicability::HasPlaceholders,
+ );
}
- _ => "a type".to_string(),
- };
+ InferSourceKind::FullyQualifiedMethodCall { receiver, successor, substs, def_id } => {
+ let printer = fmt_printer(self, Namespace::ValueNS);
+ let def_path = printer.print_def_path(def_id, substs).unwrap().into_buffer();
+
+ // We only care about whether we have to add `&` or `&mut ` for now.
+ // This is the case if the last adjustment is a borrow and the
+ // first adjustment was not a builtin deref.
+ let adjustment = match typeck_results.expr_adjustments(receiver) {
+ [
+ Adjustment { kind: Adjust::Deref(None), target: _ },
+ ..,
+ Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), target: _ },
+ ] => "",
+ [
+ ..,
+ Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mut_)), target: _ },
+ ] => match mut_ {
+ AutoBorrowMutability::Mut { .. } => "&mut ",
+ AutoBorrowMutability::Not => "&",
+ },
+ _ => "",
+ };
- if let Some(e) = local_visitor.found_exact_method_call {
- if let ExprKind::MethodCall(segment, ..) = &e.kind {
- // Suggest specifying type params or point out the return type of the call:
- //
- // error[E0282]: type annotations needed
- // --> $DIR/type-annotations-needed-expr.rs:2:39
- // |
- // LL | let _ = x.into_iter().sum() as f64;
- // | ^^^
- // | |
- // | cannot infer type for `S`
- // | help: consider specifying the type argument in
- // | the method call: `sum::<S>`
- // |
- // = note: type must be known at this point
- //
- // or
- //
- // error[E0282]: type annotations needed
- // --> $DIR/issue-65611.rs:59:20
- // |
- // LL | let x = buffer.last().unwrap().0.clone();
- // | -------^^^^--
- // | | |
- // | | cannot infer type for `T`
- // | this method call resolves to `std::option::Option<&T>`
- // |
- // = note: type must be known at this point
- self.annotate_method_call(segment, e, &mut err);
- }
- } else if let Some(pattern) = local_visitor.found_arg_pattern {
- // We don't want to show the default label for closures.
- //
- // So, before clearing, the output would look something like this:
- // ```
- // let x = |_| { };
- // - ^^^^ cannot infer type for `[_; 0]`
- // |
- // consider giving this closure parameter a type
- // ```
- //
- // After clearing, it looks something like this:
- // ```
- // let x = |_| { };
- // ^ consider giving this closure parameter the type `[_; 0]`
- // with the type parameter `_` specified
- // ```
- err.span_label(
- pattern.span,
- format!("consider giving this closure parameter {}", suffix),
- );
- } else if let Some(pattern) = local_visitor.found_local_pattern {
- let msg = if let Some(simple_ident) = pattern.simple_ident() {
- match pattern.span.desugaring_kind() {
- None => format!("consider giving `{}` {}", simple_ident, suffix),
- Some(_) => format!("this needs {}", suffix),
- }
- } else {
- format!("consider giving this pattern {}", suffix)
- };
- err.span_label(pattern.span, msg);
- } else if let Some(e) = local_visitor.found_method_call {
- if let ExprKind::MethodCall(segment, exprs, _) = &e.kind {
- // Suggest impl candidates:
- //
- // error[E0283]: type annotations needed
- // --> $DIR/E0283.rs:35:24
- // |
- // LL | let bar = foo_impl.into() * 1u32;
- // | ---------^^^^--
- // | | |
- // | | cannot infer type for type parameter `T` declared on the trait `Into`
- // | this method call resolves to `T`
- // | help: specify type like: `<Impl as Into<u32>>::into(foo_impl)`
- // |
- // = note: cannot satisfy `Impl: Into<_>`
- debug!(?segment);
- if !impl_candidates.is_empty() && e.span.contains(span)
- && let Some(expr) = exprs.first()
- && let ExprKind::Path(hir::QPath::Resolved(_, path)) = expr.kind
- && let [_] = path.segments
- {
- let mut eraser = TypeParamEraser(self.tcx);
- let candidate_len = impl_candidates.len();
- let mut suggestions: Vec<_> = impl_candidates.iter().filter_map(|candidate| {
- let trait_item = self.tcx
- .associated_items(candidate.def_id)
- .find_by_name_and_kind(
- self.tcx,
- segment.ident,
- ty::AssocKind::Fn,
- candidate.def_id
- );
- if trait_item.is_none() {
- return None;
- }
- let prefix = if let Some(trait_item) = trait_item
- && let Some(trait_m) = trait_item.def_id.as_local()
- && let hir::TraitItemKind::Fn(fn_, _) = &self.tcx.hir().trait_item(hir::TraitItemId { def_id: trait_m }).kind
- {
- match fn_.decl.implicit_self {
- hir::ImplicitSelfKind::ImmRef => "&",
- hir::ImplicitSelfKind::MutRef => "&mut ",
- _ => "",
- }
- } else {
- ""
- };
- let candidate = candidate.super_fold_with(&mut eraser);
- Some(vec![
- (expr.span.shrink_to_lo(), format!("{}::{}({}", candidate, segment.ident, prefix)),
- if exprs.len() == 1 {
- (expr.span.shrink_to_hi().with_hi(e.span.hi()), ")".to_string())
- } else {
- (expr.span.shrink_to_hi().with_hi(exprs[1].span.lo()), ", ".to_string())
- },
- ])
- }).collect();
- suggestions.sort_by(|a, b| a[0].1.cmp(&b[0].1));
- if !suggestions.is_empty() {
- err.multipart_suggestions(
- &format!(
- "use the fully qualified path for the potential candidate{}",
- pluralize!(candidate_len),
- ),
- suggestions.into_iter(),
- Applicability::MaybeIncorrect,
- );
- }
- }
- // Suggest specifying type params or point out the return type of the call:
- //
- // error[E0282]: type annotations needed
- // --> $DIR/type-annotations-needed-expr.rs:2:39
- // |
- // LL | let _ = x.into_iter().sum() as f64;
- // | ^^^
- // | |
- // | cannot infer type for `S`
- // | help: consider specifying the type argument in
- // | the method call: `sum::<S>`
- // |
- // = note: type must be known at this point
- //
- // or
- //
- // error[E0282]: type annotations needed
- // --> $DIR/issue-65611.rs:59:20
- // |
- // LL | let x = buffer.last().unwrap().0.clone();
- // | -------^^^^--
- // | | |
- // | | cannot infer type for `T`
- // | this method call resolves to `std::option::Option<&T>`
- // |
- // = note: type must be known at this point
- self.annotate_method_call(segment, e, &mut err);
+ let suggestion = vec![
+ (receiver.span.shrink_to_lo(), format!("{def_path}({adjustment}")),
+ (receiver.span.shrink_to_hi().with_hi(successor.1), successor.0.to_string()),
+ ];
+ err.multipart_suggestion_verbose(
+ "try using a fully qualified path to specify the expected types",
+ suggestion,
+ Applicability::HasPlaceholders,
+ );
}
- } else if let Some(scrutinee) = local_visitor.found_for_loop_iter {
- err.span_label(
- scrutinee.span,
- "the element type for this iterator is not specified".to_string(),
- );
- }
- // Instead of the following:
- // error[E0282]: type annotations needed
- // --> file2.rs:3:15
- // |
- // 3 | let _ = x.sum() as f64;
- // | --^^^--------- cannot infer type for `S`
- // |
- // = note: type must be known at this point
- // We want:
- // error[E0282]: type annotations needed
- // --> file2.rs:3:15
- // |
- // 3 | let _ = x.sum() as f64;
- // | ^^^ cannot infer type for `S`
- // |
- // = note: type must be known at this point
- let span = arg_data.span.unwrap_or(err_span);
-
- // Avoid multiple labels pointing at `span`.
- if !err
- .span
- .span_labels()
- .iter()
- .any(|span_label| span_label.label.is_some() && span_label.span == span)
- && local_visitor.found_arg_pattern.is_none()
- {
- // FIXME(const_generics): we would like to handle const arguments
- // as part of the normal diagnostics flow below, but there appear to
- // be subtleties in doing so, so for now we special-case const args
- // here.
- if let (UnderspecifiedArgKind::Const { .. }, Some(parent_data)) =
- (&arg_data.kind, &arg_data.parent)
- {
- // (#83606): Do not emit a suggestion if the parent has an `impl Trait`
- // as an argument otherwise it will cause the E0282 error.
- if !self.tcx.generics_of(parent_data.def_id).has_impl_trait()
- || self.tcx.features().explicit_generic_args_with_impl_trait
- {
- err.span_suggestion_verbose(
- span,
- "consider specifying the const argument",
- format!("{}::<{}>", parent_data.name, arg_data.name),
- Applicability::MaybeIncorrect,
- );
- }
+ InferSourceKind::ClosureReturn { ty, data, should_wrap_expr } => {
+ let ret = ty_to_string(self, ty);
+ let (arrow, post) = match data {
+ FnRetTy::DefaultReturn(_) => ("-> ", " "),
+ _ => ("", ""),
+ };
+ let suggestion = match should_wrap_expr {
+ Some(end_span) => vec![
+ (data.span(), format!("{}{}{}{{ ", arrow, ret, post)),
+ (end_span, " }".to_string()),
+ ],
+ None => vec![(data.span(), format!("{}{}{}", arrow, ret, post))],
+ };
+ err.multipart_suggestion_verbose(
+ "try giving this closure an explicit return type",
+ suggestion,
+ Applicability::HasPlaceholders,
+ );
}
-
- self.report_ambiguous_type_parameter(&mut err, arg);
- err.span_label(
- span,
- arg_data.cannot_infer_msg(use_diag.filter(|d| d.applies_to(span))),
- );
}
-
err
}
- fn trait_def_from_hir_fn(&self, hir_id: hir::HirId) -> Option<DefId> {
- // The DefId will be the method's trait item ID unless this is an inherent impl
- if let Some((DefKind::AssocFn, def_id)) =
- self.in_progress_typeck_results?.borrow().type_dependent_def(hir_id)
- {
- let parent_def_id = self.tcx.parent(def_id);
- return self.tcx.is_trait(parent_def_id).then_some(parent_def_id);
- }
-
- None
- }
-
- /// If the `FnSig` for the method call can be found and type arguments are identified as
- /// needed, suggest annotating the call, otherwise point out the resulting type of the call.
- fn annotate_method_call(
- &self,
- segment: &hir::PathSegment<'_>,
- e: &Expr<'_>,
- err: &mut Diagnostic,
- ) {
- if let (Some(typeck_results), None) = (self.in_progress_typeck_results, &segment.args) {
- let borrow = typeck_results.borrow();
- if let Some((DefKind::AssocFn, did)) = borrow.type_dependent_def(e.hir_id) {
- let generics = self.tcx.generics_of(did);
- if !generics.params.is_empty() && !generics.has_impl_trait() {
- err.span_suggestion_verbose(
- segment.ident.span.shrink_to_hi(),
- &format!(
- "consider specifying the type argument{} in the method call",
- pluralize!(generics.params.len()),
- ),
- format!(
- "::<{}>",
- generics
- .params
- .iter()
- .map(|p| p.name.to_string())
- .collect::<Vec<String>>()
- .join(", ")
- ),
- Applicability::HasPlaceholders,
- );
- } else {
- let sig = self.tcx.fn_sig(did);
- let bound_output = sig.output();
- let output = bound_output.skip_binder();
- err.span_label(e.span, &format!("this method call resolves to `{}`", output));
- let kind = output.kind();
- if let ty::Projection(proj) = kind {
- if let Some(span) = self.tcx.hir().span_if_local(proj.item_def_id) {
- err.span_label(span, &format!("`{}` defined here", output));
- }
- }
- }
- }
- }
- }
-
- fn report_ambiguous_type_parameter(&self, err: &mut Diagnostic, arg: GenericArg<'tcx>) {
- if let GenericArgKind::Type(ty) = arg.unpack()
- && let ty::Infer(ty::TyVar(ty_vid)) = *ty.kind()
- {
- let mut inner = self.inner.borrow_mut();
- let ty_vars = &inner.type_variables();
- let var_origin = ty_vars.var_origin(ty_vid);
- if let TypeVariableOriginKind::TypeParameterDefinition(_, Some(def_id)) =
- var_origin.kind
- && let Some(parent_def_id) = self.tcx.parent(def_id).as_local()
- && let Some(node) = self.tcx.hir().find_by_def_id(parent_def_id)
- {
- match node {
- hir::Node::Item(item) if matches!(item.kind, hir::ItemKind::Impl(_) | hir::ItemKind::Fn(..)) => (),
- hir::Node::ImplItem(impl_item) if matches!(impl_item.kind, hir::ImplItemKind::Fn(..)) => (),
- _ => return,
- }
- err.span_help(self.tcx.def_span(def_id), "type parameter declared here");
- }
- }
- }
-
pub fn need_type_info_err_in_generator(
&self,
kind: hir::GeneratorKind,
"type inside {} must be known in this context",
kind,
);
- err.span_label(span, data.cannot_infer_msg(None));
+ err.span_label(span, data.cannot_infer_msg());
err
}
}
-/// Turn *resolved* type params into `[type error]` to signal we don't want to display them. After
-/// performing that replacement, we'll turn all remaining infer type params to use their name from
-/// their definition, and replace all the `[type error]`s back to being infer so they display in
-/// the output as `_`. If we didn't go through `[type error]`, we would either show all type params
-/// by their name *or* `_`, neither of which is desirable: we want to show all types that we could
-/// infer as `_` to reduce verbosity and avoid telling the user about unnecessary type annotations.
-struct ResolvedTypeParamEraser<'tcx> {
- tcx: TyCtxt<'tcx>,
- level: usize,
+#[derive(Debug)]
+struct InferSource<'tcx> {
+ span: Span,
+ kind: InferSourceKind<'tcx>,
}
-impl<'tcx> ResolvedTypeParamEraser<'tcx> {
- fn new(tcx: TyCtxt<'tcx>) -> Self {
- ResolvedTypeParamEraser { tcx, level: 0 }
- }
+#[derive(Debug)]
+enum InferSourceKind<'tcx> {
+ LetBinding {
+ insert_span: Span,
+ pattern_name: Option<Ident>,
+ ty: Ty<'tcx>,
+ },
+ ClosureArg {
+ insert_span: Span,
+ ty: Ty<'tcx>,
+ },
+ GenericArg {
+ insert_span: Span,
+ argument_index: usize,
+ generics_def_id: DefId,
+ def_id: DefId,
+ generic_args: &'tcx [GenericArg<'tcx>],
+ },
+ FullyQualifiedMethodCall {
+ receiver: &'tcx Expr<'tcx>,
+ /// If the method has other arguments, this is ", " and the start of the first argument,
+ /// while for methods without arguments this is ")" and the end of the method call.
+ successor: (&'static str, BytePos),
+ substs: SubstsRef<'tcx>,
+ def_id: DefId,
+ },
+ ClosureReturn {
+ ty: Ty<'tcx>,
+ data: &'tcx FnRetTy<'tcx>,
+ should_wrap_expr: Option<Span>,
+ },
+}
- /// Replace not yet inferred const params with their def name.
- fn replace_infers(&self, c: Const<'tcx>, index: u32, name: Symbol) -> Const<'tcx> {
- match c.val() {
- ty::ConstKind::Infer(..) => self.tcx().mk_const_param(index, name, c.ty()),
- _ => c,
+impl<'tcx> InferSourceKind<'tcx> {
+ fn ty_msg(&self, infcx: &InferCtxt<'_, 'tcx>) -> String {
+ match *self {
+ InferSourceKind::LetBinding { ty, .. }
+ | InferSourceKind::ClosureArg { ty, .. }
+ | InferSourceKind::ClosureReturn { ty, .. } => {
+ if ty.is_closure() {
+ format!(" for the closure `{}`", closure_as_fn_str(infcx, ty))
+ } else if !ty.is_ty_infer() {
+ format!(" for `{}`", ty_to_string(infcx, ty))
+ } else {
+ String::new()
+ }
+ }
+ // FIXME: We should be able to add some additional info here.
+ InferSourceKind::GenericArg { .. }
+ | InferSourceKind::FullyQualifiedMethodCall { .. } => String::new(),
}
}
}
-impl<'tcx> TypeFolder<'tcx> for ResolvedTypeParamEraser<'tcx> {
- fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
- self.tcx
+struct InsertableGenericArgs<'tcx> {
+ insert_span: Span,
+ substs: SubstsRef<'tcx>,
+ generics_def_id: DefId,
+ def_id: DefId,
+}
+
+/// A visitor which searches for the "best" spot to use in the inference error.
+///
+/// For this it walks over the hir body and tries to check all places where
+/// inference variables could be bound.
+///
+/// While doing so, the currently best spot is stored in `infer_source`.
+/// For details on how we rank spots, see [Self::source_cost]
+struct FindInferSourceVisitor<'a, 'tcx> {
+ infcx: &'a InferCtxt<'a, 'tcx>,
+ typeck_results: &'a TypeckResults<'tcx>,
+
+ target: GenericArg<'tcx>,
+
+ attempt: usize,
+ infer_source_cost: usize,
+ infer_source: Option<InferSource<'tcx>>,
+}
+
+impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
+ fn new(
+ infcx: &'a InferCtxt<'a, 'tcx>,
+ typeck_results: &'a TypeckResults<'tcx>,
+ target: GenericArg<'tcx>,
+ ) -> Self {
+ FindInferSourceVisitor {
+ infcx,
+ typeck_results,
+
+ target,
+
+ attempt: 0,
+ infer_source_cost: usize::MAX,
+ infer_source: None,
+ }
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
- self.level += 1;
- let t = match t.kind() {
- // We'll hide this type only if all its type params are hidden as well.
- ty::Adt(def, substs) => {
- let generics = self.tcx().generics_of(def.did());
- // Account for params with default values, like `Vec`, where we
- // want to show `Vec<T>`, not `Vec<T, _>`. If we replaced that
- // subst, then we'd get the incorrect output, so we passthrough.
- let substs: Vec<_> = substs
- .iter()
- .zip(generics.params.iter())
- .map(|(subst, param)| match &(subst.unpack(), ¶m.kind) {
- (_, ty::GenericParamDefKind::Type { has_default: true, .. }) => subst,
- (crate::infer::GenericArgKind::Const(c), _) => {
- self.replace_infers(*c, param.index, param.name).into()
- }
- _ => subst.super_fold_with(self),
- })
- .collect();
- let should_keep = |subst: &GenericArg<'_>| match subst.unpack() {
- ty::subst::GenericArgKind::Type(t) => match t.kind() {
- ty::Error(_) => false,
- _ => true,
- },
- // Account for `const` params here, otherwise `doesnt_infer.rs`
- // shows `_` instead of `Foo<{ _: u32 }>`
- ty::subst::GenericArgKind::Const(_) => true,
- _ => false,
+
+ /// Computes cost for the given source.
+ ///
+ /// Sources with a small cost are prefer and should result
+ /// in a clearer and idiomatic suggestion.
+ fn source_cost(&self, source: &InferSource<'tcx>) -> usize {
+ let tcx = self.infcx.tcx;
+
+ fn arg_cost<'tcx>(arg: GenericArg<'tcx>) -> usize {
+ match arg.unpack() {
+ GenericArgKind::Lifetime(_) => 0, // erased
+ GenericArgKind::Type(ty) => ty_cost(ty),
+ GenericArgKind::Const(_) => 3, // some non-zero value
+ }
+ }
+ fn ty_cost<'tcx>(ty: Ty<'tcx>) -> usize {
+ match ty.kind() {
+ ty::Closure(..) => 100,
+ ty::FnDef(..) => 20,
+ ty::FnPtr(..) => 10,
+ ty::Infer(..) => 0,
+ _ => 1,
+ }
+ }
+
+ // The sources are listed in order of preference here.
+ match source.kind {
+ InferSourceKind::LetBinding { ty, .. } => ty_cost(ty),
+ InferSourceKind::ClosureArg { ty, .. } => 5 + ty_cost(ty),
+ InferSourceKind::GenericArg { def_id, generic_args, .. } => {
+ let variant_cost = match tcx.def_kind(def_id) {
+ DefKind::Variant | DefKind::Ctor(CtorOf::Variant, _) => 15, // `None::<u32>` and friends are ugly.
+ _ => 12,
};
- if self.level == 1 || substs.iter().any(should_keep) {
- let substs = self.tcx().intern_substs(&substs[..]);
- self.tcx().mk_ty(ty::Adt(*def, substs))
- } else {
- self.tcx().ty_error()
+ variant_cost + generic_args.iter().map(|&arg| arg_cost(arg)).sum::<usize>()
+ }
+ InferSourceKind::FullyQualifiedMethodCall { substs, .. } => {
+ 20 + substs.iter().map(|arg| arg_cost(arg)).sum::<usize>()
+ }
+ InferSourceKind::ClosureReturn { ty, should_wrap_expr, .. } => {
+ 30 + ty_cost(ty) + if should_wrap_expr.is_some() { 10 } else { 0 }
+ }
+ }
+ }
+
+ /// Uses `fn source_cost` to determine whether this inference source is preferable to
+ /// previous sources. We generally prefer earlier sources.
+ #[instrument(level = "debug", skip(self))]
+ fn update_infer_source(&mut self, new_source: InferSource<'tcx>) {
+ let cost = self.source_cost(&new_source) + self.attempt;
+ self.attempt += 1;
+ if cost < self.infer_source_cost {
+ self.infer_source_cost = cost;
+ self.infer_source = Some(new_source);
+ }
+ }
+
+ fn opt_node_type(&self, hir_id: HirId) -> Option<Ty<'tcx>> {
+ let ty = self.typeck_results.node_type_opt(hir_id);
+ self.infcx.resolve_vars_if_possible(ty)
+ }
+
+ // Check whether this generic argument is the inference variable we
+ // are looking for.
+ fn generic_arg_is_target(&self, arg: GenericArg<'tcx>) -> bool {
+ if arg == self.target {
+ return true;
+ }
+
+ match (arg.unpack(), self.target.unpack()) {
+ (GenericArgKind::Type(inner_ty), GenericArgKind::Type(target_ty)) => {
+ use ty::{Infer, TyVar};
+ match (inner_ty.kind(), target_ty.kind()) {
+ (&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => {
+ self.infcx.inner.borrow_mut().type_variables().sub_unified(a_vid, b_vid)
+ }
+ _ => false,
+ }
+ }
+ (GenericArgKind::Const(inner_ct), GenericArgKind::Const(target_ct)) => {
+ use ty::InferConst::*;
+ match (inner_ct.val(), target_ct.val()) {
+ (ty::ConstKind::Infer(Var(a_vid)), ty::ConstKind::Infer(Var(b_vid))) => self
+ .infcx
+ .inner
+ .borrow_mut()
+ .const_unification_table()
+ .unioned(a_vid, b_vid),
+ _ => false,
+ }
+ }
+ _ => false,
+ }
+ }
+
+ /// Does this generic argument contain our target inference variable
+ /// in a way which can be written by the user.
+ fn generic_arg_contains_target(&self, arg: GenericArg<'tcx>) -> bool {
+ let mut walker = arg.walk();
+ while let Some(inner) = walker.next() {
+ if self.generic_arg_is_target(inner) {
+ return true;
+ }
+ match inner.unpack() {
+ GenericArgKind::Lifetime(_) => {}
+ GenericArgKind::Type(ty) => {
+ if matches!(ty.kind(), ty::Opaque(..) | ty::Closure(..) | ty::Generator(..)) {
+ // Opaque types can't be named by the user right now.
+ //
+ // Both the generic arguments of closures and generators can
+ // also not be named. We may want to only look into the closure
+ // signature in case it has no captures, as that can be represented
+ // using `fn(T) -> R`.
+
+ // FIXME(type_alias_impl_trait): These opaque types
+ // can actually be named, so it would make sense to
+ // adjust this case and add a test for it.
+ walker.skip_current_subtree();
+ }
+ }
+ GenericArgKind::Const(ct) => {
+ if matches!(ct.val(), ty::ConstKind::Unevaluated(..)) {
+ // You can't write the generic arguments for
+ // unevaluated constants.
+ walker.skip_current_subtree();
+ }
}
}
- ty::Ref(_, ty, _) => {
- let ty = self.fold_ty(*ty);
- match ty.kind() {
- // Avoid `&_`, these can be safely presented as `_`.
- ty::Error(_) => self.tcx().ty_error(),
- _ => t.super_fold_with(self),
+ }
+ false
+ }
+
+ fn expr_inferred_subst_iter(
+ &self,
+ expr: &'tcx hir::Expr<'tcx>,
+ ) -> Box<dyn Iterator<Item = InsertableGenericArgs<'tcx>> + 'a> {
+ let tcx = self.infcx.tcx;
+ match expr.kind {
+ hir::ExprKind::Path(ref path) => {
+ if let Some(substs) = self.typeck_results.node_substs_opt(expr.hir_id) {
+ return self.path_inferred_subst_iter(expr.hir_id, substs, path);
}
}
- // We could account for `()` if we wanted to replace it, but it's assured to be short.
- ty::Tuple(_)
- | ty::Slice(_)
- | ty::RawPtr(_)
- | ty::FnDef(..)
- | ty::FnPtr(_)
- | ty::Opaque(..)
- | ty::Projection(_)
- | ty::Never => t.super_fold_with(self),
- ty::Array(ty, c) => {
- self.tcx().mk_ty(ty::Array(self.fold_ty(*ty), self.replace_infers(*c, 0, sym::N)))
+ hir::ExprKind::Struct(path, _, _) => {
+ if let Some(ty) = self.opt_node_type(expr.hir_id) {
+ if let ty::Adt(_, substs) = ty.kind() {
+ return self.path_inferred_subst_iter(expr.hir_id, substs, path);
+ }
+ }
+ }
+ hir::ExprKind::MethodCall(segment, _, _) => {
+ if let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id) {
+ let generics = tcx.generics_of(def_id);
+ let insertable: Option<_> = try {
+ if generics.has_impl_trait() {
+ None?
+ }
+ let substs = self.typeck_results.node_substs_opt(expr.hir_id)?;
+ let span = tcx.hir().span(segment.hir_id?);
+ let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi());
+ InsertableGenericArgs {
+ insert_span,
+ substs,
+ generics_def_id: def_id,
+ def_id,
+ }
+ };
+ return Box::new(insertable.into_iter());
+ }
+ }
+ _ => {}
+ }
+
+ Box::new(iter::empty())
+ }
+
+ fn resolved_path_inferred_subst_iter(
+ &self,
+ path: &'tcx hir::Path<'tcx>,
+ substs: SubstsRef<'tcx>,
+ ) -> impl Iterator<Item = InsertableGenericArgs<'tcx>> + 'a {
+ let tcx = self.infcx.tcx;
+ // The last segment of a path often has `Res::Err` and the
+ // correct `Res` is the one of the whole path.
+ //
+ // FIXME: We deal with that one separately for now,
+ // would be good to remove this special case.
+ let last_segment_using_path_data: Option<_> = try {
+ let generics_def_id = tcx.res_generics_def_id(path.res)?;
+ let generics = tcx.generics_of(generics_def_id);
+ if generics.has_impl_trait() {
+ None?
+ }
+ let insert_span =
+ path.segments.last().unwrap().ident.span.shrink_to_hi().with_hi(path.span.hi());
+ InsertableGenericArgs {
+ insert_span,
+ substs,
+ generics_def_id,
+ def_id: path.res.def_id(),
}
- // We don't want to hide type params that haven't been resolved yet.
- // This would be the type that will be written out with the type param
- // name in the output.
- ty::Infer(_) => t,
- // We don't want to hide the outermost type, only its type params.
- _ if self.level == 1 => t.super_fold_with(self),
- // Hide this type
- _ => self.tcx().ty_error(),
};
- self.level -= 1;
- t
+
+ path.segments
+ .iter()
+ .filter_map(move |segment| {
+ let res = segment.res?;
+ let generics_def_id = tcx.res_generics_def_id(res)?;
+ let generics = tcx.generics_of(generics_def_id);
+ if generics.has_impl_trait() {
+ return None;
+ }
+ let span = tcx.hir().span(segment.hir_id?);
+ let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi());
+ Some(InsertableGenericArgs {
+ insert_span,
+ substs,
+ generics_def_id,
+ def_id: res.def_id(),
+ })
+ })
+ .chain(last_segment_using_path_data)
+ }
+
+ fn path_inferred_subst_iter(
+ &self,
+ hir_id: HirId,
+ substs: SubstsRef<'tcx>,
+ qpath: &'tcx hir::QPath<'tcx>,
+ ) -> Box<dyn Iterator<Item = InsertableGenericArgs<'tcx>> + 'a> {
+ let tcx = self.infcx.tcx;
+ match qpath {
+ hir::QPath::Resolved(_self_ty, path) => {
+ Box::new(self.resolved_path_inferred_subst_iter(path, substs))
+ }
+ hir::QPath::TypeRelative(ty, segment) => {
+ let Some(def_id) = self.typeck_results.type_dependent_def_id(hir_id) else {
+ return Box::new(iter::empty());
+ };
+
+ let generics = tcx.generics_of(def_id);
+ let segment: Option<_> = try {
+ if !segment.infer_args || generics.has_impl_trait() {
+ None?;
+ }
+ let span = tcx.hir().span(segment.hir_id?);
+ let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi());
+ InsertableGenericArgs { insert_span, substs, generics_def_id: def_id, def_id }
+ };
+
+ let parent_def_id = generics.parent.unwrap();
+ if tcx.def_kind(parent_def_id) == DefKind::Impl {
+ let parent_ty = tcx.bound_type_of(parent_def_id).subst(tcx, substs);
+ match (parent_ty.kind(), &ty.kind) {
+ (
+ ty::Adt(def, substs),
+ hir::TyKind::Path(hir::QPath::Resolved(_self_ty, path)),
+ ) => {
+ if tcx.res_generics_def_id(path.res) != Some(def.did()) {
+ bug!(
+ "unexpected path: def={:?} substs={:?} path={:?}",
+ def,
+ substs,
+ path,
+ );
+ } else {
+ return Box::new(
+ self.resolved_path_inferred_subst_iter(path, substs)
+ .chain(segment),
+ );
+ }
+ }
+ _ => (),
+ }
+ }
+
+ Box::new(segment.into_iter())
+ }
+ hir::QPath::LangItem(_, _, _) => Box::new(iter::empty()),
+ }
}
}
-/// Replace `[type error]` with `ty::Infer(ty::Var)` to display `_`.
-struct ErrTypeParamEraser<'tcx>(TyCtxt<'tcx>);
-impl<'tcx> TypeFolder<'tcx> for ErrTypeParamEraser<'tcx> {
- fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
- self.0
+impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
+ type NestedFilter = nested_filter::OnlyBodies;
+
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.infcx.tcx.hir()
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
- match t.kind() {
- ty::Error(_) => self.tcx().mk_ty_var(ty::TyVid::from_u32(0)),
- _ => t.super_fold_with(self),
+
+ fn visit_local(&mut self, local: &'tcx Local<'tcx>) {
+ intravisit::walk_local(self, local);
+
+ if let Some(ty) = self.opt_node_type(local.hir_id) {
+ if self.generic_arg_contains_target(ty.into()) {
+ match local.source {
+ LocalSource::Normal if local.ty.is_none() => {
+ self.update_infer_source(InferSource {
+ span: local.pat.span,
+ kind: InferSourceKind::LetBinding {
+ insert_span: local.pat.span.shrink_to_hi(),
+ pattern_name: local.pat.simple_ident(),
+ ty,
+ },
+ })
+ }
+ _ => {}
+ }
+ }
}
}
-}
-/// Replace type parameters with `ty::Infer(ty::Var)` to display `_`.
-struct TypeParamEraser<'tcx>(TyCtxt<'tcx>);
+ /// For closures, we first visit the parameters and then the content,
+ /// as we prefer those.
+ fn visit_body(&mut self, body: &'tcx Body<'tcx>) {
+ for param in body.params {
+ debug!(
+ "param: span {:?}, ty_span {:?}, pat.span {:?}",
+ param.span, param.ty_span, param.pat.span
+ );
+ if param.ty_span != param.pat.span {
+ debug!("skipping param: has explicit type");
+ continue;
+ }
+
+ let Some(param_ty) = self.opt_node_type(param.hir_id) else {
+ continue
+ };
-impl<'tcx> TypeFolder<'tcx> for TypeParamEraser<'tcx> {
- fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
- self.0
+ if self.generic_arg_contains_target(param_ty.into()) {
+ self.update_infer_source(InferSource {
+ span: param.pat.span,
+ kind: InferSourceKind::ClosureArg {
+ insert_span: param.pat.span.shrink_to_hi(),
+ ty: param_ty,
+ },
+ })
+ }
+ }
+ intravisit::walk_body(self, body);
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
- match t.kind() {
- ty::Param(_) | ty::Error(_) => self.tcx().mk_ty_var(ty::TyVid::from_u32(0)),
- _ => t.super_fold_with(self),
+
+ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
+ let tcx = self.infcx.tcx;
+ match expr.kind {
+ // When encountering `func(arg)` first look into `arg` and then `func`,
+ // as `arg` is "more specific".
+ ExprKind::Call(func, args) => {
+ for arg in args {
+ self.visit_expr(arg);
+ }
+ self.visit_expr(func);
+ }
+ _ => intravisit::walk_expr(self, expr),
+ }
+
+ for InsertableGenericArgs { insert_span, substs, generics_def_id, def_id } in
+ self.expr_inferred_subst_iter(expr)
+ {
+ let generics = tcx.generics_of(generics_def_id);
+ if let Some(argument_index) =
+ generics.own_substs(substs).iter().position(|&arg| self.generic_arg_is_target(arg))
+ {
+ let substs = self.infcx.resolve_vars_if_possible(substs);
+ let num_args = generics
+ .params
+ .iter()
+ .rev()
+ .filter(|&p| !matches!(p.kind, GenericParamDefKind::Lifetime))
+ .skip_while(|¶m| {
+ if let Some(default) = param.default_value(tcx) {
+ // FIXME: Using structural comparisions has a bunch of false negatives.
+ //
+ // We should instead try to replace inference variables with placeholders and
+ // then use `infcx.can_eq`. That probably should be a separate method
+ // generally used during error reporting.
+ default.subst(tcx, substs) == substs[param.index as usize]
+ } else {
+ false
+ }
+ })
+ .count();
+ let generic_args =
+ &generics.own_substs(substs)[generics.own_counts().lifetimes..][..num_args];
+ let span = match expr.kind {
+ ExprKind::MethodCall(path, _, _) => path.ident.span,
+ _ => expr.span,
+ };
+
+ self.update_infer_source(InferSource {
+ span,
+ kind: InferSourceKind::GenericArg {
+ insert_span,
+ argument_index,
+ generics_def_id,
+ def_id,
+ generic_args,
+ },
+ });
+ }
+ }
+
+ if let Some(node_ty) = self.opt_node_type(expr.hir_id) {
+ if let (&ExprKind::Closure(_, decl, body_id, span, _), ty::Closure(_, substs)) =
+ (&expr.kind, node_ty.kind())
+ {
+ let output = substs.as_closure().sig().output().skip_binder();
+ if self.generic_arg_contains_target(output.into()) {
+ let body = self.infcx.tcx.hir().body(body_id);
+ let should_wrap_expr = if matches!(body.value.kind, ExprKind::Block(..)) {
+ None
+ } else {
+ Some(body.value.span.shrink_to_hi())
+ };
+ self.update_infer_source(InferSource {
+ span,
+ kind: InferSourceKind::ClosureReturn {
+ ty: output,
+ data: &decl.output,
+ should_wrap_expr,
+ },
+ })
+ }
+ }
+ }
+
+ let has_impl_trait = |def_id| {
+ iter::successors(Some(tcx.generics_of(def_id)), |generics| {
+ generics.parent.map(|def_id| tcx.generics_of(def_id))
+ })
+ .any(|generics| generics.has_impl_trait())
+ };
+ if let ExprKind::MethodCall(path, args, span) = expr.kind
+ && let Some(substs) = self.typeck_results.node_substs_opt(expr.hir_id)
+ && substs.iter().any(|arg| self.generic_arg_contains_target(arg))
+ && let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id)
+ && self.infcx.tcx.trait_of_item(def_id).is_some()
+ && !has_impl_trait(def_id)
+ {
+ let successor =
+ args.get(1).map_or_else(|| (")", span.hi()), |arg| (", ", arg.span.lo()));
+ let substs = self.infcx.resolve_vars_if_possible(substs);
+ self.update_infer_source(InferSource {
+ span: path.ident.span,
+ kind: InferSourceKind::FullyQualifiedMethodCall {
+ receiver: args.first().unwrap(),
+ successor,
+ substs,
+ def_id,
+ }
+ })
}
}
}
use rustc_hir as hir;
use rustc_hir::{GenericParamKind, Ty};
use rustc_middle::ty::Region;
+use rustc_span::symbol::kw;
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
/// Print the error message for lifetime errors when both the concerned regions are anonymous.
return false;
};
- if !lifetime_sub.name.is_elided() || !lifetime_sup.name.is_elided() {
+ if !lifetime_sub.name.is_anonymous() || !lifetime_sup.name.is_anonymous() {
return false;
};
_ => return false,
};
- let (suggestion_param_name, introduce_new) = generics
+ let suggestion_param_name = generics
.params
.iter()
- .find(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
- .and_then(|p| tcx.sess.source_map().span_to_snippet(p.span).ok())
- .map(|name| (name, false))
- .unwrap_or_else(|| ("'a".to_string(), true));
-
- let mut suggestions = vec![
- if let hir::LifetimeName::Underscore = lifetime_sub.name {
- (lifetime_sub.span, suggestion_param_name.clone())
+ .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
+ .map(|p| p.name.ident().name)
+ .find(|i| *i != kw::UnderscoreLifetime);
+ let introduce_new = suggestion_param_name.is_none();
+ let suggestion_param_name =
+ suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned());
+
+ debug!(?lifetime_sup.span);
+ debug!(?lifetime_sub.span);
+ let make_suggestion = |span: rustc_span::Span| {
+ if span.is_empty() {
+ (span, format!("{}, ", suggestion_param_name))
+ } else if let Ok("&") = tcx.sess.source_map().span_to_snippet(span).as_deref() {
+ (span.shrink_to_hi(), format!("{} ", suggestion_param_name))
} else {
- (lifetime_sub.span.shrink_to_hi(), suggestion_param_name.clone() + " ")
- },
- if let hir::LifetimeName::Underscore = lifetime_sup.name {
- (lifetime_sup.span, suggestion_param_name.clone())
- } else {
- (lifetime_sup.span.shrink_to_hi(), suggestion_param_name.clone() + " ")
- },
- ];
+ (span, suggestion_param_name.clone())
+ }
+ };
+ let mut suggestions =
+ vec![make_suggestion(lifetime_sub.span), make_suggestion(lifetime_sup.span)];
if introduce_new {
- let new_param_suggestion = match &generics.params {
- [] => (generics.span, format!("<{}>", suggestion_param_name)),
- [first, ..] => (first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name)),
- };
+ let new_param_suggestion =
+ if let Some(first) = generics.params.iter().find(|p| !p.name.ident().span.is_empty()) {
+ (first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name))
+ } else {
+ (generics.span, format!("<{}>", suggestion_param_name))
+ };
suggestions.push(new_param_suggestion);
}
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
use rustc_middle::ty;
+use rustc_span::symbol::kw;
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
/// When given a `ConcreteFailure` for a function with parameters containing a named region and
let is_impl_item = region_info.is_impl_item;
match br {
- ty::BrAnon(_) => {}
+ ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) => {}
_ => {
/* not an anonymous region */
debug!("try_report_named_anon_conflict: not an anonymous region");
#![feature(let_else)]
#![feature(min_specialization)]
#![feature(never_type)]
+#![feature(try_blocks)]
#![recursion_limit = "512"] // For rustdoc
#[macro_use]
use rustc_plugin_impl as plugin;
use rustc_query_impl::{OnDiskCache, Queries as TcxQueries};
use rustc_resolve::{Resolver, ResolverArenas};
-use rustc_serialize::json;
use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType};
use rustc_session::cstore::{MetadataLoader, MetadataLoaderDyn};
use rustc_session::output::{filename_for_input, filename_for_metadata};
}
})?;
- if sess.opts.debugging_opts.ast_json_noexpand {
- println!("{}", json::as_json(&krate));
- }
-
if sess.opts.debugging_opts.input_stats {
eprintln!("Lines of code: {}", sess.source_map().count_lines());
eprintln!("Pre-expansion node count: {}", count_nodes(&krate));
hir_stats::print_ast_stats(&krate, "POST EXPANSION AST STATS");
}
- if sess.opts.debugging_opts.ast_json {
- println!("{}", json::as_json(&krate));
- }
-
resolver.resolve_crate(&krate);
// Needs to go *after* expansion to be able to check the results of macro expansion.
// Make sure that changing an [UNTRACKED] option leaves the hash unchanged.
// This list is in alphabetical order.
untracked!(assert_incr_state, Some(String::from("loaded")));
- untracked!(ast_json, true);
- untracked!(ast_json_noexpand, true);
untracked!(borrowck, String::from("other"));
untracked!(deduplicate_diagnostics, false);
untracked!(dep_tasks, true);
edition = "2021"
[dependencies]
+serde = { version = "1.0.125", features = ["derive"] }
rustc_ast = { path = "../rustc_ast" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_error_messages = { path = "../rustc_error_messages" }
use rustc_span::{sym, symbol::Ident, Span, Symbol};
use rustc_target::spec::abi::Abi;
+use serde::{Deserialize, Serialize};
+
pub mod builtin;
#[macro_export]
/// All suggestions are marked with an `Applicability`. Tools use the applicability of a suggestion
/// to determine whether it should be automatically applied or if the user should be consulted
/// before applying the suggestion.
-#[derive(Copy, Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
+#[derive(Copy, Clone, Debug, PartialEq, Hash, Encodable, Decodable, Serialize, Deserialize)]
pub enum Applicability {
/// The suggestion is definitely what the user intended, or maintains the exact meaning of the code.
/// This suggestion should be automatically applied.
let encode_body = match s.variants() {
[_] => {
- let mut field_idx = 0usize;
let encode_inner = s.each_variant(|vi| {
vi.bindings()
.iter()
.map(|binding| {
let bind_ident = &binding.binding;
- let field_name = binding
- .ast()
- .ident
- .as_ref()
- .map_or_else(|| field_idx.to_string(), |i| i.to_string());
- let first = field_idx == 0;
let result = quote! {
- match ::rustc_serialize::Encoder::emit_struct_field(
+ match ::rustc_serialize::Encodable::<#encoder_ty>::encode(
+ #bind_ident,
__encoder,
- #field_name,
- #first,
- |__encoder|
- ::rustc_serialize::Encodable::<#encoder_ty>::encode(#bind_ident, __encoder),
) {
::std::result::Result::Ok(()) => (),
::std::result::Result::Err(__err)
=> return ::std::result::Result::Err(__err),
}
};
- field_idx += 1;
result
})
.collect::<TokenStream>()
});
- let no_fields = field_idx == 0;
quote! {
- ::rustc_serialize::Encoder::emit_struct(__encoder, #no_fields, |__encoder| {
- ::std::result::Result::Ok(match *self { #encode_inner })
- })
+ ::std::result::Result::Ok(match *self { #encode_inner })
}
}
_ => {
let mut variant_idx = 0usize;
let encode_inner = s.each_variant(|vi| {
- let variant_name = vi.ast().ident.to_string();
- let mut field_idx = 0usize;
-
let encode_fields: TokenStream = vi
.bindings()
.iter()
.map(|binding| {
let bind_ident = &binding.binding;
- let first = field_idx == 0;
let result = quote! {
- match ::rustc_serialize::Encoder::emit_enum_variant_arg(
+ match ::rustc_serialize::Encodable::<#encoder_ty>::encode(
+ #bind_ident,
__encoder,
- #first,
- |__encoder|
- ::rustc_serialize::Encodable::<#encoder_ty>::encode(#bind_ident, __encoder),
) {
::std::result::Result::Ok(()) => (),
::std::result::Result::Err(__err)
=> return ::std::result::Result::Err(__err),
}
};
- field_idx += 1;
result
})
.collect();
- let result = if field_idx != 0 {
+ let result = if !vi.bindings().is_empty() {
quote! {
::rustc_serialize::Encoder::emit_enum_variant(
__encoder,
- #variant_name,
#variant_idx,
- #field_idx,
|__encoder| { ::std::result::Result::Ok({ #encode_fields }) }
)
}
quote! {
::rustc_serialize::Encoder::emit_fieldless_enum_variant::<#variant_idx>(
__encoder,
- #variant_name,
)
}
};
result
});
quote! {
- ::rustc_serialize::Encoder::emit_enum(__encoder, |__encoder| {
- match *self {
- #encode_inner
- }
- })
+ match *self {
+ #encode_inner
+ }
}
}
};
impl<'a, 'tcx> Encoder for EncodeContext<'a, 'tcx> {
type Error = <opaque::Encoder as Encoder>::Error;
- #[inline]
- fn emit_unit(&mut self) -> Result<(), Self::Error> {
- Ok(())
- }
-
encoder_methods! {
emit_usize(usize);
emit_u128(u128);
pub fn get_generics(self, id: LocalDefId) -> Option<&'hir Generics<'hir>> {
let node = self.tcx.hir_owner(id)?;
- match node.node {
- OwnerNode::ImplItem(impl_item) => Some(&impl_item.generics),
- OwnerNode::TraitItem(trait_item) => Some(&trait_item.generics),
- OwnerNode::Item(Item {
- kind:
- ItemKind::Fn(_, generics, _)
- | ItemKind::TyAlias(_, generics)
- | ItemKind::Enum(_, generics)
- | ItemKind::Struct(_, generics)
- | ItemKind::Union(_, generics)
- | ItemKind::Trait(_, _, generics, ..)
- | ItemKind::TraitAlias(generics, _)
- | ItemKind::Impl(Impl { generics, .. }),
- ..
- }) => Some(generics),
- _ => None,
- }
+ node.node.generics()
}
pub fn item(self, id: ItemId) -> &'hir Item<'hir> {
Node::AnonConst(constant) => self.body(constant.body).value.span,
Node::Expr(expr) => expr.span,
Node::Stmt(stmt) => stmt.span,
- Node::PathSegment(seg) => seg.ident.span,
+ Node::PathSegment(seg) => {
+ let ident_span = seg.ident.span;
+ ident_span
+ .with_hi(seg.args.map_or_else(|| ident_span.hi(), |args| args.span_ext.hi()))
+ }
Node::Ty(ty) => ty.span,
Node::TraitRef(tr) => tr.path.span,
Node::Binding(pat) => pat.span,
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::ItemLocalId;
use rustc_macros::HashStable;
-use rustc_span::symbol::Symbol;
#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)]
pub enum Region {
/// so that we can e.g. suggest elided-lifetimes-in-paths of the form <'_, '_> e.g.
#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)]
pub enum LifetimeScopeForPath {
- // Contains all lifetime names that are in scope and could possibly be used in generics
- // arguments of path.
- NonElided(Vec<Symbol>),
+ /// Contains all lifetime names that are in scope and could possibly be used in generics
+ /// arguments of path.
+ NonElided(Vec<LocalDefId>),
- // Information that allows us to suggest args of the form `<'_>` in case
- // no generic arguments were provided for a path.
+ /// Information that allows us to suggest args of the form `<'_>` in case
+ /// no generic arguments were provided for a path.
Elided,
}
ScalarSizeMismatch { target_size: target_size.bytes(), data_size: size.bytes() }
})?),
Scalar::Ptr(ptr, sz) => {
- if target_size.bytes() != sz.into() {
+ if target_size.bytes() != u64::from(sz) {
return Err(ScalarSizeMismatch {
target_size: target_size.bytes(),
data_size: sz.into(),
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
static_assert_size!(Rvalue<'_>, 40);
+impl<'tcx> Rvalue<'tcx> {
+ #[inline]
+ pub fn is_pointer_int_cast(&self) -> bool {
+ matches!(self, Rvalue::Cast(CastKind::PointerExposeAddress, _, _))
+ }
+}
+
#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
pub enum CastKind {
- Misc,
+ /// An exposing pointer to address cast. A cast between a pointer and an integer type, or
+ /// between a function pointer and an integer type.
+ /// See the docs on `expose_addr` for more details.
+ PointerExposeAddress,
+ /// An address-to-pointer cast that picks up an exposed provenance.
+ /// See the docs on `from_exposed_addr` for more details.
+ PointerFromExposedAddress,
+ /// All sorts of pointer-to-pointer casts. Note that reference-to-raw-ptr casts are
+ /// translated into `&raw mut/const *r`, i.e., they are not actually casts.
Pointer(PointerCast),
+ /// Remaining unclassified casts.
+ Misc,
}
#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
impl<S: serialize::Encoder> serialize::Encodable<S> for PredecessorCache {
#[inline]
- fn encode(&self, s: &mut S) -> Result<(), S::Error> {
- s.emit_unit()
+ fn encode(&self, _s: &mut S) -> Result<(), S::Error> {
+ Ok(())
}
}
impl<S: serialize::Encoder> serialize::Encodable<S> for SwitchSourceCache {
#[inline]
- fn encode(&self, s: &mut S) -> Result<(), S::Error> {
- s.emit_unit()
+ fn encode(&self, _s: &mut S) -> Result<(), S::Error> {
+ Ok(())
}
}
*/
use crate::mir::*;
-use crate::ty::cast::CastTy;
use crate::ty::subst::Subst;
use crate::ty::{self, Ty, TyCtxt};
use rustc_hir as hir;
_ => RvalueInitializationState::Deep,
}
}
-
- pub fn is_pointer_int_cast<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> bool
- where
- D: HasLocalDecls<'tcx>,
- {
- if let Rvalue::Cast(CastKind::Misc, src_op, dest_ty) = self {
- if let Some(CastTy::Int(_)) = CastTy::from_ty(*dest_ty) {
- let src_ty = src_op.ty(local_decls, tcx);
- if let Some(CastTy::FnPtr | CastTy::Ptr(_)) = CastTy::from_ty(src_ty) {
- return true;
- }
- }
- }
-
- false
- }
}
impl<'tcx> Operand<'tcx> {
impl<S: serialize::Encoder> serialize::Encodable<S> for PostorderCache {
#[inline]
- fn encode(&self, s: &mut S) -> Result<(), S::Error> {
- s.emit_unit()
+ fn encode(&self, _s: &mut S) -> Result<(), S::Error> {
+ Ok(())
}
}
Option<&'tcx FxHashMap<ItemLocalId, Region>> {
desc { "looking up a named region" }
}
- query is_late_bound_map(_: LocalDefId) -> Option<(LocalDefId, &'tcx FxHashSet<LocalDefId>)> {
+ query is_late_bound_map(_: LocalDefId) -> Option<&'tcx FxHashSet<LocalDefId>> {
desc { "testing if a region is late bound" }
}
/// For a given item (like a struct), gets the default lifetimes to be used
query upvars_mentioned(def_id: DefId) -> Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>> {
desc { |tcx| "collecting upvars mentioned in `{}`", tcx.def_path_str(def_id) }
}
- query maybe_unused_trait_import(def_id: LocalDefId) -> bool {
- desc { |tcx| "maybe_unused_trait_import for `{}`", tcx.def_path_str(def_id.to_def_id()) }
+ query maybe_unused_trait_imports(_: ()) -> &'tcx FxIndexSet<LocalDefId> {
+ desc { "fetching potentially unused trait imports" }
}
query maybe_unused_extern_crates(_: ()) -> &'tcx [(LocalDefId, Span)] {
desc { "looking up all possibly unused extern crates" }
self.named_region_map(id.owner).and_then(|map| map.get(&id.local_id).cloned())
}
+ pub fn is_late_bound(self, id: HirId) -> bool {
+ self.is_late_bound_map(id.owner).map_or(false, |set| {
+ let def_id = self.hir().local_def_id(id);
+ set.contains(&def_id)
+ })
+ }
+
pub fn late_bound_vars(self, id: HirId) -> &'tcx List<ty::BoundVariableKind> {
self.mk_bound_variable_kinds(
self.late_bound_vars_map(id.owner)
assert_eq!(id, LOCAL_CRATE);
tcx.crate_name
};
- providers.maybe_unused_trait_import =
- |tcx, id| tcx.resolutions(()).maybe_unused_trait_imports.contains(&id);
+ providers.maybe_unused_trait_imports =
+ |tcx, ()| &tcx.resolutions(()).maybe_unused_trait_imports;
providers.maybe_unused_extern_crates =
|tcx, ()| &tcx.resolutions(()).maybe_unused_extern_crates[..];
providers.names_imported_by_glob_use = |tcx, id| {
continue;
}
- let constraint = constraints.iter().map(|&(c, _)| c).collect::<Vec<_>>().join(" + ");
+ let mut constraint = constraints.iter().map(|&(c, _)| c).collect::<Vec<_>>();
+ constraint.sort();
+ constraint.dedup();
+ let constraint = constraint.join(" + ");
let mut suggest_restrict = |span, bound_list_non_empty| {
suggestions.push((
span,
bug!("cannot convert a non-lifetime parameter def to an early bound region")
}
}
+
+ pub fn has_default(&self) -> bool {
+ match self.kind {
+ GenericParamDefKind::Type { has_default, .. }
+ | GenericParamDefKind::Const { has_default } => has_default,
+ GenericParamDefKind::Lifetime => false,
+ }
+ }
+
+ pub fn default_value<'tcx>(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ ) -> Option<EarlyBinder<ty::GenericArg<'tcx>>> {
+ match self.kind {
+ GenericParamDefKind::Type { has_default, .. } if has_default => {
+ Some(EarlyBinder(tcx.type_of(self.def_id).into()))
+ }
+ GenericParamDefKind::Const { has_default } if has_default => {
+ Some(EarlyBinder(tcx.const_param_default(self.def_id).into()))
+ }
+ _ => None,
+ }
+ }
}
#[derive(Default)]
matches!(param.kind, ty::GenericParamDefKind::Type { synthetic: true, .. })
})
}
+
+ /// Returns the substs corresponding to the generic parameters of this item, excluding `Self`.
+ pub fn own_substs(&'tcx self, substs: SubstsRef<'tcx>) -> &'tcx [ty::GenericArg<'tcx>] {
+ let own = &substs[self.parent_count..][..self.params.len()];
+ if self.has_self && self.parent.is_none() { &own[1..] } else { &own }
+ }
}
/// Bounds on generics.
use rustc_ast as ast;
use rustc_attr as attr;
use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
use rustc_data_structures::intern::{Interned, WithStableHash};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::tagged_ptr::CopyTaggedPtr;
pub has_pub_restricted: bool,
pub access_levels: AccessLevels,
pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
- pub maybe_unused_trait_imports: FxHashSet<LocalDefId>,
+ pub maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
pub reexport_map: FxHashMap<LocalDefId, Vec<ModChild>>,
pub glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
define_scoped_cx!(self);
let mut region_index = self.region_index;
+ let mut next_name = |this: &Self| loop {
+ let name = name_by_region_index(region_index);
+ region_index += 1;
+ if !this.used_region_names.contains(&name) {
+ break name;
+ }
+ };
+
// If we want to print verbosely, then print *all* binders, even if they
// aren't named. Eventually, we might just want this as the default, but
// this is not *quite* right and changes the ordering of some output
// anyways.
let (new_value, map) = if self.tcx().sess.verbose() {
- // anon index + 1 (BrEnv takes 0) -> name
- let mut region_map: BTreeMap<u32, Symbol> = BTreeMap::default();
- let bound_vars = value.bound_vars();
- for var in bound_vars {
- match var {
- ty::BoundVariableKind::Region(ty::BrNamed(_, name)) => {
- start_or_continue(&mut self, "for<", ", ");
- do_continue(&mut self, name);
- }
- ty::BoundVariableKind::Region(ty::BrAnon(i)) => {
- start_or_continue(&mut self, "for<", ", ");
- let name = loop {
- let name = name_by_region_index(region_index);
- region_index += 1;
- if !self.used_region_names.contains(&name) {
- break name;
- }
- };
- do_continue(&mut self, name);
- region_map.insert(i + 1, name);
- }
- ty::BoundVariableKind::Region(ty::BrEnv) => {
- start_or_continue(&mut self, "for<", ", ");
- let name = loop {
- let name = name_by_region_index(region_index);
- region_index += 1;
- if !self.used_region_names.contains(&name) {
- break name;
- }
- };
- do_continue(&mut self, name);
- region_map.insert(0, name);
+ let regions: Vec<_> = value
+ .bound_vars()
+ .into_iter()
+ .map(|var| {
+ let ty::BoundVariableKind::Region(var) = var else {
+ // This doesn't really matter because it doesn't get used,
+ // it's just an empty value
+ return ty::BrAnon(0);
+ };
+ match var {
+ ty::BrAnon(_) | ty::BrEnv => {
+ start_or_continue(&mut self, "for<", ", ");
+ let name = next_name(&self);
+ do_continue(&mut self, name);
+ ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
+ }
+ ty::BrNamed(def_id, kw::UnderscoreLifetime) => {
+ start_or_continue(&mut self, "for<", ", ");
+ let name = next_name(&self);
+ do_continue(&mut self, name);
+ ty::BrNamed(def_id, name)
+ }
+ ty::BrNamed(def_id, name) => {
+ start_or_continue(&mut self, "for<", ", ");
+ do_continue(&mut self, name);
+ ty::BrNamed(def_id, name)
+ }
}
- _ => continue,
- }
- }
+ })
+ .collect();
start_or_continue(&mut self, "", "> ");
self.tcx.replace_late_bound_regions(value.clone(), |br| {
- let kind = match br.kind {
- ty::BrNamed(_, _) => br.kind,
- ty::BrAnon(i) => {
- let name = region_map[&(i + 1)];
- ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
- }
- ty::BrEnv => {
- let name = region_map[&0];
- ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
- }
- };
+ let kind = regions[br.var.as_usize()];
self.tcx.mk_region(ty::ReLateBound(
ty::INNERMOST,
ty::BoundRegion { var: br.var, kind },
let mut name = |br: ty::BoundRegion| {
start_or_continue(&mut self, "for<", ", ");
let kind = match br.kind {
- ty::BrNamed(_, name) => {
- do_continue(&mut self, name);
- br.kind
- }
ty::BrAnon(_) | ty::BrEnv => {
- let name = loop {
- let name = name_by_region_index(region_index);
- region_index += 1;
- if !self.used_region_names.contains(&name) {
- break name;
- }
- };
+ let name = next_name(&self);
do_continue(&mut self, name);
ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
}
+ ty::BrNamed(def_id, kw::UnderscoreLifetime) => {
+ let name = next_name(&self);
+ do_continue(&mut self, name);
+ ty::BrNamed(def_id, name)
+ }
+ ty::BrNamed(_, name) => {
+ do_continue(&mut self, name);
+ br.kind
+ }
};
tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { var: br.var, kind }))
};
use rustc_ast as ast;
use rustc_ast::expand::allocator::AllocatorKind;
use rustc_attr as attr;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
use rustc_data_structures::steal::Steal;
use rustc_data_structures::svh::Svh;
use rustc_data_structures::sync::Lrc;
use rustc_middle::mir::Place;
use rustc_middle::mir::*;
use rustc_middle::thir::*;
+use rustc_middle::ty::cast::CastTy;
use rustc_middle::ty::{self, Ty, UpvarSubsts};
use rustc_span::Span;
block.and(Rvalue::Use(Operand::Move(Place::from(result))))
}
ExprKind::Cast { source } => {
+ let source = &this.thir[source];
+ let from_ty = CastTy::from_ty(source.ty);
+ let cast_ty = CastTy::from_ty(expr.ty);
+ let cast_kind = match (from_ty, cast_ty) {
+ (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => {
+ CastKind::PointerExposeAddress
+ }
+ (Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => {
+ CastKind::PointerFromExposedAddress
+ }
+ (_, _) => CastKind::Misc,
+ };
let source = unpack!(
- block =
- this.as_operand(block, scope, &this.thir[source], None, NeedsTemporary::No)
+ block = this.as_operand(block, scope, source, None, NeedsTemporary::No)
);
- block.and(Rvalue::Cast(CastKind::Misc, source, expr.ty))
+ block.and(Rvalue::Cast(cast_kind, source, expr.ty))
}
ExprKind::Pointer { cast, source } => {
let source = unpack!(
use rustc_index::bit_set::{BitSet, ChunkedBitSet};
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
-use rustc_middle::mir::{self, Local, LocalDecls, Location, Place, StatementKind};
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::mir::{self, Local, Location, Place, StatementKind};
use crate::{Analysis, AnalysisDomain, Backward, CallReturnPlaces, GenKill, GenKillAnalysis};
/// This is basically written for dead store elimination and nothing else.
///
/// All of the caveats of `MaybeLiveLocals` apply.
-pub struct MaybeTransitiveLiveLocals<'a, 'tcx> {
+pub struct MaybeTransitiveLiveLocals<'a> {
always_live: &'a BitSet<Local>,
- local_decls: &'a LocalDecls<'tcx>,
- tcx: TyCtxt<'tcx>,
}
-impl<'a, 'tcx> MaybeTransitiveLiveLocals<'a, 'tcx> {
+impl<'a> MaybeTransitiveLiveLocals<'a> {
/// The `always_alive` set is the set of locals to which all stores should unconditionally be
/// considered live.
///
/// This should include at least all locals that are ever borrowed.
- pub fn new(
- always_live: &'a BitSet<Local>,
- local_decls: &'a LocalDecls<'tcx>,
- tcx: TyCtxt<'tcx>,
- ) -> Self {
- MaybeTransitiveLiveLocals { always_live, local_decls, tcx }
+ pub fn new(always_live: &'a BitSet<Local>) -> Self {
+ MaybeTransitiveLiveLocals { always_live }
}
}
-impl<'a, 'tcx> AnalysisDomain<'tcx> for MaybeTransitiveLiveLocals<'a, 'tcx> {
+impl<'a, 'tcx> AnalysisDomain<'tcx> for MaybeTransitiveLiveLocals<'a> {
type Domain = ChunkedBitSet<Local>;
type Direction = Backward;
}
}
-impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a, 'tcx> {
+impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
fn apply_statement_effect(
&self,
trans: &mut Self::Domain,
// Compute the place that we are storing to, if any
let destination = match &statement.kind {
StatementKind::Assign(assign) => {
- if assign.1.is_pointer_int_cast(self.local_decls, self.tcx) {
+ if assign.1.is_pointer_int_cast() {
// Pointer to int casts may be side-effects due to exposing the provenance.
// While the model is undecided, we should be conservative. See
// <https://www.ralfj.de/blog/2022/04/11/provenance-exposed.html>
/// The `borrowed` set must be a `BitSet` of all the locals that are ever borrowed in this body. It
/// can be generated via the [`get_borrowed_locals`] function.
pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitSet<Local>) {
- let mut live = MaybeTransitiveLiveLocals::new(borrowed, &body.local_decls, tcx)
+ let mut live = MaybeTransitiveLiveLocals::new(borrowed)
.into_engine(tcx, body)
.iterate_to_fixpoint()
.into_results_cursor(body);
for (statement_index, statement) in bb_data.statements.iter().enumerate().rev() {
let loc = Location { block: bb, statement_index };
if let StatementKind::Assign(assign) = &statement.kind {
- if assign.1.is_pointer_int_cast(&body.local_decls, tcx) {
+ if assign.1.is_pointer_int_cast() {
continue;
}
}
return Err("optimization fuel exhausted");
}
- let callee_body = callsite.callee.subst_mir_and_normalize_erasing_regions(
+ let Ok(callee_body) = callsite.callee.try_subst_mir_and_normalize_erasing_regions(
self.tcx,
self.param_env,
callee_body.clone(),
- );
+ ) else {
+ return Err("failed to normalize callee body");
+ };
let old_blocks = caller_body.basic_blocks().next_index();
self.inline_call(caller_body, &callsite, callee_body);
let func_ty = func.ty(caller_body, self.tcx);
if let ty::FnDef(def_id, substs) = *func_ty.kind() {
// To resolve an instance its substs have to be fully normalized.
- let substs = self.tcx.normalize_erasing_regions(self.param_env, substs);
+ let substs = self.tcx.try_normalize_erasing_regions(self.param_env, substs).ok()?;
let callee =
Instance::resolve(self.tcx, self.param_env, def_id, substs).ok().flatten()?;
if let ty::FnDef(def_id, substs) =
*callsite.callee.subst_mir(self.tcx, &f.literal.ty()).kind()
{
- let substs = self.tcx.normalize_erasing_regions(self.param_env, substs);
- if let Ok(Some(instance)) =
- Instance::resolve(self.tcx, self.param_env, def_id, substs)
+ if let Ok(substs) =
+ self.tcx.try_normalize_erasing_regions(self.param_env, substs)
{
- if callsite.callee.def_id() == instance.def_id() {
- return Err("self-recursion");
- } else if self.history.contains(&instance) {
- return Err("already inlined");
+ if let Ok(Some(instance)) =
+ Instance::resolve(self.tcx, self.param_env, def_id, substs)
+ {
+ if callsite.callee.def_id() == instance.def_id() {
+ return Err("self-recursion");
+ } else if self.history.contains(&instance) {
+ return Err("already inlined");
+ }
}
}
// Don't give intrinsics the extra penalty for calls
use super::pat::Expected;
-use super::ty::{AllowPlus, RecoverQuestionMark};
use super::{
- BlockMode, CommaRecoveryMode, Parser, PathStyle, RecoverColon, RecoverComma, Restrictions,
- SemiColonMode, SeqSep, TokenExpectType, TokenType,
+ BlockMode, CommaRecoveryMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep,
+ TokenExpectType, TokenType,
};
use crate::lexer::UnmatchedBrace;
},
}
+#[derive(SessionDiagnostic)]
+#[error(slug = "parser-maybe-recover-from-bad-qpath-stage-2")]
+struct BadQPathStage2 {
+ #[primary_span]
+ #[suggestion(applicability = "maybe-incorrect")]
+ span: Span,
+ ty: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(slug = "parser-incorrect-semicolon")]
+struct IncorrectSemicolon<'a> {
+ #[primary_span]
+ #[suggestion_short(applicability = "machine-applicable")]
+ span: Span,
+ #[help]
+ opt_help: Option<()>,
+ name: &'a str,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(slug = "parser-incorrect-use-of-await")]
+struct IncorrectUseOfAwait {
+ #[primary_span]
+ #[suggestion(message = "parentheses-suggestion", applicability = "machine-applicable")]
+ span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(slug = "parser-incorrect-use-of-await")]
+struct IncorrectAwait {
+ #[primary_span]
+ span: Span,
+ #[suggestion(message = "postfix-suggestion", code = "{expr}.await{question_mark}")]
+ sugg_span: (Span, Applicability),
+ expr: String,
+ question_mark: &'static str,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(slug = "parser-in-in-typo")]
+struct InInTypo {
+ #[primary_span]
+ span: Span,
+ #[suggestion(applicability = "machine-applicable")]
+ sugg_span: Span,
+}
+
// SnapshotParser is used to create a snapshot of the parser
// without causing duplicate errors being emitted when the `Parser`
// is dropped.
}
}
- pub(super) fn maybe_report_ambiguous_plus(
- &mut self,
- allow_plus: AllowPlus,
- impl_dyn_multi: bool,
- ty: &Ty,
- ) {
- if matches!(allow_plus, AllowPlus::No) && impl_dyn_multi {
+ pub(super) fn maybe_report_ambiguous_plus(&mut self, impl_dyn_multi: bool, ty: &Ty) {
+ if impl_dyn_multi {
self.sess.emit_err(AmbiguousPlus { sum_ty: pprust::ty_to_string(&ty), span: ty.span });
}
}
/// Swift lets users write `Ty?` to mean `Option<Ty>`. Parse the construct and recover from it.
- pub(super) fn maybe_recover_from_question_mark(
- &mut self,
- ty: P<Ty>,
- recover_question_mark: RecoverQuestionMark,
- ) -> P<Ty> {
- if let RecoverQuestionMark::No = recover_question_mark {
- return ty;
- }
+ pub(super) fn maybe_recover_from_question_mark(&mut self, ty: P<Ty>) -> P<Ty> {
if self.token == token::Question {
self.bump();
self.struct_span_err(self.prev_token.span, "invalid `?` in type")
}
}
- pub(super) fn maybe_recover_from_bad_type_plus(
- &mut self,
- allow_plus: AllowPlus,
- ty: &Ty,
- ) -> PResult<'a, ()> {
+ pub(super) fn maybe_recover_from_bad_type_plus(&mut self, ty: &Ty) -> PResult<'a, ()> {
// Do not add `+` to expected tokens.
- if matches!(allow_plus, AllowPlus::No) || !self.token.is_like_plus() {
+ if !self.token.is_like_plus() {
return Ok(());
}
pub(super) fn maybe_recover_from_bad_qpath<T: RecoverQPath>(
&mut self,
base: P<T>,
- allow_recovery: bool,
) -> PResult<'a, P<T>> {
// Do not add `::` to expected tokens.
- if allow_recovery && self.token == token::ModSep {
+ if self.token == token::ModSep {
if let Some(ty) = base.to_ty() {
return self.maybe_recover_from_bad_qpath_stage_2(ty.span, ty);
}
path.span = ty_span.to(self.prev_token.span);
let ty_str = self.span_to_snippet(ty_span).unwrap_or_else(|_| pprust::ty_to_string(&ty));
- self.struct_span_err(path.span, "missing angle brackets in associated item path")
- .span_suggestion(
- // This is a best-effort recovery.
- path.span,
- "try",
- format!("<{}>::{}", ty_str, pprust::path_to_string(&path)),
- Applicability::MaybeIncorrect,
- )
- .emit();
+ self.sess.emit_err(BadQPathStage2 {
+ span: path.span,
+ ty: format!("<{}>::{}", ty_str, pprust::path_to_string(&path)),
+ });
let path_span = ty_span.shrink_to_hi(); // Use an empty path since `position == 0`.
Ok(P(T::recovered(Some(QSelf { ty, path_span, position: 0 }), path)))
pub fn maybe_consume_incorrect_semicolon(&mut self, items: &[P<Item>]) -> bool {
if self.token.kind == TokenKind::Semi {
self.bump();
- let mut err = self.struct_span_err(self.prev_token.span, "expected item, found `;`");
- err.span_suggestion_short(
- self.prev_token.span,
- "remove this semicolon",
- String::new(),
- Applicability::MachineApplicable,
- );
+
+ let mut err =
+ IncorrectSemicolon { span: self.prev_token.span, opt_help: None, name: "" };
+
if !items.is_empty() {
let previous_item = &items[items.len() - 1];
let previous_item_kind_name = match previous_item.kind {
_ => None,
};
if let Some(name) = previous_item_kind_name {
- err.help(&format!("{name} declarations are not followed by a semicolon"));
+ err.opt_help = Some(());
+ err.name = name;
}
}
- err.emit();
+ self.sess.emit_err(err);
true
} else {
false
_ => ExprKind::Await(expr),
};
let expr = self.mk_expr(lo.to(sp), kind, attrs);
- self.maybe_recover_from_bad_qpath(expr, true)
+ self.maybe_recover_from_bad_qpath(expr)
}
fn recover_await_macro(&mut self) -> PResult<'a, (Span, P<Expr>, bool)> {
}
fn error_on_incorrect_await(&self, lo: Span, hi: Span, expr: &Expr, is_question: bool) -> Span {
- let expr_str =
- self.span_to_snippet(expr.span).unwrap_or_else(|_| pprust::expr_to_string(&expr));
- let suggestion = format!("{}.await{}", expr_str, if is_question { "?" } else { "" });
- let sp = lo.to(hi);
- let app = match expr.kind {
+ let span = lo.to(hi);
+ let applicability = match expr.kind {
ExprKind::Try(_) => Applicability::MaybeIncorrect, // `await <expr>?`
_ => Applicability::MachineApplicable,
};
- self.struct_span_err(sp, "incorrect use of `await`")
- .span_suggestion(sp, "`await` is a postfix operation", suggestion, app)
- .emit();
- sp
+
+ self.sess.emit_err(IncorrectAwait {
+ span,
+ sugg_span: (span, applicability),
+ expr: self.span_to_snippet(expr.span).unwrap_or_else(|_| pprust::expr_to_string(&expr)),
+ question_mark: if is_question { "?" } else { "" },
+ });
+
+ span
}
/// If encountering `future.await()`, consumes and emits an error.
// future.await()
let lo = self.token.span;
self.bump(); // (
- let sp = lo.to(self.token.span);
+ let span = lo.to(self.token.span);
self.bump(); // )
- self.struct_span_err(sp, "incorrect use of `await`")
- .span_suggestion(
- sp,
- "`await` is not a method call, remove the parentheses",
- String::new(),
- Applicability::MachineApplicable,
- )
- .emit();
+
+ self.sess.emit_err(IncorrectUseOfAwait { span });
}
}
pub(super) fn check_for_for_in_in_typo(&mut self, in_span: Span) {
if self.eat_keyword(kw::In) {
// a common typo: `for _ in in bar {}`
- self.struct_span_err(self.prev_token.span, "expected iterable, found keyword `in`")
- .span_suggestion_short(
- in_span.until(self.prev_token.span),
- "remove the duplicated `in`",
- String::new(),
- Applicability::MachineApplicable,
- )
- .emit();
+ self.sess.emit_err(InInTypo {
+ span: self.prev_token.span,
+ sugg_span: in_span.until(self.prev_token.span),
+ });
}
}
pub(crate) fn maybe_recover_colon_colon_in_pat_typo(
&mut self,
mut first_pat: P<Pat>,
- ra: RecoverColon,
expected: Expected,
) -> P<Pat> {
- if RecoverColon::Yes != ra || token::Colon != self.token.kind {
+ if token::Colon != self.token.kind {
return first_pat;
}
if !matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..))
pub(crate) fn maybe_recover_unexpected_comma(
&mut self,
lo: Span,
- rc: RecoverComma,
rt: CommaRecoveryMode,
) -> PResult<'a, ()> {
- if rc == RecoverComma::No || self.token != token::Comma {
+ if self.token != token::Comma {
return Ok(());
}
match self.parse_opt_lit() {
Some(literal) => {
let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Lit(literal), attrs);
- self.maybe_recover_from_bad_qpath(expr, true)
+ self.maybe_recover_from_bad_qpath(expr)
}
None => self.try_macro_suggestion(),
}
ExprKind::Tup(es)
};
let expr = self.mk_expr(lo.to(self.prev_token.span), kind, attrs);
- self.maybe_recover_from_bad_qpath(expr, true)
+ self.maybe_recover_from_bad_qpath(expr)
}
fn parse_array_or_repeat_expr(
}
};
let expr = self.mk_expr(lo.to(self.prev_token.span), kind, attrs);
- self.maybe_recover_from_bad_qpath(expr, true)
+ self.maybe_recover_from_bad_qpath(expr)
}
fn parse_path_start_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
};
let expr = self.mk_expr(lo.to(hi), kind, attrs);
- self.maybe_recover_from_bad_qpath(expr, true)
+ self.maybe_recover_from_bad_qpath(expr)
}
/// Parse `'label: $expr`. The label is already parsed.
let lo = self.prev_token.span;
let kind = ExprKind::Ret(self.parse_expr_opt()?);
let expr = self.mk_expr(lo.to(self.prev_token.span), kind, attrs);
- self.maybe_recover_from_bad_qpath(expr, true)
+ self.maybe_recover_from_bad_qpath(expr)
}
/// Parse `"do" "yeet" expr?`.
let span = lo.to(self.prev_token.span);
self.sess.gated_spans.gate(sym::yeet_expr, span);
let expr = self.mk_expr(span, kind, attrs);
- self.maybe_recover_from_bad_qpath(expr, true)
+ self.maybe_recover_from_bad_qpath(expr)
}
/// Parse `"break" (('label (:? expr)?) | expr?)` with `"break"` token already eaten.
None
};
let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Break(label, kind), attrs);
- self.maybe_recover_from_bad_qpath(expr, true)
+ self.maybe_recover_from_bad_qpath(expr)
}
/// Parse `"yield" expr?`.
let span = lo.to(self.prev_token.span);
self.sess.gated_spans.gate(sym::generators, span);
let expr = self.mk_expr(span, kind, attrs);
- self.maybe_recover_from_bad_qpath(expr, true)
+ self.maybe_recover_from_bad_qpath(expr)
}
/// Returns a string literal if the next token is a string literal.
};
// Parse the first pattern (`p_0`).
- let first_pat = self.parse_pat_no_top_alt(expected)?;
- self.maybe_recover_unexpected_comma(first_pat.span, rc, rt)?;
+ let mut first_pat = self.parse_pat_no_top_alt(expected)?;
+ if rc == RecoverComma::Yes {
+ self.maybe_recover_unexpected_comma(first_pat.span, rt)?;
+ }
// If the next token is not a `|`,
// this is not an or-pattern and we should exit here.
// This complicated procedure is done purely for diagnostics UX.
// Check if the user wrote `foo:bar` instead of `foo::bar`.
- let first_pat = self.maybe_recover_colon_colon_in_pat_typo(first_pat, ra, expected);
+ if ra == RecoverColon::Yes {
+ first_pat = self.maybe_recover_colon_colon_in_pat_typo(first_pat, expected);
+ }
if let Some(leading_vert_span) = leading_vert_span {
// If there was a leading vert, treat this as an or-pattern. This improves
err.span_label(lo, WHILE_PARSING_OR_MSG);
err
})?;
- self.maybe_recover_unexpected_comma(pat.span, rc, rt)?;
+ if rc == RecoverComma::Yes {
+ self.maybe_recover_unexpected_comma(pat.span, rt)?;
+ }
pats.push(pat);
}
let or_pattern_span = lo.to(self.prev_token.span);
};
let pat = self.mk_pat(lo.to(self.prev_token.span), pat);
- let pat = self.maybe_recover_from_bad_qpath(pat, true)?;
+ let pat = self.maybe_recover_from_bad_qpath(pat)?;
let pat = self.recover_intersection_pat(pat)?;
if !allow_range_pat {
} else {
// Since none of the above applied, this is an expression statement macro.
let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac), AttrVec::new());
- let e = self.maybe_recover_from_bad_qpath(e, true)?;
+ let e = self.maybe_recover_from_bad_qpath(e)?;
let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?;
let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?;
StmtKind::Expr(e)
};
let span = lo.to(self.prev_token.span);
- let ty = self.mk_ty(span, kind);
+ let mut ty = self.mk_ty(span, kind);
// Try to recover from use of `+` with incorrect priority.
- self.maybe_report_ambiguous_plus(allow_plus, impl_dyn_multi, &ty);
- self.maybe_recover_from_bad_type_plus(allow_plus, &ty)?;
- let ty = self.maybe_recover_from_question_mark(ty, recover_question_mark);
- self.maybe_recover_from_bad_qpath(ty, allow_qpath_recovery)
+ if matches!(allow_plus, AllowPlus::Yes) {
+ self.maybe_recover_from_bad_type_plus(&ty)?;
+ } else {
+ self.maybe_report_ambiguous_plus(impl_dyn_multi, &ty);
+ }
+ if let RecoverQuestionMark::Yes = recover_question_mark {
+ ty = self.maybe_recover_from_question_mark(ty);
+ }
+ if allow_qpath_recovery { self.maybe_recover_from_bad_qpath(ty) } else { Ok(ty) }
}
/// Parses either:
traits_str,
is_are
);
- let multispan = ign_traits
- .iter()
- .map(|(_, impl_id)| self.tcx.def_span(*impl_id))
- .collect::<Vec<_>>();
- err.span_note(multispan, &msg);
+ err.note(&msg);
}
err.emit();
});
hir::TraitItemKind::Fn(_, hir::TraitFn::Required(_))
| hir::TraitItemKind::Type(..) => false,
},
- Some(Node::ImplItem(impl_item)) => {
- match impl_item.kind {
- hir::ImplItemKind::Const(..) => true,
- hir::ImplItemKind::Fn(..) => {
- let attrs = self.tcx.codegen_fn_attrs(def_id);
- let generics = self.tcx.generics_of(def_id);
- if generics.requires_monomorphization(self.tcx) || attrs.requests_inline() {
- true
- } else {
- let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
- let impl_did = self.tcx.hir().get_parent_item(hir_id);
- // Check the impl. If the generics on the self
- // type of the impl require inlining, this method
- // does too.
- match self.tcx.hir().expect_item(impl_did).kind {
- hir::ItemKind::Impl { .. } => {
- let generics = self.tcx.generics_of(impl_did);
- generics.requires_monomorphization(self.tcx)
- }
- _ => false,
- }
- }
- }
- hir::ImplItemKind::TyAlias(_) => false,
+ Some(Node::ImplItem(impl_item)) => match impl_item.kind {
+ hir::ImplItemKind::Const(..) => true,
+ hir::ImplItemKind::Fn(..) => {
+ let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
+ let impl_did = self.tcx.hir().get_parent_item(hir_id);
+ method_might_be_inlined(self.tcx, impl_item, impl_did)
}
- }
+ hir::ImplItemKind::TyAlias(_) => false,
+ },
Some(_) => false,
None => false, // This will happen for default methods.
}
let len = BytePos::decode(decoder);
let file_lo = decoder.file_index_to_file(file_lo_index);
- let lo = file_lo.lines[line_lo - 1] + col_lo;
+ let lo = file_lo.lines(|lines| lines[line_lo - 1] + col_lo);
let hi = lo + len;
Span::new(lo, hi, ctxt, parent)
{
type Error = E::Error;
- #[inline]
- fn emit_unit(&mut self) -> Result<(), Self::Error> {
- Ok(())
- }
-
encoder_methods! {
emit_usize(usize);
emit_u128(u128);
external_src: _,
start_pos,
end_pos: _,
- ref lines,
+ lines: _,
ref multibyte_chars,
ref non_narrow_chars,
ref normalized_pos,
src_hash.hash_stable(hcx, hasher);
- // We only hash the relative position within this source_file
- lines.len().hash_stable(hcx, hasher);
- for &line in lines.iter() {
- stable_byte_pos(line, start_pos).hash_stable(hcx, hasher);
- }
+ // We are always in `Lines` form by the time we reach here.
+ assert!(self.lines.borrow().is_lines());
+ self.lines(|lines| {
+ // We only hash the relative position within this source_file
+ lines.len().hash_stable(hcx, hasher);
+ for &line in lines.iter() {
+ stable_byte_pos(line, start_pos).hash_stable(hcx, hasher);
+ }
+ });
// We only hash the relative position within this source_file
multibyte_chars.len().hash_stable(hcx, hasher);
)),
)
} else if self.session.edition() == Edition::Edition2015 {
- (format!("maybe a missing crate `{}`?", ident), None)
+ (
+ format!("maybe a missing crate `{ident}`?"),
+ Some((
+ vec![],
+ format!(
+ "consider adding `extern crate {ident}` to use the `{ident}` crate"
+ ),
+ Applicability::MaybeIncorrect,
+ )),
+ )
} else {
- (format!("could not find `{}` in the crate root", ident), None)
+ (format!("could not find `{ident}` in the crate root"), None)
}
} else if i > 0 {
let parent = path[i - 1].ident.name;
"the list of imported crates".to_owned()
}
kw::PathRoot | kw::Crate => "the crate root".to_owned(),
- _ => format!("`{}`", parent),
+ _ => format!("`{parent}`"),
};
let mut msg = format!("could not find `{}` in {}", ident, parent);
}
if let Some((suggestions, msg, applicability)) = err.suggestion {
+ if suggestions.is_empty() {
+ diag.help(&msg);
+ continue;
+ }
diag.multipart_suggestion(&msg, suggestions, applicability);
}
}
AssocItemRibKind | ItemRibKind(_) | ForwardGenericParamBanRibKind => true,
}
}
+
+ /// This rib forbids referring to labels defined in upwards ribs.
+ fn is_label_barrier(self) -> bool {
+ match self {
+ NormalRibKind | MacroDefinition(..) => false,
+
+ AssocItemRibKind
+ | ClosureOrAsyncRibKind
+ | FnItemRibKind
+ | ItemRibKind(..)
+ | ConstantItemRibKind(..)
+ | ModuleRibKind(..)
+ | ForwardGenericParamBanRibKind
+ | ConstParamTyRibKind
+ | InlineAsmSymRibKind => true,
+ }
+ }
}
/// A single local scope.
// Create a value rib for the function.
self.with_rib(ValueNS, rib_kind, |this| {
// Create a label rib for the function.
- this.with_label_rib(rib_kind, |this| {
+ this.with_label_rib(FnItemRibKind, |this| {
let async_node_id = fn_kind.header().and_then(|h| h.asyncness.opt_return_id());
if let FnKind::Fn(_, _, _, _, generics, _) = fn_kind {
/// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved
/// label and reports an error if the label is not found or is unreachable.
- fn resolve_label(&mut self, mut label: Ident) -> Option<NodeId> {
+ fn resolve_label(&mut self, mut label: Ident) -> Result<(NodeId, Span), ResolutionError<'a>> {
let mut suggestion = None;
- // Preserve the original span so that errors contain "in this macro invocation"
- // information.
- let original_span = label.span;
-
for i in (0..self.label_ribs.len()).rev() {
let rib = &self.label_ribs[i];
if let Some((ident, id)) = rib.bindings.get_key_value(&ident) {
let definition_span = ident.span;
return if self.is_label_valid_from_rib(i) {
- Some(*id)
+ Ok((*id, definition_span))
} else {
- self.report_error(
- original_span,
- ResolutionError::UnreachableLabel {
- name: label.name,
- definition_span,
- suggestion,
- },
- );
-
- None
+ Err(ResolutionError::UnreachableLabel {
+ name: label.name,
+ definition_span,
+ suggestion,
+ })
};
}
suggestion = suggestion.or_else(|| self.suggestion_for_label_in_rib(i, label));
}
- self.report_error(
- original_span,
- ResolutionError::UndeclaredLabel { name: label.name, suggestion },
- );
- None
+ Err(ResolutionError::UndeclaredLabel { name: label.name, suggestion })
}
/// Determine whether or not a label from the `rib_index`th label rib is reachable.
let ribs = &self.label_ribs[rib_index + 1..];
for rib in ribs {
- match rib.kind {
- NormalRibKind | MacroDefinition(..) => {
- // Nothing to do. Continue.
- }
-
- AssocItemRibKind
- | ClosureOrAsyncRibKind
- | FnItemRibKind
- | ItemRibKind(..)
- | ConstantItemRibKind(..)
- | ModuleRibKind(..)
- | ForwardGenericParamBanRibKind
- | ConstParamTyRibKind
- | InlineAsmSymRibKind => {
- return false;
- }
+ if rib.kind.is_label_barrier() {
+ return false;
}
}
let mut function_value_rib = Rib::new(kind);
let mut function_lifetime_rib = LifetimeRib::new(lifetime_kind);
let mut seen_bindings = FxHashMap::default();
+ // Store all seen lifetimes names from outer scopes.
+ let mut seen_lifetimes = FxHashSet::default();
// We also can't shadow bindings from the parent item
if let AssocItemRibKind = kind {
add_bindings_for_ns(TypeNS);
}
+ // Forbid shadowing lifetime bindings
+ for rib in self.lifetime_ribs.iter().rev() {
+ seen_lifetimes.extend(rib.bindings.iter().map(|(ident, _)| *ident));
+ if let LifetimeRibKind::Item = rib.kind {
+ break;
+ }
+ }
+
for param in params {
let ident = param.ident.normalize_to_macros_2_0();
debug!("with_generic_param_rib: {}", param.id);
+ if let GenericParamKind::Lifetime = param.kind
+ && let Some(&original) = seen_lifetimes.get(&ident)
+ {
+ diagnostics::signal_lifetime_shadowing(self.r.session, original, param.ident);
+ // Record lifetime res, so lowering knows there is something fishy.
+ self.record_lifetime_res(param.id, LifetimeRes::Error);
+ continue;
+ }
+
match seen_bindings.entry(ident) {
Entry::Occupied(entry) => {
let span = *entry.get();
let err = ResolutionError::NameAlreadyUsedInParameterList(ident.name, span);
- if !matches!(param.kind, GenericParamKind::Lifetime) {
- self.report_error(param.ident.span, err);
+ self.report_error(param.ident.span, err);
+ if let GenericParamKind::Lifetime = param.kind {
+ // Record lifetime res, so lowering knows there is something fishy.
+ self.record_lifetime_res(param.id, LifetimeRes::Error);
+ continue;
}
}
Entry::Vacant(entry) => {
)
.span_label(param.ident.span, "`'_` is a reserved lifetime name")
.emit();
+ // Record lifetime res, so lowering knows there is something fishy.
+ self.record_lifetime_res(param.id, LifetimeRes::Error);
continue;
}
)
.span_label(param.ident.span, "'static is a reserved lifetime name")
.emit();
+ // Record lifetime res, so lowering knows there is something fishy.
+ self.record_lifetime_res(param.id, LifetimeRes::Error);
continue;
}
if label.ident.as_str().as_bytes()[1] != b'_' {
self.diagnostic_metadata.unused_labels.insert(id, label.ident.span);
}
+
+ if let Ok((_, orig_span)) = self.resolve_label(label.ident) {
+ diagnostics::signal_label_shadowing(self.r.session, orig_span, label.ident)
+ }
+
self.with_label_rib(NormalRibKind, |this| {
let ident = label.ident.normalize_to_macro_rules();
this.label_ribs.last_mut().unwrap().bindings.insert(ident, id);
}
ExprKind::Break(Some(label), _) | ExprKind::Continue(Some(label)) => {
- if let Some(node_id) = self.resolve_label(label.ident) {
- // Since this res is a label, it is never read.
- self.r.label_res_map.insert(expr.id, node_id);
- self.diagnostic_metadata.unused_labels.remove(&node_id);
+ match self.resolve_label(label.ident) {
+ Ok((node_id, _)) => {
+ // Since this res is a label, it is never read.
+ self.r.label_res_map.insert(expr.id, node_id);
+ self.diagnostic_metadata.unused_labels.remove(&node_id);
+ }
+ Err(error) => {
+ self.report_error(label.ident.span, error);
+ }
}
// visit `break` argument if any
};
use rustc_ast_lowering::ResolverAstLowering;
use rustc_ast_pretty::pprust::path_segment_to_string;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_errors::{
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
MultiSpan,
use rustc_hir as hir;
use rustc_hir::def::Namespace::{self, *};
use rustc_hir::def::{self, CtorKind, CtorOf, DefKind};
-use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_hir::PrimTy;
use rustc_session::lint;
use rustc_session::parse::feature_err;
+use rustc_session::Session;
use rustc_span::edition::Edition;
use rustc_span::hygiene::MacroKind;
use rustc_span::lev_distance::find_best_match_for_name;
}
}
+/// Report lifetime/lifetime shadowing as an error.
+pub fn signal_lifetime_shadowing(sess: &Session, orig: Ident, shadower: Ident) {
+ let mut err = struct_span_err!(
+ sess,
+ shadower.span,
+ E0496,
+ "lifetime name `{}` shadows a lifetime name that is already in scope",
+ orig.name,
+ );
+ err.span_label(orig.span, "first declared here");
+ err.span_label(shadower.span, format!("lifetime `{}` already in scope", orig.name));
+ err.emit();
+}
+
+/// Shadowing involving a label is only a warning for historical reasons.
+//FIXME: make this a proper lint.
+pub fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident) {
+ let name = shadower.name;
+ let shadower = shadower.span;
+ let mut err = sess.struct_span_warn(
+ shadower,
+ &format!("label name `{}` shadows a label name that is already in scope", name),
+ );
+ err.span_label(orig, "first declared here");
+ err.span_label(shadower, format!("label `{}` already in scope", name));
+ err.emit();
+}
+
impl<'tcx> LifetimeContext<'_, 'tcx> {
pub(crate) fn report_missing_lifetime_specifiers(
&self,
/// Returns whether to add `'static` lifetime to the suggested lifetime list.
pub(crate) fn report_elision_failure(
- &mut self,
+ &self,
diag: &mut Diagnostic,
params: &[ElisionFailureInfo],
) -> bool {
&self,
err: &mut Diagnostic,
mut spans_with_counts: Vec<(Span, usize)>,
- lifetime_names: &FxHashSet<Symbol>,
- lifetime_spans: Vec<Span>,
- params: &[ElisionFailureInfo],
+ in_scope_lifetimes: FxIndexSet<LocalDefId>,
+ params: Option<&[ElisionFailureInfo]>,
) {
+ let (mut lifetime_names, lifetime_spans): (FxHashSet<_>, Vec<_>) = in_scope_lifetimes
+ .iter()
+ .filter_map(|def_id| {
+ let name = self.tcx.item_name(def_id.to_def_id());
+ let span = self.tcx.def_ident_span(def_id.to_def_id())?;
+ Some((name, span))
+ })
+ .filter(|&(n, _)| n != kw::UnderscoreLifetime)
+ .unzip();
+
+ if let Some(params) = params {
+ // If there's no lifetime available, suggest `'static`.
+ if self.report_elision_failure(err, params) && lifetime_names.is_empty() {
+ lifetime_names.insert(kw::StaticLifetime);
+ }
+ }
+ let params = params.unwrap_or(&[]);
+
let snippets: Vec<Option<String>> = spans_with_counts
.iter()
.map(|(span, _)| self.tcx.sess.source_map().span_to_snippet(*span).ok())
use crate::late::diagnostics::{ForLifetimeSpanType, MissingLifetimeSpot};
use rustc_ast::walk_list;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefIdMap, LocalDefId};
use rustc_hir::hir_id::ItemLocalId;
use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node, ParamName};
-use rustc_hir::{GenericParamKind, HirIdMap, HirIdSet};
+use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node};
+use rustc_hir::{GenericParamKind, HirIdMap};
use rustc_middle::hir::map::Map;
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::resolve_lifetime::*;
-use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, TyCtxt};
+use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_span::def_id::DefId;
-use rustc_span::symbol::{kw, sym, Ident, Symbol};
+use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Span;
use std::borrow::Cow;
use std::cell::Cell;
use tracing::{debug, span, Level};
trait RegionExt {
- fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (ParamName, Region);
+ fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (LocalDefId, Region);
- fn late(index: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region);
+ fn late(index: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region);
fn late_anon(named_late_bound_vars: u32, index: &Cell<u32>) -> Region;
}
impl RegionExt for Region {
- fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (ParamName, Region) {
+ fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (LocalDefId, Region) {
let i = *index;
*index += 1;
let def_id = hir_map.local_def_id(param.hir_id);
debug!("Region::early: index={} def_id={:?}", i, def_id);
- (param.name.normalize_to_macros_2_0(), Region::EarlyBound(i, def_id.to_def_id()))
+ (def_id, Region::EarlyBound(i, def_id.to_def_id()))
}
- fn late(idx: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region) {
+ fn late(idx: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region) {
let depth = ty::INNERMOST;
let def_id = hir_map.local_def_id(param.hir_id);
debug!(
"Region::late: idx={:?}, param={:?} depth={:?} def_id={:?}",
idx, param, depth, def_id,
);
- (param.name.normalize_to_macros_2_0(), Region::LateBound(depth, idx, def_id.to_def_id()))
+ (def_id, Region::LateBound(depth, idx, def_id.to_def_id()))
}
fn late_anon(named_late_bound_vars: u32, index: &Cell<u32>) -> Region {
// `Region` describing how that region is bound
defs: HirIdMap<Region>,
- // the set of lifetime def ids that are late-bound; a region can
- // be late-bound if (a) it does NOT appear in a where-clause and
- // (b) it DOES appear in the arguments.
- late_bound: HirIdSet,
-
// Maps relevant hir items to the bound vars on them. These include:
// - function defs
// - function pointers
/// we eventually need lifetimes resolve for trait items.
trait_definition_only: bool,
- /// List of labels in the function/method currently under analysis.
- labels_in_fn: Vec<Ident>,
-
/// Cache for cross-crate per-definition object lifetime defaults.
xcrate_object_lifetime_defaults: DefIdMap<Vec<ObjectLifetimeDefault>>,
Binder {
/// We use an IndexMap here because we want these lifetimes in order
/// for diagnostics.
- lifetimes: FxIndexMap<hir::ParamName, Region>,
+ lifetimes: FxIndexMap<LocalDefId, Region>,
/// if we extend this scope with another scope, what is the next index
/// we should use for an early-bound region?
tcx: TyCtxt<'_>,
local_def_id: LocalDefId,
) -> ResolveLifetimes {
- convert_named_region_map(tcx, do_resolve(tcx, local_def_id, true, false))
+ convert_named_region_map(do_resolve(tcx, local_def_id, true, false))
}
/// Computes the `ResolveLifetimes` map that contains data for an entire `Item`.
/// `named_region_map`, `is_late_bound_map`, etc.
#[tracing::instrument(level = "debug", skip(tcx))]
fn resolve_lifetimes(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> ResolveLifetimes {
- convert_named_region_map(tcx, do_resolve(tcx, local_def_id, false, false))
+ convert_named_region_map(do_resolve(tcx, local_def_id, false, false))
}
fn do_resolve(
let item = tcx.hir().expect_item(local_def_id);
let mut named_region_map = NamedRegionMap {
defs: Default::default(),
- late_bound: Default::default(),
late_bound_vars: Default::default(),
scope_for_path: with_scope_for_path.then(|| Default::default()),
};
map: &mut named_region_map,
scope: ROOT_SCOPE,
trait_definition_only,
- labels_in_fn: vec![],
xcrate_object_lifetime_defaults: Default::default(),
missing_named_lifetime_spots: vec![],
};
named_region_map
}
-fn convert_named_region_map(tcx: TyCtxt<'_>, named_region_map: NamedRegionMap) -> ResolveLifetimes {
+fn convert_named_region_map(named_region_map: NamedRegionMap) -> ResolveLifetimes {
let mut rl = ResolveLifetimes::default();
for (hir_id, v) in named_region_map.defs {
let map = rl.defs.entry(hir_id.owner).or_default();
map.insert(hir_id.local_id, v);
}
- for hir_id in named_region_map.late_bound {
- let map = rl.late_bound.entry(hir_id.owner).or_default();
- let def_id = tcx.hir().local_def_id(hir_id);
- map.insert(def_id);
- }
for (hir_id, v) in named_region_map.late_bound_vars {
let map = rl.late_bound_vars.entry(hir_id.owner).or_default();
map.insert(hir_id.local_id, v);
item
}
-fn is_late_bound_map<'tcx>(
- tcx: TyCtxt<'tcx>,
- def_id: LocalDefId,
-) -> Option<(LocalDefId, &'tcx FxHashSet<LocalDefId>)> {
- match tcx.def_kind(def_id) {
- DefKind::AnonConst | DefKind::InlineConst => {
- let mut def_id = tcx.local_parent(def_id);
- // We search for the next outer anon const or fn here
- // while skipping closures.
- //
- // Note that for `AnonConst` we still just recurse until we
- // find a function body, but who cares :shrug:
- while tcx.is_closure(def_id.to_def_id()) {
- def_id = tcx.local_parent(def_id);
- }
-
- tcx.is_late_bound_map(def_id)
- }
- _ => resolve_lifetimes_for(tcx, def_id).late_bound.get(&def_id).map(|lt| (def_id, lt)),
- }
-}
-
/// In traits, there is an implicit `Self` type parameter which comes before the generics.
/// We have to account for this when computing the index of the other generic parameters.
/// This function returns whether there is such an implicit parameter defined on the given item.
loop {
match scope {
Scope::Binder { lifetimes, s, .. } => {
- available_lifetimes.extend(lifetimes.keys().filter_map(|p| match p {
- hir::ParamName::Plain(ident) => Some(ident.name),
- _ => None,
- }));
+ available_lifetimes.extend(lifetimes.keys());
scope = s;
}
Scope::Body { s, .. } => {
}
fn visit_nested_body(&mut self, body: hir::BodyId) {
- // Each body has their own set of labels, save labels.
- let saved = take(&mut self.labels_in_fn);
let body = self.tcx.hir().body(body);
- extract_labels(self, body);
- self.with(Scope::Body { id: body.id(), s: self.scope }, |_, this| {
+ self.with(Scope::Body { id: body.id(), s: self.scope }, |this| {
this.visit_body(body);
});
- self.labels_in_fn = saved;
}
fn visit_fn(
scope_type: BinderScopeType::Normal,
allow_late_bound: true,
};
- self.with(scope, move |_old_scope, this| {
- intravisit::walk_fn(this, fk, fd, b, s, hir_id)
- });
+ self.with(scope, move |this| intravisit::walk_fn(this, fk, fd, b, s, hir_id));
}
}
}
_ => {}
}
match item.kind {
- hir::ItemKind::Fn(ref sig, ref generics, _) => {
+ hir::ItemKind::Fn(_, ref generics, _) => {
self.missing_named_lifetime_spots.push(generics.into());
- self.visit_early_late(None, item.hir_id(), &sig.decl, generics, |this| {
+ self.visit_early_late(None, item.hir_id(), generics, |this| {
intravisit::walk_item(this, item);
});
self.missing_named_lifetime_spots.pop();
hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => {
// No lifetime parameters, but implied 'static.
let scope = Scope::Elision { elide: Elide::Exact(Region::Static), s: ROOT_SCOPE };
- self.with(scope, |_, this| intravisit::walk_item(this, item));
+ self.with(scope, |this| intravisit::walk_item(this, item));
}
hir::ItemKind::OpaqueTy(hir::OpaqueTy { .. }) => {
// Opaque types are visited when we visit the
self.map.defs.insert(hir::HirId { owner, local_id }, *region);
});
}
- for (&owner, late_bound) in resolved_lifetimes.late_bound.iter() {
- late_bound.iter().for_each(|&id| {
- let hir_id = self.tcx.local_def_id_to_hir_id(id);
- debug_assert_eq!(owner, hir_id.owner);
- self.map.late_bound.insert(hir_id);
- });
- }
for (&owner, late_bound_vars) in
resolved_lifetimes.late_bound_vars.iter()
{
s: ROOT_SCOPE,
allow_late_bound: false,
};
- self.with(scope, |old_scope, this| {
- this.check_lifetime_params(old_scope, &generics.params);
+ self.with(scope, |this| {
let scope = Scope::TraitRefBoundary { s: this.scope };
- this.with(scope, |_, this| {
+ this.with(scope, |this| {
intravisit::walk_item(this, item);
});
});
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
match item.kind {
- hir::ForeignItemKind::Fn(ref decl, _, ref generics) => {
- self.visit_early_late(None, item.hir_id(), decl, generics, |this| {
+ hir::ForeignItemKind::Fn(_, _, ref generics) => {
+ self.visit_early_late(None, item.hir_id(), generics, |this| {
intravisit::walk_foreign_item(this, item);
})
}
};
self.missing_named_lifetime_spots
.push(MissingLifetimeSpot::HigherRanked { span, span_type });
- let (lifetimes, binders): (FxIndexMap<hir::ParamName, Region>, Vec<_>) = c
+ let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) = c
.generic_params
.iter()
.filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. }))
scope_type: BinderScopeType::Normal,
allow_late_bound: true,
};
- self.with(scope, |old_scope, this| {
+ self.with(scope, |this| {
// a bare fn has no bounds, so everything
// contained within is scoped within its binder.
- this.check_lifetime_params(old_scope, &c.generic_params);
intravisit::walk_ty(this, ty);
});
self.missing_named_lifetime_spots.pop();
hir::TyKind::TraitObject(bounds, ref lifetime, _) => {
debug!(?bounds, ?lifetime, "TraitObject");
let scope = Scope::TraitRefBoundary { s: self.scope };
- self.with(scope, |_, this| {
+ self.with(scope, |this| {
for bound in bounds {
this.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None);
}
// cc #48468
self.resolve_elided_lifetimes(&[lifetime])
}
- LifetimeName::Param(_) | LifetimeName::Static => {
+ LifetimeName::Param(..) | LifetimeName::Static => {
// If the user wrote an explicit name, use that.
self.visit_lifetime(lifetime);
}
lifetime: self.map.defs.get(&lifetime_ref.hir_id).cloned(),
s: self.scope,
};
- self.with(scope, |_, this| this.visit_ty(&mt.ty));
+ self.with(scope, |this| this.visit_ty(&mt.ty));
}
hir::TyKind::OpaqueDef(item_id, lifetimes) => {
// Resolve the lifetimes in the bounds to the lifetime defs in the generics.
// Elided lifetimes are not allowed in non-return
// position impl Trait
let scope = Scope::TraitRefBoundary { s: self.scope };
- self.with(scope, |_, this| {
+ self.with(scope, |this| {
let scope = Scope::Elision { elide: Elide::Forbid, s: this.scope };
- this.with(scope, |_, this| {
+ this.with(scope, |this| {
intravisit::walk_item(this, opaque_ty);
})
});
for param in generics.params {
match param.kind {
GenericParamKind::Lifetime { .. } => {
- let (name, reg) = Region::early(self.tcx.hir(), &mut index, ¶m);
+ let (def_id, reg) = Region::early(self.tcx.hir(), &mut index, ¶m);
if let hir::ParamName::Plain(Ident {
name: kw::UnderscoreLifetime,
..
- }) = name
+ }) = param.name
{
// Pick the elided lifetime "definition" if one exists
// and use it to make an elision scope.
elision = Some(reg);
} else {
- lifetimes.insert(name, reg);
+ lifetimes.insert(def_id, reg);
}
}
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
if let Some(elision_region) = elision {
let scope =
Scope::Elision { elide: Elide::Exact(elision_region), s: self.scope };
- self.with(scope, |_old_scope, this| {
+ self.with(scope, |this| {
let scope = Scope::Binder {
hir_id: ty.hir_id,
lifetimes,
scope_type: BinderScopeType::Normal,
allow_late_bound: false,
};
- this.with(scope, |_old_scope, this| {
+ this.with(scope, |this| {
this.visit_generics(generics);
let scope = Scope::TraitRefBoundary { s: this.scope };
- this.with(scope, |_, this| {
+ this.with(scope, |this| {
for bound in bounds {
this.visit_param_bound(bound);
}
scope_type: BinderScopeType::Normal,
allow_late_bound: false,
};
- self.with(scope, |_old_scope, this| {
+ self.with(scope, |this| {
let scope = Scope::TraitRefBoundary { s: this.scope };
- this.with(scope, |_, this| {
+ this.with(scope, |this| {
this.visit_generics(generics);
for bound in bounds {
this.visit_param_bound(bound);
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
use self::hir::TraitItemKind::*;
match trait_item.kind {
- Fn(ref sig, _) => {
+ Fn(_, _) => {
self.missing_named_lifetime_spots.push((&trait_item.generics).into());
let tcx = self.tcx;
self.visit_early_late(
Some(tcx.hir().get_parent_item(trait_item.hir_id())),
trait_item.hir_id(),
- &sig.decl,
&trait_item.generics,
|this| intravisit::walk_trait_item(this, trait_item),
);
scope_type: BinderScopeType::Normal,
allow_late_bound: false,
};
- self.with(scope, |old_scope, this| {
- this.check_lifetime_params(old_scope, &generics.params);
+ self.with(scope, |this| {
let scope = Scope::TraitRefBoundary { s: this.scope };
- this.with(scope, |_, this| {
+ this.with(scope, |this| {
this.visit_generics(generics);
for bound in bounds {
this.visit_param_bound(bound);
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
use self::hir::ImplItemKind::*;
match impl_item.kind {
- Fn(ref sig, _) => {
+ Fn(..) => {
self.missing_named_lifetime_spots.push((&impl_item.generics).into());
let tcx = self.tcx;
self.visit_early_late(
Some(tcx.hir().get_parent_item(impl_item.hir_id())),
impl_item.hir_id(),
- &sig.decl,
&impl_item.generics,
|this| intravisit::walk_impl_item(this, impl_item),
);
let mut index = self.next_early_index();
let mut non_lifetime_count = 0;
debug!("visit_ty: index = {}", index);
- let lifetimes: FxIndexMap<hir::ParamName, Region> = generics
+ let lifetimes: FxIndexMap<LocalDefId, Region> = generics
.params
.iter()
.filter_map(|param| match param.kind {
scope_type: BinderScopeType::Normal,
allow_late_bound: true,
};
- self.with(scope, |old_scope, this| {
- this.check_lifetime_params(old_scope, &generics.params);
+ self.with(scope, |this| {
let scope = Scope::TraitRefBoundary { s: this.scope };
- this.with(scope, |_, this| {
+ this.with(scope, |this| {
this.visit_generics(generics);
this.visit_ty(ty);
})
#[tracing::instrument(level = "debug", skip(self))]
fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
- if lifetime_ref.is_elided() {
- self.resolve_elided_lifetimes(&[lifetime_ref]);
- return;
- }
- if lifetime_ref.is_static() {
- self.insert_lifetime(lifetime_ref, Region::Static);
- return;
+ match lifetime_ref.name {
+ hir::LifetimeName::ImplicitObjectLifetimeDefault
+ | hir::LifetimeName::Implicit
+ | hir::LifetimeName::Underscore => self.resolve_elided_lifetimes(&[lifetime_ref]),
+ hir::LifetimeName::Static => self.insert_lifetime(lifetime_ref, Region::Static),
+ hir::LifetimeName::Param(param_def_id, _) => {
+ self.resolve_lifetime_ref(param_def_id, lifetime_ref)
+ }
+ // If we've already reported an error, just ignore `lifetime_ref`.
+ hir::LifetimeName::Error => {}
}
- self.resolve_lifetime_ref(lifetime_ref);
}
fn visit_assoc_type_binding(&mut self, type_binding: &'tcx hir::TypeBinding<'_>) {
fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
let scope = Scope::TraitRefBoundary { s: self.scope };
- self.with(scope, |_, this| {
+ self.with(scope, |this| {
for param in generics.params {
match param.kind {
GenericParamKind::Lifetime { .. } => {}
ref bound_generic_params,
..
}) => {
- let (lifetimes, binders): (FxIndexMap<hir::ParamName, Region>, Vec<_>) =
+ let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) =
bound_generic_params
.iter()
.filter(|param| {
scope_type: BinderScopeType::Normal,
allow_late_bound: true,
};
- this.with(scope, |old_scope, this| {
- this.check_lifetime_params(old_scope, &bound_generic_params);
+ this.with(scope, |this| {
this.visit_ty(&bounded_ty);
walk_list!(this, visit_param_bound, bounds);
})
scope_type,
allow_late_bound: true,
};
- self.with(scope, |_, this| {
+ self.with(scope, |this| {
intravisit::walk_param_bound(this, bound);
});
}
let (mut binders, scope_type) = self.poly_trait_ref_binder_info();
let initial_bound_vars = binders.len() as u32;
- let mut lifetimes: FxIndexMap<hir::ParamName, Region> = FxIndexMap::default();
+ let mut lifetimes: FxIndexMap<LocalDefId, Region> = FxIndexMap::default();
let binders_iter = trait_ref
.bound_generic_params
.iter()
scope_type,
allow_late_bound: true,
};
- self.with(scope, |old_scope, this| {
- this.check_lifetime_params(old_scope, &trait_ref.bound_generic_params);
+ self.with(scope, |this| {
walk_list!(this, visit_generic_param, trait_ref.bound_generic_params);
this.visit_trait_ref(&trait_ref.trait_ref);
});
}
}
-#[derive(Copy, Clone, PartialEq)]
-enum ShadowKind {
- Label,
- Lifetime,
-}
-struct Original {
- kind: ShadowKind,
- span: Span,
-}
-struct Shadower {
- kind: ShadowKind,
- span: Span,
-}
-
-fn original_label(span: Span) -> Original {
- Original { kind: ShadowKind::Label, span }
-}
-fn shadower_label(span: Span) -> Shadower {
- Shadower { kind: ShadowKind::Label, span }
-}
-fn original_lifetime(span: Span) -> Original {
- Original { kind: ShadowKind::Lifetime, span }
-}
-fn shadower_lifetime(param: &hir::GenericParam<'_>) -> Shadower {
- Shadower { kind: ShadowKind::Lifetime, span: param.span }
-}
-
-impl ShadowKind {
- fn desc(&self) -> &'static str {
- match *self {
- ShadowKind::Label => "label",
- ShadowKind::Lifetime => "lifetime",
- }
- }
-}
-
-fn signal_shadowing_problem(tcx: TyCtxt<'_>, name: Symbol, orig: Original, shadower: Shadower) {
- let mut err = if let (ShadowKind::Lifetime, ShadowKind::Lifetime) = (orig.kind, shadower.kind) {
- // lifetime/lifetime shadowing is an error
- struct_span_err!(
- tcx.sess,
- shadower.span,
- E0496,
- "{} name `{}` shadows a \
- {} name that is already in scope",
- shadower.kind.desc(),
- name,
- orig.kind.desc()
- )
- .forget_guarantee()
- } else {
- // shadowing involving a label is only a warning, due to issues with
- // labels and lifetimes not being macro-hygienic.
- tcx.sess.struct_span_warn(
- shadower.span,
- &format!(
- "{} name `{}` shadows a \
- {} name that is already in scope",
- shadower.kind.desc(),
- name,
- orig.kind.desc()
- ),
- )
- };
- err.span_label(orig.span, "first declared here");
- err.span_label(shadower.span, format!("{} `{}` already in scope", orig.kind.desc(), name));
- err.emit();
-}
-
-// Adds all labels in `b` to `ctxt.labels_in_fn`, signalling a warning
-// if one of the label shadows a lifetime or another label.
-fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body<'_>) {
- struct GatherLabels<'a, 'tcx> {
- tcx: TyCtxt<'tcx>,
- scope: ScopeRef<'a>,
- labels_in_fn: &'a mut Vec<Ident>,
- }
-
- let mut gather =
- GatherLabels { tcx: ctxt.tcx, scope: ctxt.scope, labels_in_fn: &mut ctxt.labels_in_fn };
- gather.visit_body(body);
-
- impl<'v, 'a, 'tcx> Visitor<'v> for GatherLabels<'a, 'tcx> {
- fn visit_expr(&mut self, ex: &hir::Expr<'_>) {
- if let Some(label) = expression_label(ex) {
- for prior_label in &self.labels_in_fn[..] {
- // FIXME (#24278): non-hygienic comparison
- if label.name == prior_label.name {
- signal_shadowing_problem(
- self.tcx,
- label.name,
- original_label(prior_label.span),
- shadower_label(label.span),
- );
- }
- }
-
- check_if_label_shadows_lifetime(self.tcx, self.scope, label);
-
- self.labels_in_fn.push(label);
- }
- intravisit::walk_expr(self, ex)
- }
- }
-
- fn expression_label(ex: &hir::Expr<'_>) -> Option<Ident> {
- match ex.kind {
- hir::ExprKind::Loop(_, Some(label), ..) => Some(label.ident),
- hir::ExprKind::Block(_, Some(label)) => Some(label.ident),
- _ => None,
- }
- }
-
- fn check_if_label_shadows_lifetime(tcx: TyCtxt<'_>, mut scope: ScopeRef<'_>, label: Ident) {
- loop {
- match *scope {
- Scope::Body { s, .. }
- | Scope::Elision { s, .. }
- | Scope::ObjectLifetimeDefault { s, .. }
- | Scope::Supertrait { s, .. }
- | Scope::TraitRefBoundary { s, .. } => {
- scope = s;
- }
-
- Scope::Root => {
- return;
- }
-
- Scope::Binder { ref lifetimes, s, .. } => {
- // FIXME (#24278): non-hygienic comparison
- if let Some(def) =
- lifetimes.get(&hir::ParamName::Plain(label.normalize_to_macros_2_0()))
- {
- signal_shadowing_problem(
- tcx,
- label.name,
- original_lifetime(tcx.def_span(def.id().unwrap().expect_local())),
- shadower_label(label.span),
- );
- return;
- }
- scope = s;
- }
- }
- }
- }
-}
-
fn compute_object_lifetime_defaults<'tcx>(
tcx: TyCtxt<'tcx>,
item: &hir::Item<'_>,
.iter()
.filter_map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => {
- Some((param.hir_id, hir::LifetimeName::Param(param.name)))
+ let param_def_id = tcx.hir().local_def_id(param.hir_id);
+ Some((
+ param_def_id,
+ hir::LifetimeName::Param(param_def_id, param.name),
+ ))
}
_ => None,
})
.enumerate()
.find(|&(_, (_, lt_name))| lt_name == name)
- .map_or(Set1::Many, |(i, (id, _))| {
- let def_id = tcx.hir().local_def_id(id);
+ .map_or(Set1::Many, |(i, (def_id, _))| {
Set1::One(Region::EarlyBound(i as u32, def_id.to_def_id()))
})
}
impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
fn with<F>(&mut self, wrap_scope: Scope<'_>, f: F)
where
- F: for<'b> FnOnce(ScopeRef<'_>, &mut LifetimeContext<'b, 'tcx>),
+ F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>),
{
let LifetimeContext { tcx, map, .. } = self;
- let labels_in_fn = take(&mut self.labels_in_fn);
let xcrate_object_lifetime_defaults = take(&mut self.xcrate_object_lifetime_defaults);
let missing_named_lifetime_spots = take(&mut self.missing_named_lifetime_spots);
let mut this = LifetimeContext {
map,
scope: &wrap_scope,
trait_definition_only: self.trait_definition_only,
- labels_in_fn,
xcrate_object_lifetime_defaults,
missing_named_lifetime_spots,
};
let span = tracing::debug_span!("scope", scope = ?TruncatedScopeDebug(&this.scope));
{
let _enter = span.enter();
- f(self.scope, &mut this);
+ f(&mut this);
}
- self.labels_in_fn = this.labels_in_fn;
self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults;
self.missing_named_lifetime_spots = this.missing_named_lifetime_spots;
}
&mut self,
parent_id: Option<LocalDefId>,
hir_id: hir::HirId,
- decl: &'tcx hir::FnDecl<'tcx>,
generics: &'tcx hir::Generics<'tcx>,
walk: F,
) where
F: for<'b, 'c> FnOnce(&'b mut LifetimeContext<'c, 'tcx>),
{
- insert_late_bound_lifetimes(self.map, decl, generics);
-
// Find the start of nested early scopes, e.g., in methods.
let mut next_early_index = 0;
if let Some(parent_id) = parent_id {
let mut non_lifetime_count = 0;
let mut named_late_bound_vars = 0;
- let lifetimes: FxIndexMap<hir::ParamName, Region> = generics
+ let lifetimes: FxIndexMap<LocalDefId, Region> = generics
.params
.iter()
.filter_map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => {
- if self.map.late_bound.contains(¶m.hir_id) {
+ if self.tcx.is_late_bound(param.hir_id) {
let late_bound_idx = named_late_bound_vars;
named_late_bound_vars += 1;
Some(Region::late(late_bound_idx, self.tcx.hir(), param))
.iter()
.filter(|param| {
matches!(param.kind, GenericParamKind::Lifetime { .. })
- && self.map.late_bound.contains(¶m.hir_id)
+ && self.tcx.is_late_bound(param.hir_id)
})
.enumerate()
.map(|(late_bound_idx, param)| {
scope_type: BinderScopeType::Normal,
allow_late_bound: true,
};
- self.with(scope, move |old_scope, this| {
- this.check_lifetime_params(old_scope, &generics.params);
- walk(this);
- });
+ self.with(scope, walk);
}
fn next_early_index_helper(&self, only_opaque_type_parent: bool) -> u32 {
self.next_early_index_helper(false)
}
- fn resolve_lifetime_ref(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
- debug!("resolve_lifetime_ref(lifetime_ref={:?})", lifetime_ref);
-
- // If we've already reported an error, just ignore `lifetime_ref`.
- if let LifetimeName::Error = lifetime_ref.name {
- return;
- }
-
+ #[tracing::instrument(level = "debug", skip(self))]
+ fn resolve_lifetime_ref(
+ &mut self,
+ region_def_id: LocalDefId,
+ lifetime_ref: &'tcx hir::Lifetime,
+ ) {
// Walk up the scope chain, tracking the number of fn scopes
// that we pass through, until we find a lifetime with the
// given name or we run out of scopes.
}
Scope::Binder { ref lifetimes, scope_type, s, .. } => {
- match lifetime_ref.name {
- LifetimeName::Param(param_name) => {
- if let Some(&def) = lifetimes.get(¶m_name.normalize_to_macros_2_0())
- {
- break Some(def.shifted(late_depth));
- }
- }
- _ => bug!("expected LifetimeName::Param"),
+ if let Some(&def) = lifetimes.get(®ion_def_id) {
+ break Some(def.shifted(late_depth));
}
match scope_type {
BinderScopeType::Normal => late_depth += 1,
GenericArg::Type(ty) => {
if let Some(<) = object_lifetime_defaults.get(i) {
let scope = Scope::ObjectLifetimeDefault { lifetime: lt, s: self.scope };
- self.with(scope, |_, this| this.visit_ty(ty));
+ self.with(scope, |this| this.visit_ty(ty));
} else {
self.visit_ty(ty);
}
type_def_id,
binding.ident,
);
- self.with(scope, |_, this| {
+ self.with(scope, |this| {
let scope = Scope::Supertrait {
lifetimes: lifetimes.unwrap_or_default(),
s: this.scope,
};
- this.with(scope, |_, this| this.visit_assoc_type_binding(binding));
+ this.with(scope, |this| this.visit_assoc_type_binding(binding));
});
} else {
- self.with(scope, |_, this| this.visit_assoc_type_binding(binding));
+ self.with(scope, |this| this.visit_assoc_type_binding(binding));
}
}
}
elide: Elide::FreshLateAnon(named_late_bound_vars, Cell::new(0)),
s: self.scope,
};
- self.with(arg_scope, |_, this| {
+ self.with(arg_scope, |this| {
for input in inputs {
this.visit_ty(input);
}
visitor.visit_ty(&inputs[0]);
if let Set1::One(lifetime) = visitor.lifetime {
let scope = Scope::Elision { elide: Elide::Exact(lifetime), s: self.scope };
- self.with(scope, |_, this| this.visit_ty(output));
+ self.with(scope, |this| this.visit_ty(output));
return;
}
}
debug!(?elide);
let scope = Scope::Elision { elide, s: self.scope };
- self.with(scope, |_, this| this.visit_ty(output));
+ self.with(scope, |this| this.visit_ty(output));
struct GatherLifetimes<'a> {
map: &'a NamedRegionMap,
let mut late_depth = 0;
let mut scope = self.scope;
- let mut lifetime_names = FxHashSet::default();
- let mut lifetime_spans = vec![];
+ let mut in_scope_lifetimes = FxIndexSet::default();
let error = loop {
match *scope {
// Do not assign any resolution, it will be inferred.
Scope::Binder { s, ref lifetimes, scope_type, .. } => {
// collect named lifetimes for suggestions
- for name in lifetimes.keys() {
- if let hir::ParamName::Plain(name) = name {
- lifetime_names.insert(name.name);
- lifetime_spans.push(name.span);
- }
- }
+ in_scope_lifetimes.extend(lifetimes.keys().copied());
match scope_type {
BinderScopeType::Normal => late_depth += 1,
BinderScopeType::Concatenating => {}
match scope {
Scope::Binder { ref lifetimes, s, .. } => {
// Collect named lifetimes for suggestions.
- for name in lifetimes.keys() {
- if let hir::ParamName::Plain(name) = name {
- lifetime_names.insert(name.name);
- lifetime_spans.push(name.span);
- }
- }
+ in_scope_lifetimes.extend(lifetimes.keys().copied());
scope = s;
}
Scope::ObjectLifetimeDefault { ref s, .. }
let mut err = self.report_missing_lifetime_specifiers(spans.clone(), lifetime_refs.len());
- if let Some(params) = error {
- // If there's no lifetime available, suggest `'static`.
- if self.report_elision_failure(&mut err, params) && lifetime_names.is_empty() {
- lifetime_names.insert(kw::StaticLifetime);
- }
- }
-
self.add_missing_lifetime_specifiers_label(
&mut err,
spans_with_counts,
- &lifetime_names,
- lifetime_spans,
- error.unwrap_or(&[]),
+ in_scope_lifetimes,
+ error,
);
err.emit();
}
self.insert_lifetime(lifetime_ref, lifetime.shifted(late_depth));
}
- fn check_lifetime_params(
- &mut self,
- old_scope: ScopeRef<'_>,
- params: &'tcx [hir::GenericParam<'tcx>],
- ) {
- let lifetimes: Vec<_> = params
- .iter()
- .filter_map(|param| match param.kind {
- GenericParamKind::Lifetime { .. } => {
- Some((param, param.name.normalize_to_macros_2_0()))
- }
- _ => None,
- })
- .collect();
- for (i, (lifetime_i, lifetime_i_name)) in lifetimes.iter().enumerate() {
- if let hir::ParamName::Plain(_) = lifetime_i_name {
- let name = lifetime_i_name.ident().name;
- if name == kw::UnderscoreLifetime || name == kw::StaticLifetime {
- self.tcx.sess.delay_span_bug(
- lifetime_i.span,
- &format!("invalid lifetime parameter name: `{}`", lifetime_i.name.ident()),
- );
- }
- }
-
- // It is a hard error to shadow a lifetime within the same scope.
- for (lifetime_j, lifetime_j_name) in lifetimes.iter().skip(i + 1) {
- if lifetime_i_name == lifetime_j_name {
- struct_span_err!(
- self.tcx.sess,
- lifetime_j.span,
- E0263,
- "lifetime name `{}` declared twice in the same scope",
- lifetime_j.name.ident()
- )
- .span_label(lifetime_j.span, "declared twice")
- .span_label(lifetime_i.span, "previous declaration here")
- .emit();
- }
- }
-
- // It is a soft error to shadow a lifetime within a parent scope.
- self.check_lifetime_param_for_shadowing(old_scope, &lifetime_i);
- }
- }
-
- fn check_lifetime_param_for_shadowing(
- &self,
- mut old_scope: ScopeRef<'_>,
- param: &'tcx hir::GenericParam<'tcx>,
- ) {
- for label in &self.labels_in_fn {
- // FIXME (#24278): non-hygienic comparison
- if param.name.ident().name == label.name {
- signal_shadowing_problem(
- self.tcx,
- label.name,
- original_label(label.span),
- shadower_lifetime(¶m),
- );
- return;
- }
- }
-
- loop {
- match *old_scope {
- Scope::Body { s, .. }
- | Scope::Elision { s, .. }
- | Scope::ObjectLifetimeDefault { s, .. }
- | Scope::Supertrait { s, .. }
- | Scope::TraitRefBoundary { s, .. } => {
- old_scope = s;
- }
-
- Scope::Root => {
- return;
- }
-
- Scope::Binder { ref lifetimes, s, .. } => {
- if let Some(&def) = lifetimes.get(¶m.name.normalize_to_macros_2_0()) {
- signal_shadowing_problem(
- self.tcx,
- param.name.ident().name,
- original_lifetime(self.tcx.def_span(def.id().unwrap())),
- shadower_lifetime(¶m),
- );
- return;
- }
-
- old_scope = s;
- }
- }
- }
- }
-
#[tracing::instrument(level = "debug", skip(self))]
fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) {
debug!(
}
/// Detects late-bound lifetimes and inserts them into
-/// `map.late_bound`.
+/// `late_bound`.
///
/// A region declared on a fn is **late-bound** if:
/// - it is constrained by an argument type;
/// "Constrained" basically means that it appears in any type but
/// not amongst the inputs to a projection. In other words, `<&'a
/// T as Trait<''b>>::Foo` does not constrain `'a` or `'b`.
-#[tracing::instrument(level = "debug", skip(map))]
-fn insert_late_bound_lifetimes(
- map: &mut NamedRegionMap,
- decl: &hir::FnDecl<'_>,
- generics: &hir::Generics<'_>,
-) {
+fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxHashSet<LocalDefId>> {
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+ let decl = tcx.hir().fn_decl_by_hir_id(hir_id)?;
+ let generics = tcx.hir().get_generics(def_id)?;
+
+ let mut late_bound = FxHashSet::default();
+
let mut constrained_by_input = ConstrainedCollector::default();
for arg_ty in decl.inputs {
constrained_by_input.visit_ty(arg_ty);
hir::GenericParamKind::Type { .. } | hir::GenericParamKind::Const { .. } => continue,
}
- let lt_name = hir::LifetimeName::Param(param.name.normalize_to_macros_2_0());
+ let param_def_id = tcx.hir().local_def_id(param.hir_id);
+
// appears in the where clauses? early-bound.
- if appears_in_where_clause.regions.contains(<_name) {
+ if appears_in_where_clause.regions.contains(¶m_def_id) {
continue;
}
// does not appear in the inputs, but appears in the return type? early-bound.
- if !constrained_by_input.regions.contains(<_name)
- && appears_in_output.regions.contains(<_name)
+ if !constrained_by_input.regions.contains(¶m_def_id)
+ && appears_in_output.regions.contains(¶m_def_id)
{
continue;
}
debug!("lifetime {:?} with id {:?} is late-bound", param.name.ident(), param.hir_id);
- let inserted = map.late_bound.insert(param.hir_id);
+ let inserted = late_bound.insert(param_def_id);
assert!(inserted, "visited lifetime {:?} twice", param.hir_id);
}
- return;
+ debug!(?late_bound);
+ return Some(tcx.arena.alloc(late_bound));
#[derive(Default)]
struct ConstrainedCollector {
- regions: FxHashSet<hir::LifetimeName>,
+ regions: FxHashSet<LocalDefId>,
}
impl<'v> Visitor<'v> for ConstrainedCollector {
}
fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) {
- self.regions.insert(lifetime_ref.name.normalize_to_macros_2_0());
+ if let hir::LifetimeName::Param(def_id, _) = lifetime_ref.name {
+ self.regions.insert(def_id);
+ }
}
}
#[derive(Default)]
struct AllCollector {
- regions: FxHashSet<hir::LifetimeName>,
+ regions: FxHashSet<LocalDefId>,
}
impl<'v> Visitor<'v> for AllCollector {
fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) {
- self.regions.insert(lifetime_ref.name.normalize_to_macros_2_0());
+ if let hir::LifetimeName::Param(def_id, _) = lifetime_ref.name {
+ self.regions.insert(def_id);
+ }
}
}
}
use rustc_ast::{self as ast, NodeId, CRATE_NODE_ID};
use rustc_ast::{AngleBracketedArg, Crate, Expr, ExprKind, GenericArg, GenericArgs, LitKind, Path};
use rustc_ast_lowering::{LifetimeRes, ResolverAstLowering};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
use rustc_data_structures::intern::Interned;
use rustc_data_structures::sync::Lrc;
use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed};
visibilities: FxHashMap<LocalDefId, ty::Visibility>,
has_pub_restricted: bool,
used_imports: FxHashSet<NodeId>,
- maybe_unused_trait_imports: FxHashSet<LocalDefId>,
+ maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
/// Privacy errors are delayed until the end in order to deduplicate them.
PathResult::NonModule(partial_res) if partial_res.unresolved_segments() == 0 => {
return Ok(true);
}
+ PathResult::NonModule(..) |
+ // HACK(Urgau): This shouldn't be necessary
+ PathResult::Failed { is_error_from_last_segment: false, .. } => {
+ self.session
+ .struct_span_err(span, "not sure whether the path is accessible or not")
+ .note("the type may have associated items, but we are currently not checking them")
+ .emit();
+
+ // If we get a partially resolved NonModule in one namespace, we should get the
+ // same result in any other namespaces, so we can return early.
+ return Ok(false);
+ }
PathResult::Indeterminate => indeterminate = true,
- // FIXME: `resolve_path` is not ready to report partially resolved paths
- // correctly, so we just report an error if the path was reported as unresolved.
- // This needs to be fixed for `cfg_accessible` to be useful.
- PathResult::NonModule(..) | PathResult::Failed { .. } => {}
+ // We can only be sure that a path doesn't exist after having tested all the
+ // posibilities, only at that time we can return false.
+ PathResult::Failed { .. } => {}
PathResult::Module(_) => panic!("unexpected path resolution"),
}
}
return Err(Indeterminate);
}
- self.session
- .struct_span_err(span, "not sure whether the path is accessible or not")
- .span_note(span, "`cfg_accessible` is not fully implemented")
- .emit();
Ok(false)
}
impl<S: Encoder, T: Encodable<S>> Encodable<S> for LinkedList<T> {
fn encode(&self, s: &mut S) -> Result<(), S::Error> {
- s.emit_seq(self.len(), |s| {
- for (i, e) in self.iter().enumerate() {
- s.emit_seq_elt(i, |s| e.encode(s))?;
- }
- Ok(())
- })
+ s.emit_usize(self.len())?;
+ for e in self.iter() {
+ e.encode(s)?;
+ }
+ Ok(())
}
}
impl<S: Encoder, T: Encodable<S>> Encodable<S> for VecDeque<T> {
fn encode(&self, s: &mut S) -> Result<(), S::Error> {
- s.emit_seq(self.len(), |s| {
- for (i, e) in self.iter().enumerate() {
- s.emit_seq_elt(i, |s| e.encode(s))?;
- }
- Ok(())
- })
+ s.emit_usize(self.len())?;
+ for e in self.iter() {
+ e.encode(s)?;
+ }
+ Ok(())
}
}
V: Encodable<S>,
{
fn encode(&self, e: &mut S) -> Result<(), S::Error> {
- e.emit_map(self.len(), |e| {
- for (i, (key, val)) in self.iter().enumerate() {
- e.emit_map_elt_key(i, |e| key.encode(e))?;
- e.emit_map_elt_val(|e| val.encode(e))?;
- }
- Ok(())
- })
+ e.emit_usize(self.len())?;
+ for (key, val) in self.iter() {
+ key.encode(e)?;
+ val.encode(e)?;
+ }
+ Ok(())
}
}
T: Encodable<S> + PartialEq + Ord,
{
fn encode(&self, s: &mut S) -> Result<(), S::Error> {
- s.emit_seq(self.len(), |s| {
- for (i, e) in self.iter().enumerate() {
- s.emit_seq_elt(i, |s| e.encode(s))?;
- }
- Ok(())
- })
+ s.emit_usize(self.len())?;
+ for e in self.iter() {
+ e.encode(s)?;
+ }
+ Ok(())
}
}
S: BuildHasher,
{
fn encode(&self, e: &mut E) -> Result<(), E::Error> {
- e.emit_map(self.len(), |e| {
- for (i, (key, val)) in self.iter().enumerate() {
- e.emit_map_elt_key(i, |e| key.encode(e))?;
- e.emit_map_elt_val(|e| val.encode(e))?;
- }
- Ok(())
- })
+ e.emit_usize(self.len())?;
+ for (key, val) in self.iter() {
+ key.encode(e)?;
+ val.encode(e)?;
+ }
+ Ok(())
}
}
S: BuildHasher,
{
fn encode(&self, s: &mut E) -> Result<(), E::Error> {
- s.emit_seq(self.len(), |s| {
- for (i, e) in self.iter().enumerate() {
- s.emit_seq_elt(i, |s| e.encode(s))?;
- }
- Ok(())
- })
+ s.emit_usize(self.len())?;
+ for e in self.iter() {
+ e.encode(s)?;
+ }
+ Ok(())
}
}
S: BuildHasher,
{
fn encode(&self, e: &mut E) -> Result<(), E::Error> {
- e.emit_map(self.len(), |e| {
- for (i, (key, val)) in self.iter().enumerate() {
- e.emit_map_elt_key(i, |e| key.encode(e))?;
- e.emit_map_elt_val(|e| val.encode(e))?;
- }
- Ok(())
- })
+ e.emit_usize(self.len())?;
+ for (key, val) in self.iter() {
+ key.encode(e)?;
+ val.encode(e)?;
+ }
+ Ok(())
}
}
S: BuildHasher,
{
fn encode(&self, s: &mut E) -> Result<(), E::Error> {
- s.emit_seq(self.len(), |s| {
- for (i, e) in self.iter().enumerate() {
- s.emit_seq_elt(i, |s| e.encode(s))?;
- }
- Ok(())
- })
+ s.emit_usize(self.len())?;
+ for e in self.iter() {
+ e.encode(s)?;
+ }
+ Ok(())
}
}
+++ /dev/null
-// Rust JSON serialization library.
-// Copyright (c) 2011 Google Inc.
-
-#![forbid(non_camel_case_types)]
-#![allow(missing_docs)]
-
-//! JSON parsing and serialization
-//!
-//! # What is JSON?
-//!
-//! JSON (JavaScript Object Notation) is a way to write data in Javascript.
-//! Like XML, it allows to encode structured data in a text format that can be easily read by humans
-//! Its simple syntax and native compatibility with JavaScript have made it a widely used format.
-//!
-//! Data types that can be encoded are JavaScript types (see the `Json` enum for more details):
-//!
-//! * `Boolean`: equivalent to rust's `bool`
-//! * `Number`: equivalent to rust's `f64`
-//! * `String`: equivalent to rust's `String`
-//! * `Array`: equivalent to rust's `Vec<T>`, but also allowing objects of different types in the
-//! same array
-//! * `Object`: equivalent to rust's `BTreeMap<String, json::Json>`
-//! * `Null`
-//!
-//! An object is a series of string keys mapping to values, in `"key": value` format.
-//! Arrays are enclosed in square brackets ([ ... ]) and objects in curly brackets ({ ... }).
-//! A simple JSON document encoding a person, their age, address and phone numbers could look like
-//!
-//! ```json
-//! {
-//! "FirstName": "John",
-//! "LastName": "Doe",
-//! "Age": 43,
-//! "Address": {
-//! "Street": "Downing Street 10",
-//! "City": "London",
-//! "Country": "Great Britain"
-//! },
-//! "PhoneNumbers": [
-//! "+44 1234567",
-//! "+44 2345678"
-//! ]
-//! }
-//! ```
-//!
-//! # Rust Type-based Encoding and Decoding
-//!
-//! To be able to encode a piece of data, it must implement the
-//! `serialize::Encodable` trait. The `rustc_macros` crate provides an
-//! annotation to automatically generate the code for this trait: `#[derive(Encodable)]`.
-//!
-//! The JSON API provides an enum `json::Json` and a trait `ToJson` to encode objects.
-//! The `ToJson` trait provides a `to_json` method to convert an object into a `json::Json` value.
-//! A `json::Json` value can be encoded as a string or buffer using the functions described above.
-//! You can also use the `json::Encoder` object, which implements the `Encoder` trait.
-//!
-//! When using `ToJson` the `Encodable` trait implementation is not mandatory.
-//!
-//! # Examples of use
-//!
-//! ## Using Autoserialization
-//!
-//! Create a struct called `TestStruct` and serialize and deserialize it to and from JSON using the
-//! serialization API, using the derived serialization code.
-//!
-//! ```rust
-//! # #![feature(rustc_private)]
-//! use rustc_macros::{Encodable};
-//! use rustc_serialize::json;
-//!
-//! // Automatically generate `Encodable` trait implementations
-//! #[derive(Encodable)]
-//! pub struct TestStruct {
-//! data_int: u8,
-//! data_str: String,
-//! data_vector: Vec<u8>,
-//! }
-//!
-//! let object = TestStruct {
-//! data_int: 1,
-//! data_str: "homura".to_string(),
-//! data_vector: vec![2,3,4,5],
-//! };
-//!
-//! // Serialize using `json::encode`
-//! let encoded = json::encode(&object).unwrap();
-//! ```
-//!
-//! ## Using the `ToJson` trait
-//!
-//! The examples above use the `ToJson` trait to generate the JSON string, which is required
-//! for custom mappings.
-//!
-//! ### Simple example of `ToJson` usage
-//!
-//! ```rust
-//! # #![feature(rustc_private)]
-//! use rustc_macros::Encodable;
-//! use rustc_serialize::json::{self, ToJson, Json};
-//!
-//! // A custom data structure
-//! struct ComplexNum {
-//! a: f64,
-//! b: f64,
-//! }
-//!
-//! // JSON value representation
-//! impl ToJson for ComplexNum {
-//! fn to_json(&self) -> Json {
-//! Json::String(format!("{}+{}i", self.a, self.b))
-//! }
-//! }
-//!
-//! // Only generate `Encodable` trait implementation
-//! #[derive(Encodable)]
-//! pub struct ComplexNumRecord {
-//! uid: u8,
-//! dsc: String,
-//! val: Json,
-//! }
-//!
-//! let num = ComplexNum { a: 0.0001, b: 12.539 };
-//! let data: String = json::encode(&ComplexNumRecord{
-//! uid: 1,
-//! dsc: "test".to_string(),
-//! val: num.to_json(),
-//! }).unwrap();
-//! println!("data: {}", data);
-//! // data: {"uid":1,"dsc":"test","val":"0.0001+12.539i"};
-//! ```
-//!
-//! ### Verbose example of `ToJson` usage
-//!
-//! ```rust
-//! # #![feature(rustc_private)]
-//! use std::collections::BTreeMap;
-//! use rustc_serialize::json::{Json, ToJson};
-//!
-//! pub struct TestStruct {
-//! data_int: u8,
-//! data_str: String,
-//! data_vector: Vec<u8>,
-//! }
-//!
-//! // Specify encoding method manually
-//! impl ToJson for TestStruct {
-//! fn to_json(&self) -> Json {
-//! let mut d = BTreeMap::new();
-//! // All standard types implement `to_json()`, so use it
-//! d.insert("data_int".to_string(), self.data_int.to_json());
-//! d.insert("data_str".to_string(), self.data_str.to_json());
-//! d.insert("data_vector".to_string(), self.data_vector.to_json());
-//! Json::Object(d)
-//! }
-//! }
-//!
-//! // Serialize using `ToJson`
-//! let input_data = TestStruct {
-//! data_int: 1,
-//! data_str: "madoka".to_string(),
-//! data_vector: vec![2,3,4,5],
-//! };
-//! let json_obj: Json = input_data.to_json();
-//! let json_str: String = json_obj.to_string();
-//! ```
-
-use self::ErrorCode::*;
-use self::InternalStackElement::*;
-use self::JsonEvent::*;
-use self::ParserError::*;
-use self::ParserState::*;
-
-use std::borrow::Cow;
-use std::collections::{BTreeMap, HashMap};
-use std::mem::swap;
-use std::num::FpCategory as Fp;
-use std::ops::Index;
-use std::str::FromStr;
-use std::string;
-use std::{char, fmt, str};
-
-use crate::Encodable;
-
-/// Represents a json value
-#[derive(Clone, PartialEq, PartialOrd, Debug)]
-pub enum Json {
- I64(i64),
- U64(u64),
- F64(f64),
- String(string::String),
- Boolean(bool),
- Array(self::Array),
- Object(self::Object),
- Null,
-}
-
-pub type Array = Vec<Json>;
-pub type Object = BTreeMap<string::String, Json>;
-
-pub struct PrettyJson<'a> {
- inner: &'a Json,
-}
-
-pub struct AsJson<'a, T> {
- inner: &'a T,
-}
-pub struct AsPrettyJson<'a, T> {
- inner: &'a T,
- indent: Option<usize>,
-}
-
-/// The errors that can arise while parsing a JSON stream.
-#[derive(Clone, Copy, PartialEq, Debug)]
-pub enum ErrorCode {
- InvalidSyntax,
- InvalidNumber,
- EOFWhileParsingObject,
- EOFWhileParsingArray,
- EOFWhileParsingValue,
- EOFWhileParsingString,
- KeyMustBeAString,
- ExpectedColon,
- TrailingCharacters,
- TrailingComma,
- InvalidEscape,
- InvalidUnicodeCodePoint,
- LoneLeadingSurrogateInHexEscape,
- UnexpectedEndOfHexEscape,
- UnrecognizedHex,
- NotFourDigit,
- NotUtf8,
-}
-
-#[derive(Clone, PartialEq, Debug)]
-pub enum ParserError {
- /// msg, line, col
- SyntaxError(ErrorCode, usize, usize),
-}
-
-// Builder and Parser have the same errors.
-pub type BuilderError = ParserError;
-
-#[derive(Copy, Clone, Debug)]
-pub enum EncoderError {
- FmtError(fmt::Error),
- BadHashmapKey,
-}
-
-/// Returns a readable error string for a given error code.
-pub fn error_str(error: ErrorCode) -> &'static str {
- match error {
- InvalidSyntax => "invalid syntax",
- InvalidNumber => "invalid number",
- EOFWhileParsingObject => "EOF While parsing object",
- EOFWhileParsingArray => "EOF While parsing array",
- EOFWhileParsingValue => "EOF While parsing value",
- EOFWhileParsingString => "EOF While parsing string",
- KeyMustBeAString => "key must be a string",
- ExpectedColon => "expected `:`",
- TrailingCharacters => "trailing characters",
- TrailingComma => "trailing comma",
- InvalidEscape => "invalid escape",
- UnrecognizedHex => "invalid \\u{ esc}ape (unrecognized hex)",
- NotFourDigit => "invalid \\u{ esc}ape (not four digits)",
- NotUtf8 => "contents not utf-8",
- InvalidUnicodeCodePoint => "invalid Unicode code point",
- LoneLeadingSurrogateInHexEscape => "lone leading surrogate in hex escape",
- UnexpectedEndOfHexEscape => "unexpected end of hex escape",
- }
-}
-
-/// Shortcut function to encode a `T` into a JSON `String`
-pub fn encode<T: for<'r> crate::Encodable<Encoder<'r>>>(
- object: &T,
-) -> Result<string::String, EncoderError> {
- let mut s = String::new();
- {
- let mut encoder = Encoder::new(&mut s);
- object.encode(&mut encoder)?;
- }
- Ok(s)
-}
-
-impl fmt::Display for ErrorCode {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- error_str(*self).fmt(f)
- }
-}
-
-impl fmt::Display for ParserError {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- // FIXME this should be a nicer error
- fmt::Debug::fmt(self, f)
- }
-}
-
-impl fmt::Display for EncoderError {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- // FIXME this should be a nicer error
- fmt::Debug::fmt(self, f)
- }
-}
-
-impl std::error::Error for EncoderError {}
-
-impl From<fmt::Error> for EncoderError {
- /// Converts a [`fmt::Error`] into `EncoderError`
- ///
- /// This conversion does not allocate memory.
- fn from(err: fmt::Error) -> EncoderError {
- EncoderError::FmtError(err)
- }
-}
-
-pub type EncodeResult = Result<(), EncoderError>;
-
-fn escape_str(wr: &mut dyn fmt::Write, v: &str) -> EncodeResult {
- wr.write_str("\"")?;
-
- let mut start = 0;
-
- for (i, byte) in v.bytes().enumerate() {
- let escaped = match byte {
- b'"' => "\\\"",
- b'\\' => "\\\\",
- b'\x00' => "\\u0000",
- b'\x01' => "\\u0001",
- b'\x02' => "\\u0002",
- b'\x03' => "\\u0003",
- b'\x04' => "\\u0004",
- b'\x05' => "\\u0005",
- b'\x06' => "\\u0006",
- b'\x07' => "\\u0007",
- b'\x08' => "\\b",
- b'\t' => "\\t",
- b'\n' => "\\n",
- b'\x0b' => "\\u000b",
- b'\x0c' => "\\f",
- b'\r' => "\\r",
- b'\x0e' => "\\u000e",
- b'\x0f' => "\\u000f",
- b'\x10' => "\\u0010",
- b'\x11' => "\\u0011",
- b'\x12' => "\\u0012",
- b'\x13' => "\\u0013",
- b'\x14' => "\\u0014",
- b'\x15' => "\\u0015",
- b'\x16' => "\\u0016",
- b'\x17' => "\\u0017",
- b'\x18' => "\\u0018",
- b'\x19' => "\\u0019",
- b'\x1a' => "\\u001a",
- b'\x1b' => "\\u001b",
- b'\x1c' => "\\u001c",
- b'\x1d' => "\\u001d",
- b'\x1e' => "\\u001e",
- b'\x1f' => "\\u001f",
- b'\x7f' => "\\u007f",
- _ => {
- continue;
- }
- };
-
- if start < i {
- wr.write_str(&v[start..i])?;
- }
-
- wr.write_str(escaped)?;
-
- start = i + 1;
- }
-
- if start != v.len() {
- wr.write_str(&v[start..])?;
- }
-
- wr.write_str("\"")?;
- Ok(())
-}
-
-fn escape_char(writer: &mut dyn fmt::Write, v: char) -> EncodeResult {
- escape_str(writer, v.encode_utf8(&mut [0; 4]))
-}
-
-fn spaces(wr: &mut dyn fmt::Write, mut n: usize) -> EncodeResult {
- const BUF: &str = " ";
-
- while n >= BUF.len() {
- wr.write_str(BUF)?;
- n -= BUF.len();
- }
-
- if n > 0 {
- wr.write_str(&BUF[..n])?;
- }
- Ok(())
-}
-
-fn fmt_number_or_null(v: f64) -> string::String {
- match v.classify() {
- Fp::Nan | Fp::Infinite => string::String::from("null"),
- _ if v.fract() != 0f64 => v.to_string(),
- _ => v.to_string() + ".0",
- }
-}
-
-/// A structure for implementing serialization to JSON.
-pub struct Encoder<'a> {
- writer: &'a mut (dyn fmt::Write + 'a),
- is_emitting_map_key: bool,
-}
-
-impl<'a> Encoder<'a> {
- /// Creates a new JSON encoder whose output will be written to the writer
- /// specified.
- pub fn new(writer: &'a mut dyn fmt::Write) -> Encoder<'a> {
- Encoder { writer, is_emitting_map_key: false }
- }
-}
-
-macro_rules! emit_enquoted_if_mapkey {
- ($enc:ident,$e:expr) => {{
- if $enc.is_emitting_map_key {
- write!($enc.writer, "\"{}\"", $e)?;
- } else {
- write!($enc.writer, "{}", $e)?;
- }
- Ok(())
- }};
-}
-
-impl<'a> crate::Encoder for Encoder<'a> {
- type Error = EncoderError;
-
- fn emit_unit(&mut self) -> EncodeResult {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- write!(self.writer, "null")?;
- Ok(())
- }
-
- fn emit_usize(&mut self, v: usize) -> EncodeResult {
- emit_enquoted_if_mapkey!(self, v)
- }
- fn emit_u128(&mut self, v: u128) -> EncodeResult {
- emit_enquoted_if_mapkey!(self, v)
- }
- fn emit_u64(&mut self, v: u64) -> EncodeResult {
- emit_enquoted_if_mapkey!(self, v)
- }
- fn emit_u32(&mut self, v: u32) -> EncodeResult {
- emit_enquoted_if_mapkey!(self, v)
- }
- fn emit_u16(&mut self, v: u16) -> EncodeResult {
- emit_enquoted_if_mapkey!(self, v)
- }
- fn emit_u8(&mut self, v: u8) -> EncodeResult {
- emit_enquoted_if_mapkey!(self, v)
- }
-
- fn emit_isize(&mut self, v: isize) -> EncodeResult {
- emit_enquoted_if_mapkey!(self, v)
- }
- fn emit_i128(&mut self, v: i128) -> EncodeResult {
- emit_enquoted_if_mapkey!(self, v)
- }
- fn emit_i64(&mut self, v: i64) -> EncodeResult {
- emit_enquoted_if_mapkey!(self, v)
- }
- fn emit_i32(&mut self, v: i32) -> EncodeResult {
- emit_enquoted_if_mapkey!(self, v)
- }
- fn emit_i16(&mut self, v: i16) -> EncodeResult {
- emit_enquoted_if_mapkey!(self, v)
- }
- fn emit_i8(&mut self, v: i8) -> EncodeResult {
- emit_enquoted_if_mapkey!(self, v)
- }
-
- fn emit_bool(&mut self, v: bool) -> EncodeResult {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- if v {
- write!(self.writer, "true")?;
- } else {
- write!(self.writer, "false")?;
- }
- Ok(())
- }
-
- fn emit_f64(&mut self, v: f64) -> EncodeResult {
- emit_enquoted_if_mapkey!(self, fmt_number_or_null(v))
- }
- fn emit_f32(&mut self, v: f32) -> EncodeResult {
- self.emit_f64(f64::from(v))
- }
-
- fn emit_char(&mut self, v: char) -> EncodeResult {
- escape_char(self.writer, v)
- }
- fn emit_str(&mut self, v: &str) -> EncodeResult {
- escape_str(self.writer, v)
- }
- fn emit_raw_bytes(&mut self, s: &[u8]) -> Result<(), Self::Error> {
- for &c in s.iter() {
- self.emit_u8(c)?;
- }
- Ok(())
- }
-
- fn emit_enum<F>(&mut self, f: F) -> EncodeResult
- where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
- {
- f(self)
- }
-
- fn emit_enum_variant<F>(&mut self, name: &str, _id: usize, cnt: usize, f: F) -> EncodeResult
- where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
- {
- // enums are encoded as strings or objects
- // Bunny => "Bunny"
- // Kangaroo(34,"William") => {"variant": "Kangaroo", "fields": [34,"William"]}
- if cnt == 0 {
- escape_str(self.writer, name)
- } else {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- write!(self.writer, "{{\"variant\":")?;
- escape_str(self.writer, name)?;
- write!(self.writer, ",\"fields\":[")?;
- f(self)?;
- write!(self.writer, "]}}")?;
- Ok(())
- }
- }
-
- fn emit_fieldless_enum_variant<const ID: usize>(
- &mut self,
- name: &str,
- ) -> Result<(), Self::Error> {
- escape_str(self.writer, name)
- }
-
- fn emit_enum_variant_arg<F>(&mut self, first: bool, f: F) -> EncodeResult
- where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- if !first {
- write!(self.writer, ",")?;
- }
- f(self)
- }
-
- fn emit_struct<F>(&mut self, _: bool, f: F) -> EncodeResult
- where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- write!(self.writer, "{{")?;
- f(self)?;
- write!(self.writer, "}}")?;
- Ok(())
- }
-
- fn emit_struct_field<F>(&mut self, name: &str, first: bool, f: F) -> EncodeResult
- where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- if !first {
- write!(self.writer, ",")?;
- }
- escape_str(self.writer, name)?;
- write!(self.writer, ":")?;
- f(self)
- }
-
- fn emit_tuple<F>(&mut self, len: usize, f: F) -> EncodeResult
- where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- self.emit_seq(len, f)
- }
- fn emit_tuple_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult
- where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- self.emit_seq_elt(idx, f)
- }
-
- fn emit_option<F>(&mut self, f: F) -> EncodeResult
- where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- f(self)
- }
- fn emit_option_none(&mut self) -> EncodeResult {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- self.emit_unit()
- }
- fn emit_option_some<F>(&mut self, f: F) -> EncodeResult
- where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- f(self)
- }
-
- fn emit_seq<F>(&mut self, _len: usize, f: F) -> EncodeResult
- where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- write!(self.writer, "[")?;
- f(self)?;
- write!(self.writer, "]")?;
- Ok(())
- }
-
- fn emit_seq_elt<F>(&mut self, idx: usize, f: F) -> EncodeResult
- where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- if idx != 0 {
- write!(self.writer, ",")?;
- }
- f(self)
- }
-
- fn emit_map<F>(&mut self, _len: usize, f: F) -> EncodeResult
- where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- write!(self.writer, "{{")?;
- f(self)?;
- write!(self.writer, "}}")?;
- Ok(())
- }
-
- fn emit_map_elt_key<F>(&mut self, idx: usize, f: F) -> EncodeResult
- where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- if idx != 0 {
- write!(self.writer, ",")?
- }
- self.is_emitting_map_key = true;
- f(self)?;
- self.is_emitting_map_key = false;
- Ok(())
- }
-
- fn emit_map_elt_val<F>(&mut self, f: F) -> EncodeResult
- where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- write!(self.writer, ":")?;
- f(self)
- }
-}
-
-/// Another encoder for JSON, but prints out human-readable JSON instead of
-/// compact data
-pub struct PrettyEncoder<'a> {
- writer: &'a mut (dyn fmt::Write + 'a),
- curr_indent: usize,
- indent: usize,
- is_emitting_map_key: bool,
-}
-
-impl<'a> PrettyEncoder<'a> {
- /// Creates a new encoder whose output will be written to the specified writer
- pub fn new(writer: &'a mut dyn fmt::Write) -> PrettyEncoder<'a> {
- PrettyEncoder { writer, curr_indent: 0, indent: 2, is_emitting_map_key: false }
- }
-
- /// Sets the number of spaces to indent for each level.
- /// This is safe to set during encoding.
- pub fn set_indent(&mut self, indent: usize) {
- // self.indent very well could be 0 so we need to use checked division.
- let level = self.curr_indent.checked_div(self.indent).unwrap_or(0);
- self.indent = indent;
- self.curr_indent = level * self.indent;
- }
-}
-
-impl<'a> crate::Encoder for PrettyEncoder<'a> {
- type Error = EncoderError;
-
- fn emit_unit(&mut self) -> EncodeResult {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- write!(self.writer, "null")?;
- Ok(())
- }
-
- fn emit_usize(&mut self, v: usize) -> EncodeResult {
- emit_enquoted_if_mapkey!(self, v)
- }
- fn emit_u128(&mut self, v: u128) -> EncodeResult {
- emit_enquoted_if_mapkey!(self, v)
- }
- fn emit_u64(&mut self, v: u64) -> EncodeResult {
- emit_enquoted_if_mapkey!(self, v)
- }
- fn emit_u32(&mut self, v: u32) -> EncodeResult {
- emit_enquoted_if_mapkey!(self, v)
- }
- fn emit_u16(&mut self, v: u16) -> EncodeResult {
- emit_enquoted_if_mapkey!(self, v)
- }
- fn emit_u8(&mut self, v: u8) -> EncodeResult {
- emit_enquoted_if_mapkey!(self, v)
- }
-
- fn emit_isize(&mut self, v: isize) -> EncodeResult {
- emit_enquoted_if_mapkey!(self, v)
- }
- fn emit_i128(&mut self, v: i128) -> EncodeResult {
- emit_enquoted_if_mapkey!(self, v)
- }
- fn emit_i64(&mut self, v: i64) -> EncodeResult {
- emit_enquoted_if_mapkey!(self, v)
- }
- fn emit_i32(&mut self, v: i32) -> EncodeResult {
- emit_enquoted_if_mapkey!(self, v)
- }
- fn emit_i16(&mut self, v: i16) -> EncodeResult {
- emit_enquoted_if_mapkey!(self, v)
- }
- fn emit_i8(&mut self, v: i8) -> EncodeResult {
- emit_enquoted_if_mapkey!(self, v)
- }
-
- fn emit_bool(&mut self, v: bool) -> EncodeResult {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- if v {
- write!(self.writer, "true")?;
- } else {
- write!(self.writer, "false")?;
- }
- Ok(())
- }
-
- fn emit_f64(&mut self, v: f64) -> EncodeResult {
- emit_enquoted_if_mapkey!(self, fmt_number_or_null(v))
- }
- fn emit_f32(&mut self, v: f32) -> EncodeResult {
- self.emit_f64(f64::from(v))
- }
-
- fn emit_char(&mut self, v: char) -> EncodeResult {
- escape_char(self.writer, v)
- }
- fn emit_str(&mut self, v: &str) -> EncodeResult {
- escape_str(self.writer, v)
- }
- fn emit_raw_bytes(&mut self, s: &[u8]) -> Result<(), Self::Error> {
- for &c in s.iter() {
- self.emit_u8(c)?;
- }
- Ok(())
- }
-
- fn emit_enum<F>(&mut self, f: F) -> EncodeResult
- where
- F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
- {
- f(self)
- }
-
- fn emit_enum_variant<F>(&mut self, name: &str, _id: usize, cnt: usize, f: F) -> EncodeResult
- where
- F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
- {
- if cnt == 0 {
- escape_str(self.writer, name)
- } else {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- writeln!(self.writer, "{{")?;
- self.curr_indent += self.indent;
- spaces(self.writer, self.curr_indent)?;
- write!(self.writer, "\"variant\": ")?;
- escape_str(self.writer, name)?;
- writeln!(self.writer, ",")?;
- spaces(self.writer, self.curr_indent)?;
- writeln!(self.writer, "\"fields\": [")?;
- self.curr_indent += self.indent;
- f(self)?;
- self.curr_indent -= self.indent;
- writeln!(self.writer)?;
- spaces(self.writer, self.curr_indent)?;
- self.curr_indent -= self.indent;
- writeln!(self.writer, "]")?;
- spaces(self.writer, self.curr_indent)?;
- write!(self.writer, "}}")?;
- Ok(())
- }
- }
-
- fn emit_fieldless_enum_variant<const ID: usize>(
- &mut self,
- name: &str,
- ) -> Result<(), Self::Error> {
- escape_str(self.writer, name)
- }
-
- fn emit_enum_variant_arg<F>(&mut self, first: bool, f: F) -> EncodeResult
- where
- F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- if !first {
- writeln!(self.writer, ",")?;
- }
- spaces(self.writer, self.curr_indent)?;
- f(self)
- }
-
- fn emit_struct<F>(&mut self, no_fields: bool, f: F) -> EncodeResult
- where
- F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- if no_fields {
- write!(self.writer, "{{}}")?;
- } else {
- write!(self.writer, "{{")?;
- self.curr_indent += self.indent;
- f(self)?;
- self.curr_indent -= self.indent;
- writeln!(self.writer)?;
- spaces(self.writer, self.curr_indent)?;
- write!(self.writer, "}}")?;
- }
- Ok(())
- }
-
- fn emit_struct_field<F>(&mut self, name: &str, first: bool, f: F) -> EncodeResult
- where
- F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- if first {
- writeln!(self.writer)?;
- } else {
- writeln!(self.writer, ",")?;
- }
- spaces(self.writer, self.curr_indent)?;
- escape_str(self.writer, name)?;
- write!(self.writer, ": ")?;
- f(self)
- }
-
- fn emit_tuple<F>(&mut self, len: usize, f: F) -> EncodeResult
- where
- F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- self.emit_seq(len, f)
- }
- fn emit_tuple_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult
- where
- F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- self.emit_seq_elt(idx, f)
- }
-
- fn emit_option<F>(&mut self, f: F) -> EncodeResult
- where
- F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- f(self)
- }
- fn emit_option_none(&mut self) -> EncodeResult {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- self.emit_unit()
- }
- fn emit_option_some<F>(&mut self, f: F) -> EncodeResult
- where
- F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- f(self)
- }
-
- fn emit_seq<F>(&mut self, len: usize, f: F) -> EncodeResult
- where
- F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- if len == 0 {
- write!(self.writer, "[]")?;
- } else {
- write!(self.writer, "[")?;
- self.curr_indent += self.indent;
- f(self)?;
- self.curr_indent -= self.indent;
- writeln!(self.writer)?;
- spaces(self.writer, self.curr_indent)?;
- write!(self.writer, "]")?;
- }
- Ok(())
- }
-
- fn emit_seq_elt<F>(&mut self, idx: usize, f: F) -> EncodeResult
- where
- F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- if idx == 0 {
- writeln!(self.writer)?;
- } else {
- writeln!(self.writer, ",")?;
- }
- spaces(self.writer, self.curr_indent)?;
- f(self)
- }
-
- fn emit_map<F>(&mut self, len: usize, f: F) -> EncodeResult
- where
- F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- if len == 0 {
- write!(self.writer, "{{}}")?;
- } else {
- write!(self.writer, "{{")?;
- self.curr_indent += self.indent;
- f(self)?;
- self.curr_indent -= self.indent;
- writeln!(self.writer)?;
- spaces(self.writer, self.curr_indent)?;
- write!(self.writer, "}}")?;
- }
- Ok(())
- }
-
- fn emit_map_elt_key<F>(&mut self, idx: usize, f: F) -> EncodeResult
- where
- F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- if idx == 0 {
- writeln!(self.writer)?;
- } else {
- writeln!(self.writer, ",")?;
- }
- spaces(self.writer, self.curr_indent)?;
- self.is_emitting_map_key = true;
- f(self)?;
- self.is_emitting_map_key = false;
- Ok(())
- }
-
- fn emit_map_elt_val<F>(&mut self, f: F) -> EncodeResult
- where
- F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- write!(self.writer, ": ")?;
- f(self)
- }
-}
-
-impl<E: crate::Encoder> Encodable<E> for Json {
- fn encode(&self, e: &mut E) -> Result<(), E::Error> {
- match *self {
- Json::I64(v) => v.encode(e),
- Json::U64(v) => v.encode(e),
- Json::F64(v) => v.encode(e),
- Json::String(ref v) => v.encode(e),
- Json::Boolean(v) => v.encode(e),
- Json::Array(ref v) => v.encode(e),
- Json::Object(ref v) => v.encode(e),
- Json::Null => e.emit_unit(),
- }
- }
-}
-
-/// Creates an `AsJson` wrapper which can be used to print a value as JSON
-/// on-the-fly via `write!`
-pub fn as_json<T>(t: &T) -> AsJson<'_, T> {
- AsJson { inner: t }
-}
-
-/// Creates an `AsPrettyJson` wrapper which can be used to print a value as JSON
-/// on-the-fly via `write!`
-pub fn as_pretty_json<T>(t: &T) -> AsPrettyJson<'_, T> {
- AsPrettyJson { inner: t, indent: None }
-}
-
-impl Json {
- /// Borrow this json object as a pretty object to generate a pretty
- /// representation for it via `Display`.
- pub fn pretty(&self) -> PrettyJson<'_> {
- PrettyJson { inner: self }
- }
-
- /// If the Json value is an Object, returns the value associated with the provided key.
- /// Otherwise, returns None.
- pub fn find(&self, key: &str) -> Option<&Json> {
- match *self {
- Json::Object(ref map) => map.get(key),
- _ => None,
- }
- }
-
- /// If the Json value is an Object, deletes the value associated with the
- /// provided key from the Object and returns it. Otherwise, returns None.
- pub fn remove_key(&mut self, key: &str) -> Option<Json> {
- match *self {
- Json::Object(ref mut map) => map.remove(key),
- _ => None,
- }
- }
-
- /// Attempts to get a nested Json Object for each key in `keys`.
- /// If any key is found not to exist, `find_path` will return `None`.
- /// Otherwise, it will return the Json value associated with the final key.
- pub fn find_path<'a>(&'a self, keys: &[&str]) -> Option<&'a Json> {
- let mut target = self;
- for key in keys {
- target = target.find(*key)?;
- }
- Some(target)
- }
-
- /// If the Json value is an Object, performs a depth-first search until
- /// a value associated with the provided key is found. If no value is found
- /// or the Json value is not an Object, returns `None`.
- pub fn search(&self, key: &str) -> Option<&Json> {
- match *self {
- Json::Object(ref map) => match map.get(key) {
- Some(json_value) => Some(json_value),
- None => {
- for v in map.values() {
- match v.search(key) {
- x if x.is_some() => return x,
- _ => (),
- }
- }
- None
- }
- },
- _ => None,
- }
- }
-
- /// Returns `true` if the Json value is an `Object`.
- pub fn is_object(&self) -> bool {
- self.as_object().is_some()
- }
-
- /// If the Json value is an `Object`, returns the associated `BTreeMap`;
- /// returns `None` otherwise.
- pub fn as_object(&self) -> Option<&Object> {
- match *self {
- Json::Object(ref map) => Some(map),
- _ => None,
- }
- }
-
- /// Returns `true` if the Json value is an `Array`.
- pub fn is_array(&self) -> bool {
- self.as_array().is_some()
- }
-
- /// If the Json value is an `Array`, returns the associated vector;
- /// returns `None` otherwise.
- pub fn as_array(&self) -> Option<&Array> {
- match *self {
- Json::Array(ref array) => Some(&*array),
- _ => None,
- }
- }
-
- /// Returns `true` if the Json value is a `String`.
- pub fn is_string(&self) -> bool {
- self.as_string().is_some()
- }
-
- /// If the Json value is a `String`, returns the associated `str`;
- /// returns `None` otherwise.
- pub fn as_string(&self) -> Option<&str> {
- match *self {
- Json::String(ref s) => Some(&s[..]),
- _ => None,
- }
- }
-
- /// Returns `true` if the Json value is a `Number`.
- pub fn is_number(&self) -> bool {
- matches!(*self, Json::I64(_) | Json::U64(_) | Json::F64(_))
- }
-
- /// Returns `true` if the Json value is an `i64`.
- pub fn is_i64(&self) -> bool {
- matches!(*self, Json::I64(_))
- }
-
- /// Returns `true` if the Json value is a `u64`.
- pub fn is_u64(&self) -> bool {
- matches!(*self, Json::U64(_))
- }
-
- /// Returns `true` if the Json value is a `f64`.
- pub fn is_f64(&self) -> bool {
- matches!(*self, Json::F64(_))
- }
-
- /// If the Json value is a number, returns or cast it to an `i64`;
- /// returns `None` otherwise.
- pub fn as_i64(&self) -> Option<i64> {
- match *self {
- Json::I64(n) => Some(n),
- Json::U64(n) => Some(n as i64),
- _ => None,
- }
- }
-
- /// If the Json value is a number, returns or cast it to a `u64`;
- /// returns `None` otherwise.
- pub fn as_u64(&self) -> Option<u64> {
- match *self {
- Json::I64(n) => Some(n as u64),
- Json::U64(n) => Some(n),
- _ => None,
- }
- }
-
- /// If the Json value is a number, returns or cast it to a `f64`;
- /// returns `None` otherwise.
- pub fn as_f64(&self) -> Option<f64> {
- match *self {
- Json::I64(n) => Some(n as f64),
- Json::U64(n) => Some(n as f64),
- Json::F64(n) => Some(n),
- _ => None,
- }
- }
-
- /// Returns `true` if the Json value is a `Boolean`.
- pub fn is_boolean(&self) -> bool {
- self.as_boolean().is_some()
- }
-
- /// If the Json value is a `Boolean`, returns the associated `bool`;
- /// returns `None` otherwise.
- pub fn as_boolean(&self) -> Option<bool> {
- match *self {
- Json::Boolean(b) => Some(b),
- _ => None,
- }
- }
-
- /// Returns `true` if the Json value is a `Null`.
- pub fn is_null(&self) -> bool {
- self.as_null().is_some()
- }
-
- /// If the Json value is a `Null`, returns `()`;
- /// returns `None` otherwise.
- pub fn as_null(&self) -> Option<()> {
- match *self {
- Json::Null => Some(()),
- _ => None,
- }
- }
-}
-
-impl<'a> Index<&'a str> for Json {
- type Output = Json;
-
- fn index(&self, idx: &'a str) -> &Json {
- self.find(idx).unwrap()
- }
-}
-
-impl Index<usize> for Json {
- type Output = Json;
-
- fn index(&self, idx: usize) -> &Json {
- match *self {
- Json::Array(ref v) => &v[idx],
- _ => panic!("can only index Json with usize if it is an array"),
- }
- }
-}
-
-/// The output of the streaming parser.
-#[derive(PartialEq, Clone, Debug)]
-pub enum JsonEvent {
- ObjectStart,
- ObjectEnd,
- ArrayStart,
- ArrayEnd,
- BooleanValue(bool),
- I64Value(i64),
- U64Value(u64),
- F64Value(f64),
- StringValue(string::String),
- NullValue,
- Error(ParserError),
-}
-
-#[derive(PartialEq, Debug)]
-enum ParserState {
- // Parse a value in an array, true means first element.
- ParseArray(bool),
- // Parse ',' or ']' after an element in an array.
- ParseArrayComma,
- // Parse a key:value in an object, true means first element.
- ParseObject(bool),
- // Parse ',' or ']' after an element in an object.
- ParseObjectComma,
- // Initial state.
- ParseStart,
- // Expecting the stream to end.
- ParseBeforeFinish,
- // Parsing can't continue.
- ParseFinished,
-}
-
-/// A Stack represents the current position of the parser in the logical
-/// structure of the JSON stream.
-///
-/// An example is `foo.bar[3].x`.
-#[derive(Default)]
-pub struct Stack {
- stack: Vec<InternalStackElement>,
- str_buffer: Vec<u8>,
-}
-
-/// StackElements compose a Stack.
-///
-/// As an example, `StackElement::Key("foo")`, `StackElement::Key("bar")`,
-/// `StackElement::Index(3)`, and `StackElement::Key("x")` are the
-/// StackElements composing the stack that represents `foo.bar[3].x`.
-#[derive(PartialEq, Clone, Debug)]
-pub enum StackElement<'l> {
- Index(u32),
- Key(&'l str),
-}
-
-// Internally, Key elements are stored as indices in a buffer to avoid
-// allocating a string for every member of an object.
-#[derive(PartialEq, Clone, Debug)]
-enum InternalStackElement {
- InternalIndex(u32),
- InternalKey(u16, u16), // start, size
-}
-
-impl Stack {
- pub fn new() -> Stack {
- Self::default()
- }
-
- /// Returns The number of elements in the Stack.
- pub fn len(&self) -> usize {
- self.stack.len()
- }
-
- /// Returns `true` if the stack is empty.
- pub fn is_empty(&self) -> bool {
- self.stack.is_empty()
- }
-
- /// Provides access to the StackElement at a given index.
- /// lower indices are at the bottom of the stack while higher indices are
- /// at the top.
- pub fn get(&self, idx: usize) -> StackElement<'_> {
- match self.stack[idx] {
- InternalIndex(i) => StackElement::Index(i),
- InternalKey(start, size) => StackElement::Key(
- str::from_utf8(&self.str_buffer[start as usize..start as usize + size as usize])
- .unwrap(),
- ),
- }
- }
-
- /// Compares this stack with an array of StackElement<'_>s.
- pub fn is_equal_to(&self, rhs: &[StackElement<'_>]) -> bool {
- if self.stack.len() != rhs.len() {
- return false;
- }
- for (i, r) in rhs.iter().enumerate() {
- if self.get(i) != *r {
- return false;
- }
- }
- true
- }
-
- /// Returns `true` if the bottom-most elements of this stack are the same as
- /// the ones passed as parameter.
- pub fn starts_with(&self, rhs: &[StackElement<'_>]) -> bool {
- if self.stack.len() < rhs.len() {
- return false;
- }
- for (i, r) in rhs.iter().enumerate() {
- if self.get(i) != *r {
- return false;
- }
- }
- true
- }
-
- /// Returns `true` if the top-most elements of this stack are the same as
- /// the ones passed as parameter.
- pub fn ends_with(&self, rhs: &[StackElement<'_>]) -> bool {
- if self.stack.len() < rhs.len() {
- return false;
- }
- let offset = self.stack.len() - rhs.len();
- for (i, r) in rhs.iter().enumerate() {
- if self.get(i + offset) != *r {
- return false;
- }
- }
- true
- }
-
- /// Returns the top-most element (if any).
- pub fn top(&self) -> Option<StackElement<'_>> {
- match self.stack.last() {
- None => None,
- Some(&InternalIndex(i)) => Some(StackElement::Index(i)),
- Some(&InternalKey(start, size)) => Some(StackElement::Key(
- str::from_utf8(&self.str_buffer[start as usize..(start + size) as usize]).unwrap(),
- )),
- }
- }
-
- // Used by Parser to insert StackElement::Key elements at the top of the stack.
- fn push_key(&mut self, key: string::String) {
- self.stack.push(InternalKey(self.str_buffer.len() as u16, key.len() as u16));
- self.str_buffer.extend(key.as_bytes());
- }
-
- // Used by Parser to insert StackElement::Index elements at the top of the stack.
- fn push_index(&mut self, index: u32) {
- self.stack.push(InternalIndex(index));
- }
-
- // Used by Parser to remove the top-most element of the stack.
- fn pop(&mut self) {
- assert!(!self.is_empty());
- match *self.stack.last().unwrap() {
- InternalKey(_, sz) => {
- let new_size = self.str_buffer.len() - sz as usize;
- self.str_buffer.truncate(new_size);
- }
- InternalIndex(_) => {}
- }
- self.stack.pop();
- }
-
- // Used by Parser to test whether the top-most element is an index.
- fn last_is_index(&self) -> bool {
- matches!(self.stack.last(), Some(InternalIndex(_)))
- }
-
- // Used by Parser to increment the index of the top-most element.
- fn bump_index(&mut self) {
- let len = self.stack.len();
- let idx = match *self.stack.last().unwrap() {
- InternalIndex(i) => i + 1,
- _ => {
- panic!();
- }
- };
- self.stack[len - 1] = InternalIndex(idx);
- }
-}
-
-/// A streaming JSON parser implemented as an iterator of JsonEvent, consuming
-/// an iterator of char.
-pub struct Parser<T> {
- rdr: T,
- ch: Option<char>,
- line: usize,
- col: usize,
- // We maintain a stack representing where we are in the logical structure
- // of the JSON stream.
- stack: Stack,
- // A state machine is kept to make it possible to interrupt and resume parsing.
- state: ParserState,
-}
-
-impl<T: Iterator<Item = char>> Iterator for Parser<T> {
- type Item = JsonEvent;
-
- fn next(&mut self) -> Option<JsonEvent> {
- if self.state == ParseFinished {
- return None;
- }
-
- if self.state == ParseBeforeFinish {
- self.parse_whitespace();
- // Make sure there is no trailing characters.
- if self.eof() {
- self.state = ParseFinished;
- return None;
- } else {
- return Some(self.error_event(TrailingCharacters));
- }
- }
-
- Some(self.parse())
- }
-}
-
-impl<T: Iterator<Item = char>> Parser<T> {
- /// Creates the JSON parser.
- pub fn new(rdr: T) -> Parser<T> {
- let mut p = Parser {
- rdr,
- ch: Some('\x00'),
- line: 1,
- col: 0,
- stack: Stack::new(),
- state: ParseStart,
- };
- p.bump();
- p
- }
-
- /// Provides access to the current position in the logical structure of the
- /// JSON stream.
- pub fn stack(&self) -> &Stack {
- &self.stack
- }
-
- fn eof(&self) -> bool {
- self.ch.is_none()
- }
- fn ch_or_null(&self) -> char {
- self.ch.unwrap_or('\x00')
- }
- fn bump(&mut self) {
- self.ch = self.rdr.next();
-
- if self.ch_is('\n') {
- self.line += 1;
- self.col = 1;
- } else {
- self.col += 1;
- }
- }
-
- fn next_char(&mut self) -> Option<char> {
- self.bump();
- self.ch
- }
- fn ch_is(&self, c: char) -> bool {
- self.ch == Some(c)
- }
-
- fn error<U>(&self, reason: ErrorCode) -> Result<U, ParserError> {
- Err(SyntaxError(reason, self.line, self.col))
- }
-
- fn parse_whitespace(&mut self) {
- while self.ch_is(' ') || self.ch_is('\n') || self.ch_is('\t') || self.ch_is('\r') {
- self.bump();
- }
- }
-
- fn parse_number(&mut self) -> JsonEvent {
- let neg = if self.ch_is('-') {
- self.bump();
- true
- } else {
- false
- };
-
- let res = match self.parse_u64() {
- Ok(res) => res,
- Err(e) => {
- return Error(e);
- }
- };
-
- if self.ch_is('.') || self.ch_is('e') || self.ch_is('E') {
- let mut res = res as f64;
-
- if self.ch_is('.') {
- res = match self.parse_decimal(res) {
- Ok(res) => res,
- Err(e) => {
- return Error(e);
- }
- };
- }
-
- if self.ch_is('e') || self.ch_is('E') {
- res = match self.parse_exponent(res) {
- Ok(res) => res,
- Err(e) => {
- return Error(e);
- }
- };
- }
-
- if neg {
- res *= -1.0;
- }
-
- F64Value(res)
- } else if neg {
- let res = (res as i64).wrapping_neg();
-
- // Make sure we didn't underflow.
- if res > 0 {
- Error(SyntaxError(InvalidNumber, self.line, self.col))
- } else {
- I64Value(res)
- }
- } else {
- U64Value(res)
- }
- }
-
- fn parse_u64(&mut self) -> Result<u64, ParserError> {
- let mut accum = 0u64;
- let last_accum = 0; // necessary to detect overflow.
-
- match self.ch_or_null() {
- '0' => {
- self.bump();
-
- // A leading '0' must be the only digit before the decimal point.
- if let '0'..='9' = self.ch_or_null() {
- return self.error(InvalidNumber);
- }
- }
- '1'..='9' => {
- while !self.eof() {
- match self.ch_or_null() {
- c @ '0'..='9' => {
- accum = accum.wrapping_mul(10);
- accum = accum.wrapping_add((c as u64) - ('0' as u64));
-
- // Detect overflow by comparing to the last value.
- if accum <= last_accum {
- return self.error(InvalidNumber);
- }
-
- self.bump();
- }
- _ => break,
- }
- }
- }
- _ => return self.error(InvalidNumber),
- }
-
- Ok(accum)
- }
-
- fn parse_decimal(&mut self, mut res: f64) -> Result<f64, ParserError> {
- self.bump();
-
- // Make sure a digit follows the decimal place.
- match self.ch_or_null() {
- '0'..='9' => (),
- _ => return self.error(InvalidNumber),
- }
-
- let mut dec = 1.0;
- while !self.eof() {
- match self.ch_or_null() {
- c @ '0'..='9' => {
- dec /= 10.0;
- res += (((c as isize) - ('0' as isize)) as f64) * dec;
- self.bump();
- }
- _ => break,
- }
- }
-
- Ok(res)
- }
-
- fn parse_exponent(&mut self, mut res: f64) -> Result<f64, ParserError> {
- self.bump();
-
- let mut exp = 0;
- let mut neg_exp = false;
-
- if self.ch_is('+') {
- self.bump();
- } else if self.ch_is('-') {
- self.bump();
- neg_exp = true;
- }
-
- // Make sure a digit follows the exponent place.
- match self.ch_or_null() {
- '0'..='9' => (),
- _ => return self.error(InvalidNumber),
- }
- while !self.eof() {
- match self.ch_or_null() {
- c @ '0'..='9' => {
- exp *= 10;
- exp += (c as usize) - ('0' as usize);
-
- self.bump();
- }
- _ => break,
- }
- }
-
- let exp = 10_f64.powi(exp as i32);
- if neg_exp {
- res /= exp;
- } else {
- res *= exp;
- }
-
- Ok(res)
- }
-
- fn decode_hex_escape(&mut self) -> Result<u16, ParserError> {
- let mut i = 0;
- let mut n = 0;
- while i < 4 && !self.eof() {
- self.bump();
- n = match self.ch_or_null() {
- c @ '0'..='9' => n * 16 + ((c as u16) - ('0' as u16)),
- 'a' | 'A' => n * 16 + 10,
- 'b' | 'B' => n * 16 + 11,
- 'c' | 'C' => n * 16 + 12,
- 'd' | 'D' => n * 16 + 13,
- 'e' | 'E' => n * 16 + 14,
- 'f' | 'F' => n * 16 + 15,
- _ => return self.error(InvalidEscape),
- };
-
- i += 1;
- }
-
- // Error out if we didn't parse 4 digits.
- if i != 4 {
- return self.error(InvalidEscape);
- }
-
- Ok(n)
- }
-
- fn parse_str(&mut self) -> Result<string::String, ParserError> {
- let mut escape = false;
- let mut res = string::String::new();
-
- loop {
- self.bump();
- if self.eof() {
- return self.error(EOFWhileParsingString);
- }
-
- if escape {
- match self.ch_or_null() {
- '"' => res.push('"'),
- '\\' => res.push('\\'),
- '/' => res.push('/'),
- 'b' => res.push('\x08'),
- 'f' => res.push('\x0c'),
- 'n' => res.push('\n'),
- 'r' => res.push('\r'),
- 't' => res.push('\t'),
- 'u' => match self.decode_hex_escape()? {
- 0xDC00..=0xDFFF => return self.error(LoneLeadingSurrogateInHexEscape),
-
- // Non-BMP characters are encoded as a sequence of
- // two hex escapes, representing UTF-16 surrogates.
- n1 @ 0xD800..=0xDBFF => {
- match (self.next_char(), self.next_char()) {
- (Some('\\'), Some('u')) => (),
- _ => return self.error(UnexpectedEndOfHexEscape),
- }
-
- let n2 = self.decode_hex_escape()?;
- if !(0xDC00..=0xDFFF).contains(&n2) {
- return self.error(LoneLeadingSurrogateInHexEscape);
- }
- let c =
- (u32::from(n1 - 0xD800) << 10 | u32::from(n2 - 0xDC00)) + 0x1_0000;
- res.push(char::from_u32(c).unwrap());
- }
-
- n => match char::from_u32(u32::from(n)) {
- Some(c) => res.push(c),
- None => return self.error(InvalidUnicodeCodePoint),
- },
- },
- _ => return self.error(InvalidEscape),
- }
- escape = false;
- } else if self.ch_is('\\') {
- escape = true;
- } else {
- match self.ch {
- Some('"') => {
- self.bump();
- return Ok(res);
- }
- Some(c) => res.push(c),
- None => unreachable!(),
- }
- }
- }
- }
-
- // Invoked at each iteration, consumes the stream until it has enough
- // information to return a JsonEvent.
- // Manages an internal state so that parsing can be interrupted and resumed.
- // Also keeps track of the position in the logical structure of the json
- // stream isize the form of a stack that can be queried by the user using the
- // stack() method.
- fn parse(&mut self) -> JsonEvent {
- loop {
- // The only paths where the loop can spin a new iteration
- // are in the cases ParseArrayComma and ParseObjectComma if ','
- // is parsed. In these cases the state is set to (respectively)
- // ParseArray(false) and ParseObject(false), which always return,
- // so there is no risk of getting stuck in an infinite loop.
- // All other paths return before the end of the loop's iteration.
- self.parse_whitespace();
-
- match self.state {
- ParseStart => {
- return self.parse_start();
- }
- ParseArray(first) => {
- return self.parse_array(first);
- }
- ParseArrayComma => {
- if let Some(evt) = self.parse_array_comma_or_end() {
- return evt;
- }
- }
- ParseObject(first) => {
- return self.parse_object(first);
- }
- ParseObjectComma => {
- self.stack.pop();
- if self.ch_is(',') {
- self.state = ParseObject(false);
- self.bump();
- } else {
- return self.parse_object_end();
- }
- }
- _ => {
- return self.error_event(InvalidSyntax);
- }
- }
- }
- }
-
- fn parse_start(&mut self) -> JsonEvent {
- let val = self.parse_value();
- self.state = match val {
- Error(_) => ParseFinished,
- ArrayStart => ParseArray(true),
- ObjectStart => ParseObject(true),
- _ => ParseBeforeFinish,
- };
- val
- }
-
- fn parse_array(&mut self, first: bool) -> JsonEvent {
- if self.ch_is(']') {
- if !first {
- self.error_event(InvalidSyntax)
- } else {
- self.state = if self.stack.is_empty() {
- ParseBeforeFinish
- } else if self.stack.last_is_index() {
- ParseArrayComma
- } else {
- ParseObjectComma
- };
- self.bump();
- ArrayEnd
- }
- } else {
- if first {
- self.stack.push_index(0);
- }
- let val = self.parse_value();
- self.state = match val {
- Error(_) => ParseFinished,
- ArrayStart => ParseArray(true),
- ObjectStart => ParseObject(true),
- _ => ParseArrayComma,
- };
- val
- }
- }
-
- fn parse_array_comma_or_end(&mut self) -> Option<JsonEvent> {
- if self.ch_is(',') {
- self.stack.bump_index();
- self.state = ParseArray(false);
- self.bump();
- None
- } else if self.ch_is(']') {
- self.stack.pop();
- self.state = if self.stack.is_empty() {
- ParseBeforeFinish
- } else if self.stack.last_is_index() {
- ParseArrayComma
- } else {
- ParseObjectComma
- };
- self.bump();
- Some(ArrayEnd)
- } else if self.eof() {
- Some(self.error_event(EOFWhileParsingArray))
- } else {
- Some(self.error_event(InvalidSyntax))
- }
- }
-
- fn parse_object(&mut self, first: bool) -> JsonEvent {
- if self.ch_is('}') {
- if !first {
- if self.stack.is_empty() {
- return self.error_event(TrailingComma);
- } else {
- self.stack.pop();
- }
- }
- self.state = if self.stack.is_empty() {
- ParseBeforeFinish
- } else if self.stack.last_is_index() {
- ParseArrayComma
- } else {
- ParseObjectComma
- };
- self.bump();
- return ObjectEnd;
- }
- if self.eof() {
- return self.error_event(EOFWhileParsingObject);
- }
- if !self.ch_is('"') {
- return self.error_event(KeyMustBeAString);
- }
- let s = match self.parse_str() {
- Ok(s) => s,
- Err(e) => {
- self.state = ParseFinished;
- return Error(e);
- }
- };
- self.parse_whitespace();
- if self.eof() {
- return self.error_event(EOFWhileParsingObject);
- } else if self.ch_or_null() != ':' {
- return self.error_event(ExpectedColon);
- }
- self.stack.push_key(s);
- self.bump();
- self.parse_whitespace();
-
- let val = self.parse_value();
-
- self.state = match val {
- Error(_) => ParseFinished,
- ArrayStart => ParseArray(true),
- ObjectStart => ParseObject(true),
- _ => ParseObjectComma,
- };
- val
- }
-
- fn parse_object_end(&mut self) -> JsonEvent {
- if self.ch_is('}') {
- self.state = if self.stack.is_empty() {
- ParseBeforeFinish
- } else if self.stack.last_is_index() {
- ParseArrayComma
- } else {
- ParseObjectComma
- };
- self.bump();
- ObjectEnd
- } else if self.eof() {
- self.error_event(EOFWhileParsingObject)
- } else {
- self.error_event(InvalidSyntax)
- }
- }
-
- fn parse_value(&mut self) -> JsonEvent {
- if self.eof() {
- return self.error_event(EOFWhileParsingValue);
- }
- match self.ch_or_null() {
- 'n' => self.parse_ident("ull", NullValue),
- 't' => self.parse_ident("rue", BooleanValue(true)),
- 'f' => self.parse_ident("alse", BooleanValue(false)),
- '0'..='9' | '-' => self.parse_number(),
- '"' => match self.parse_str() {
- Ok(s) => StringValue(s),
- Err(e) => Error(e),
- },
- '[' => {
- self.bump();
- ArrayStart
- }
- '{' => {
- self.bump();
- ObjectStart
- }
- _ => self.error_event(InvalidSyntax),
- }
- }
-
- fn parse_ident(&mut self, ident: &str, value: JsonEvent) -> JsonEvent {
- if ident.chars().all(|c| Some(c) == self.next_char()) {
- self.bump();
- value
- } else {
- Error(SyntaxError(InvalidSyntax, self.line, self.col))
- }
- }
-
- fn error_event(&mut self, reason: ErrorCode) -> JsonEvent {
- self.state = ParseFinished;
- Error(SyntaxError(reason, self.line, self.col))
- }
-}
-
-/// A Builder consumes a json::Parser to create a generic Json structure.
-pub struct Builder<T> {
- parser: Parser<T>,
- token: Option<JsonEvent>,
-}
-
-impl<T: Iterator<Item = char>> Builder<T> {
- /// Creates a JSON Builder.
- pub fn new(src: T) -> Builder<T> {
- Builder { parser: Parser::new(src), token: None }
- }
-
- // Decode a Json value from a Parser.
- pub fn build(&mut self) -> Result<Json, BuilderError> {
- self.bump();
- let result = self.build_value();
- self.bump();
- match self.token {
- None => {}
- Some(Error(ref e)) => {
- return Err(e.clone());
- }
- ref tok => {
- panic!("unexpected token {:?}", tok.clone());
- }
- }
- result
- }
-
- fn bump(&mut self) {
- self.token = self.parser.next();
- }
-
- fn build_value(&mut self) -> Result<Json, BuilderError> {
- match self.token {
- Some(NullValue) => Ok(Json::Null),
- Some(I64Value(n)) => Ok(Json::I64(n)),
- Some(U64Value(n)) => Ok(Json::U64(n)),
- Some(F64Value(n)) => Ok(Json::F64(n)),
- Some(BooleanValue(b)) => Ok(Json::Boolean(b)),
- Some(StringValue(ref mut s)) => {
- let mut temp = string::String::new();
- swap(s, &mut temp);
- Ok(Json::String(temp))
- }
- Some(Error(ref e)) => Err(e.clone()),
- Some(ArrayStart) => self.build_array(),
- Some(ObjectStart) => self.build_object(),
- Some(ObjectEnd) => self.parser.error(InvalidSyntax),
- Some(ArrayEnd) => self.parser.error(InvalidSyntax),
- None => self.parser.error(EOFWhileParsingValue),
- }
- }
-
- fn build_array(&mut self) -> Result<Json, BuilderError> {
- self.bump();
- let mut values = Vec::new();
-
- loop {
- if self.token == Some(ArrayEnd) {
- return Ok(Json::Array(values.into_iter().collect()));
- }
- match self.build_value() {
- Ok(v) => values.push(v),
- Err(e) => return Err(e),
- }
- self.bump();
- }
- }
-
- fn build_object(&mut self) -> Result<Json, BuilderError> {
- self.bump();
-
- let mut values = BTreeMap::new();
-
- loop {
- match self.token {
- Some(ObjectEnd) => {
- return Ok(Json::Object(values));
- }
- Some(Error(ref e)) => {
- return Err(e.clone());
- }
- None => {
- break;
- }
- _ => {}
- }
- let key = match self.parser.stack().top() {
- Some(StackElement::Key(k)) => k.to_owned(),
- _ => {
- panic!("invalid state");
- }
- };
- match self.build_value() {
- Ok(value) => {
- values.insert(key, value);
- }
- Err(e) => {
- return Err(e);
- }
- }
- self.bump();
- }
- self.parser.error(EOFWhileParsingObject)
- }
-}
-
-/// Decodes a json value from a string
-pub fn from_str(s: &str) -> Result<Json, BuilderError> {
- let mut builder = Builder::new(s.chars());
- builder.build()
-}
-
-/// A trait for converting values to JSON
-pub trait ToJson {
- /// Converts the value of `self` to an instance of JSON
- fn to_json(&self) -> Json;
-}
-
-macro_rules! to_json_impl_i64 {
- ($($t:ty), +) => (
- $(impl ToJson for $t {
- fn to_json(&self) -> Json {
- Json::I64(*self as i64)
- }
- })+
- )
-}
-
-to_json_impl_i64! { isize, i8, i16, i32, i64 }
-
-macro_rules! to_json_impl_u64 {
- ($($t:ty), +) => (
- $(impl ToJson for $t {
- fn to_json(&self) -> Json {
- Json::U64(*self as u64)
- }
- })+
- )
-}
-
-to_json_impl_u64! { usize, u8, u16, u32, u64 }
-
-impl ToJson for Json {
- fn to_json(&self) -> Json {
- self.clone()
- }
-}
-
-impl ToJson for f32 {
- fn to_json(&self) -> Json {
- f64::from(*self).to_json()
- }
-}
-
-impl ToJson for f64 {
- fn to_json(&self) -> Json {
- match self.classify() {
- Fp::Nan | Fp::Infinite => Json::Null,
- _ => Json::F64(*self),
- }
- }
-}
-
-impl ToJson for () {
- fn to_json(&self) -> Json {
- Json::Null
- }
-}
-
-impl ToJson for bool {
- fn to_json(&self) -> Json {
- Json::Boolean(*self)
- }
-}
-
-impl ToJson for str {
- fn to_json(&self) -> Json {
- Json::String(self.to_string())
- }
-}
-
-impl ToJson for string::String {
- fn to_json(&self) -> Json {
- Json::String((*self).clone())
- }
-}
-
-impl<'a> ToJson for Cow<'a, str> {
- fn to_json(&self) -> Json {
- Json::String(self.to_string())
- }
-}
-
-macro_rules! tuple_impl {
- // use variables to indicate the arity of the tuple
- ($($tyvar:ident),* ) => {
- // the trailing commas are for the 1 tuple
- impl<
- $( $tyvar : ToJson ),*
- > ToJson for ( $( $tyvar ),* , ) {
-
- #[inline]
- #[allow(non_snake_case)]
- fn to_json(&self) -> Json {
- match *self {
- ($(ref $tyvar),*,) => Json::Array(vec![$($tyvar.to_json()),*])
- }
- }
- }
- }
-}
-
-tuple_impl! {A}
-tuple_impl! {A, B}
-tuple_impl! {A, B, C}
-tuple_impl! {A, B, C, D}
-tuple_impl! {A, B, C, D, E}
-tuple_impl! {A, B, C, D, E, F}
-tuple_impl! {A, B, C, D, E, F, G}
-tuple_impl! {A, B, C, D, E, F, G, H}
-tuple_impl! {A, B, C, D, E, F, G, H, I}
-tuple_impl! {A, B, C, D, E, F, G, H, I, J}
-tuple_impl! {A, B, C, D, E, F, G, H, I, J, K}
-tuple_impl! {A, B, C, D, E, F, G, H, I, J, K, L}
-
-impl<A: ToJson> ToJson for [A] {
- fn to_json(&self) -> Json {
- Json::Array(self.iter().map(|elt| elt.to_json()).collect())
- }
-}
-
-impl<A: ToJson> ToJson for Vec<A> {
- fn to_json(&self) -> Json {
- Json::Array(self.iter().map(|elt| elt.to_json()).collect())
- }
-}
-
-impl<'a, A: ToJson> ToJson for Cow<'a, [A]>
-where
- [A]: ToOwned,
-{
- fn to_json(&self) -> Json {
- Json::Array(self.iter().map(|elt| elt.to_json()).collect())
- }
-}
-
-impl<T: ToString, A: ToJson> ToJson for BTreeMap<T, A> {
- fn to_json(&self) -> Json {
- let mut d = BTreeMap::new();
- for (key, value) in self {
- d.insert(key.to_string(), value.to_json());
- }
- Json::Object(d)
- }
-}
-
-impl<A: ToJson> ToJson for HashMap<string::String, A> {
- fn to_json(&self) -> Json {
- let mut d = BTreeMap::new();
- for (key, value) in self {
- d.insert((*key).clone(), value.to_json());
- }
- Json::Object(d)
- }
-}
-
-impl<A: ToJson> ToJson for Option<A> {
- fn to_json(&self) -> Json {
- match *self {
- None => Json::Null,
- Some(ref value) => value.to_json(),
- }
- }
-}
-
-struct FormatShim<'a, 'b> {
- inner: &'a mut fmt::Formatter<'b>,
-}
-
-impl<'a, 'b> fmt::Write for FormatShim<'a, 'b> {
- fn write_str(&mut self, s: &str) -> fmt::Result {
- match self.inner.write_str(s) {
- Ok(_) => Ok(()),
- Err(_) => Err(fmt::Error),
- }
- }
-}
-
-impl fmt::Display for Json {
- /// Encodes a json value into a string
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- let mut shim = FormatShim { inner: f };
- let mut encoder = Encoder::new(&mut shim);
- match self.encode(&mut encoder) {
- Ok(_) => Ok(()),
- Err(_) => Err(fmt::Error),
- }
- }
-}
-
-impl<'a> fmt::Display for PrettyJson<'a> {
- /// Encodes a json value into a string
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- let mut shim = FormatShim { inner: f };
- let mut encoder = PrettyEncoder::new(&mut shim);
- match self.inner.encode(&mut encoder) {
- Ok(_) => Ok(()),
- Err(_) => Err(fmt::Error),
- }
- }
-}
-
-impl<'a, T: for<'r> Encodable<Encoder<'r>>> fmt::Display for AsJson<'a, T> {
- /// Encodes a json value into a string
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- let mut shim = FormatShim { inner: f };
- let mut encoder = Encoder::new(&mut shim);
- match self.inner.encode(&mut encoder) {
- Ok(_) => Ok(()),
- Err(_) => Err(fmt::Error),
- }
- }
-}
-
-impl<'a, T> AsPrettyJson<'a, T> {
- /// Sets the indentation level for the emitted JSON
- pub fn indent(mut self, indent: usize) -> AsPrettyJson<'a, T> {
- self.indent = Some(indent);
- self
- }
-}
-
-impl<'a, T: for<'x> Encodable<PrettyEncoder<'x>>> fmt::Display for AsPrettyJson<'a, T> {
- /// Encodes a json value into a string
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- let mut shim = FormatShim { inner: f };
- let mut encoder = PrettyEncoder::new(&mut shim);
- if let Some(n) = self.indent {
- encoder.set_indent(n);
- }
- match self.inner.encode(&mut encoder) {
- Ok(_) => Ok(()),
- Err(_) => Err(fmt::Error),
- }
- }
-}
-
-impl FromStr for Json {
- type Err = BuilderError;
- fn from_str(s: &str) -> Result<Json, BuilderError> {
- from_str(s)
- }
-}
-
-#[cfg(test)]
-mod tests;
+++ /dev/null
-// Benchmarks and tests that require private items
-
-extern crate test;
-use super::{from_str, Parser, Stack, StackElement};
-use std::string;
-use test::Bencher;
-
-#[test]
-fn test_stack() {
- let mut stack = Stack::new();
-
- assert!(stack.is_empty());
- assert!(stack.is_empty());
- assert!(!stack.last_is_index());
-
- stack.push_index(0);
- stack.bump_index();
-
- assert!(stack.len() == 1);
- assert!(stack.is_equal_to(&[StackElement::Index(1)]));
- assert!(stack.starts_with(&[StackElement::Index(1)]));
- assert!(stack.ends_with(&[StackElement::Index(1)]));
- assert!(stack.last_is_index());
- assert!(stack.get(0) == StackElement::Index(1));
-
- stack.push_key("foo".to_string());
-
- assert!(stack.len() == 2);
- assert!(stack.is_equal_to(&[StackElement::Index(1), StackElement::Key("foo")]));
- assert!(stack.starts_with(&[StackElement::Index(1), StackElement::Key("foo")]));
- assert!(stack.starts_with(&[StackElement::Index(1)]));
- assert!(stack.ends_with(&[StackElement::Index(1), StackElement::Key("foo")]));
- assert!(stack.ends_with(&[StackElement::Key("foo")]));
- assert!(!stack.last_is_index());
- assert!(stack.get(0) == StackElement::Index(1));
- assert!(stack.get(1) == StackElement::Key("foo"));
-
- stack.push_key("bar".to_string());
-
- assert!(stack.len() == 3);
- assert!(stack.is_equal_to(&[
- StackElement::Index(1),
- StackElement::Key("foo"),
- StackElement::Key("bar")
- ]));
- assert!(stack.starts_with(&[StackElement::Index(1)]));
- assert!(stack.starts_with(&[StackElement::Index(1), StackElement::Key("foo")]));
- assert!(stack.starts_with(&[
- StackElement::Index(1),
- StackElement::Key("foo"),
- StackElement::Key("bar")
- ]));
- assert!(stack.ends_with(&[StackElement::Key("bar")]));
- assert!(stack.ends_with(&[StackElement::Key("foo"), StackElement::Key("bar")]));
- assert!(stack.ends_with(&[
- StackElement::Index(1),
- StackElement::Key("foo"),
- StackElement::Key("bar")
- ]));
- assert!(!stack.last_is_index());
- assert!(stack.get(0) == StackElement::Index(1));
- assert!(stack.get(1) == StackElement::Key("foo"));
- assert!(stack.get(2) == StackElement::Key("bar"));
-
- stack.pop();
-
- assert!(stack.len() == 2);
- assert!(stack.is_equal_to(&[StackElement::Index(1), StackElement::Key("foo")]));
- assert!(stack.starts_with(&[StackElement::Index(1), StackElement::Key("foo")]));
- assert!(stack.starts_with(&[StackElement::Index(1)]));
- assert!(stack.ends_with(&[StackElement::Index(1), StackElement::Key("foo")]));
- assert!(stack.ends_with(&[StackElement::Key("foo")]));
- assert!(!stack.last_is_index());
- assert!(stack.get(0) == StackElement::Index(1));
- assert!(stack.get(1) == StackElement::Key("foo"));
-}
-
-#[bench]
-fn bench_streaming_small(b: &mut Bencher) {
- b.iter(|| {
- let mut parser = Parser::new(
- r#"{
- "a": 1.0,
- "b": [
- true,
- "foo\nbar",
- { "c": {"d": null} }
- ]
- }"#
- .chars(),
- );
- loop {
- match parser.next() {
- None => return,
- _ => {}
- }
- }
- });
-}
-#[bench]
-fn bench_small(b: &mut Bencher) {
- b.iter(|| {
- let _ = from_str(
- r#"{
- "a": 1.0,
- "b": [
- true,
- "foo\nbar",
- { "c": {"d": null} }
- ]
- }"#,
- );
- });
-}
-
-fn big_json() -> string::String {
- let mut src = "[\n".to_string();
- for _ in 0..500 {
- src.push_str(
- r#"{ "a": true, "b": null, "c":3.1415, "d": "Hello world", "e": \
- [1,2,3]},"#,
- );
- }
- src.push_str("{}]");
- return src;
-}
-
-#[bench]
-fn bench_streaming_large(b: &mut Bencher) {
- let src = big_json();
- b.iter(|| {
- let mut parser = Parser::new(src.chars());
- loop {
- match parser.next() {
- None => return,
- _ => {}
- }
- }
- });
-}
-#[bench]
-fn bench_large(b: &mut Bencher) {
- let src = big_json();
- b.iter(|| {
- let _ = from_str(&src);
- });
-}
mod collection_impls;
mod serialize;
-pub mod json;
-
pub mod leb128;
pub mod opaque;
impl serialize::Encoder for Encoder {
type Error = !;
- #[inline]
- fn emit_unit(&mut self) -> EncodeResult {
- Ok(())
- }
-
#[inline]
fn emit_usize(&mut self, v: usize) -> EncodeResult {
write_leb128!(self, v, usize, write_usize_leb128)
impl serialize::Encoder for FileEncoder {
type Error = io::Error;
- #[inline]
- fn emit_unit(&mut self) -> FileEncodeResult {
- Ok(())
- }
-
#[inline]
fn emit_usize(&mut self, v: usize) -> FileEncodeResult {
file_encoder_write_leb128!(self, v, usize, write_usize_leb128)
type Error;
// Primitive types:
- fn emit_unit(&mut self) -> Result<(), Self::Error>;
fn emit_usize(&mut self, v: usize) -> Result<(), Self::Error>;
fn emit_u128(&mut self, v: u128) -> Result<(), Self::Error>;
fn emit_u64(&mut self, v: u64) -> Result<(), Self::Error>;
fn emit_str(&mut self, v: &str) -> Result<(), Self::Error>;
fn emit_raw_bytes(&mut self, s: &[u8]) -> Result<(), Self::Error>;
- // Compound types:
- #[inline]
- fn emit_enum<F>(&mut self, f: F) -> Result<(), Self::Error>
- where
- F: FnOnce(&mut Self) -> Result<(), Self::Error>,
- {
- f(self)
- }
-
- fn emit_enum_variant<F>(
- &mut self,
- _v_name: &str,
- v_id: usize,
- _len: usize,
- f: F,
- ) -> Result<(), Self::Error>
+ // Convenience for the derive macro:
+ fn emit_enum_variant<F>(&mut self, v_id: usize, f: F) -> Result<(), Self::Error>
where
F: FnOnce(&mut Self) -> Result<(), Self::Error>,
{
// optimization that would otherwise be necessary here, likely due to the
// multiple levels of inlining and const-prop that are needed.
#[inline]
- fn emit_fieldless_enum_variant<const ID: usize>(
- &mut self,
- _v_name: &str,
- ) -> Result<(), Self::Error> {
+ fn emit_fieldless_enum_variant<const ID: usize>(&mut self) -> Result<(), Self::Error> {
self.emit_usize(ID)
}
-
- #[inline]
- fn emit_enum_variant_arg<F>(&mut self, _first: bool, f: F) -> Result<(), Self::Error>
- where
- F: FnOnce(&mut Self) -> Result<(), Self::Error>,
- {
- f(self)
- }
-
- #[inline]
- fn emit_struct<F>(&mut self, _no_fields: bool, f: F) -> Result<(), Self::Error>
- where
- F: FnOnce(&mut Self) -> Result<(), Self::Error>,
- {
- f(self)
- }
-
- #[inline]
- fn emit_struct_field<F>(&mut self, _f_name: &str, _first: bool, f: F) -> Result<(), Self::Error>
- where
- F: FnOnce(&mut Self) -> Result<(), Self::Error>,
- {
- f(self)
- }
-
- #[inline]
- fn emit_tuple<F>(&mut self, _len: usize, f: F) -> Result<(), Self::Error>
- where
- F: FnOnce(&mut Self) -> Result<(), Self::Error>,
- {
- f(self)
- }
-
- #[inline]
- fn emit_tuple_arg<F>(&mut self, _idx: usize, f: F) -> Result<(), Self::Error>
- where
- F: FnOnce(&mut Self) -> Result<(), Self::Error>,
- {
- f(self)
- }
-
- // Specialized types:
- fn emit_option<F>(&mut self, f: F) -> Result<(), Self::Error>
- where
- F: FnOnce(&mut Self) -> Result<(), Self::Error>,
- {
- self.emit_enum(f)
- }
-
- #[inline]
- fn emit_option_none(&mut self) -> Result<(), Self::Error> {
- self.emit_enum_variant("None", 0, 0, |_| Ok(()))
- }
-
- fn emit_option_some<F>(&mut self, f: F) -> Result<(), Self::Error>
- where
- F: FnOnce(&mut Self) -> Result<(), Self::Error>,
- {
- self.emit_enum_variant("Some", 1, 1, f)
- }
-
- fn emit_seq<F>(&mut self, len: usize, f: F) -> Result<(), Self::Error>
- where
- F: FnOnce(&mut Self) -> Result<(), Self::Error>,
- {
- self.emit_usize(len)?;
- f(self)
- }
-
- #[inline]
- fn emit_seq_elt<F>(&mut self, _idx: usize, f: F) -> Result<(), Self::Error>
- where
- F: FnOnce(&mut Self) -> Result<(), Self::Error>,
- {
- f(self)
- }
-
- fn emit_map<F>(&mut self, len: usize, f: F) -> Result<(), Self::Error>
- where
- F: FnOnce(&mut Self) -> Result<(), Self::Error>,
- {
- self.emit_usize(len)?;
- f(self)
- }
-
- #[inline]
- fn emit_map_elt_key<F>(&mut self, _idx: usize, f: F) -> Result<(), Self::Error>
- where
- F: FnOnce(&mut Self) -> Result<(), Self::Error>,
- {
- f(self)
- }
-
- #[inline]
- fn emit_map_elt_val<F>(&mut self, f: F) -> Result<(), Self::Error>
- where
- F: FnOnce(&mut Self) -> Result<(), Self::Error>,
- {
- f(self)
- }
}
// Note: all the methods in this trait are infallible, which may be surprising.
}
impl<S: Encoder> Encodable<S> for () {
- fn encode(&self, s: &mut S) -> Result<(), S::Error> {
- s.emit_unit()
+ fn encode(&self, _s: &mut S) -> Result<(), S::Error> {
+ Ok(())
}
}
}
impl<S: Encoder, T> Encodable<S> for PhantomData<T> {
- fn encode(&self, s: &mut S) -> Result<(), S::Error> {
- s.emit_unit()
+ fn encode(&self, _s: &mut S) -> Result<(), S::Error> {
+ Ok(())
}
}
impl<S: Encoder, T: Encodable<S>> Encodable<S> for [T] {
default fn encode(&self, s: &mut S) -> Result<(), S::Error> {
- s.emit_seq(self.len(), |s| {
- for (i, e) in self.iter().enumerate() {
- s.emit_seq_elt(i, |s| e.encode(s))?
- }
- Ok(())
- })
+ s.emit_usize(self.len())?;
+ for e in self.iter() {
+ e.encode(s)?
+ }
+ Ok(())
}
}
impl<S: Encoder, T: Encodable<S>> Encodable<S> for Option<T> {
fn encode(&self, s: &mut S) -> Result<(), S::Error> {
- s.emit_option(|s| match *self {
- None => s.emit_option_none(),
- Some(ref v) => s.emit_option_some(|s| v.encode(s)),
- })
+ match *self {
+ None => s.emit_enum_variant(0, |_| Ok(())),
+ Some(ref v) => s.emit_enum_variant(1, |s| v.encode(s)),
+ }
}
}
impl<S: Encoder, T1: Encodable<S>, T2: Encodable<S>> Encodable<S> for Result<T1, T2> {
fn encode(&self, s: &mut S) -> Result<(), S::Error> {
- s.emit_enum(|s| match *self {
- Ok(ref v) => {
- s.emit_enum_variant("Ok", 0, 1, |s| s.emit_enum_variant_arg(true, |s| v.encode(s)))
- }
- Err(ref v) => {
- s.emit_enum_variant("Err", 1, 1, |s| s.emit_enum_variant_arg(true, |s| v.encode(s)))
- }
- })
+ match *self {
+ Ok(ref v) => s.emit_enum_variant(0, |s| v.encode(s)),
+ Err(ref v) => s.emit_enum_variant(1, |s| v.encode(s)),
+ }
}
}
($name:ident, $($other:ident,)*) => (tuple! { $($other,)* })
}
-/// Evaluates to the number of tokens passed to it.
-///
-/// Logarithmic counting: every one or two recursive expansions, the number of
-/// tokens to count is divided by two, instead of being reduced by one.
-/// Therefore, the recursion depth is the binary logarithm of the number of
-/// tokens to count, and the expanded tree is likewise very small.
-macro_rules! count {
- ($one:tt) => (1usize);
- ($($pairs:tt $_p:tt)*) => (count!($($pairs)*) << 1usize);
- ($odd:tt $($rest:tt)*) => (count!($($rest)*) | 1usize);
-}
-
macro_rules! tuple {
() => ();
( $($name:ident,)+ ) => (
#[allow(non_snake_case)]
fn encode(&self, s: &mut S) -> Result<(), S::Error> {
let ($(ref $name,)+) = *self;
- let len: usize = count!($($name)+);
- s.emit_tuple(len, |s| {
- let mut i = 0;
- $(s.emit_tuple_arg({ i+=1; i-1 }, |s| $name.encode(s))?;)+
- Ok(())
- })
+ $($name.encode(s)?;)+
+ Ok(())
}
}
peel! { $($name,)+ }
+++ /dev/null
-#![allow(rustc::internal)]
-
-use json::ErrorCode::*;
-use json::Json::*;
-use json::JsonEvent::*;
-use json::ParserError::*;
-use json::{from_str, Encoder, EncoderError, Json, JsonEvent, Parser, StackElement};
-use rustc_macros::Encodable;
-use rustc_serialize::json;
-use rustc_serialize::Encodable;
-
-use std::collections::BTreeMap;
-use std::io::prelude::*;
-use std::string;
-use Animal::*;
-
-#[derive(Eq, PartialEq, Debug)]
-struct OptionData {
- opt: Option<usize>,
-}
-
-#[derive(PartialEq, Encodable, Debug)]
-enum Animal {
- Dog,
- Frog(string::String, isize),
-}
-
-#[derive(PartialEq, Encodable, Debug)]
-struct Inner {
- a: (),
- b: usize,
- c: Vec<string::String>,
-}
-
-#[derive(PartialEq, Encodable, Debug)]
-struct Outer {
- inner: Vec<Inner>,
-}
-
-fn mk_object(items: &[(string::String, Json)]) -> Json {
- let mut d = BTreeMap::new();
-
- for item in items {
- match *item {
- (ref key, ref value) => {
- d.insert((*key).clone(), (*value).clone());
- }
- }
- }
-
- Object(d)
-}
-
-#[test]
-fn test_from_str_trait() {
- let s = "null";
- assert!(s.parse::<Json>().unwrap() == s.parse().unwrap());
-}
-
-#[test]
-fn test_write_null() {
- assert_eq!(Null.to_string(), "null");
- assert_eq!(Null.pretty().to_string(), "null");
-}
-
-#[test]
-fn test_write_i64() {
- assert_eq!(U64(0).to_string(), "0");
- assert_eq!(U64(0).pretty().to_string(), "0");
-
- assert_eq!(U64(1234).to_string(), "1234");
- assert_eq!(U64(1234).pretty().to_string(), "1234");
-
- assert_eq!(I64(-5678).to_string(), "-5678");
- assert_eq!(I64(-5678).pretty().to_string(), "-5678");
-
- assert_eq!(U64(7650007200025252000).to_string(), "7650007200025252000");
- assert_eq!(U64(7650007200025252000).pretty().to_string(), "7650007200025252000");
-}
-
-#[test]
-fn test_write_f64() {
- assert_eq!(F64(3.0).to_string(), "3.0");
- assert_eq!(F64(3.0).pretty().to_string(), "3.0");
-
- assert_eq!(F64(3.1).to_string(), "3.1");
- assert_eq!(F64(3.1).pretty().to_string(), "3.1");
-
- assert_eq!(F64(-1.5).to_string(), "-1.5");
- assert_eq!(F64(-1.5).pretty().to_string(), "-1.5");
-
- assert_eq!(F64(0.5).to_string(), "0.5");
- assert_eq!(F64(0.5).pretty().to_string(), "0.5");
-
- assert_eq!(F64(f64::NAN).to_string(), "null");
- assert_eq!(F64(f64::NAN).pretty().to_string(), "null");
-
- assert_eq!(F64(f64::INFINITY).to_string(), "null");
- assert_eq!(F64(f64::INFINITY).pretty().to_string(), "null");
-
- assert_eq!(F64(f64::NEG_INFINITY).to_string(), "null");
- assert_eq!(F64(f64::NEG_INFINITY).pretty().to_string(), "null");
-}
-
-#[test]
-fn test_write_str() {
- assert_eq!(String("".to_string()).to_string(), "\"\"");
- assert_eq!(String("".to_string()).pretty().to_string(), "\"\"");
-
- assert_eq!(String("homura".to_string()).to_string(), "\"homura\"");
- assert_eq!(String("madoka".to_string()).pretty().to_string(), "\"madoka\"");
-}
-
-#[test]
-fn test_write_bool() {
- assert_eq!(Boolean(true).to_string(), "true");
- assert_eq!(Boolean(true).pretty().to_string(), "true");
-
- assert_eq!(Boolean(false).to_string(), "false");
- assert_eq!(Boolean(false).pretty().to_string(), "false");
-}
-
-#[test]
-fn test_write_array() {
- assert_eq!(Array(vec![]).to_string(), "[]");
- assert_eq!(Array(vec![]).pretty().to_string(), "[]");
-
- assert_eq!(Array(vec![Boolean(true)]).to_string(), "[true]");
- assert_eq!(
- Array(vec![Boolean(true)]).pretty().to_string(),
- "\
- [\n \
- true\n\
- ]"
- );
-
- let long_test_array =
- Array(vec![Boolean(false), Null, Array(vec![String("foo\nbar".to_string()), F64(3.5)])]);
-
- assert_eq!(long_test_array.to_string(), "[false,null,[\"foo\\nbar\",3.5]]");
- assert_eq!(
- long_test_array.pretty().to_string(),
- "\
- [\n \
- false,\n \
- null,\n \
- [\n \
- \"foo\\nbar\",\n \
- 3.5\n \
- ]\n\
- ]"
- );
-}
-
-#[test]
-fn test_write_object() {
- assert_eq!(mk_object(&[]).to_string(), "{}");
- assert_eq!(mk_object(&[]).pretty().to_string(), "{}");
-
- assert_eq!(mk_object(&[("a".to_string(), Boolean(true))]).to_string(), "{\"a\":true}");
- assert_eq!(
- mk_object(&[("a".to_string(), Boolean(true))]).pretty().to_string(),
- "\
- {\n \
- \"a\": true\n\
- }"
- );
-
- let complex_obj = mk_object(&[(
- "b".to_string(),
- Array(vec![
- mk_object(&[("c".to_string(), String("\x0c\r".to_string()))]),
- mk_object(&[("d".to_string(), String("".to_string()))]),
- ]),
- )]);
-
- assert_eq!(
- complex_obj.to_string(),
- "{\
- \"b\":[\
- {\"c\":\"\\f\\r\"},\
- {\"d\":\"\"}\
- ]\
- }"
- );
- assert_eq!(
- complex_obj.pretty().to_string(),
- "\
- {\n \
- \"b\": [\n \
- {\n \
- \"c\": \"\\f\\r\"\n \
- },\n \
- {\n \
- \"d\": \"\"\n \
- }\n \
- ]\n\
- }"
- );
-
- let a = mk_object(&[
- ("a".to_string(), Boolean(true)),
- (
- "b".to_string(),
- Array(vec![
- mk_object(&[("c".to_string(), String("\x0c\r".to_string()))]),
- mk_object(&[("d".to_string(), String("".to_string()))]),
- ]),
- ),
- ]);
-
- // We can't compare the strings directly because the object fields be
- // printed in a different order.
- assert_eq!(a.clone(), a.to_string().parse().unwrap());
- assert_eq!(a.clone(), a.pretty().to_string().parse().unwrap());
-}
-
-#[test]
-fn test_write_enum() {
- let animal = Dog;
- assert_eq!(json::as_json(&animal).to_string(), "\"Dog\"");
- assert_eq!(json::as_pretty_json(&animal).to_string(), "\"Dog\"");
-
- let animal = Frog("Henry".to_string(), 349);
- assert_eq!(
- json::as_json(&animal).to_string(),
- "{\"variant\":\"Frog\",\"fields\":[\"Henry\",349]}"
- );
- assert_eq!(
- json::as_pretty_json(&animal).to_string(),
- "{\n \
- \"variant\": \"Frog\",\n \
- \"fields\": [\n \
- \"Henry\",\n \
- 349\n \
- ]\n\
- }"
- );
-}
-
-macro_rules! check_encoder_for_simple {
- ($value:expr, $expected:expr) => {{
- let s = json::as_json(&$value).to_string();
- assert_eq!(s, $expected);
-
- let s = json::as_pretty_json(&$value).to_string();
- assert_eq!(s, $expected);
- }};
-}
-
-#[test]
-fn test_write_some() {
- check_encoder_for_simple!(Some("jodhpurs".to_string()), "\"jodhpurs\"");
-}
-
-#[test]
-fn test_write_none() {
- check_encoder_for_simple!(None::<string::String>, "null");
-}
-
-#[test]
-fn test_write_char() {
- check_encoder_for_simple!('a', "\"a\"");
- check_encoder_for_simple!('\t', "\"\\t\"");
- check_encoder_for_simple!('\u{0000}', "\"\\u0000\"");
- check_encoder_for_simple!('\u{001b}', "\"\\u001b\"");
- check_encoder_for_simple!('\u{007f}', "\"\\u007f\"");
- check_encoder_for_simple!('\u{00a0}', "\"\u{00a0}\"");
- check_encoder_for_simple!('\u{abcd}', "\"\u{abcd}\"");
- check_encoder_for_simple!('\u{10ffff}', "\"\u{10ffff}\"");
-}
-
-#[test]
-fn test_trailing_characters() {
- assert_eq!(from_str("nulla"), Err(SyntaxError(TrailingCharacters, 1, 5)));
- assert_eq!(from_str("truea"), Err(SyntaxError(TrailingCharacters, 1, 5)));
- assert_eq!(from_str("falsea"), Err(SyntaxError(TrailingCharacters, 1, 6)));
- assert_eq!(from_str("1a"), Err(SyntaxError(TrailingCharacters, 1, 2)));
- assert_eq!(from_str("[]a"), Err(SyntaxError(TrailingCharacters, 1, 3)));
- assert_eq!(from_str("{}a"), Err(SyntaxError(TrailingCharacters, 1, 3)));
-}
-
-#[test]
-fn test_read_identifiers() {
- assert_eq!(from_str("n"), Err(SyntaxError(InvalidSyntax, 1, 2)));
- assert_eq!(from_str("nul"), Err(SyntaxError(InvalidSyntax, 1, 4)));
- assert_eq!(from_str("t"), Err(SyntaxError(InvalidSyntax, 1, 2)));
- assert_eq!(from_str("truz"), Err(SyntaxError(InvalidSyntax, 1, 4)));
- assert_eq!(from_str("f"), Err(SyntaxError(InvalidSyntax, 1, 2)));
- assert_eq!(from_str("faz"), Err(SyntaxError(InvalidSyntax, 1, 3)));
-
- assert_eq!(from_str("null"), Ok(Null));
- assert_eq!(from_str("true"), Ok(Boolean(true)));
- assert_eq!(from_str("false"), Ok(Boolean(false)));
- assert_eq!(from_str(" null "), Ok(Null));
- assert_eq!(from_str(" true "), Ok(Boolean(true)));
- assert_eq!(from_str(" false "), Ok(Boolean(false)));
-}
-
-#[test]
-fn test_read_number() {
- assert_eq!(from_str("+"), Err(SyntaxError(InvalidSyntax, 1, 1)));
- assert_eq!(from_str("."), Err(SyntaxError(InvalidSyntax, 1, 1)));
- assert_eq!(from_str("NaN"), Err(SyntaxError(InvalidSyntax, 1, 1)));
- assert_eq!(from_str("-"), Err(SyntaxError(InvalidNumber, 1, 2)));
- assert_eq!(from_str("00"), Err(SyntaxError(InvalidNumber, 1, 2)));
- assert_eq!(from_str("1."), Err(SyntaxError(InvalidNumber, 1, 3)));
- assert_eq!(from_str("1e"), Err(SyntaxError(InvalidNumber, 1, 3)));
- assert_eq!(from_str("1e+"), Err(SyntaxError(InvalidNumber, 1, 4)));
-
- assert_eq!(from_str("18446744073709551616"), Err(SyntaxError(InvalidNumber, 1, 20)));
- assert_eq!(from_str("-9223372036854775809"), Err(SyntaxError(InvalidNumber, 1, 21)));
-
- assert_eq!(from_str("3"), Ok(U64(3)));
- assert_eq!(from_str("3.1"), Ok(F64(3.1)));
- assert_eq!(from_str("-1.2"), Ok(F64(-1.2)));
- assert_eq!(from_str("0.4"), Ok(F64(0.4)));
- assert_eq!(from_str("0.4e5"), Ok(F64(0.4e5)));
- assert_eq!(from_str("0.4e+15"), Ok(F64(0.4e15)));
- assert_eq!(from_str("0.4e-01"), Ok(F64(0.4e-01)));
- assert_eq!(from_str(" 3 "), Ok(U64(3)));
-
- assert_eq!(from_str("-9223372036854775808"), Ok(I64(i64::MIN)));
- assert_eq!(from_str("9223372036854775807"), Ok(U64(i64::MAX as u64)));
- assert_eq!(from_str("18446744073709551615"), Ok(U64(u64::MAX)));
-}
-
-#[test]
-fn test_read_str() {
- assert_eq!(from_str("\""), Err(SyntaxError(EOFWhileParsingString, 1, 2)));
- assert_eq!(from_str("\"lol"), Err(SyntaxError(EOFWhileParsingString, 1, 5)));
-
- assert_eq!(from_str("\"\""), Ok(String("".to_string())));
- assert_eq!(from_str("\"foo\""), Ok(String("foo".to_string())));
- assert_eq!(from_str("\"\\\"\""), Ok(String("\"".to_string())));
- assert_eq!(from_str("\"\\b\""), Ok(String("\x08".to_string())));
- assert_eq!(from_str("\"\\n\""), Ok(String("\n".to_string())));
- assert_eq!(from_str("\"\\r\""), Ok(String("\r".to_string())));
- assert_eq!(from_str("\"\\t\""), Ok(String("\t".to_string())));
- assert_eq!(from_str(" \"foo\" "), Ok(String("foo".to_string())));
- assert_eq!(from_str("\"\\u12ab\""), Ok(String("\u{12ab}".to_string())));
- assert_eq!(from_str("\"\\uAB12\""), Ok(String("\u{AB12}".to_string())));
-}
-
-#[test]
-fn test_read_array() {
- assert_eq!(from_str("["), Err(SyntaxError(EOFWhileParsingValue, 1, 2)));
- assert_eq!(from_str("[1"), Err(SyntaxError(EOFWhileParsingArray, 1, 3)));
- assert_eq!(from_str("[1,"), Err(SyntaxError(EOFWhileParsingValue, 1, 4)));
- assert_eq!(from_str("[1,]"), Err(SyntaxError(InvalidSyntax, 1, 4)));
- assert_eq!(from_str("[6 7]"), Err(SyntaxError(InvalidSyntax, 1, 4)));
-
- assert_eq!(from_str("[]"), Ok(Array(vec![])));
- assert_eq!(from_str("[ ]"), Ok(Array(vec![])));
- assert_eq!(from_str("[true]"), Ok(Array(vec![Boolean(true)])));
- assert_eq!(from_str("[ false ]"), Ok(Array(vec![Boolean(false)])));
- assert_eq!(from_str("[null]"), Ok(Array(vec![Null])));
- assert_eq!(from_str("[3, 1]"), Ok(Array(vec![U64(3), U64(1)])));
- assert_eq!(from_str("\n[3, 2]\n"), Ok(Array(vec![U64(3), U64(2)])));
- assert_eq!(from_str("[2, [4, 1]]"), Ok(Array(vec![U64(2), Array(vec![U64(4), U64(1)])])));
-}
-
-#[test]
-fn test_read_object() {
- assert_eq!(from_str("{"), Err(SyntaxError(EOFWhileParsingObject, 1, 2)));
- assert_eq!(from_str("{ "), Err(SyntaxError(EOFWhileParsingObject, 1, 3)));
- assert_eq!(from_str("{1"), Err(SyntaxError(KeyMustBeAString, 1, 2)));
- assert_eq!(from_str("{ \"a\""), Err(SyntaxError(EOFWhileParsingObject, 1, 6)));
- assert_eq!(from_str("{\"a\""), Err(SyntaxError(EOFWhileParsingObject, 1, 5)));
- assert_eq!(from_str("{\"a\" "), Err(SyntaxError(EOFWhileParsingObject, 1, 6)));
-
- assert_eq!(from_str("{\"a\" 1"), Err(SyntaxError(ExpectedColon, 1, 6)));
- assert_eq!(from_str("{\"a\":"), Err(SyntaxError(EOFWhileParsingValue, 1, 6)));
- assert_eq!(from_str("{\"a\":1"), Err(SyntaxError(EOFWhileParsingObject, 1, 7)));
- assert_eq!(from_str("{\"a\":1 1"), Err(SyntaxError(InvalidSyntax, 1, 8)));
- assert_eq!(from_str("{\"a\":1,"), Err(SyntaxError(EOFWhileParsingObject, 1, 8)));
-
- assert_eq!(from_str("{}").unwrap(), mk_object(&[]));
- assert_eq!(from_str("{\"a\": 3}").unwrap(), mk_object(&[("a".to_string(), U64(3))]));
-
- assert_eq!(
- from_str("{ \"a\": null, \"b\" : true }").unwrap(),
- mk_object(&[("a".to_string(), Null), ("b".to_string(), Boolean(true))])
- );
- assert_eq!(
- from_str("\n{ \"a\": null, \"b\" : true }\n").unwrap(),
- mk_object(&[("a".to_string(), Null), ("b".to_string(), Boolean(true))])
- );
- assert_eq!(
- from_str("{\"a\" : 1.0 ,\"b\": [ true ]}").unwrap(),
- mk_object(&[("a".to_string(), F64(1.0)), ("b".to_string(), Array(vec![Boolean(true)]))])
- );
- assert_eq!(
- from_str(
- "{\
- \"a\": 1.0, \
- \"b\": [\
- true,\
- \"foo\\nbar\", \
- { \"c\": {\"d\": null} } \
- ]\
- }"
- )
- .unwrap(),
- mk_object(&[
- ("a".to_string(), F64(1.0)),
- (
- "b".to_string(),
- Array(vec![
- Boolean(true),
- String("foo\nbar".to_string()),
- mk_object(&[("c".to_string(), mk_object(&[("d".to_string(), Null)]))])
- ])
- )
- ])
- );
-}
-
-#[test]
-fn test_multiline_errors() {
- assert_eq!(from_str("{\n \"foo\":\n \"bar\""), Err(SyntaxError(EOFWhileParsingObject, 3, 8)));
-}
-
-#[test]
-fn test_find() {
- let json_value = from_str("{\"dog\" : \"cat\"}").unwrap();
- let found_str = json_value.find("dog");
- assert!(found_str.unwrap().as_string().unwrap() == "cat");
-}
-
-#[test]
-fn test_find_path() {
- let json_value = from_str("{\"dog\":{\"cat\": {\"mouse\" : \"cheese\"}}}").unwrap();
- let found_str = json_value.find_path(&["dog", "cat", "mouse"]);
- assert!(found_str.unwrap().as_string().unwrap() == "cheese");
-}
-
-#[test]
-fn test_search() {
- let json_value = from_str("{\"dog\":{\"cat\": {\"mouse\" : \"cheese\"}}}").unwrap();
- let found_str = json_value.search("mouse").and_then(|j| j.as_string());
- assert!(found_str.unwrap() == "cheese");
-}
-
-#[test]
-fn test_index() {
- let json_value = from_str("{\"animals\":[\"dog\",\"cat\",\"mouse\"]}").unwrap();
- let ref array = json_value["animals"];
- assert_eq!(array[0].as_string().unwrap(), "dog");
- assert_eq!(array[1].as_string().unwrap(), "cat");
- assert_eq!(array[2].as_string().unwrap(), "mouse");
-}
-
-#[test]
-fn test_is_object() {
- let json_value = from_str("{}").unwrap();
- assert!(json_value.is_object());
-}
-
-#[test]
-fn test_as_object() {
- let json_value = from_str("{}").unwrap();
- let json_object = json_value.as_object();
- assert!(json_object.is_some());
-}
-
-#[test]
-fn test_is_array() {
- let json_value = from_str("[1, 2, 3]").unwrap();
- assert!(json_value.is_array());
-}
-
-#[test]
-fn test_as_array() {
- let json_value = from_str("[1, 2, 3]").unwrap();
- let json_array = json_value.as_array();
- let expected_length = 3;
- assert!(json_array.is_some() && json_array.unwrap().len() == expected_length);
-}
-
-#[test]
-fn test_is_string() {
- let json_value = from_str("\"dog\"").unwrap();
- assert!(json_value.is_string());
-}
-
-#[test]
-fn test_as_string() {
- let json_value = from_str("\"dog\"").unwrap();
- let json_str = json_value.as_string();
- let expected_str = "dog";
- assert_eq!(json_str, Some(expected_str));
-}
-
-#[test]
-fn test_is_number() {
- let json_value = from_str("12").unwrap();
- assert!(json_value.is_number());
-}
-
-#[test]
-fn test_is_i64() {
- let json_value = from_str("-12").unwrap();
- assert!(json_value.is_i64());
-
- let json_value = from_str("12").unwrap();
- assert!(!json_value.is_i64());
-
- let json_value = from_str("12.0").unwrap();
- assert!(!json_value.is_i64());
-}
-
-#[test]
-fn test_is_u64() {
- let json_value = from_str("12").unwrap();
- assert!(json_value.is_u64());
-
- let json_value = from_str("-12").unwrap();
- assert!(!json_value.is_u64());
-
- let json_value = from_str("12.0").unwrap();
- assert!(!json_value.is_u64());
-}
-
-#[test]
-fn test_is_f64() {
- let json_value = from_str("12").unwrap();
- assert!(!json_value.is_f64());
-
- let json_value = from_str("-12").unwrap();
- assert!(!json_value.is_f64());
-
- let json_value = from_str("12.0").unwrap();
- assert!(json_value.is_f64());
-
- let json_value = from_str("-12.0").unwrap();
- assert!(json_value.is_f64());
-}
-
-#[test]
-fn test_as_i64() {
- let json_value = from_str("-12").unwrap();
- let json_num = json_value.as_i64();
- assert_eq!(json_num, Some(-12));
-}
-
-#[test]
-fn test_as_u64() {
- let json_value = from_str("12").unwrap();
- let json_num = json_value.as_u64();
- assert_eq!(json_num, Some(12));
-}
-
-#[test]
-fn test_as_f64() {
- let json_value = from_str("12.0").unwrap();
- let json_num = json_value.as_f64();
- assert_eq!(json_num, Some(12f64));
-}
-
-#[test]
-fn test_is_boolean() {
- let json_value = from_str("false").unwrap();
- assert!(json_value.is_boolean());
-}
-
-#[test]
-fn test_as_boolean() {
- let json_value = from_str("false").unwrap();
- let json_bool = json_value.as_boolean();
- let expected_bool = false;
- assert!(json_bool.is_some() && json_bool.unwrap() == expected_bool);
-}
-
-#[test]
-fn test_is_null() {
- let json_value = from_str("null").unwrap();
- assert!(json_value.is_null());
-}
-
-#[test]
-fn test_as_null() {
- let json_value = from_str("null").unwrap();
- let json_null = json_value.as_null();
- let expected_null = ();
- assert!(json_null.is_some() && json_null.unwrap() == expected_null);
-}
-
-#[test]
-fn test_encode_hashmap_with_numeric_key() {
- use std::collections::HashMap;
- use std::str::from_utf8;
- let mut hm: HashMap<usize, bool> = HashMap::new();
- hm.insert(1, true);
- let mut mem_buf = Vec::new();
- write!(&mut mem_buf, "{}", json::as_pretty_json(&hm)).unwrap();
- let json_str = from_utf8(&mem_buf[..]).unwrap();
- match from_str(json_str) {
- Err(_) => panic!("Unable to parse json_str: {:?}", json_str),
- _ => {} // it parsed and we are good to go
- }
-}
-
-#[test]
-fn test_prettyencode_hashmap_with_numeric_key() {
- use std::collections::HashMap;
- use std::str::from_utf8;
- let mut hm: HashMap<usize, bool> = HashMap::new();
- hm.insert(1, true);
- let mut mem_buf = Vec::new();
- write!(&mut mem_buf, "{}", json::as_pretty_json(&hm)).unwrap();
- let json_str = from_utf8(&mem_buf[..]).unwrap();
- match from_str(json_str) {
- Err(_) => panic!("Unable to parse json_str: {:?}", json_str),
- _ => {} // it parsed and we are good to go
- }
-}
-
-#[test]
-fn test_prettyencoder_indent_level_param() {
- use std::collections::BTreeMap;
- use std::str::from_utf8;
-
- let mut tree = BTreeMap::new();
-
- tree.insert("hello".to_string(), String("guten tag".to_string()));
- tree.insert("goodbye".to_string(), String("sayonara".to_string()));
-
- let json = Array(
- // The following layout below should look a lot like
- // the pretty-printed JSON (indent * x)
- vec![
- // 0x
- String("greetings".to_string()), // 1x
- Object(tree), // 1x + 2x + 2x + 1x
- ], // 0x
- // End JSON array (7 lines)
- );
-
- // Helper function for counting indents
- fn indents(source: &str) -> usize {
- let trimmed = source.trim_start_matches(' ');
- source.len() - trimmed.len()
- }
-
- // Test up to 4 spaces of indents (more?)
- for i in 0..4 {
- let mut writer = Vec::new();
- write!(&mut writer, "{}", json::as_pretty_json(&json).indent(i)).unwrap();
-
- let printed = from_utf8(&writer[..]).unwrap();
-
- // Check for indents at each line
- let lines: Vec<&str> = printed.lines().collect();
- assert_eq!(lines.len(), 7); // JSON should be 7 lines
-
- assert_eq!(indents(lines[0]), 0 * i); // [
- assert_eq!(indents(lines[1]), 1 * i); // "greetings",
- assert_eq!(indents(lines[2]), 1 * i); // {
- assert_eq!(indents(lines[3]), 2 * i); // "hello": "guten tag",
- assert_eq!(indents(lines[4]), 2 * i); // "goodbye": "sayonara"
- assert_eq!(indents(lines[5]), 1 * i); // },
- assert_eq!(indents(lines[6]), 0 * i); // ]
-
- // Finally, test that the pretty-printed JSON is valid
- from_str(printed).ok().expect("Pretty-printed JSON is invalid!");
- }
-}
-
-#[test]
-fn test_hashmap_with_enum_key() {
- use std::collections::HashMap;
- #[derive(Encodable, Eq, Hash, PartialEq, Debug)]
- enum Enum {
- Foo,
- #[allow(dead_code)]
- Bar,
- }
- let mut map = HashMap::new();
- map.insert(Enum::Foo, 0);
- let result = json::encode(&map).unwrap();
- assert_eq!(&result[..], r#"{"Foo":0}"#);
-}
-
-fn assert_stream_equal(src: &str, expected: Vec<(JsonEvent, Vec<StackElement<'_>>)>) {
- let mut parser = Parser::new(src.chars());
- let mut i = 0;
- loop {
- let evt = match parser.next() {
- Some(e) => e,
- None => {
- break;
- }
- };
- let (ref expected_evt, ref expected_stack) = expected[i];
- if !parser.stack().is_equal_to(expected_stack) {
- panic!("Parser stack is not equal to {:?}", expected_stack);
- }
- assert_eq!(&evt, expected_evt);
- i += 1;
- }
-}
-#[test]
-fn test_streaming_parser() {
- assert_stream_equal(
- r#"{ "foo":"bar", "array" : [0, 1, 2, 3, 4, 5], "idents":[null,true,false]}"#,
- vec![
- (ObjectStart, vec![]),
- (StringValue("bar".to_string()), vec![StackElement::Key("foo")]),
- (ArrayStart, vec![StackElement::Key("array")]),
- (U64Value(0), vec![StackElement::Key("array"), StackElement::Index(0)]),
- (U64Value(1), vec![StackElement::Key("array"), StackElement::Index(1)]),
- (U64Value(2), vec![StackElement::Key("array"), StackElement::Index(2)]),
- (U64Value(3), vec![StackElement::Key("array"), StackElement::Index(3)]),
- (U64Value(4), vec![StackElement::Key("array"), StackElement::Index(4)]),
- (U64Value(5), vec![StackElement::Key("array"), StackElement::Index(5)]),
- (ArrayEnd, vec![StackElement::Key("array")]),
- (ArrayStart, vec![StackElement::Key("idents")]),
- (NullValue, vec![StackElement::Key("idents"), StackElement::Index(0)]),
- (BooleanValue(true), vec![StackElement::Key("idents"), StackElement::Index(1)]),
- (BooleanValue(false), vec![StackElement::Key("idents"), StackElement::Index(2)]),
- (ArrayEnd, vec![StackElement::Key("idents")]),
- (ObjectEnd, vec![]),
- ],
- );
-}
-fn last_event(src: &str) -> JsonEvent {
- let mut parser = Parser::new(src.chars());
- let mut evt = NullValue;
- loop {
- evt = match parser.next() {
- Some(e) => e,
- None => return evt,
- }
- }
-}
-
-#[test]
-fn test_read_object_streaming() {
- assert_eq!(last_event("{ "), Error(SyntaxError(EOFWhileParsingObject, 1, 3)));
- assert_eq!(last_event("{1"), Error(SyntaxError(KeyMustBeAString, 1, 2)));
- assert_eq!(last_event("{ \"a\""), Error(SyntaxError(EOFWhileParsingObject, 1, 6)));
- assert_eq!(last_event("{\"a\""), Error(SyntaxError(EOFWhileParsingObject, 1, 5)));
- assert_eq!(last_event("{\"a\" "), Error(SyntaxError(EOFWhileParsingObject, 1, 6)));
-
- assert_eq!(last_event("{\"a\" 1"), Error(SyntaxError(ExpectedColon, 1, 6)));
- assert_eq!(last_event("{\"a\":"), Error(SyntaxError(EOFWhileParsingValue, 1, 6)));
- assert_eq!(last_event("{\"a\":1"), Error(SyntaxError(EOFWhileParsingObject, 1, 7)));
- assert_eq!(last_event("{\"a\":1 1"), Error(SyntaxError(InvalidSyntax, 1, 8)));
- assert_eq!(last_event("{\"a\":1,"), Error(SyntaxError(EOFWhileParsingObject, 1, 8)));
- assert_eq!(last_event("{\"a\":1,}"), Error(SyntaxError(TrailingComma, 1, 8)));
-
- assert_stream_equal("{}", vec![(ObjectStart, vec![]), (ObjectEnd, vec![])]);
- assert_stream_equal(
- "{\"a\": 3}",
- vec![
- (ObjectStart, vec![]),
- (U64Value(3), vec![StackElement::Key("a")]),
- (ObjectEnd, vec![]),
- ],
- );
- assert_stream_equal(
- "{ \"a\": null, \"b\" : true }",
- vec![
- (ObjectStart, vec![]),
- (NullValue, vec![StackElement::Key("a")]),
- (BooleanValue(true), vec![StackElement::Key("b")]),
- (ObjectEnd, vec![]),
- ],
- );
- assert_stream_equal(
- "{\"a\" : 1.0 ,\"b\": [ true ]}",
- vec![
- (ObjectStart, vec![]),
- (F64Value(1.0), vec![StackElement::Key("a")]),
- (ArrayStart, vec![StackElement::Key("b")]),
- (BooleanValue(true), vec![StackElement::Key("b"), StackElement::Index(0)]),
- (ArrayEnd, vec![StackElement::Key("b")]),
- (ObjectEnd, vec![]),
- ],
- );
- assert_stream_equal(
- r#"{
- "a": 1.0,
- "b": [
- true,
- "foo\nbar",
- { "c": {"d": null} }
- ]
- }"#,
- vec![
- (ObjectStart, vec![]),
- (F64Value(1.0), vec![StackElement::Key("a")]),
- (ArrayStart, vec![StackElement::Key("b")]),
- (BooleanValue(true), vec![StackElement::Key("b"), StackElement::Index(0)]),
- (
- StringValue("foo\nbar".to_string()),
- vec![StackElement::Key("b"), StackElement::Index(1)],
- ),
- (ObjectStart, vec![StackElement::Key("b"), StackElement::Index(2)]),
- (
- ObjectStart,
- vec![StackElement::Key("b"), StackElement::Index(2), StackElement::Key("c")],
- ),
- (
- NullValue,
- vec![
- StackElement::Key("b"),
- StackElement::Index(2),
- StackElement::Key("c"),
- StackElement::Key("d"),
- ],
- ),
- (
- ObjectEnd,
- vec![StackElement::Key("b"), StackElement::Index(2), StackElement::Key("c")],
- ),
- (ObjectEnd, vec![StackElement::Key("b"), StackElement::Index(2)]),
- (ArrayEnd, vec![StackElement::Key("b")]),
- (ObjectEnd, vec![]),
- ],
- );
-}
-#[test]
-fn test_read_array_streaming() {
- assert_stream_equal("[]", vec![(ArrayStart, vec![]), (ArrayEnd, vec![])]);
- assert_stream_equal("[ ]", vec![(ArrayStart, vec![]), (ArrayEnd, vec![])]);
- assert_stream_equal(
- "[true]",
- vec![
- (ArrayStart, vec![]),
- (BooleanValue(true), vec![StackElement::Index(0)]),
- (ArrayEnd, vec![]),
- ],
- );
- assert_stream_equal(
- "[ false ]",
- vec![
- (ArrayStart, vec![]),
- (BooleanValue(false), vec![StackElement::Index(0)]),
- (ArrayEnd, vec![]),
- ],
- );
- assert_stream_equal(
- "[null]",
- vec![(ArrayStart, vec![]), (NullValue, vec![StackElement::Index(0)]), (ArrayEnd, vec![])],
- );
- assert_stream_equal(
- "[3, 1]",
- vec![
- (ArrayStart, vec![]),
- (U64Value(3), vec![StackElement::Index(0)]),
- (U64Value(1), vec![StackElement::Index(1)]),
- (ArrayEnd, vec![]),
- ],
- );
- assert_stream_equal(
- "\n[3, 2]\n",
- vec![
- (ArrayStart, vec![]),
- (U64Value(3), vec![StackElement::Index(0)]),
- (U64Value(2), vec![StackElement::Index(1)]),
- (ArrayEnd, vec![]),
- ],
- );
- assert_stream_equal(
- "[2, [4, 1]]",
- vec![
- (ArrayStart, vec![]),
- (U64Value(2), vec![StackElement::Index(0)]),
- (ArrayStart, vec![StackElement::Index(1)]),
- (U64Value(4), vec![StackElement::Index(1), StackElement::Index(0)]),
- (U64Value(1), vec![StackElement::Index(1), StackElement::Index(1)]),
- (ArrayEnd, vec![StackElement::Index(1)]),
- (ArrayEnd, vec![]),
- ],
- );
-
- assert_eq!(last_event("["), Error(SyntaxError(EOFWhileParsingValue, 1, 2)));
-
- assert_eq!(from_str("["), Err(SyntaxError(EOFWhileParsingValue, 1, 2)));
- assert_eq!(from_str("[1"), Err(SyntaxError(EOFWhileParsingArray, 1, 3)));
- assert_eq!(from_str("[1,"), Err(SyntaxError(EOFWhileParsingValue, 1, 4)));
- assert_eq!(from_str("[1,]"), Err(SyntaxError(InvalidSyntax, 1, 4)));
- assert_eq!(from_str("[6 7]"), Err(SyntaxError(InvalidSyntax, 1, 4)));
-}
-#[test]
-fn test_trailing_characters_streaming() {
- assert_eq!(last_event("nulla"), Error(SyntaxError(TrailingCharacters, 1, 5)));
- assert_eq!(last_event("truea"), Error(SyntaxError(TrailingCharacters, 1, 5)));
- assert_eq!(last_event("falsea"), Error(SyntaxError(TrailingCharacters, 1, 6)));
- assert_eq!(last_event("1a"), Error(SyntaxError(TrailingCharacters, 1, 2)));
- assert_eq!(last_event("[]a"), Error(SyntaxError(TrailingCharacters, 1, 3)));
- assert_eq!(last_event("{}a"), Error(SyntaxError(TrailingCharacters, 1, 3)));
-}
-#[test]
-fn test_read_identifiers_streaming() {
- assert_eq!(Parser::new("null".chars()).next(), Some(NullValue));
- assert_eq!(Parser::new("true".chars()).next(), Some(BooleanValue(true)));
- assert_eq!(Parser::new("false".chars()).next(), Some(BooleanValue(false)));
-
- assert_eq!(last_event("n"), Error(SyntaxError(InvalidSyntax, 1, 2)));
- assert_eq!(last_event("nul"), Error(SyntaxError(InvalidSyntax, 1, 4)));
- assert_eq!(last_event("t"), Error(SyntaxError(InvalidSyntax, 1, 2)));
- assert_eq!(last_event("truz"), Error(SyntaxError(InvalidSyntax, 1, 4)));
- assert_eq!(last_event("f"), Error(SyntaxError(InvalidSyntax, 1, 2)));
- assert_eq!(last_event("faz"), Error(SyntaxError(InvalidSyntax, 1, 3)));
-}
-
-#[test]
-fn test_to_json() {
- use json::ToJson;
- use std::collections::{BTreeMap, HashMap};
-
- let array2 = Array(vec![U64(1), U64(2)]);
- let array3 = Array(vec![U64(1), U64(2), U64(3)]);
- let object = {
- let mut tree_map = BTreeMap::new();
- tree_map.insert("a".to_string(), U64(1));
- tree_map.insert("b".to_string(), U64(2));
- Object(tree_map)
- };
-
- assert_eq!(array2.to_json(), array2);
- assert_eq!(object.to_json(), object);
- assert_eq!(3_isize.to_json(), I64(3));
- assert_eq!(4_i8.to_json(), I64(4));
- assert_eq!(5_i16.to_json(), I64(5));
- assert_eq!(6_i32.to_json(), I64(6));
- assert_eq!(7_i64.to_json(), I64(7));
- assert_eq!(8_usize.to_json(), U64(8));
- assert_eq!(9_u8.to_json(), U64(9));
- assert_eq!(10_u16.to_json(), U64(10));
- assert_eq!(11_u32.to_json(), U64(11));
- assert_eq!(12_u64.to_json(), U64(12));
- assert_eq!(13.0_f32.to_json(), F64(13.0_f64));
- assert_eq!(14.0_f64.to_json(), F64(14.0_f64));
- assert_eq!(().to_json(), Null);
- assert_eq!(f32::INFINITY.to_json(), Null);
- assert_eq!(f64::NAN.to_json(), Null);
- assert_eq!(true.to_json(), Boolean(true));
- assert_eq!(false.to_json(), Boolean(false));
- assert_eq!("abc".to_json(), String("abc".to_string()));
- assert_eq!("abc".to_string().to_json(), String("abc".to_string()));
- assert_eq!((1_usize, 2_usize).to_json(), array2);
- assert_eq!((1_usize, 2_usize, 3_usize).to_json(), array3);
- assert_eq!([1_usize, 2_usize].to_json(), array2);
- assert_eq!((&[1_usize, 2_usize, 3_usize]).to_json(), array3);
- assert_eq!((vec![1_usize, 2_usize]).to_json(), array2);
- assert_eq!(vec![1_usize, 2_usize, 3_usize].to_json(), array3);
- let mut tree_map = BTreeMap::new();
- tree_map.insert("a".to_string(), 1 as usize);
- tree_map.insert("b".to_string(), 2);
- assert_eq!(tree_map.to_json(), object);
- let mut hash_map = HashMap::new();
- hash_map.insert("a".to_string(), 1 as usize);
- hash_map.insert("b".to_string(), 2);
- assert_eq!(hash_map.to_json(), object);
- assert_eq!(Some(15).to_json(), I64(15));
- assert_eq!(Some(15 as usize).to_json(), U64(15));
- assert_eq!(None::<isize>.to_json(), Null);
-}
-
-#[test]
-fn test_encode_hashmap_with_arbitrary_key() {
- use std::collections::HashMap;
- #[derive(PartialEq, Eq, Hash, Encodable)]
- struct ArbitraryType(usize);
- let mut hm: HashMap<ArbitraryType, bool> = HashMap::new();
- hm.insert(ArbitraryType(1), true);
- let mut mem_buf = string::String::new();
- let mut encoder = Encoder::new(&mut mem_buf);
- let result = hm.encode(&mut encoder);
- match result.unwrap_err() {
- EncoderError::BadHashmapKey => (),
- _ => panic!("expected bad hash map key"),
- }
-}
assert_incr_state: Option<String> = (None, parse_opt_string, [UNTRACKED],
"assert that the incremental cache is in given state: \
either `loaded` or `not-loaded`."),
- ast_json: bool = (false, parse_bool, [UNTRACKED],
- "print the AST as JSON and halt (default: no)"),
- ast_json_noexpand: bool = (false, parse_bool, [UNTRACKED],
- "print the pre-expansion AST as JSON and halt (default: no)"),
binary_dep_depinfo: bool = (false, parse_bool, [TRACKED],
"include artifacts (sysroot, crate dependencies) used during compilation in dep-info \
(default: no)"),
impl<E: Encoder> Encodable<E> for DefId {
default fn encode(&self, s: &mut E) -> Result<(), E::Error> {
- s.emit_struct(false, |s| {
- s.emit_struct_field("krate", true, |s| self.krate.encode(s))?;
-
- s.emit_struct_field("index", false, |s| self.index.encode(s))
- })
+ self.krate.encode(s)?;
+ self.index.encode(s)
}
}
// an added assert statement
impl<S: Encoder> Encodable<S> for RealFileName {
fn encode(&self, encoder: &mut S) -> Result<(), S::Error> {
- encoder.emit_enum(|encoder| match *self {
- RealFileName::LocalPath(ref local_path) => {
- encoder.emit_enum_variant("LocalPath", 0, 1, |encoder| {
- encoder.emit_enum_variant_arg(true, |encoder| local_path.encode(encoder))?;
- Ok(())
+ match *self {
+ RealFileName::LocalPath(ref local_path) => encoder.emit_enum_variant(0, |encoder| {
+ Ok({
+ local_path.encode(encoder)?;
})
- }
+ }),
RealFileName::Remapped { ref local_path, ref virtual_name } => encoder
- .emit_enum_variant("Remapped", 1, 2, |encoder| {
+ .emit_enum_variant(1, |encoder| {
// For privacy and build reproducibility, we must not embed host-dependant path in artifacts
// if they have been remapped by --remap-path-prefix
assert!(local_path.is_none());
- encoder.emit_enum_variant_arg(true, |encoder| local_path.encode(encoder))?;
- encoder.emit_enum_variant_arg(false, |encoder| virtual_name.encode(encoder))?;
+ local_path.encode(encoder)?;
+ virtual_name.encode(encoder)?;
Ok(())
}),
- })
+ }
}
}
impl<E: Encoder> Encodable<E> for Span {
default fn encode(&self, s: &mut E) -> Result<(), E::Error> {
let span = self.data();
- s.emit_struct(false, |s| {
- s.emit_struct_field("lo", true, |s| span.lo.encode(s))?;
- s.emit_struct_field("hi", false, |s| span.hi.encode(s))
- })
+ span.lo.encode(s)?;
+ span.hi.encode(s)
}
}
impl<D: Decoder> Decodable<D> for Span {
}
}
+#[derive(Clone)]
+pub enum SourceFileLines {
+ /// The source file lines, in decoded (random-access) form.
+ Lines(Vec<BytePos>),
+
+ /// The source file lines, in undecoded difference list form.
+ Diffs(SourceFileDiffs),
+}
+
+impl SourceFileLines {
+ pub fn is_lines(&self) -> bool {
+ matches!(self, SourceFileLines::Lines(_))
+ }
+}
+
+/// The source file lines in difference list form. This matches the form
+/// used within metadata, which saves space by exploiting the fact that the
+/// lines list is sorted and individual lines are usually not that long.
+///
+/// We read it directly from metadata and only decode it into `Lines` form
+/// when necessary. This is a significant performance win, especially for
+/// small crates where very little of `std`'s metadata is used.
+#[derive(Clone)]
+pub struct SourceFileDiffs {
+ /// Position of the first line. Note that this is always encoded as a
+ /// `BytePos` because it is often much larger than any of the
+ /// differences.
+ line_start: BytePos,
+
+ /// Always 1, 2, or 4. Always as small as possible, while being big
+ /// enough to hold the length of the longest line in the source file.
+ /// The 1 case is by far the most common.
+ bytes_per_diff: usize,
+
+ /// The number of diffs encoded in `raw_diffs`. Always one less than
+ /// the number of lines in the source file.
+ num_diffs: usize,
+
+ /// The diffs in "raw" form. Each segment of `bytes_per_diff` length
+ /// encodes one little-endian diff. Note that they aren't LEB128
+ /// encoded. This makes for much faster decoding. Besides, the
+ /// bytes_per_diff==1 case is by far the most common, and LEB128
+ /// encoding has no effect on that case.
+ raw_diffs: Vec<u8>,
+}
+
/// A single source in the [`SourceMap`].
#[derive(Clone)]
pub struct SourceFile {
/// The end position of this source in the `SourceMap`.
pub end_pos: BytePos,
/// Locations of lines beginnings in the source code.
- pub lines: Vec<BytePos>,
+ pub lines: Lock<SourceFileLines>,
/// Locations of multi-byte characters in the source code.
pub multibyte_chars: Vec<MultiByteChar>,
/// Width of characters that are not narrow in the source code.
impl<S: Encoder> Encodable<S> for SourceFile {
fn encode(&self, s: &mut S) -> Result<(), S::Error> {
- s.emit_struct(false, |s| {
- s.emit_struct_field("name", true, |s| self.name.encode(s))?;
- s.emit_struct_field("src_hash", false, |s| self.src_hash.encode(s))?;
- s.emit_struct_field("start_pos", false, |s| self.start_pos.encode(s))?;
- s.emit_struct_field("end_pos", false, |s| self.end_pos.encode(s))?;
- s.emit_struct_field("lines", false, |s| {
- let lines = &self.lines[..];
- // Store the length.
- s.emit_u32(lines.len() as u32)?;
-
- if !lines.is_empty() {
- // In order to preserve some space, we exploit the fact that
- // the lines list is sorted and individual lines are
- // probably not that long. Because of that we can store lines
- // as a difference list, using as little space as possible
- // for the differences. But note that the first line is
- // always encoded as a `BytePos` because its position is
- // often much larger than any of the differences.
- let max_line_length = if lines.len() == 1 {
- 0
- } else {
- lines
- .array_windows()
- .map(|&[fst, snd]| snd - fst)
- .map(|bp| bp.to_usize())
- .max()
- .unwrap()
- };
-
- let bytes_per_diff: u8 = match max_line_length {
- 0..=0xFF => 1,
- 0x100..=0xFFFF => 2,
- _ => 4,
- };
-
- // Encode the number of bytes used per diff.
- bytes_per_diff.encode(s)?;
-
- // Encode the first element.
- lines[0].encode(s)?;
-
- let diff_iter = lines.array_windows().map(|&[fst, snd]| snd - fst);
-
- match bytes_per_diff {
- 1 => {
- for diff in diff_iter {
- (diff.0 as u8).encode(s)?
- }
+ self.name.encode(s)?;
+ self.src_hash.encode(s)?;
+ self.start_pos.encode(s)?;
+ self.end_pos.encode(s)?;
+
+ // We are always in `Lines` form by the time we reach here.
+ assert!(self.lines.borrow().is_lines());
+ self.lines(|lines| {
+ // Store the length.
+ s.emit_u32(lines.len() as u32)?;
+
+ // Compute and store the difference list.
+ if lines.len() != 0 {
+ let max_line_length = if lines.len() == 1 {
+ 0
+ } else {
+ lines
+ .array_windows()
+ .map(|&[fst, snd]| snd - fst)
+ .map(|bp| bp.to_usize())
+ .max()
+ .unwrap()
+ };
+
+ let bytes_per_diff: usize = match max_line_length {
+ 0..=0xFF => 1,
+ 0x100..=0xFFFF => 2,
+ _ => 4,
+ };
+
+ // Encode the number of bytes used per diff.
+ s.emit_u8(bytes_per_diff as u8)?;
+
+ // Encode the first element.
+ lines[0].encode(s)?;
+
+ // Encode the difference list.
+ let diff_iter = lines.array_windows().map(|&[fst, snd]| snd - fst);
+ let num_diffs = lines.len() - 1;
+ let mut raw_diffs;
+ match bytes_per_diff {
+ 1 => {
+ raw_diffs = Vec::with_capacity(num_diffs);
+ for diff in diff_iter {
+ raw_diffs.push(diff.0 as u8);
}
- 2 => {
- for diff in diff_iter {
- (diff.0 as u16).encode(s)?
- }
+ }
+ 2 => {
+ raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs);
+ for diff in diff_iter {
+ raw_diffs.extend_from_slice(&(diff.0 as u16).to_le_bytes());
}
- 4 => {
- for diff in diff_iter {
- diff.0.encode(s)?
- }
+ }
+ 4 => {
+ raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs);
+ for diff in diff_iter {
+ raw_diffs.extend_from_slice(&(diff.0 as u32).to_le_bytes());
}
- _ => unreachable!(),
}
+ _ => unreachable!(),
}
+ s.emit_raw_bytes(&raw_diffs)?;
+ }
+ Ok(())
+ })?;
- Ok(())
- })?;
- s.emit_struct_field("multibyte_chars", false, |s| self.multibyte_chars.encode(s))?;
- s.emit_struct_field("non_narrow_chars", false, |s| self.non_narrow_chars.encode(s))?;
- s.emit_struct_field("name_hash", false, |s| self.name_hash.encode(s))?;
- s.emit_struct_field("normalized_pos", false, |s| self.normalized_pos.encode(s))?;
- s.emit_struct_field("cnum", false, |s| self.cnum.encode(s))
- })
+ self.multibyte_chars.encode(s)?;
+ self.non_narrow_chars.encode(s)?;
+ self.name_hash.encode(s)?;
+ self.normalized_pos.encode(s)?;
+ self.cnum.encode(s)
}
}
let src_hash: SourceFileHash = Decodable::decode(d);
let start_pos: BytePos = Decodable::decode(d);
let end_pos: BytePos = Decodable::decode(d);
- let lines: Vec<BytePos> = {
+ let lines = {
let num_lines: u32 = Decodable::decode(d);
- let mut lines = Vec::with_capacity(num_lines as usize);
-
if num_lines > 0 {
// Read the number of bytes used per diff.
- let bytes_per_diff: u8 = Decodable::decode(d);
+ let bytes_per_diff = d.read_u8() as usize;
// Read the first element.
- let mut line_start: BytePos = Decodable::decode(d);
- lines.push(line_start);
-
- match bytes_per_diff {
- 1 => lines.extend((1..num_lines).map(|_| {
- line_start = line_start + BytePos(d.read_u8() as u32);
- line_start
- })),
- 2 => lines.extend((1..num_lines).map(|_| {
- line_start = line_start + BytePos(d.read_u16() as u32);
- line_start
- })),
- 4 => lines.extend((1..num_lines).map(|_| {
- line_start = line_start + BytePos(d.read_u32());
- line_start
- })),
- _ => unreachable!(),
- }
+ let line_start: BytePos = Decodable::decode(d);
+
+ // Read the difference list.
+ let num_diffs = num_lines as usize - 1;
+ let raw_diffs = d.read_raw_bytes(bytes_per_diff * num_diffs).to_vec();
+ SourceFileLines::Diffs(SourceFileDiffs {
+ line_start,
+ bytes_per_diff,
+ num_diffs,
+ raw_diffs,
+ })
+ } else {
+ SourceFileLines::Lines(vec![])
}
-
- lines
};
let multibyte_chars: Vec<MultiByteChar> = Decodable::decode(d);
let non_narrow_chars: Vec<NonNarrowChar> = Decodable::decode(d);
// Unused - the metadata decoder will construct
// a new SourceFile, filling in `external_src` properly
external_src: Lock::new(ExternalSource::Unneeded),
- lines,
+ lines: Lock::new(lines),
multibyte_chars,
non_narrow_chars,
normalized_pos,
external_src: Lock::new(ExternalSource::Unneeded),
start_pos,
end_pos: Pos::from_usize(end_pos),
- lines,
+ lines: Lock::new(SourceFileLines::Lines(lines)),
multibyte_chars,
non_narrow_chars,
normalized_pos,
}
}
+ pub fn lines<F, R>(&self, f: F) -> R
+ where
+ F: FnOnce(&[BytePos]) -> R,
+ {
+ let mut guard = self.lines.borrow_mut();
+ match &*guard {
+ SourceFileLines::Lines(lines) => f(lines),
+ SourceFileLines::Diffs(SourceFileDiffs {
+ mut line_start,
+ bytes_per_diff,
+ num_diffs,
+ raw_diffs,
+ }) => {
+ // Convert from "diffs" form to "lines" form.
+ let num_lines = num_diffs + 1;
+ let mut lines = Vec::with_capacity(num_lines);
+ lines.push(line_start);
+
+ assert_eq!(*num_diffs, raw_diffs.len() / bytes_per_diff);
+ match bytes_per_diff {
+ 1 => {
+ lines.extend(raw_diffs.into_iter().map(|&diff| {
+ line_start = line_start + BytePos(diff as u32);
+ line_start
+ }));
+ }
+ 2 => {
+ lines.extend((0..*num_diffs).map(|i| {
+ let pos = bytes_per_diff * i;
+ let bytes = [raw_diffs[pos], raw_diffs[pos + 1]];
+ let diff = u16::from_le_bytes(bytes);
+ line_start = line_start + BytePos(diff as u32);
+ line_start
+ }));
+ }
+ 4 => {
+ lines.extend((0..*num_diffs).map(|i| {
+ let pos = bytes_per_diff * i;
+ let bytes = [
+ raw_diffs[pos],
+ raw_diffs[pos + 1],
+ raw_diffs[pos + 2],
+ raw_diffs[pos + 3],
+ ];
+ let diff = u32::from_le_bytes(bytes);
+ line_start = line_start + BytePos(diff);
+ line_start
+ }));
+ }
+ _ => unreachable!(),
+ }
+ let res = f(&lines);
+ *guard = SourceFileLines::Lines(lines);
+ res
+ }
+ }
+ }
+
/// Returns the `BytePos` of the beginning of the current line.
pub fn line_begin_pos(&self, pos: BytePos) -> BytePos {
let line_index = self.lookup_line(pos).unwrap();
- self.lines[line_index]
+ self.lines(|lines| lines[line_index])
}
/// Add externally loaded source.
}
let begin = {
- let line = self.lines.get(line_number)?;
- let begin: BytePos = *line - self.start_pos;
+ let line = self.lines(|lines| lines.get(line_number).copied())?;
+ let begin: BytePos = line - self.start_pos;
begin.to_usize()
};
}
pub fn count_lines(&self) -> usize {
- self.lines.len()
+ self.lines(|lines| lines.len())
}
/// Finds the line containing the given position. The return value is the
/// number. If the source_file is empty or the position is located before the
/// first line, `None` is returned.
pub fn lookup_line(&self, pos: BytePos) -> Option<usize> {
- match self.lines.binary_search(&pos) {
+ self.lines(|lines| match lines.binary_search(&pos) {
Ok(idx) => Some(idx),
Err(0) => None,
Err(idx) => Some(idx - 1),
- }
+ })
}
pub fn line_bounds(&self, line_index: usize) -> Range<BytePos> {
return self.start_pos..self.end_pos;
}
- assert!(line_index < self.lines.len());
- if line_index == (self.lines.len() - 1) {
- self.lines[line_index]..self.end_pos
- } else {
- self.lines[line_index]..self.lines[line_index + 1]
- }
+ self.lines(|lines| {
+ assert!(line_index < lines.len());
+ if line_index == (lines.len() - 1) {
+ lines[line_index]..self.end_pos
+ } else {
+ lines[line_index]..lines[line_index + 1]
+ }
+ })
}
/// Returns whether or not the file contains the given `SourceMap` byte
match self.lookup_line(pos) {
Some(a) => {
let line = a + 1; // Line numbers start at 1
- let linebpos = self.lines[a];
+ let linebpos = self.lines(|lines| lines[a]);
let linechpos = self.bytepos_to_file_charpos(linebpos);
let col = chpos - linechpos;
debug!("byte pos {:?} is on the line at byte pos {:?}", pos, linebpos);
let (line, col_or_chpos) = self.lookup_file_pos(pos);
if line > 0 {
let col = col_or_chpos;
- let linebpos = self.lines[line - 1];
+ let linebpos = self.lines(|lines| lines[line - 1]);
let col_display = {
let start_width_idx = self
.non_narrow_chars
name_hash: u128,
source_len: usize,
cnum: CrateNum,
- mut file_local_lines: Vec<BytePos>,
+ file_local_lines: Lock<SourceFileLines>,
mut file_local_multibyte_chars: Vec<MultiByteChar>,
mut file_local_non_narrow_chars: Vec<NonNarrowChar>,
mut file_local_normalized_pos: Vec<NormalizedPos>,
// form rather than pre-computing the offset into a local variable. The
// compiler backend can optimize away the repeated computations in a
// way that won't trigger overflow checks.
- for pos in &mut file_local_lines {
- *pos = (*pos - original_start_pos) + start_pos;
+ match &mut *file_local_lines.borrow_mut() {
+ SourceFileLines::Lines(lines) => {
+ for pos in lines {
+ *pos = (*pos - original_start_pos) + start_pos;
+ }
+ }
+ SourceFileLines::Diffs(SourceFileDiffs { line_start, .. }) => {
+ *line_start = (*line_start - original_start_pos) + start_pos;
+ }
}
for mbc in &mut file_local_multibyte_chars {
mbc.pos = (mbc.pos - original_start_pos) + start_pos;
generator_state,
generators,
generic_arg_infer,
+ generic_assert,
generic_associated_types,
generic_associated_types_extended,
generic_const_exprs,
rustc_allow_const_fn_unstable,
rustc_allow_incoherent_impl,
rustc_attrs,
+ rustc_box,
rustc_builtin_macro,
rustc_capture_analysis,
rustc_clean,
let source = "abcdefghijklm\nabcdefghij\n...".to_owned();
let sf =
SourceFile::new(FileName::Anon(0), source, BytePos(3), SourceFileHashAlgorithm::Sha256);
- assert_eq!(sf.lines.as_slice(), &[BytePos(3), BytePos(17), BytePos(28)]);
+ sf.lines(|lines| assert_eq!(lines, &[BytePos(3), BytePos(17), BytePos(28)]));
assert_eq!(sf.lookup_line(BytePos(0)), None);
assert_eq!(sf.lookup_line(BytePos(3)), Some(0));
[dependencies]
bitflags = "1.2.1"
tracing = "0.1"
+serde_json = "1.0.59"
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_macros = { path = "../rustc_macros" }
rustc_serialize = { path = "../rustc_serialize" }
pub use Integer::*;
pub use Primitive::*;
+use crate::json::{Json, ToJson};
use crate::spec::Target;
use std::convert::{TryFrom, TryInto};
use rustc_data_structures::intern::Interned;
use rustc_index::vec::{Idx, IndexVec};
use rustc_macros::HashStable_Generic;
-use rustc_serialize::json::{Json, ToJson};
pub mod call;
));
}
- if dl.pointer_size.bits() != target.pointer_width.into() {
+ let target_pointer_width: u64 = target.pointer_width.into();
+ if dl.pointer_size.bits() != target_pointer_width {
return Err(format!(
"inconsistent target specification: \"data-layout\" claims \
pointers are {}-bit, while \"target-pointer-width\" is `{}`",
}
/// A pair of alignments, ABI-mandated and preferred.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Encodable, Decodable)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
#[derive(HashStable_Generic)]
pub struct AbiAndPrefAlign {
pub abi: Align,
--- /dev/null
+use std::borrow::Cow;
+use std::collections::BTreeMap;
+
+pub use serde_json::Value as Json;
+use serde_json::{Map, Number};
+
+pub trait ToJson {
+ fn to_json(&self) -> Json;
+}
+
+impl ToJson for Json {
+ fn to_json(&self) -> Json {
+ self.clone()
+ }
+}
+
+macro_rules! to_json_impl_num {
+ ($($t:ty), +) => (
+ $(impl ToJson for $t {
+ fn to_json(&self) -> Json {
+ Json::Number(Number::from(*self))
+ }
+ })+
+ )
+}
+
+to_json_impl_num! { isize, i8, i16, i32, i64, usize, u8, u16, u32, u64 }
+
+impl ToJson for bool {
+ fn to_json(&self) -> Json {
+ Json::Bool(*self)
+ }
+}
+
+impl ToJson for str {
+ fn to_json(&self) -> Json {
+ Json::String(self.to_owned())
+ }
+}
+
+impl ToJson for String {
+ fn to_json(&self) -> Json {
+ Json::String(self.to_owned())
+ }
+}
+
+impl<'a> ToJson for Cow<'a, str> {
+ fn to_json(&self) -> Json {
+ Json::String(self.to_string())
+ }
+}
+
+impl<A: ToJson> ToJson for [A] {
+ fn to_json(&self) -> Json {
+ Json::Array(self.iter().map(|elt| elt.to_json()).collect())
+ }
+}
+
+impl<A: ToJson> ToJson for Vec<A> {
+ fn to_json(&self) -> Json {
+ Json::Array(self.iter().map(|elt| elt.to_json()).collect())
+ }
+}
+
+impl<'a, A: ToJson> ToJson for Cow<'a, [A]>
+where
+ [A]: ToOwned,
+{
+ fn to_json(&self) -> Json {
+ Json::Array(self.iter().map(|elt| elt.to_json()).collect())
+ }
+}
+
+impl<T: ToString, A: ToJson> ToJson for BTreeMap<T, A> {
+ fn to_json(&self) -> Json {
+ let mut d = Map::new();
+ for (key, value) in self {
+ d.insert(key.to_string(), value.to_json());
+ }
+ Json::Object(d)
+ }
+}
+
+impl<A: ToJson> ToJson for Option<A> {
+ fn to_json(&self) -> Json {
+ match *self {
+ None => Json::Null,
+ Some(ref value) => value.to_json(),
+ }
+ }
+}
pub mod abi;
pub mod asm;
+pub mod json;
pub mod spec;
#[cfg(test)]
//! but not gcc's. As a result rustc cannot link with C++ static libraries (#36710)
//! when linking in self-contained mode.
+use crate::json::{Json, ToJson};
use crate::spec::LinkOutputKind;
-use rustc_serialize::json::{Json, ToJson};
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::str::FromStr;
//! to the list specified by the target, rather than replace.
use crate::abi::Endian;
+use crate::json::{Json, ToJson};
use crate::spec::abi::{lookup as lookup_abi, Abi};
use crate::spec::crt_objects::{CrtObjects, CrtObjectsFallback};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_serialize::json::{Json, ToJson};
use rustc_span::symbol::{sym, Symbol};
+use serde_json::Value;
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::convert::TryFrom;
}
}
-#[derive(Clone, Copy, Debug, PartialEq, Hash, Encodable, Decodable)]
+#[derive(Clone, Copy, Debug, PartialEq, Hash)]
pub enum RelroLevel {
Full,
Partial,
}
}
-#[derive(Clone, Copy, Debug, PartialEq, Hash, Encodable, Decodable)]
+#[derive(Clone, Copy, Debug, PartialEq, Hash)]
pub enum MergeFunctions {
Disabled,
Trampolines,
let object = json.as_object().ok_or_else(|| "expected a JSON object")?;
let kind = object
.get("kind")
- .and_then(|o| o.as_string())
+ .and_then(|o| o.as_str())
.ok_or_else(|| "expected `kind` to be a string")?;
match kind {
"none" => Ok(StackProbeType::None),
StackProbeType::Call => {
[(String::from("kind"), "call".to_json())].into_iter().collect()
}
- StackProbeType::InlineOrCall { min_llvm_version_for_inline } => [
+ StackProbeType::InlineOrCall { min_llvm_version_for_inline: (maj, min, patch) } => [
(String::from("kind"), "inline-or-call".to_json()),
(
String::from("min-llvm-version-for-inline"),
- min_llvm_version_for_inline.to_json(),
+ Json::Array(vec![maj.to_json(), min.to_json(), patch.to_json()]),
),
]
.into_iter()
}
/// Loads a target descriptor from a JSON object.
- pub fn from_json(mut obj: Json) -> Result<(Target, TargetWarnings), String> {
+ pub fn from_json(obj: Json) -> Result<(Target, TargetWarnings), String> {
// While ugly, this code must remain this way to retain
// compatibility with existing JSON fields and the internal
// expected naming of the Target and TargetOptions structs.
// are round-tripped through this code to catch cases where
// the JSON parser is not updated to match the structs.
+ let mut obj = match obj {
+ Value::Object(obj) => obj,
+ _ => return Err("Expected JSON object for target")?,
+ };
+
let mut get_req_field = |name: &str| {
- obj.remove_key(name)
- .and_then(|j| Json::as_string(&j).map(str::to_string))
+ obj.remove(name)
+ .and_then(|j| j.as_str().map(str::to_string))
.ok_or_else(|| format!("Field {} in target specification is required", name))
};
macro_rules! key {
($key_name:ident) => ( {
let name = (stringify!($key_name)).replace("_", "-");
- if let Some(s) = obj.remove_key(&name).and_then(|j| Json::as_string(&j).map(str::to_string).map(Cow::from)) {
+ if let Some(s) = obj.remove(&name).and_then(|s| s.as_str().map(str::to_string).map(Cow::from)) {
base.$key_name = s;
}
} );
($key_name:ident = $json_name:expr) => ( {
let name = $json_name;
- if let Some(s) = obj.remove_key(&name).and_then(|j| Json::as_string(&j).map(str::to_string).map(Cow::from)) {
+ if let Some(s) = obj.remove(name).and_then(|s| s.as_str().map(str::to_string).map(Cow::from)) {
base.$key_name = s;
}
} );
($key_name:ident, bool) => ( {
let name = (stringify!($key_name)).replace("_", "-");
- if let Some(s) = obj.remove_key(&name).and_then(|j| Json::as_boolean(&j)) {
+ if let Some(s) = obj.remove(&name).and_then(|b| b.as_bool()) {
base.$key_name = s;
}
} );
($key_name:ident, u64) => ( {
let name = (stringify!($key_name)).replace("_", "-");
- if let Some(s) = obj.remove_key(&name).and_then(|j| Json::as_u64(&j)) {
+ if let Some(s) = obj.remove(&name).and_then(|j| Json::as_u64(&j)) {
base.$key_name = s;
}
} );
($key_name:ident, Option<u32>) => ( {
let name = (stringify!($key_name)).replace("_", "-");
- if let Some(s) = obj.remove_key(&name).and_then(|j| Json::as_u64(&j)) {
+ if let Some(s) = obj.remove(&name).and_then(|b| b.as_u64()) {
if s < 1 || s > 5 {
return Err("Not a valid DWARF version number".into());
}
} );
($key_name:ident, Option<u64>) => ( {
let name = (stringify!($key_name)).replace("_", "-");
- if let Some(s) = obj.remove_key(&name).and_then(|j| Json::as_u64(&j)) {
+ if let Some(s) = obj.remove(&name).and_then(|b| b.as_u64()) {
base.$key_name = Some(s);
}
} );
($key_name:ident, MergeFunctions) => ( {
let name = (stringify!($key_name)).replace("_", "-");
- obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+ obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
match s.parse::<MergeFunctions>() {
Ok(mergefunc) => base.$key_name = mergefunc,
_ => return Some(Err(format!("'{}' is not a valid value for \
} );
($key_name:ident, RelocModel) => ( {
let name = (stringify!($key_name)).replace("_", "-");
- obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+ obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
match s.parse::<RelocModel>() {
Ok(relocation_model) => base.$key_name = relocation_model,
_ => return Some(Err(format!("'{}' is not a valid relocation model. \
} );
($key_name:ident, CodeModel) => ( {
let name = (stringify!($key_name)).replace("_", "-");
- obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+ obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
match s.parse::<CodeModel>() {
Ok(code_model) => base.$key_name = Some(code_model),
_ => return Some(Err(format!("'{}' is not a valid code model. \
} );
($key_name:ident, TlsModel) => ( {
let name = (stringify!($key_name)).replace("_", "-");
- obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+ obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
match s.parse::<TlsModel>() {
Ok(tls_model) => base.$key_name = tls_model,
_ => return Some(Err(format!("'{}' is not a valid TLS model. \
} );
($key_name:ident, PanicStrategy) => ( {
let name = (stringify!($key_name)).replace("_", "-");
- obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+ obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
match s {
"unwind" => base.$key_name = PanicStrategy::Unwind,
"abort" => base.$key_name = PanicStrategy::Abort,
} );
($key_name:ident, RelroLevel) => ( {
let name = (stringify!($key_name)).replace("_", "-");
- obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+ obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
match s.parse::<RelroLevel>() {
Ok(level) => base.$key_name = level,
_ => return Some(Err(format!("'{}' is not a valid value for \
} );
($key_name:ident, SplitDebuginfo) => ( {
let name = (stringify!($key_name)).replace("_", "-");
- obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+ obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
match s.parse::<SplitDebuginfo>() {
Ok(level) => base.$key_name = level,
_ => return Some(Err(format!("'{}' is not a valid value for \
} );
($key_name:ident, list) => ( {
let name = (stringify!($key_name)).replace("_", "-");
- if let Some(j) = obj.remove_key(&name){
- if let Some(v) = Json::as_array(&j) {
+ if let Some(j) = obj.remove(&name) {
+ if let Some(v) = j.as_array() {
base.$key_name = v.iter()
- .map(|a| a.as_string().unwrap().to_string().into())
+ .map(|a| a.as_str().unwrap().to_string().into())
.collect();
} else {
incorrect_type.push(name)
} );
($key_name:ident, opt_list) => ( {
let name = (stringify!($key_name)).replace("_", "-");
- if let Some(j) = obj.remove_key(&name) {
- if let Some(v) = Json::as_array(&j) {
+ if let Some(j) = obj.remove(&name) {
+ if let Some(v) = j.as_array() {
base.$key_name = Some(v.iter()
- .map(|a| a.as_string().unwrap().to_string().into())
+ .map(|a| a.as_str().unwrap().to_string().into())
.collect());
} else {
incorrect_type.push(name)
} );
($key_name:ident, optional) => ( {
let name = (stringify!($key_name)).replace("_", "-");
- if let Some(o) = obj.remove_key(&name[..]) {
+ if let Some(o) = obj.remove(&name) {
base.$key_name = o
- .as_string()
+ .as_str()
.map(|s| s.to_string().into());
}
} );
($key_name:ident, LldFlavor) => ( {
let name = (stringify!($key_name)).replace("_", "-");
- obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+ obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
if let Some(flavor) = LldFlavor::from_str(&s) {
base.$key_name = flavor;
} else {
} );
($key_name:ident, LinkerFlavor) => ( {
let name = (stringify!($key_name)).replace("_", "-");
- obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+ obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
match LinkerFlavor::from_str(s) {
Some(linker_flavor) => base.$key_name = linker_flavor,
_ => return Some(Err(format!("'{}' is not a valid value for linker-flavor. \
} );
($key_name:ident, StackProbeType) => ( {
let name = (stringify!($key_name)).replace("_", "-");
- obj.remove_key(&name[..]).and_then(|o| match StackProbeType::from_json(&o) {
+ obj.remove(&name).and_then(|o| match StackProbeType::from_json(&o) {
Ok(v) => {
base.$key_name = v;
Some(Ok(()))
} );
($key_name:ident, SanitizerSet) => ( {
let name = (stringify!($key_name)).replace("_", "-");
- if let Some(o) = obj.remove_key(&name[..]) {
+ if let Some(o) = obj.remove(&name) {
if let Some(a) = o.as_array() {
for s in a {
- base.$key_name |= match s.as_string() {
+ base.$key_name |= match s.as_str() {
Some("address") => SanitizerSet::ADDRESS,
Some("cfi") => SanitizerSet::CFI,
Some("leak") => SanitizerSet::LEAK,
($key_name:ident, crt_objects_fallback) => ( {
let name = (stringify!($key_name)).replace("_", "-");
- obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+ obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
match s.parse::<CrtObjectsFallback>() {
Ok(fallback) => base.$key_name = Some(fallback),
_ => return Some(Err(format!("'{}' is not a valid CRT objects fallback. \
} );
($key_name:ident, link_objects) => ( {
let name = (stringify!($key_name)).replace("_", "-");
- if let Some(val) = obj.remove_key(&name[..]) {
+ if let Some(val) = obj.remove(&name) {
let obj = val.as_object().ok_or_else(|| format!("{}: expected a \
JSON object with fields per CRT object kind.", name))?;
let mut args = CrtObjects::new();
format!("{}.{}: expected a JSON array", name, k)
)?.iter().enumerate()
.map(|(i,s)| {
- let s = s.as_string().ok_or_else(||
+ let s = s.as_str().ok_or_else(||
format!("{}.{}[{}]: expected a JSON string", name, k, i))?;
Ok(s.to_string().into())
})
} );
($key_name:ident, link_args) => ( {
let name = (stringify!($key_name)).replace("_", "-");
- if let Some(val) = obj.remove_key(&name[..]) {
+ if let Some(val) = obj.remove(&name) {
let obj = val.as_object().ok_or_else(|| format!("{}: expected a \
JSON object with fields per linker-flavor.", name))?;
let mut args = LinkArgs::new();
format!("{}.{}: expected a JSON array", name, k)
)?.iter().enumerate()
.map(|(i,s)| {
- let s = s.as_string().ok_or_else(||
+ let s = s.as_str().ok_or_else(||
format!("{}.{}[{}]: expected a JSON string", name, k, i))?;
Ok(s.to_string().into())
})
} );
($key_name:ident, env) => ( {
let name = (stringify!($key_name)).replace("_", "-");
- if let Some(o) = obj.remove_key(&name[..]) {
+ if let Some(o) = obj.remove(&name) {
if let Some(a) = o.as_array() {
for o in a {
- if let Some(s) = o.as_string() {
+ if let Some(s) = o.as_str() {
let p = s.split('=').collect::<Vec<_>>();
if p.len() == 2 {
let k = p[0].to_string();
} );
($key_name:ident, Option<Abi>) => ( {
let name = (stringify!($key_name)).replace("_", "-");
- obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+ obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
match lookup_abi(s) {
Some(abi) => base.$key_name = Some(abi),
_ => return Some(Err(format!("'{}' is not a valid value for abi", s))),
})).unwrap_or(Ok(()))
} );
($key_name:ident, TargetFamilies) => ( {
- if let Some(value) = obj.remove_key("target-family") {
- if let Some(v) = Json::as_array(&value) {
+ if let Some(value) = obj.remove("target-family") {
+ if let Some(v) = value.as_array() {
base.$key_name = v.iter()
- .map(|a| a.as_string().unwrap().to_string().into())
+ .map(|a| a.as_str().unwrap().to_string().into())
.collect();
- } else if let Some(v) = Json::as_string(&value) {
+ } else if let Some(v) = value.as_str() {
base.$key_name = vec![v.to_string().into()].into();
}
}
} );
}
- if let Some(j) = obj.remove_key("target-endian") {
- if let Some(s) = Json::as_string(&j) {
+ if let Some(j) = obj.remove("target-endian") {
+ if let Some(s) = j.as_str() {
base.endian = s.parse()?;
} else {
incorrect_type.push("target-endian".into())
}
}
- if let Some(fp) = obj.remove_key("frame-pointer") {
- if let Some(s) = Json::as_string(&fp) {
+ if let Some(fp) = obj.remove("frame-pointer") {
+ if let Some(s) = fp.as_str() {
base.frame_pointer = s
.parse()
.map_err(|()| format!("'{}' is not a valid value for frame-pointer", s))?;
// This can cause unfortunate ICEs later down the line.
return Err("may not set is_builtin for targets not built-in".into());
}
- // Each field should have been read using `Json::remove_key` so any keys remaining are unused.
- let remaining_keys = obj.as_object().ok_or("Expected JSON object for target")?.keys();
+ // Each field should have been read using `Json::remove` so any keys remaining are unused.
+ let remaining_keys = obj.keys();
Ok((
base,
TargetWarnings { unused_fields: remaining_keys.cloned().collect(), incorrect_type },
target_triple: &TargetTriple,
sysroot: &Path,
) -> Result<(Target, TargetWarnings), String> {
- use rustc_serialize::json;
use std::env;
use std::fs;
fn load_file(path: &Path) -> Result<(Target, TargetWarnings), String> {
let contents = fs::read_to_string(path).map_err(|e| e.to_string())?;
- let obj = json::from_str(&contents).map_err(|e| e.to_string())?;
+ let obj = serde_json::from_str(&contents).map_err(|e| e.to_string())?;
Target::from_json(obj)
}
impl ToJson for Target {
fn to_json(&self) -> Json {
- let mut d = BTreeMap::new();
+ let mut d = serde_json::Map::new();
let default: TargetOptions = Default::default();
macro_rules! target_val {
use crate::spec::Target;
-use rustc_serialize::json::Json;
-use std::str::FromStr;
#[test]
fn report_unused_fields() {
- let json = Json::from_str(
+ let json = serde_json::from_str(
r#"
{
"arch": "powerpc64",
#[test]
fn report_incorrect_json_type() {
- let json = Json::from_str(
+ let json = serde_json::from_str(
r#"
{
"arch": "powerpc64",
#[test]
fn no_warnings_for_valid_target() {
- let json = Json::from_str(
+ let json = serde_json::from_str(
r#"
{
"arch": "powerpc64",
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
use rustc_middle::hir::map;
use rustc_middle::ty::{
- self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
+ self,
+ subst::{GenericArgKind, SubstsRef},
+ suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, ToPredicate, Ty, TyCtxt,
TypeFoldable,
};
_ => (false, None),
};
+ let generic_args_have_impl_trait = |args: SubstsRef<'tcx>| -> bool {
+ args.iter().any(|arg| match arg.unpack() {
+ GenericArgKind::Type(ty) => match ty.kind() {
+ ty::Param(param) => param.name.as_str().starts_with("impl"),
+ _ => false,
+ },
+ _ => false,
+ })
+ };
+
// FIXME: Add check for trait bound that is already present, particularly `?Sized` so we
// don't suggest `T: Sized + ?Sized`.
let mut hir_id = body_id;
| hir::ItemKind::TraitAlias(generics, _)
| hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }),
..
- }) if !param_ty => {
+ }) if !param_ty
+ && !generic_args_have_impl_trait(trait_pred.skip_binder().trait_ref.substs) =>
+ {
// Missing generic type parameter bound.
let param_name = self_ty.to_string();
let constraint = trait_pred.print_modifiers_and_trait_path().to_string();
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
self_type: Ty<'tcx>,
- cause: ObligationCause<'tcx>,
+ parent_cause: ObligationCause<'tcx>,
) -> Result<(), CopyImplementationError<'tcx>> {
// FIXME: (@jroesch) float this code up
tcx.infer_ctxt().enter(|infcx| {
.ty(tcx, traits::InternalSubsts::identity_for_item(tcx, adt.did()))
.has_param_types_or_consts()
{
- cause.clone()
+ parent_cause.clone()
} else {
ObligationCause::dummy_with_span(span)
};
}
}
-/// Takes the place of a
+/// States returned from `poly_project_and_unify_type`. Takes the place
+/// of the old return type, which was:
+/// ```ignore (not-rust)
/// Result<
/// Result<Option<Vec<PredicateObligation<'tcx>>>, InProgress>,
/// MismatchedProjectionTypes<'tcx>,
/// >
+/// ```
pub(super) enum ProjectAndUnifyResult<'tcx> {
+ /// The projection bound holds subject to the given obligations. If the
+ /// projection cannot be normalized because the required trait bound does
+ /// not hold, this is returned, with `obligations` being a predicate that
+ /// cannot be proven.
Holds(Vec<PredicateObligation<'tcx>>),
+ /// The projection cannot be normalized due to ambiguity. Resolving some
+ /// inference variables in the projection may fix this.
FailedNormalization,
+ /// The project cannot be normalized because `poly_project_and_unify_type`
+ /// is called recursively while normalizing the same projection.
Recursive,
+ // the projection can be normalized, but is not equal to the expected type.
+ // Returns the type error that arose from the mismatch.
MismatchedProjectionTypes(MismatchedProjectionTypes<'tcx>),
}
/// ```
/// If successful, this may result in additional obligations. Also returns
/// the projection cache key used to track these additional obligations.
-///
-/// ## Returns
-///
-/// - `Err(_)`: the projection can be normalized, but is not equal to the
-/// expected type.
-/// - `Ok(Err(InProgress))`: this is called recursively while normalizing
-/// the same projection.
-/// - `Ok(Ok(None))`: The projection cannot be normalized due to ambiguity
-/// (resolving some inference variables in the projection may fix this).
-/// - `Ok(Ok(Some(obligations)))`: The projection bound holds subject to
-/// the given obligations. If the projection cannot be normalized because
-/// the required trait bound doesn't hold this returned with `obligations`
-/// being a predicate that cannot be proven.
#[instrument(level = "debug", skip(selcx))]
pub(super) fn poly_project_and_unify_type<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
body_id: hir::HirId,
trait_ref: &ty::TraitRef<'tcx>,
span: Span,
- item: Option<&'tcx hir::Item<'tcx>>,
+ item: &'tcx hir::Item<'tcx>,
) -> Vec<traits::PredicateObligation<'tcx>> {
- let mut wf =
- WfPredicates { infcx, param_env, body_id, span, out: vec![], recursion_depth: 0, item };
+ let mut wf = WfPredicates {
+ infcx,
+ param_env,
+ body_id,
+ span,
+ out: vec![],
+ recursion_depth: 0,
+ item: Some(item),
+ };
wf.compute_trait_ref(trait_ref, Elaborate::All);
debug!(obligations = ?wf.out);
wf.normalize()
I::AllocId: Encodable<E>,
{
fn encode(&self, e: &mut E) -> Result<(), <E as rustc_serialize::Encoder>::Error> {
- rustc_serialize::Encoder::emit_enum(e, |e| {
- let disc = discriminant(self);
- match self {
- Bool => e.emit_enum_variant("Bool", disc, 0, |_| Ok(())),
- Char => e.emit_enum_variant("Char", disc, 0, |_| Ok(())),
- Int(i) => e.emit_enum_variant("Int", disc, 1, |e| {
- e.emit_enum_variant_arg(true, |e| i.encode(e))?;
- Ok(())
- }),
- Uint(u) => e.emit_enum_variant("Uint", disc, 1, |e| {
- e.emit_enum_variant_arg(true, |e| u.encode(e))?;
- Ok(())
- }),
- Float(f) => e.emit_enum_variant("Float", disc, 1, |e| {
- e.emit_enum_variant_arg(true, |e| f.encode(e))?;
- Ok(())
- }),
- Adt(adt, substs) => e.emit_enum_variant("Adt", disc, 2, |e| {
- e.emit_enum_variant_arg(true, |e| adt.encode(e))?;
- e.emit_enum_variant_arg(false, |e| substs.encode(e))?;
- Ok(())
- }),
- Foreign(def_id) => e.emit_enum_variant("Foreign", disc, 1, |e| {
- e.emit_enum_variant_arg(true, |e| def_id.encode(e))?;
- Ok(())
- }),
- Str => e.emit_enum_variant("Str", disc, 0, |_| Ok(())),
- Array(t, c) => e.emit_enum_variant("Array", disc, 2, |e| {
- e.emit_enum_variant_arg(true, |e| t.encode(e))?;
- e.emit_enum_variant_arg(false, |e| c.encode(e))?;
- Ok(())
- }),
- Slice(t) => e.emit_enum_variant("Slice", disc, 1, |e| {
- e.emit_enum_variant_arg(true, |e| t.encode(e))?;
- Ok(())
- }),
- RawPtr(tam) => e.emit_enum_variant("RawPtr", disc, 1, |e| {
- e.emit_enum_variant_arg(true, |e| tam.encode(e))?;
- Ok(())
- }),
- Ref(r, t, m) => e.emit_enum_variant("Ref", disc, 3, |e| {
- e.emit_enum_variant_arg(true, |e| r.encode(e))?;
- e.emit_enum_variant_arg(false, |e| t.encode(e))?;
- e.emit_enum_variant_arg(false, |e| m.encode(e))?;
- Ok(())
- }),
- FnDef(def_id, substs) => e.emit_enum_variant("FnDef", disc, 2, |e| {
- e.emit_enum_variant_arg(true, |e| def_id.encode(e))?;
- e.emit_enum_variant_arg(false, |e| substs.encode(e))?;
- Ok(())
- }),
- FnPtr(polyfnsig) => e.emit_enum_variant("FnPtr", disc, 1, |e| {
- e.emit_enum_variant_arg(true, |e| polyfnsig.encode(e))?;
- Ok(())
- }),
- Dynamic(l, r) => e.emit_enum_variant("Dynamic", disc, 2, |e| {
- e.emit_enum_variant_arg(true, |e| l.encode(e))?;
- e.emit_enum_variant_arg(false, |e| r.encode(e))?;
- Ok(())
- }),
- Closure(def_id, substs) => e.emit_enum_variant("Closure", disc, 2, |e| {
- e.emit_enum_variant_arg(true, |e| def_id.encode(e))?;
- e.emit_enum_variant_arg(false, |e| substs.encode(e))?;
- Ok(())
- }),
- Generator(def_id, substs, m) => e.emit_enum_variant("Generator", disc, 3, |e| {
- e.emit_enum_variant_arg(true, |e| def_id.encode(e))?;
- e.emit_enum_variant_arg(false, |e| substs.encode(e))?;
- e.emit_enum_variant_arg(false, |e| m.encode(e))?;
- Ok(())
- }),
- GeneratorWitness(b) => e.emit_enum_variant("GeneratorWitness", disc, 1, |e| {
- e.emit_enum_variant_arg(true, |e| b.encode(e))?;
- Ok(())
- }),
- Never => e.emit_enum_variant("Never", disc, 0, |_| Ok(())),
- Tuple(substs) => e.emit_enum_variant("Tuple", disc, 1, |e| {
- e.emit_enum_variant_arg(true, |e| substs.encode(e))?;
- Ok(())
- }),
- Projection(p) => e.emit_enum_variant("Projection", disc, 1, |e| {
- e.emit_enum_variant_arg(true, |e| p.encode(e))?;
- Ok(())
- }),
- Opaque(def_id, substs) => e.emit_enum_variant("Opaque", disc, 2, |e| {
- e.emit_enum_variant_arg(true, |e| def_id.encode(e))?;
- e.emit_enum_variant_arg(false, |e| substs.encode(e))?;
- Ok(())
- }),
- Param(p) => e.emit_enum_variant("Param", disc, 1, |e| {
- e.emit_enum_variant_arg(true, |e| p.encode(e))?;
- Ok(())
- }),
- Bound(d, b) => e.emit_enum_variant("Bound", disc, 2, |e| {
- e.emit_enum_variant_arg(true, |e| d.encode(e))?;
- e.emit_enum_variant_arg(false, |e| b.encode(e))?;
- Ok(())
- }),
- Placeholder(p) => e.emit_enum_variant("Placeholder", disc, 1, |e| {
- e.emit_enum_variant_arg(true, |e| p.encode(e))?;
- Ok(())
- }),
- Infer(i) => e.emit_enum_variant("Infer", disc, 1, |e| {
- e.emit_enum_variant_arg(true, |e| i.encode(e))?;
- Ok(())
- }),
- Error(d) => e.emit_enum_variant("Error", disc, 1, |e| {
- e.emit_enum_variant_arg(true, |e| d.encode(e))?;
- Ok(())
- }),
- }
- })
+ let disc = discriminant(self);
+ match self {
+ Bool => e.emit_enum_variant(disc, |_| Ok(())),
+ Char => e.emit_enum_variant(disc, |_| Ok(())),
+ Int(i) => e.emit_enum_variant(disc, |e| {
+ i.encode(e)?;
+ Ok(())
+ }),
+ Uint(u) => e.emit_enum_variant(disc, |e| {
+ u.encode(e)?;
+ Ok(())
+ }),
+ Float(f) => e.emit_enum_variant(disc, |e| {
+ f.encode(e)?;
+ Ok(())
+ }),
+ Adt(adt, substs) => e.emit_enum_variant(disc, |e| {
+ adt.encode(e)?;
+ substs.encode(e)?;
+ Ok(())
+ }),
+ Foreign(def_id) => e.emit_enum_variant(disc, |e| {
+ def_id.encode(e)?;
+ Ok(())
+ }),
+ Str => e.emit_enum_variant(disc, |_| Ok(())),
+ Array(t, c) => e.emit_enum_variant(disc, |e| {
+ t.encode(e)?;
+ c.encode(e)?;
+ Ok(())
+ }),
+ Slice(t) => e.emit_enum_variant(disc, |e| {
+ t.encode(e)?;
+ Ok(())
+ }),
+ RawPtr(tam) => e.emit_enum_variant(disc, |e| {
+ tam.encode(e)?;
+ Ok(())
+ }),
+ Ref(r, t, m) => e.emit_enum_variant(disc, |e| {
+ r.encode(e)?;
+ t.encode(e)?;
+ m.encode(e)?;
+ Ok(())
+ }),
+ FnDef(def_id, substs) => e.emit_enum_variant(disc, |e| {
+ def_id.encode(e)?;
+ substs.encode(e)?;
+ Ok(())
+ }),
+ FnPtr(polyfnsig) => e.emit_enum_variant(disc, |e| {
+ polyfnsig.encode(e)?;
+ Ok(())
+ }),
+ Dynamic(l, r) => e.emit_enum_variant(disc, |e| {
+ l.encode(e)?;
+ r.encode(e)?;
+ Ok(())
+ }),
+ Closure(def_id, substs) => e.emit_enum_variant(disc, |e| {
+ def_id.encode(e)?;
+ substs.encode(e)?;
+ Ok(())
+ }),
+ Generator(def_id, substs, m) => e.emit_enum_variant(disc, |e| {
+ def_id.encode(e)?;
+ substs.encode(e)?;
+ m.encode(e)?;
+ Ok(())
+ }),
+ GeneratorWitness(b) => e.emit_enum_variant(disc, |e| {
+ b.encode(e)?;
+ Ok(())
+ }),
+ Never => e.emit_enum_variant(disc, |_| Ok(())),
+ Tuple(substs) => e.emit_enum_variant(disc, |e| {
+ substs.encode(e)?;
+ Ok(())
+ }),
+ Projection(p) => e.emit_enum_variant(disc, |e| {
+ p.encode(e)?;
+ Ok(())
+ }),
+ Opaque(def_id, substs) => e.emit_enum_variant(disc, |e| {
+ def_id.encode(e)?;
+ substs.encode(e)?;
+ Ok(())
+ }),
+ Param(p) => e.emit_enum_variant(disc, |e| {
+ p.encode(e)?;
+ Ok(())
+ }),
+ Bound(d, b) => e.emit_enum_variant(disc, |e| {
+ d.encode(e)?;
+ b.encode(e)?;
+ Ok(())
+ }),
+ Placeholder(p) => e.emit_enum_variant(disc, |e| {
+ p.encode(e)?;
+ Ok(())
+ }),
+ Infer(i) => e.emit_enum_variant(disc, |e| {
+ i.encode(e)?;
+ Ok(())
+ }),
+ Error(d) => e.emit_enum_variant(disc, |e| {
+ d.encode(e)?;
+ Ok(())
+ }),
+ }
}
}
use rustc_ast::TraitObjectSyntax;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{
- struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError,
+ struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError, MultiSpan,
};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS};
use rustc_span::edition::Edition;
use rustc_span::lev_distance::find_best_match_for_name;
-use rustc_span::symbol::{Ident, Symbol};
+use rustc_span::symbol::{kw, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
use rustc_target::spec::abi;
use rustc_trait_selection::traits;
span, item_def_id, item_segment
);
if tcx.generics_of(item_def_id).params.is_empty() {
- self.prohibit_generics(slice::from_ref(item_segment));
+ self.prohibit_generics(slice::from_ref(item_segment).iter(), |_| {});
parent_substs
} else {
trait_ref: &hir::TraitRef<'_>,
self_ty: Ty<'tcx>,
) -> ty::TraitRef<'tcx> {
- self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1);
+ self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
self.ast_path_to_mono_trait_ref(
trait_ref.path.span,
let args = trait_segment.args();
let infer_args = trait_segment.infer_args;
- self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1);
+ self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, false);
self.instantiate_poly_trait_ref_inner(
hir_ref_id: hir::HirId,
span: Span,
qself_ty: Ty<'tcx>,
- qself_res: Res,
+ qself: &hir::Ty<'_>,
assoc_segment: &hir::PathSegment<'_>,
permit_variants: bool,
) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> {
let tcx = self.tcx();
let assoc_ident = assoc_segment.ident;
+ let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = qself.kind {
+ path.res
+ } else {
+ Res::Err
+ };
debug!("associated_path_to_ty: {:?}::{}", qself_ty, assoc_ident);
if let Some(variant_def) = variant_def {
if permit_variants {
tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span, None);
- self.prohibit_generics(slice::from_ref(assoc_segment));
+ self.prohibit_generics(slice::from_ref(assoc_segment).iter(), |err| {
+ err.note("enum variants can't have type parameters");
+ let type_name = tcx.item_name(adt_def.did());
+ let msg = format!(
+ "you might have meant to specity type parameters on enum \
+ `{type_name}`"
+ );
+ let Some(args) = assoc_segment.args else { return; };
+ // Get the span of the generics args *including* the leading `::`.
+ let args_span = assoc_segment.ident.span.shrink_to_hi().to(args.span_ext);
+ if tcx.generics_of(adt_def.did()).count() == 0 {
+ // FIXME(estebank): we could also verify that the arguments being
+ // work for the `enum`, instead of just looking if it takes *any*.
+ err.span_suggestion_verbose(
+ args_span,
+ &format!("{type_name} doesn't have generic parameters"),
+ String::new(),
+ Applicability::MachineApplicable,
+ );
+ return;
+ }
+ let Ok(snippet) = tcx.sess.source_map().span_to_snippet(args_span) else {
+ err.note(&msg);
+ return;
+ };
+ let (qself_sugg_span, is_self) = if let hir::TyKind::Path(
+ hir::QPath::Resolved(_, ref path)
+ ) = qself.kind {
+ // If the path segment already has type params, we want to overwrite
+ // them.
+ match &path.segments[..] {
+ // `segment` is the previous to last element on the path,
+ // which would normally be the `enum` itself, while the last
+ // `_` `PathSegment` corresponds to the variant.
+ [.., hir::PathSegment {
+ ident,
+ args,
+ res: Some(Res::Def(DefKind::Enum, _)),
+ ..
+ }, _] => (
+ // We need to include the `::` in `Type::Variant::<Args>`
+ // to point the span to `::<Args>`, not just `<Args>`.
+ ident.span.shrink_to_hi().to(args.map_or(
+ ident.span.shrink_to_hi(),
+ |a| a.span_ext)),
+ false,
+ ),
+ [segment] => (
+ // We need to include the `::` in `Type::Variant::<Args>`
+ // to point the span to `::<Args>`, not just `<Args>`.
+ segment.ident.span.shrink_to_hi().to(segment.args.map_or(
+ segment.ident.span.shrink_to_hi(),
+ |a| a.span_ext)),
+ kw::SelfUpper == segment.ident.name,
+ ),
+ _ => {
+ err.note(&msg);
+ return;
+ }
+ }
+ } else {
+ err.note(&msg);
+ return;
+ };
+ let suggestion = vec![
+ if is_self {
+ // Account for people writing `Self::Variant::<Args>`, where
+ // `Self` is the enum, and suggest replacing `Self` with the
+ // appropriate type: `Type::<Args>::Variant`.
+ (qself.span, format!("{type_name}{snippet}"))
+ } else {
+ (qself_sugg_span, snippet)
+ },
+ (args_span, String::new()),
+ ];
+ err.multipart_suggestion_verbose(
+ &msg,
+ suggestion,
+ Applicability::MaybeIncorrect,
+ );
+ });
return Ok((qself_ty, DefKind::Variant, variant_def.def_id));
} else {
variant_resolution = Some(variant_def.def_id);
self.normalize_ty(span, tcx.mk_projection(item_def_id, item_substs))
}
- pub fn prohibit_generics<'a, T: IntoIterator<Item = &'a hir::PathSegment<'a>>>(
+ pub fn prohibit_generics<'a>(
&self,
- segments: T,
+ segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
+ extend: impl Fn(&mut DiagnosticBuilder<'tcx, ErrorGuaranteed>),
) -> bool {
- let mut has_err = false;
- for segment in segments {
- let (mut err_for_lt, mut err_for_ty, mut err_for_ct) = (false, false, false);
- for arg in segment.args().args {
- let (span, kind) = match arg {
- hir::GenericArg::Lifetime(lt) => {
- if err_for_lt {
- continue;
- }
- err_for_lt = true;
- has_err = true;
- (lt.span, "lifetime")
- }
- hir::GenericArg::Type(ty) => {
- if err_for_ty {
- continue;
- }
- err_for_ty = true;
- has_err = true;
- (ty.span, "type")
- }
- hir::GenericArg::Const(ct) => {
- if err_for_ct {
- continue;
- }
- err_for_ct = true;
- has_err = true;
- (ct.span, "const")
- }
- hir::GenericArg::Infer(inf) => {
- if err_for_ty {
- continue;
- }
- has_err = true;
- err_for_ty = true;
- (inf.span, "generic")
+ let args = segments.clone().flat_map(|segment| segment.args().args);
+ let types_and_spans: Vec<_> = segments
+ .clone()
+ .flat_map(|segment| {
+ segment.res.and_then(|res| {
+ if segment.args().args.is_empty() {
+ None
+ } else {
+ Some((
+ match res {
+ Res::PrimTy(ty) => format!("{} `{}`", res.descr(), ty.name()),
+ Res::Def(_, def_id)
+ if let Some(name) = self.tcx().opt_item_name(def_id) => {
+ format!("{} `{name}`", res.descr())
+ }
+ Res::Err => "this type".to_string(),
+ _ => res.descr().to_string(),
+ },
+ segment.ident.span,
+ ))
}
- };
- let mut err = struct_span_err!(
- self.tcx().sess,
- span,
- E0109,
- "{} arguments are not allowed for this type",
- kind,
- );
- err.span_label(span, format!("{} argument not allowed", kind));
- err.emit();
- if err_for_lt && err_for_ty && err_for_ct {
- break;
- }
+ })
+ })
+ .collect();
+ let this_type = match &types_and_spans[..] {
+ [.., _, (last, _)] => format!(
+ "{} and {last}",
+ types_and_spans[..types_and_spans.len() - 1]
+ .iter()
+ .map(|(x, _)| x.as_str())
+ .intersperse(&", ")
+ .collect::<String>()
+ ),
+ [(only, _)] => only.to_string(),
+ [] => "this type".to_string(),
+ };
+
+ let (lt, ty, ct, inf) =
+ args.clone().fold((false, false, false, false), |(lt, ty, ct, inf), arg| match arg {
+ hir::GenericArg::Lifetime(_) => (true, ty, ct, inf),
+ hir::GenericArg::Type(_) => (lt, true, ct, inf),
+ hir::GenericArg::Const(_) => (lt, ty, true, inf),
+ hir::GenericArg::Infer(_) => (lt, ty, ct, true),
+ });
+ let mut emitted = false;
+ if lt || ty || ct || inf {
+ let arg_spans: Vec<Span> = args.map(|arg| arg.span()).collect();
+
+ let mut kinds = Vec::with_capacity(4);
+ if lt {
+ kinds.push("lifetime");
+ }
+ if ty {
+ kinds.push("type");
+ }
+ if ct {
+ kinds.push("const");
}
+ if inf {
+ kinds.push("generic");
+ }
+ let (kind, s) = match kinds[..] {
+ [.., _, last] => (
+ format!(
+ "{} and {last}",
+ kinds[..kinds.len() - 1]
+ .iter()
+ .map(|&x| x)
+ .intersperse(", ")
+ .collect::<String>()
+ ),
+ "s",
+ ),
+ [only] => (format!("{only}"), ""),
+ [] => unreachable!(),
+ };
+ let last_span = *arg_spans.last().unwrap();
+ let span: MultiSpan = arg_spans.into();
+ let mut err = struct_span_err!(
+ self.tcx().sess,
+ span,
+ E0109,
+ "{kind} arguments are not allowed on {this_type}",
+ );
+ err.span_label(last_span, format!("{kind} argument{s} not allowed"));
+ for (_, span) in types_and_spans {
+ err.span_label(span, "not allowed on this");
+ }
+ extend(&mut err);
+ err.emit();
+ emitted = true;
+ }
+ for segment in segments {
// Only emit the first error to avoid overloading the user with error messages.
if let [binding, ..] = segment.args().bindings {
- has_err = true;
Self::prohibit_assoc_ty_binding(self.tcx(), binding.span);
+ return true;
}
}
- has_err
+ emitted
}
// FIXME(eddyb, varkor) handle type paths here too, not just value ones.
// Check for desugared `impl Trait`.
assert!(ty::is_impl_trait_defn(tcx, did).is_none());
let item_segment = path.segments.split_last().unwrap();
- self.prohibit_generics(item_segment.1);
+ self.prohibit_generics(item_segment.1.iter(), |err| {
+ err.note("`impl Trait` types can't have type parameters");
+ });
let substs = self.ast_path_substs_for_ty(span, did, item_segment.0);
self.normalize_ty(span, tcx.mk_opaque(did, substs))
}
did,
) => {
assert_eq!(opt_self_ty, None);
- self.prohibit_generics(path.segments.split_last().unwrap().1);
+ self.prohibit_generics(path.segments.split_last().unwrap().1.iter(), |_| {});
self.ast_path_to_ty(span, did, path.segments.last().unwrap())
}
Res::Def(kind @ DefKind::Variant, def_id) if permit_variants => {
self.def_ids_for_value_path_segments(path.segments, None, kind, def_id);
let generic_segs: FxHashSet<_> =
path_segs.iter().map(|PathSeg(_, index)| index).collect();
- self.prohibit_generics(path.segments.iter().enumerate().filter_map(
- |(index, seg)| {
+ self.prohibit_generics(
+ path.segments.iter().enumerate().filter_map(|(index, seg)| {
if !generic_segs.contains(&index) { Some(seg) } else { None }
+ }),
+ |err| {
+ err.note("enum variants can't have type parameters");
},
- ));
+ );
let PathSeg(def_id, index) = path_segs.last().unwrap();
self.ast_path_to_ty(span, *def_id, &path.segments[*index])
}
Res::Def(DefKind::TyParam, def_id) => {
assert_eq!(opt_self_ty, None);
- self.prohibit_generics(path.segments);
+ self.prohibit_generics(path.segments.iter(), |err| {
+ if let Some(span) = tcx.def_ident_span(def_id) {
+ let name = tcx.item_name(def_id);
+ err.span_note(span, &format!("type parameter `{name}` defined here"));
+ }
+ });
let def_id = def_id.expect_local();
let item_def_id = tcx.hir().ty_param_owner(def_id);
Res::SelfTy { trait_: Some(_), alias_to: None } => {
// `Self` in trait or type alias.
assert_eq!(opt_self_ty, None);
- self.prohibit_generics(path.segments);
+ self.prohibit_generics(path.segments.iter(), |err| {
+ if let [hir::PathSegment { args: Some(args), ident, .. }] = &path.segments[..] {
+ err.span_suggestion_verbose(
+ ident.span.shrink_to_hi().to(args.span_ext),
+ "the `Self` type doesn't accept type parameters",
+ String::new(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ });
tcx.types.self_param
}
Res::SelfTy { trait_: _, alias_to: Some((def_id, forbid_generic)) } => {
// `Self` in impl (we know the concrete type).
assert_eq!(opt_self_ty, None);
- self.prohibit_generics(path.segments);
// Try to evaluate any array length constants.
let ty = tcx.at(span).type_of(def_id);
+ let span_of_impl = tcx.span_of_impl(def_id);
+ self.prohibit_generics(path.segments.iter(), |err| {
+ let def_id = match *ty.kind() {
+ ty::Adt(self_def, _) => self_def.did(),
+ _ => return,
+ };
+
+ let type_name = tcx.item_name(def_id);
+ let span_of_ty = tcx.def_ident_span(def_id);
+ let generics = tcx.generics_of(def_id).count();
+
+ let msg = format!("`Self` is of type `{ty}`");
+ if let (Ok(i_sp), Some(t_sp)) = (span_of_impl, span_of_ty) {
+ let i_sp = tcx.sess.source_map().guess_head_span(i_sp);
+ let mut span: MultiSpan = vec![t_sp].into();
+ span.push_span_label(
+ i_sp,
+ &format!("`Self` is on type `{type_name}` in this `impl`"),
+ );
+ let mut postfix = "";
+ if generics == 0 {
+ postfix = ", which doesn't have generic parameters";
+ }
+ span.push_span_label(
+ t_sp,
+ &format!("`Self` corresponds to this type{postfix}"),
+ );
+ err.span_note(span, &msg);
+ } else {
+ err.note(&msg);
+ }
+ for segment in path.segments {
+ if let Some(args) = segment.args && segment.ident.name == kw::SelfUpper {
+ if generics == 0 {
+ // FIXME(estebank): we could also verify that the arguments being
+ // work for the `enum`, instead of just looking if it takes *any*.
+ err.span_suggestion_verbose(
+ segment.ident.span.shrink_to_hi().to(args.span_ext),
+ "the `Self` type doesn't accept type parameters",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
+ return;
+ } else {
+ err.span_suggestion_verbose(
+ segment.ident.span,
+ format!(
+ "the `Self` type doesn't accept type parameters, use the \
+ concrete type's name `{type_name}` instead if you want to \
+ specify its type parameters"
+ ),
+ type_name.to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ }
+ });
// HACK(min_const_generics): Forbid generic `Self` types
// here as we can't easily do that during nameres.
//
}
Res::Def(DefKind::AssocTy, def_id) => {
debug_assert!(path.segments.len() >= 2);
- self.prohibit_generics(&path.segments[..path.segments.len() - 2]);
+ self.prohibit_generics(path.segments[..path.segments.len() - 2].iter(), |_| {});
self.qpath_to_ty(
span,
opt_self_ty,
}
Res::PrimTy(prim_ty) => {
assert_eq!(opt_self_ty, None);
- self.prohibit_generics(path.segments);
+ self.prohibit_generics(path.segments.iter(), |err| {
+ let name = prim_ty.name_str();
+ for segment in path.segments {
+ if let Some(args) = segment.args {
+ err.span_suggestion_verbose(
+ segment.ident.span.shrink_to_hi().to(args.span_ext),
+ &format!("primitive type `{name}` doesn't have generic parameters"),
+ String::new(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ });
match prim_ty {
hir::PrimTy::Bool => tcx.types.bool,
hir::PrimTy::Char => tcx.types.char,
hir::TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => {
debug!(?qself, ?segment);
let ty = self.ast_ty_to_ty_inner(qself, false, true);
-
- let res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = qself.kind {
- path.res
- } else {
- Res::Err
- };
- self.associated_path_to_ty(ast_ty.hir_id, ast_ty.span, ty, res, segment, false)
+ self.associated_path_to_ty(ast_ty.hir_id, ast_ty.span, ty, qself, segment, false)
.map(|(ty, _, _)| ty)
.unwrap_or_else(|_| tcx.ty_error())
}
use rustc_attr as attr;
use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
+use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
-use rustc_hir::{def::Res, ItemKind, Node, PathSegment};
+use rustc_hir::{ItemKind, Node, PathSegment};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
use rustc_infer::traits::Obligation;
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
use rustc_ty_utils::representability::{self, Representability};
-use rustc_hir::def::DefKind;
use std::iter;
use std::ops::ControlFlow;
fcx.return_type_pre_known = return_type_pre_known;
let tcx = fcx.tcx;
- let sess = tcx.sess;
let hir = tcx.hir();
let declared_ret_ty = fn_sig.output();
if let Some(panic_impl_did) = tcx.lang_items().panic_impl()
&& panic_impl_did == hir.local_def_id(fn_id).to_def_id()
{
- if let Some(panic_info_did) = tcx.lang_items().panic_info() {
- if *declared_ret_ty.kind() != ty::Never {
- sess.span_err(decl.output.span(), "return type should be `!`");
- }
-
- let inputs = fn_sig.inputs();
- let span = hir.span(fn_id);
- if inputs.len() == 1 {
- let arg_is_panic_info = match *inputs[0].kind() {
- ty::Ref(region, ty, mutbl) => match *ty.kind() {
- ty::Adt(ref adt, _) => {
- adt.did() == panic_info_did
- && mutbl == hir::Mutability::Not
- && !region.is_static()
- }
- _ => false,
- },
- _ => false,
- };
-
- if !arg_is_panic_info {
- sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`");
- }
-
- if let Node::Item(item) = hir.get(fn_id)
- && let ItemKind::Fn(_, ref generics, _) = item.kind
- && !generics.params.is_empty()
- {
- sess.span_err(span, "should have no type parameters");
- }
- } else {
- let span = sess.source_map().guess_head_span(span);
- sess.span_err(span, "function should have one argument");
- }
- } else {
- sess.err("language item required, but not found: `panic_info`");
- }
+ check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty);
}
// Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !`
if let Some(alloc_error_handler_did) = tcx.lang_items().oom()
&& alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id()
{
- if let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() {
- if *declared_ret_ty.kind() != ty::Never {
- sess.span_err(decl.output.span(), "return type should be `!`");
- }
+ check_alloc_error_fn(tcx, alloc_error_handler_did.expect_local(), fn_sig, decl, declared_ret_ty);
+ }
- let inputs = fn_sig.inputs();
- let span = hir.span(fn_id);
- if inputs.len() == 1 {
- let arg_is_alloc_layout = match inputs[0].kind() {
- ty::Adt(ref adt, _) => adt.did() == alloc_layout_did,
- _ => false,
- };
+ (fcx, gen_ty)
+}
- if !arg_is_alloc_layout {
- sess.span_err(decl.inputs[0].span, "argument should be `Layout`");
- }
+fn check_panic_info_fn(
+ tcx: TyCtxt<'_>,
+ fn_id: LocalDefId,
+ fn_sig: ty::FnSig<'_>,
+ decl: &hir::FnDecl<'_>,
+ declared_ret_ty: Ty<'_>,
+) {
+ let Some(panic_info_did) = tcx.lang_items().panic_info() else {
+ tcx.sess.err("language item required, but not found: `panic_info`");
+ return;
+ };
- if let Node::Item(item) = hir.get(fn_id)
- && let ItemKind::Fn(_, ref generics, _) = item.kind
- && !generics.params.is_empty()
- {
- sess.span_err(
- span,
- "`#[alloc_error_handler]` function should have no type parameters",
- );
- }
- } else {
- let span = sess.source_map().guess_head_span(span);
- sess.span_err(span, "function should have one argument");
+ if *declared_ret_ty.kind() != ty::Never {
+ tcx.sess.span_err(decl.output.span(), "return type should be `!`");
+ }
+
+ let span = tcx.def_span(fn_id);
+ let inputs = fn_sig.inputs();
+ if inputs.len() != 1 {
+ let span = tcx.sess.source_map().guess_head_span(span);
+ tcx.sess.span_err(span, "function should have one argument");
+ return;
+ }
+
+ let arg_is_panic_info = match *inputs[0].kind() {
+ ty::Ref(region, ty, mutbl) => match *ty.kind() {
+ ty::Adt(ref adt, _) => {
+ adt.did() == panic_info_did && mutbl == hir::Mutability::Not && !region.is_static()
}
- } else {
- sess.err("language item required, but not found: `alloc_layout`");
- }
+ _ => false,
+ },
+ _ => false,
+ };
+
+ if !arg_is_panic_info {
+ tcx.sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`");
}
- (fcx, gen_ty)
+ let DefKind::Fn = tcx.def_kind(fn_id) else {
+ let span = tcx.def_span(fn_id);
+ tcx.sess.span_err(span, "should be a function");
+ return;
+ };
+
+ let generic_counts = tcx.generics_of(fn_id).own_counts();
+ if generic_counts.types != 0 {
+ let span = tcx.def_span(fn_id);
+ tcx.sess.span_err(span, "should have no type parameters");
+ }
+ if generic_counts.consts != 0 {
+ let span = tcx.def_span(fn_id);
+ tcx.sess.span_err(span, "should have no const parameters");
+ }
+}
+
+fn check_alloc_error_fn(
+ tcx: TyCtxt<'_>,
+ fn_id: LocalDefId,
+ fn_sig: ty::FnSig<'_>,
+ decl: &hir::FnDecl<'_>,
+ declared_ret_ty: Ty<'_>,
+) {
+ let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() else {
+ tcx.sess.err("language item required, but not found: `alloc_layout`");
+ return;
+ };
+
+ if *declared_ret_ty.kind() != ty::Never {
+ tcx.sess.span_err(decl.output.span(), "return type should be `!`");
+ }
+
+ let inputs = fn_sig.inputs();
+ if inputs.len() != 1 {
+ let span = tcx.def_span(fn_id);
+ let span = tcx.sess.source_map().guess_head_span(span);
+ tcx.sess.span_err(span, "function should have one argument");
+ return;
+ }
+
+ let arg_is_alloc_layout = match inputs[0].kind() {
+ ty::Adt(ref adt, _) => adt.did() == alloc_layout_did,
+ _ => false,
+ };
+
+ if !arg_is_alloc_layout {
+ tcx.sess.span_err(decl.inputs[0].span, "argument should be `Layout`");
+ }
+
+ let DefKind::Fn = tcx.def_kind(fn_id) else {
+ let span = tcx.def_span(fn_id);
+ tcx.sess.span_err(span, "`#[alloc_error_handler]` should be a function");
+ return;
+ };
+
+ let generic_counts = tcx.generics_of(fn_id).own_counts();
+ if generic_counts.types != 0 {
+ let span = tcx.def_span(fn_id);
+ tcx.sess.span_err(span, "`#[alloc_error_handler]` function should have no type parameters");
+ }
+ if generic_counts.consts != 0 {
+ let span = tcx.def_span(fn_id);
+ tcx.sess
+ .span_err(span, "`#[alloc_error_handler]` function should have no const parameters");
+ }
}
fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) {
coercion_error.clone(),
fcx,
parent_id,
- expression.map(|expr| (expr, blk_id)),
+ expression,
+ Some(blk_id),
);
if !fcx.tcx.features().unsized_locals {
unsized_return = self.is_return_ty_unsized(fcx, blk_id);
coercion_error.clone(),
fcx,
id,
+ expression,
None,
);
if !fcx.tcx.features().unsized_locals {
ty_err: TypeError<'tcx>,
fcx: &FnCtxt<'a, 'tcx>,
id: hir::HirId,
- expression: Option<(&'tcx hir::Expr<'tcx>, hir::HirId)>,
+ expression: Option<&'tcx hir::Expr<'tcx>>,
+ blk_id: Option<hir::HirId>,
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
let mut err = fcx.report_mismatched_types(cause, expected, found, ty_err);
let mut pointing_at_return_type = false;
let mut fn_output = None;
+ let parent_id = fcx.tcx.hir().get_parent_node(id);
+ let parent = fcx.tcx.hir().get(parent_id);
+ if let Some(expr) = expression
+ && let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(_, _, body_id, ..), .. }) = parent
+ && !matches!(fcx.tcx.hir().get(body_id.hir_id), hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Block(..), .. }))
+ {
+ fcx.suggest_missing_semicolon(&mut err, expr, expected, true);
+ }
// Verify that this is a tail expression of a function, otherwise the
// label pointing out the cause for the type coercion will be wrong
// as prior return coercions would not be relevant (#57664).
- let parent_id = fcx.tcx.hir().get_parent_node(id);
- let fn_decl = if let Some((expr, blk_id)) = expression {
+ let fn_decl = if let (Some(expr), Some(blk_id)) = (expression, blk_id) {
pointing_at_return_type =
fcx.suggest_mismatched_types_on_tail(&mut err, expr, expected, found, blk_id);
- let parent = fcx.tcx.hir().get(parent_id);
if let (Some(cond_expr), true, false) = (
fcx.tcx.hir().get_if_cause(expr.hir_id),
expected.is_unit(),
};
if let Some((fn_decl, can_suggest)) = fn_decl {
- if expression.is_none() {
+ if blk_id.is_none() {
pointing_at_return_type |= fcx.suggest_missing_return_type(
&mut err,
&fn_decl,
let parent_id = fcx.tcx.hir().get_parent_item(id);
let parent_item = fcx.tcx.hir().get_by_def_id(parent_id);
- if let (Some((expr, _)), Some((fn_decl, _, _))) =
- (expression, fcx.get_node_fn_decl(parent_item))
+ if let (Some(expr), Some(_), Some((fn_decl, _, _))) =
+ (expression, blk_id, fcx.get_node_fn_decl(parent_item))
{
fcx.suggest_missing_break_or_return_expr(
&mut err,
_ => None,
})
.collect();
- let spans = impl_item.generics.spans();
- let span = spans.primary_span();
+ let spans = if impl_item.generics.params.is_empty() {
+ vec![impl_item.generics.span]
+ } else {
+ impl_item
+ .generics
+ .params
+ .iter()
+ .filter(|p| {
+ matches!(
+ p.kind,
+ hir::GenericParamKind::Type { .. }
+ | hir::GenericParamKind::Const { .. }
+ )
+ })
+ .map(|p| p.span)
+ .collect::<Vec<Span>>()
+ };
+ let span = spans.first().copied();
let mut err = tcx.sess.struct_span_err_with_code(
spans,
None
}
}),
+ |_| {},
);
if let Res::Local(hid) = res {
QPath::TypeRelative(ref qself, ref segment) => {
let ty = self.to_ty(qself);
- let res = if let hir::TyKind::Path(QPath::Resolved(_, ref path)) = qself.kind {
- path.res
- } else {
- Res::Err
- };
let result = <dyn AstConv<'_>>::associated_path_to_ty(
- self, hir_id, path_span, ty, res, segment, true,
+ self, hir_id, path_span, ty, qself, segment, true,
);
let ty = result.map(|(ty, _, _)| ty).unwrap_or_else(|_| self.tcx().ty_error());
let result = result.map(|(_, kind, def_id)| (kind, def_id));
blk_id: hir::HirId,
) -> bool {
let expr = expr.peel_drop_temps();
- // If the expression is from an external macro, then do not suggest
- // adding a semicolon, because there's nowhere to put it.
- // See issue #81943.
- if expr.can_have_side_effects() && !in_external_macro(self.tcx.sess, expr.span) {
- self.suggest_missing_semicolon(err, expr, expected);
- }
+ self.suggest_missing_semicolon(err, expr, expected, false);
let mut pointing_at_return_type = false;
if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
let fn_id = self.tcx.hir().get_return_block(blk_id).unwrap();
/// This routine checks if the return expression in a block would make sense on its own as a
/// statement and the return type has been left as default or has been specified as `()`. If so,
/// it suggests adding a semicolon.
- fn suggest_missing_semicolon(
+ ///
+ /// If the expression is the expression of a closure without block (`|| expr`), a
+ /// block is needed to be added too (`|| { expr; }`). This is denoted by `needs_block`.
+ pub fn suggest_missing_semicolon(
&self,
err: &mut Diagnostic,
expression: &'tcx hir::Expr<'tcx>,
expected: Ty<'tcx>,
+ needs_block: bool,
) {
if expected.is_unit() {
// `BlockTailExpression` only relevant if the tail expr would be
| ExprKind::If(..)
| ExprKind::Match(..)
| ExprKind::Block(..)
- if expression.can_have_side_effects() =>
+ if expression.can_have_side_effects()
+ // If the expression is from an external macro, then do not suggest
+ // adding a semicolon, because there's nowhere to put it.
+ // See issue #81943.
+ && !in_external_macro(self.tcx.sess, expression.span) =>
{
- err.span_suggestion(
- expression.span.shrink_to_hi(),
- "consider using a semicolon here",
- ";".to_string(),
- Applicability::MachineApplicable,
- );
+ if needs_block {
+ err.multipart_suggestion(
+ "consider using a semicolon here",
+ vec![
+ (expression.span.shrink_to_lo(), "{ ".to_owned()),
+ (expression.span.shrink_to_hi(), "; }".to_owned()),
+ ],
+ Applicability::MachineApplicable,
+ );
+ } else {
+ err.span_suggestion(
+ expression.span.shrink_to_hi(),
+ "consider using a semicolon here",
+ ";".to_string(),
+ Applicability::MachineApplicable,
+ );
+ }
}
_ => (),
}
label_span_not_found(&mut err);
}
- if let SelfSource::MethodCall(expr) = source
- && let Some((fields, substs)) = self.get_field_candidates(span, actual)
- {
- let call_expr =
- self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
- for candidate_field in fields.iter() {
- if let Some(field_path) = self.check_for_nested_field_satisfying(
- span,
- &|_, field_ty| {
- self.lookup_probe(
- span,
- item_name,
- field_ty,
- call_expr,
- ProbeScope::AllTraits,
- )
- .is_ok()
- },
- candidate_field,
- substs,
- vec![],
- self.tcx.parent_module(expr.hir_id).to_def_id(),
- ) {
- let field_path_str = field_path
- .iter()
- .map(|id| id.name.to_ident_string())
- .collect::<Vec<String>>()
- .join(".");
- debug!("field_path_str: {:?}", field_path_str);
+ self.check_for_field_method(&mut err, source, span, actual, item_name);
- err.span_suggestion_verbose(
- item_name.span.shrink_to_lo(),
- "one of the expressions' fields has a method of the same name",
- format!("{field_path_str}."),
- Applicability::MaybeIncorrect,
- );
- }
- }
- }
+ self.check_for_unwrap_self(&mut err, source, span, actual, item_name);
bound_spans.sort();
bound_spans.dedup();
false
}
+ fn check_for_field_method(
+ &self,
+ err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+ source: SelfSource<'tcx>,
+ span: Span,
+ actual: Ty<'tcx>,
+ item_name: Ident,
+ ) {
+ if let SelfSource::MethodCall(expr) = source
+ && let Some((fields, substs)) = self.get_field_candidates(span, actual)
+ {
+ let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
+ for candidate_field in fields.iter() {
+ if let Some(field_path) = self.check_for_nested_field_satisfying(
+ span,
+ &|_, field_ty| {
+ self.lookup_probe(
+ span,
+ item_name,
+ field_ty,
+ call_expr,
+ ProbeScope::AllTraits,
+ )
+ .is_ok()
+ },
+ candidate_field,
+ substs,
+ vec![],
+ self.tcx.parent_module(expr.hir_id).to_def_id(),
+ ) {
+ let field_path_str = field_path
+ .iter()
+ .map(|id| id.name.to_ident_string())
+ .collect::<Vec<String>>()
+ .join(".");
+ debug!("field_path_str: {:?}", field_path_str);
+
+ err.span_suggestion_verbose(
+ item_name.span.shrink_to_lo(),
+ "one of the expressions' fields has a method of the same name",
+ format!("{field_path_str}."),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ }
+ }
+
+ fn check_for_unwrap_self(
+ &self,
+ err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+ source: SelfSource<'tcx>,
+ span: Span,
+ actual: Ty<'tcx>,
+ item_name: Ident,
+ ) {
+ let tcx = self.tcx;
+ let SelfSource::MethodCall(expr) = source else { return; };
+ let call_expr = tcx.hir().expect_expr(tcx.hir().get_parent_node(expr.hir_id));
+
+ let ty::Adt(kind, substs) = actual.kind() else { return; };
+ if !kind.is_enum() {
+ return;
+ }
+
+ let matching_variants: Vec<_> = kind
+ .variants()
+ .iter()
+ .flat_map(|variant| {
+ let [field] = &variant.fields[..] else { return None; };
+ let field_ty = field.ty(tcx, substs);
+
+ // Skip `_`, since that'll just lead to ambiguity.
+ if self.resolve_vars_if_possible(field_ty).is_ty_var() {
+ return None;
+ }
+
+ self.lookup_probe(span, item_name, field_ty, call_expr, ProbeScope::AllTraits)
+ .ok()
+ .map(|pick| (variant, field, pick))
+ })
+ .collect();
+
+ let ret_ty_matches = |diagnostic_item| {
+ if let Some(ret_ty) = self
+ .ret_coercion
+ .as_ref()
+ .map(|c| self.resolve_vars_if_possible(c.borrow().expected_ty()))
+ && let ty::Adt(kind, _) = ret_ty.kind()
+ && tcx.get_diagnostic_item(diagnostic_item) == Some(kind.did())
+ {
+ true
+ } else {
+ false
+ }
+ };
+
+ match &matching_variants[..] {
+ [(_, field, pick)] => {
+ let self_ty = field.ty(tcx, substs);
+ err.span_note(
+ tcx.def_span(pick.item.def_id),
+ &format!("the method `{item_name}` exists on the type `{self_ty}`"),
+ );
+ let (article, kind, variant, question) =
+ if Some(kind.did()) == tcx.get_diagnostic_item(sym::Result) {
+ ("a", "Result", "Err", ret_ty_matches(sym::Result))
+ } else if Some(kind.did()) == tcx.get_diagnostic_item(sym::Option) {
+ ("an", "Option", "None", ret_ty_matches(sym::Option))
+ } else {
+ return;
+ };
+ if question {
+ err.span_suggestion_verbose(
+ expr.span.shrink_to_hi(),
+ format!(
+ "use the `?` operator to extract the `{self_ty}` value, propagating \
+ {article} `{kind}::{variant}` value to the caller"
+ ),
+ "?".to_owned(),
+ Applicability::MachineApplicable,
+ );
+ } else {
+ err.span_suggestion_verbose(
+ expr.span.shrink_to_hi(),
+ format!(
+ "consider using `{kind}::expect` to unwrap the `{self_ty}` value, \
+ panicking if the value is {article} `{kind}::{variant}`"
+ ),
+ ".expect(\"REASON\")".to_owned(),
+ Applicability::HasPlaceholders,
+ );
+ }
+ }
+ // FIXME(compiler-errors): Support suggestions for other matching enum variants
+ _ => {}
+ }
+ }
+
pub(crate) fn note_unmet_impls_on_type(
&self,
err: &mut Diagnostic,
(self.tcx.mk_mut_ref(self.tcx.lifetimes.re_erased, rcvr_ty), "&mut "),
(self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, rcvr_ty), "&"),
] {
- match self.lookup_probe(
- span,
- item_name,
- *rcvr_ty,
- rcvr,
- crate::check::method::probe::ProbeScope::AllTraits,
- ) {
+ match self.lookup_probe(span, item_name, *rcvr_ty, rcvr, ProbeScope::AllTraits) {
Ok(pick) => {
// If the method is defined for the receiver we have, it likely wasn't `use`d.
// We point at the method, but we just skip the rest of the check for arbitrary
(self.tcx.mk_diagnostic_item(*rcvr_ty, sym::Arc), "Arc::new"),
(self.tcx.mk_diagnostic_item(*rcvr_ty, sym::Rc), "Rc::new"),
] {
- if let Some(new_rcvr_t) = *rcvr_ty && let Ok(pick) = self.lookup_probe(
- span,
- item_name,
- new_rcvr_t,
- rcvr,
- crate::check::method::probe::ProbeScope::AllTraits,
- ) {
+ if let Some(new_rcvr_t) = *rcvr_ty
+ && let Ok(pick) = self.lookup_probe(
+ span,
+ item_name,
+ new_rcvr_t,
+ rcvr,
+ ProbeScope::AllTraits,
+ )
+ {
debug!("try_alt_rcvr: pick candidate {:?}", pick);
let did = Some(pick.item.container.id());
// We don't want to suggest a container type when the missing
fcx.body_id,
&trait_ref,
ast_trait_ref.path.span,
- Some(item),
+ item,
);
debug!(?obligations);
for obligation in obligations {
used_trait_imports.extend(imports.iter());
}
- for id in tcx.hir().items() {
- if matches!(tcx.def_kind(id.def_id), DefKind::Use) {
- if tcx.visibility(id.def_id).is_public() {
- continue;
- }
- let item = tcx.hir().item(id);
- if item.span.is_dummy() {
- continue;
- }
- if let hir::ItemKind::Use(path, _) = item.kind {
- check_import(tcx, &mut used_trait_imports, item.item_id(), path.span);
- }
+ for &id in tcx.maybe_unused_trait_imports(()) {
+ debug_assert_eq!(tcx.def_kind(id), DefKind::Use);
+ if tcx.visibility(id).is_public() {
+ continue;
+ }
+ if used_trait_imports.contains(&id) {
+ continue;
}
+ let item = tcx.hir().expect_item(id);
+ if item.span.is_dummy() {
+ continue;
+ }
+ let hir::ItemKind::Use(path, _) = item.kind else { unreachable!() };
+ tcx.struct_span_lint_hir(lint::builtin::UNUSED_IMPORTS, item.hir_id(), path.span, |lint| {
+ let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(path.span) {
+ format!("unused import: `{}`", snippet)
+ } else {
+ "unused import".to_owned()
+ };
+ lint.build(&msg).emit();
+ });
}
unused_crates_lint(tcx);
}
-fn check_import<'tcx>(
- tcx: TyCtxt<'tcx>,
- used_trait_imports: &mut FxHashSet<LocalDefId>,
- item_id: hir::ItemId,
- span: Span,
-) {
- if !tcx.maybe_unused_trait_import(item_id.def_id) {
- return;
- }
-
- if used_trait_imports.contains(&item_id.def_id) {
- return;
- }
-
- tcx.struct_span_lint_hir(lint::builtin::UNUSED_IMPORTS, item_id.hir_id(), span, |lint| {
- let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) {
- format!("unused import: `{}`", snippet)
- } else {
- "unused import".to_owned()
- };
- lint.build(&msg).emit();
- });
-}
-
fn unused_crates_lint(tcx: TyCtxt<'_>) {
let lint = lint::builtin::UNUSED_EXTERN_CRATES;
//! up data structures required by type-checking/codegen.
use crate::errors::{CopyImplOnNonAdt, CopyImplOnTypeWithDtor, DropImplOnWrongItem};
-use rustc_errors::struct_span_err;
+use rustc_errors::{struct_span_err, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::{RegionckMode, TyCtxtInferExt};
use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
-use rustc_middle::ty::TypeFoldable;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeFoldable};
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
use rustc_trait_selection::traits::misc::{can_type_implement_copy, CopyImplementationError};
use rustc_trait_selection::traits::predicate_for_trait_def;
use rustc_trait_selection::traits::{self, ObligationCause, TraitEngine, TraitEngineExt};
+use std::collections::BTreeMap;
pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) {
let lang_items = tcx.lang_items();
E0204,
"the trait `Copy` may not be implemented for this type"
);
+
+ // We'll try to suggest constraining type parameters to fulfill the requirements of
+ // their `Copy` implementation.
+ let mut generics = None;
+ if let ty::Adt(def, _substs) = self_type.kind() {
+ let self_def_id = def.did();
+ if let Some(local) = self_def_id.as_local() {
+ let self_item = tcx.hir().expect_item(local);
+ generics = self_item.kind.generics();
+ }
+ }
+ let mut errors: BTreeMap<_, Vec<_>> = Default::default();
+ let mut bounds = vec![];
+
for (field, ty) in fields {
let field_span = tcx.def_span(field.did);
+ let field_ty_span = match tcx.hir().get_if_local(field.did) {
+ Some(hir::Node::Field(field_def)) => field_def.ty.span,
+ _ => field_span,
+ };
err.span_label(field_span, "this field does not implement `Copy`");
// Spin up a new FulfillmentContext, so we can get the _precise_ reason
// why this field does not implement Copy. This is useful because sometimes
param_env,
ty,
tcx.lang_items().copy_trait().unwrap(),
- traits::ObligationCause::dummy_with_span(field_span),
+ traits::ObligationCause::dummy_with_span(field_ty_span),
);
for error in fulfill_cx.select_all_or_error(&infcx) {
let error_predicate = error.obligation.predicate;
// FIXME: This error could be more descriptive, especially if the error_predicate
// contains a foreign type or if it's a deeply nested type...
if error_predicate != error.root_obligation.predicate {
- err.span_note(
- error.obligation.cause.span,
- &format!(
- "the `Copy` impl for `{}` requires that `{}`",
- ty, error_predicate
- ),
- );
+ errors
+ .entry((ty.to_string(), error_predicate.to_string()))
+ .or_default()
+ .push(error.obligation.cause.span);
+ }
+ if let ty::PredicateKind::Trait(ty::TraitPredicate {
+ trait_ref,
+ polarity: ty::ImplPolarity::Positive,
+ ..
+ }) = error_predicate.kind().skip_binder()
+ {
+ let ty = trait_ref.self_ty();
+ if let ty::Param(_) = ty.kind() {
+ bounds.push((
+ format!("{ty}"),
+ trait_ref.print_only_trait_path().to_string(),
+ Some(trait_ref.def_id),
+ ));
+ }
}
}
});
}
+ for ((ty, error_predicate), spans) in errors {
+ let span: MultiSpan = spans.into();
+ err.span_note(
+ span,
+ &format!("the `Copy` impl for `{}` requires that `{}`", ty, error_predicate),
+ );
+ }
+ if let Some(generics) = generics {
+ suggest_constraining_type_params(
+ tcx,
+ generics,
+ &mut err,
+ bounds.iter().map(|(param, constraint, def_id)| {
+ (param.as_str(), constraint.as_str(), *def_id)
+ }),
+ );
+ }
err.emit();
}
Err(CopyImplementationError::NotAnAdt) => {
E0322,
"explicit impls for the `Pointee` trait are not permitted"
)
- .span_label(span, "impl of 'Pointee' not allowed")
+ .span_label(span, "impl of `Pointee` not allowed")
.emit();
return;
}
E0322,
"explicit impls for the `DiscriminantKind` trait are not permitted"
)
- .span_label(span, "impl of 'DiscriminantKind' not allowed")
+ .span_label(span, "impl of `DiscriminantKind` not allowed")
.emit();
return;
}
E0322,
"explicit impls for the `Sized` trait are not permitted"
)
- .span_label(span, "impl of 'Sized' not allowed")
+ .span_label(span, "impl of `Sized` not allowed")
.emit();
return;
}
fn has_late_bound_regions<'tcx>(
tcx: TyCtxt<'tcx>,
- def_id: LocalDefId,
generics: &'tcx hir::Generics<'tcx>,
decl: &'tcx hir::FnDecl<'tcx>,
) -> Option<Span> {
outer_index: ty::INNERMOST,
has_late_bound_regions: None,
};
- let late_bound_map = tcx.is_late_bound_map(def_id);
- let is_late_bound = |id| {
- let id = tcx.hir().local_def_id(id);
- late_bound_map.map_or(false, |(_, set)| set.contains(&id))
- };
for param in generics.params {
if let GenericParamKind::Lifetime { .. } = param.kind {
- if is_late_bound(param.hir_id) {
+ if tcx.is_late_bound(param.hir_id) {
return Some(param.span);
}
}
match node {
Node::TraitItem(item) => match item.kind {
hir::TraitItemKind::Fn(ref sig, _) => {
- has_late_bound_regions(tcx, item.def_id, &item.generics, sig.decl)
+ has_late_bound_regions(tcx, &item.generics, sig.decl)
}
_ => None,
},
Node::ImplItem(item) => match item.kind {
hir::ImplItemKind::Fn(ref sig, _) => {
- has_late_bound_regions(tcx, item.def_id, &item.generics, sig.decl)
+ has_late_bound_regions(tcx, &item.generics, sig.decl)
}
_ => None,
},
Node::ForeignItem(item) => match item.kind {
hir::ForeignItemKind::Fn(fn_decl, _, ref generics) => {
- has_late_bound_regions(tcx, item.def_id, generics, fn_decl)
+ has_late_bound_regions(tcx, generics, fn_decl)
}
_ => None,
},
Node::Item(item) => match item.kind {
hir::ItemKind::Fn(ref sig, .., ref generics, _) => {
- has_late_bound_regions(tcx, item.def_id, generics, sig.decl)
+ has_late_bound_regions(tcx, generics, sig.decl)
}
_ => None,
},
_ => None,
};
- let mut opt_self = None;
- let mut allow_defaults = false;
-
let no_generics = hir::Generics::empty();
- let ast_generics = match node {
- Node::TraitItem(item) => &item.generics,
-
- Node::ImplItem(item) => &item.generics,
-
+ let ast_generics = node.generics().unwrap_or(&no_generics);
+ let (opt_self, allow_defaults) = match node {
Node::Item(item) => {
match item.kind {
- ItemKind::Fn(.., ref generics, _)
- | ItemKind::Impl(hir::Impl { ref generics, .. }) => generics,
-
- ItemKind::TyAlias(_, ref generics)
- | ItemKind::Enum(_, ref generics)
- | ItemKind::Struct(_, ref generics)
- | ItemKind::OpaqueTy(hir::OpaqueTy { ref generics, .. })
- | ItemKind::Union(_, ref generics) => {
- allow_defaults = true;
- generics
- }
-
- ItemKind::Trait(_, _, ref generics, ..)
- | ItemKind::TraitAlias(ref generics, ..) => {
+ ItemKind::Trait(..) | ItemKind::TraitAlias(..) => {
// Add in the self type parameter.
//
// Something of a hack: use the node id for the trait, also as
// the node id for the Self type parameter.
- let param_id = item.def_id;
-
- opt_self = Some(ty::GenericParamDef {
+ let opt_self = Some(ty::GenericParamDef {
index: 0,
name: kw::SelfUpper,
- def_id: param_id.to_def_id(),
+ def_id,
pure_wrt_drop: false,
kind: ty::GenericParamDefKind::Type {
has_default: false,
},
});
- allow_defaults = true;
- generics
+ (opt_self, true)
}
-
- _ => &no_generics,
+ ItemKind::TyAlias(..)
+ | ItemKind::Enum(..)
+ | ItemKind::Struct(..)
+ | ItemKind::OpaqueTy(..)
+ | ItemKind::Union(..) => (None, true),
+ _ => (None, false),
}
}
-
- Node::ForeignItem(item) => match item.kind {
- ForeignItemKind::Static(..) => &no_generics,
- ForeignItemKind::Fn(_, _, ref generics) => generics,
- ForeignItemKind::Type => &no_generics,
- },
-
- _ => &no_generics,
+ _ => (None, false),
};
let has_self = opt_self.is_some();
params.push(opt_self);
}
- let early_lifetimes = early_bound_lifetimes_from_generics(tcx, hir_id.owner, ast_generics);
+ let early_lifetimes = early_bound_lifetimes_from_generics(tcx, ast_generics);
params.extend(early_lifetimes.enumerate().map(|(i, param)| ty::GenericParamDef {
name: param.name.ident().name,
index: own_start + i as u32,
/// `resolve_lifetime::early_bound_lifetimes`.
fn early_bound_lifetimes_from_generics<'a, 'tcx: 'a>(
tcx: TyCtxt<'tcx>,
- def_id: LocalDefId,
generics: &'a hir::Generics<'a>,
) -> impl Iterator<Item = &'a hir::GenericParam<'a>> + Captures<'tcx> {
- let late_bound_map = if generics.params.is_empty() {
- // This function may be called on `def_id == CRATE_DEF_ID`,
- // which makes `is_late_bound_map` ICE. Don't even try if there
- // is no generic parameter.
- None
- } else {
- tcx.is_late_bound_map(def_id)
- };
- let is_late_bound = move |hir_id| {
- let id = tcx.hir().local_def_id(hir_id);
- late_bound_map.map_or(false, |(_, set)| set.contains(&id))
- };
generics.params.iter().filter(move |param| match param.kind {
- GenericParamKind::Lifetime { .. } => !is_late_bound(param.hir_id),
+ GenericParamKind::Lifetime { .. } => !tcx.is_late_bound(param.hir_id),
_ => false,
})
}
// have to be careful to only iterate over early-bound regions.
let mut index = parent_count
+ has_own_self as u32
- + early_bound_lifetimes_from_generics(tcx, hir_id.owner, ast_generics).count() as u32;
+ + early_bound_lifetimes_from_generics(tcx, ast_generics).count() as u32;
// Collect the predicates that were written inline by the user on each
// type parameter (e.g., `<T: Foo>`).
// We've encountered an `AnonConst` in some path, so we need to
// figure out which generic parameter it corresponds to and return
// the relevant type.
- let filtered = path.segments.iter().find_map(|seg| {
- seg.args?
- .args
+ let Some((arg_index, segment)) = path.segments.iter().find_map(|seg| {
+ let args = seg.args?;
+ args.args
+ .iter()
+ .filter(|arg| arg.is_ty_or_const())
+ .position(|arg| arg.id() == hir_id)
+ .map(|index| (index, seg)).or_else(|| args.bindings
.iter()
- .filter(|arg| arg.is_ty_or_const())
- .position(|arg| arg.id() == hir_id)
- .map(|index| (index, seg))
- });
-
- // FIXME(associated_const_generics): can we blend this with iteration above?
- let (arg_index, segment) = match filtered {
- None => {
- let binding_filtered = path.segments.iter().find_map(|seg| {
- seg.args?
- .bindings
- .iter()
- .filter_map(TypeBinding::opt_const)
- .position(|ct| ct.hir_id == hir_id)
- .map(|idx| (idx, seg))
- });
- match binding_filtered {
- Some(inner) => inner,
- None => {
- tcx.sess.delay_span_bug(
- tcx.def_span(def_id),
- "no arg matching AnonConst in path",
- );
- return None;
- }
- }
- }
- Some(inner) => inner,
+ .filter_map(TypeBinding::opt_const)
+ .position(|ct| ct.hir_id == hir_id)
+ .map(|idx| (idx, seg)))
+ }) else {
+ tcx.sess.delay_span_bug(
+ tcx.def_span(def_id),
+ "no arg matching AnonConst in path",
+ );
+ return None;
};
// Try to use the segment resolution if it is valid, otherwise we
param_names
.iter()
.take(num_params_to_take)
- .map(|p| p.as_str())
+ .map(|def_id| {
+ self.tcx.item_name(def_id.to_def_id()).to_ident_string()
+ })
.collect::<Vec<_>>()
.join(", ")
} else {
# a Nix toolchain on non-NixOS distributions.
#patch-binaries-for-nix = false
+# Collect information and statistics about the current build and writes it to
+# disk. Enabling this or not has no impact on the resulting build output. The
+# schema of the file generated by the build metrics feature is unstable, and
+# this is not intended to be used during local development.
+#metrics = false
+
# =============================================================================
# General install configuration options
# =============================================================================
/// Basic usage:
///
/// ```
- /// # #![feature(toowned_clone_into)]
/// let mut s: String = String::new();
/// "hello".clone_into(&mut s);
///
/// let mut v: Vec<i32> = Vec::new();
/// [1, 2][..].clone_into(&mut v);
/// ```
- #[unstable(feature = "toowned_clone_into", reason = "recently added", issue = "41263")]
+ #[stable(feature = "toowned_clone_into", since = "1.63.0")]
fn clone_into(&self, target: &mut Self::Owned) {
*target = self.to_owned();
}
//! definition is just using `T*` can lead to undefined behavior, as
//! described in [rust-lang/unsafe-code-guidelines#198][ucg#198].
//!
+//! # Considerations for unsafe code
+//!
+//! **Warning: This section is not normative and is subject to change, possibly
+//! being relaxed in the future! It is a simplified summary of the rules
+//! currently implemented in the compiler.**
+//!
+//! The aliasing rules for `Box<T>` are the same as for `&mut T`. `Box<T>`
+//! asserts uniqueness over its content. Using raw pointers derived from a box
+//! after that box has been mutated through, moved or borrowed as `&mut T`
+//! is not allowed. For more guidance on working with box from unsafe code, see
+//! [rust-lang/unsafe-code-guidelines#326][ucg#326].
+//!
+//!
//! [ucg#198]: https://github.com/rust-lang/unsafe-code-guidelines/issues/198
+//! [ucg#326]: https://github.com/rust-lang/unsafe-code-guidelines/issues/326
//! [dereferencing]: core::ops::Deref
//! [`Box::<T>::from_raw(value)`]: Box::from_raw
//! [`Global`]: crate::alloc::Global
/// ```
/// let five = Box::new(5);
/// ```
- #[cfg(not(no_global_oom_handling))]
+ #[cfg(all(not(no_global_oom_handling), not(bootstrap)))]
+ #[inline(always)]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
+ pub fn new(x: T) -> Self {
+ #[rustc_box]
+ Box::new(x)
+ }
+
+ /// Allocates memory on the heap and then places `x` into it.
+ ///
+ /// This doesn't actually allocate if `T` is zero-sized.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let five = Box::new(5);
+ /// ```
+ #[cfg(all(not(no_global_oom_handling), bootstrap))]
#[inline(always)]
#[stable(feature = "rust1", since = "1.0.0")]
#[must_use]
Self::new_zeroed_in(Global)
}
- /// Constructs a new `Pin<Box<T>>`. If `T` does not implement `Unpin`, then
+ /// Constructs a new `Pin<Box<T>>`. If `T` does not implement [`Unpin`], then
/// `x` will be pinned in memory and unable to be moved.
+ ///
+ /// Constructing and pinning of the `Box` can also be done in two steps: `Box::pin(x)`
+ /// does the same as <code>[Box::into_pin]\([Box::new]\(x))</code>. Consider using
+ /// [`into_pin`](Box::into_pin) if you already have a `Box<T>`, or if you want to
+ /// construct a (pinned) `Box` in a different way than with [`Box::new`].
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "pin", since = "1.33.0")]
#[must_use]
#[inline(always)]
pub fn pin(x: T) -> Pin<Box<T>> {
- (box x).into()
+ (#[cfg_attr(not(bootstrap), rustc_box)]
+ Box::new(x))
+ .into()
}
/// Allocates memory on the heap then places `x` into it,
unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) }
}
- /// Constructs a new `Pin<Box<T, A>>`. If `T` does not implement `Unpin`, then
+ /// Constructs a new `Pin<Box<T, A>>`. If `T` does not implement [`Unpin`], then
/// `x` will be pinned in memory and unable to be moved.
+ ///
+ /// Constructing and pinning of the `Box` can also be done in two steps: `Box::pin_in(x, alloc)`
+ /// does the same as <code>[Box::into_pin]\([Box::new_in]\(x, alloc))</code>. Consider using
+ /// [`into_pin`](Box::into_pin) if you already have a `Box<T, A>`, or if you want to
+ /// construct a (pinned) `Box` in a different way than with [`Box::new_in`].
#[cfg(not(no_global_oom_handling))]
#[unstable(feature = "allocator_api", issue = "32838")]
#[rustc_const_unstable(feature = "const_box", issue = "92521")]
unsafe { &mut *mem::ManuallyDrop::new(b).0.as_ptr() }
}
- /// Converts a `Box<T>` into a `Pin<Box<T>>`
+ /// Converts a `Box<T>` into a `Pin<Box<T>>`. If `T` does not implement [`Unpin`], then
+ /// `*boxed` will be pinned in memory and unable to be moved.
///
/// This conversion does not allocate on the heap and happens in place.
///
/// This is also available via [`From`].
- #[unstable(feature = "box_into_pin", issue = "62370")]
+ ///
+ /// Constructing and pinning a `Box` with <code>Box::into_pin([Box::new]\(x))</code>
+ /// can also be written more concisely using <code>[Box::pin]\(x)</code>.
+ /// This `into_pin` method is useful if you already have a `Box<T>`, or you are
+ /// constructing a (pinned) `Box` in a different way than with [`Box::new`].
+ ///
+ /// # Notes
+ ///
+ /// It's not recommended that crates add an impl like `From<Box<T>> for Pin<T>`,
+ /// as it'll introduce an ambiguity when calling `Pin::from`.
+ /// A demonstration of such a poor impl is shown below.
+ ///
+ /// ```compile_fail
+ /// # use std::pin::Pin;
+ /// struct Foo; // A type defined in this crate.
+ /// impl From<Box<()>> for Pin<Foo> {
+ /// fn from(_: Box<()>) -> Pin<Foo> {
+ /// Pin::new(Foo)
+ /// }
+ /// }
+ ///
+ /// let foo = Box::new(());
+ /// let bar = Pin::from(foo);
+ /// ```
+ #[stable(feature = "box_into_pin", since = "1.63.0")]
#[rustc_const_unstable(feature = "const_box", issue = "92521")]
pub const fn into_pin(boxed: Self) -> Pin<Self>
where
A: 'static,
{
// It's not possible to move or replace the insides of a `Pin<Box<T>>`
- // when `T: !Unpin`, so it's safe to pin it directly without any
+ // when `T: !Unpin`, so it's safe to pin it directly without any
// additional requirements.
unsafe { Pin::new_unchecked(boxed) }
}
impl<T: Default> Default for Box<T> {
/// Creates a `Box<T>`, with the `Default` value for T.
fn default() -> Self {
- box T::default()
+ #[cfg_attr(not(bootstrap), rustc_box)]
+ Box::new(T::default())
}
}
where
A: 'static,
{
- /// Converts a `Box<T>` into a `Pin<Box<T>>`
+ /// Converts a `Box<T>` into a `Pin<Box<T>>`. If `T` does not implement [`Unpin`], then
+ /// `*boxed` will be pinned in memory and unable to be moved.
///
/// This conversion does not allocate on the heap and happens in place.
+ ///
+ /// This is also available via [`Box::into_pin`].
+ ///
+ /// Constructing and pinning a `Box` with <code><Pin<Box\<T>>>::from([Box::new]\(x))</code>
+ /// can also be written more concisely using <code>[Box::pin]\(x)</code>.
+ /// This `From` implementation is useful if you already have a `Box<T>`, or you are
+ /// constructing a (pinned) `Box` in a different way than with [`Box::new`].
fn from(boxed: Box<T, A>) -> Self {
Box::into_pin(boxed)
}
/// println!("{boxed:?}");
/// ```
fn from(array: [T; N]) -> Box<[T]> {
- box array
+ #[cfg_attr(not(bootstrap), rustc_box)]
+ Box::new(array)
}
}
}
}
-/// A pointer to type-erased data, guaranteed to have a header `H` before the pointed-to location.
+/// A pointer to type-erased data, guaranteed to either be:
+/// 1. `NonNull::dangling()`, in the case where both the pointee (`T`) and
+/// metadata (`H`) are ZSTs.
+/// 2. A pointer to a valid `T` that has a header `H` directly before the
+/// pointed-to location.
struct WithHeader<H>(NonNull<u8>, PhantomData<H>);
impl<H> WithHeader<H> {
};
unsafe {
- let ptr = alloc::alloc(layout);
-
- if ptr.is_null() {
- alloc::handle_alloc_error(layout);
- }
- // Safety:
- // - The size is at least `aligned_header_size`.
- let ptr = ptr.add(value_offset) as *mut _;
-
- let ptr = NonNull::new_unchecked(ptr);
+ // Note: It's UB to pass a layout with a zero size to `alloc::alloc`, so
+ // we use `layout.dangling()` for this case, which should have a valid
+ // alignment for both `T` and `H`.
+ let ptr = if layout.size() == 0 {
+ // Some paranoia checking, mostly so that the ThinBox tests are
+ // more able to catch issues.
+ debug_assert!(
+ value_offset == 0 && mem::size_of::<T>() == 0 && mem::size_of::<H>() == 0
+ );
+ layout.dangling()
+ } else {
+ let ptr = alloc::alloc(layout);
+ if ptr.is_null() {
+ alloc::handle_alloc_error(layout);
+ }
+ // Safety:
+ // - The size is at least `aligned_header_size`.
+ let ptr = ptr.add(value_offset) as *mut _;
+
+ NonNull::new_unchecked(ptr)
+ };
let result = WithHeader(ptr, PhantomData);
ptr::write(result.header(), header);
}
}
- // Safety:
- // - Assumes that `value` can be dereferenced.
+ // Safety:
+ // - Assumes that either `value` can be dereferenced, or is the
+ // `NonNull::dangling()` we use when both `T` and `H` are ZSTs.
unsafe fn drop<T: ?Sized>(&self, value: *mut T) {
unsafe {
+ let value_layout = Layout::for_value_raw(value);
// SAFETY: Layout must have been computable if we're in drop
- let (layout, value_offset) =
- Self::alloc_layout(Layout::for_value_raw(value)).unwrap_unchecked();
+ let (layout, value_offset) = Self::alloc_layout(value_layout).unwrap_unchecked();
- ptr::drop_in_place::<T>(value);
// We only drop the value because the Pointee trait requires that the metadata is copy
- // aka trivially droppable
- alloc::dealloc(self.0.as_ptr().sub(value_offset), layout);
+ // aka trivially droppable.
+ ptr::drop_in_place::<T>(value);
+
+ // Note: Don't deallocate if the layout size is zero, because the pointer
+ // didn't come from the allocator.
+ if layout.size() != 0 {
+ alloc::dealloc(self.0.as_ptr().sub(value_offset), layout);
+ } else {
+ debug_assert!(
+ value_offset == 0 && mem::size_of::<H>() == 0 && value_layout.size() == 0
+ );
+ }
}
}
// needed to align the header. Subtracting the header size from the aligned data pointer
// will always result in an aligned header pointer, it just may not point to the
// beginning of the allocation.
- unsafe { self.0.as_ptr().sub(Self::header_size()) as *mut H }
+ let hp = unsafe { self.0.as_ptr().sub(Self::header_size()) as *mut H };
+ debug_assert!(hp.is_aligned());
+ hp
}
fn value(&self) -> *mut u8 {
/// item's ordering relative to any other item, as determined by the [`Ord`]
/// trait, changes while it is in the heap. This is normally only possible
/// through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. The
-/// behavior resulting from such a logic error is not specified (it
-/// could include panics, incorrect results, aborts, memory leaks, or
-/// non-termination) but will not be undefined behavior.
+/// behavior resulting from such a logic error is not specified, but will
+/// be encapsulated to the `BinaryHeap` that observed the logic error and not
+/// result in undefined behavior. This could include panics, incorrect results,
+/// aborts, memory leaks, and non-termination.
///
/// # Examples
///
/// It is a logic error for a key to be modified in such a way that the key's ordering relative to
/// any other key, as determined by the [`Ord`] trait, changes while it is in the map. This is
/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
-/// The behavior resulting from such a logic error is not specified (it could include panics,
-/// incorrect results, aborts, memory leaks, or non-termination) but will not be undefined
-/// behavior.
+/// The behavior resulting from such a logic error is not specified, but will be encapsulated to the
+/// `BTreeMap` that observed the logic error and not result in undefined behavior. This could
+/// include panics, incorrect results, aborts, memory leaks, and non-termination.
///
/// Iterators obtained from functions such as [`BTreeMap::iter`], [`BTreeMap::values`], or
/// [`BTreeMap::keys`] produce their items in order by key, and take worst-case logarithmic and
/// It is a logic error for an item to be modified in such a way that the item's ordering relative
/// to any other item, as determined by the [`Ord`] trait, changes while it is in the set. This is
/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
-/// The behavior resulting from such a logic error is not specified (it could include panics,
-/// incorrect results, aborts, memory leaks, or non-termination) but will not be undefined
-/// behavior.
+/// The behavior resulting from such a logic error is not specified, but will be encapsulated to the
+/// `BTreeSet` that observed the logic error and not result in undefined behavior. This could
+/// include panics, incorrect results, aborts, memory leaks, and non-termination.
///
/// Iterators returned by [`BTreeSet::iter`] produce their items in order, and take worst-case
/// logarithmic and amortized constant time per item returned.
/// Adds a value to the set.
///
- /// If the set did not have an equal element present, `true` is returned.
+ /// Returns whether the value was newly inserted. That is:
///
- /// If the set did have an equal element present, `false` is returned, and
- /// the entry is not updated. See the [module-level documentation] for more.
+ /// - If the set did not previously contain an equal value, `true` is
+ /// returned.
+ /// - If the set already contained an equal value, `false` is returned, and
+ /// the entry is not updated.
+ ///
+ /// See the [module-level documentation] for more.
///
/// [module-level documentation]: index.html#insert-and-complex-keys
///
#![feature(ptr_sub_ptr)]
#![feature(receiver_trait)]
#![feature(set_ptr_value)]
+#![feature(slice_from_ptr_range)]
#![feature(slice_group_by)]
#![feature(slice_ptr_get)]
#![feature(slice_ptr_len)]
#![feature(allocator_internals)]
#![feature(allow_internal_unstable)]
#![feature(associated_type_bounds)]
-#![feature(box_syntax)]
+#![cfg_attr(bootstrap, feature(box_syntax))]
#![feature(cfg_sanitize)]
#![feature(const_deref)]
#![feature(const_mut_refs)]
#![feature(nll)] // Not necessary, but here to test the `nll` feature.
#![feature(rustc_allow_const_fn_unstable)]
#![feature(rustc_attrs)]
+#![feature(pointer_is_aligned)]
#![feature(slice_internals)]
#![feature(staged_api)]
+#![feature(stmt_expr_attributes)]
#![cfg_attr(test, feature(test))]
#![feature(unboxed_closures)]
#![feature(unsized_fn_params)]
/// be mindful of side effects.
///
/// [`Vec`]: crate::vec::Vec
-#[cfg(all(not(no_global_oom_handling), not(test)))]
+#[cfg(all(not(no_global_oom_handling), not(test), not(bootstrap)))]
+#[macro_export]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_diagnostic_item = "vec_macro"]
+#[allow_internal_unstable(rustc_attrs, liballoc_internals)]
+macro_rules! vec {
+ () => (
+ $crate::__rust_force_expr!($crate::vec::Vec::new())
+ );
+ ($elem:expr; $n:expr) => (
+ $crate::__rust_force_expr!($crate::vec::from_elem($elem, $n))
+ );
+ ($($x:expr),+ $(,)?) => (
+ $crate::__rust_force_expr!(<[_]>::into_vec(
+ #[rustc_box]
+ $crate::boxed::Box::new([$($x),+])
+ ))
+ );
+}
+
+/// Creates a `Vec` containing the arguments (bootstrap version).
+#[cfg(all(not(no_global_oom_handling), not(test), bootstrap))]
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "vec_macro"]
$crate::vec::from_elem($elem, $n)
);
($($x:expr),*) => (
- $crate::slice::into_vec(box [$($x),*])
+ $crate::slice::into_vec($crate::boxed::Box::new([$($x),*]))
);
($($x:expr,)*) => (vec![$($x),*])
}
pub use core::slice::SliceIndex;
#[stable(feature = "from_ref", since = "1.28.0")]
pub use core::slice::{from_mut, from_ref};
+#[unstable(feature = "slice_from_ptr_range", issue = "89792")]
+pub use core::slice::{from_mut_ptr_range, from_ptr_range};
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::slice::{from_raw_parts, from_raw_parts_mut};
#[stable(feature = "rust1", since = "1.0.0")]
/// referred to as clone-on-write.
///
/// However, if there are no other `Arc` pointers to this allocation, but some [`Weak`]
- /// pointers, then the [`Weak`] pointers will be disassociated and the inner value will not
+ /// pointers, then the [`Weak`] pointers will be dissociated and the inner value will not
/// be cloned.
///
/// See also [`get_mut`], which will fail rather than cloning the inner value
- /// or diassociating [`Weak`] pointers.
+ /// or dissociating [`Weak`] pointers.
///
/// [`clone`]: Clone::clone
/// [`get_mut`]: Arc::get_mut
/// assert_eq!(*other_data, 12);
/// ```
///
- /// [`Weak`] pointers will be disassociated:
+ /// [`Weak`] pointers will be dissociated:
///
/// ```
/// use std::sync::Arc;
self
}
- /// Returns a raw pointer to the vector's buffer.
+ /// Returns a raw pointer to the vector's buffer, or a dangling raw pointer
+ /// valid for zero sized reads if the vector didn't allocate.
///
/// The caller must ensure that the vector outlives the pointer this
/// function returns, or else it will end up pointing to garbage.
ptr
}
- /// Returns an unsafe mutable pointer to the vector's buffer.
+ /// Returns an unsafe mutable pointer to the vector's buffer, or a dangling
+ /// raw pointer valid for zero sized reads if the vector didn't allocate.
///
/// The caller must ensure that the vector outlives the pointer this
/// function returns, or else it will end up pointing to garbage.
// SAFETY:
// - Both pointers are created from unique slice references (`&mut [_]`)
// so they are valid and do not overlap.
- // - Elements are :Copy so it's OK to to copy them, without doing
+ // - Elements are :Copy so it's OK to copy them, without doing
// anything with the original values
// - `count` is equal to the len of `source`, so source is valid for
// `count` reads
impl<T, A: Allocator> ops::Deref for Vec<T, A> {
type Target = [T];
+ #[inline]
fn deref(&self) -> &[T] {
unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, A: Allocator> ops::DerefMut for Vec<T, A> {
+ #[inline]
fn deref_mut(&mut self) -> &mut [T] {
unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
}
/// ```
#[cfg(not(test))]
fn from(s: [T; N]) -> Vec<T> {
- <[T]>::into_vec(box s)
+ <[T]>::into_vec(
+ #[cfg_attr(not(bootstrap), rustc_box)]
+ Box::new(s),
+ )
}
#[cfg(test)]
fn from(s: [T; N]) -> Vec<T> {
- crate::slice::into_vec(box s)
+ crate::slice::into_vec(Box::new(s))
}
}
#![feature(panic_update_hook)]
#![feature(slice_flatten)]
#![feature(thin_box)]
+#![feature(bench_black_box)]
+#![feature(strict_provenance)]
+#![feature(once_cell)]
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
+use core::fmt::Debug;
use core::mem::size_of;
use std::boxed::ThinBox;
assert!(is_thin::<[i32]>());
assert!(is_thin::<i32>());
}
+
+#[track_caller]
+fn verify_aligned<T>(ptr: *const T) {
+ // Use `black_box` to attempt to obscure the fact that we're calling this
+ // function on pointers that come from box/references, which the compiler
+ // would otherwise realize is impossible (because it would mean we've
+ // already executed UB).
+ //
+ // That is, we'd *like* it to be possible for the asserts in this function
+ // to detect brokenness in the ThinBox impl.
+ //
+ // It would probably be better if we instead had these as debug_asserts
+ // inside `ThinBox`, prior to the point where we do the UB. Anyway, in
+ // practice these checks are mostly just smoke-detectors for an extremely
+ // broken `ThinBox` impl, since it's an extremely subtle piece of code.
+ let ptr = core::hint::black_box(ptr);
+ let align = core::mem::align_of::<T>();
+ assert!(
+ (ptr.addr() & (align - 1)) == 0 && !ptr.is_null(),
+ "misaligned ThinBox data; valid pointers to `{}` should be aligned to {align}: {ptr:p}",
+ core::any::type_name::<T>(),
+ );
+}
+
+#[track_caller]
+fn check_thin_sized<T: Debug + PartialEq + Clone>(make: impl FnOnce() -> T) {
+ let value = make();
+ let boxed = ThinBox::new(value.clone());
+ let val = &*boxed;
+ verify_aligned(val as *const T);
+ assert_eq!(val, &value);
+}
+
+#[track_caller]
+fn check_thin_dyn<T: Debug + PartialEq + Clone>(make: impl FnOnce() -> T) {
+ let value = make();
+ let wanted_debug = format!("{value:?}");
+ let boxed: ThinBox<dyn Debug> = ThinBox::new_unsize(value.clone());
+ let val = &*boxed;
+ // wide reference -> wide pointer -> thin pointer
+ verify_aligned(val as *const dyn Debug as *const T);
+ let got_debug = format!("{val:?}");
+ assert_eq!(wanted_debug, got_debug);
+}
+
+macro_rules! define_test {
+ (
+ @test_name: $testname:ident;
+
+ $(#[$m:meta])*
+ struct $Type:ident($inner:ty);
+
+ $($test_stmts:tt)*
+ ) => {
+ #[test]
+ fn $testname() {
+ use core::sync::atomic::{AtomicIsize, Ordering};
+ // Define the type, and implement new/clone/drop in such a way that
+ // the number of live instances will be counted.
+ $(#[$m])*
+ #[derive(Debug, PartialEq)]
+ struct $Type {
+ _priv: $inner,
+ }
+
+ impl Clone for $Type {
+ fn clone(&self) -> Self {
+ verify_aligned(self);
+ Self::new(self._priv.clone())
+ }
+ }
+
+ impl Drop for $Type {
+ fn drop(&mut self) {
+ verify_aligned(self);
+ Self::modify_live(-1);
+ }
+ }
+
+ impl $Type {
+ fn new(i: $inner) -> Self {
+ Self::modify_live(1);
+ Self { _priv: i }
+ }
+
+ fn modify_live(n: isize) -> isize {
+ static COUNTER: AtomicIsize = AtomicIsize::new(0);
+ COUNTER.fetch_add(n, Ordering::Relaxed) + n
+ }
+
+ fn live_objects() -> isize {
+ Self::modify_live(0)
+ }
+ }
+ // Run the test statements
+ let _: () = { $($test_stmts)* };
+ // Check that we didn't leak anything, or call drop too many times.
+ assert_eq!(
+ $Type::live_objects(), 0,
+ "Wrong number of drops of {}, `initializations - drops` should be 0.",
+ stringify!($Type),
+ );
+ }
+ };
+}
+
+define_test! {
+ @test_name: align1zst;
+ struct Align1Zst(());
+
+ check_thin_sized(|| Align1Zst::new(()));
+ check_thin_dyn(|| Align1Zst::new(()));
+}
+
+define_test! {
+ @test_name: align1small;
+ struct Align1Small(u8);
+
+ check_thin_sized(|| Align1Small::new(50));
+ check_thin_dyn(|| Align1Small::new(50));
+}
+
+define_test! {
+ @test_name: align1_size_not_pow2;
+ struct Align64NotPow2Size([u8; 79]);
+
+ check_thin_sized(|| Align64NotPow2Size::new([100; 79]));
+ check_thin_dyn(|| Align64NotPow2Size::new([100; 79]));
+}
+
+define_test! {
+ @test_name: align1big;
+ struct Align1Big([u8; 256]);
+
+ check_thin_sized(|| Align1Big::new([5u8; 256]));
+ check_thin_dyn(|| Align1Big::new([5u8; 256]));
+}
+
+// Note: `#[repr(align(2))]` is worth testing because
+// - can have pointers which are misaligned, unlike align(1)
+// - is still expected to have an alignment less than the alignment of a vtable.
+define_test! {
+ @test_name: align2zst;
+ #[repr(align(2))]
+ struct Align2Zst(());
+
+ check_thin_sized(|| Align2Zst::new(()));
+ check_thin_dyn(|| Align2Zst::new(()));
+}
+
+define_test! {
+ @test_name: align2small;
+ #[repr(align(2))]
+ struct Align2Small(u8);
+
+ check_thin_sized(|| Align2Small::new(60));
+ check_thin_dyn(|| Align2Small::new(60));
+}
+
+define_test! {
+ @test_name: align2full;
+ #[repr(align(2))]
+ struct Align2Full([u8; 2]);
+ check_thin_sized(|| Align2Full::new([3u8; 2]));
+ check_thin_dyn(|| Align2Full::new([3u8; 2]));
+}
+
+define_test! {
+ @test_name: align2_size_not_pow2;
+ #[repr(align(2))]
+ struct Align2NotPower2Size([u8; 6]);
+
+ check_thin_sized(|| Align2NotPower2Size::new([3; 6]));
+ check_thin_dyn(|| Align2NotPower2Size::new([3; 6]));
+}
+
+define_test! {
+ @test_name: align2big;
+ #[repr(align(2))]
+ struct Align2Big([u8; 256]);
+
+ check_thin_sized(|| Align2Big::new([5u8; 256]));
+ check_thin_dyn(|| Align2Big::new([5u8; 256]));
+}
+
+define_test! {
+ @test_name: align64zst;
+ #[repr(align(64))]
+ struct Align64Zst(());
+
+ check_thin_sized(|| Align64Zst::new(()));
+ check_thin_dyn(|| Align64Zst::new(()));
+}
+
+define_test! {
+ @test_name: align64small;
+ #[repr(align(64))]
+ struct Align64Small(u8);
+
+ check_thin_sized(|| Align64Small::new(50));
+ check_thin_dyn(|| Align64Small::new(50));
+}
+
+define_test! {
+ @test_name: align64med;
+ #[repr(align(64))]
+ struct Align64Med([u8; 64]);
+ check_thin_sized(|| Align64Med::new([10; 64]));
+ check_thin_dyn(|| Align64Med::new([10; 64]));
+}
+
+define_test! {
+ @test_name: align64_size_not_pow2;
+ #[repr(align(64))]
+ struct Align64NotPow2Size([u8; 192]);
+
+ check_thin_sized(|| Align64NotPow2Size::new([10; 192]));
+ check_thin_dyn(|| Align64NotPow2Size::new([10; 192]));
+}
+
+define_test! {
+ @test_name: align64big;
+ #[repr(align(64))]
+ struct Align64Big([u8; 256]);
+
+ check_thin_sized(|| Align64Big::new([10; 256]));
+ check_thin_dyn(|| Align64Big::new([10; 256]));
+}
});
}
+#[bench]
+fn write_str_macro_debug_ascii(bh: &mut Bencher) {
+ bh.iter(|| {
+ let mut mem = String::new();
+ let wr = &mut mem as &mut dyn fmt::Write;
+ for _ in 0..1000 {
+ write!(wr, "{:?}", "Hello, World!").unwrap();
+ }
+ });
+}
+
#[bench]
fn write_u128_max(bh: &mut Bencher) {
bh.iter(|| {
/// Converts a reference to `T` into a reference to an array of length 1 (without copying).
#[stable(feature = "array_from_ref", since = "1.53.0")]
-#[rustc_const_unstable(feature = "const_array_from_ref", issue = "90206")]
+#[rustc_const_stable(feature = "const_array_from_ref_shared", since = "1.63.0")]
pub const fn from_ref<T>(s: &T) -> &[T; 1] {
// SAFETY: Converting `&T` to `&[T; 1]` is sound.
unsafe { &*(s as *const T).cast::<[T; 1]>() }
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Pointer for *const T {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
- /// Since the formatting will be identical for all pointer types, use a non-monomorphized
- /// implementation for the actual formatting to reduce the amount of codegen work needed
- fn inner(ptr: *const (), f: &mut Formatter<'_>) -> Result {
- let old_width = f.width;
- let old_flags = f.flags;
-
- // The alternate flag is already treated by LowerHex as being special-
- // it denotes whether to prefix with 0x. We use it to work out whether
- // or not to zero extend, and then unconditionally set it to get the
- // prefix.
- if f.alternate() {
- f.flags |= 1 << (FlagV1::SignAwareZeroPad as u32);
-
- if f.width.is_none() {
- f.width = Some((usize::BITS / 4) as usize + 2);
- }
- }
- f.flags |= 1 << (FlagV1::Alternate as u32);
+ // Cast is needed here because `.addr()` requires `T: Sized`.
+ pointer_fmt_inner((*self as *const ()).addr(), f)
+ }
+}
- let ret = LowerHex::fmt(&(ptr.addr()), f);
+/// Since the formatting will be identical for all pointer types, use a non-monomorphized
+/// implementation for the actual formatting to reduce the amount of codegen work needed.
+///
+/// This uses `ptr_addr: usize` and not `ptr: *const ()` to be able to use this for
+/// `fn(...) -> ...` without using [problematic] "Oxford Casts".
+///
+/// [problematic]: https://github.com/rust-lang/rust/issues/95489
+pub(crate) fn pointer_fmt_inner(ptr_addr: usize, f: &mut Formatter<'_>) -> Result {
+ let old_width = f.width;
+ let old_flags = f.flags;
- f.width = old_width;
- f.flags = old_flags;
+ // The alternate flag is already treated by LowerHex as being special-
+ // it denotes whether to prefix with 0x. We use it to work out whether
+ // or not to zero extend, and then unconditionally set it to get the
+ // prefix.
+ if f.alternate() {
+ f.flags |= 1 << (FlagV1::SignAwareZeroPad as u32);
- ret
+ if f.width.is_none() {
+ f.width = Some((usize::BITS / 4) as usize + 2);
}
-
- inner(*self as *const (), f)
}
+ f.flags |= 1 << (FlagV1::Alternate as u32);
+
+ let ret = LowerHex::fmt(&ptr_addr, f);
+
+ f.width = old_width;
+ f.flags = old_flags;
+
+ ret
}
#[stable(feature = "rust1", since = "1.0.0")]
/// // Now the box is fine
/// assert_eq!(*v, 42);
/// ```
+#[doc(alias = "memset")]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")]
#[inline]
/// ```txt
/// Float ::= Sign? ( 'inf' | 'infinity' | 'nan' | Number )
/// Number ::= ( Digit+ |
- /// '.' Digit* |
/// Digit+ '.' Digit* |
/// Digit* '.' Digit+ ) Exp?
/// Exp ::= 'e' Sign? Digit+
#[stable(feature = "fnptr_impls", since = "1.4.0")]
impl<Ret, $($Arg),*> fmt::Pointer for $FnTy {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- // HACK: The intermediate cast as usize is required for AVR
- // so that the address space of the source function pointer
- // is preserved in the final function pointer.
- //
- // https://github.com/avr-rust/rust/issues/143
- fmt::Pointer::fmt(&(*self as usize as *const ()), f)
+ fmt::pointer_fmt_inner(*self as usize, f)
}
}
#[stable(feature = "fnptr_impls", since = "1.4.0")]
impl<Ret, $($Arg),*> fmt::Debug for $FnTy {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- // HACK: The intermediate cast as usize is required for AVR
- // so that the address space of the source function pointer
- // is preserved in the final function pointer.
- //
- // https://github.com/avr-rust/rust/issues/143
- fmt::Pointer::fmt(&(*self as usize as *const ()), f)
+ fmt::pointer_fmt_inner(*self as usize, f)
}
}
}
/// See [`ptr::write_bytes`] for safety concerns and examples.
///
/// [`ptr::write_bytes`]: crate::ptr::write_bytes()
+ #[doc(alias = "memset")]
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")]
#[inline(always)]
metadata(self)
}
+ /// Returns `true` if the raw slice has a length of 0.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(slice_ptr_len)]
+ ///
+ /// let mut a = [1, 2, 3];
+ /// let ptr = &mut a as *mut [_];
+ /// assert!(!ptr.is_empty());
+ /// ```
+ #[inline(always)]
+ #[unstable(feature = "slice_ptr_len", issue = "71146")]
+ #[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")]
+ pub const fn is_empty(self) -> bool {
+ self.len() == 0
+ }
+
+ /// Divides one mutable raw slice into two at an index.
+ ///
+ /// The first will contain all indices from `[0, mid)` (excluding
+ /// the index `mid` itself) and the second will contain all
+ /// indices from `[mid, len)` (excluding the index `len` itself).
+ ///
+ /// # Panics
+ ///
+ /// Panics if `mid > len`.
+ ///
+ /// # Safety
+ ///
+ /// `mid` must be [in-bounds] of the underlying [allocated object].
+ /// Which means `self` must be dereferenceable and span a single allocation
+ /// that is at least `mid * size_of::<T>()` bytes long. Not upholding these
+ /// requirements is *[undefined behavior]* even if the resulting pointers are not used.
+ ///
+ /// Since `len` being in-bounds it is not a safety invariant of `*mut [T]` the
+ /// safety requirements of this method are the same as for [`split_at_mut_unchecked`].
+ /// The explicit bounds check is only as useful as `len` is correct.
+ ///
+ /// [`split_at_mut_unchecked`]: #method.split_at_mut_unchecked
+ /// [in-bounds]: #method.add
+ /// [allocated object]: crate::ptr#allocated-object
+ /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(raw_slice_split)]
+ /// #![feature(slice_ptr_get)]
+ ///
+ /// let mut v = [1, 0, 3, 0, 5, 6];
+ /// let ptr = &mut v as *mut [_];
+ /// unsafe {
+ /// let (left, right) = ptr.split_at_mut(2);
+ /// assert_eq!(&*left, [1, 0]);
+ /// assert_eq!(&*right, [3, 0, 5, 6]);
+ /// }
+ /// ```
+ #[inline(always)]
+ #[track_caller]
+ #[unstable(feature = "raw_slice_split", issue = "95595")]
+ pub unsafe fn split_at_mut(self, mid: usize) -> (*mut [T], *mut [T]) {
+ assert!(mid <= self.len());
+ // SAFETY: The assert above is only a safety-net as long as `self.len()` is correct
+ // The actual safety requirements of this function are the same as for `split_at_mut_unchecked`
+ unsafe { self.split_at_mut_unchecked(mid) }
+ }
+
+ /// Divides one mutable raw slice into two at an index, without doing bounds checking.
+ ///
+ /// The first will contain all indices from `[0, mid)` (excluding
+ /// the index `mid` itself) and the second will contain all
+ /// indices from `[mid, len)` (excluding the index `len` itself).
+ ///
+ /// # Safety
+ ///
+ /// `mid` must be [in-bounds] of the underlying [allocated object].
+ /// Which means `self` must be dereferenceable and span a single allocation
+ /// that is at least `mid * size_of::<T>()` bytes long. Not upholding these
+ /// requirements is *[undefined behavior]* even if the resulting pointers are not used.
+ ///
+ /// [in-bounds]: #method.add
+ /// [out-of-bounds index]: #method.add
+ /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(raw_slice_split)]
+ ///
+ /// let mut v = [1, 0, 3, 0, 5, 6];
+ /// // scoped to restrict the lifetime of the borrows
+ /// unsafe {
+ /// let ptr = &mut v as *mut [_];
+ /// let (left, right) = ptr.split_at_mut_unchecked(2);
+ /// assert_eq!(&*left, [1, 0]);
+ /// assert_eq!(&*right, [3, 0, 5, 6]);
+ /// (&mut *left)[1] = 2;
+ /// (&mut *right)[1] = 4;
+ /// }
+ /// assert_eq!(v, [1, 2, 3, 4, 5, 6]);
+ /// ```
+ #[inline(always)]
+ #[unstable(feature = "raw_slice_split", issue = "95595")]
+ pub unsafe fn split_at_mut_unchecked(self, mid: usize) -> (*mut [T], *mut [T]) {
+ let len = self.len();
+ let ptr = self.as_mut_ptr();
+
+ // SAFETY: Caller must pass a valid pointer and an index that is in-bounds.
+ let tail = unsafe { ptr.add(mid) };
+ (
+ crate::ptr::slice_from_raw_parts_mut(ptr, mid),
+ crate::ptr::slice_from_raw_parts_mut(tail, len - mid),
+ )
+ }
+
/// Returns a raw pointer to the slice's buffer.
///
/// This is equivalent to casting `self` to `*mut T`, but more type-safe.
/// Returns a raw pointer to an element or subslice, without doing bounds
/// checking.
///
- /// Calling this method with an out-of-bounds index or when `self` is not dereferenceable
+ /// Calling this method with an [out-of-bounds index] or when `self` is not dereferenceable
/// is *[undefined behavior]* even if the resulting pointer is not used.
///
+ /// [out-of-bounds index]: #method.add
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
///
/// # Examples
/// buf.fill_with(Default::default);
/// assert_eq!(buf, vec![0; 10]);
/// ```
- #[doc(alias = "memset")]
#[stable(feature = "slice_fill_with", since = "1.51.0")]
pub fn fill_with<F>(&mut self, mut f: F)
where
/// Converts a reference to T into a slice of length 1 (without copying).
#[stable(feature = "from_ref", since = "1.28.0")]
-#[rustc_const_unstable(feature = "const_slice_from_ref", issue = "90206")]
+#[rustc_const_stable(feature = "const_slice_from_ref_shared", since = "1.63.0")]
#[must_use]
pub const fn from_ref<T>(s: &T) -> &[T] {
array::from_ref(s)
///
/// [valid]: ptr#safety
#[unstable(feature = "slice_from_ptr_range", issue = "89792")]
-pub unsafe fn from_ptr_range<'a, T>(range: Range<*const T>) -> &'a [T] {
+#[rustc_const_unstable(feature = "const_slice_from_ptr_range", issue = "89792")]
+pub const unsafe fn from_ptr_range<'a, T>(range: Range<*const T>) -> &'a [T] {
// SAFETY: the caller must uphold the safety contract for `from_ptr_range`.
unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
}
///
/// [valid]: ptr#safety
#[unstable(feature = "slice_from_ptr_range", issue = "89792")]
-pub unsafe fn from_mut_ptr_range<'a, T>(range: Range<*mut T>) -> &'a mut [T] {
+#[rustc_const_unstable(feature = "const_slice_from_mut_ptr_range", issue = "89792")]
+pub const unsafe fn from_mut_ptr_range<'a, T>(range: Range<*mut T>) -> &'a mut [T] {
// SAFETY: the caller must uphold the safety contract for `from_mut_ptr_range`.
unsafe { from_raw_parts_mut(range.start, range.end.sub_ptr(range.start)) }
}
normal1 = compress_normal(normal1)
print("""\
-// NOTE: The following code was generated by "src/libcore/unicode/printable.py",
+// NOTE: The following code was generated by "library/core/src/unicode/printable.py",
// do not edit directly!
fn check(x: u16, singletonuppers: &[(u8, u8)], singletonlowers: &[u8], normal: &[u8]) -> bool {
pub(crate) fn is_printable(x: char) -> bool {
let x = x as u32;
let lower = x as u16;
- if x < 0x10000 {
+
+ if x < 32 {
+ // ASCII fast path
+ false
+ } else if x < 127 {
+ // ASCII fast path
+ true
+ } else if x < 0x10000 {
check(lower, SINGLETONS0U, SINGLETONS0L, NORMAL0)
} else if x < 0x20000 {
check(lower, SINGLETONS1U, SINGLETONS1L, NORMAL1)
-// NOTE: The following code was generated by "src/libcore/unicode/printable.py",
+// NOTE: The following code was generated by "library/core/src/unicode/printable.py",
// do not edit directly!
fn check(x: u16, singletonuppers: &[(u8, u8)], singletonlowers: &[u8], normal: &[u8]) -> bool {
pub(crate) fn is_printable(x: char) -> bool {
let x = x as u32;
let lower = x as u16;
- if x < 0x10000 {
+
+ if x < 32 {
+ // ASCII fast path
+ false
+ } else if x < 127 {
+ // ASCII fast path
+ true
+ } else if x < 0x10000 {
check(lower, SINGLETONS0U, SINGLETONS0L, NORMAL0)
} else if x < 0x20000 {
check(lower, SINGLETONS1U, SINGLETONS1L, NORMAL1)
#![feature(const_option)]
#![feature(const_option_ext)]
#![feature(const_result)]
+#![feature(const_intrinsic_copy)]
#![feature(integer_atomics)]
#![feature(int_roundings)]
#![feature(slice_group_by)]
use core::cell::RefCell;
+use core::mem::{self, MaybeUninit};
use core::num::NonZeroUsize;
use core::ptr;
use core::ptr::*;
}
}
}
+
+#[test]
+fn test_const_copy() {
+ const {
+ let ptr1 = &1;
+ let mut ptr2 = &666;
+
+ // Copy ptr1 to ptr2, bytewise.
+ unsafe {
+ ptr::copy(
+ &ptr1 as *const _ as *const MaybeUninit<u8>,
+ &mut ptr2 as *mut _ as *mut MaybeUninit<u8>,
+ mem::size_of::<&i32>(),
+ );
+ }
+
+ // Make sure they still work.
+ assert!(*ptr1 == 1);
+ assert!(*ptr2 == 1);
+ };
+
+ const {
+ let ptr1 = &1;
+ let mut ptr2 = &666;
+
+ // Copy ptr1 to ptr2, bytewise.
+ unsafe {
+ ptr::copy_nonoverlapping(
+ &ptr1 as *const _ as *const MaybeUninit<u8>,
+ &mut ptr2 as *mut _ as *mut MaybeUninit<u8>,
+ mem::size_of::<&i32>(),
+ );
+ }
+
+ // Make sure they still work.
+ assert!(*ptr1 == 1);
+ assert!(*ptr2 == 1);
+ };
+}
unsafe impl Send for Buffer {}
impl Default for Buffer {
+ #[inline]
fn default() -> Self {
Self::from(vec![])
}
impl Deref for Buffer {
type Target = [u8];
+ #[inline]
fn deref(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.data as *const u8, self.len) }
}
}
impl DerefMut for Buffer {
+ #[inline]
fn deref_mut(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.data, self.len) }
}
}
impl Buffer {
+ #[inline]
pub(super) fn new() -> Self {
Self::default()
}
+ #[inline]
pub(super) fn clear(&mut self) {
self.len = 0;
}
+ #[inline]
pub(super) fn take(&mut self) -> Self {
mem::take(self)
}
// because in the case of small arrays, codegen can be more efficient
// (avoiding a memmove call). With extend_from_slice, LLVM at least
// currently is not able to make that optimization.
+ #[inline]
pub(super) fn extend_from_array<const N: usize>(&mut self, xs: &[u8; N]) {
if xs.len() > (self.capacity - self.len) {
let b = self.take();
}
}
+ #[inline]
pub(super) fn extend_from_slice(&mut self, xs: &[u8]) {
if xs.len() > (self.capacity - self.len) {
let b = self.take();
}
}
+ #[inline]
pub(super) fn push(&mut self, v: u8) {
// The code here is taken from Vec::push, and we know that reserve()
// will panic if we're exceeding isize::MAX bytes and so there's no need
}
impl Write for Buffer {
+ #[inline]
fn write(&mut self, xs: &[u8]) -> io::Result<usize> {
self.extend_from_slice(xs);
Ok(xs.len())
}
+ #[inline]
fn write_all(&mut self, xs: &[u8]) -> io::Result<()> {
self.extend_from_slice(xs);
Ok(())
}
+ #[inline]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
impl Drop for Buffer {
+ #[inline]
fn drop(&mut self) {
let b = self.take();
(b.drop)(b);
/// `[ ... ]`
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
Bracket,
- /// `/*«*/ ... /*»*/`
+ /// `Ø ... Ø`
/// An invisible delimiter, that may, for example, appear around tokens coming from a
/// "macro variable" `$var`. It is important to preserve operator priorities in cases like
/// `$var * 3` where `$var` is `1 + 2`.
- /// Invisible delimiters are not directly writable in normal Rust code except as comments.
- /// Therefore, they might not survive a roundtrip of a token stream through a string.
+ /// Invisible delimiters might not survive roundtrip of a token stream through a string.
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
None,
}
panic_abort = { path = "../panic_abort" }
core = { path = "../core" }
libc = { version = "0.2.126", default-features = false, features = ['rustc-dep-of-std'] }
-compiler_builtins = { version = "0.1.71" }
+compiler_builtins = { version = "0.1.73" }
profiler_builtins = { path = "../profiler_builtins", optional = true }
unwind = { path = "../unwind" }
hashbrown = { version = "0.12", default-features = false, features = ['rustc-dep-of-std'] }
/// the [`Eq`] trait, changes while it is in the map. This is normally only
/// possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
/// The behavior resulting from such a logic error is not specified, but will
-/// not result in undefined behavior. This could include panics, incorrect results,
+/// be encapsulated to the `HashMap` that observed the logic error and not
+/// result in undefined behavior. This could include panics, incorrect results,
/// aborts, memory leaks, and non-termination.
///
/// The hash table implementation is a Rust port of Google's [SwissTable].
self.base.get_key_value(k)
}
+ /// Attempts to get mutable references to `N` values in the map at once.
+ ///
+ /// Returns an array of length `N` with the results of each query. For soundness, at most one
+ /// mutable reference will be returned to any value. `None` will be returned if any of the
+ /// keys are duplicates or missing.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(map_many_mut)]
+ /// use std::collections::HashMap;
+ ///
+ /// let mut libraries = HashMap::new();
+ /// libraries.insert("Bodleian Library".to_string(), 1602);
+ /// libraries.insert("Athenæum".to_string(), 1807);
+ /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691);
+ /// libraries.insert("Library of Congress".to_string(), 1800);
+ ///
+ /// let got = libraries.get_many_mut([
+ /// "Athenæum",
+ /// "Library of Congress",
+ /// ]);
+ /// assert_eq!(
+ /// got,
+ /// Some([
+ /// &mut 1807,
+ /// &mut 1800,
+ /// ]),
+ /// );
+ ///
+ /// // Missing keys result in None
+ /// let got = libraries.get_many_mut([
+ /// "Athenæum",
+ /// "New York Public Library",
+ /// ]);
+ /// assert_eq!(got, None);
+ ///
+ /// // Duplicate keys result in None
+ /// let got = libraries.get_many_mut([
+ /// "Athenæum",
+ /// "Athenæum",
+ /// ]);
+ /// assert_eq!(got, None);
+ /// ```
+ #[inline]
+ #[unstable(feature = "map_many_mut", issue = "97601")]
+ pub fn get_many_mut<Q: ?Sized, const N: usize>(&mut self, ks: [&Q; N]) -> Option<[&'_ mut V; N]>
+ where
+ K: Borrow<Q>,
+ Q: Hash + Eq,
+ {
+ self.base.get_many_mut(ks)
+ }
+
+ /// Attempts to get mutable references to `N` values in the map at once, without validating that
+ /// the values are unique.
+ ///
+ /// Returns an array of length `N` with the results of each query. `None` will be returned if
+ /// any of the keys are missing.
+ ///
+ /// For a safe alternative see [`get_many_mut`](Self::get_many_mut).
+ ///
+ /// # Safety
+ ///
+ /// Calling this method with overlapping keys is *[undefined behavior]* even if the resulting
+ /// references are not used.
+ ///
+ /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(map_many_mut)]
+ /// use std::collections::HashMap;
+ ///
+ /// let mut libraries = HashMap::new();
+ /// libraries.insert("Bodleian Library".to_string(), 1602);
+ /// libraries.insert("Athenæum".to_string(), 1807);
+ /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691);
+ /// libraries.insert("Library of Congress".to_string(), 1800);
+ ///
+ /// let got = libraries.get_many_mut([
+ /// "Athenæum",
+ /// "Library of Congress",
+ /// ]);
+ /// assert_eq!(
+ /// got,
+ /// Some([
+ /// &mut 1807,
+ /// &mut 1800,
+ /// ]),
+ /// );
+ ///
+ /// // Missing keys result in None
+ /// let got = libraries.get_many_mut([
+ /// "Athenæum",
+ /// "New York Public Library",
+ /// ]);
+ /// assert_eq!(got, None);
+ /// ```
+ #[inline]
+ #[unstable(feature = "map_many_mut", issue = "97601")]
+ pub unsafe fn get_many_unchecked_mut<Q: ?Sized, const N: usize>(
+ &mut self,
+ ks: [&Q; N],
+ ) -> Option<[&'_ mut V; N]>
+ where
+ K: Borrow<Q>,
+ Q: Hash + Eq,
+ {
+ self.base.get_many_unchecked_mut(ks)
+ }
+
/// Returns `true` if the map contains a value for the specified key.
///
/// The key may be any borrowed form of the map's key type, but
/// In other words, if two keys are equal, their hashes must be equal.
///
///
-/// It is a logic error for an item to be modified in such a way that the
-/// item's hash, as determined by the [`Hash`] trait, or its equality, as
-/// determined by the [`Eq`] trait, changes while it is in the set. This is
-/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or
-/// unsafe code. The behavior resulting from such a logic error is not
-/// specified (it could include panics, incorrect results, aborts, memory
-/// leaks, or non-termination) but will not be undefined behavior.
+/// It is a logic error for a key to be modified in such a way that the key's
+/// hash, as determined by the [`Hash`] trait, or its equality, as determined by
+/// the [`Eq`] trait, changes while it is in the map. This is normally only
+/// possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
+/// The behavior resulting from such a logic error is not specified, but will
+/// be encapsulated to the `HashSet` that observed the logic error and not
+/// result in undefined behavior. This could include panics, incorrect results,
+/// aborts, memory leaks, and non-termination.
///
/// # Examples
///
/// Adds a value to the set.
///
- /// If the set did not have this value present, `true` is returned.
+ /// Returns whether the value was newly inserted. That is:
///
- /// If the set did have this value present, `false` is returned.
+ /// - If the set did not previously contain this value, `true` is returned.
+ /// - If the set already contained this value, `false` is returned.
///
/// # Examples
///
/// # Platform-specific behavior
///
/// This function currently corresponds to the `stat` function on Unix
-/// and the `GetFileAttributesEx` function on Windows.
+/// and the `GetFileInformationByHandle` function on Windows.
/// Note that, this [may change in the future][changes].
///
/// [changes]: io#platform-specific-behavior
/// # Platform-specific behavior
///
/// This function currently corresponds to the `lstat` function on Unix
-/// and the `GetFileAttributesEx` function on Windows.
+/// and the `GetFileInformationByHandle` function on Windows.
/// Note that, this [may change in the future][changes].
///
/// [changes]: io#platform-specific-behavior
#![feature(map_try_insert)]
#![feature(new_uninit)]
#![feature(thin_box)]
-#![feature(toowned_clone_into)]
#![feature(try_reserve_kind)]
#![feature(vec_into_raw_parts)]
#![feature(slice_concat_trait)]
use crate::ops::{Deref, DerefMut};
#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
-#[repr(align(64))]
+#[cfg_attr(target_arch = "aarch64", repr(align(128)))]
+#[cfg_attr(not(target_arch = "aarch64"), repr(align(64)))]
pub(super) struct CacheAligned<T>(pub T);
impl<T> Deref for CacheAligned<T> {
mutex.lock();
res == 0
}
+}
- pub unsafe fn destroy(&self) {
- let _ = abi::sem_destroy(self.sem1);
- let _ = abi::sem_destroy(self.sem2);
+impl Drop for Condvar {
+ fn drop(&mut self) {
+ unsafe {
+ let _ = abi::sem_destroy(self.sem1);
+ let _ = abi::sem_destroy(self.sem2);
+ }
}
}
}
guard.locked
}
-
- #[inline]
- pub unsafe fn destroy(&self) {}
}
// FIXME: should only wake up one of these some of the time
self.cond.notify_all();
}
-
- #[inline]
- pub unsafe fn destroy(&self) {
- self.lock.destroy();
- self.cond.destroy();
- }
}
impl State {
unsafe { mutex.lock() };
success
}
-
- pub unsafe fn destroy(&self) {}
}
mod waiter_queue {
}
}
}
+}
- pub unsafe fn destroy(&self) {
+impl Drop for Mutex {
+ fn drop(&mut self) {
if let Some(mtx) = self.mtx.get().map(|x| x.0) {
expect_success_aborting(unsafe { abi::del_mtx(mtx) }, &"del_mtx");
}
use crate::sys::locks::Mutex;
+use crate::sys_common::lazy_box::{LazyBox, LazyInit};
use crate::time::Duration;
use super::waitqueue::{SpinMutex, WaitQueue, WaitVariable};
inner: SpinMutex<WaitVariable<()>>,
}
-pub type MovableCondvar = Box<Condvar>;
+pub(crate) type MovableCondvar = LazyBox<Condvar>;
+
+impl LazyInit for Condvar {
+ fn init() -> Box<Self> {
+ Box::new(Self::new())
+ }
+}
impl Condvar {
pub const fn new() -> Condvar {
Condvar { inner: SpinMutex::new(WaitVariable::new(())) }
}
- #[inline]
- pub unsafe fn init(&mut self) {}
-
#[inline]
pub unsafe fn notify_one(&self) {
let _ = WaitQueue::notify_one(self.inner.lock());
unsafe { mutex.lock() };
success
}
-
- #[inline]
- pub unsafe fn destroy(&self) {}
}
use super::waitqueue::{try_lock_or_false, SpinMutex, WaitQueue, WaitVariable};
+use crate::sys_common::lazy_box::{LazyBox, LazyInit};
pub struct Mutex {
inner: SpinMutex<WaitVariable<bool>>,
}
// not movable: see UnsafeList implementation
-pub type MovableMutex = Box<Mutex>;
+pub(crate) type MovableMutex = LazyBox<Mutex>;
+
+impl LazyInit for Mutex {
+ fn init() -> Box<Self> {
+ Box::new(Self::new())
+ }
+}
// Implementation according to “Operating Systems: Three Easy Pieces”, chapter 28
impl Mutex {
true
}
}
-
- #[inline]
- pub unsafe fn destroy(&self) {}
}
mod tests;
use crate::num::NonZeroUsize;
+use crate::sys_common::lazy_box::{LazyBox, LazyInit};
use super::waitqueue::{
try_lock_or_false, NotifiedTcs, SpinMutex, SpinMutexGuard, WaitQueue, WaitVariable,
writer: SpinMutex<WaitVariable<bool>>,
}
-pub type MovableRwLock = Box<RwLock>;
+pub(crate) type MovableRwLock = LazyBox<RwLock>;
+
+impl LazyInit for RwLock {
+ fn init() -> Box<Self> {
+ Box::new(Self::new())
+ }
+}
// Check at compile time that RwLock size matches C definition (see test_c_rwlock_initializer below)
//
unsafe { self.__read_unlock(rguard, wguard) };
}
}
-
- #[inline]
- pub unsafe fn destroy(&self) {}
}
// The following functions are needed by libunwind. These symbols are named
let rwl = self.raw();
expect_success_aborting(unsafe { abi::rwl_unl_rwl(rwl) }, &"rwl_unl_rwl");
}
+}
+impl Drop for RwLock {
#[inline]
- pub unsafe fn destroy(&self) {
+ fn drop(&mut self) {
if let Some(rwl) = self.rwl.get().map(|x| x.0) {
expect_success_aborting(unsafe { abi::rwl_del_rwl(rwl) }, &"rwl_del_rwl");
}
#[inline]
pub unsafe fn init(&mut self) {}
- #[inline]
- pub unsafe fn destroy(&self) {}
-
#[inline]
pub unsafe fn try_lock(&self) -> bool {
self.futex.compare_exchange(0, 1, Acquire, Relaxed).is_ok()
Self { futex: AtomicU32::new(0) }
}
- #[inline]
- pub unsafe fn init(&mut self) {}
-
- #[inline]
- pub unsafe fn destroy(&self) {}
-
// All the memory orderings here are `Relaxed`,
// because synchronization is done by unlocking and locking the mutex.
Self { state: AtomicU32::new(0), writer_notify: AtomicU32::new(0) }
}
- #[inline]
- pub unsafe fn destroy(&self) {}
-
#[inline]
pub unsafe fn try_read(&self) -> bool {
self.state
))] {
mod futex;
mod futex_rwlock;
- pub use futex::{Mutex, MovableMutex, Condvar, MovableCondvar};
- pub use futex_rwlock::{RwLock, MovableRwLock};
+ pub(crate) use futex::{Mutex, MovableMutex, MovableCondvar};
+ pub(crate) use futex_rwlock::{RwLock, MovableRwLock};
} else {
mod pthread_mutex;
mod pthread_rwlock;
mod pthread_condvar;
- pub use pthread_mutex::{Mutex, MovableMutex};
- pub use pthread_rwlock::{RwLock, MovableRwLock};
- pub use pthread_condvar::{Condvar, MovableCondvar};
+ pub(crate) use pthread_mutex::{Mutex, MovableMutex};
+ pub(crate) use pthread_rwlock::{RwLock, MovableRwLock};
+ pub(crate) use pthread_condvar::MovableCondvar;
}
}
use crate::cell::UnsafeCell;
use crate::sys::locks::{pthread_mutex, Mutex};
+use crate::sys_common::lazy_box::{LazyBox, LazyInit};
use crate::time::Duration;
pub struct Condvar {
inner: UnsafeCell<libc::pthread_cond_t>,
}
-pub type MovableCondvar = Box<Condvar>;
+pub(crate) type MovableCondvar = LazyBox<Condvar>;
unsafe impl Send for Condvar {}
unsafe impl Sync for Condvar {}
if value > <libc::time_t>::MAX as u64 { <libc::time_t>::MAX } else { value as libc::time_t }
}
+impl LazyInit for Condvar {
+ fn init() -> Box<Self> {
+ let mut condvar = Box::new(Self::new());
+ unsafe { condvar.init() };
+ condvar
+ }
+}
+
impl Condvar {
pub const fn new() -> Condvar {
// Might be moved and address is changing it is better to avoid
target_os = "android",
target_os = "redox"
))]
- pub unsafe fn init(&mut self) {}
+ unsafe fn init(&mut self) {}
// NOTE: ESP-IDF's PTHREAD_COND_INITIALIZER support is not released yet
// So on that platform, init() should always be called
// Moreover, that platform does not have pthread_condattr_setclock support,
// hence that initialization should be skipped as well
#[cfg(target_os = "espidf")]
- pub unsafe fn init(&mut self) {
+ unsafe fn init(&mut self) {
let r = libc::pthread_cond_init(self.inner.get(), crate::ptr::null());
assert_eq!(r, 0);
}
target_os = "redox",
target_os = "espidf"
)))]
- pub unsafe fn init(&mut self) {
+ unsafe fn init(&mut self) {
use crate::mem::MaybeUninit;
let mut attr = MaybeUninit::<libc::pthread_condattr_t>::uninit();
let r = libc::pthread_condattr_init(attr.as_mut_ptr());
#[inline]
#[cfg(not(target_os = "dragonfly"))]
- pub unsafe fn destroy(&self) {
+ unsafe fn destroy(&mut self) {
let r = libc::pthread_cond_destroy(self.inner.get());
debug_assert_eq!(r, 0);
}
#[inline]
#[cfg(target_os = "dragonfly")]
- pub unsafe fn destroy(&self) {
+ unsafe fn destroy(&mut self) {
let r = libc::pthread_cond_destroy(self.inner.get());
// On DragonFly pthread_cond_destroy() returns EINVAL if called on
// a condvar that was just initialized with
debug_assert!(r == 0 || r == libc::EINVAL);
}
}
+
+impl Drop for Condvar {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe { self.destroy() };
+ }
+}
use crate::cell::UnsafeCell;
use crate::mem::MaybeUninit;
use crate::sys::cvt_nz;
+use crate::sys_common::lazy_box::{LazyBox, LazyInit};
pub struct Mutex {
inner: UnsafeCell<libc::pthread_mutex_t>,
}
-pub type MovableMutex = Box<Mutex>;
+pub(crate) type MovableMutex = LazyBox<Mutex>;
#[inline]
pub unsafe fn raw(m: &Mutex) -> *mut libc::pthread_mutex_t {
unsafe impl Send for Mutex {}
unsafe impl Sync for Mutex {}
+impl LazyInit for Mutex {
+ fn init() -> Box<Self> {
+ let mut mutex = Box::new(Self::new());
+ unsafe { mutex.init() };
+ mutex
+ }
+}
+
impl Mutex {
pub const fn new() -> Mutex {
// Might be moved to a different address, so it is better to avoid
}
#[inline]
#[cfg(not(target_os = "dragonfly"))]
- pub unsafe fn destroy(&self) {
+ unsafe fn destroy(&mut self) {
let r = libc::pthread_mutex_destroy(self.inner.get());
debug_assert_eq!(r, 0);
}
#[inline]
#[cfg(target_os = "dragonfly")]
- pub unsafe fn destroy(&self) {
+ unsafe fn destroy(&mut self) {
let r = libc::pthread_mutex_destroy(self.inner.get());
// On DragonFly pthread_mutex_destroy() returns EINVAL if called on a
// mutex that was just initialized with libc::PTHREAD_MUTEX_INITIALIZER.
}
}
+impl Drop for Mutex {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe { self.destroy() };
+ }
+}
+
pub(super) struct PthreadMutexAttr<'a>(pub &'a mut MaybeUninit<libc::pthread_mutexattr_t>);
impl Drop for PthreadMutexAttr<'_> {
use crate::cell::UnsafeCell;
use crate::sync::atomic::{AtomicUsize, Ordering};
+use crate::sys_common::lazy_box::{LazyBox, LazyInit};
pub struct RwLock {
inner: UnsafeCell<libc::pthread_rwlock_t>,
num_readers: AtomicUsize,
}
-pub type MovableRwLock = Box<RwLock>;
+pub(crate) type MovableRwLock = LazyBox<RwLock>;
unsafe impl Send for RwLock {}
unsafe impl Sync for RwLock {}
+impl LazyInit for RwLock {
+ fn init() -> Box<Self> {
+ Box::new(Self::new())
+ }
+}
+
impl RwLock {
pub const fn new() -> RwLock {
RwLock {
self.raw_unlock();
}
#[inline]
- pub unsafe fn destroy(&self) {
+ unsafe fn destroy(&mut self) {
let r = libc::pthread_rwlock_destroy(self.inner.get());
// On DragonFly pthread_rwlock_destroy() returns EINVAL if called on a
// rwlock that was just initialized with
}
}
}
+
+impl Drop for RwLock {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe { self.destroy() };
+ }
+}
#![allow(missing_docs, nonstandard_style)]
+use crate::ffi::CStr;
use crate::io::ErrorKind;
pub use self::rand::hashmap_random_keys;
stack_overflow::init();
args::init(argc, argv);
+ // Normally, `thread::spawn` will call `Thread::set_name` but since this thread
+ // already exists, we have to call it ourselves. We only do this on macos
+ // because some unix-like operating systems such as Linux share process-id and
+ // thread-id for the main thread and so renaming the main thread will rename the
+ // process and we only want to enable this on platforms we've tested.
+ if cfg!(target_os = "macos") {
+ thread::Thread::set_name(&CStr::from_bytes_with_nul_unchecked(b"main\0"));
+ }
+
unsafe fn sanitize_standard_fds() {
#[cfg(not(miri))]
// The standard fds are always available in Miri.
}
}
+/// Convert a signal number to a readable, searchable name.
+///
+/// This string should be displayed right after the signal number.
+/// If a signal is unrecognized, it returns the empty string, so that
+/// you just get the number like "0". If it is recognized, you'll get
+/// something like "9 (SIGKILL)".
+fn signal_string(signal: i32) -> &'static str {
+ match signal {
+ libc::SIGHUP => " (SIGHUP)",
+ libc::SIGINT => " (SIGINT)",
+ libc::SIGQUIT => " (SIGQUIT)",
+ libc::SIGILL => " (SIGILL)",
+ libc::SIGTRAP => " (SIGTRAP)",
+ libc::SIGABRT => " (SIGABRT)",
+ libc::SIGBUS => " (SIGBUS)",
+ libc::SIGFPE => " (SIGFPE)",
+ libc::SIGKILL => " (SIGKILL)",
+ libc::SIGUSR1 => " (SIGUSR1)",
+ libc::SIGSEGV => " (SIGSEGV)",
+ libc::SIGUSR2 => " (SIGUSR2)",
+ libc::SIGPIPE => " (SIGPIPE)",
+ libc::SIGALRM => " (SIGALRM)",
+ libc::SIGTERM => " (SIGTERM)",
+ libc::SIGCHLD => " (SIGCHLD)",
+ libc::SIGCONT => " (SIGCONT)",
+ libc::SIGSTOP => " (SIGSTOP)",
+ libc::SIGTSTP => " (SIGTSTP)",
+ libc::SIGTTIN => " (SIGTTIN)",
+ libc::SIGTTOU => " (SIGTTOU)",
+ libc::SIGURG => " (SIGURG)",
+ libc::SIGXCPU => " (SIGXCPU)",
+ libc::SIGXFSZ => " (SIGXFSZ)",
+ libc::SIGVTALRM => " (SIGVTALRM)",
+ libc::SIGPROF => " (SIGPROF)",
+ libc::SIGWINCH => " (SIGWINCH)",
+ libc::SIGIO => " (SIGIO)",
+ libc::SIGSYS => " (SIGSYS)",
+ // For information on Linux signals, run `man 7 signal`
+ #[cfg(all(
+ target_os = "linux",
+ any(
+ target_arch = "x86_64",
+ target_arch = "x86",
+ target_arch = "arm",
+ target_arch = "aarch64"
+ )
+ ))]
+ libc::SIGSTKFLT => " (SIGSTKFLT)",
+ #[cfg(target_os = "linux")]
+ libc::SIGPWR => " (SIGPWR)",
+ #[cfg(any(
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "tvos",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ target_os = "openbsd",
+ target_os = "dragonfly"
+ ))]
+ libc::SIGEMT => " (SIGEMT)",
+ #[cfg(any(
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "tvos",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ target_os = "openbsd",
+ target_os = "dragonfly"
+ ))]
+ libc::SIGINFO => " (SIGINFO)",
+ _ => "",
+ }
+}
+
impl fmt::Display for ExitStatus {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(code) = self.code() {
write!(f, "exit status: {code}")
} else if let Some(signal) = self.signal() {
+ let signal_string = signal_string(signal);
if self.core_dumped() {
- write!(f, "signal: {signal} (core dumped)")
+ write!(f, "signal: {signal}{signal_string} (core dumped)")
} else {
- write!(f, "signal: {signal}")
+ write!(f, "signal: {signal}{signal_string}")
}
} else if let Some(signal) = self.stopped_signal() {
- write!(f, "stopped (not terminated) by signal: {signal}")
+ let signal_string = signal_string(signal);
+ write!(f, "stopped (not terminated) by signal: {signal}{signal_string}")
} else if self.continued() {
write!(f, "continued (WIFCONTINUED)")
} else {
let t = |v, s| assert_eq!(s, format!("{}", <ExitStatus as ExitStatusExt>::from_raw(v)));
- t(0x0000f, "signal: 15");
- t(0x0008b, "signal: 11 (core dumped)");
+ t(0x0000f, "signal: 15 (SIGTERM)");
+ t(0x0008b, "signal: 11 (SIGSEGV) (core dumped)");
t(0x00000, "exit status: 0");
t(0x0ff00, "exit status: 255");
// The purpose of this test is to test our string formatting, not our understanding of the wait
// status magic numbers. So restrict these to Linux.
if cfg!(target_os = "linux") {
- t(0x0137f, "stopped (not terminated) by signal: 19");
+ t(0x0137f, "stopped (not terminated) by signal: 19 (SIGSTOP)");
t(0x0ffff, "continued (WIFCONTINUED)");
}
Condvar {}
}
- #[inline]
- pub unsafe fn init(&mut self) {}
-
#[inline]
pub unsafe fn notify_one(&self) {}
pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool {
panic!("condvar wait not supported");
}
-
- #[inline]
- pub unsafe fn destroy(&self) {}
}
pub unsafe fn try_lock(&self) -> bool {
self.locked.replace(true) == false
}
-
- #[inline]
- pub unsafe fn destroy(&self) {}
}
pub unsafe fn write_unlock(&self) {
assert_eq!(self.mode.replace(0), -1);
}
-
- #[inline]
- pub unsafe fn destroy(&self) {}
}
#![allow(unsafe_op_in_unsafe_fn)]
mod futex;
mod futex_rwlock;
- pub use futex::{Mutex, MovableMutex, Condvar, MovableCondvar};
- pub use futex_rwlock::{RwLock, MovableRwLock};
+ pub(crate) use futex::{Mutex, MovableMutex, Condvar, MovableCondvar};
+ pub(crate) use futex_rwlock::{RwLock, MovableRwLock};
}
#[path = "atomics/futex.rs"]
pub mod futex;
Condvar { inner: UnsafeCell::new(c::CONDITION_VARIABLE_INIT) }
}
- #[inline]
- pub unsafe fn init(&mut self) {}
-
#[inline]
pub unsafe fn wait(&self, mutex: &Mutex) {
let r = c::SleepConditionVariableSRW(self.inner.get(), mutex::raw(mutex), c::INFINITE, 0);
pub unsafe fn notify_all(&self) {
c::WakeAllConditionVariable(self.inner.get())
}
-
- pub unsafe fn destroy(&self) {
- // ...
- }
}
pub unsafe fn unlock(&self) {
c::ReleaseSRWLockExclusive(raw(self));
}
-
- #[inline]
- pub unsafe fn destroy(&self) {
- // SRWLock does not need to be destroyed.
- }
}
pub unsafe fn write_unlock(&self) {
c::ReleaseSRWLockExclusive(self.inner.get())
}
-
- #[inline]
- pub unsafe fn destroy(&self) {
- // ...
- }
}
#![allow(missing_docs, nonstandard_style)]
-use crate::ffi::{OsStr, OsString};
+use crate::ffi::{CStr, OsStr, OsString};
use crate::io::ErrorKind;
use crate::os::windows::ffi::{OsStrExt, OsStringExt};
use crate::path::PathBuf;
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
stack_overflow::init();
+
+ // Normally, `thread::spawn` will call `Thread::set_name` but since this thread already
+ // exists, we have to call it ourselves.
+ thread::Thread::set_name(&CStr::from_bytes_with_nul_unchecked(b"main\0"));
}
// SAFETY: must be called only once during runtime cleanup.
impl Condvar {
/// Creates a new condition variable for use.
pub fn new() -> Self {
- let mut c = imp::MovableCondvar::from(imp::Condvar::new());
- unsafe { c.init() };
- Self { inner: c, check: CondvarCheck::new() }
+ Self { inner: imp::MovableCondvar::new(), check: CondvarCheck::new() }
}
/// Signals one waiter on this condition variable to wake up.
self.inner.wait_timeout(mutex.raw(), dur)
}
}
-
-impl Drop for Condvar {
- fn drop(&mut self) {
- unsafe { self.inner.destroy() };
- }
-}
use crate::ptr;
use crate::sync::atomic::{AtomicPtr, Ordering};
use crate::sys::locks as imp;
+use crate::sys_common::lazy_box::{LazyBox, LazyInit};
use crate::sys_common::mutex::MovableMutex;
pub trait CondvarCheck {
/// For boxed mutexes, a `Condvar` will check it's only ever used with the same
/// mutex, based on its (stable) address.
-impl CondvarCheck for Box<imp::Mutex> {
+impl<T: LazyInit> CondvarCheck for LazyBox<T> {
type Check = SameMutexCheck;
}
--- /dev/null
+#![allow(dead_code)] // Only used on some platforms.
+
+// This is used to wrap pthread {Mutex, Condvar, RwLock} in.
+
+use crate::marker::PhantomData;
+use crate::ops::{Deref, DerefMut};
+use crate::ptr::null_mut;
+use crate::sync::atomic::{
+ AtomicPtr,
+ Ordering::{AcqRel, Acquire},
+};
+
+pub(crate) struct LazyBox<T: LazyInit> {
+ ptr: AtomicPtr<T>,
+ _phantom: PhantomData<T>,
+}
+
+pub(crate) trait LazyInit {
+ /// This is called before the box is allocated, to provide the value to
+ /// move into the new box.
+ ///
+ /// It might be called more than once per LazyBox, as multiple threads
+ /// might race to initialize it concurrently, each constructing and initializing
+ /// their own box. (All but one of them will be destroyed right after.)
+ fn init() -> Box<Self>;
+}
+
+impl<T: LazyInit> LazyBox<T> {
+ #[inline]
+ pub const fn new() -> Self {
+ Self { ptr: AtomicPtr::new(null_mut()), _phantom: PhantomData }
+ }
+
+ #[inline]
+ fn get_pointer(&self) -> *mut T {
+ let ptr = self.ptr.load(Acquire);
+ if ptr.is_null() { self.initialize() } else { ptr }
+ }
+
+ #[cold]
+ fn initialize(&self) -> *mut T {
+ let new_ptr = Box::into_raw(T::init());
+ match self.ptr.compare_exchange(null_mut(), new_ptr, AcqRel, Acquire) {
+ Ok(_) => new_ptr,
+ Err(ptr) => {
+ // Lost the race to another thread.
+ // Drop the box we created, and use the one from the other thread instead.
+ drop(unsafe { Box::from_raw(new_ptr) });
+ ptr
+ }
+ }
+ }
+}
+
+impl<T: LazyInit> Deref for LazyBox<T> {
+ type Target = T;
+ #[inline]
+ fn deref(&self) -> &T {
+ unsafe { &*self.get_pointer() }
+ }
+}
+
+impl<T: LazyInit> DerefMut for LazyBox<T> {
+ #[inline]
+ fn deref_mut(&mut self) -> &mut T {
+ unsafe { &mut *self.get_pointer() }
+ }
+}
+
+impl<T: LazyInit> Drop for LazyBox<T> {
+ fn drop(&mut self) {
+ let ptr = *self.ptr.get_mut();
+ if !ptr.is_null() {
+ drop(unsafe { Box::from_raw(ptr) });
+ }
+ }
+}
pub mod condvar;
pub mod fs;
pub mod io;
+pub mod lazy_box;
pub mod memchr;
pub mod mutex;
pub mod process;
impl MovableMutex {
/// Creates a new mutex.
pub fn new() -> Self {
- let mut mutex = imp::MovableMutex::from(imp::Mutex::new());
- unsafe { mutex.init() };
- Self(mutex)
+ Self(imp::MovableMutex::new())
}
pub(super) fn raw(&self) -> &imp::Mutex {
self.0.unlock()
}
}
-
-impl Drop for MovableMutex {
- fn drop(&mut self) {
- unsafe { self.0.destroy() };
- }
-}
}
}
-impl<T> Drop for ReentrantMutex<T> {
- fn drop(&mut self) {
- // Safety: We're the unique owner of this mutex and not going to use it afterwards.
- unsafe { self.mutex.destroy() }
- }
-}
-
impl<T> Deref for ReentrantMutexGuard<'_, T> {
type Target = T;
impl MovableRwLock {
/// Creates a new reader-writer lock for use.
pub fn new() -> Self {
- Self(imp::MovableRwLock::from(imp::RwLock::new()))
+ Self(imp::MovableRwLock::new())
}
/// Acquires shared access to the underlying lock, blocking the current
self.0.write_unlock()
}
}
-
-impl Drop for MovableRwLock {
- fn drop(&mut self) {
- unsafe { self.0.destroy() };
- }
-}
once_cell = "1.7.2"
xz2 = "0.1"
+# Dependencies needed by the build-metrics feature
+sysinfo = { version = "0.24.1", optional = true }
+
[target.'cfg(windows)'.dependencies.winapi]
version = "0.3"
features = [
[dev-dependencies]
pretty_assertions = "0.7"
+
+[features]
+build-metrics = ["sysinfo"]
args.append("--locked")
if self.use_vendored_sources:
args.append("--frozen")
+ if self.get_toml("metrics", "build"):
+ args.append("--features")
+ args.append("build-metrics")
run(args, env=env, verbose=self.verbose)
def build_triple(self):
// get some support for setting `--check-cfg` within build script, it's the least invasive
// hack that still let's us have cfg checking for the vast majority of the codebase.
if stage != 0 {
- // Enable cfg checking of cargo features for everything but std.
+ // Enable cfg checking of cargo features for everything but std and also enable cfg
+ // checking of names and values.
//
// Note: `std`, `alloc` and `core` imports some dependencies by #[path] (like
- // backtrace, core_simd, std_float, ...), those dependencies have their own features
- // but cargo isn't involved in the #[path] and so cannot pass the complete list of
- // features, so for that reason we don't enable checking of features for std.
+ // backtrace, core_simd, std_float, ...), those dependencies have their own
+ // features but cargo isn't involved in the #[path] process and so cannot pass the
+ // complete list of features, so for that reason we don't enable checking of
+ // features for std crates.
+ cargo.arg(if mode != Mode::Std {
+ "-Zcheck-cfg=names,values,features"
+ } else {
+ "-Zcheck-cfg=names,values"
+ });
+
+ // Add extra cfg not defined in/by rustc
//
- // FIXME: Re-enable this after the beta bump as apperently rustc-perf doesn't use the
- // beta cargo. See https://github.com/rust-lang/rust/pull/96984#issuecomment-1126678773
- // #[cfg(not(bootstrap))]
- // if mode != Mode::Std {
- // cargo.arg("-Zcheck-cfg-features"); // -Zcheck-cfg=features after bump
- // }
-
- // Enable cfg checking of well known names/values
- rustflags
- .arg("-Zunstable-options")
- // Enable checking of well known names
- .arg("--check-cfg=names()")
- // Enable checking of well known values
- .arg("--check-cfg=values()");
-
- // Add extra cfg not defined in rustc
+ // Note: Altrough it would seems that "-Zunstable-options" to `rustflags` is useless as
+ // cargo would implicitly add it, it was discover that sometimes bootstrap only use
+ // `rustflags` without `cargo` making it required.
+ rustflags.arg("-Zunstable-options");
for (restricted_mode, name, values) in EXTRA_CHECK_CFGS {
if *restricted_mode == None || *restricted_mode == Some(mode) {
// Creating a string of the values by concatenating each value:
stack.push(Box::new(step.clone()));
}
+ #[cfg(feature = "build-metrics")]
+ self.metrics.enter_step(&step);
+
let (out, dur) = {
let start = Instant::now();
let zero = Duration::new(0, 0);
);
}
+ #[cfg(feature = "build-metrics")]
+ self.metrics.exit_step();
+
{
let mut stack = self.stack.borrow_mut();
let cur_step = stack.pop().expect("step stack empty");
dist_stage: Option<u32> = "dist-stage",
bench_stage: Option<u32> = "bench-stage",
patch_binaries_for_nix: Option<bool> = "patch-binaries-for-nix",
+ metrics: Option<bool> = "metrics",
}
}
mod toolstate;
pub mod util;
+#[cfg(feature = "build-metrics")]
+mod metrics;
+
#[cfg(windows)]
mod job;
prerelease_version: Cell<Option<u32>>,
tool_artifacts:
RefCell<HashMap<TargetSelection, HashMap<String, (&'static str, PathBuf, Vec<String>)>>>,
+
+ #[cfg(feature = "build-metrics")]
+ metrics: metrics::BuildMetrics,
}
#[derive(Debug)]
delayed_failures: RefCell::new(Vec::new()),
prerelease_version: Cell::new(None),
tool_artifacts: Default::default(),
+
+ #[cfg(feature = "build-metrics")]
+ metrics: metrics::BuildMetrics::init(),
};
build.verbose("finding compilers");
}
process::exit(1);
}
+
+ #[cfg(feature = "build-metrics")]
+ self.metrics.persist(self);
}
/// Clear out `dir` if `input` is newer.
--- /dev/null
+//! This module is responsible for collecting metrics profiling information for the current build
+//! and dumping it to disk as JSON, to aid investigations on build and CI performance.
+//!
+//! As this module requires additional dependencies not present during local builds, it's cfg'd
+//! away whenever the `build.metrics` config option is not set to `true`.
+
+use crate::builder::Step;
+use crate::util::t;
+use crate::Build;
+use serde::{Deserialize, Serialize};
+use std::cell::RefCell;
+use std::fs::File;
+use std::io::BufWriter;
+use std::time::{Duration, Instant};
+use sysinfo::{CpuExt, System, SystemExt};
+
+pub(crate) struct BuildMetrics {
+ state: RefCell<MetricsState>,
+}
+
+impl BuildMetrics {
+ pub(crate) fn init() -> Self {
+ let state = RefCell::new(MetricsState {
+ finished_steps: Vec::new(),
+ running_steps: Vec::new(),
+
+ system_info: System::new(),
+ timer_start: None,
+ invocation_timer_start: Instant::now(),
+ });
+
+ BuildMetrics { state }
+ }
+
+ pub(crate) fn enter_step<S: Step>(&self, step: &S) {
+ let mut state = self.state.borrow_mut();
+
+ // Consider all the stats gathered so far as the parent's.
+ if !state.running_steps.is_empty() {
+ self.collect_stats(&mut *state);
+ }
+
+ state.system_info.refresh_cpu();
+ state.timer_start = Some(Instant::now());
+
+ state.running_steps.push(StepMetrics {
+ type_: std::any::type_name::<S>().into(),
+ debug_repr: format!("{step:?}"),
+
+ cpu_usage_time_sec: 0.0,
+ duration_excluding_children_sec: Duration::ZERO,
+
+ children: Vec::new(),
+ });
+ }
+
+ pub(crate) fn exit_step(&self) {
+ let mut state = self.state.borrow_mut();
+
+ self.collect_stats(&mut *state);
+
+ let step = state.running_steps.pop().unwrap();
+ if state.running_steps.is_empty() {
+ state.finished_steps.push(step);
+ state.timer_start = None;
+ } else {
+ state.running_steps.last_mut().unwrap().children.push(step);
+
+ // Start collecting again for the parent step.
+ state.system_info.refresh_cpu();
+ state.timer_start = Some(Instant::now());
+ }
+ }
+
+ fn collect_stats(&self, state: &mut MetricsState) {
+ let step = state.running_steps.last_mut().unwrap();
+
+ let elapsed = state.timer_start.unwrap().elapsed();
+ step.duration_excluding_children_sec += elapsed;
+
+ state.system_info.refresh_cpu();
+ let cpu = state.system_info.cpus().iter().map(|p| p.cpu_usage()).sum::<f32>();
+ step.cpu_usage_time_sec += cpu as f64 / 100.0 * elapsed.as_secs_f64();
+ }
+
+ pub(crate) fn persist(&self, build: &Build) {
+ let mut state = self.state.borrow_mut();
+ assert!(state.running_steps.is_empty(), "steps are still executing");
+
+ let dest = build.out.join("metrics.json");
+
+ let mut system = System::new();
+ system.refresh_cpu();
+ system.refresh_memory();
+
+ let system_stats = JsonInvocationSystemStats {
+ cpu_threads_count: system.cpus().len(),
+ cpu_model: system.cpus()[0].brand().into(),
+
+ memory_total_bytes: system.total_memory() * 1024,
+ };
+ let steps = std::mem::take(&mut state.finished_steps);
+
+ // Some of our CI builds consist of multiple independent CI invocations. Ensure all the
+ // previous invocations are still present in the resulting file.
+ let mut invocations = match std::fs::read(&dest) {
+ Ok(contents) => t!(serde_json::from_slice::<JsonRoot>(&contents)).invocations,
+ Err(err) => {
+ if err.kind() != std::io::ErrorKind::NotFound {
+ panic!("failed to open existing metrics file at {}: {err}", dest.display());
+ }
+ Vec::new()
+ }
+ };
+ invocations.push(JsonInvocation {
+ duration_including_children_sec: state.invocation_timer_start.elapsed().as_secs_f64(),
+ children: steps.into_iter().map(|step| self.prepare_json_step(step)).collect(),
+ });
+
+ let json = JsonRoot { system_stats, invocations };
+
+ t!(std::fs::create_dir_all(dest.parent().unwrap()));
+ let mut file = BufWriter::new(t!(File::create(&dest)));
+ t!(serde_json::to_writer(&mut file, &json));
+ }
+
+ fn prepare_json_step(&self, step: StepMetrics) -> JsonNode {
+ JsonNode::RustbuildStep {
+ type_: step.type_,
+ debug_repr: step.debug_repr,
+
+ duration_excluding_children_sec: step.duration_excluding_children_sec.as_secs_f64(),
+ system_stats: JsonStepSystemStats {
+ cpu_utilization_percent: step.cpu_usage_time_sec * 100.0
+ / step.duration_excluding_children_sec.as_secs_f64(),
+ },
+
+ children: step
+ .children
+ .into_iter()
+ .map(|child| self.prepare_json_step(child))
+ .collect(),
+ }
+ }
+}
+
+struct MetricsState {
+ finished_steps: Vec<StepMetrics>,
+ running_steps: Vec<StepMetrics>,
+
+ system_info: System,
+ timer_start: Option<Instant>,
+ invocation_timer_start: Instant,
+}
+
+struct StepMetrics {
+ type_: String,
+ debug_repr: String,
+
+ cpu_usage_time_sec: f64,
+ duration_excluding_children_sec: Duration,
+
+ children: Vec<StepMetrics>,
+}
+
+#[derive(Serialize, Deserialize)]
+#[serde(rename_all = "snake_case")]
+struct JsonRoot {
+ system_stats: JsonInvocationSystemStats,
+ invocations: Vec<JsonInvocation>,
+}
+
+#[derive(Serialize, Deserialize)]
+#[serde(rename_all = "snake_case")]
+struct JsonInvocation {
+ duration_including_children_sec: f64,
+ children: Vec<JsonNode>,
+}
+
+#[derive(Serialize, Deserialize)]
+#[serde(tag = "kind", rename_all = "snake_case")]
+enum JsonNode {
+ RustbuildStep {
+ #[serde(rename = "type")]
+ type_: String,
+ debug_repr: String,
+
+ duration_excluding_children_sec: f64,
+ system_stats: JsonStepSystemStats,
+
+ children: Vec<JsonNode>,
+ },
+}
+
+#[derive(Serialize, Deserialize)]
+#[serde(rename_all = "snake_case")]
+struct JsonInvocationSystemStats {
+ cpu_threads_count: usize,
+ cpu_model: String,
+
+ memory_total_bytes: u64,
+}
+
+#[derive(Serialize, Deserialize)]
+#[serde(rename_all = "snake_case")]
+struct JsonStepSystemStats {
+ cpu_utilization_percent: f64,
+}
if builder.config.llvm_profile_generate {
cfg.define("LLVM_BUILD_INSTRUMENTED", "IR");
+ if let Ok(llvm_profile_dir) = std::env::var("LLVM_PROFILE_DIR") {
+ cfg.define("LLVM_PROFILE_DATA_DIR", llvm_profile_dir);
+ }
cfg.define("LLVM_BUILD_RUNTIME", "No");
}
if let Some(path) = builder.config.llvm_profile_use.as_ref() {
rm -rf /tmp/rustc-pgo
+# This path has to be absolute
+LLVM_PROFILE_DIRECTORY_ROOT=/tmp/llvm-pgo
+
# We collect LLVM profiling information and rustc profiling information in
# separate phases. This increases build time -- though not by a huge amount --
# but prevents any problems from arising due to different profiling runtimes
# being simultaneously linked in.
-
-python3 ../x.py build --target=$PGO_HOST --host=$PGO_HOST \
+# LLVM IR PGO does not respect LLVM_PROFILE_FILE, so we have to set the profiling file
+# path through our custom environment variable. We include the PID in the directory path
+# to avoid updates to profile files being lost because of race conditions.
+LLVM_PROFILE_DIR=${LLVM_PROFILE_DIRECTORY_ROOT}/prof-%p python3 ../x.py build \
+ --target=$PGO_HOST \
+ --host=$PGO_HOST \
--stage 2 library/std \
--llvm-profile-generate
gather_profiles "Debug,Opt" "Full" \
"syn-1.0.89,cargo-0.60.0,serde-1.0.136,ripgrep-13.0.0,regex-1.5.5,clap-3.1.6,hyper-0.14.18"
+LLVM_PROFILE_MERGED_FILE=/tmp/llvm-pgo.profdata
+
# Merge the profile data we gathered for LLVM
# Note that this uses the profdata from the clang we used to build LLVM,
# which likely has a different version than our in-tree clang.
-/rustroot/bin/llvm-profdata \
- merge -o /tmp/llvm-pgo.profdata ./build/$PGO_HOST/llvm/build/profiles
+/rustroot/bin/llvm-profdata merge -o ${LLVM_PROFILE_MERGED_FILE} ${LLVM_PROFILE_DIRECTORY_ROOT}
+
+echo "LLVM PGO statistics"
+du -sh ${LLVM_PROFILE_MERGED_FILE}
+du -sh ${LLVM_PROFILE_DIRECTORY_ROOT}
+echo "Profile file count"
+find ${LLVM_PROFILE_DIRECTORY_ROOT} -type f | wc -l
# Rustbuild currently doesn't support rebuilding LLVM when PGO options
# change (or any other llvm-related options); so just clear out the relevant
# Okay, LLVM profiling is done, switch to rustc PGO.
+# The path has to be absolute
+RUSTC_PROFILE_DIRECTORY_ROOT=/tmp/rustc-pgo
+
python3 ../x.py build --target=$PGO_HOST --host=$PGO_HOST \
--stage 2 library/std \
- --rust-profile-generate=/tmp/rustc-pgo
+ --rust-profile-generate=${RUSTC_PROFILE_DIRECTORY_ROOT}
# Here we're profiling the `rustc` frontend, so we also include `Check`.
# The benchmark set includes various stress tests that put the frontend under pressure.
# rustc invocation ends. Empirically, this can result in some profiling data being lost.
# That's why we override the profile path to include the PID. This will produce many more profiling
# files, but the resulting profile will produce a slightly faster rustc binary.
-LLVM_PROFILE_FILE=/tmp/rustc-pgo/default_%m_%p.profraw gather_profiles "Check,Debug,Opt" "All" \
-"externs,ctfe-stress-5,cargo-0.60.0,token-stream-stress,match-stress,tuple-stress,diesel-1.4.8,bitmaps-3.1.0"
+LLVM_PROFILE_FILE=${RUSTC_PROFILE_DIRECTORY_ROOT}/default_%m_%p.profraw gather_profiles \
+ "Check,Debug,Opt" "All" \
+ "externs,ctfe-stress-5,cargo-0.60.0,token-stream-stress,match-stress,tuple-stress,diesel-1.4.8,bitmaps-3.1.0"
+
+RUSTC_PROFILE_MERGED_FILE=/tmp/rustc-pgo.profdata
# Merge the profile data we gathered
./build/$PGO_HOST/llvm/bin/llvm-profdata \
- merge -o /tmp/rustc-pgo.profdata /tmp/rustc-pgo
+ merge -o ${RUSTC_PROFILE_MERGED_FILE} ${RUSTC_PROFILE_DIRECTORY_ROOT}
+
+echo "Rustc PGO statistics"
+du -sh ${RUSTC_PROFILE_MERGED_FILE}
+du -sh ${RUSTC_PROFILE_DIRECTORY_ROOT}
+echo "Profile file count"
+find ${RUSTC_PROFILE_DIRECTORY_ROOT} -type f | wc -l
# Rustbuild currently doesn't support rebuilding LLVM when PGO options
# change (or any other llvm-related options); so just clear out the relevant
# This produces the actual final set of artifacts, using both the LLVM and rustc
# collected profiling data.
$@ \
- --rust-profile-use=/tmp/rustc-pgo.profdata \
- --llvm-profile-use=/tmp/llvm-pgo.profdata
+ --rust-profile-use=${RUSTC_PROFILE_MERGED_FILE} \
+ --llvm-profile-use=${LLVM_PROFILE_MERGED_FILE}
if ! isCI || isCiBranch auto || isCiBranch beta || isCiBranch try; then
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.print-step-timings --enable-verbose-tests"
+ RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.metrics"
fi
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-sccache"
upload_dir="$(mktemp -d)"
+build_dir=build
+if isLinux; then
+ build_dir=obj/build
+fi
+
# Release tarballs produced by a dist builder.
if [[ "${DEPLOY-0}" -eq "1" ]] || [[ "${DEPLOY_ALT-0}" -eq "1" ]]; then
- dist_dir=build/dist
- if isLinux; then
- dist_dir=obj/build/dist
- fi
+ dist_dir="${build_dir}/dist"
rm -rf "${dist_dir}/doc"
cp -r "${dist_dir}"/* "${upload_dir}"
fi
# CPU usage statistics.
cp cpu-usage.csv "${upload_dir}/cpu-${CI_JOB_NAME}.csv"
+# Build metrics generated by x.py.
+cp "${build_dir}/metrics.json" "${upload_dir}/metrics-${CI_JOB_NAME}.json"
+
# Toolstate data.
if [[ -n "${DEPLOY_TOOLSTATES_JSON+x}" ]]; then
cp /tmp/toolstate/toolstates.json "${upload_dir}/${DEPLOY_TOOLSTATES_JSON}"
else:
actual_str = flatten(actual_tree)
+ expected_str = expected_str.replace("{{channel}}", channel)
+
# Conditions:
# 1. Is --bless
# 2. Are actual and expected tree different
generics: Option<&hir::Generics<'tcx>>,
param: &hir::GenericParam<'tcx>,
) -> GenericParamDef {
+ let did = cx.tcx.hir().local_def_id(param.hir_id);
let (name, kind) = match param.kind {
hir::GenericParamKind::Lifetime { .. } => {
let outlives = if let Some(generics) = generics {
generics
- .predicates
- .iter()
- .flat_map(|pred| {
- match pred {
- hir::WherePredicate::RegionPredicate(rp)
- if rp.lifetime.name == hir::LifetimeName::Param(param.name)
- && !rp.in_where_clause =>
- {
- rp.bounds
- }
- _ => &[],
- }
- .iter()
- })
+ .outlives_for_param(did)
+ .filter(|bp| !bp.in_where_clause)
+ .flat_map(|bp| bp.bounds)
.map(|bound| match bound {
hir::GenericBound::Outlives(lt) => lt.clean(cx),
_ => panic!(),
(param.name.ident().name, GenericParamDefKind::Lifetime { outlives })
}
hir::GenericParamKind::Type { ref default, synthetic } => {
- let did = cx.tcx.hir().local_def_id(param.hir_id);
let bounds = if let Some(generics) = generics {
generics
.bounds_for_param(did)
hir::GenericParamKind::Const { ty, default } => (
param.name.ident().name,
GenericParamDefKind::Const {
- did: cx.tcx.hir().local_def_id(param.hir_id).to_def_id(),
+ did: did.to_def_id(),
ty: Box::new(ty.clean(cx)),
default: default.map(|ct| {
let def_id = cx.tcx.hir().local_def_id(ct.hir_id);
// Turning `fn f(&'_ self)` into `fn f(&self)` isn't the worst thing in the world, though;
// there's no case where it could cause the function to fail to compile.
let elided =
- l.is_elided() || matches!(l.name, LifetimeName::Param(ParamName::Fresh(_)));
+ l.is_elided() || matches!(l.name, LifetimeName::Param(_, ParamName::Fresh));
let lifetime = if elided { None } else { Some(l.clean(cx)) };
BorrowedRef { lifetime, mutability: m.mutbl, type_: box m.ty.clean(cx) }
}
matches!(self, Type::Generic(_))
}
+ pub(crate) fn is_impl_trait(&self) -> bool {
+ matches!(self, Type::ImplTrait(_))
+ }
+
pub(crate) fn is_primitive(&self) -> bool {
self.primitive_type().is_some()
}
pub(crate) use renderer::{run_format, FormatRenderer};
use crate::clean::{self, ItemId};
+use crate::html::render::Context;
/// Specifies whether rendering directly implemented trait items or ones from a certain Deref
/// impl.
}
}
}
+
+ // Returns true if this is an implementation on a "local" type, meaning:
+ // the type is in the current crate, or the type and the trait are both
+ // re-exported by the current crate.
+ pub(crate) fn is_on_local_type(&self, cx: &Context<'_>) -> bool {
+ let cache = cx.cache();
+ let for_type = &self.inner_impl().for_;
+ if let Some(for_type_did) = for_type.def_id(cache) {
+ // The "for" type is local if it's in the paths for the current crate.
+ if cache.paths.contains_key(&for_type_did) {
+ return true;
+ }
+ if let Some(trait_did) = self.trait_did() {
+ // The "for" type and the trait are from the same crate. That could
+ // be different from the current crate, for instance when both were
+ // re-exported from some other crate. But they are local with respect to
+ // each other.
+ if for_type_did.krate == trait_did.krate {
+ return true;
+ }
+ // Hack: many traits and types in std are re-exported from
+ // core or alloc. In general, rustdoc is capable of recognizing
+ // these implementations as being on local types. However, in at
+ // least one case (https://github.com/rust-lang/rust/issues/97610),
+ // rustdoc gets confused and labels an implementation as being on
+ // a foreign type. To make sure that confusion doesn't pass on to
+ // the reader, consider all implementations in std, core, and alloc
+ // to be on local types.
+ let crate_name = cx.tcx().crate_name(trait_did.krate);
+ if matches!(crate_name.as_str(), "std" | "core" | "alloc") {
+ return true;
+ }
+ }
+ return false;
+ };
+ true
+ }
}
}
}
}
- clean::Slice(ref t) => {
- primitive_link(f, PrimitiveType::Slice, "[", cx)?;
- fmt::Display::fmt(&t.print(cx), f)?;
- primitive_link(f, PrimitiveType::Slice, "]", cx)
- }
+ clean::Slice(ref t) => match **t {
+ clean::Generic(name) => {
+ primitive_link(f, PrimitiveType::Slice, &format!("[{name}]"), cx)
+ }
+ _ => {
+ primitive_link(f, PrimitiveType::Slice, "[", cx)?;
+ fmt::Display::fmt(&t.print(cx), f)?;
+ primitive_link(f, PrimitiveType::Slice, "]", cx)
+ }
+ },
clean::Array(ref t, ref n) => {
primitive_link(f, PrimitiveType::Array, "[", cx)?;
fmt::Display::fmt(&t.print(cx), f)?;
clean::Slice(ref bt) => {
// `BorrowedRef{ ... Slice(T) }` is `&[T]`
match **bt {
- clean::Generic(_) => {
- if f.alternate() {
- primitive_link(
- f,
- PrimitiveType::Slice,
- &format!("{}{}{}[{:#}]", amp, lt, m, bt.print(cx)),
- cx,
- )
- } else {
- primitive_link(
- f,
- PrimitiveType::Slice,
- &format!("{}{}{}[{}]", amp, lt, m, bt.print(cx)),
- cx,
- )
- }
- }
+ clean::Generic(name) => primitive_link(
+ f,
+ PrimitiveType::Slice,
+ &format!("{amp}{lt}{m}[{name}]"),
+ cx,
+ ),
_ => {
primitive_link(
f,
|sym| format!("<a href=\"#{1}.{0}\">{0}</a>", sym, ItemType::Method),
);
- let cache = cx.cache();
- if let Some(implementors) = cache.implementors.get(&it.item_id.expect_def_id()) {
+ if let Some(implementors) = cx.cache().implementors.get(&it.item_id.expect_def_id()) {
let mut res = implementors
.iter()
- .filter(|i| {
- i.inner_impl().for_.def_id(cache).map_or(false, |d| !cache.paths.contains_key(&d))
- })
+ .filter(|i| !i.is_on_local_type(cx))
.filter_map(|i| extract_for_impl_name(&i.impl_item, cx))
.collect::<Vec<_>>();
}
}
- let (local, foreign) = implementors.iter().partition::<Vec<_>, _>(|i| {
- i.inner_impl().for_.def_id(cache).map_or(true, |d| cache.paths.contains_key(&d))
- });
+ let (local, foreign) =
+ implementors.iter().partition::<Vec<_>, _>(|i| i.is_on_local_type(cx));
let (mut synthetic, mut concrete): (Vec<&&Impl>, Vec<&&Impl>) =
local.iter().partition(|i| i.inner_impl().kind.is_auto());
Some(path.segments.last().unwrap().name)
}
// We return an empty name because we don't care about the generic name itself.
- clean::Generic(_) => Some(kw::Empty),
+ clean::Generic(_) | clean::ImplTrait(_) => Some(kw::Empty),
clean::Primitive(ref p) => Some(p.as_sym()),
- clean::BorrowedRef { ref type_, .. } => get_index_type_name(type_),
+ clean::BorrowedRef { ref type_, .. } | clean::RawPointer(_, ref type_) => {
+ get_index_type_name(type_)
+ }
clean::BareFunction(_)
| clean::Tuple(_)
| clean::Slice(_)
| clean::Array(_, _)
- | clean::RawPointer(_, _)
| clean::QPath { .. }
- | clean::Infer
- | clean::ImplTrait(_) => None,
+ | clean::Infer => None,
}
}
mut generics: Vec<TypeWithKind>,
cache: &Cache,
) {
- let is_full_generic = ty.is_full_generic();
+ // generics and impl trait are both identified by their generics,
+ // rather than a type name itself
+ let anonymous = ty.is_full_generic() || ty.is_impl_trait();
let generics_empty = generics.is_empty();
- if is_full_generic {
+ if anonymous {
if generics_empty {
// This is a type parameter with no trait bounds (for example: `T` in
// `fn f<T>(p: T)`, so not useful for the rustdoc search because we would end up
if index_ty.name.as_ref().map(|s| s.is_empty() && generics_empty).unwrap_or(true) {
return;
}
- if is_full_generic {
+ if anonymous {
// We remove the name of the full generic because we have no use for it.
index_ty.name = Some(String::new());
res.push(TypeWithKind::from((index_ty, ItemType::Generic)));
}
insert_ty(res, tcx, arg.clone(), ty_generics, cache);
}
+ } else if let Type::ImplTrait(ref bounds) = *arg {
+ let mut ty_generics = Vec::new();
+ for bound in bounds {
+ if let Some(path) = bound.get_trait_path() {
+ let ty = Type::Path { path };
+ add_generics_and_bounds_as_types(
+ self_,
+ generics,
+ &ty,
+ tcx,
+ recurse + 1,
+ &mut ty_generics,
+ cache,
+ );
+ }
+ }
+ insert_ty(res, tcx, arg.clone(), ty_generics, cache);
} else {
// This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're
// looking at `Option`, we enter this "else" condition, otherwise if it's `T`, we don't.
"no-dupe-keys": "error",
"no-duplicate-case": "error",
"no-ex-assign": "error",
+ "no-fallthrough": "error",
+ "no-invalid-regexp": "error",
+ "no-import-assign": "error",
+ "no-self-compare": "error",
+ "no-template-curly-in-string": "error",
+ "block-scoped-var": "error",
+ "guard-for-in": "error",
+ "no-alert": "error",
}
};
position: relative;
}
-.setting-line > div {
- display: inline-block;
- vertical-align: top;
- font-size: 17px;
- padding-top: 2px;
-}
-
-.setting-line > .title {
- font-size: 19px;
- width: 100%;
- max-width: none;
- border-bottom: 1px solid;
-}
-
-.setting-line .radio-line,
.setting-line .choices {
display: flex;
flex-wrap: wrap;
}
-.setting-line .radio-line .setting-name {
- flex-grow: 1;
- margin-top: auto;
- margin-bottom: auto;
-}
-
.setting-line .radio-line input {
margin-right: 0.3em;
+ height: 1.2rem;
+ width: 1.2rem;
+ border: 1px solid;
+ outline: none;
+ -webkit-appearance: none;
+ cursor: pointer;
+ border-radius: 50%;
+}
+.setting-line .radio-line input + span {
+ padding-bottom: 1px;
+}
+
+.radio-line .setting-name {
+ width: 100%;
}
.radio-line .choice {
- border-radius: 0.1em;
- border: 1px solid;
- margin-left: 0.5em;
margin-top: 0.1em;
margin-bottom: 0.1em;
min-width: 3.8em;
padding: 0.3em;
+ display: flex;
+ align-items: center;
+ cursor: pointer;
+}
+.radio-line .choice + .choice {
+ margin-left: 0.5em;
}
.toggle {
width: 19px;
left: 4px;
bottom: 4px;
- background-color: white;
transition: .3s;
}
-input:checked + .slider {
- background-color: #2196F3;
-}
-
-input:focus + .slider {
- box-shadow: 0 0 0 2px #0a84ff, 0 0 0 6px rgba(10, 132, 255, 0.3);
-}
-
input:checked + .slider:before {
transform: translateX(19px);
}
color: #c5c5c5;
}
+.setting-line .radio-line input {
+ border-color: #c5c5c5;
+}
+.setting-line .radio-line input:checked {
+ box-shadow: inset 0 0 0 3px #0f1419;
+ background-color: #ffb454;
+}
+.setting-line .radio-line input:focus {
+ box-shadow: 0 0 1px 1px #ffb454;
+}
+/* In here we combine both `:focus` and `:checked` properties. */
+.setting-line .radio-line input:checked:focus {
+ box-shadow: inset 0 0 0 3px 0f1419,
+ 0 0 2px 2px #ffb454;
+}
+.setting-line .radio-line input:hover {
+ border-color: #ffb454 !important;
+}
+
+.slider {
+ background-color: #ccc;
+}
+.slider:before {
+ background-color: white;
+}
+input:checked + .slider {
+ background-color: #ffb454;
+}
+input:focus + .slider {
+ box-shadow: 0 0 0 2px #0a84ff, 0 0 0 6px rgba(10, 132, 255, 0.3);
+}
+
h1, h2, h3, h4 {
color: white;
}
background-color: #14191f;
color: #ffb44c;
}
-.setting-line > .title {
- border-bottom-color: #5c6773;
-}
-input:checked + .slider {
- background-color: #ffb454 !important;
-}
-
.scraped-example-list .scrape-help {
border-color: #aaa;
color: #ddd;
}
+.setting-line .radio-line input {
+ border-color: #ddd;
+}
+.setting-line .radio-line input:checked {
+ box-shadow: inset 0 0 0 3px #353535;
+ background-color: #2196f3;
+}
+.setting-line .radio-line input:focus {
+ box-shadow: 0 0 1px 1px #2196f3;
+}
+/* In here we combine both `:focus` and `:checked` properties. */
+.setting-line .radio-line input:checked:focus {
+ box-shadow: inset 0 0 0 3px #353535,
+ 0 0 2px 2px #2196f3;
+}
+.setting-line .radio-line input:hover {
+ border-color: #2196f3 !important;
+}
+
+.slider {
+ background-color: #ccc;
+}
+.slider:before {
+ background-color: white;
+}
+input:checked + .slider {
+ background-color: #2196F3;
+}
+input:focus + .slider {
+ box-shadow: 0 0 0 2px #0a84ff, 0 0 0 6px rgba(10, 132, 255, 0.3);
+}
+
h1, h2, h3, h4 {
color: #ddd;
}
div.files > .selected {
background-color: #333;
}
-.setting-line > .title {
- border-bottom-color: #ddd;
-}
.scraped-example-list .scrape-help {
border-color: #aaa;
color: black;
}
+.setting-line .radio-line input {
+ border-color: black;
+}
+.setting-line .radio-line input:checked {
+ box-shadow: inset 0 0 0 3px white;
+ background-color: #2196f3;
+}
+.setting-line .radio-line input:focus {
+ box-shadow: 0 0 1px 1px #2196f3;
+}
+/* In here we combine both `:focus` and `:checked` properties. */
+.setting-line .radio-line input:checked:focus {
+ box-shadow: inset 0 0 0 3px white,
+ 0 0 2px 2px #2196f3;
+}
+.setting-line .radio-line input:hover {
+ border-color: #2196f3 !important;
+}
+
+.slider {
+ background-color: #ccc;
+}
+.slider:before {
+ background-color: white;
+}
+input:checked + .slider {
+ background-color: #2196F3;
+}
+input:focus + .slider {
+ box-shadow: 0 0 0 2px #0a84ff, 0 0 0 6px rgba(10, 132, 255, 0.3);
+}
+
h1, h2, h3, h4 {
color: black;
}
div.files > .selected {
background-color: #fff;
}
-.setting-line > .title {
- border-bottom-color: #D5D5D5;
-}
.scraped-example-list .scrape-help {
border-color: #555;
output += `<label for="${js_data_name}-${option}" class="choice">\
<input type="radio" name="${js_data_name}" \
id="${js_data_name}-${option}" value="${option}"${checked}>\
- ${option}\
+ <span>${option}</span>\
</label>`;
});
output += "</div></div>";
use rustc_ast::ast;
use rustc_hir::{def::CtorKind, def_id::DefId};
use rustc_middle::ty::{self, TyCtxt};
-use rustc_span::Pos;
+use rustc_span::{Pos, Symbol};
use rustc_target::spec::abi::Abi as RustcAbi;
use rustdoc_json_types::*;
.get(&item.item_id)
.into_iter()
.flatten()
- .map(|clean::ItemLink { link, did, .. }| (link.clone(), from_item_id((*did).into())))
+ .map(|clean::ItemLink { link, did, .. }| {
+ (link.clone(), from_item_id((*did).into(), self.tcx))
+ })
.collect();
let docs = item.attrs.collapsed_doc_value();
let attrs = item
_ => from_clean_item(item, self.tcx),
};
Some(Item {
- id: from_item_id(item_id),
+ id: from_item_id_with_name(item_id, self.tcx, name),
crate_id: item_id.krate().as_u32(),
name: name.map(|sym| sym.to_string()),
span: self.convert_span(span),
Inherited => Visibility::Default,
Restricted(did) if did.is_crate_root() => Visibility::Crate,
Restricted(did) => Visibility::Restricted {
- parent: from_item_id(did.into()),
+ parent: from_item_id(did.into(), self.tcx),
path: self.tcx.def_path(did).to_string_no_crate_verbose(),
},
}
}
}
-pub(crate) fn from_item_id(item_id: ItemId) -> Id {
- struct DisplayDefId(DefId);
+/// It generates an ID as follows:
+///
+/// `CRATE_ID:ITEM_ID[:NAME_ID]` (if there is no name, NAME_ID is not generated).
+pub(crate) fn from_item_id(item_id: ItemId, tcx: TyCtxt<'_>) -> Id {
+ from_item_id_with_name(item_id, tcx, None)
+}
+
+// FIXME: this function (and appending the name at the end of the ID) should be removed when
+// reexports are not inlined anymore for json format. It should be done in #93518.
+pub(crate) fn from_item_id_with_name(item_id: ItemId, tcx: TyCtxt<'_>, name: Option<Symbol>) -> Id {
+ struct DisplayDefId<'a>(DefId, TyCtxt<'a>, Option<Symbol>);
- impl fmt::Display for DisplayDefId {
+ impl<'a> fmt::Display for DisplayDefId<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "{}:{}", self.0.krate.as_u32(), u32::from(self.0.index))
+ let name = match self.2 {
+ Some(name) => format!(":{}", name.as_u32()),
+ None => self
+ .1
+ .opt_item_name(self.0)
+ .map(|n| format!(":{}", n.as_u32()))
+ .unwrap_or_default(),
+ };
+ write!(f, "{}:{}{}", self.0.krate.as_u32(), u32::from(self.0.index), name)
}
}
match item_id {
- ItemId::DefId(did) => Id(format!("{}", DisplayDefId(did))),
+ ItemId::DefId(did) => Id(format!("{}", DisplayDefId(did, tcx, name))),
ItemId::Blanket { for_, impl_id } => {
- Id(format!("b:{}-{}", DisplayDefId(impl_id), DisplayDefId(for_)))
+ Id(format!("b:{}-{}", DisplayDefId(impl_id, tcx, None), DisplayDefId(for_, tcx, name)))
}
ItemId::Auto { for_, trait_ } => {
- Id(format!("a:{}-{}", DisplayDefId(trait_), DisplayDefId(for_)))
+ Id(format!("a:{}-{}", DisplayDefId(trait_, tcx, None), DisplayDefId(for_, tcx, name)))
}
ItemId::Primitive(ty, krate) => Id(format!("p:{}:{}", krate.as_u32(), ty.as_sym())),
}
let header = item.fn_header(tcx);
match *item.kind {
- ModuleItem(m) => ItemEnum::Module(Module { is_crate, items: ids(m.items) }),
+ ModuleItem(m) => ItemEnum::Module(Module { is_crate, items: ids(m.items, tcx) }),
ImportItem(i) => ItemEnum::Import(i.into_tcx(tcx)),
StructItem(s) => ItemEnum::Struct(s.into_tcx(tcx)),
UnionItem(u) => ItemEnum::Union(u.into_tcx(tcx)),
struct_type: from_ctor_kind(struct_type),
generics: generics.into_tcx(tcx),
fields_stripped,
- fields: ids(fields),
+ fields: ids(fields, tcx),
impls: Vec::new(), // Added in JsonRenderer::item
}
}
Union {
generics: generics.into_tcx(tcx),
fields_stripped,
- fields: ids(fields),
+ fields: ids(fields, tcx),
impls: Vec::new(), // Added in JsonRenderer::item
}
}
match ty {
clean::Type::Path { path } => Type::ResolvedPath {
name: path.whole_name(),
- id: from_item_id(path.def_id().into()),
+ id: from_item_id(path.def_id().into(), tcx),
args: path.segments.last().map(|args| Box::new(args.clone().args.into_tcx(tcx))),
param_names: Vec::new(),
},
Type::ResolvedPath {
name: first_trait.whole_name(),
- id: from_item_id(first_trait.def_id().into()),
+ id: from_item_id(first_trait.def_id().into(), tcx),
args: first_trait
.segments
.last()
Trait {
is_auto,
is_unsafe: unsafety == rustc_hir::Unsafety::Unsafe,
- items: ids(items),
+ items: ids(items, tcx),
generics: generics.into_tcx(tcx),
bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
implementations: Vec::new(), // Added in JsonRenderer::item
.collect(),
trait_,
for_: for_.into_tcx(tcx),
- items: ids(items),
+ items: ids(items, tcx),
negative: negative_polarity,
synthetic,
blanket_impl: blanket_impl.map(|x| x.into_tcx(tcx)),
Enum {
generics: generics.into_tcx(tcx),
variants_stripped,
- variants: ids(variants),
+ variants: ids(variants, tcx),
impls: Vec::new(), // Added in JsonRenderer::item
}
}
}
impl FromWithTcx<clean::VariantStruct> for Struct {
- fn from_tcx(struct_: clean::VariantStruct, _tcx: TyCtxt<'_>) -> Self {
+ fn from_tcx(struct_: clean::VariantStruct, tcx: TyCtxt<'_>) -> Self {
let fields_stripped = struct_.has_stripped_entries();
let clean::VariantStruct { struct_type, fields } = struct_;
Struct {
struct_type: from_ctor_kind(struct_type),
generics: Default::default(),
fields_stripped,
- fields: ids(fields),
+ fields: ids(fields, tcx),
impls: Vec::new(),
}
}
})
.collect(),
),
- Struct(s) => Variant::Struct(ids(s.fields)),
+ Struct(s) => Variant::Struct(ids(s.fields, tcx)),
}
}
}
impl FromWithTcx<clean::Import> for Import {
- fn from_tcx(import: clean::Import, _tcx: TyCtxt<'_>) -> Self {
+ fn from_tcx(import: clean::Import, tcx: TyCtxt<'_>) -> Self {
use clean::ImportKind::*;
match import.kind {
Simple(s) => Import {
source: import.source.path.whole_name(),
name: s.to_string(),
- id: import.source.did.map(ItemId::from).map(from_item_id),
+ id: import.source.did.map(ItemId::from).map(|i| from_item_id(i, tcx)),
glob: false,
},
Glob => Import {
source: import.source.path.whole_name(),
name: import.source.path.last().to_string(),
- id: import.source.did.map(ItemId::from).map(from_item_id),
+ id: import.source.did.map(ItemId::from).map(|i| from_item_id(i, tcx)),
glob: true,
},
}
}
}
-fn ids(items: impl IntoIterator<Item = clean::Item>) -> Vec<Id> {
- items.into_iter().filter(|x| !x.is_stripped()).map(|i| from_item_id(i.item_id)).collect()
+fn ids(items: impl IntoIterator<Item = clean::Item>, tcx: TyCtxt<'_>) -> Vec<Id> {
+ items
+ .into_iter()
+ .filter(|x| !x.is_stripped())
+ .map(|i| from_item_id_with_name(i.item_id, tcx, i.name))
+ .collect()
}
use rustc_hir::def_id::DefId;
use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
+use rustc_span::def_id::LOCAL_CRATE;
use rustdoc_json_types as types;
use crate::error::Error;
use crate::formats::cache::Cache;
use crate::formats::FormatRenderer;
-use crate::json::conversions::{from_item_id, IntoWithTcx};
+use crate::json::conversions::{from_item_id, from_item_id_with_name, IntoWithTcx};
use crate::{clean, try_err};
#[derive(Clone)]
.map(|i| {
let item = &i.impl_item;
self.item(item.clone()).unwrap();
- from_item_id(item.item_id)
+ from_item_id_with_name(item.item_id, self.tcx, item.name)
})
.collect()
})
if item.item_id.is_local() || is_primitive_impl {
self.item(item.clone()).unwrap();
- Some(from_item_id(item.item_id))
+ Some(from_item_id_with_name(item.item_id, self.tcx, item.name))
} else {
None
}
if !id.is_local() {
let trait_item = &trait_item.trait_;
trait_item.items.clone().into_iter().for_each(|i| self.item(i).unwrap());
+ let item_id = from_item_id(id.into(), self.tcx);
Some((
- from_item_id(id.into()),
+ item_id.clone(),
types::Item {
- id: from_item_id(id.into()),
+ id: item_id,
crate_id: id.krate.as_u32(),
name: self
.cache
// Flatten items that recursively store other items
item.kind.inner_items().for_each(|i| self.item(i.clone()).unwrap());
+ let name = item.name;
let item_id = item.item_id;
if let Some(mut new_item) = self.convert_item(item) {
if let types::ItemEnum::Trait(ref mut t) = new_item.inner {
} else if let types::ItemEnum::Union(ref mut u) = new_item.inner {
u.impls = self.get_impls(item_id.expect_def_id())
}
- let removed = self.index.borrow_mut().insert(from_item_id(item_id), new_item.clone());
+ let removed = self
+ .index
+ .borrow_mut()
+ .insert(from_item_id_with_name(item_id, self.tcx, name), new_item.clone());
// FIXME(adotinthevoid): Currently, the index is duplicated. This is a sanity check
// to make sure the items are unique. The main place this happens is when an item, is
self.get_impls(*primitive);
}
+ let e = ExternalCrate { crate_num: LOCAL_CRATE };
+
let mut index = (*self.index).clone().into_inner();
index.extend(self.get_trait_items());
// This needs to be the default HashMap for compatibility with the public interface for
// rustdoc-json-types
#[allow(rustc::default_hash_types)]
let output = types::Crate {
- root: types::Id(String::from("0:0")),
+ root: types::Id(format!("0:0:{}", e.name(self.tcx).as_u32())),
crate_version: self.cache.crate_version.clone(),
includes_private: self.cache.document_private,
index: index.into_iter().collect(),
.chain(self.cache.external_paths.clone().into_iter())
.map(|(k, (path, kind))| {
(
- from_item_id(k.into()),
+ from_item_id(k.into(), self.tcx),
types::ItemSummary {
crate_id: k.krate.as_u32(),
path: path.iter().map(|s| s.to_string()).collect(),
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::def_id::DefId;
-use rustc_middle::ty::DefIdTree;
+use rustc_middle::ty::{self, DefIdTree};
use rustc_span::symbol::sym;
pub(crate) const COLLECT_TRAIT_IMPLS: Pass = Pass {
// Do not calculate blanket impl list for docs that are not going to be rendered.
// While the `impl` blocks themselves are only in `libcore`, the module with `doc`
// attached is directly included in `libstd` as well.
+ let tcx = cx.tcx;
if did.is_local() {
- for def_id in prim.impls(cx.tcx) {
+ for def_id in prim.impls(tcx).filter(|def_id| {
+ // Avoid including impl blocks with filled-in generics.
+ // https://github.com/rust-lang/rust/issues/94937
+ //
+ // FIXME(notriddle): https://github.com/rust-lang/rust/issues/97129
+ //
+ // This tactic of using inherent impl blocks for getting
+ // auto traits and blanket impls is a hack. What we really
+ // want is to check if `[T]` impls `Send`, which has
+ // nothing to do with the inherent impl.
+ //
+ // Rustdoc currently uses these `impl` block as a source of
+ // the `Ty`, as well as the `ParamEnv`, `SubstsRef`, and
+ // `Generics`. To avoid relying on the `impl` block, these
+ // things would need to be created from wholecloth, in a
+ // form that is valid for use in type inference.
+ let ty = tcx.type_of(def_id);
+ match ty.kind() {
+ ty::Slice(ty)
+ | ty::Ref(_, ty, _)
+ | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
+ matches!(ty.kind(), ty::Param(..))
+ }
+ ty::Tuple(tys) => tys.iter().all(|ty| matches!(ty.kind(), ty::Param(..))),
+ _ => true,
+ }
+ }) {
let impls = get_auto_trait_and_blanket_impls(cx, def_id);
new_items_external.extend(impls.filter(|i| cx.inlined.insert(i.item_id)));
}
self.visit_foreign_item(item, None, om);
}
}
- // If we're inlining, skip private items.
- _ if self.inlining && !is_pub => {}
+ // If we're inlining, skip private items or item reexported as "_".
+ _ if self.inlining && (!is_pub || renamed == Some(kw::Underscore)) => {}
hir::ItemKind::GlobalAsm(..) => {}
hir::ItemKind::Use(_, hir::UseKind::ListStem) => {}
hir::ItemKind::Use(path, kind) => {
-Subproject commit 47848665966fc7393cb6f898077994f6dec2b591
+Subproject commit c9e2e89ed3aa5a3be77143aa0c86906b4138374a
--- /dev/null
+// compile-flags:-g
+// We can't set the main thread name on Linux because it renames the process (#97191)
+// ignore-linux
+// ignore-android
+// ignore-dragonfly
+// ignore-emscripten
+// ignore-freebsd
+// ignore-haiku
+// ignore-ios
+// ignore-netbsd
+// ignore-openbsd
+// ignore-solaris
+// ignore-sgx
+// ignore-windows-gnu
+
+// === GDB TESTS ==================================================================================
+//
+// gdb-command:run
+//
+// gdb-command:info threads
+// gdb-check: 1 Thread [...] [...] "main" [...]
+// gdb-check:* 2 Thread [...] [...] "my new thread" [...]
+
+// === LLDB TESTS =================================================================================
+//
+// lldb-command:run
+//
+// lldb-command:thread info 1
+// lldb-check:thread #1:[...]name = 'main'[...]
+// lldb-command:thread info 2
+// lldb-check:thread #2:[...]name = 'my new thread'[...]
+
+// === CDB TESTS ==================================================================================
+//
+// cdb-command:g
+//
+// cdb-command:~
+// cdb-check: 0 Id: [...] Suspend: 1 Teb: [...] Unfrozen "main"
+// cdb-check:. [...] Id: [...] Suspend: 1 Teb: [...] Unfrozen "my new thread"
+
+use std::thread;
+
+fn main() {
+ let handle = thread::Builder::new().name("my new thread".into()).spawn(|| {
+ zzz(); // #break
+ }).unwrap();
+
+ handle.join().unwrap();
+}
+
+fn zzz() {}
// + span: $DIR/const_prop_fails_gracefully.rs:7:13: 7:16
// + literal: Const { ty: &i32, val: Unevaluated(FOO, [], None) }
_2 = &raw const (*_3); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:16
- _1 = move _2 as usize (Misc); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:39
+ _1 = move _2 as usize (PointerExposeAddress); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:39
StorageDead(_2); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:38: 7:39
StorageDead(_3); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:39: 7:40
StorageLive(_4); // scope 1 at $DIR/const_prop_fails_gracefully.rs:8:5: 8:12
// mir::Constant
// + span: $DIR/reify_fn_ptr.rs:4:13: 4:17
// + literal: Const { ty: fn() {main}, val: Value(Scalar(<ZST>)) }
- _2 = move _3 as usize (Misc); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:26
+ _2 = move _3 as usize (PointerExposeAddress); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:26
StorageDead(_3); // scope 0 at $DIR/reify_fn_ptr.rs:4:25: 4:26
- _1 = move _2 as *const fn() (Misc); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:41
+ _1 = move _2 as *const fn() (PointerFromExposedAddress); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:41
StorageDead(_2); // scope 0 at $DIR/reify_fn_ptr.rs:4:40: 4:41
StorageDead(_1); // scope 0 at $DIR/reify_fn_ptr.rs:4:41: 4:42
nop; // scope 0 at $DIR/reify_fn_ptr.rs:3:11: 5:2
StorageLive(_2); // scope 0 at $DIR/provenance_soundness.rs:8:9: 8:11
StorageLive(_3); // scope 0 at $DIR/provenance_soundness.rs:8:14: 8:15
_3 = _1; // scope 0 at $DIR/provenance_soundness.rs:8:14: 8:15
- _2 = move _3 as usize (Misc); // scope 0 at $DIR/provenance_soundness.rs:8:14: 8:24
+ _2 = move _3 as usize (PointerExposeAddress); // scope 0 at $DIR/provenance_soundness.rs:8:14: 8:24
StorageDead(_3); // scope 0 at $DIR/provenance_soundness.rs:8:23: 8:24
StorageLive(_4); // scope 1 at $DIR/provenance_soundness.rs:9:9: 9:11
StorageLive(_5); // scope 1 at $DIR/provenance_soundness.rs:9:14: 9:15
_5 = _1; // scope 1 at $DIR/provenance_soundness.rs:9:14: 9:15
- _4 = move _5 as isize (Misc); // scope 1 at $DIR/provenance_soundness.rs:9:14: 9:24
+ _4 = move _5 as isize (PointerExposeAddress); // scope 1 at $DIR/provenance_soundness.rs:9:14: 9:24
StorageDead(_5); // scope 1 at $DIR/provenance_soundness.rs:9:23: 9:24
_0 = const (); // scope 0 at $DIR/provenance_soundness.rs:7:32: 10:2
StorageDead(_4); // scope 1 at $DIR/provenance_soundness.rs:10:1: 10:2
+++ /dev/null
-- // MIR for `deep_opt` before InstCombine
-+ // MIR for `deep_opt` after InstCombine
-
- fn deep_opt() -> (u64, u64, u64) {
- let mut _0: (u64, u64, u64); // return place in scope 0 at $DIR/inst_combine_deref.rs:11:18: 11:33
- let _1: u64; // in scope 0 at $DIR/inst_combine_deref.rs:12:9: 12:11
- let mut _10: u64; // in scope 0 at $DIR/inst_combine_deref.rs:21:6: 21:8
- let mut _11: u64; // in scope 0 at $DIR/inst_combine_deref.rs:21:10: 21:12
- let mut _12: u64; // in scope 0 at $DIR/inst_combine_deref.rs:21:14: 21:16
- scope 1 {
- debug x1 => _1; // in scope 1 at $DIR/inst_combine_deref.rs:12:9: 12:11
- let _2: u64; // in scope 1 at $DIR/inst_combine_deref.rs:13:9: 13:11
- scope 2 {
- debug x2 => _2; // in scope 2 at $DIR/inst_combine_deref.rs:13:9: 13:11
- let _3: u64; // in scope 2 at $DIR/inst_combine_deref.rs:14:9: 14:11
- scope 3 {
- debug x3 => _3; // in scope 3 at $DIR/inst_combine_deref.rs:14:9: 14:11
- let _4: &u64; // in scope 3 at $DIR/inst_combine_deref.rs:15:9: 15:11
- scope 4 {
- debug y1 => _4; // in scope 4 at $DIR/inst_combine_deref.rs:15:9: 15:11
- let _5: &u64; // in scope 4 at $DIR/inst_combine_deref.rs:16:9: 16:11
- scope 5 {
- debug y2 => _5; // in scope 5 at $DIR/inst_combine_deref.rs:16:9: 16:11
- let _6: &u64; // in scope 5 at $DIR/inst_combine_deref.rs:17:9: 17:11
- scope 6 {
- debug y3 => _6; // in scope 6 at $DIR/inst_combine_deref.rs:17:9: 17:11
- let _7: u64; // in scope 6 at $DIR/inst_combine_deref.rs:18:9: 18:11
- scope 7 {
- debug z1 => _7; // in scope 7 at $DIR/inst_combine_deref.rs:18:9: 18:11
- let _8: u64; // in scope 7 at $DIR/inst_combine_deref.rs:19:9: 19:11
- scope 8 {
- debug z2 => _8; // in scope 8 at $DIR/inst_combine_deref.rs:19:9: 19:11
- let _9: u64; // in scope 8 at $DIR/inst_combine_deref.rs:20:9: 20:11
- scope 9 {
- debug z3 => _9; // in scope 9 at $DIR/inst_combine_deref.rs:20:9: 20:11
- }
- }
- }
- }
- }
- }
- }
- }
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/inst_combine_deref.rs:12:9: 12:11
- _1 = const 1_u64; // scope 0 at $DIR/inst_combine_deref.rs:12:14: 12:15
- StorageLive(_2); // scope 1 at $DIR/inst_combine_deref.rs:13:9: 13:11
- _2 = const 2_u64; // scope 1 at $DIR/inst_combine_deref.rs:13:14: 13:15
- StorageLive(_3); // scope 2 at $DIR/inst_combine_deref.rs:14:9: 14:11
- _3 = const 3_u64; // scope 2 at $DIR/inst_combine_deref.rs:14:14: 14:15
- StorageLive(_4); // scope 3 at $DIR/inst_combine_deref.rs:15:9: 15:11
- _4 = &_1; // scope 3 at $DIR/inst_combine_deref.rs:15:14: 15:17
- StorageLive(_5); // scope 4 at $DIR/inst_combine_deref.rs:16:9: 16:11
- _5 = &_2; // scope 4 at $DIR/inst_combine_deref.rs:16:14: 16:17
- StorageLive(_6); // scope 5 at $DIR/inst_combine_deref.rs:17:9: 17:11
- _6 = &_3; // scope 5 at $DIR/inst_combine_deref.rs:17:14: 17:17
- StorageLive(_7); // scope 6 at $DIR/inst_combine_deref.rs:18:9: 18:11
-- _7 = (*_4); // scope 6 at $DIR/inst_combine_deref.rs:18:14: 18:17
-+ _7 = _1; // scope 6 at $DIR/inst_combine_deref.rs:18:14: 18:17
- StorageLive(_8); // scope 7 at $DIR/inst_combine_deref.rs:19:9: 19:11
-- _8 = (*_5); // scope 7 at $DIR/inst_combine_deref.rs:19:14: 19:17
-+ _8 = _2; // scope 7 at $DIR/inst_combine_deref.rs:19:14: 19:17
- StorageLive(_9); // scope 8 at $DIR/inst_combine_deref.rs:20:9: 20:11
-- _9 = (*_6); // scope 8 at $DIR/inst_combine_deref.rs:20:14: 20:17
-+ _9 = _3; // scope 8 at $DIR/inst_combine_deref.rs:20:14: 20:17
- StorageLive(_10); // scope 9 at $DIR/inst_combine_deref.rs:21:6: 21:8
- _10 = _7; // scope 9 at $DIR/inst_combine_deref.rs:21:6: 21:8
- StorageLive(_11); // scope 9 at $DIR/inst_combine_deref.rs:21:10: 21:12
- _11 = _8; // scope 9 at $DIR/inst_combine_deref.rs:21:10: 21:12
- StorageLive(_12); // scope 9 at $DIR/inst_combine_deref.rs:21:14: 21:16
- _12 = _9; // scope 9 at $DIR/inst_combine_deref.rs:21:14: 21:16
- (_0.0: u64) = move _10; // scope 9 at $DIR/inst_combine_deref.rs:21:5: 21:17
- (_0.1: u64) = move _11; // scope 9 at $DIR/inst_combine_deref.rs:21:5: 21:17
- (_0.2: u64) = move _12; // scope 9 at $DIR/inst_combine_deref.rs:21:5: 21:17
- StorageDead(_12); // scope 9 at $DIR/inst_combine_deref.rs:21:16: 21:17
- StorageDead(_11); // scope 9 at $DIR/inst_combine_deref.rs:21:16: 21:17
- StorageDead(_10); // scope 9 at $DIR/inst_combine_deref.rs:21:16: 21:17
- StorageDead(_9); // scope 8 at $DIR/inst_combine_deref.rs:22:1: 22:2
- StorageDead(_8); // scope 7 at $DIR/inst_combine_deref.rs:22:1: 22:2
- StorageDead(_7); // scope 6 at $DIR/inst_combine_deref.rs:22:1: 22:2
- StorageDead(_6); // scope 5 at $DIR/inst_combine_deref.rs:22:1: 22:2
- StorageDead(_5); // scope 4 at $DIR/inst_combine_deref.rs:22:1: 22:2
- StorageDead(_4); // scope 3 at $DIR/inst_combine_deref.rs:22:1: 22:2
- StorageDead(_3); // scope 2 at $DIR/inst_combine_deref.rs:22:1: 22:2
- StorageDead(_2); // scope 1 at $DIR/inst_combine_deref.rs:22:1: 22:2
- StorageDead(_1); // scope 0 at $DIR/inst_combine_deref.rs:22:1: 22:2
- return; // scope 0 at $DIR/inst_combine_deref.rs:22:2: 22:2
- }
- }
-
+++ /dev/null
-- // MIR for `do_not_miscompile` before InstCombine
-+ // MIR for `do_not_miscompile` after InstCombine
-
- fn do_not_miscompile() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/inst_combine_deref.rs:54:24: 54:24
- let _1: i32; // in scope 0 at $DIR/inst_combine_deref.rs:55:9: 55:10
- let mut _5: &i32; // in scope 0 at $DIR/inst_combine_deref.rs:59:10: 59:12
- let _6: &i32; // in scope 0 at $DIR/inst_combine_deref.rs:59:10: 59:12
- let _7: (); // in scope 0 at $DIR/inst_combine_deref.rs:60:5: 60:23
- let mut _8: bool; // in scope 0 at $DIR/inst_combine_deref.rs:60:5: 60:23
- let mut _9: bool; // in scope 0 at $DIR/inst_combine_deref.rs:60:13: 60:21
- let mut _10: i32; // in scope 0 at $DIR/inst_combine_deref.rs:60:13: 60:15
- let mut _11: !; // in scope 0 at $DIR/inst_combine_deref.rs:60:5: 60:23
- scope 1 {
- debug x => _1; // in scope 1 at $DIR/inst_combine_deref.rs:55:9: 55:10
- let _2: i32; // in scope 1 at $DIR/inst_combine_deref.rs:56:9: 56:10
- scope 2 {
- debug a => _2; // in scope 2 at $DIR/inst_combine_deref.rs:56:9: 56:10
- let mut _3: &i32; // in scope 2 at $DIR/inst_combine_deref.rs:57:9: 57:14
- scope 3 {
- debug y => _3; // in scope 3 at $DIR/inst_combine_deref.rs:57:9: 57:14
- let _4: &mut &i32; // in scope 3 at $DIR/inst_combine_deref.rs:58:9: 58:10
- scope 4 {
- debug z => _4; // in scope 4 at $DIR/inst_combine_deref.rs:58:9: 58:10
- }
- }
- }
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/inst_combine_deref.rs:55:9: 55:10
- _1 = const 42_i32; // scope 0 at $DIR/inst_combine_deref.rs:55:13: 55:15
- StorageLive(_2); // scope 1 at $DIR/inst_combine_deref.rs:56:9: 56:10
- _2 = const 99_i32; // scope 1 at $DIR/inst_combine_deref.rs:56:13: 56:15
- StorageLive(_3); // scope 2 at $DIR/inst_combine_deref.rs:57:9: 57:14
- _3 = &_1; // scope 2 at $DIR/inst_combine_deref.rs:57:17: 57:19
- StorageLive(_4); // scope 3 at $DIR/inst_combine_deref.rs:58:9: 58:10
- _4 = &mut _3; // scope 3 at $DIR/inst_combine_deref.rs:58:13: 58:19
- StorageLive(_5); // scope 4 at $DIR/inst_combine_deref.rs:59:10: 59:12
- StorageLive(_6); // scope 4 at $DIR/inst_combine_deref.rs:59:10: 59:12
- _6 = &_2; // scope 4 at $DIR/inst_combine_deref.rs:59:10: 59:12
-- _5 = &(*_6); // scope 4 at $DIR/inst_combine_deref.rs:59:10: 59:12
-+ _5 = _6; // scope 4 at $DIR/inst_combine_deref.rs:59:10: 59:12
- (*_4) = move _5; // scope 4 at $DIR/inst_combine_deref.rs:59:5: 59:12
- StorageDead(_5); // scope 4 at $DIR/inst_combine_deref.rs:59:11: 59:12
- StorageDead(_6); // scope 4 at $DIR/inst_combine_deref.rs:59:12: 59:13
- StorageLive(_7); // scope 4 at $DIR/inst_combine_deref.rs:60:5: 60:23
- StorageLive(_8); // scope 4 at $DIR/inst_combine_deref.rs:60:5: 60:23
- StorageLive(_9); // scope 4 at $DIR/inst_combine_deref.rs:60:13: 60:21
- StorageLive(_10); // scope 4 at $DIR/inst_combine_deref.rs:60:13: 60:15
- _10 = (*_3); // scope 4 at $DIR/inst_combine_deref.rs:60:13: 60:15
- _9 = Eq(move _10, const 99_i32); // scope 4 at $DIR/inst_combine_deref.rs:60:13: 60:21
- StorageDead(_10); // scope 4 at $DIR/inst_combine_deref.rs:60:20: 60:21
- _8 = Not(move _9); // scope 4 at $DIR/inst_combine_deref.rs:60:5: 60:23
- StorageDead(_9); // scope 4 at $DIR/inst_combine_deref.rs:60:22: 60:23
- switchInt(move _8) -> [false: bb2, otherwise: bb1]; // scope 4 at $DIR/inst_combine_deref.rs:60:5: 60:23
- }
-
- bb1: {
- StorageLive(_11); // scope 4 at $DIR/inst_combine_deref.rs:60:5: 60:23
- core::panicking::panic(const "assertion failed: *y == 99"); // scope 4 at $DIR/inst_combine_deref.rs:60:5: 60:23
- // mir::Constant
- // + span: $DIR/inst_combine_deref.rs:60:5: 60:23
- // + literal: Const { ty: fn(&'static str) -> ! {core::panicking::panic}, val: Value(Scalar(<ZST>)) }
- // ty::Const
- // + ty: &str
- // + val: Value(Slice { data: Allocation { bytes: [97, 115, 115, 101, 114, 116, 105, 111, 110, 32, 102, 97, 105, 108, 101, 100, 58, 32, 42, 121, 32, 61, 61, 32, 57, 57], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [67108863], len: Size { raw: 26 } }, size: Size { raw: 26 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 26 })
- // mir::Constant
- // + span: $DIR/inst_combine_deref.rs:1:1: 1:1
- // + literal: Const { ty: &str, val: Value(Slice { data: Allocation { bytes: [97, 115, 115, 101, 114, 116, 105, 111, 110, 32, 102, 97, 105, 108, 101, 100, 58, 32, 42, 121, 32, 61, 61, 32, 57, 57], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [67108863], len: Size { raw: 26 } }, size: Size { raw: 26 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 26 }) }
- }
-
- bb2: {
- _7 = const (); // scope 4 at $DIR/inst_combine_deref.rs:60:23: 60:23
- StorageDead(_8); // scope 4 at $DIR/inst_combine_deref.rs:60:22: 60:23
- StorageDead(_7); // scope 4 at $DIR/inst_combine_deref.rs:60:22: 60:23
- _0 = const (); // scope 0 at $DIR/inst_combine_deref.rs:54:24: 61:2
- StorageDead(_4); // scope 3 at $DIR/inst_combine_deref.rs:61:1: 61:2
- StorageDead(_3); // scope 2 at $DIR/inst_combine_deref.rs:61:1: 61:2
- StorageDead(_2); // scope 1 at $DIR/inst_combine_deref.rs:61:1: 61:2
- StorageDead(_1); // scope 0 at $DIR/inst_combine_deref.rs:61:1: 61:2
- return; // scope 0 at $DIR/inst_combine_deref.rs:61:2: 61:2
- }
- }
-
+++ /dev/null
-- // MIR for `dont_opt` before InstCombine
-+ // MIR for `dont_opt` after InstCombine
-
- fn dont_opt() -> u64 {
- let mut _0: u64; // return place in scope 0 at $DIR/inst_combine_deref.rs:43:18: 43:21
- let _1: i32; // in scope 0 at $DIR/inst_combine_deref.rs:44:9: 44:10
- let mut _5: &i32; // in scope 0 at $DIR/inst_combine_deref.rs:48:10: 48:14
- scope 1 {
- debug y => _1; // in scope 1 at $DIR/inst_combine_deref.rs:44:9: 44:10
- let _2: &i32; // in scope 1 at $DIR/inst_combine_deref.rs:45:9: 45:13
- scope 2 {
- debug _ref => _2; // in scope 2 at $DIR/inst_combine_deref.rs:45:9: 45:13
- let _3: i32; // in scope 2 at $DIR/inst_combine_deref.rs:46:9: 46:10
- scope 3 {
- debug x => _3; // in scope 3 at $DIR/inst_combine_deref.rs:46:9: 46:10
- let mut _4: &i32; // in scope 3 at $DIR/inst_combine_deref.rs:47:9: 47:15
- scope 4 {
- debug _1 => _4; // in scope 4 at $DIR/inst_combine_deref.rs:47:9: 47:15
- let _6: i32; // in scope 4 at $DIR/inst_combine_deref.rs:49:9: 49:11
- scope 5 {
- debug _4 => _6; // in scope 5 at $DIR/inst_combine_deref.rs:49:9: 49:11
- }
- }
- }
- }
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/inst_combine_deref.rs:44:9: 44:10
- _1 = const 5_i32; // scope 0 at $DIR/inst_combine_deref.rs:44:13: 44:14
- StorageLive(_2); // scope 1 at $DIR/inst_combine_deref.rs:45:9: 45:13
- _2 = &_1; // scope 1 at $DIR/inst_combine_deref.rs:45:16: 45:18
- StorageLive(_3); // scope 2 at $DIR/inst_combine_deref.rs:46:9: 46:10
- _3 = const 5_i32; // scope 2 at $DIR/inst_combine_deref.rs:46:13: 46:14
- StorageLive(_4); // scope 3 at $DIR/inst_combine_deref.rs:47:9: 47:15
- _4 = &_3; // scope 3 at $DIR/inst_combine_deref.rs:47:18: 47:20
- StorageLive(_5); // scope 4 at $DIR/inst_combine_deref.rs:48:10: 48:14
-- _5 = &(*_2); // scope 4 at $DIR/inst_combine_deref.rs:48:10: 48:14
-+ _5 = _2; // scope 4 at $DIR/inst_combine_deref.rs:48:10: 48:14
- _4 = move _5; // scope 4 at $DIR/inst_combine_deref.rs:48:5: 48:14
- StorageDead(_5); // scope 4 at $DIR/inst_combine_deref.rs:48:13: 48:14
- StorageLive(_6); // scope 4 at $DIR/inst_combine_deref.rs:49:9: 49:11
- _6 = (*_4); // scope 4 at $DIR/inst_combine_deref.rs:49:14: 49:17
- _0 = const 0_u64; // scope 5 at $DIR/inst_combine_deref.rs:50:5: 50:6
- StorageDead(_6); // scope 4 at $DIR/inst_combine_deref.rs:51:1: 51:2
- StorageDead(_4); // scope 3 at $DIR/inst_combine_deref.rs:51:1: 51:2
- StorageDead(_3); // scope 2 at $DIR/inst_combine_deref.rs:51:1: 51:2
- StorageDead(_2); // scope 1 at $DIR/inst_combine_deref.rs:51:1: 51:2
- StorageDead(_1); // scope 0 at $DIR/inst_combine_deref.rs:51:1: 51:2
- return; // scope 0 at $DIR/inst_combine_deref.rs:51:2: 51:2
- }
- }
-
+++ /dev/null
-- // MIR for `opt_struct` before InstCombine
-+ // MIR for `opt_struct` after InstCombine
-
- fn opt_struct(_1: S) -> u64 {
- debug s => _1; // in scope 0 at $DIR/inst_combine_deref.rs:30:15: 30:16
- let mut _0: u64; // return place in scope 0 at $DIR/inst_combine_deref.rs:30:24: 30:27
- let _2: &u64; // in scope 0 at $DIR/inst_combine_deref.rs:31:9: 31:10
- let mut _5: u64; // in scope 0 at $DIR/inst_combine_deref.rs:34:5: 34:7
- let mut _6: u64; // in scope 0 at $DIR/inst_combine_deref.rs:34:10: 34:11
- scope 1 {
- debug a => _2; // in scope 1 at $DIR/inst_combine_deref.rs:31:9: 31:10
- let _3: &u64; // in scope 1 at $DIR/inst_combine_deref.rs:32:9: 32:10
- scope 2 {
- debug b => _3; // in scope 2 at $DIR/inst_combine_deref.rs:32:9: 32:10
- let _4: u64; // in scope 2 at $DIR/inst_combine_deref.rs:33:9: 33:10
- scope 3 {
- debug x => _4; // in scope 3 at $DIR/inst_combine_deref.rs:33:9: 33:10
- }
- }
- }
-
- bb0: {
- StorageLive(_2); // scope 0 at $DIR/inst_combine_deref.rs:31:9: 31:10
- _2 = &(_1.0: u64); // scope 0 at $DIR/inst_combine_deref.rs:31:13: 31:17
- StorageLive(_3); // scope 1 at $DIR/inst_combine_deref.rs:32:9: 32:10
- _3 = &(_1.1: u64); // scope 1 at $DIR/inst_combine_deref.rs:32:13: 32:17
- StorageLive(_4); // scope 2 at $DIR/inst_combine_deref.rs:33:9: 33:10
-- _4 = (*_2); // scope 2 at $DIR/inst_combine_deref.rs:33:13: 33:15
-+ _4 = (_1.0: u64); // scope 2 at $DIR/inst_combine_deref.rs:33:13: 33:15
- StorageLive(_5); // scope 3 at $DIR/inst_combine_deref.rs:34:5: 34:7
-- _5 = (*_3); // scope 3 at $DIR/inst_combine_deref.rs:34:5: 34:7
-+ _5 = (_1.1: u64); // scope 3 at $DIR/inst_combine_deref.rs:34:5: 34:7
- StorageLive(_6); // scope 3 at $DIR/inst_combine_deref.rs:34:10: 34:11
- _6 = _4; // scope 3 at $DIR/inst_combine_deref.rs:34:10: 34:11
- _0 = Add(move _5, move _6); // scope 3 at $DIR/inst_combine_deref.rs:34:5: 34:11
- StorageDead(_6); // scope 3 at $DIR/inst_combine_deref.rs:34:10: 34:11
- StorageDead(_5); // scope 3 at $DIR/inst_combine_deref.rs:34:10: 34:11
- StorageDead(_4); // scope 2 at $DIR/inst_combine_deref.rs:35:1: 35:2
- StorageDead(_3); // scope 1 at $DIR/inst_combine_deref.rs:35:1: 35:2
- StorageDead(_2); // scope 0 at $DIR/inst_combine_deref.rs:35:1: 35:2
- return; // scope 0 at $DIR/inst_combine_deref.rs:35:2: 35:2
- }
- }
-
+++ /dev/null
-- // MIR for `simple_opt` before InstCombine
-+ // MIR for `simple_opt` after InstCombine
-
- fn simple_opt() -> u64 {
- let mut _0: u64; // return place in scope 0 at $DIR/inst_combine_deref.rs:3:20: 3:23
- let _1: u64; // in scope 0 at $DIR/inst_combine_deref.rs:4:9: 4:10
- scope 1 {
- debug x => _1; // in scope 1 at $DIR/inst_combine_deref.rs:4:9: 4:10
- let _2: &u64; // in scope 1 at $DIR/inst_combine_deref.rs:5:9: 5:10
- scope 2 {
- debug y => _2; // in scope 2 at $DIR/inst_combine_deref.rs:5:9: 5:10
- let _3: u64; // in scope 2 at $DIR/inst_combine_deref.rs:6:9: 6:10
- scope 3 {
- debug z => _3; // in scope 3 at $DIR/inst_combine_deref.rs:6:9: 6:10
- }
- }
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/inst_combine_deref.rs:4:9: 4:10
- _1 = const 5_u64; // scope 0 at $DIR/inst_combine_deref.rs:4:13: 4:14
- StorageLive(_2); // scope 1 at $DIR/inst_combine_deref.rs:5:9: 5:10
- _2 = &_1; // scope 1 at $DIR/inst_combine_deref.rs:5:13: 5:15
- StorageLive(_3); // scope 2 at $DIR/inst_combine_deref.rs:6:9: 6:10
-- _3 = (*_2); // scope 2 at $DIR/inst_combine_deref.rs:6:13: 6:15
-+ _3 = _1; // scope 2 at $DIR/inst_combine_deref.rs:6:13: 6:15
- _0 = _3; // scope 3 at $DIR/inst_combine_deref.rs:7:5: 7:6
- StorageDead(_3); // scope 2 at $DIR/inst_combine_deref.rs:8:1: 8:2
- StorageDead(_2); // scope 1 at $DIR/inst_combine_deref.rs:8:1: 8:2
- StorageDead(_1); // scope 0 at $DIR/inst_combine_deref.rs:8:1: 8:2
- return; // scope 0 at $DIR/inst_combine_deref.rs:8:2: 8:2
- }
- }
-
+// EMIT_MIR tls_access.main.PreCodegen.after.mir
+// compile-flags: -Zmir-opt-level=0
+
#![feature(thread_local)]
#[thread_local]
FOO = 42;
}
}
-
-// EMIT_MIR tls_access.main.SimplifyCfg-final.after.mir
-// compile-flags: -Zmir-opt-level=0
--- /dev/null
+// MIR for `main` after PreCodegen
+
+fn main() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/tls-access.rs:9:11: 9:11
+ let _2: *mut u8; // in scope 0 at $DIR/tls-access.rs:11:18: 11:21
+ let mut _3: *mut u8; // in scope 0 at $DIR/tls-access.rs:12:9: 12:12
+ scope 1 {
+ let _1: &u8; // in scope 1 at $DIR/tls-access.rs:11:13: 11:14
+ scope 2 {
+ debug a => _1; // in scope 2 at $DIR/tls-access.rs:11:13: 11:14
+ }
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 1 at $DIR/tls-access.rs:11:13: 11:14
+ StorageLive(_2); // scope 1 at $DIR/tls-access.rs:11:18: 11:21
+ _2 = &/*tls*/ mut FOO; // scope 1 at $DIR/tls-access.rs:11:18: 11:21
+ _1 = &(*_2); // scope 1 at $DIR/tls-access.rs:11:17: 11:21
+ StorageLive(_3); // scope 2 at $DIR/tls-access.rs:12:9: 12:12
+ _3 = &/*tls*/ mut FOO; // scope 2 at $DIR/tls-access.rs:12:9: 12:12
+ (*_3) = const 42_u8; // scope 2 at $DIR/tls-access.rs:12:9: 12:17
+ StorageDead(_3); // scope 2 at $DIR/tls-access.rs:12:17: 12:18
+ _0 = const (); // scope 1 at $DIR/tls-access.rs:10:5: 13:6
+ StorageDead(_2); // scope 1 at $DIR/tls-access.rs:13:5: 13:6
+ StorageDead(_1); // scope 1 at $DIR/tls-access.rs:13:5: 13:6
+ return; // scope 0 at $DIR/tls-access.rs:14:2: 14:2
+ }
+}
+++ /dev/null
-// MIR for `main` after SimplifyCfg-final
-
-fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/tls-access.rs:6:11: 6:11
- let _2: *mut u8; // in scope 0 at $DIR/tls-access.rs:8:18: 8:21
- let mut _3: *mut u8; // in scope 0 at $DIR/tls-access.rs:9:9: 9:12
- scope 1 {
- let _1: &u8; // in scope 1 at $DIR/tls-access.rs:8:13: 8:14
- scope 2 {
- debug a => _1; // in scope 2 at $DIR/tls-access.rs:8:13: 8:14
- }
- }
-
- bb0: {
- StorageLive(_1); // scope 1 at $DIR/tls-access.rs:8:13: 8:14
- StorageLive(_2); // scope 1 at $DIR/tls-access.rs:8:18: 8:21
- StorageLive(_3); // scope 2 at $DIR/tls-access.rs:9:9: 9:12
- _3 = &/*tls*/ mut FOO; // scope 2 at $DIR/tls-access.rs:9:9: 9:12
- (*_3) = const 42_u8; // scope 2 at $DIR/tls-access.rs:9:9: 9:17
- StorageDead(_3); // scope 2 at $DIR/tls-access.rs:9:17: 9:18
- StorageDead(_2); // scope 1 at $DIR/tls-access.rs:10:5: 10:6
- StorageDead(_1); // scope 1 at $DIR/tls-access.rs:10:5: 10:6
- return; // scope 0 at $DIR/tls-access.rs:11:2: 11:2
- }
-}
// This test ensures that the settings menu display is working as expected.
goto: file://|DOC_PATH|/test_docs/index.html
+show-text: true // needed when we check for colors below.
// First, we check that the settings page doesn't exist.
assert-false: "#settings"
// We now click on the settings button.
// We check that the correct theme is selected.
assert-property: ("#theme .choices #theme-dark", {"checked": "true"})
+// Some style checks...
+// First we check the "default" display.
+assert-css: (
+ "#theme-dark",
+ {
+ "border-color": "rgb(221, 221, 221)",
+ "box-shadow": "rgb(53, 53, 53) 0px 0px 0px 3px inset",
+ },
+)
+assert-css: ("#theme-light", {"border-color": "rgb(221, 221, 221)", "box-shadow": "none"})
+// Let's start with the hover.
+move-cursor-to: "#theme-dark"
+assert-css: (
+ "#theme-dark",
+ {
+ "border-color": "rgb(33, 150, 243)",
+ "box-shadow": "rgb(53, 53, 53) 0px 0px 0px 3px inset",
+ },
+)
+move-cursor-to: "#theme-light"
+assert-css: ("#theme-light", {"border-color": "rgb(33, 150, 243)", "box-shadow": "none"})
+move-cursor-to: "#theme-ayu"
+// Let's now check with the focus.
+focus: "#theme-dark"
+assert-css: (
+ "#theme-dark",
+ {
+ "border-color": "rgb(221, 221, 221)",
+ "box-shadow": "rgb(53, 53, 53) 0px 0px 0px 3px inset, rgb(33, 150, 243) 0px 0px 2px 2px",
+ },
+)
+focus: "#theme-light"
+assert-css: (
+ "#theme-light",
+ {
+ "border-color": "rgb(221, 221, 221)",
+ "box-shadow": "rgb(33, 150, 243) 0px 0px 1px 1px",
+ },
+)
+// Now we check we both focus and hover.
+move-cursor-to: "#theme-dark"
+focus: "#theme-dark"
+assert-css: (
+ "#theme-dark",
+ {
+ "border-color": "rgb(33, 150, 243)",
+ "box-shadow": "rgb(53, 53, 53) 0px 0px 0px 3px inset, rgb(33, 150, 243) 0px 0px 2px 2px",
+ },
+)
+move-cursor-to: "#theme-light"
+focus: "#theme-light"
+assert-css: (
+ "#theme-light",
+ {
+ "border-color": "rgb(33, 150, 243)",
+ "box-shadow": "rgb(33, 150, 243) 0px 0px 1px 1px",
+ },
+)
+
// We now switch the display.
click: "#use-system-theme"
// Wait for the hidden element to show up.
--- /dev/null
+// ignore-order
+
+const QUERY = [
+ 'Aaaaaaa -> i32',
+ 'Aaaaaaa -> Aaaaaaa',
+ 'Aaaaaaa -> usize',
+ '-> Aaaaaaa',
+ 'Aaaaaaa',
+];
+
+const EXPECTED = [
+ {
+ // Aaaaaaa -> i32
+ 'others': [
+ { 'path': 'impl_trait::Ccccccc', 'name': 'eeeeeee' },
+ ],
+ },
+ {
+ // Aaaaaaa -> Aaaaaaa
+ 'others': [
+ { 'path': 'impl_trait::Ccccccc', 'name': 'fffffff' },
+ ],
+ },
+ {
+ // Aaaaaaa -> usize
+ 'others': [],
+ },
+ {
+ // -> Aaaaaaa
+ 'others': [
+ { 'path': 'impl_trait::Ccccccc', 'name': 'fffffff' },
+ { 'path': 'impl_trait::Ccccccc', 'name': 'ddddddd' },
+ { 'path': 'impl_trait', 'name': 'bbbbbbb' },
+ ],
+ },
+ {
+ // Aaaaaaa
+ 'others': [
+ { 'path': 'impl_trait', 'name': 'Aaaaaaa' },
+ ],
+ 'in_args': [
+ { 'path': 'impl_trait::Ccccccc', 'name': 'fffffff' },
+ { 'path': 'impl_trait::Ccccccc', 'name': 'eeeeeee' },
+ ],
+ 'returned': [
+ { 'path': 'impl_trait::Ccccccc', 'name': 'fffffff' },
+ { 'path': 'impl_trait::Ccccccc', 'name': 'ddddddd' },
+ { 'path': 'impl_trait', 'name': 'bbbbbbb' },
+ ],
+ },
+];
--- /dev/null
+pub trait Aaaaaaa {}
+
+impl Aaaaaaa for () {}
+
+pub fn bbbbbbb() -> impl Aaaaaaa {
+ ()
+}
+
+pub struct Ccccccc {}
+
+impl Ccccccc {
+ pub fn ddddddd(&self) -> impl Aaaaaaa {
+ ()
+ }
+ pub fn eeeeeee(&self, _x: impl Aaaaaaa) -> i32 {
+ 0
+ }
+ pub fn fffffff(&self, x: impl Aaaaaaa) -> impl Aaaaaaa {
+ x
+ }
+}
--- /dev/null
+// ignore-order
+
+const QUERY = [
+ 'Aaaaaaa -> i32',
+ 'Aaaaaaa -> Aaaaaaa',
+ 'Aaaaaaa -> usize',
+ '-> Aaaaaaa',
+ 'Aaaaaaa',
+];
+
+const EXPECTED = [
+ {
+ // Aaaaaaa -> i32
+ 'others': [
+ { 'path': 'raw_pointer::Ccccccc', 'name': 'eeeeeee' },
+ ],
+ },
+ {
+ // Aaaaaaa -> Aaaaaaa
+ 'others': [
+ { 'path': 'raw_pointer::Ccccccc', 'name': 'fffffff' },
+ { 'path': 'raw_pointer::Ccccccc', 'name': 'ggggggg' },
+ ],
+ },
+ {
+ // Aaaaaaa -> usize
+ 'others': [],
+ },
+ {
+ // -> Aaaaaaa
+ 'others': [
+ { 'path': 'raw_pointer::Ccccccc', 'name': 'fffffff' },
+ { 'path': 'raw_pointer::Ccccccc', 'name': 'ggggggg' },
+ { 'path': 'raw_pointer::Ccccccc', 'name': 'ddddddd' },
+ { 'path': 'raw_pointer', 'name': 'bbbbbbb' },
+ ],
+ },
+ {
+ // Aaaaaaa
+ 'others': [
+ { 'path': 'raw_pointer', 'name': 'Aaaaaaa' },
+ ],
+ 'in_args': [
+ { 'path': 'raw_pointer::Ccccccc', 'name': 'fffffff' },
+ { 'path': 'raw_pointer::Ccccccc', 'name': 'ggggggg' },
+ { 'path': 'raw_pointer::Ccccccc', 'name': 'eeeeeee' },
+ ],
+ 'returned': [
+ { 'path': 'raw_pointer::Ccccccc', 'name': 'fffffff' },
+ { 'path': 'raw_pointer::Ccccccc', 'name': 'ggggggg' },
+ { 'path': 'raw_pointer::Ccccccc', 'name': 'ddddddd' },
+ { 'path': 'raw_pointer', 'name': 'bbbbbbb' },
+ ],
+ },
+];
--- /dev/null
+use std::ptr;
+
+pub struct Aaaaaaa {}
+
+pub fn bbbbbbb() -> *const Aaaaaaa {
+ ptr::null()
+}
+
+pub struct Ccccccc {}
+
+impl Ccccccc {
+ pub fn ddddddd(&self) -> *const Aaaaaaa {
+ ptr::null()
+ }
+ pub fn eeeeeee(&self, _x: *const Aaaaaaa) -> i32 {
+ 0
+ }
+ pub fn fffffff(&self, x: *const Aaaaaaa) -> *const Aaaaaaa {
+ x
+ }
+ pub fn ggggggg(&self, x: *mut Aaaaaaa) -> *mut Aaaaaaa {
+ x
+ }
+}
--- /dev/null
+// Regression test for https://github.com/rust-lang/rust/issues/97432.
+
+#![feature(no_core)]
+#![no_std]
+#![no_core]
+
+// @has same_type_reexported_more_than_once.json
+// @set trait_id = - "$.index[*][?(@.name=='Trait')].id"
+// @has - "$.index[*][?(@.name=='same_type_reexported_more_than_once')].inner.items[*]" $trait_id
+pub use inner::Trait;
+// @set reexport_id = - "$.index[*][?(@.name=='Reexport')].id"
+// @has - "$.index[*][?(@.name=='same_type_reexported_more_than_once')].inner.items[*]" $reexport_id
+pub use inner::Trait as Reexport;
+
+mod inner {
+ pub trait Trait {}
+}
|
LL | use unresolved_crate::module::Name;
| ^^^^^^^^^^^^^^^^ maybe a missing crate `unresolved_crate`?
+ |
+ = help: consider adding `extern crate unresolved_crate` to use the `unresolved_crate` crate
error: Compilation failed, aborting rustdoc
|
LL | pub(in crate::r#mod) fn main() {}
| ^^^^^ maybe a missing crate `r#mod`?
+ |
+ = help: consider adding `extern crate r#mod` to use the `r#mod` crate
error: Compilation failed, aborting rustdoc
--- /dev/null
+#![crate_name = "foo"]
+
+// This test ensures we don't display anonymous (non-inline) re-exports of public items.
+
+// @has 'foo/index.html'
+// @has - '//*[@id="main-content"]' ''
+// We check that the only "h2" present is for "Bla".
+// @count - '//*[@id="main-content"]/h2' 1
+// @has - '//*[@id="main-content"]/h2' 'Structs'
+// @count - '//*[@id="main-content"]//a[@class="struct"]' 1
+
+mod ext {
+ pub trait Foo {}
+ pub trait Bar {}
+ pub struct S;
+}
+
+pub use crate::ext::Foo as _;
+pub use crate::ext::Bar as _;
+pub use crate::ext::S as _;
+
+pub struct Bla;
--- /dev/null
+pub mod my_trait {
+ pub trait MyTrait {
+ fn my_fn(&self) -> Self;
+ }
+}
+
+pub mod prelude {
+ #[doc(inline)]
+ pub use crate::my_trait::MyTrait;
+}
+
+pub struct SomeStruct;
+
+impl my_trait::MyTrait for SomeStruct {
+ fn my_fn(&self) -> SomeStruct {
+ SomeStruct
+ }
+}
--- /dev/null
+// aux-build:implementors_inline.rs
+// build-aux-docs
+// ignore-cross-compile
+
+extern crate implementors_inline;
+
+// @!has implementors/implementors_js/trait.MyTrait.js
+// @has implementors/implementors_inline/my_trait/trait.MyTrait.js
+// @!has implementors/implementors_inline/prelude/trait.MyTrait.js
+// @has implementors_inline/my_trait/trait.MyTrait.html
+// @has - '//script/@src' '../../implementors/implementors_inline/my_trait/trait.MyTrait.js'
+// @has implementors_js/trait.MyTrait.html
+// @has - '//script/@src' '../implementors/implementors_inline/my_trait/trait.MyTrait.js'
+/// When re-exporting this trait, the HTML will be inlined,
+/// but, vitally, the JavaScript will be located only at the
+/// one canonical path.
+pub use implementors_inline::prelude::MyTrait;
+
+pub struct OtherStruct;
+
+impl MyTrait for OtherStruct {
+ fn my_fn(&self) -> OtherStruct {
+ OtherStruct
+ }
+}
-#![allow(rustdoc::broken_intra_doc_links)]
+#![forbid(rustdoc::broken_intra_doc_links)]
//! Email me at <hello@example.com>.
//! Email me at <hello-world@example.com>.
-//! Email me at <hello@localhost> (this warns but will still become a link).
+//! Email me at <hello@localhost>.
+//! Email me at <prim@i32>.
// @has email_address/index.html '//a[@href="mailto:hello@example.com"]' 'hello@example.com'
// @has email_address/index.html '//a[@href="mailto:hello-world@example.com"]' 'hello-world@example.com'
// @has email_address/index.html '//a[@href="mailto:hello@localhost"]' 'hello@localhost'
+// @has email_address/index.html '//a[@href="mailto:prim@i32"]' 'prim@i32'
// @!has foo/trait.Deref.html '//*[@id="impl-Deref-for-EndianSlice"]//h3[@class="code-header in-band"]' 'impl Deref for EndianSlice'
pub use realcore::Deref;
-// @has foo/trait.Join.html '//*[@id="impl-Join-for-Foo"]//h3[@class="code-header in-band"]' 'impl Join for Foo'
+// @has foo/trait.Join.html '//*[@id="impl-Join"]//h3[@class="code-header in-band"]' 'impl Join for Foo'
pub use realcore::Join;
--- /dev/null
+#![crate_name = "aCrate"]
+
+mod a_module {
+ pub fn private_function() {}
+
+ pub use a_module::private_function as other_private_function;
+
+ pub mod a_nested_module {
+ // @has aCrate/a_nested_module/index.html '//a[@href="fn.a_nested_public_function.html"]' 'a_nested_public_function'
+ // @has aCrate/a_nested_module/fn.a_nested_public_function.html 'pub fn a_nested_public_function()'
+ pub fn a_nested_public_function() {}
+
+ // @has aCrate/a_nested_module/index.html '//a[@href="fn.another_nested_public_function.html"]' 'another_nested_public_function'
+ // @has aCrate/a_nested_module/fn.another_nested_public_function.html 'pub fn another_nested_public_function()'
+ pub use a_nested_module::a_nested_public_function as another_nested_public_function;
+ }
+
+ // @!has aCrate/a_nested_module/index.html 'yet_another_nested_public_function'
+ pub use a_nested_module::a_nested_public_function as yet_another_nested_public_function;
+
+ // @!has aCrate/a_nested_module/index.html 'one_last_nested_public_function'
+ pub use a_nested_module::another_nested_public_function as one_last_nested_public_function;
+}
+
+// @!has aCrate/index.html 'a_module'
+// @has aCrate/index.html '//a[@href="a_nested_module/index.html"]' 'a_nested_module'
+pub use a_module::a_nested_module;
+
+// @has aCrate/index.html '//a[@href="fn.a_nested_public_function.html"]' 'a_nested_public_function'
+// @has aCrate/index.html '//a[@href="fn.another_nested_public_function.html"]' 'another_nested_public_function'
+// @has aCrate/index.html '//a[@href="fn.yet_another_nested_public_function.html"]' 'yet_another_nested_public_function'
+// @has aCrate/index.html '//a[@href="fn.one_last_nested_public_function.html"]' 'one_last_nested_public_function'
+pub use a_module::{
+ a_nested_module::{a_nested_public_function, another_nested_public_function},
+ one_last_nested_public_function, yet_another_nested_public_function,
+};
+
+// @has aCrate/index.html '//a[@href="fn.private_function.html"]' 'private_function'
+// @!has aCrate/fn.private_function.html 'a_module'
+// @has aCrate/index.html '//a[@href="fn.other_private_function.html"]' 'other_private_function'
+// @!has aCrate/fn.other_private_function.html 'a_module'
+pub use a_module::{other_private_function, private_function};
--- /dev/null
+// compile-flags: --crate-type lib --edition 2018
+
+#![crate_name = "foo"]
+#![feature(rustdoc_internals)]
+
+// @has foo/primitive.slice.html '//a[@class="primitive"]' 'slice'
+// @has - '//span[@class="in-band"]' 'Primitive Type slice'
+// @has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
+// @has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations'
+// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl<T> Send for [T] where T: Send'
+// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl<T> Sync for [T] where T: Sync'
+#[doc(primitive = "slice")]
+/// this is a test!
+mod slice_prim {}
--- /dev/null
+<code>pub fn delta<T>() -> <a class="struct" href="struct.MyBox.html" title="struct foo::MyBox">MyBox</a><<a class="primitive" href="{{channel}}/core/primitive.slice.html">[T]</a>></code>
\ No newline at end of file
--- /dev/null
+<code>pub fn gamma() -> <a class="struct" href="struct.MyBox.html" title="struct foo::MyBox">MyBox</a><<a class="primitive" href="{{channel}}/core/primitive.slice.html">[</a><a class="primitive" href="{{channel}}/core/primitive.u32.html">u32</a><a class="primitive" href="{{channel}}/core/primitive.slice.html">]</a>></code>
\ No newline at end of file
--- /dev/null
+<code>pub fn beta<T>() -> <a class="primitive" href="{{channel}}/core/primitive.slice.html">&'static [T]</a></code>
\ No newline at end of file
--- /dev/null
+<code>pub fn alpha() -> <a class="primitive" href="{{channel}}/core/primitive.slice.html">&'static [</a><a class="primitive" href="{{channel}}/core/primitive.u32.html">u32</a><a class="primitive" href="{{channel}}/core/primitive.slice.html">]</a></code>
\ No newline at end of file
--- /dev/null
+#![crate_name = "foo"]
+#![no_std]
+
+pub struct MyBox<T: ?Sized>(*const T);
+
+// @has 'foo/fn.alpha.html'
+// @snapshot link_slice_u32 - '//pre[@class="rust fn"]/code'
+pub fn alpha() -> &'static [u32] {
+ loop {}
+}
+
+// @has 'foo/fn.beta.html'
+// @snapshot link_slice_generic - '//pre[@class="rust fn"]/code'
+pub fn beta<T>() -> &'static [T] {
+ loop {}
+}
+
+// @has 'foo/fn.gamma.html'
+// @snapshot link_box_u32 - '//pre[@class="rust fn"]/code'
+pub fn gamma() -> MyBox<[u32]> {
+ loop {}
+}
+
+// @has 'foo/fn.delta.html'
+// @snapshot link_box_generic - '//pre[@class="rust fn"]/code'
+pub fn delta<T>() -> MyBox<[T]> {
+ loop {}
+}
#![allow(unused_imports)]
#![feature(rustc_private)]
-extern crate rustc_serialize;
-use rustc_serialize::json::Object;
+extern crate libc;
+use libc::c_void;
pub fn main() {
println!("Hello world!");
#![allow(unused_must_use)]
#![allow(dead_code)]
#![allow(unused_imports)]
-#![feature(rustc_private)]
-
-extern crate rustc_macros;
-extern crate rustc_serialize;
use std::fmt;
use std::io::prelude::*;
use std::io::Cursor;
use std::slice;
+use std::marker::PhantomData;
+
+trait Encoder {
+ type Error;
+}
+
+trait Encodable<S: Encoder> {
+ fn encode(&self, s: &mut S) -> Result<(), S::Error>;
+}
+
+struct JsonEncoder<'a>(PhantomData<&'a mut ()>);
+
+impl Encoder for JsonEncoder<'_> {
+ type Error = ();
+}
+
+struct AsJson<'a, T> {
+ inner: &'a T,
+}
+
+impl<'a, T: for<'r> Encodable<JsonEncoder<'r>>> fmt::Display for AsJson<'a, T> {
+ /// Encodes a json value into a string
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ Ok(())
+ }
+}
+
+fn as_json<T>(t: &T) -> AsJson<'_, T> {
+ AsJson { inner: t }
+}
+
+struct OpaqueEncoder(Vec<u8>);
+
+impl Encoder for OpaqueEncoder {
+ type Error = ();
+}
-use rustc_macros::Encodable;
-use rustc_serialize::json;
-use rustc_serialize::opaque;
-use rustc_serialize::{Encodable, Encoder};
-#[derive(Encodable)]
struct Foo {
baz: bool,
}
-#[derive(Encodable)]
+impl<S: Encoder> Encodable<S> for Foo {
+ fn encode(&self, _s: &mut S) -> Result<(), S::Error> {
+ Ok(())
+ }
+}
+
struct Bar {
froboz: usize,
}
+impl<S: Encoder> Encodable<S> for Bar {
+ fn encode(&self, _s: &mut S) -> Result<(), S::Error> {
+ Ok(())
+ }
+}
+
enum WireProtocol {
JSON,
Opaque,
// ...
}
-fn encode_json<T: for<'a> Encodable<json::Encoder<'a>>>(val: &T, wr: &mut Cursor<Vec<u8>>) {
- write!(wr, "{}", json::as_json(val));
+fn encode_json<T: for<'a> Encodable<JsonEncoder<'a>>>(val: &T, wr: &mut Cursor<Vec<u8>>) {
+ write!(wr, "{}", as_json(val));
}
-fn encode_opaque<T: Encodable<opaque::Encoder>>(val: &T, wr: Vec<u8>) {
- let mut encoder = opaque::Encoder::new(wr);
+fn encode_opaque<T: Encodable<OpaqueEncoder>>(val: &T, wr: Vec<u8>) {
+ let mut encoder = OpaqueEncoder(wr);
val.encode(&mut encoder);
}
#![allow(unused_imports)]
#![allow(unused_must_use)]
// pretty-expanded FIXME #23616
-#![feature(rustc_private)]
-extern crate rustc_serialize;
-
-use rustc_serialize::json;
-use rustc_serialize::{Encodable, Encoder};
use std::fmt;
+use std::marker::PhantomData;
+
+trait Encoder {
+ type Error;
+}
+
+trait Encodable<S: Encoder> {
+ fn encode(&self, s: &mut S) -> Result<(), S::Error>;
+}
+
+impl<S: Encoder> Encodable<S> for i32 {
+ fn encode(&self, _s: &mut S) -> Result<(), S::Error> {
+ Ok(())
+ }
+}
+
+struct JsonEncoder<'a>(PhantomData<&'a mut ()>);
+
+impl Encoder for JsonEncoder<'_> {
+ type Error = ();
+}
+
+fn encode_json<T: for<'r> Encodable<JsonEncoder<'r>>>(
+ object: &T,
+) -> Result<String, ()> {
+ let s = String::new();
+ {
+ let mut encoder = JsonEncoder(PhantomData);
+ object.encode(&mut encoder)?;
+ }
+ Ok(s)
+}
-struct Foo<T: for<'a> Encodable<json::Encoder<'a>>> {
+struct Foo<T: for<'a> Encodable<JsonEncoder<'a>>> {
v: T,
}
-impl<T: for<'a> Encodable<json::Encoder<'a>>> Drop for Foo<T> {
+impl<T: for<'a> Encodable<JsonEncoder<'a>>> Drop for Foo<T> {
fn drop(&mut self) {
- json::encode(&self.v);
+ encode_json(&self.v);
}
}
#![allow(non_camel_case_types)]
#![allow(dead_code)]
-#![feature(rustc_private)]
-extern crate rustc_serialize;
-
-use std::collections::HashMap;
-use rustc_serialize::json::{self, Json};
+use std::collections::{BTreeMap, HashMap};
use std::option;
+#[derive(Clone, Debug)]
+enum Json {
+ I64(i64),
+ U64(u64),
+ F64(f64),
+ String(String),
+ Boolean(bool),
+ Array(Array),
+ Object(Object),
+ Null,
+}
+
+type Array = Vec<Json>;
+type Object = BTreeMap<String, Json>;
+
enum object {
bool_value(bool),
int_value(i64),
}
-fn lookup(table: json::Object, key: String, default: String) -> String
+fn lookup(table: Object, key: String, default: String) -> String
{
match table.get(&key) {
option::Option::Some(&Json::String(ref s)) => {
s.to_string()
}
option::Option::Some(value) => {
- println!("{} was expected to be a string but is a {}", key, value);
+ println!("{} was expected to be a string but is a {:?}", key, value);
default
}
option::Option::None => {
}
}
-fn add_interface(_store: isize, managed_ip: String, data: json::Json) -> (String, object)
+fn add_interface(_store: isize, managed_ip: String, data: Json) -> (String, object)
{
match &data {
&Json::Object(ref interface) => {
(label, object::bool_value(false))
}
_ => {
- println!("Expected dict for {} interfaces, found {}", managed_ip, data);
+ println!("Expected dict for {} interfaces, found {:?}", managed_ip, data);
("gnos:missing-interface".to_string(), object::bool_value(true))
}
}
}
-fn add_interfaces(store: isize, managed_ip: String, device: HashMap<String, json::Json>)
+fn add_interfaces(store: isize, managed_ip: String, device: HashMap<String, Json>)
-> Vec<(String, object)> {
match device["interfaces"] {
Json::Array(ref interfaces) =>
}
_ =>
{
- println!("Expected list for {} interfaces, found {}", managed_ip,
+ println!("Expected list for {} interfaces, found {:?}", managed_ip,
device["interfaces"]);
Vec::new()
}
--> $DIR/infer_array_len.rs:19:9
|
LL | let [_, _] = a.into();
- | ^^^^^^ consider giving this pattern a type
+ | ^^^^^^
|
= note: type must be known at this point
+help: consider giving this pattern a type
+ |
+LL | let [_, _]: _ = a.into();
+ | +++
error: aborting due to previous error
error[E0282]: type annotations needed for `Vec<T>`
- --> $DIR/vector-no-ann.rs:2:16
+ --> $DIR/vector-no-ann.rs:2:9
|
LL | let _foo = Vec::new();
- | ---- ^^^^^^^^ cannot infer type for type parameter `T`
- | |
- | consider giving `_foo` the explicit type `Vec<T>`, where the type parameter `T` is specified
+ | ^^^^
+ |
+help: consider giving `_foo` an explicit type, where the type for type parameter `T` is specified
+ |
+LL | let _foo: Vec<T> = Vec::new();
+ | ++++++++
error: aborting due to previous error
+++ /dev/null
-// Test that AST json serialization doesn't ICE (#63728).
-
-// revisions: expand noexpand
-
-//[expand] compile-flags: -Zast-json
-//[noexpand] compile-flags: -Zast-json-noexpand
-
-// check-pass
-// dont-check-compiler-stdout - don't check for any AST change.
-
-enum V {
- A(i32),
- B { f: [i64; 3 + 4] }
-}
-
-trait X {
- type Output;
- fn read(&self) -> Self::Output;
- fn write(&mut self, _: Self::Output);
-}
-
-macro_rules! call_println {
- ($y:ident) => { println!("{}", $y) }
-}
-
-fn main() {
- let x: (i32) = 35;
- let y = x as i64<> + 5;
-
- call_println!(y);
-
- struct A;
-}
-
-// Regressions tests for issues #78398 and #78510 (captured tokens in associated and foreign items)
-
-struct S;
-
-macro_rules! mac_extern {
- ($i:item) => {
- extern "C" { $i }
- }
-}
-macro_rules! mac_assoc {
- ($i:item) => {
- impl S { $i }
- trait Bar { $i }
- }
-}
-
-mac_extern! {
- fn foo();
-}
-mac_assoc! {
- fn foo() {}
-}
+++ /dev/null
-// Check that AST json printing works.
-#![crate_type = "lib"]
-
-// check-pass
-// compile-flags: -Zast-json-noexpand
-// normalize-stdout-test ":\d+" -> ":0"
-
-// Only include a single item to reduce how often the test output needs
-// updating.
-extern crate core;
+++ /dev/null
-{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"variant":"Ast","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"spans":{"inner_span":{"lo":0,"hi":0},"inject_use_span":{"lo":0,"hi":0}},"id":0,"is_placeholder":false}
+++ /dev/null
-// Check that AST json printing works.
-#![crate_type = "lib"]
-
-// check-pass
-// compile-flags: -Zast-json
-// normalize-stdout-test ":\d+" -> ":0"
-
-// Only include a single item to reduce how often the test output needs
-// updating.
-extern crate core;
+++ /dev/null
-{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"variant":"Ast","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"rust_2015","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"spans":{"inner_span":{"lo":0,"hi":0},"inject_use_span":{"lo":0,"hi":0}},"id":0,"is_placeholder":false}
| ---------------- these two types are declared with different lifetimes...
LL | ListFut(bufs).await
| ^^^^ ...but data from `bufs` flows into `bufs` here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+ |
+LL | async fn fut<'a>(bufs: &'a mut [&'a mut [u8]]) {
+ | ++++ ++ ++
error[E0623]: lifetime mismatch
--> $DIR/issue-76547.rs:39:14
| ---------------- these two types are declared with different lifetimes...
LL | ListFut2(bufs).await
| ^^^^ ...but data from `bufs` flows into `bufs` here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+ |
+LL | async fn fut2<'a>(bufs: &'a mut [&'a mut [u8]]) -> i32 {
+ | ++++ ++ ++
error: aborting due to 2 previous errors
| let's call the lifetime of this reference `'1`
LL | ListFut(bufs).await
| ^^^^ this usage requires that `'1` must outlive `'2`
+ |
+help: consider introducing a named lifetime parameter
+ |
+LL | async fn fut<'a>(bufs: &'a mut [&'a mut [u8]]) {
+ | ++++ ++ ++
error: lifetime may not live long enough
--> $DIR/issue-76547.rs:39:14
| let's call the lifetime of this reference `'1`
LL | ListFut2(bufs).await
| ^^^^ this usage requires that `'1` must outlive `'2`
+ |
+help: consider introducing a named lifetime parameter
+ |
+LL | async fn fut2<'a>(bufs: &'a mut [&'a mut [u8]]) -> i32 {
+ | ++++ ++ ++
error: aborting due to 2 previous errors
-error[E0623]: lifetime mismatch
+error[E0621]: explicit lifetime required in the type of `foo`
--> $DIR/issue-63388-1.rs:19:9
|
LL | &'a self, foo: &dyn Foo
- | -------- this parameter and the return type are declared with different lifetimes...
-LL | ) -> &dyn Foo
- | --------
+ | -------- help: add explicit lifetime `'a` to the type of `foo`: `&'a (dyn Foo + 'a)`
...
LL | foo
- | ^^^ ...but data from `foo` is returned here
+ | ^^^ lifetime `'a` required
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0623`.
+For more information about this error, try `rustc --explain E0621`.
-error: lifetime may not live long enough
+error[E0621]: explicit lifetime required in the type of `foo`
--> $DIR/issue-63388-1.rs:17:5
|
-LL | async fn do_sth<'a>(
- | -- lifetime `'a` defined here
LL | &'a self, foo: &dyn Foo
- | - let's call the lifetime of this reference `'1`
+ | -------- help: add explicit lifetime `'a` to the type of `foo`: `&'a (dyn Foo + 'a)`
LL | ) -> &dyn Foo
LL | / {
LL | |
LL | | foo
LL | |
LL | | }
- | |_____^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`
+ | |_____^ lifetime `'a` required
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0621`.
&'a self, foo: &dyn Foo
) -> &dyn Foo
{
- //[nll]~^ ERROR lifetime may not live long enough
+ //[nll]~^ ERROR explicit lifetime required in the type of `foo` [E0621]
foo
- //[base]~^ ERROR lifetime mismatch
+ //[base]~^ ERROR explicit lifetime required in the type of `foo` [E0621]
}
}
fn function(#[inline] param: u32) {
//~^ ERROR attribute should be applied to function or closure
- //~| ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes
+ //~| ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes
}
fn main() {}
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
--> $DIR/attrs-on-params.rs:3:13
|
LL | fn function(#[inline] param: u32) {
|
LL | pub(in nonexistent) field: u8
| ^^^^^^^^^^^ maybe a missing crate `nonexistent`?
+ |
+ = help: consider adding `extern crate nonexistent` to use the `nonexistent` crate
error[E0433]: failed to resolve: maybe a missing crate `nonexistent`?
--> $DIR/field-attributes-vis-unresolved.rs:22:12
|
LL | pub(in nonexistent) u8
| ^^^^^^^^^^^ maybe a missing crate `nonexistent`?
+ |
+ = help: consider adding `extern crate nonexistent` to use the `nonexistent` crate
error: aborting due to 2 previous errors
--- /dev/null
+// Regression test for #71546.
+
+// ignore-compare-mode-nll
+// NLL stderr is different from the original one.
+
+pub fn serialize_as_csv<V>(value: &V) -> Result<String, &str>
+where
+ V: 'static,
+ for<'a> &'a V: IntoIterator,
+ for<'a> <&'a V as IntoIterator>::Item: ToString + 'static,
+{
+ let csv_str: String = value //~ ERROR: the associated type `<&'a V as IntoIterator>::Item` may not live long enough
+ .into_iter()
+ .map(|elem| elem.to_string())
+ .collect::<String>();
+ Ok(csv_str)
+}
+
+fn main() {}
--- /dev/null
+error[E0310]: the associated type `<&'a V as IntoIterator>::Item` may not live long enough
+ --> $DIR/issue-71546.rs:12:27
+ |
+LL | let csv_str: String = value
+ | ___________________________^
+LL | | .into_iter()
+LL | | .map(|elem| elem.to_string())
+ | |_____________________________________^
+ |
+ = help: consider adding an explicit lifetime bound `<&'a V as IntoIterator>::Item: 'static`...
+ = note: ...so that the type `<&'a V as IntoIterator>::Item` will meet its required lifetime bounds...
+note: ...that is required by this bound
+ --> $DIR/issue-71546.rs:10:55
+ |
+LL | for<'a> <&'a V as IntoIterator>::Item: ToString + 'static,
+ | ^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0310`.
--> $DIR/expect-two-infer-vars-supply-ty-with-bound-region.rs:8:27
|
LL | with_closure(|x: u32, y| {});
- | ^ consider giving this closure parameter a type
+ | ^
+ |
+help: consider giving this closure parameter an explicit type
+ |
+LL | with_closure(|x: u32, y: B| {});
+ | +++
error: aborting due to previous error
--- /dev/null
+fn foo(_f: impl Fn()) {}
+
+fn bar() -> i32 {
+ 1
+}
+
+fn main() {
+ foo(|| bar())
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider using a semicolon here
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/add_semicolon_non_block_closure.rs:8:12
+ |
+LL | fn main() {
+ | - expected `()` because of default return type
+LL | foo(|| bar())
+ | ^^^^^ expected `()`, found `i32`
+ |
+help: consider using a semicolon here
+ |
+LL | foo(|| { bar(); })
+ | + +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--> $DIR/issue-52437.rs:2:30
|
LL | [(); &(&'static: loop { |x| {}; }) as *const _ as usize]
- | ^ consider giving this closure parameter a type
+ | ^
+ |
+help: consider giving this closure parameter an explicit type
+ |
+LL | [(); &(&'static: loop { |x: _| {}; }) as *const _ as usize]
+ | +++
error[E0308]: mismatched types
--> $DIR/issue-52437.rs:2:5
--- /dev/null
+use std::{ptr::NonNull, task::Poll};
+
+struct TaskRef;
+
+struct Header {
+ vtable: &'static Vtable,
+}
+
+struct Vtable {
+ poll: unsafe fn(TaskRef) -> Poll<()>,
+ deallocate: unsafe fn(NonNull<Header>),
+}
+
+// in the "Header" type, which is a private type in maitake
+impl Header {
+ pub(crate) const fn new_stub() -> Self {
+ unsafe fn nop(_ptr: TaskRef) -> Poll<()> {
+ Poll::Pending
+ }
+
+ unsafe fn nop_deallocate(ptr: NonNull<Header>) {
+ unreachable!("stub task ({ptr:p}) should never be deallocated!");
+ }
+
+ Self { vtable: &Vtable { poll: nop, deallocate: nop_deallocate } }
+ }
+}
+
+// This is a public type in `maitake`
+#[repr(transparent)]
+#[cfg_attr(loom, allow(dead_code))]
+pub struct TaskStub {
+ hdr: Header,
+}
+
+impl TaskStub {
+ /// Create a new unique stub [`Task`].
+ pub const fn new() -> Self {
+ Self { hdr: Header::new_stub() }
+ }
+}
--- /dev/null
+// build-pass
+// aux-build:issue-97708-aux.rs
+
+extern crate issue_97708_aux;
+use issue_97708_aux::TaskStub;
+
+static TASK_STUB: TaskStub = TaskStub::new();
+
+fn main() {}
| ^^^ type aliases cannot be used as traits
|
help: you might have meant to use `#![feature(trait_alias)]` instead of a `type` alias
+ --> $DIR/two_files_data.rs:5:1
|
LL | trait Bar = dyn Foo;
|
--> $DIR/coherence-impls-sized.rs:14:1
|
LL | impl Sized for TestE {}
- | ^^^^^^^^^^^^^^^^^^^^ impl of 'Sized' not allowed
+ | ^^^^^^^^^^^^^^^^^^^^ impl of `Sized` not allowed
error[E0322]: explicit impls for the `Sized` trait are not permitted
--> $DIR/coherence-impls-sized.rs:17:1
|
LL | impl Sized for MyType {}
- | ^^^^^^^^^^^^^^^^^^^^^ impl of 'Sized' not allowed
+ | ^^^^^^^^^^^^^^^^^^^^^ impl of `Sized` not allowed
error[E0322]: explicit impls for the `Sized` trait are not permitted
--> $DIR/coherence-impls-sized.rs:20:1
|
LL | impl Sized for (MyType, MyType) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of 'Sized' not allowed
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `Sized` not allowed
error[E0322]: explicit impls for the `Sized` trait are not permitted
--> $DIR/coherence-impls-sized.rs:24:1
|
LL | impl Sized for &'static NotSync {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of 'Sized' not allowed
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `Sized` not allowed
error[E0322]: explicit impls for the `Sized` trait are not permitted
--> $DIR/coherence-impls-sized.rs:27:1
|
LL | impl Sized for [MyType] {}
- | ^^^^^^^^^^^^^^^^^^^^^^^ impl of 'Sized' not allowed
+ | ^^^^^^^^^^^^^^^^^^^^^^^ impl of `Sized` not allowed
error[E0322]: explicit impls for the `Sized` trait are not permitted
--> $DIR/coherence-impls-sized.rs:31:1
|
LL | impl Sized for &'static [NotSync] {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of 'Sized' not allowed
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `Sized` not allowed
error: aborting due to 9 previous errors
--- /dev/null
+// This test is a collection of test that should pass.
+//
+// check-fail
+
+#![feature(cfg_accessible)]
+#![feature(trait_alias)]
+
+trait TraitAlias = std::fmt::Debug + Send;
+
+// FIXME: Currently shows "cannot determine" but should be `false`
+#[cfg_accessible(unresolved)] //~ ERROR cannot determine
+const C: bool = true;
+
+// FIXME: Currently shows "not sure" but should be `false`
+#[cfg_accessible(TraitAlias::unresolved)] //~ ERROR not sure whether the path is accessible or not
+const D: bool = true;
+
+fn main() {}
--- /dev/null
+error: not sure whether the path is accessible or not
+ --> $DIR/cfg_accessible-bugs.rs:15:18
+ |
+LL | #[cfg_accessible(TraitAlias::unresolved)]
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the type may have associated items, but we are currently not checking them
+
+error: cannot determine whether the path is accessible or not
+ --> $DIR/cfg_accessible-bugs.rs:11:1
+ |
+LL | #[cfg_accessible(unresolved)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+error: not sure whether the path is accessible or not
+ --> $DIR/cfg_accessible-not_sure.rs:14:18
+ |
+LL | #[cfg_accessible(Struct::existing)]
+ | ^^^^^^^^^^^^^^^^
+ |
+ = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+ --> $DIR/cfg_accessible-not_sure.rs:16:18
+ |
+LL | #[cfg_accessible(Struct::unresolved)]
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+ --> $DIR/cfg_accessible-not_sure.rs:25:18
+ |
+LL | #[cfg_accessible(Union::existing)]
+ | ^^^^^^^^^^^^^^^
+ |
+ = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+ --> $DIR/cfg_accessible-not_sure.rs:27:18
+ |
+LL | #[cfg_accessible(Union::unresolved)]
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+ --> $DIR/cfg_accessible-not_sure.rs:36:18
+ |
+LL | #[cfg_accessible(Enum::Existing::existing)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+ --> $DIR/cfg_accessible-not_sure.rs:38:18
+ |
+LL | #[cfg_accessible(Enum::Existing::unresolved)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+ --> $DIR/cfg_accessible-not_sure.rs:40:18
+ |
+LL | #[cfg_accessible(Enum::unresolved)]
+ | ^^^^^^^^^^^^^^^^
+ |
+ = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+ --> $DIR/cfg_accessible-not_sure.rs:50:18
+ |
+LL | #[cfg_accessible(Trait::existing)]
+ | ^^^^^^^^^^^^^^^
+ |
+ = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+ --> $DIR/cfg_accessible-not_sure.rs:52:18
+ |
+LL | #[cfg_accessible(Trait::unresolved)]
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+ --> $DIR/cfg_accessible-not_sure.rs:59:18
+ |
+LL | #[cfg_accessible(TypeAlias::existing)]
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+ --> $DIR/cfg_accessible-not_sure.rs:61:18
+ |
+LL | #[cfg_accessible(TypeAlias::unresolved)]
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+ --> $DIR/cfg_accessible-not_sure.rs:70:18
+ |
+LL | #[cfg_accessible(ForeignType::unresolved)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+ --> $DIR/cfg_accessible-not_sure.rs:79:18
+ |
+LL | #[cfg_accessible(AssocType::AssocType::unresolved)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+ --> $DIR/cfg_accessible-not_sure.rs:84:18
+ |
+LL | #[cfg_accessible(u8::unresolved)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+ --> $DIR/cfg_accessible-not_sure.rs:86:18
+ |
+LL | #[cfg_accessible(u8::is_ascii)]
+ | ^^^^^^^^^^^^
+ |
+ = note: the type may have associated items, but we are currently not checking them
+
+error: aborting due to 15 previous errors
+
--- /dev/null
+error: not sure whether the path is accessible or not
+ --> $DIR/cfg_accessible-not_sure.rs:14:18
+ |
+LL | #[cfg_accessible(Struct::existing)]
+ | ^^^^^^^^^^^^^^^^
+ |
+ = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+ --> $DIR/cfg_accessible-not_sure.rs:16:18
+ |
+LL | #[cfg_accessible(Struct::unresolved)]
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+ --> $DIR/cfg_accessible-not_sure.rs:25:18
+ |
+LL | #[cfg_accessible(Union::existing)]
+ | ^^^^^^^^^^^^^^^
+ |
+ = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+ --> $DIR/cfg_accessible-not_sure.rs:27:18
+ |
+LL | #[cfg_accessible(Union::unresolved)]
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+ --> $DIR/cfg_accessible-not_sure.rs:36:18
+ |
+LL | #[cfg_accessible(Enum::Existing::existing)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+ --> $DIR/cfg_accessible-not_sure.rs:38:18
+ |
+LL | #[cfg_accessible(Enum::Existing::unresolved)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+ --> $DIR/cfg_accessible-not_sure.rs:40:18
+ |
+LL | #[cfg_accessible(Enum::unresolved)]
+ | ^^^^^^^^^^^^^^^^
+ |
+ = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+ --> $DIR/cfg_accessible-not_sure.rs:50:18
+ |
+LL | #[cfg_accessible(Trait::existing)]
+ | ^^^^^^^^^^^^^^^
+ |
+ = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+ --> $DIR/cfg_accessible-not_sure.rs:52:18
+ |
+LL | #[cfg_accessible(Trait::unresolved)]
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+ --> $DIR/cfg_accessible-not_sure.rs:59:18
+ |
+LL | #[cfg_accessible(TypeAlias::existing)]
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+ --> $DIR/cfg_accessible-not_sure.rs:61:18
+ |
+LL | #[cfg_accessible(TypeAlias::unresolved)]
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+ --> $DIR/cfg_accessible-not_sure.rs:70:18
+ |
+LL | #[cfg_accessible(ForeignType::unresolved)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+ --> $DIR/cfg_accessible-not_sure.rs:79:18
+ |
+LL | #[cfg_accessible(AssocType::AssocType::unresolved)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+ --> $DIR/cfg_accessible-not_sure.rs:84:18
+ |
+LL | #[cfg_accessible(u8::unresolved)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: the type may have associated items, but we are currently not checking them
+
+error: not sure whether the path is accessible or not
+ --> $DIR/cfg_accessible-not_sure.rs:86:18
+ |
+LL | #[cfg_accessible(u8::is_ascii)]
+ | ^^^^^^^^^^^^
+ |
+ = note: the type may have associated items, but we are currently not checking them
+
+error: aborting due to 15 previous errors
+
--- /dev/null
+// revisions: edition2015 edition2021
+// [edition2015]compile-flags: --edition=2015
+// [edition2021]compile-flags: --edition=2021
+
+#![feature(extern_types)]
+#![feature(cfg_accessible)]
+
+// Struct::unresolved - error
+
+struct Struct {
+ existing: u8,
+}
+
+#[cfg_accessible(Struct::existing)] //~ ERROR not sure
+const A: bool = true;
+#[cfg_accessible(Struct::unresolved)] //~ ERROR not sure
+const B: bool = true;
+
+// Union::unresolved - error
+
+struct Union {
+ existing: u8,
+}
+
+#[cfg_accessible(Union::existing)] //~ ERROR not sure
+const A: bool = true;
+#[cfg_accessible(Union::unresolved)] //~ ERROR not sure
+const B: bool = true;
+
+// Enum::unresolved - error
+
+enum Enum {
+ Existing { existing: u8 },
+}
+
+#[cfg_accessible(Enum::Existing::existing)] //~ ERROR not sure
+const A: bool = true;
+#[cfg_accessible(Enum::Existing::unresolved)] //~ ERROR not sure
+const B: bool = true;
+#[cfg_accessible(Enum::unresolved)] //~ ERROR not sure
+const C: bool = true;
+
+// Trait::unresolved - false or error, depending on edition (error if you can write Trait::foo
+// instead of <dyn Trait>::foo for methods like impl dyn Trait { fn foo() {} })
+
+trait Trait {}
+impl dyn Trait { fn existing() {} }
+
+// FIXME: Should be a error for edition > 2015
+#[cfg_accessible(Trait::existing)] //~ ERROR not sure
+const A: bool = true;
+#[cfg_accessible(Trait::unresolved)] //~ ERROR not sure
+const B: bool = true;
+
+// TypeAlias::unresolved - error
+
+type TypeAlias = Struct;
+
+#[cfg_accessible(TypeAlias::existing)] //~ ERROR not sure
+const A: bool = true;
+#[cfg_accessible(TypeAlias::unresolved)] //~ ERROR not sure
+const B: bool = true;
+
+// ForeignType::unresolved - error
+
+extern {
+ type ForeignType;
+}
+
+#[cfg_accessible(ForeignType::unresolved)] //~ ERROR not sure
+const A: bool = true;
+
+// AssocType::unresolved - error
+
+trait AssocType {
+ type AssocType;
+}
+
+#[cfg_accessible(AssocType::AssocType::unresolved)] //~ ERROR not sure
+const A: bool = true;
+
+// PrimitiveType::unresolved - error
+
+#[cfg_accessible(u8::unresolved)] //~ ERROR not sure
+const A: bool = true;
+#[cfg_accessible(u8::is_ascii)] //~ ERROR not sure
+const B: bool = true;
+
+fn main() {}
--- /dev/null
+// check-pass
+
+#![feature(cfg_accessible)]
+
+mod private {
+ struct Struct;
+ enum Enum{}
+ union Union{_a:u8}
+}
+
+#[cfg_accessible(private::Struct)]
+const A: bool = true;
+
+#[cfg_accessible(private::Enum)]
+const A: bool = true;
+
+#[cfg_accessible(private::Union)]
+const A: bool = true;
+
+const A: bool = false; // Will conflict if any of those is accessible
+fn main() {}
struct ExistingPrivate;
}
+trait Trait {
+ type Assoc;
+}
+
+enum Enum {
+ Existing,
+}
+
+#[cfg_accessible(Enum)]
+struct ExistingResolved;
+
+#[cfg_accessible(Enum::Existing)]
+struct ExistingResolvedVariant;
+
#[cfg_accessible(m::ExistingPublic)]
struct ExistingPublic;
-// FIXME: Not implemented yet.
-#[cfg_accessible(m::ExistingPrivate)] //~ ERROR not sure whether the path is accessible or not
+#[cfg_accessible(m::ExistingPrivate)]
struct ExistingPrivate;
-// FIXME: Not implemented yet.
-#[cfg_accessible(m::NonExistent)] //~ ERROR not sure whether the path is accessible or not
-struct ExistingPrivate;
+#[cfg_accessible(m::NonExistent)]
+struct NonExistingPrivate;
#[cfg_accessible(n::AccessibleExpanded)] // OK, `cfg_accessible` can wait and retry.
struct AccessibleExpanded;
+#[cfg_accessible(Trait::Assoc)]
+struct AccessibleTraitAssoc;
+
macro_rules! generate_accessible_expanded {
() => {
mod n {
generate_accessible_expanded!();
-struct S {
- field: u8,
-}
-
-// FIXME: Not implemented yet.
-#[cfg_accessible(S::field)] //~ ERROR not sure whether the path is accessible or not
-struct Field;
-
fn main() {
ExistingPublic;
AccessibleExpanded;
+ AccessibleTraitAssoc;
+
+ ExistingPrivate; //~ ERROR cannot find
+ NonExistingPrivate; //~ ERROR cannot find
+ NonExistingTraitAlias; //~ ERROR cannot find
}
-error: not sure whether the path is accessible or not
- --> $DIR/cfg_accessible.rs:12:18
+error[E0425]: cannot find value `ExistingPrivate` in this scope
+ --> $DIR/cfg_accessible.rs:52:5
|
-LL | #[cfg_accessible(m::ExistingPrivate)]
- | ^^^^^^^^^^^^^^^^^^
+LL | ExistingPrivate;
+ | ^^^^^^^^^^^^^^^ not found in this scope
|
-note: `cfg_accessible` is not fully implemented
- --> $DIR/cfg_accessible.rs:12:18
+note: unit struct `m::ExistingPrivate` exists but is inaccessible
+ --> $DIR/cfg_accessible.rs:5:5
|
-LL | #[cfg_accessible(m::ExistingPrivate)]
- | ^^^^^^^^^^^^^^^^^^
+LL | struct ExistingPrivate;
+ | ^^^^^^^^^^^^^^^^^^^^^^^ not accessible
-error: not sure whether the path is accessible or not
- --> $DIR/cfg_accessible.rs:16:18
+error[E0425]: cannot find value `NonExistingPrivate` in this scope
+ --> $DIR/cfg_accessible.rs:53:5
|
-LL | #[cfg_accessible(m::NonExistent)]
- | ^^^^^^^^^^^^^^
- |
-note: `cfg_accessible` is not fully implemented
- --> $DIR/cfg_accessible.rs:16:18
- |
-LL | #[cfg_accessible(m::NonExistent)]
- | ^^^^^^^^^^^^^^
+LL | NonExistingPrivate;
+ | ^^^^^^^^^^^^^^^^^^ not found in this scope
-error: not sure whether the path is accessible or not
- --> $DIR/cfg_accessible.rs:37:18
- |
-LL | #[cfg_accessible(S::field)]
- | ^^^^^^^^
- |
-note: `cfg_accessible` is not fully implemented
- --> $DIR/cfg_accessible.rs:37:18
+error[E0425]: cannot find value `NonExistingTraitAlias` in this scope
+ --> $DIR/cfg_accessible.rs:54:5
|
-LL | #[cfg_accessible(S::field)]
- | ^^^^^^^^
+LL | NonExistingTraitAlias;
+ | ^^^^^^^^^^^^^^^^^^^^^ not found in this scope
error: aborting due to 3 previous errors
+For more information about this error, try `rustc --explain E0425`.
error[E0282]: type annotations needed for `Foo<N>`
- --> $DIR/doesnt_infer.rs:11:15
+ --> $DIR/doesnt_infer.rs:11:9
|
LL | let foo = Foo::foo();
- | --- ^^^^^^^^ cannot infer the value of const parameter `N`
- | |
- | consider giving `foo` the explicit type `Foo<N>`, where the const parameter `N` is specified
+ | ^^^
+ |
+help: consider giving `foo` an explicit type, where the the value of const parameter `N` is specified
+ |
+LL | let foo: Foo<N> = Foo::foo();
+ | ++++++++
error: aborting due to previous error
error[E0283]: type annotations needed for `Mask<_, LANES>`
- --> $DIR/issue-91614.rs:6:13
+ --> $DIR/issue-91614.rs:6:9
|
LL | let y = Mask::<_, _>::splat(false);
- | - ^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T`
- | |
- | consider giving `y` the explicit type `Mask<_, LANES>`, where the type parameter `T` is specified
+ | ^
|
= note: cannot satisfy `_: MaskElement`
note: required by a bound in `Mask::<T, LANES>::splat`
|
LL | T: MaskElement,
| ^^^^^^^^^^^ required by this bound in `Mask::<T, LANES>::splat`
+help: consider giving `y` an explicit type, where the type for type parameter `T` is specified
+ |
+LL | let y: Mask<_, LANES> = Mask::<_, _>::splat(false);
+ | ++++++++++++++++
error: aborting due to previous error
--> $DIR/const_eval_resolve_canonical.rs:26:9
|
LL | let mut _q = Default::default();
- | ^^^^^^ consider giving `_q` a type
+ | ^^^^^^
+ |
+help: consider giving `_q` an explicit type
+ |
+LL | let mut _q: _ = Default::default();
+ | +++
error[E0283]: type annotations needed
--> $DIR/const_eval_resolve_canonical.rs:29:10
|
LL | _q = foo::<_, 2>(_q);
- | ^^^^^^^^^^^ cannot infer type
+ | ^^^^^^^^^^^ cannot infer the value of the constant `{ N + 1 }`
|
note: multiple `impl`s satisfying `(): Foo<{ N + 1 }>` found
--> $DIR/const_eval_resolve_canonical.rs:8:1
|
= note: the crate this constant originates from uses `#![feature(generic_const_exprs)]`
help: consider enabling this feature
+ --> $DIR/issue-94287.rs:1:1
|
LL | #![feature(generic_const_exprs)]
|
--> $DIR/cannot-infer-const-args.rs:6:5
|
LL | foo();
- | ^^^ cannot infer the value of const parameter `X` declared on the function `foo`
+ | ^^^ cannot infer the value of the const parameter `X` declared on the function `foo`
|
-help: consider specifying the const argument
+help: consider specifying the generic argument
|
LL | foo::<X>();
- | ~~~~~~~~
+ | +++++
error: aborting due to previous error
--> $DIR/issue-77092.rs:11:26
|
LL | println!("{:?}", take_array_from_mut(&mut arr, i));
- | ^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `take_array_from_mut`
+ | ^^^^^^^^^^^^^^^^^^^ cannot infer the value of the const parameter `N` declared on the function `take_array_from_mut`
|
-help: consider specifying the const argument
+help: consider specifying the generic arguments
|
-LL | println!("{:?}", take_array_from_mut::<N>(&mut arr, i));
- | ~~~~~~~~~~~~~~~~~~~~~~~~
+LL | println!("{:?}", take_array_from_mut::<i32, N>(&mut arr, i));
+ | ++++++++++
error: aborting due to previous error
--> $DIR/method-chain.rs:15:33
|
LL | Foo.bar().bar().bar().bar().baz();
- | ^^^ cannot infer the value of const parameter `N` declared on the associated function `baz`
+ | ^^^ cannot infer the value of the const parameter `N` declared on the associated function `baz`
|
-help: consider specifying the const argument
+help: consider specifying the generic argument
|
LL | Foo.bar().bar().bar().bar().baz::<N>();
- | ~~~~~~~~
+ | +++++
error: aborting due to previous error
--> $DIR/one-param-uninferred.rs:9:23
|
LL | let _: [u8; 17] = foo();
- | ^^^ cannot infer the value of const parameter `M` declared on the function `foo`
+ | ^^^ cannot infer the value of the const parameter `M` declared on the function `foo`
|
-help: consider specifying the const argument
+help: consider specifying the generic arguments
|
-LL | let _: [u8; 17] = foo::<M>();
- | ~~~~~~~~
+LL | let _: [u8; 17] = foo::<17_usize, M>();
+ | +++++++++++++++
error: aborting due to previous error
--> $DIR/uninferred-consts.rs:9:9
|
LL | Foo.foo();
- | ^^^ cannot infer the value of const parameter `A` declared on the associated function `foo`
+ | ^^^ cannot infer the value of the const parameter `A` declared on the associated function `foo`
|
-help: consider specifying the const argument
+help: consider specifying the generic arguments
|
-LL | Foo.foo::<A>();
- | ~~~~~~~~
+LL | Foo.foo::<A, B>();
+ | ++++++++
error: aborting due to previous error
error[E0282]: type annotations needed
- --> $DIR/issue-83249.rs:19:13
+ --> $DIR/issue-83249.rs:19:9
|
LL | let _ = foo([0; 1]);
- | - ^^^ cannot infer type for type parameter `T` declared on the function `foo`
- | |
- | consider giving this pattern a type
+ | ^
|
-help: type parameter declared here
- --> $DIR/issue-83249.rs:12:8
+help: consider giving this pattern a type
|
-LL | fn foo<T: Foo>(_: [u8; T::N]) -> T {
- | ^
+LL | let _: _ = foo([0; 1]);
+ | +++
error: aborting due to previous error
--- /dev/null
+// run-pass
+#![feature(
+ const_slice_from_raw_parts,
+ slice_from_ptr_range,
+ const_slice_from_ptr_range,
+ pointer_byte_offsets,
+ const_pointer_byte_offsets
+)]
+use std::{
+ mem::MaybeUninit,
+ ptr,
+ slice::{from_ptr_range, from_raw_parts},
+};
+
+// Dangling is ok, as long as it's either for ZST reads or for no reads
+pub static S0: &[u32] = unsafe { from_raw_parts(dangling(), 0) };
+pub static S1: &[()] = unsafe { from_raw_parts(dangling(), 3) };
+
+// References are always valid of reads of a single element (basically `slice::from_ref`)
+pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 1) };
+pub static S3: &[MaybeUninit<&u32>] = unsafe { from_raw_parts(&D1, 1) };
+
+// Reinterpreting data is fine, as long as layouts match
+pub static S4: &[u8] = unsafe { from_raw_parts((&D0) as *const _ as _, 3) };
+// This is only valid because D1 has uninitialized bytes, if it was an initialized pointer,
+// that would reinterpret pointers as integers which is UB in CTFE.
+pub static S5: &[MaybeUninit<u8>] = unsafe { from_raw_parts((&D1) as *const _ as _, 2) };
+// Even though u32 and [bool; 4] have different layouts, D0 has a value that
+// is valid as [bool; 4], so this is not UB (it's basically a transmute)
+pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) };
+
+// Structs are considered single allocated objects,
+// as long as you don't reinterpret padding as initialized
+// data everything is ok.
+pub static S7: &[u16] = unsafe {
+ let ptr = (&D2 as *const Struct as *const u16).byte_add(4);
+
+ from_raw_parts(ptr, 3)
+};
+pub static S8: &[MaybeUninit<u16>] = unsafe {
+ let ptr = &D2 as *const Struct as *const MaybeUninit<u16>;
+
+ from_raw_parts(ptr, 6)
+};
+
+pub static R0: &[u32] = unsafe { from_ptr_range(dangling()..dangling()) };
+// from_ptr_range panics on zst
+//pub static R1: &[()] = unsafe { from_ptr_range(dangling(), dangling().byte_add(3)) };
+pub static R2: &[u32] = unsafe {
+ let ptr = &D0 as *const u32;
+ from_ptr_range(ptr..ptr.add(1))
+};
+pub static R3: &[MaybeUninit<&u32>] = unsafe {
+ let ptr = &D1 as *const MaybeUninit<&u32>;
+ from_ptr_range(ptr..ptr.add(1))
+};
+pub static R4: &[u8] = unsafe {
+ let ptr = &D0 as *const u32 as *const u8;
+ from_ptr_range(ptr..ptr.add(3))
+};
+pub static R5: &[MaybeUninit<u8>] = unsafe {
+ let ptr = &D1 as *const MaybeUninit<&u32> as *const MaybeUninit<u8>;
+ from_ptr_range(ptr..ptr.add(2))
+};
+pub static R6: &[bool] = unsafe {
+ let ptr = &D0 as *const u32 as *const bool;
+ from_ptr_range(ptr..ptr.add(4))
+};
+pub static R7: &[u16] = unsafe {
+ let d2 = &D2;
+ let l = &d2.b as *const u32 as *const u16;
+ let r = &d2.d as *const u8 as *const u16;
+
+ from_ptr_range(l..r)
+};
+pub static R8: &[MaybeUninit<u16>] = unsafe {
+ let d2 = &D2;
+ let l = d2 as *const Struct as *const MaybeUninit<u16>;
+ let r = &d2.d as *const u8 as *const MaybeUninit<u16>;
+
+ from_ptr_range(l..r)
+};
+
+// Using valid slice is always valid
+pub static R9: &[u32] = unsafe { from_ptr_range(R0.as_ptr_range()) };
+pub static R10: &[u32] = unsafe { from_ptr_range(R2.as_ptr_range()) };
+
+const D0: u32 = (1 << 16) | 1;
+const D1: MaybeUninit<&u32> = MaybeUninit::uninit();
+const D2: Struct = Struct { a: 1, b: 2, c: 3, d: 4 };
+
+const fn dangling<T>() -> *const T {
+ ptr::NonNull::dangling().as_ptr() as _
+}
+
+#[repr(C)]
+struct Struct {
+ a: u8,
+ // _pad: [MaybeUninit<u8>; 3]
+ b: u32,
+ c: u16,
+ d: u8,
+ // _pad: [MaybeUninit<u8>; 1]
+}
+
+fn main() {}
--- /dev/null
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+LL | &*ptr::slice_from_raw_parts(data, len)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | dereferencing pointer failed: null pointer is not a valid pointer
+ | inside `std::slice::from_raw_parts::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+ ::: $DIR/forbidden_slices.rs:19:34
+ |
+LL | pub static S0: &[u32] = unsafe { from_raw_parts(ptr::null(), 0) };
+ | ------------------------------ inside `S0` at $DIR/forbidden_slices.rs:19:34
+
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+LL | &*ptr::slice_from_raw_parts(data, len)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | dereferencing pointer failed: null pointer is not a valid pointer
+ | inside `std::slice::from_raw_parts::<()>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+ ::: $DIR/forbidden_slices.rs:20:33
+ |
+LL | pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) };
+ | ------------------------------ inside `S1` at $DIR/forbidden_slices.rs:20:33
+
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+LL | &*ptr::slice_from_raw_parts(data, len)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | dereferencing pointer failed: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+ | inside `std::slice::from_raw_parts::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+ ::: $DIR/forbidden_slices.rs:23:34
+ |
+LL | pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 2) };
+ | ---------------------- inside `S2` at $DIR/forbidden_slices.rs:23:34
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/forbidden_slices.rs:26:1
+ |
+LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered uninitialized bytes
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ ╾─ALLOC_ID─╼ 01 00 00 00 │ ╾──╼....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/forbidden_slices.rs:28:1
+ |
+LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size_of::<&u32>()) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ ╾─ALLOC_ID─╼ 04 00 00 00 │ ╾──╼....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/forbidden_slices.rs:30:1
+ |
+LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered 0x11, but expected a boolean
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ ╾─ALLOC_ID─╼ 04 00 00 00 │ ╾──╼....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/forbidden_slices.rs:33:1
+ |
+LL | / pub static S7: &[u16] = unsafe {
+LL | |
+LL | | let ptr = (&D2 as *const Struct as *const u16).byte_add(1);
+LL | |
+LL | | from_raw_parts(ptr, 4)
+LL | | };
+ | |__^ type validation failed: encountered an unaligned reference (required 2 byte alignment but found 1)
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ ╾─A_ID+0x1─╼ 04 00 00 00 │ ╾──╼....
+ }
+
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+LL | &*ptr::slice_from_raw_parts(data, len)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | dereferencing pointer failed: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
+ | inside `std::slice::from_raw_parts::<u64>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+ ::: $DIR/forbidden_slices.rs:44:5
+ |
+LL | from_raw_parts(ptr, 1)
+ | ---------------------- inside `S8` at $DIR/forbidden_slices.rs:44:5
+
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | out-of-bounds offset_from: null pointer is not a valid pointer
+ | inside `ptr::const_ptr::<impl *const u32>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+ ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+LL | unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
+ | ------------------------------ inside `from_ptr_range::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+ ::: $DIR/forbidden_slices.rs:47:34
+ |
+LL | pub static R0: &[u32] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
+ | ---------------------------------------- inside `R0` at $DIR/forbidden_slices.rs:47:34
+
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+LL | assert!(0 < pointee_size && pointee_size <= isize::MAX as usize);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | the evaluated program panicked at 'assertion failed: 0 < pointee_size && pointee_size <= isize::MAX as usize', $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ | inside `ptr::const_ptr::<impl *const ()>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+ ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+LL | unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
+ | ------------------------------ inside `from_ptr_range::<()>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+ ::: $DIR/forbidden_slices.rs:48:33
+ |
+LL | pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
+ | ---------------------------------------- inside `R1` at $DIR/forbidden_slices.rs:48:33
+ |
+ = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+LL | unsafe { intrinsics::offset(self, count) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | pointer arithmetic failed: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+ | inside `ptr::const_ptr::<impl *const u32>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+...
+LL | unsafe { self.offset(count as isize) }
+ | --------------------------- inside `ptr::const_ptr::<impl *const u32>::add` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+ ::: $DIR/forbidden_slices.rs:51:25
+ |
+LL | from_ptr_range(ptr..ptr.add(2))
+ | ---------- inside `R2` at $DIR/forbidden_slices.rs:51:25
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/forbidden_slices.rs:53:1
+ |
+LL | / pub static R4: &[u8] = unsafe {
+LL | |
+LL | | let ptr = (&D1) as *const MaybeUninit<&u32> as *const u8;
+LL | | from_ptr_range(ptr..ptr.add(1))
+LL | | };
+ | |__^ type validation failed at .<deref>[0]: encountered uninitialized bytes
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ ╾ALLOC_ID─╼ 01 00 00 00 │ ╾──╼....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/forbidden_slices.rs:58:1
+ |
+LL | / pub static R5: &[u8] = unsafe {
+LL | |
+LL | | let ptr = &D3 as *const &u32;
+LL | | from_ptr_range(ptr.cast()..ptr.add(1).cast())
+LL | | };
+ | |__^ type validation failed at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ ╾ALLOC_ID─╼ 04 00 00 00 │ ╾──╼....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/forbidden_slices.rs:63:1
+ |
+LL | / pub static R6: &[bool] = unsafe {
+LL | |
+LL | | let ptr = &D0 as *const u32 as *const bool;
+LL | | from_ptr_range(ptr..ptr.add(4))
+LL | | };
+ | |__^ type validation failed at .<deref>[0]: encountered 0x11, but expected a boolean
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ ╾ALLOC_ID─╼ 04 00 00 00 │ ╾──╼....
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/forbidden_slices.rs:68:1
+ |
+LL | / pub static R7: &[u16] = unsafe {
+LL | |
+LL | | let ptr = (&D2 as *const Struct as *const u16).byte_add(1);
+LL | | from_ptr_range(ptr..ptr.add(4))
+LL | | };
+ | |__^ type validation failed: encountered an unaligned reference (required 2 byte alignment but found 1)
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+ = note: the raw bytes of the constant (size: 8, align: 4) {
+ ╾A_ID+0x1─╼ 04 00 00 00 │ ╾──╼....
+ }
+
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+LL | unsafe { intrinsics::offset(self, count) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | pointer arithmetic failed: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
+ | inside `ptr::const_ptr::<impl *const u64>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+...
+LL | unsafe { self.offset(count as isize) }
+ | --------------------------- inside `ptr::const_ptr::<impl *const u64>::add` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+ ::: $DIR/forbidden_slices.rs:75:25
+ |
+LL | from_ptr_range(ptr..ptr.add(1))
+ | ---------- inside `R8` at $DIR/forbidden_slices.rs:75:25
+
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | ptr_offset_from_unsigned cannot compute offset of pointers into different allocations.
+ | inside `ptr::const_ptr::<impl *const u32>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+ ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+LL | unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
+ | ------------------------------ inside `from_ptr_range::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+ ::: $DIR/forbidden_slices.rs:80:34
+ |
+LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) };
+ | ----------------------------------------------- inside `R9` at $DIR/forbidden_slices.rs:80:34
+
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | ptr_offset_from_unsigned cannot compute offset of pointers into different allocations.
+ | inside `ptr::const_ptr::<impl *const u32>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+ ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+LL | unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
+ | ------------------------------ inside `from_ptr_range::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+ ::: $DIR/forbidden_slices.rs:81:35
+ |
+LL | pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) };
+ | ------------------------ inside `R10` at $DIR/forbidden_slices.rs:81:35
+
+error: aborting due to 18 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
--- /dev/null
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+LL | &*ptr::slice_from_raw_parts(data, len)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | dereferencing pointer failed: null pointer is not a valid pointer
+ | inside `std::slice::from_raw_parts::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+ ::: $DIR/forbidden_slices.rs:19:34
+ |
+LL | pub static S0: &[u32] = unsafe { from_raw_parts(ptr::null(), 0) };
+ | ------------------------------ inside `S0` at $DIR/forbidden_slices.rs:19:34
+
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+LL | &*ptr::slice_from_raw_parts(data, len)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | dereferencing pointer failed: null pointer is not a valid pointer
+ | inside `std::slice::from_raw_parts::<()>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+ ::: $DIR/forbidden_slices.rs:20:33
+ |
+LL | pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) };
+ | ------------------------------ inside `S1` at $DIR/forbidden_slices.rs:20:33
+
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+LL | &*ptr::slice_from_raw_parts(data, len)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | dereferencing pointer failed: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+ | inside `std::slice::from_raw_parts::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+ ::: $DIR/forbidden_slices.rs:23:34
+ |
+LL | pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 2) };
+ | ---------------------- inside `S2` at $DIR/forbidden_slices.rs:23:34
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/forbidden_slices.rs:26:1
+ |
+LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered uninitialized bytes
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ ╾───────ALLOC_ID───────╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/forbidden_slices.rs:28:1
+ |
+LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size_of::<&u32>()) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ ╾───────ALLOC_ID───────╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/forbidden_slices.rs:30:1
+ |
+LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered 0x11, but expected a boolean
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ ╾───────ALLOC_ID───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/forbidden_slices.rs:33:1
+ |
+LL | / pub static S7: &[u16] = unsafe {
+LL | |
+LL | | let ptr = (&D2 as *const Struct as *const u16).byte_add(1);
+LL | |
+LL | | from_raw_parts(ptr, 4)
+LL | | };
+ | |__^ type validation failed: encountered an unaligned reference (required 2 byte alignment but found 1)
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ ╾─────ALLOC_ID+0x1─────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
+ }
+
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+LL | &*ptr::slice_from_raw_parts(data, len)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | dereferencing pointer failed: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
+ | inside `std::slice::from_raw_parts::<u64>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+ ::: $DIR/forbidden_slices.rs:44:5
+ |
+LL | from_raw_parts(ptr, 1)
+ | ---------------------- inside `S8` at $DIR/forbidden_slices.rs:44:5
+
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | out-of-bounds offset_from: null pointer is not a valid pointer
+ | inside `ptr::const_ptr::<impl *const u32>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+ ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+LL | unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
+ | ------------------------------ inside `from_ptr_range::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+ ::: $DIR/forbidden_slices.rs:47:34
+ |
+LL | pub static R0: &[u32] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
+ | ---------------------------------------- inside `R0` at $DIR/forbidden_slices.rs:47:34
+
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+LL | assert!(0 < pointee_size && pointee_size <= isize::MAX as usize);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | the evaluated program panicked at 'assertion failed: 0 < pointee_size && pointee_size <= isize::MAX as usize', $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ | inside `ptr::const_ptr::<impl *const ()>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+ ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+LL | unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
+ | ------------------------------ inside `from_ptr_range::<()>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+ ::: $DIR/forbidden_slices.rs:48:33
+ |
+LL | pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
+ | ---------------------------------------- inside `R1` at $DIR/forbidden_slices.rs:48:33
+ |
+ = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+LL | unsafe { intrinsics::offset(self, count) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | pointer arithmetic failed: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+ | inside `ptr::const_ptr::<impl *const u32>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+...
+LL | unsafe { self.offset(count as isize) }
+ | --------------------------- inside `ptr::const_ptr::<impl *const u32>::add` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+ ::: $DIR/forbidden_slices.rs:51:25
+ |
+LL | from_ptr_range(ptr..ptr.add(2))
+ | ---------- inside `R2` at $DIR/forbidden_slices.rs:51:25
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/forbidden_slices.rs:53:1
+ |
+LL | / pub static R4: &[u8] = unsafe {
+LL | |
+LL | | let ptr = (&D1) as *const MaybeUninit<&u32> as *const u8;
+LL | | from_ptr_range(ptr..ptr.add(1))
+LL | | };
+ | |__^ type validation failed at .<deref>[0]: encountered uninitialized bytes
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ ╾──────ALLOC_ID───────╼ 01 00 00 00 00 00 00 00 │ ╾──────╼........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/forbidden_slices.rs:58:1
+ |
+LL | / pub static R5: &[u8] = unsafe {
+LL | |
+LL | | let ptr = &D3 as *const &u32;
+LL | | from_ptr_range(ptr.cast()..ptr.add(1).cast())
+LL | | };
+ | |__^ type validation failed at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ ╾──────ALLOC_ID───────╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/forbidden_slices.rs:63:1
+ |
+LL | / pub static R6: &[bool] = unsafe {
+LL | |
+LL | | let ptr = &D0 as *const u32 as *const bool;
+LL | | from_ptr_range(ptr..ptr.add(4))
+LL | | };
+ | |__^ type validation failed at .<deref>[0]: encountered 0x11, but expected a boolean
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ ╾──────ALLOC_ID───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
+ }
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/forbidden_slices.rs:68:1
+ |
+LL | / pub static R7: &[u16] = unsafe {
+LL | |
+LL | | let ptr = (&D2 as *const Struct as *const u16).byte_add(1);
+LL | | from_ptr_range(ptr..ptr.add(4))
+LL | | };
+ | |__^ type validation failed: encountered an unaligned reference (required 2 byte alignment but found 1)
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+ = note: the raw bytes of the constant (size: 16, align: 8) {
+ ╾────ALLOC_ID+0x1─────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
+ }
+
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+LL | unsafe { intrinsics::offset(self, count) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | pointer arithmetic failed: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
+ | inside `ptr::const_ptr::<impl *const u64>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+...
+LL | unsafe { self.offset(count as isize) }
+ | --------------------------- inside `ptr::const_ptr::<impl *const u64>::add` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+ ::: $DIR/forbidden_slices.rs:75:25
+ |
+LL | from_ptr_range(ptr..ptr.add(1))
+ | ---------- inside `R8` at $DIR/forbidden_slices.rs:75:25
+
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | ptr_offset_from_unsigned cannot compute offset of pointers into different allocations.
+ | inside `ptr::const_ptr::<impl *const u32>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+ ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+LL | unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
+ | ------------------------------ inside `from_ptr_range::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+ ::: $DIR/forbidden_slices.rs:80:34
+ |
+LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) };
+ | ----------------------------------------------- inside `R9` at $DIR/forbidden_slices.rs:80:34
+
+error[E0080]: could not evaluate static initializer
+ --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | ptr_offset_from_unsigned cannot compute offset of pointers into different allocations.
+ | inside `ptr::const_ptr::<impl *const u32>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+ |
+ ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+LL | unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
+ | ------------------------------ inside `from_ptr_range::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
+ |
+ ::: $DIR/forbidden_slices.rs:81:35
+ |
+LL | pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) };
+ | ------------------------ inside `R10` at $DIR/forbidden_slices.rs:81:35
+
+error: aborting due to 18 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
--- /dev/null
+// stderr-per-bitwidth
+// normalize-stderr-test "alloc[0-9]+" -> "ALLOC_ID"
+// normalize-stderr-test "a[0-9]+\+0x" -> "A_ID+0x"
+// error-pattern: could not evaluate static initializer
+#![feature(
+ const_slice_from_raw_parts,
+ slice_from_ptr_range,
+ const_slice_from_ptr_range,
+ pointer_byte_offsets,
+ const_pointer_byte_offsets
+)]
+use std::{
+ mem::{size_of, MaybeUninit},
+ ptr,
+ slice::{from_ptr_range, from_raw_parts},
+};
+
+// Null is never valid for reads
+pub static S0: &[u32] = unsafe { from_raw_parts(ptr::null(), 0) };
+pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) };
+
+// Out of bounds
+pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 2) };
+
+// Reading uninitialized data
+pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; //~ ERROR: it is undefined behavior to use this value
+// Reinterpret pointers as integers (UB in CTFE.)
+pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size_of::<&u32>()) }; //~ ERROR: it is undefined behavior to use this value
+// Layout mismatch
+pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) }; //~ ERROR: it is undefined behavior to use this value
+
+// Reading padding is not ok
+pub static S7: &[u16] = unsafe {
+ //~^ ERROR: it is undefined behavior to use this value
+ let ptr = (&D2 as *const Struct as *const u16).byte_add(1);
+
+ from_raw_parts(ptr, 4)
+};
+
+// Unaligned read
+pub static S8: &[u64] = unsafe {
+ let ptr = (&D4 as *const [u32; 2] as *const u32).byte_add(1).cast::<u64>();
+
+ from_raw_parts(ptr, 1)
+};
+
+pub static R0: &[u32] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
+pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
+pub static R2: &[u32] = unsafe {
+ let ptr = &D0 as *const u32;
+ from_ptr_range(ptr..ptr.add(2))
+};
+pub static R4: &[u8] = unsafe {
+ //~^ ERROR: it is undefined behavior to use this value
+ let ptr = (&D1) as *const MaybeUninit<&u32> as *const u8;
+ from_ptr_range(ptr..ptr.add(1))
+};
+pub static R5: &[u8] = unsafe {
+ //~^ ERROR: it is undefined behavior to use this value
+ let ptr = &D3 as *const &u32;
+ from_ptr_range(ptr.cast()..ptr.add(1).cast())
+};
+pub static R6: &[bool] = unsafe {
+ //~^ ERROR: it is undefined behavior to use this value
+ let ptr = &D0 as *const u32 as *const bool;
+ from_ptr_range(ptr..ptr.add(4))
+};
+pub static R7: &[u16] = unsafe {
+ //~^ ERROR: it is undefined behavior to use this value
+ let ptr = (&D2 as *const Struct as *const u16).byte_add(1);
+ from_ptr_range(ptr..ptr.add(4))
+};
+pub static R8: &[u64] = unsafe {
+ let ptr = (&D4 as *const [u32; 2] as *const u32).byte_add(1).cast::<u64>();
+ from_ptr_range(ptr..ptr.add(1))
+};
+
+// This is sneaky: &D0 and &D0 point to different objects
+// (even if at runtime they have the same address)
+pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) };
+pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) };
+
+const D0: u32 = 0x11;
+const D1: MaybeUninit<&u32> = MaybeUninit::uninit();
+const D2: Struct = Struct { a: 1, b: 2, c: 3, d: 4 };
+const D3: &u32 = &42;
+const D4: [u32; 2] = [17, 42];
+
+#[repr(C)]
+struct Struct {
+ a: u8,
+ // _pad: [MaybeUninit<u8>; 3]
+ b: u32,
+ c: u16,
+ d: u8,
+ // _pad: [MaybeUninit<u8>; 1]
+}
+
+fn main() {}
--- /dev/null
+// check-pass
+
+pub struct GstRc {
+ _obj: *const (),
+ _borrowed: bool,
+}
+
+const FOO: Option<GstRc> = None;
+
+fn main() {
+ let _meh = FOO;
+}
--> $DIR/issue-64662.rs:2:9
|
LL | A = foo(),
- | ^^^ cannot infer type for type parameter `T` declared on the function `foo`
+ | ^^^ cannot infer type of the type parameter `T` declared on the function `foo`
|
-help: type parameter declared here
- --> $DIR/issue-64662.rs:6:14
+help: consider specifying the generic argument
|
-LL | const fn foo<T>() -> isize {
- | ^
+LL | A = foo::<T>(),
+ | +++++
error[E0282]: type annotations needed
--> $DIR/issue-64662.rs:3:9
|
LL | B = foo(),
- | ^^^ cannot infer type for type parameter `T` declared on the function `foo`
+ | ^^^ cannot infer type of the type parameter `T` declared on the function `foo`
|
-help: type parameter declared here
- --> $DIR/issue-64662.rs:6:14
+help: consider specifying the generic argument
|
-LL | const fn foo<T>() -> isize {
- | ^
+LL | B = foo::<T>(),
+ | +++++
error: aborting due to 2 previous errors
| ^^^^^^^^^^
|
= note: `-W dead-code` implied by `-W unused`
-note: `Foo` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
- --> $DIR/derive-uninhabited-enum-38885.rs:10:10
- |
-LL | #[derive(Debug)]
- | ^^^^^
- = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: `Foo` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
warning: 1 warning emitted
LL | struct B { f: () }
| ^^^^^
|
-note: `B` has a derived impl for the trait `Clone`, but this is intentionally ignored during dead code analysis
- --> $DIR/clone-debug-dead-code.rs:9:10
- |
-LL | #[derive(Clone)]
- | ^^^^^
- = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: `B` has a derived impl for the trait `Clone`, but this is intentionally ignored during dead code analysis
error: field is never read: `f`
--> $DIR/clone-debug-dead-code.rs:14:12
LL | struct C { f: () }
| ^^^^^
|
-note: `C` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
- --> $DIR/clone-debug-dead-code.rs:13:10
- |
-LL | #[derive(Debug)]
- | ^^^^^
- = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: `C` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
error: field is never read: `f`
--> $DIR/clone-debug-dead-code.rs:18:12
LL | struct D { f: () }
| ^^^^^
|
-note: `D` has derived impls for the traits `Clone` and `Debug`, but these are intentionally ignored during dead code analysis
- --> $DIR/clone-debug-dead-code.rs:17:10
- |
-LL | #[derive(Debug,Clone)]
- | ^^^^^ ^^^^^
- = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: `D` has derived impls for the traits `Clone` and `Debug`, but these are intentionally ignored during dead code analysis
error: field is never read: `f`
--> $DIR/clone-debug-dead-code.rs:21:12
use std::fmt::Debug;
#[derive(Debug)]
-pub struct Irrelevant<Irrelevant> { //~ ERROR type arguments are not allowed for this type
+pub struct Irrelevant<Irrelevant> { //~ ERROR type arguments are not allowed on type parameter
irrelevant: Irrelevant,
}
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on type parameter `Irrelevant`
--> $DIR/issue-97343.rs:4:23
|
LL | #[derive(Debug)]
- | ----- in this derive macro expansion
+ | -----
+ | |
+ | not allowed on this
+ | in this derive macro expansion
LL | pub struct Irrelevant<Irrelevant> {
| ^^^^^^^^^^ type argument not allowed
|
+note: type parameter `Irrelevant` defined here
+ --> $DIR/issue-97343.rs:4:23
+ |
+LL | pub struct Irrelevant<Irrelevant> {
+ | ^^^^^^^^^^
= note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
|
= note: this error originates in the macro `produces_async` (in Nightly builds, run with -Z macro-backtrace for more info)
help: escape `async` to use it as an identifier
+ --> $DIR/auxiliary/edition-kw-macro-2018.rs:7:19
|
LL | () => (pub fn r#async() {})
| ++
|
= note: this error originates in the macro `produces_async` (in Nightly builds, run with -Z macro-backtrace for more info)
help: escape `async` to use it as an identifier
+ --> $DIR/auxiliary/edition-kw-macro-2018.rs:7:19
|
LL | () => (pub fn r#async() {})
| ++
--> $DIR/forbidden-discriminant-kind-impl.rs:9:1
|
LL | impl DiscriminantKind for NewType {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of 'DiscriminantKind' not allowed
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `DiscriminantKind` not allowed
error: aborting due to previous error
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
--> $DIR/E0109.rs:1:14
|
LL | type X = u32<i32>;
- | ^^^ type argument not allowed
+ | --- ^^^ type argument not allowed
+ | |
+ | not allowed on this
+ |
+help: primitive type `u32` doesn't have generic parameters
+ |
+LL - type X = u32<i32>;
+LL + type X = u32;
+ |
error: aborting due to previous error
-error[E0109]: lifetime arguments are not allowed for this type
+error[E0109]: lifetime arguments are not allowed on this type
--> $DIR/E0110.rs:1:14
|
LL | type X = u32<'static>;
- | ^^^^^^^ lifetime argument not allowed
+ | --- ^^^^^^^ lifetime argument not allowed
+ | |
+ | not allowed on this
+ |
+help: primitive type `u32` doesn't have generic parameters
+ |
+LL - type X = u32<'static>;
+LL + type X = u32;
+ |
error: aborting due to previous error
fn foo<'a, 'b, 'a>(x: &'a str, y: &'b str) {
- //~^ ERROR E0263
+ //~^ ERROR E0403
}
fn main() {}
-error[E0263]: lifetime name `'a` declared twice in the same scope
+error[E0403]: the name `'a` is already used for a generic parameter in this item's generic parameters
--> $DIR/E0263.rs:1:16
|
LL | fn foo<'a, 'b, 'a>(x: &'a str, y: &'b str) {
- | -- ^^ declared twice
+ | -- ^^ already used
| |
- | previous declaration here
+ | first use of `'a`
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0263`.
+For more information about this error, try `rustc --explain E0403`.
--> $DIR/E0282.rs:2:9
|
LL | let x = "hello".chars().rev().collect();
- | ^ consider giving `x` a type
+ | ^
+ |
+help: consider giving `x` an explicit type
+ |
+LL | let x: _ = "hello".chars().rev().collect();
+ | +++
error: aborting due to previous error
--> $DIR/E0283.rs:35:24
|
LL | let bar = foo_impl.into() * 1u32;
- | ---------^^^^--
- | | |
- | | cannot infer type for type parameter `T` declared on the trait `Into`
- | this method call resolves to `T`
+ | ^^^^
|
note: multiple `impl`s satisfying `Impl: Into<_>` found
--> $DIR/E0283.rs:17:1
= note: and another `impl` found in the `core` crate:
- impl<T, U> Into<U> for T
where U: From<T>;
-help: use the fully qualified path for the potential candidate
+help: try using a fully qualified path to specify the expected types
|
-LL | let bar = <Impl as Into<u32>>::into(foo_impl) * 1u32;
- | ++++++++++++++++++++++++++ ~
+LL | let bar = <Impl as Into<T>>::into(foo_impl) * 1u32;
+ | ++++++++++++++++++++++++ ~
error: aborting due to 2 previous errors
|
= note: expected trait `<&dyn DynEq as PartialEq>`
found trait `<&(dyn DynEq + 'static) as PartialEq>`
-note: the lifetime `'_` as defined here...
+note: the anonymous lifetime as defined here...
--> $DIR/E0308-2.rs:9:13
|
LL | impl Eq for &dyn DynEq {}
--> $DIR/E0401.rs:11:5
|
LL | bfnr(x);
- | ^^^^ cannot infer type for type parameter `U` declared on the function `bfnr`
+ | ^^^^ cannot infer type of the type parameter `U` declared on the function `bfnr`
|
-help: type parameter declared here
- --> $DIR/E0401.rs:4:13
+help: consider specifying the generic arguments
|
-LL | fn bfnr<U, V: Baz<U>, W: Fn()>(y: T) {
- | ^
+LL | bfnr::<U, V, W>(x);
+ | +++++++++++
error: aborting due to 4 previous errors
|
LL | use something::Foo;
| ^^^^^^^^^ maybe a missing crate `something`?
+ |
+ = help: consider adding `extern crate something` to use the `something` crate
error: aborting due to previous error
|
LL | use core::default;
| ^^^^ maybe a missing crate `core`?
+ |
+ = help: consider adding `extern crate core` to use the `core` crate
error[E0433]: failed to resolve: maybe a missing crate `core`?
--> $DIR/feature-gate-extern_absolute_paths.rs:4:19
|
LL | let _: u8 = ::core::default::Default();
| ^^^^ maybe a missing crate `core`?
+ |
+ = help: consider adding `extern crate core` to use the `core` crate
error: aborting due to 2 previous errors
0 => break 'a 0,
v if { if v % 2 == 0 { break 'a 1; }; v % 3 == 0 } => { x += 1; },
v if { 'b: { break 'b v == 5; } } => { x = 41; },
- _ => 'b: { //~ WARNING `'b` shadows a label
+ _ => 'b: {
break 'b ();
},
}
0
};
assert_eq!(x, 0);
- let x: u8 = 'a: { //~ WARNING `'a` shadows a label
- 'b: { //~ WARNING `'b` shadows a label
+ let x: u8 = 'a: {
+ 'b: {
if true {
mac1!('a, 1);
}
+++ /dev/null
-warning: label name `'b` shadows a label name that is already in scope
- --> $DIR/label_break_value.rs:105:18
- |
-LL | v if { 'b: { break 'b v == 5; } } => { x = 41; },
- | -- first declared here
-LL | _ => 'b: {
- | ^^ label `'b` already in scope
-
-warning: label name `'a` shadows a label name that is already in scope
- --> $DIR/label_break_value.rs:131:17
- |
-LL | let x: u8 = 'a: {
- | -- first declared here
-...
-LL | let x: u8 = 'a: {
- | ^^ label `'a` already in scope
-
-warning: label name `'b` shadows a label name that is already in scope
- --> $DIR/label_break_value.rs:132:9
- |
-LL | 'b: {
- | -- first declared here
-...
-LL | 'b: {
- | ^^ label `'b` already in scope
-
-warning: 3 warnings emitted
-
macro_rules! mac3 {
($val:expr) => {
'a: {
- //~^ WARNING `'a` shadows a label
- //~| WARNING `'a` shadows a label
- //~| WARNING `'a` shadows a label
$val
}
};
}
- let x: u8 = mac3!('b: { //~ WARNING `'b` shadows a label
+ let x: u8 = mac3!('b: {
if true {
break 'a 3; //~ ERROR undeclared label `'a` [E0426]
}
= note: this error originates in the macro `mac2` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0426]: use of undeclared label `'a`
- --> $DIR/label_break_value_invalid.rs:32:19
+ --> $DIR/label_break_value_invalid.rs:29:19
|
LL | let x: u8 = mac3!('b: {
| -- a label with a similar name is reachable
| help: try using similarly named label: `'b`
error[E0426]: use of undeclared label `'a`
- --> $DIR/label_break_value_invalid.rs:37:29
+ --> $DIR/label_break_value_invalid.rs:34:29
|
LL | let x: u8 = mac3!(break 'a 4);
| ^^ undeclared label `'a`
-warning: label name `'a` shadows a label name that is already in scope
- --> $DIR/label_break_value_invalid.rs:22:13
- |
-LL | let x: u8 = 'a: {
- | -- first declared here
-...
-LL | 'a: {
- | ^^ label `'a` already in scope
-...
-LL | let x: u8 = mac3!('b: {
- | _________________-
-LL | | if true {
-LL | | break 'a 3;
-LL | | }
-LL | | 0
-LL | | });
- | |______- in this macro invocation
- |
- = note: this warning originates in the macro `mac3` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'b` shadows a label name that is already in scope
- --> $DIR/label_break_value_invalid.rs:30:23
- |
-LL | 'b: {
- | -- first declared here
-...
-LL | let x: u8 = mac3!('b: {
- | ^^ label `'b` already in scope
-
-warning: label name `'a` shadows a label name that is already in scope
- --> $DIR/label_break_value_invalid.rs:22:13
- |
-LL | let x: u8 = 'a: {
- | -- first declared here
-...
-LL | 'a: {
- | ^^ label `'a` already in scope
-...
-LL | let x: u8 = mac3!(break 'a 4);
- | ----------------- in this macro invocation
- |
- = note: this warning originates in the macro `mac3` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'a` shadows a label name that is already in scope
- --> $DIR/label_break_value_invalid.rs:22:13
- |
-LL | 'a: {
- | ^^
- | |
- | first declared here
- | label `'a` already in scope
-...
-LL | let x: u8 = mac3!(break 'a 4);
- | ----------------- in this macro invocation
- |
- = note: this warning originates in the macro `mac3` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 3 previous errors; 4 warnings emitted
+error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0426`.
error[E0282]: type annotations needed
- --> $DIR/for-loop-unconstrained-element-type.rs:8:9
+ --> $DIR/for-loop-unconstrained-element-type.rs:8:14
|
LL | for i in Vec::new() { }
- | ^ ---------- the element type for this iterator is not specified
- | |
- | cannot infer type
+ | ^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Vec`
+ |
+help: consider specifying the generic argument
+ |
+LL | for i in Vec::<T>::new() { }
+ | +++++
error: aborting due to previous error
--- /dev/null
+// compile-flags: -Cdebuginfo=2
+// build-pass
+
+// Regression test for #87142
+// This test needs the above flags and the "lib" crate type.
+
+#![feature(type_alias_impl_trait, generator_trait, generators)]
+#![crate_type = "lib"]
+
+use std::ops::Generator;
+
+pub trait GeneratorProviderAlt: Sized {
+ type Gen: Generator<(), Return = (), Yield = ()>;
+
+ fn start(ctx: Context<Self>) -> Self::Gen;
+}
+
+pub struct Context<G: 'static + GeneratorProviderAlt> {
+ pub link: Box<G::Gen>,
+}
+
+impl GeneratorProviderAlt for () {
+ type Gen = impl Generator<(), Return = (), Yield = ()>;
+ fn start(ctx: Context<Self>) -> Self::Gen {
+ move || {
+ match ctx {
+ _ => (),
+ }
+ yield ();
+ }
+ }
+}
//~| ERROR this associated type takes 0 generic arguments but 1 generic argument
//~| ERROR this associated type takes 1 lifetime argument but 0 lifetime arguments
+
+fn bar<'a>(arg: Box<dyn X<Y() = ()>>) {}
+ //~^ ERROR: parenthesized generic arguments cannot be used
+ //~| ERROR this associated type takes 1 lifetime argument but 0 lifetime arguments
+
fn main() {}
|
LL | fn foo<'a>(arg: Box<dyn X<Y('a) = &'a ()>>) {}
| ^^^^^
+ |
+help: use angle brackets instead
+ |
+LL | fn foo<'a>(arg: Box<dyn X<Y<'a> = &'a ()>>) {}
+ | ~ ~
+
+error: parenthesized generic arguments cannot be used in associated type constraints
+ --> $DIR/gat-trait-path-parenthesised-args.rs:14:27
+ |
+LL | fn bar<'a>(arg: Box<dyn X<Y() = ()>>) {}
+ | ^--
+ | |
+ | help: remove these parentheses
error[E0107]: this associated type takes 1 lifetime argument but 0 lifetime arguments were supplied
--> $DIR/gat-trait-path-parenthesised-args.rs:7:27
LL | type Y<'a>;
| ^
-error: aborting due to 4 previous errors
+error[E0107]: this associated type takes 1 lifetime argument but 0 lifetime arguments were supplied
+ --> $DIR/gat-trait-path-parenthesised-args.rs:14:27
+ |
+LL | fn bar<'a>(arg: Box<dyn X<Y() = ()>>) {}
+ | ^ expected 1 lifetime argument
+ |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/gat-trait-path-parenthesised-args.rs:4:8
+ |
+LL | type Y<'a>;
+ | ^ --
+help: add missing lifetime argument
+ |
+LL | fn bar<'a>(arg: Box<dyn X<Y('a) = ()>>) {}
+ | ++
+
+error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0107`.
--> $DIR/issue-91762.rs:25:15
|
LL | ret = <Self::Base as Functor>::fmap(arg);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the associated function `fmap`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the associated function `fmap`
+ |
+help: consider specifying the generic arguments
+ |
+LL | ret = <Self::Base as Functor>::fmap::<T, U>(arg);
+ | ++++++++
error: aborting due to previous error
| ^ lifetimes do not match type in trait
error[E0049]: type `B` has 1 type parameter but its trait declaration has 0 type parameters
- --> $DIR/parameter_number_and_kind_impl.rs:17:12
+ --> $DIR/parameter_number_and_kind_impl.rs:17:16
|
LL | type B<'a, 'b>;
| -- --
| expected 0 type parameters
...
LL | type B<'a, T> = Vec<T>;
- | ^^ ^
- | |
- | found 1 type parameter
+ | ^ found 1 type parameter
error[E0195]: lifetime parameters or bounds on type `C` do not match the trait declaration
--> $DIR/parameter_number_and_kind_impl.rs:19:11
+error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scope
+ --> $DIR/shadowing.rs:4:14
+ |
+LL | trait Shadow<'a> {
+ | -- first declared here
+LL | type Bar<'a>;
+ | ^^ lifetime `'a` already in scope
+
+error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scope
+ --> $DIR/shadowing.rs:13:14
+ |
+LL | impl<'a> NoShadow<'a> for &'a u32 {
+ | -- first declared here
+LL | type Bar<'a> = i32;
+ | ^^ lifetime `'a` already in scope
+
error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters
--> $DIR/shadowing.rs:18:14
|
LL | type Bar<T> = i32;
| ^ already used
-error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scope
- --> $DIR/shadowing.rs:13:14
- |
-LL | impl<'a> NoShadow<'a> for &'a u32 {
- | -- first declared here
-LL | type Bar<'a> = i32;
- | ^^ lifetime `'a` already in scope
-
-error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scope
- --> $DIR/shadowing.rs:4:14
- |
-LL | trait Shadow<'a> {
- | -- first declared here
-LL | type Bar<'a>;
- | ^^ lifetime `'a` already in scope
-
error: aborting due to 4 previous errors
Some errors have detailed explanations: E0403, E0496.
#[rustc_macro_transparency = "semitransparent"]
macro m($a:lifetime) {
- fn g<$a, 'a>() {} //~ ERROR lifetime name `'a` declared twice
+ fn g<$a, 'a>() {} //~ ERROR the name `'a` is already used for a generic parameter
}
#[rustc_macro_transparency = "transparent"]
macro n($a:lifetime) {
- fn h<$a, 'a>() {} //~ ERROR lifetime name `'a` declared twice
+ fn h<$a, 'a>() {} //~ ERROR the name `'a` is already used for a generic parameter
}
m!('a);
-error[E0263]: lifetime name `'a` declared twice in the same scope
+error[E0403]: the name `'a` is already used for a generic parameter in this item's generic parameters
--> $DIR/duplicate_lifetimes.rs:8:14
|
LL | fn g<$a, 'a>() {}
- | ^^ declared twice
+ | ^^ already used
...
LL | m!('a);
| ------
| | |
- | | previous declaration here
+ | | first use of `'a`
| in this macro invocation
|
= note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0263]: lifetime name `'a` declared twice in the same scope
+error[E0403]: the name `'a` is already used for a generic parameter in this item's generic parameters
--> $DIR/duplicate_lifetimes.rs:13:14
|
LL | fn h<$a, 'a>() {}
- | ^^ declared twice
+ | ^^ already used
...
LL | n!('a);
| ------
| | |
- | | previous declaration here
+ | | first use of `'a`
| in this macro invocation
|
= note: this error originates in the macro `n` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0263`.
+For more information about this error, try `rustc --explain E0403`.
macro_rules! loop_x {
($e: expr) => {
// $e shouldn't be able to interact with this 'x
- 'x: loop { $e }
- //~^ WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- }
+ 'x: loop {
+ $e
+ }
+ };
}
macro_rules! while_true {
($e: expr) => {
// $e shouldn't be able to interact with this 'x
- 'x: while 1 + 1 == 2 { $e }
- //~^ WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- }
+ 'x: while 1 + 1 == 2 {
+ $e
+ }
+ };
}
macro_rules! run_once {
($e: expr) => {
// ditto
- 'x: for _ in 0..1 { $e }
- //~^ WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- }
+ 'x: for _ in 0..1 {
+ $e
+ }
+ };
}
pub fn main() {
let k: isize = {
'x: for _ in 0..1 {
- //~^ WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
// ditto
loop_x!(break 'x);
i += 1;
let l: isize = {
'x: for _ in 0..1 {
- //~^ WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
// ditto
while_true!(break 'x);
i += 1;
let n: isize = {
'x: for _ in 0..1 {
- //~^ WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
// ditto
run_once!(continue 'x);
i += 1;
+++ /dev/null
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:16:9
- |
-LL | 'x: loop { $e }
- | ^^ label `'x` already in scope
-...
-LL | 'x: loop {
- | -- first declared here
-LL | // this 'x should refer to the outer loop, lexically
-LL | loop_x!(break 'x);
- | ----------------- in this macro invocation
- |
- = note: this warning originates in the macro `loop_x` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:64:9
- |
-LL | 'x: loop {
- | -- first declared here
-...
-LL | 'x: for _ in 0..1 {
- | ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:64:9
- |
-LL | 'x: loop { $e }
- | -- first declared here
-...
-LL | 'x: for _ in 0..1 {
- | ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:16:9
- |
-LL | 'x: loop { $e }
- | ^^ label `'x` already in scope
-...
-LL | 'x: loop {
- | -- first declared here
-...
-LL | loop_x!(break 'x);
- | ----------------- in this macro invocation
- |
- = note: this warning originates in the macro `loop_x` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:16:9
- |
-LL | 'x: loop { $e }
- | ^^
- | |
- | first declared here
- | label `'x` already in scope
-...
-LL | loop_x!(break 'x);
- | ----------------- in this macro invocation
- |
- = note: this warning originates in the macro `loop_x` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:16:9
- |
-LL | 'x: loop { $e }
- | ^^ label `'x` already in scope
-...
-LL | 'x: for _ in 0..1 {
- | -- first declared here
-...
-LL | loop_x!(break 'x);
- | ----------------- in this macro invocation
- |
- = note: this warning originates in the macro `loop_x` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:76:9
- |
-LL | 'x: loop {
- | -- first declared here
-...
-LL | 'x: for _ in 0..1 {
- | ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:76:9
- |
-LL | 'x: loop { $e }
- | -- first declared here
-...
-LL | 'x: for _ in 0..1 {
- | ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:76:9
- |
-LL | 'x: for _ in 0..1 {
- | -- first declared here
-...
-LL | 'x: for _ in 0..1 {
- | ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:76:9
- |
-LL | 'x: loop { $e }
- | -- first declared here
-...
-LL | 'x: for _ in 0..1 {
- | ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:27:9
- |
-LL | 'x: while 1 + 1 == 2 { $e }
- | ^^ label `'x` already in scope
-...
-LL | 'x: loop {
- | -- first declared here
-...
-LL | while_true!(break 'x);
- | --------------------- in this macro invocation
- |
- = note: this warning originates in the macro `while_true` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:27:9
- |
-LL | 'x: loop { $e }
- | -- first declared here
-...
-LL | 'x: while 1 + 1 == 2 { $e }
- | ^^ label `'x` already in scope
-...
-LL | while_true!(break 'x);
- | --------------------- in this macro invocation
- |
- = note: this warning originates in the macro `while_true` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:27:9
- |
-LL | 'x: while 1 + 1 == 2 { $e }
- | ^^ label `'x` already in scope
-...
-LL | 'x: for _ in 0..1 {
- | -- first declared here
-...
-LL | while_true!(break 'x);
- | --------------------- in this macro invocation
- |
- = note: this warning originates in the macro `while_true` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:27:9
- |
-LL | 'x: loop { $e }
- | -- first declared here
-...
-LL | 'x: while 1 + 1 == 2 { $e }
- | ^^ label `'x` already in scope
-...
-LL | while_true!(break 'x);
- | --------------------- in this macro invocation
- |
- = note: this warning originates in the macro `while_true` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:27:9
- |
-LL | 'x: while 1 + 1 == 2 { $e }
- | ^^ label `'x` already in scope
-...
-LL | 'x: for _ in 0..1 {
- | -- first declared here
-...
-LL | while_true!(break 'x);
- | --------------------- in this macro invocation
- |
- = note: this warning originates in the macro `while_true` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:90:9
- |
-LL | 'x: loop {
- | -- first declared here
-...
-LL | 'x: for _ in 0..1 {
- | ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:90:9
- |
-LL | 'x: loop { $e }
- | -- first declared here
-...
-LL | 'x: for _ in 0..1 {
- | ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:90:9
- |
-LL | 'x: for _ in 0..1 {
- | -- first declared here
-...
-LL | 'x: for _ in 0..1 {
- | ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:90:9
- |
-LL | 'x: loop { $e }
- | -- first declared here
-...
-LL | 'x: for _ in 0..1 {
- | ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:90:9
- |
-LL | 'x: for _ in 0..1 {
- | -- first declared here
-...
-LL | 'x: for _ in 0..1 {
- | ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:90:9
- |
-LL | 'x: while 1 + 1 == 2 { $e }
- | -- first declared here
-...
-LL | 'x: for _ in 0..1 {
- | ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:39:9
- |
-LL | 'x: for _ in 0..1 { $e }
- | ^^ label `'x` already in scope
-...
-LL | 'x: loop {
- | -- first declared here
-...
-LL | run_once!(continue 'x);
- | ---------------------- in this macro invocation
- |
- = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:39:9
- |
-LL | 'x: loop { $e }
- | -- first declared here
-...
-LL | 'x: for _ in 0..1 { $e }
- | ^^ label `'x` already in scope
-...
-LL | run_once!(continue 'x);
- | ---------------------- in this macro invocation
- |
- = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:39:9
- |
-LL | 'x: for _ in 0..1 { $e }
- | ^^ label `'x` already in scope
-...
-LL | 'x: for _ in 0..1 {
- | -- first declared here
-...
-LL | run_once!(continue 'x);
- | ---------------------- in this macro invocation
- |
- = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:39:9
- |
-LL | 'x: loop { $e }
- | -- first declared here
-...
-LL | 'x: for _ in 0..1 { $e }
- | ^^ label `'x` already in scope
-...
-LL | run_once!(continue 'x);
- | ---------------------- in this macro invocation
- |
- = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:39:9
- |
-LL | 'x: for _ in 0..1 { $e }
- | ^^ label `'x` already in scope
-...
-LL | 'x: for _ in 0..1 {
- | -- first declared here
-...
-LL | run_once!(continue 'x);
- | ---------------------- in this macro invocation
- |
- = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:39:9
- |
-LL | 'x: while 1 + 1 == 2 { $e }
- | -- first declared here
-...
-LL | 'x: for _ in 0..1 { $e }
- | ^^ label `'x` already in scope
-...
-LL | run_once!(continue 'x);
- | ---------------------- in this macro invocation
- |
- = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels-in-let.rs:39:9
- |
-LL | 'x: for _ in 0..1 { $e }
- | ^^ label `'x` already in scope
-...
-LL | 'x: for _ in 0..1 {
- | -- first declared here
-...
-LL | run_once!(continue 'x);
- | ---------------------- in this macro invocation
- |
- = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: 28 warnings emitted
-
macro_rules! loop_x {
($e: expr) => {
// $e shouldn't be able to interact with this 'x
- 'x: loop { $e }
- //~^ WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- }
+ 'x: loop {
+ $e
+ }
+ };
}
macro_rules! run_once {
($e: expr) => {
// ditto
- 'x: for _ in 0..1 { $e }
- //~^ WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- }
+ 'x: for _ in 0..1 {
+ $e
+ }
+ };
}
macro_rules! while_x {
($e: expr) => {
// ditto
- 'x: while 1 + 1 == 2 { $e }
- //~^ WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- }
+ 'x: while 1 + 1 == 2 {
+ $e
+ }
+ };
}
pub fn main() {
}
'x: loop {
- //~^ WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
-
// ditto
loop_x!(break 'x);
panic!("break doesn't act hygienically inside infinite loop");
}
'x: while 1 + 1 == 2 {
- //~^ WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
-
while_x!(break 'x);
panic!("break doesn't act hygienically inside infinite while loop");
}
'x: for _ in 0..1 {
- //~^ WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
- //~| WARNING shadows a label name that is already in scope
-
// ditto
run_once!(continue 'x);
panic!("continue doesn't act hygienically inside for loop");
+++ /dev/null
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:13:9
- |
-LL | 'x: loop { $e }
- | ^^ label `'x` already in scope
-...
-LL | 'x: for _ in 0..1 {
- | -- first declared here
-LL | // this 'x should refer to the outer loop, lexically
-LL | loop_x!(break 'x);
- | ----------------- in this macro invocation
- |
- = note: this warning originates in the macro `loop_x` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:54:5
- |
-LL | 'x: for _ in 0..1 {
- | -- first declared here
-...
-LL | 'x: loop {
- | ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:54:5
- |
-LL | 'x: loop { $e }
- | -- first declared here
-...
-LL | 'x: loop {
- | ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:13:9
- |
-LL | 'x: loop { $e }
- | ^^ label `'x` already in scope
-...
-LL | 'x: for _ in 0..1 {
- | -- first declared here
-...
-LL | loop_x!(break 'x);
- | ----------------- in this macro invocation
- |
- = note: this warning originates in the macro `loop_x` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:13:9
- |
-LL | 'x: loop { $e }
- | ^^
- | |
- | first declared here
- | label `'x` already in scope
-...
-LL | loop_x!(break 'x);
- | ----------------- in this macro invocation
- |
- = note: this warning originates in the macro `loop_x` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:13:9
- |
-LL | 'x: loop { $e }
- | ^^ label `'x` already in scope
-...
-LL | 'x: loop {
- | -- first declared here
-...
-LL | loop_x!(break 'x);
- | ----------------- in this macro invocation
- |
- = note: this warning originates in the macro `loop_x` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:63:5
- |
-LL | 'x: for _ in 0..1 {
- | -- first declared here
-...
-LL | 'x: while 1 + 1 == 2 {
- | ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:63:5
- |
-LL | 'x: loop { $e }
- | -- first declared here
-...
-LL | 'x: while 1 + 1 == 2 {
- | ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:63:5
- |
-LL | 'x: loop {
- | -- first declared here
-...
-LL | 'x: while 1 + 1 == 2 {
- | ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:63:5
- |
-LL | 'x: loop { $e }
- | -- first declared here
-...
-LL | 'x: while 1 + 1 == 2 {
- | ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:38:9
- |
-LL | 'x: while 1 + 1 == 2 { $e }
- | ^^ label `'x` already in scope
-...
-LL | 'x: for _ in 0..1 {
- | -- first declared here
-...
-LL | while_x!(break 'x);
- | ------------------ in this macro invocation
- |
- = note: this warning originates in the macro `while_x` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:38:9
- |
-LL | 'x: loop { $e }
- | -- first declared here
-...
-LL | 'x: while 1 + 1 == 2 { $e }
- | ^^ label `'x` already in scope
-...
-LL | while_x!(break 'x);
- | ------------------ in this macro invocation
- |
- = note: this warning originates in the macro `while_x` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:38:9
- |
-LL | 'x: while 1 + 1 == 2 { $e }
- | ^^ label `'x` already in scope
-...
-LL | 'x: loop {
- | -- first declared here
-...
-LL | while_x!(break 'x);
- | ------------------ in this macro invocation
- |
- = note: this warning originates in the macro `while_x` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:38:9
- |
-LL | 'x: loop { $e }
- | -- first declared here
-...
-LL | 'x: while 1 + 1 == 2 { $e }
- | ^^ label `'x` already in scope
-...
-LL | while_x!(break 'x);
- | ------------------ in this macro invocation
- |
- = note: this warning originates in the macro `while_x` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:38:9
- |
-LL | 'x: while 1 + 1 == 2 { $e }
- | ^^ label `'x` already in scope
-...
-LL | 'x: while 1 + 1 == 2 {
- | -- first declared here
-...
-LL | while_x!(break 'x);
- | ------------------ in this macro invocation
- |
- = note: this warning originates in the macro `while_x` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:73:5
- |
-LL | 'x: for _ in 0..1 {
- | -- first declared here
-...
-LL | 'x: for _ in 0..1 {
- | ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:73:5
- |
-LL | 'x: loop { $e }
- | -- first declared here
-...
-LL | 'x: for _ in 0..1 {
- | ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:73:5
- |
-LL | 'x: loop {
- | -- first declared here
-...
-LL | 'x: for _ in 0..1 {
- | ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:73:5
- |
-LL | 'x: loop { $e }
- | -- first declared here
-...
-LL | 'x: for _ in 0..1 {
- | ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:73:5
- |
-LL | 'x: while 1 + 1 == 2 {
- | -- first declared here
-...
-LL | 'x: for _ in 0..1 {
- | ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:73:5
- |
-LL | 'x: while 1 + 1 == 2 { $e }
- | -- first declared here
-...
-LL | 'x: for _ in 0..1 {
- | ^^ label `'x` already in scope
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:24:9
- |
-LL | 'x: for _ in 0..1 { $e }
- | ^^ label `'x` already in scope
-...
-LL | 'x: for _ in 0..1 {
- | -- first declared here
-...
-LL | run_once!(continue 'x);
- | ---------------------- in this macro invocation
- |
- = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:24:9
- |
-LL | 'x: loop { $e }
- | -- first declared here
-...
-LL | 'x: for _ in 0..1 { $e }
- | ^^ label `'x` already in scope
-...
-LL | run_once!(continue 'x);
- | ---------------------- in this macro invocation
- |
- = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:24:9
- |
-LL | 'x: for _ in 0..1 { $e }
- | ^^ label `'x` already in scope
-...
-LL | 'x: loop {
- | -- first declared here
-...
-LL | run_once!(continue 'x);
- | ---------------------- in this macro invocation
- |
- = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:24:9
- |
-LL | 'x: loop { $e }
- | -- first declared here
-...
-LL | 'x: for _ in 0..1 { $e }
- | ^^ label `'x` already in scope
-...
-LL | run_once!(continue 'x);
- | ---------------------- in this macro invocation
- |
- = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:24:9
- |
-LL | 'x: for _ in 0..1 { $e }
- | ^^ label `'x` already in scope
-...
-LL | 'x: while 1 + 1 == 2 {
- | -- first declared here
-...
-LL | run_once!(continue 'x);
- | ---------------------- in this macro invocation
- |
- = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:24:9
- |
-LL | 'x: for _ in 0..1 { $e }
- | ^^ label `'x` already in scope
-...
-LL | 'x: while 1 + 1 == 2 { $e }
- | -- first declared here
-...
-LL | run_once!(continue 'x);
- | ---------------------- in this macro invocation
- |
- = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: label name `'x` shadows a label name that is already in scope
- --> $DIR/hygienic-labels.rs:24:9
- |
-LL | 'x: for _ in 0..1 { $e }
- | ^^ label `'x` already in scope
-...
-LL | 'x: for _ in 0..1 {
- | -- first declared here
-...
-LL | run_once!(continue 'x);
- | ---------------------- in this macro invocation
- |
- = note: this warning originates in the macro `run_once` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: 28 warnings emitted
-
}
fn muh() -> Result<(), impl std::fmt::Debug> {
- Err("whoops")?; //~^ ERROR type annotations needed
- Ok(())
+ Err("whoops")?;
+ Ok(()) //~ ERROR type annotations needed
}
fn muh2() -> Result<(), impl std::fmt::Debug> {
- return Err(From::from("foo")); //~^ ERROR type annotations needed
+ return Err(From::from("foo")); //~ ERROR type annotations needed
Ok(())
}
fn muh3() -> Result<(), impl std::fmt::Debug> {
- Err(From::from("foo")) //~^ ERROR type annotations needed
+ Err(From::from("foo")) //~ ERROR type annotations needed
}
fn main() {}
error[E0282]: type annotations needed
- --> $DIR/cross-return-site-inference.rs:31:24
+ --> $DIR/cross-return-site-inference.rs:33:5
|
-LL | fn muh() -> Result<(), impl std::fmt::Debug> {
- | ^^^^^^^^^^^^^^^^^^^^ cannot infer type
+LL | Ok(())
+ | ^^ cannot infer type of the type parameter `E` declared on the enum `Result`
+ |
+help: consider specifying the generic arguments
+ |
+LL | Ok::<(), E>(())
+ | +++++++++
error[E0282]: type annotations needed
- --> $DIR/cross-return-site-inference.rs:36:25
+ --> $DIR/cross-return-site-inference.rs:37:12
+ |
+LL | return Err(From::from("foo"));
+ | ^^^ cannot infer type of the type parameter `E` declared on the enum `Result`
|
-LL | fn muh2() -> Result<(), impl std::fmt::Debug> {
- | ^^^^^^^^^^^^^^^^^^^^ cannot infer type
+help: consider specifying the generic arguments
+ |
+LL | return Err::<(), E>(From::from("foo"));
+ | +++++++++
error[E0282]: type annotations needed
- --> $DIR/cross-return-site-inference.rs:41:25
+ --> $DIR/cross-return-site-inference.rs:42:5
+ |
+LL | Err(From::from("foo"))
+ | ^^^ cannot infer type of the type parameter `E` declared on the enum `Result`
+ |
+help: consider specifying the generic arguments
|
-LL | fn muh3() -> Result<(), impl std::fmt::Debug> {
- | ^^^^^^^^^^^^^^^^^^^^ cannot infer type
+LL | Err::<(), E>(From::from("foo"))
+ | +++++++++
error: aborting due to 3 previous errors
--- /dev/null
+trait Foo<T> {
+ fn foo(self, f: impl FnOnce());
+}
+
+impl<T> Foo<T> for () {
+ fn foo(self, f: impl FnOnce()) {
+ f()
+ }
+}
+
+fn main() {
+ // FIXME: This should ideally use a fully qualified path
+ // without mentioning the generic arguments of `foo`.
+ ().foo(|| ()) //~ ERROR type annotations needed
+}
--- /dev/null
+error[E0282]: type annotations needed
+ --> $DIR/fully-qualified-path-impl-trait.rs:14:8
+ |
+LL | ().foo(|| ())
+ | ^^^ cannot infer type for type parameter `T` declared on the trait `Foo`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
use std::marker::PhantomData;
fn weird() -> PhantomData<impl Sized> {
- PhantomData //~^ ERROR type annotations needed
+ PhantomData //~ ERROR type annotations needed
}
fn main() {}
error[E0282]: type annotations needed
- --> $DIR/fallback_inference.rs:3:27
+ --> $DIR/fallback_inference.rs:4:5
|
-LL | fn weird() -> PhantomData<impl Sized> {
- | ^^^^^^^^^^ cannot infer type
+LL | PhantomData
+ | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `PhantomData`
+ |
+help: consider specifying the generic argument
+ |
+LL | PhantomData::<T>
+ | +++++
error: aborting due to previous error
#![feature(type_alias_impl_trait)]
fn reify_as() -> Thunk<impl FnOnce(Continuation) -> Continuation> {
- Thunk::new(|mut cont| { //~ ERROR type annotations needed
- cont.reify_as();
+ Thunk::new(|mut cont| {
+ cont.reify_as(); //~ ERROR type annotations needed
cont
})
}
type Tait = impl FnOnce(Continuation) -> Continuation;
fn reify_as_tait() -> Thunk<Tait> {
- Thunk::new(|mut cont| { //~ ERROR type annotations needed
- cont.reify_as();
+ Thunk::new(|mut cont| {
+ cont.reify_as(); //~ ERROR type annotations needed
cont
})
}
error[E0282]: type annotations needed
- --> $DIR/hidden-type-is-opaque-2.rs:8:17
+ --> $DIR/hidden-type-is-opaque-2.rs:9:9
|
-LL | Thunk::new(|mut cont| {
- | ^^^^^^^^ consider giving this closure parameter a type
+LL | cont.reify_as();
+ | ^^^^ cannot infer type
|
= note: type must be known at this point
error[E0282]: type annotations needed
- --> $DIR/hidden-type-is-opaque-2.rs:17:17
+ --> $DIR/hidden-type-is-opaque-2.rs:18:9
|
-LL | Thunk::new(|mut cont| {
- | ^^^^^^^^ consider giving this closure parameter a type
+LL | cont.reify_as();
+ | ^^^^ cannot infer type
|
= note: type must be known at this point
--- /dev/null
+// issue-54966: ICE returning an unknown type with impl FnMut
+
+fn generate_duration() -> Oper<impl FnMut()> {}
+//~^ ERROR cannot find type `Oper` in this scope
+
+fn main() {}
--- /dev/null
+error[E0412]: cannot find type `Oper` in this scope
+ --> $DIR/issue-54966.rs:3:27
+ |
+LL | fn generate_duration() -> Oper<impl FnMut()> {}
+ | ^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0412`.
--> $DIR/issue-84073.rs:32:16
|
LL | Race::new(|race| race.when());
- | ^^^^ consider giving this closure parameter the explicit type `RaceBuilder<T, Never<T>>`, where the type parameter `T` is specified
+ | ^^^^
+ |
+help: consider giving this closure parameter an explicit type, where the type for type parameter `T` is specified
+ |
+LL | Race::new(|race: RaceBuilder<T, Never<T>>| race.when());
+ | ++++++++++++++++++++++++++
error: aborting due to previous error
--> $DIR/issue-86719.rs:9:10
|
LL | |_| true
- | ^ consider giving this closure parameter a type
+ | ^
+ |
+help: consider giving this closure parameter an explicit type
+ |
+LL | |_: _| true
+ | +++
error: aborting due to 3 previous errors
--> $DIR/issue-92305.rs:7:5
|
LL | iter::empty()
- | ^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the function `empty`
+ | ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty`
+ |
+help: consider specifying the generic argument
+ |
+LL | iter::empty::<T>()
+ | +++++
error[E0282]: type annotations needed
--> $DIR/issue-92305.rs:10:35
|
LL | use main::bar;
| ^^^^ maybe a missing crate `main`?
+ |
+ = help: consider adding `extern crate main` to use the `main` crate
error: aborting due to previous error
|
LL | use unresolved::*;
| ^^^^^^^^^^ maybe a missing crate `unresolved`?
+ |
+ = help: consider adding `extern crate unresolved` to use the `unresolved` crate
error: aborting due to previous error
--- /dev/null
+// run-pass
+use super::*;
+
+pub struct S;
--- /dev/null
+// run-pass
+use super::*;
+
+use super::B::S;
+
+pub struct T { i: i32 }
--- /dev/null
+// run-pass
+pub mod B;
+pub mod C;
+
+pub use self::C::T;
--- /dev/null
+// run-pass
+#![allow(dead_code)]
+#![allow(unused_imports)]
+#![allow(non_snake_case)]
+
+// ignore-pretty issue #37195
+
+#[path = "issue-26873-multifile/mod.rs"]
+mod multifile;
+
+fn main() {}
--- /dev/null
+// run-pass
+#![allow(dead_code)]
+#![allow(unused_imports)]
+#![allow(non_snake_case)]
+
+mod A {
+ pub mod B {
+ use super::*;
+
+ pub struct S;
+ }
+
+ pub mod C {
+ use super::*;
+ use super::B::S;
+
+ pub struct T;
+ }
+
+ pub use self::C::T;
+}
+
+use A::*;
+
+fn main() {}
--- /dev/null
+// run-pass
+mod A;
+
+use self::A::*;
+++ /dev/null
-// run-pass
-#![allow(dead_code)]
-#![allow(unused_imports)]
-#![allow(non_snake_case)]
-
-mod A {
- pub mod B {
- use super::*;
-
- pub struct S;
- }
-
- pub mod C {
- use super::*;
- use super::B::S;
-
- pub struct T;
- }
-
- pub use self::C::T;
-}
-
-use A::*;
-
-fn main() {}
|
LL | use abc::one_el;
| ^^^ maybe a missing crate `abc`?
+ |
+ = help: consider adding `extern crate abc` to use the `abc` crate
error[E0432]: unresolved import `abc`
--> $DIR/issue-33464.rs:5:5
|
LL | use abc::{a, bbb, cccccc};
| ^^^ maybe a missing crate `abc`?
+ |
+ = help: consider adding `extern crate abc` to use the `abc` crate
error[E0432]: unresolved import `a_very_long_name`
--> $DIR/issue-33464.rs:7:5
|
LL | use a_very_long_name::{el, el2};
| ^^^^^^^^^^^^^^^^ maybe a missing crate `a_very_long_name`?
+ |
+ = help: consider adding `extern crate a_very_long_name` to use the `a_very_long_name` crate
error: aborting due to 3 previous errors
|
LL | use issue_36881_aux::Foo;
| ^^^^^^^^^^^^^^^ maybe a missing crate `issue_36881_aux`?
+ |
+ = help: consider adding `extern crate issue_36881_aux` to use the `issue_36881_aux` crate
error: aborting due to previous error
|
LL | use libc::*;
| ^^^^ maybe a missing crate `libc`?
+ |
+ = help: consider adding `extern crate libc` to use the `libc` crate
error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead?
--> $DIR/issue-37887.rs:2:5
|
LL | use nonexistent_module::mac;
| ^^^^^^^^^^^^^^^^^^ maybe a missing crate `nonexistent_module`?
+ |
+ = help: consider adding `extern crate nonexistent_module` to use the `nonexistent_module` crate
error[E0659]: `mac` is ambiguous
--> $DIR/issue-53269.rs:8:5
|
LL | use non_existent::non_existent;
| ^^^^^^^^^^^^ maybe a missing crate `non_existent`?
+ |
+ = help: consider adding `extern crate non_existent` to use the `non_existent` crate
error: cannot determine resolution for the derive macro `NonExistent`
--> $DIR/issue-55457.rs:5:10
|
LL | use clippy::a::b;
| ^^^^^^ maybe a missing crate `clippy`?
+ |
+ = help: consider adding `extern crate clippy` to use the `clippy` crate
error[E0432]: unresolved import `clippy`
--> $DIR/tool-mod-child.rs:1:5
|
LL | use clippy::a;
| ^^^^^^ maybe a missing crate `clippy`?
+ |
+ = help: consider adding `extern crate clippy` to use the `clippy` crate
error[E0433]: failed to resolve: maybe a missing crate `rustdoc`?
--> $DIR/tool-mod-child.rs:5:5
|
LL | use rustdoc::a::b;
| ^^^^^^^ maybe a missing crate `rustdoc`?
+ |
+ = help: consider adding `extern crate rustdoc` to use the `rustdoc` crate
error[E0432]: unresolved import `rustdoc`
--> $DIR/tool-mod-child.rs:4:5
|
LL | use rustdoc::a;
| ^^^^^^^ maybe a missing crate `rustdoc`?
+ |
+ = help: consider adding `extern crate rustdoc` to use the `rustdoc` crate
error: aborting due to 4 previous errors
|
LL | use foo::bar;
| ^^^ maybe a missing crate `foo`?
+ |
+ = help: consider adding `extern crate foo` to use the `foo` crate
error[E0432]: unresolved import `baz`
--> $DIR/unresolved-imports-used.rs:12:5
|
LL | use baz::*;
| ^^^ maybe a missing crate `baz`?
+ |
+ = help: consider adding `extern crate baz` to use the `baz` crate
error[E0432]: unresolved import `foo2`
--> $DIR/unresolved-imports-used.rs:14:5
|
LL | use foo2::bar2;
| ^^^^ maybe a missing crate `foo2`?
+ |
+ = help: consider adding `extern crate foo2` to use the `foo2` crate
error[E0432]: unresolved import `baz2`
--> $DIR/unresolved-imports-used.rs:15:5
|
LL | use baz2::*;
| ^^^^ maybe a missing crate `baz2`?
+ |
+ = help: consider adding `extern crate baz2` to use the `baz2` crate
error[E0603]: function `quz` is private
--> $DIR/unresolved-imports-used.rs:9:10
|
LL | InMemoryStore.get_raw(&String::default());
| ^^^^^^^ cannot infer type for type parameter `K`
- |
-help: type parameter declared here
- --> $DIR/ambiguous_type_parameter.rs:9:6
- |
-LL | impl<K> Store<String, HashMap<K, String>> for InMemoryStore {
- | ^
error: aborting due to previous error
error[E0282]: type annotations needed
--> $DIR/cannot-infer-async.rs:13:9
|
-LL | let fut = async {
- | --- consider giving `fut` a type
-...
LL | Ok(())
- | ^^ cannot infer type for type parameter `E` declared on the enum `Result`
+ | ^^ cannot infer type of the type parameter `E` declared on the enum `Result`
+ |
+help: consider specifying the generic arguments
+ |
+LL | Ok::<(), E>(())
+ | +++++++++
error: aborting due to previous error
// note about the `?` operator in the closure body, which isn't relevant to
// the inference.
let x = |r| {
- //~^ ERROR type annotations needed
let v = r?;
Ok(v)
};
- let _ = x(x(Ok(())));
+ let _ = x(x(Ok(()))); //~ ERROR type annotations needed for `Result<(), E>`
}
error[E0282]: type annotations needed for `Result<(), E>`
- --> $DIR/cannot-infer-closure-circular.rs:7:14
+ --> $DIR/cannot-infer-closure-circular.rs:12:9
|
-LL | let x = |r| {
- | ^ consider giving this closure parameter the explicit type `Result<(), E>`, where the type parameter `E` is specified
+LL | let _ = x(x(Ok(())));
+ | ^
+ |
+help: consider giving this pattern a type, where the type for type parameter `E` is specified
+ |
+LL | let _: Result<(), E> = x(x(Ok(())));
+ | +++++++++++++++
error: aborting due to previous error
fn main() {
let x = |a: (), b: ()| {
Err(a)?;
- Ok(b) //~ ERROR type annotations needed for the closure
+ Ok(b) //~ ERROR type annotations needed
};
}
-error[E0282]: type annotations needed for the closure `fn((), ()) -> Result<(), _>`
+error[E0282]: type annotations needed
--> $DIR/cannot-infer-closure.rs:4:9
|
LL | Ok(b)
- | ^^ cannot infer type for type parameter `E` declared on the enum `Result`
+ | ^^ cannot infer type of the type parameter `E` declared on the enum `Result`
|
-help: give this closure an explicit return type without `_` placeholders
+help: consider specifying the generic arguments
|
-LL | let x = |a: (), b: ()| -> Result<(), _> {
- | ++++++++++++++++
+LL | Ok::<(), E>(b)
+ | +++++++++
error: aborting due to previous error
fn main() {
let x = || -> Result<_, QualifiedError<_>> {
- infallible()?; //~ ERROR type annotations needed
+ //~^ ERROR type annotations needed for `Result<(), QualifiedError<_>>`
+ infallible()?;
Ok(())
};
}
-error[E0282]: type annotations needed for the closure `fn() -> Result<(), QualifiedError<_>>`
- --> $DIR/cannot-infer-partial-try-return.rs:19:9
+error[E0282]: type annotations needed for `Result<(), QualifiedError<_>>`
+ --> $DIR/cannot-infer-partial-try-return.rs:18:13
|
-LL | infallible()?;
- | ^^^^^^^^^^^^^ cannot infer type
+LL | let x = || -> Result<_, QualifiedError<_>> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-help: give this closure an explicit return type without `_` placeholders
+help: try giving this closure an explicit return type
|
LL | let x = || -> Result<(), QualifiedError<_>> {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error[E0283]: type annotations needed for `Foo<i32, &str, W, Z>`
- --> $DIR/erase-type-params-in-label.rs:2:15
+ --> $DIR/erase-type-params-in-label.rs:2:9
|
LL | let foo = foo(1, "");
- | --- ^^^ cannot infer type for type parameter `W` declared on the function `foo`
- | |
- | consider giving `foo` the explicit type `Foo<_, _, W, Z>`, where the type parameter `W` is specified
+ | ^^^
|
-help: type parameter declared here
- --> $DIR/erase-type-params-in-label.rs:25:14
- |
-LL | fn foo<T, K, W: Default, Z: Default>(t: T, k: K) -> Foo<T, K, W, Z> {
- | ^
= note: cannot satisfy `_: Default`
note: required by a bound in `foo`
--> $DIR/erase-type-params-in-label.rs:25:17
|
LL | fn foo<T, K, W: Default, Z: Default>(t: T, k: K) -> Foo<T, K, W, Z> {
| ^^^^^^^ required by this bound in `foo`
+help: consider giving `foo` an explicit type, where the type for type parameter `W` is specified
+ |
+LL | let foo: Foo<i32, &str, W, Z> = foo(1, "");
+ | ++++++++++++++++++++++
help: consider specifying the type arguments in the function call
|
LL | let foo = foo::<T, K, W, Z>(1, "");
| ++++++++++++++
error[E0283]: type annotations needed for `Bar<i32, &str, Z>`
- --> $DIR/erase-type-params-in-label.rs:5:15
+ --> $DIR/erase-type-params-in-label.rs:5:9
|
LL | let bar = bar(1, "");
- | --- ^^^ cannot infer type for type parameter `Z` declared on the function `bar`
- | |
- | consider giving `bar` the explicit type `Bar<_, _, Z>`, where the type parameter `Z` is specified
+ | ^^^
|
-help: type parameter declared here
- --> $DIR/erase-type-params-in-label.rs:14:14
- |
-LL | fn bar<T, K, Z: Default>(t: T, k: K) -> Bar<T, K, Z> {
- | ^
= note: cannot satisfy `_: Default`
note: required by a bound in `bar`
--> $DIR/erase-type-params-in-label.rs:14:17
|
LL | fn bar<T, K, Z: Default>(t: T, k: K) -> Bar<T, K, Z> {
| ^^^^^^^ required by this bound in `bar`
+help: consider giving `bar` an explicit type, where the type for type parameter `Z` is specified
+ |
+LL | let bar: Bar<i32, &str, Z> = bar(1, "");
+ | +++++++++++++++++++
help: consider specifying the type arguments in the function call
|
LL | let bar = bar::<T, K, Z>(1, "");
--> $DIR/issue-71732.rs:18:10
|
LL | .get(&"key".into())
- | ^^^ ------------ this method call resolves to `T`
- | |
- | cannot infer type for type parameter `Q` declared on the associated function `get`
+ | ^^^ cannot infer type of the type parameter `Q` declared on the associated function `get`
|
= note: multiple `impl`s satisfying `String: Borrow<_>` found in the following crates: `alloc`, `core`:
- impl Borrow<str> for String;
|
LL | K: Borrow<Q>,
| ^^^^^^^^^ required by this bound in `HashMap::<K, V, S>::get`
+help: consider specifying the generic argument
+ |
+LL | .get::<Q>(&"key".into())
+ | +++++
help: consider specifying the type argument in the function call
|
LL | .get::<Q>(&"key".into())
error[E0283]: type annotations needed
- --> $DIR/issue-72616.rs:20:30
+ --> $DIR/issue-72616.rs:20:37
|
LL | if String::from("a") == "a".try_into().unwrap() {}
- | ^^ -------------- this method call resolves to `Result<T, <Self as TryInto<T>>::Error>`
- | |
- | cannot infer type
+ | ^^^^^^^^
|
= note: multiple `impl`s satisfying `String: PartialEq<_>` found in the `alloc` crate:
- impl PartialEq for String;
- impl<'a, 'b> PartialEq<&'a str> for String;
- impl<'a, 'b> PartialEq<Cow<'a, str>> for String;
- impl<'a, 'b> PartialEq<str> for String;
+help: try using a fully qualified path to specify the expected types
+ |
+LL | if String::from("a") == <&str as TryInto<T>>::try_into("a").unwrap() {}
+ | +++++++++++++++++++++++++++++++ ~
error: aborting due to previous error
error[E0282]: type annotations needed for `[usize; _]`
- --> $DIR/issue-83606.rs:8:13
+ --> $DIR/issue-83606.rs:8:9
|
LL | let _ = foo("foo"); //<- Do not suggest `foo::<N>("foo");`!
- | - ^^^ cannot infer the value of const parameter `N` declared on the function `foo`
- | |
- | consider giving this pattern the explicit type `[_; N]`, where the const parameter `N` is specified
+ | ^
+ |
+help: consider giving this pattern a type, where the the value of const parameter `N` is specified
+ |
+LL | let _: [usize; _] = foo("foo"); //<- Do not suggest `foo::<N>("foo");`!
+ | ++++++++++++
error: aborting due to previous error
error[E0283]: type annotations needed
- --> $DIR/issue-86162-1.rs:7:5
+ --> $DIR/issue-86162-1.rs:7:9
|
LL | foo(gen()); //<- Do not suggest `foo::<impl Clone>()`!
- | ^^^ cannot infer type for type parameter `impl Clone` declared on the function `foo`
+ | ^^^ cannot infer type of the type parameter `T` declared on the function `gen`
|
-help: type parameter declared here
- --> $DIR/issue-86162-1.rs:3:11
- |
-LL | fn foo(x: impl Clone) {}
- | ^^^^^^^^^^
= note: cannot satisfy `_: Clone`
note: required by a bound in `foo`
--> $DIR/issue-86162-1.rs:3:16
|
LL | fn foo(x: impl Clone) {}
| ^^^^^ required by this bound in `foo`
+help: consider specifying the generic argument
+ |
+LL | foo(gen::<T>()); //<- Do not suggest `foo::<impl Clone>()`!
+ | +++++
error: aborting due to previous error
error[E0283]: type annotations needed
- --> $DIR/issue-86162-2.rs:12:5
+ --> $DIR/issue-86162-2.rs:12:14
|
LL | Foo::bar(gen()); //<- Do not suggest `Foo::bar::<impl Clone>()`!
- | ^^^^^^^^ cannot infer type for type parameter `impl Clone` declared on the associated function `bar`
+ | ^^^ cannot infer type of the type parameter `T` declared on the function `gen`
|
-help: type parameter declared here
- --> $DIR/issue-86162-2.rs:8:15
- |
-LL | fn bar(x: impl Clone) {}
- | ^^^^^^^^^^
= note: cannot satisfy `_: Clone`
note: required by a bound in `Foo::bar`
--> $DIR/issue-86162-2.rs:8:20
|
LL | fn bar(x: impl Clone) {}
| ^^^^^ required by this bound in `Foo::bar`
+help: consider specifying the generic argument
+ |
+LL | Foo::bar(gen::<T>()); //<- Do not suggest `Foo::bar::<impl Clone>()`!
+ | +++++
error: aborting due to previous error
+++ /dev/null
-fn main() {
- match Some(10) {
- //~^ NOTE `match` arms have incompatible types
- Some(5) => false,
- //~^ NOTE this is found to be of type `bool`
- Some(2) => true,
- //~^ NOTE this is found to be of type `bool`
- None => (),
- //~^ ERROR `match` arms have incompatible types
- //~| NOTE expected `bool`, found `()`
- _ => true
- }
-}
+++ /dev/null
-error[E0308]: `match` arms have incompatible types
- --> $DIR/issue-11319.rs:8:20
- |
-LL | / match Some(10) {
-LL | |
-LL | | Some(5) => false,
- | | ----- this is found to be of type `bool`
-LL | |
-LL | | Some(2) => true,
- | | ---- this is found to be of type `bool`
-LL | |
-LL | | None => (),
- | | ^^ expected `bool`, found `()`
-... |
-LL | | _ => true
-LL | | }
- | |_____- `match` arms have incompatible types
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
error[E0282]: type annotations needed for `&T`
- --> $DIR/issue-12187-1.rs:6:10
+ --> $DIR/issue-12187-1.rs:6:9
|
LL | let &v = new();
- | -^
- | ||
- | |cannot infer type
- | consider giving this pattern the explicit type `&T`, with the type parameters specified
+ | ^^
+ |
+help: consider giving this pattern a type, where the placeholders `_` are specified
+ |
+LL | let &v: &T = new();
+ | ++++
error: aborting due to previous error
error[E0282]: type annotations needed for `&T`
- --> $DIR/issue-12187-2.rs:6:10
+ --> $DIR/issue-12187-2.rs:6:9
|
LL | let &v = new();
- | -^
- | ||
- | |cannot infer type
- | consider giving this pattern the explicit type `&T`, with the type parameters specified
+ | ^^
+ |
+help: consider giving this pattern a type, where the placeholders `_` are specified
+ |
+LL | let &v: &T = new();
+ | ++++
error: aborting due to previous error
+++ /dev/null
-trait FromStructReader<'a> { }
-trait ResponseHook {
- fn get(&self);
-}
-fn foo(res : Box<dyn ResponseHook>) { res.get } //~ ERROR attempted to take value of method
-fn main() {}
+++ /dev/null
-error[E0615]: attempted to take value of method `get` on type `Box<(dyn ResponseHook + 'static)>`
- --> $DIR/issue-13853-2.rs:5:43
- |
-LL | fn foo(res : Box<dyn ResponseHook>) { res.get }
- | ^^^ method, not a field
- |
-help: use parentheses to call the method
- |
-LL | fn foo(res : Box<dyn ResponseHook>) { res.get() }
- | ++
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0615`.
+++ /dev/null
-trait Deserializer<'a> { }
-
-trait Deserializable {
- fn deserialize_token<'a, D: Deserializer<'a>>(_: D, _: &'a str) -> Self;
-}
-
-impl<'a, T: Deserializable> Deserializable for &'a str {
- //~^ ERROR type parameter `T` is not constrained
- fn deserialize_token<D: Deserializer<'a>>(_x: D, _y: &'a str) -> &'a str {
- }
-}
-
-fn main() {}
+++ /dev/null
-error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
- --> $DIR/issue-13853-5.rs:7:10
- |
-LL | impl<'a, T: Deserializable> Deserializable for &'a str {
- | ^ unconstrained type parameter
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0207`.
+++ /dev/null
-trait Node {
- fn zomg();
-}
-
-trait Graph<N: Node> {
- fn nodes<'a, I: Iterator<Item=&'a N>>(&'a self) -> I
- where N: 'a;
-}
-
-impl<N: Node> Graph<N> for Vec<N> {
- fn nodes<'a, I: Iterator<Item=&'a N>>(&self) -> I
- where N: 'a
- {
- self.iter() //~ ERROR mismatched types
- }
-}
-
-struct Stuff;
-
-impl Node for Stuff {
- fn zomg() {
- println!("zomg");
- }
-}
-
-fn iterate<N: Node, G: Graph<N>>(graph: &G) {
- for node in graph.iter() { //~ ERROR no method named `iter` found
- node.zomg();
- }
-}
-
-pub fn main() {
- let graph = Vec::new();
-
- graph.push(Stuff);
-
- iterate(graph); //~ ERROR mismatched types
-}
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/issue-13853.rs:14:9
- |
-LL | fn nodes<'a, I: Iterator<Item=&'a N>>(&self) -> I
- | - this type parameter - expected `I` because of return type
-...
-LL | self.iter()
- | ^^^^^^^^^^^ expected type parameter `I`, found struct `std::slice::Iter`
- |
- = note: expected type parameter `I`
- found struct `std::slice::Iter<'_, N>`
-
-error[E0599]: no method named `iter` found for reference `&G` in the current scope
- --> $DIR/issue-13853.rs:27:23
- |
-LL | for node in graph.iter() {
- | ^^^^ method not found in `&G`
-
-error[E0308]: mismatched types
- --> $DIR/issue-13853.rs:37:13
- |
-LL | iterate(graph);
- | ------- ^^^^^
- | | |
- | | expected reference, found struct `Vec`
- | | help: consider borrowing here: `&graph`
- | arguments to this function are incorrect
- |
- = note: expected reference `&_`
- found struct `Vec<Stuff>`
-note: function defined here
- --> $DIR/issue-13853.rs:26:4
- |
-LL | fn iterate<N: Node, G: Graph<N>>(graph: &G) {
- | ^^^^^^^ ---------
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0308, E0599.
-For more information about an error, try `rustc --explain E0308`.
+++ /dev/null
-// check-pass
-// pretty-expanded FIXME #23616
-
-pub type BigRat<T = isize> = T;
-
-fn main() {}
+++ /dev/null
-// run-pass
-// pretty-expanded FIXME #23616
-
-#![feature(fn_traits, unboxed_closures)]
-
-trait Foo { fn dummy(&self) { }}
-
-struct Bar;
-
-impl<'a> std::ops::Fn<(&'a (dyn Foo+'a),)> for Bar {
- extern "rust-call" fn call(&self, _: (&'a dyn Foo,)) {}
-}
-
-impl<'a> std::ops::FnMut<(&'a (dyn Foo+'a),)> for Bar {
- extern "rust-call" fn call_mut(&mut self, a: (&'a dyn Foo,)) { self.call(a) }
-}
-
-impl<'a> std::ops::FnOnce<(&'a (dyn Foo+'a),)> for Bar {
- type Output = ();
- extern "rust-call" fn call_once(self, a: (&'a dyn Foo,)) { self.call(a) }
-}
-
-struct Baz;
-
-impl Foo for Baz {}
-
-fn main() {
- let bar = Bar;
- let baz = &Baz;
- bar(baz);
-}
--> $DIR/issue-16966.rs:2:5
|
LL | panic!(std::default::Default::default());
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `M` declared on the function `begin_panic`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `M` declared on the function `begin_panic`
|
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider specifying the generic argument
+ --> $SRC_DIR/std/src/panic.rs:LL:COL
+ |
+LL | $crate::rt::begin_panic::<M>($msg)
+ | +++++
error: aborting due to previous error
error[E0282]: type annotations needed for `B<T>`
- --> $DIR/issue-17551.rs:6:15
+ --> $DIR/issue-17551.rs:6:9
|
LL | let foo = B(marker::PhantomData);
- | --- ^ cannot infer type for type parameter `T` declared on the struct `B`
- | |
- | consider giving `foo` the explicit type `B<T>`, where the type parameter `T` is specified
+ | ^^^
+ |
+help: consider giving `foo` an explicit type, where the type for type parameter `T` is specified
+ |
+LL | let foo: B<T> = B(marker::PhantomData);
+ | ++++++
error: aborting due to previous error
|
LL | fn say(self: &Pair<&str, isize>) {
| ^^^^
-note: ...does not necessarily outlive the lifetime `'_` as defined here
+note: ...does not necessarily outlive the anonymous lifetime as defined here
--> $DIR/issue-17905-2.rs:5:5
|
LL | &str,
|
= note: expected struct `Pair<&str, _>`
found struct `Pair<&str, _>`
-note: the lifetime `'_` as defined here...
+note: the anonymous lifetime as defined here...
--> $DIR/issue-17905-2.rs:5:5
|
LL | &str,
--> $DIR/issue-18159.rs:2:9
|
LL | let x;
- | ^ consider giving `x` a type
+ | ^
+ |
+help: consider giving `x` an explicit type
+ |
+LL | let x: _;
+ | +++
error: aborting due to previous error
-error[E0282]: type annotations needed for `(_,)`
+error[E0282]: type annotations needed
--> $DIR/issue-20261.rs:4:11
|
-LL | for (ref i,) in [].iter() {
- | --------- this method call resolves to `std::slice::Iter<'_, T>`
LL | i.clone();
| ^^^^^ cannot infer type
|
fn main() {
- let x = panic!();
- x.clone(); //~ ERROR type annotations needed
+ let x = panic!(); //~ ERROR type annotations needed
+ x.clone();
}
error[E0282]: type annotations needed
- --> $DIR/issue-2151.rs:3:5
+ --> $DIR/issue-2151.rs:2:9
|
LL | let x = panic!();
- | - consider giving `x` a type
-LL | x.clone();
- | ^ cannot infer type
+ | ^
|
= note: type must be known at this point
+help: consider giving `x` an explicit type
+ |
+LL | let x: _ = panic!();
+ | +++
error: aborting due to previous error
fn is_copy<T: ::std::marker<i32>::Copy>() {}
-//~^ ERROR type arguments are not allowed for this type [E0109]
+//~^ ERROR type arguments are not allowed on module `marker` [E0109]
fn main() {}
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on module `marker`
--> $DIR/issue-22706.rs:1:29
|
LL | fn is_copy<T: ::std::marker<i32>::Copy>() {}
- | ^^^ type argument not allowed
+ | ------ ^^^ type argument not allowed
+ | |
+ | not allowed on this
error: aborting due to previous error
--> $DIR/issue-23046.rs:17:15
|
LL | let ex = |x| {
- | ^ consider giving this closure parameter the explicit type `Expr<'_, VAR>`, where the type parameter `VAR` is specified
+ | ^
+ |
+help: consider giving this closure parameter an explicit type, where the type for type parameter `VAR` is specified
+ |
+LL | let ex = |x: Expr<'_, VAR>| {
+ | +++++++++++++++
error: aborting due to previous error
--> $DIR/issue-24036.rs:9:15
|
LL | 1 => |c| c + 1,
- | ^ consider giving this closure parameter a type
+ | ^
+ |
+help: consider giving this closure parameter an explicit type
+ |
+LL | 1 => |c: _| c + 1,
+ | +++
error: aborting due to 2 previous errors
struct Foo<T> {foo: PhantomData<T>}
fn main() {
- let (tx, rx) = channel();
-
+ let (tx, rx) = //~ ERROR type annotations needed
+ channel();
+ // FIXME(#89862): Suggest adding a generic argument to `channel` instead
spawn(move || {
- tx.send(Foo{ foo: PhantomData }); //~ ERROR E0282
+ tx.send(Foo{ foo: PhantomData });
});
}
error[E0282]: type annotations needed for `(Sender<Foo<T>>, std::sync::mpsc::Receiver<Foo<T>>)`
- --> $DIR/issue-25368.rs:11:17
+ --> $DIR/issue-25368.rs:8:9
|
-LL | let (tx, rx) = channel();
- | -------- consider giving this pattern the explicit type `(Sender<Foo<T>>, std::sync::mpsc::Receiver<Foo<T>>)`, where the type parameter `T` is specified
-...
-LL | tx.send(Foo{ foo: PhantomData });
- | ^^^ cannot infer type for type parameter `T` declared on the struct `Foo`
+LL | let (tx, rx) =
+ | ^^^^^^^^
+ |
+help: consider giving this pattern a type, where the type for type parameter `T` is specified
+ |
+LL | let (tx, rx): (Sender<Foo<T>>, std::sync::mpsc::Receiver<Foo<T>>) =
+ | +++++++++++++++++++++++++++++++++++++++++++++++++++++
error: aborting due to previous error
+++ /dev/null
-// run-pass
-#![allow(dead_code)]
-#![allow(unused_imports)]
-#![allow(non_snake_case)]
-
-// ignore-pretty issue #37195
-
-#[path = "issue-26873-multifile/mod.rs"]
-mod multifile;
-
-fn main() {}
+++ /dev/null
-// run-pass
-use super::*;
-
-pub struct S;
+++ /dev/null
-// run-pass
-use super::*;
-
-use super::B::S;
-
-pub struct T { i: i32 }
+++ /dev/null
-// run-pass
-pub mod B;
-pub mod C;
-
-pub use self::C::T;
+++ /dev/null
-// run-pass
-mod A;
-
-use self::A::*;
+++ /dev/null
-fn main() {
- let _ = Iterator::next(&mut ());
- //~^ ERROR `()` is not an iterator
- //~| ERROR `()` is not an iterator
-
- for _ in false {}
- //~^ ERROR `bool` is not an iterator
-
- let _ = Iterator::next(&mut ());
- //~^ ERROR `()` is not an iterator
-
- other()
-}
-
-pub fn other() {
- // check errors are still reported globally
-
- let _ = Iterator::next(&mut ());
- //~^ ERROR `()` is not an iterator
- //~| ERROR `()` is not an iterator
-
- let _ = Iterator::next(&mut ());
- //~^ ERROR `()` is not an iterator
-
- for _ in false {}
- //~^ ERROR `bool` is not an iterator
-}
+++ /dev/null
-error[E0277]: `()` is not an iterator
- --> $DIR/issue-28098.rs:2:28
- |
-LL | let _ = Iterator::next(&mut ());
- | -------------- ^^^^^^^ `()` is not an iterator
- | |
- | required by a bound introduced by this call
- |
- = help: the trait `Iterator` is not implemented for `()`
-
-error[E0277]: `bool` is not an iterator
- --> $DIR/issue-28098.rs:6:14
- |
-LL | for _ in false {}
- | ^^^^^ `bool` is not an iterator
- |
- = help: the trait `Iterator` is not implemented for `bool`
- = note: required because of the requirements on the impl of `IntoIterator` for `bool`
-
-error[E0277]: `()` is not an iterator
- --> $DIR/issue-28098.rs:9:28
- |
-LL | let _ = Iterator::next(&mut ());
- | -------------- ^^^^^^^ `()` is not an iterator
- | |
- | required by a bound introduced by this call
- |
- = help: the trait `Iterator` is not implemented for `()`
-
-error[E0277]: `()` is not an iterator
- --> $DIR/issue-28098.rs:2:13
- |
-LL | let _ = Iterator::next(&mut ());
- | ^^^^^^^^^^^^^^ `()` is not an iterator
- |
- = help: the trait `Iterator` is not implemented for `()`
-
-error[E0277]: `()` is not an iterator
- --> $DIR/issue-28098.rs:18:28
- |
-LL | let _ = Iterator::next(&mut ());
- | -------------- ^^^^^^^ `()` is not an iterator
- | |
- | required by a bound introduced by this call
- |
- = help: the trait `Iterator` is not implemented for `()`
-
-error[E0277]: `()` is not an iterator
- --> $DIR/issue-28098.rs:22:28
- |
-LL | let _ = Iterator::next(&mut ());
- | -------------- ^^^^^^^ `()` is not an iterator
- | |
- | required by a bound introduced by this call
- |
- = help: the trait `Iterator` is not implemented for `()`
-
-error[E0277]: `bool` is not an iterator
- --> $DIR/issue-28098.rs:25:14
- |
-LL | for _ in false {}
- | ^^^^^ `bool` is not an iterator
- |
- = help: the trait `Iterator` is not implemented for `bool`
- = note: required because of the requirements on the impl of `IntoIterator` for `bool`
-
-error[E0277]: `()` is not an iterator
- --> $DIR/issue-28098.rs:18:13
- |
-LL | let _ = Iterator::next(&mut ());
- | ^^^^^^^^^^^^^^ `()` is not an iterator
- |
- = help: the trait `Iterator` is not implemented for `()`
-
-error: aborting due to 8 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
error[E0282]: type annotations needed
- --> $DIR/issue-47486.rs:3:31
+ --> $DIR/issue-47486.rs:3:11
|
LL | [0u8; std::mem::size_of::<_>()];
- | ^ cannot infer type
+ | ^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `size_of`
+ |
+help: consider specifying the generic argument
+ |
+LL | [0u8; std::mem::size_of::<_>()];
+ | ~~~~~
error[E0308]: mismatched types
--> $DIR/issue-47486.rs:2:10
--> $DIR/issue-5062.rs:1:29
|
LL | fn main() { format!("{:?}", None); }
- | ^^^^ cannot infer type for type parameter `T` declared on the enum `Option`
+ | ^^^^ cannot infer type of the type parameter `T` declared on the enum `Option`
+ |
+help: consider specifying the generic argument
+ |
+LL | fn main() { format!("{:?}", None::<T>); }
+ | +++++
error: aborting due to previous error
let tiles = Default::default();
for row in &mut tiles {
for tile in row {
- //~^ NOTE the element type for this iterator is not specified
*tile = 0;
//~^ ERROR type annotations needed
//~| NOTE cannot infer type
error[E0282]: type annotations needed
- --> $DIR/issue-51116.rs:6:13
+ --> $DIR/issue-51116.rs:5:13
|
-LL | for tile in row {
- | --- the element type for this iterator is not specified
-LL |
LL | *tile = 0;
| ^^^^^ cannot infer type
|
+++ /dev/null
-// check-pass
-
-pub struct GstRc {
- _obj: *const (),
- _borrowed: bool,
-}
-
-const FOO: Option<GstRc> = None;
-
-fn main() {
- let _meh = FOO;
-}
+++ /dev/null
-// issue-54966: ICE returning an unknown type with impl FnMut
-
-fn generate_duration() -> Oper<impl FnMut()> {}
-//~^ ERROR cannot find type `Oper` in this scope
-
-fn main() {}
+++ /dev/null
-error[E0412]: cannot find type `Oper` in this scope
- --> $DIR/issue-54966.rs:3:27
- |
-LL | fn generate_duration() -> Oper<impl FnMut()> {}
- | ^^^^ not found in this scope
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0412`.
impl<E> Gcm<E> {
pub fn crash(e: E) -> Self {
Self::<E>(e)
- //~^ ERROR type arguments are not allowed for this type
+ //~^ ERROR type arguments are not allowed on self constructor
}
}
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on self constructor
--> $DIR/issue-57924.rs:5:16
|
LL | Self::<E>(e)
- | ^ type argument not allowed
+ | ---- ^ type argument not allowed
+ | |
+ | not allowed on this
error: aborting due to previous error
fn main() {
let c1 = ();
c1::<()>;
- //~^ ERROR type arguments are not allowed for this type
+ //~^ ERROR type arguments are not allowed on local variable
let c1 = A {};
c1::<dyn Into<B>>;
- //~^ ERROR type arguments are not allowed for this type
+ //~^ ERROR type arguments are not allowed on local variable
}
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on local variable
--> $DIR/issue-60989.rs:12:10
|
LL | c1::<()>;
- | ^^ type argument not allowed
+ | -- ^^ type argument not allowed
+ | |
+ | not allowed on this
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on local variable
--> $DIR/issue-60989.rs:16:10
|
LL | c1::<dyn Into<B>>;
- | ^^^^^^^^^^^ type argument not allowed
+ | -- ^^^^^^^^^^^ type argument not allowed
+ | |
+ | not allowed on this
error: aborting due to 2 previous errors
--> $DIR/issue-6458-2.rs:3:21
|
LL | format!("{:?}", None);
- | ^^^^ cannot infer type for type parameter `T` declared on the enum `Option`
+ | ^^^^ cannot infer type of the type parameter `T` declared on the enum `Option`
+ |
+help: consider specifying the generic argument
+ |
+LL | format!("{:?}", None::<T>);
+ | +++++
error: aborting due to previous error
--> $DIR/issue-6458-3.rs:4:5
|
LL | mem::transmute(0);
- | ^^^^^^^^^^^^^^ cannot infer type for type parameter `U` declared on the function `transmute`
+ | ^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `transmute`
+ |
+help: consider specifying the generic arguments
+ |
+LL | mem::transmute::<i32, U>(0);
+ | ++++++++++
error: aborting due to previous error
error[E0282]: type annotations needed
- --> $DIR/issue-6458.rs:9:4
+ --> $DIR/issue-6458.rs:9:22
|
LL | foo(TypeWithState(marker::PhantomData));
- | ^^^ cannot infer type for type parameter `State` declared on the function `foo`
+ | ^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `PhantomData`
|
-help: type parameter declared here
- --> $DIR/issue-6458.rs:6:12
+help: consider specifying the generic argument
|
-LL | pub fn foo<State>(_: TypeWithState<State>) {}
- | ^^^^^
+LL | foo(TypeWithState(marker::PhantomData::<T>));
+ | +++++
error: aborting due to previous error
|
= note: expected trait `<&dyn T2 as T0>`
found trait `<&(dyn T2 + 'static) as T0>`
-note: the lifetime `'_` as defined here...
+note: the anonymous lifetime as defined here...
--> $DIR/issue-65230.rs:8:13
|
LL | impl T1 for &dyn T2 {}
--> $DIR/issue-66706.rs:2:11
|
LL | [0; [|_: _ &_| ()].len()]
- | ^ consider giving this closure parameter a type
+ | ^ cannot infer type
error[E0308]: mismatched types
--> $DIR/issue-66706.rs:2:5
+++ /dev/null
-macro_rules! x {
- ($($c:tt)*) => {
- $($c)ö* {} //~ ERROR missing condition for `if` expression
- }; //~| ERROR mismatched types
-}
-
-fn main() {
- x!(if);
-}
+++ /dev/null
-error: missing condition for `if` expression
- --> $DIR/issue-68091-unicode-ident-after-if.rs:3:14
- |
-LL | $($c)ö* {}
- | ^ expected if condition here
-
-error[E0308]: mismatched types
- --> $DIR/issue-68091-unicode-ident-after-if.rs:3:17
- |
-LL | $($c)ö* {}
- | ^^ expected `bool`, found `()`
-...
-LL | x!(if);
- | ------ in this macro invocation
- |
- = note: this error originates in the macro `x` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
+++ /dev/null
-macro_rules! x {
- ($($c:tt)*) => {
- $($c)ö* //~ ERROR macro expansion ends with an incomplete expression: expected expression
- };
-}
-
-fn main() {
- x!(!);
-}
+++ /dev/null
-error: macro expansion ends with an incomplete expression: expected expression
- --> $DIR/issue-68092-unicode-ident-after-incomplete-expr.rs:3:14
- |
-LL | $($c)ö*
- | ^ expected expression
-
-error: aborting due to previous error
-
error[E0282]: type annotations needed
--> $DIR/issue-69455.rs:29:20
|
-LL | type Output;
- | ------------ `<Self as Test<Rhs>>::Output` defined here
-...
LL | println!("{}", 23u64.test(xs.iter().sum()));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
- | |
- | this method call resolves to `<Self as Test<Rhs>>::Output`
- | cannot infer type for type parameter `T` declared on the associated function `new_display`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the associated function `new_display`
|
= note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider specifying the generic argument
+ |
+LL | println!("{}", 23u64.test(xs.iter().sum())::<T>);
+ | +++++
error[E0283]: type annotations needed
- --> $DIR/issue-69455.rs:29:26
+ --> $DIR/issue-69455.rs:29:41
|
LL | println!("{}", 23u64.test(xs.iter().sum()));
- | ^^^^ cannot infer type for type parameter `Rhs` declared on the trait `Test`
+ | ^^^ cannot infer type of the type parameter `S` declared on the associated function `sum`
|
note: multiple `impl`s satisfying `u64: Test<_>` found
--> $DIR/issue-69455.rs:11:1
...
LL | impl Test<u64> for u64 {
| ^^^^^^^^^^^^^^^^^^^^^^
-help: consider specifying the type argument in the method call
+help: consider specifying the generic argument
|
LL | println!("{}", 23u64.test(xs.iter().sum::<S>()));
| +++++
--> $DIR/issue-69683.rs:30:10
|
LL | 0u16.foo(b);
- | ^^^ cannot infer type for type parameter `I` declared on the trait `Foo`
+ | ^^^
|
note: multiple `impl`s satisfying `u8: Element<_>` found
--> $DIR/issue-69683.rs:5:1
LL | {
LL | fn foo(self, x: <u8 as Element<I>>::Array);
| --- required by a bound in this
+help: try using a fully qualified path to specify the expected types
+ |
+LL | <u16 as Foo<I>>::foo(0u16, b);
+ | +++++++++++++++++++++ ~
error: aborting due to 2 previous errors
|
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
help: you might have forgotten to call this function
+ --> $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
LL | if !(*left_val() == *right_val) {
| ++
--> $DIR/issue-72690.rs:7:22
|
LL | String::from("x".as_ref());
- | ----^^^^^^--
- | | |
- | | cannot infer type for type parameter `T` declared on the trait `AsRef`
- | this method call resolves to `&T`
+ | ^^^^^^
|
= note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
- impl AsRef<OsStr> for str;
- impl AsRef<Path> for str;
- impl AsRef<[u8]> for str;
- impl AsRef<str> for str;
+help: try using a fully qualified path to specify the expected types
+ |
+LL | String::from(<str as AsRef<T>>::as_ref("x"));
+ | ++++++++++++++++++++++++++ ~
error[E0282]: type annotations needed
--> $DIR/issue-72690.rs:12:6
|
LL | |x| String::from("x".as_ref());
- | ^ consider giving this closure parameter a type
+ | ^
+ |
+help: consider giving this closure parameter an explicit type
+ |
+LL | |x: _| String::from("x".as_ref());
+ | +++
error[E0283]: type annotations needed
--> $DIR/issue-72690.rs:12:26
|
LL | |x| String::from("x".as_ref());
- | ----^^^^^^--
- | | |
- | | cannot infer type for type parameter `T` declared on the trait `AsRef`
- | this method call resolves to `&T`
+ | ^^^^^^
|
= note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
- impl AsRef<OsStr> for str;
- impl AsRef<Path> for str;
- impl AsRef<[u8]> for str;
- impl AsRef<str> for str;
+help: try using a fully qualified path to specify the expected types
+ |
+LL | |x| String::from(<str as AsRef<T>>::as_ref("x"));
+ | ++++++++++++++++++++++++++ ~
error[E0283]: type annotations needed for `&T`
- --> $DIR/issue-72690.rs:17:17
+ --> $DIR/issue-72690.rs:17:9
|
LL | let _ = "x".as_ref();
- | - ^^^^^^ cannot infer type for type parameter `T` declared on the trait `AsRef`
- | |
- | consider giving this pattern the explicit type `&T`, where the type parameter `T` is specified
+ | ^
|
= note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
- impl AsRef<OsStr> for str;
- impl AsRef<Path> for str;
- impl AsRef<[u8]> for str;
- impl AsRef<str> for str;
+help: consider giving this pattern a type, where the type for type parameter `T` is specified
+ |
+LL | let _: &T = "x".as_ref();
+ | ++++
error[E0283]: type annotations needed
--> $DIR/issue-72690.rs:21:5
--> $DIR/issue-72690.rs:21:22
|
LL | String::from("x".as_ref());
- | ----^^^^^^--
- | | |
- | | cannot infer type for type parameter `T` declared on the trait `AsRef`
- | this method call resolves to `&T`
+ | ^^^^^^
|
= note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
- impl AsRef<OsStr> for str;
- impl AsRef<Path> for str;
- impl AsRef<[u8]> for str;
- impl AsRef<str> for str;
+help: try using a fully qualified path to specify the expected types
+ |
+LL | String::from(<str as AsRef<T>>::as_ref("x"));
+ | ++++++++++++++++++++++++++ ~
error[E0283]: type annotations needed
--> $DIR/issue-72690.rs:28:5
--> $DIR/issue-72690.rs:28:22
|
LL | String::from("x".as_ref());
- | ----^^^^^^--
- | | |
- | | cannot infer type for type parameter `T` declared on the trait `AsRef`
- | this method call resolves to `&T`
+ | ^^^^^^
|
= note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
- impl AsRef<OsStr> for str;
- impl AsRef<Path> for str;
- impl AsRef<[u8]> for str;
- impl AsRef<str> for str;
+help: try using a fully qualified path to specify the expected types
+ |
+LL | String::from(<str as AsRef<T>>::as_ref("x"));
+ | ++++++++++++++++++++++++++ ~
error[E0283]: type annotations needed
--> $DIR/issue-72690.rs:37:5
--> $DIR/issue-72690.rs:37:22
|
LL | String::from("x".as_ref());
- | ----^^^^^^--
- | | |
- | | cannot infer type for type parameter `T` declared on the trait `AsRef`
- | this method call resolves to `&T`
+ | ^^^^^^
|
= note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
- impl AsRef<OsStr> for str;
- impl AsRef<Path> for str;
- impl AsRef<[u8]> for str;
- impl AsRef<str> for str;
+help: try using a fully qualified path to specify the expected types
+ |
+LL | String::from(<str as AsRef<T>>::as_ref("x"));
+ | ++++++++++++++++++++++++++ ~
error[E0283]: type annotations needed
--> $DIR/issue-72690.rs:46:5
--> $DIR/issue-72690.rs:46:22
|
LL | String::from("x".as_ref());
- | ----^^^^^^--
- | | |
- | | cannot infer type for type parameter `T` declared on the trait `AsRef`
- | this method call resolves to `&T`
+ | ^^^^^^
|
= note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
- impl AsRef<OsStr> for str;
- impl AsRef<Path> for str;
- impl AsRef<[u8]> for str;
- impl AsRef<str> for str;
+help: try using a fully qualified path to specify the expected types
+ |
+LL | String::from(<str as AsRef<T>>::as_ref("x"));
+ | ++++++++++++++++++++++++++ ~
error[E0283]: type annotations needed
--> $DIR/issue-72690.rs:53:5
--> $DIR/issue-72690.rs:53:22
|
LL | String::from("x".as_ref());
- | ----^^^^^^--
- | | |
- | | cannot infer type for type parameter `T` declared on the trait `AsRef`
- | this method call resolves to `&T`
+ | ^^^^^^
|
= note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
- impl AsRef<OsStr> for str;
- impl AsRef<Path> for str;
- impl AsRef<[u8]> for str;
- impl AsRef<str> for str;
+help: try using a fully qualified path to specify the expected types
+ |
+LL | String::from(<str as AsRef<T>>::as_ref("x"));
+ | ++++++++++++++++++++++++++ ~
error[E0283]: type annotations needed
--> $DIR/issue-72690.rs:62:5
--> $DIR/issue-72690.rs:62:22
|
LL | String::from("x".as_ref());
- | ----^^^^^^--
- | | |
- | | cannot infer type for type parameter `T` declared on the trait `AsRef`
- | this method call resolves to `&T`
+ | ^^^^^^
|
= note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
- impl AsRef<OsStr> for str;
- impl AsRef<Path> for str;
- impl AsRef<[u8]> for str;
- impl AsRef<str> for str;
+help: try using a fully qualified path to specify the expected types
+ |
+LL | String::from(<str as AsRef<T>>::as_ref("x"));
+ | ++++++++++++++++++++++++++ ~
error: aborting due to 17 previous errors
error[E0282]: type annotations needed for `&[_; 0]`
- --> $DIR/issue-7813.rs:2:13
+ --> $DIR/issue-7813.rs:2:9
|
LL | let v = &[];
- | - ^^^ cannot infer type
- | |
- | consider giving `v` the explicit type `&[_; 0]`, with the type parameters specified
+ | ^
+ |
+help: consider giving `v` an explicit type, where the placeholders `_` are specified
+ |
+LL | let v: &[_; 0] = &[];
+ | +++++++++
error: aborting due to previous error
+++ /dev/null
-// Test that duplicate methods in impls are not allowed
-
-struct Foo;
-
-trait Bar {
- fn bar(&self) -> isize;
-}
-
-impl Bar for Foo {
- fn bar(&self) -> isize {1}
- fn bar(&self) -> isize {2} //~ ERROR duplicate definitions
-}
-
-fn main() {
- println!("{}", Foo.bar());
-}
+++ /dev/null
-error[E0201]: duplicate definitions with name `bar`:
- --> $DIR/issue-8153.rs:11:5
- |
-LL | fn bar(&self) -> isize {1}
- | -------------------------- previous definition of `bar` here
-LL | fn bar(&self) -> isize {2}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definition
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0201`.
--- /dev/null
+fn main() {
+ let _ = Iterator::next(&mut ());
+ //~^ ERROR `()` is not an iterator
+ //~| ERROR `()` is not an iterator
+
+ for _ in false {}
+ //~^ ERROR `bool` is not an iterator
+
+ let _ = Iterator::next(&mut ());
+ //~^ ERROR `()` is not an iterator
+
+ other()
+}
+
+pub fn other() {
+ // check errors are still reported globally
+
+ let _ = Iterator::next(&mut ());
+ //~^ ERROR `()` is not an iterator
+ //~| ERROR `()` is not an iterator
+
+ let _ = Iterator::next(&mut ());
+ //~^ ERROR `()` is not an iterator
+
+ for _ in false {}
+ //~^ ERROR `bool` is not an iterator
+}
--- /dev/null
+error[E0277]: `()` is not an iterator
+ --> $DIR/issue-28098.rs:2:28
+ |
+LL | let _ = Iterator::next(&mut ());
+ | -------------- ^^^^^^^ `()` is not an iterator
+ | |
+ | required by a bound introduced by this call
+ |
+ = help: the trait `Iterator` is not implemented for `()`
+
+error[E0277]: `bool` is not an iterator
+ --> $DIR/issue-28098.rs:6:14
+ |
+LL | for _ in false {}
+ | ^^^^^ `bool` is not an iterator
+ |
+ = help: the trait `Iterator` is not implemented for `bool`
+ = note: required because of the requirements on the impl of `IntoIterator` for `bool`
+
+error[E0277]: `()` is not an iterator
+ --> $DIR/issue-28098.rs:9:28
+ |
+LL | let _ = Iterator::next(&mut ());
+ | -------------- ^^^^^^^ `()` is not an iterator
+ | |
+ | required by a bound introduced by this call
+ |
+ = help: the trait `Iterator` is not implemented for `()`
+
+error[E0277]: `()` is not an iterator
+ --> $DIR/issue-28098.rs:2:13
+ |
+LL | let _ = Iterator::next(&mut ());
+ | ^^^^^^^^^^^^^^ `()` is not an iterator
+ |
+ = help: the trait `Iterator` is not implemented for `()`
+
+error[E0277]: `()` is not an iterator
+ --> $DIR/issue-28098.rs:18:28
+ |
+LL | let _ = Iterator::next(&mut ());
+ | -------------- ^^^^^^^ `()` is not an iterator
+ | |
+ | required by a bound introduced by this call
+ |
+ = help: the trait `Iterator` is not implemented for `()`
+
+error[E0277]: `()` is not an iterator
+ --> $DIR/issue-28098.rs:22:28
+ |
+LL | let _ = Iterator::next(&mut ());
+ | -------------- ^^^^^^^ `()` is not an iterator
+ | |
+ | required by a bound introduced by this call
+ |
+ = help: the trait `Iterator` is not implemented for `()`
+
+error[E0277]: `bool` is not an iterator
+ --> $DIR/issue-28098.rs:25:14
+ |
+LL | for _ in false {}
+ | ^^^^^ `bool` is not an iterator
+ |
+ = help: the trait `Iterator` is not implemented for `bool`
+ = note: required because of the requirements on the impl of `IntoIterator` for `bool`
+
+error[E0277]: `()` is not an iterator
+ --> $DIR/issue-28098.rs:18:13
+ |
+LL | let _ = Iterator::next(&mut ());
+ | ^^^^^^^^^^^^^^ `()` is not an iterator
+ |
+ = help: the trait `Iterator` is not implemented for `()`
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
|
LL | use extern::foo;
| ^^^^^^ maybe a missing crate `r#extern`?
+ |
+ = help: consider adding `extern crate r#extern` to use the `r#extern` crate
error: aborting due to 2 previous errors
|
LL | #![deny(dead_code)]
| ^^^^^^^^^
-note: `Enum` has a derived impl for the trait `Clone`, but this is intentionally ignored during dead code analysis
- --> $DIR/unused-variant.rs:3:10
- |
-LL | #[derive(Clone)]
- | ^^^^^
- = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: `Enum` has a derived impl for the trait `Clone`, but this is intentionally ignored during dead code analysis
error: aborting due to previous error
--- /dev/null
+// check-pass
+#![feature(lint_reasons)]
+
+#[warn(unused_variables)]
+
+/// This should catch the unused_variables lint and not emit anything
+fn check_fulfilled_expectation(#[expect(unused_variables)] unused_value: u32) {}
+
+fn check_unfulfilled_expectation(#[expect(unused_variables)] used_value: u32) {
+ //~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+ //~| NOTE `#[warn(unfulfilled_lint_expectations)]` on by default
+ println!("I use the value {used_value}");
+}
+
+fn main() {}
--- /dev/null
+warning: this lint expectation is unfulfilled
+ --> $DIR/expect_on_fn_params.rs:9:43
+ |
+LL | fn check_unfulfilled_expectation(#[expect(unused_variables)] used_value: u32) {
+ | ^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(unfulfilled_lint_expectations)]` on by default
+
+warning: 1 warning emitted
+
+warning: label name `'many_used_shadowed` shadows a label name that is already in scope
+ --> $DIR/unused_labels.rs:62:9
+ |
+LL | 'many_used_shadowed: for _ in 0..10 {
+ | ------------------- first declared here
+LL |
+LL | 'many_used_shadowed: for _ in 0..10 {
+ | ^^^^^^^^^^^^^^^^^^^ label `'many_used_shadowed` already in scope
+
warning: unused label
--> $DIR/unused_labels.rs:11:5
|
LL | 'unused_block_label: {
| ^^^^^^^^^^^^^^^^^^^
-warning: label name `'many_used_shadowed` shadows a label name that is already in scope
- --> $DIR/unused_labels.rs:62:9
- |
-LL | 'many_used_shadowed: for _ in 0..10 {
- | ------------------- first declared here
-LL |
-LL | 'many_used_shadowed: for _ in 0..10 {
- | ^^^^^^^^^^^^^^^^^^^ label `'many_used_shadowed` already in scope
-
warning: 9 warnings emitted
+++ /dev/null
-// check-pass
-#![feature(label_break_value)]
-
-// Issue #21633: reject duplicate loop labels and block labels in function bodies.
-//
-// This is testing the generalization (to the whole function body)
-// discussed here:
-// https://internals.rust-lang.org/t/psa-rejecting-duplicate-loop-labels/1833
-
-#[allow(unused_labels)]
-pub fn foo() {
- { 'fl: for _ in 0..10 { break; } }
- { 'fl: loop { break; } } //~ WARN label name `'fl` shadows a label name that is already in scope
- { 'lf: loop { break; } }
- { 'lf: for _ in 0..10 { break; } } //~ WARN label name `'lf` shadows a label name that is already in scope
- { 'wl: while 2 > 1 { break; } }
- { 'wl: loop { break; } } //~ WARN label name `'wl` shadows a label name that is already in scope
- { 'lw: loop { break; } }
- { 'lw: while 2 > 1 { break; } } //~ WARN label name `'lw` shadows a label name that is already in scope
- { 'fw: for _ in 0..10 { break; } }
- { 'fw: while 2 > 1 { break; } } //~ WARN label name `'fw` shadows a label name that is already in scope
- { 'wf: while 2 > 1 { break; } }
- { 'wf: for _ in 0..10 { break; } } //~ WARN label name `'wf` shadows a label name that is already in scope
- { 'tl: while let Some(_) = None::<i32> { break; } }
- { 'tl: loop { break; } } //~ WARN label name `'tl` shadows a label name that is already in scope
- { 'lt: loop { break; } }
- { 'lt: while let Some(_) = None::<i32> { break; } }
- //~^ WARN label name `'lt` shadows a label name that is already in scope
- { 'bl: {} }
- { 'bl: {} } //~ WARN label name `'bl` shadows a label name that is already in scope
-}
-
-
-pub fn main() {
- foo();
-}
+++ /dev/null
-warning: label name `'fl` shadows a label name that is already in scope
- --> $DIR/loops-reject-duplicate-labels-2.rs:13:7
- |
-LL | { 'fl: for _ in 0..10 { break; } }
- | --- first declared here
-LL | { 'fl: loop { break; } }
- | ^^^ label `'fl` already in scope
-
-warning: label name `'lf` shadows a label name that is already in scope
- --> $DIR/loops-reject-duplicate-labels-2.rs:15:7
- |
-LL | { 'lf: loop { break; } }
- | --- first declared here
-LL | { 'lf: for _ in 0..10 { break; } }
- | ^^^ label `'lf` already in scope
-
-warning: label name `'wl` shadows a label name that is already in scope
- --> $DIR/loops-reject-duplicate-labels-2.rs:17:7
- |
-LL | { 'wl: while 2 > 1 { break; } }
- | --- first declared here
-LL | { 'wl: loop { break; } }
- | ^^^ label `'wl` already in scope
-
-warning: label name `'lw` shadows a label name that is already in scope
- --> $DIR/loops-reject-duplicate-labels-2.rs:19:7
- |
-LL | { 'lw: loop { break; } }
- | --- first declared here
-LL | { 'lw: while 2 > 1 { break; } }
- | ^^^ label `'lw` already in scope
-
-warning: label name `'fw` shadows a label name that is already in scope
- --> $DIR/loops-reject-duplicate-labels-2.rs:21:7
- |
-LL | { 'fw: for _ in 0..10 { break; } }
- | --- first declared here
-LL | { 'fw: while 2 > 1 { break; } }
- | ^^^ label `'fw` already in scope
-
-warning: label name `'wf` shadows a label name that is already in scope
- --> $DIR/loops-reject-duplicate-labels-2.rs:23:7
- |
-LL | { 'wf: while 2 > 1 { break; } }
- | --- first declared here
-LL | { 'wf: for _ in 0..10 { break; } }
- | ^^^ label `'wf` already in scope
-
-warning: label name `'tl` shadows a label name that is already in scope
- --> $DIR/loops-reject-duplicate-labels-2.rs:25:7
- |
-LL | { 'tl: while let Some(_) = None::<i32> { break; } }
- | --- first declared here
-LL | { 'tl: loop { break; } }
- | ^^^ label `'tl` already in scope
-
-warning: label name `'lt` shadows a label name that is already in scope
- --> $DIR/loops-reject-duplicate-labels-2.rs:27:7
- |
-LL | { 'lt: loop { break; } }
- | --- first declared here
-LL | { 'lt: while let Some(_) = None::<i32> { break; } }
- | ^^^ label `'lt` already in scope
-
-warning: label name `'bl` shadows a label name that is already in scope
- --> $DIR/loops-reject-duplicate-labels-2.rs:30:7
- |
-LL | { 'bl: {} }
- | --- first declared here
-LL | { 'bl: {} }
- | ^^^ label `'bl` already in scope
-
-warning: 9 warnings emitted
-
+++ /dev/null
-// check-pass
-#![feature(label_break_value)]
-
-// Issue #21633: reject duplicate loop labels and block labels in function bodies.
-
-#[allow(unused_labels)]
-fn foo() {
- 'fl: for _ in 0..10 { break; }
- 'fl: loop { break; } //~ WARN label name `'fl` shadows a label name that is already in scope
-
- 'lf: loop { break; }
- 'lf: for _ in 0..10 { break; } //~ WARN label name `'lf` shadows a label name that is already in scope
- 'wl: while 2 > 1 { break; }
- 'wl: loop { break; } //~ WARN label name `'wl` shadows a label name that is already in scope
- 'lw: loop { break; }
- 'lw: while 2 > 1 { break; } //~ WARN label name `'lw` shadows a label name that is already in scope
- 'fw: for _ in 0..10 { break; }
- 'fw: while 2 > 1 { break; } //~ WARN label name `'fw` shadows a label name that is already in scope
- 'wf: while 2 > 1 { break; }
- 'wf: for _ in 0..10 { break; } //~ WARN label name `'wf` shadows a label name that is already in scope
- 'tl: while let Some(_) = None::<i32> { break; }
- 'tl: loop { break; } //~ WARN label name `'tl` shadows a label name that is already in scope
- 'lt: loop { break; }
- 'lt: while let Some(_) = None::<i32> { break; }
- //~^ WARN label name `'lt` shadows a label name that is already in scope
- 'bl: {}
- 'bl: {} //~ WARN label name `'bl` shadows a label name that is already in scope
-}
-
-// Note however that it is okay for the same label to be reused in
-// different methods of one impl, as illustrated here.
-
-struct S;
-impl S {
- fn m1(&self) { 'okay: loop { break 'okay; } }
- fn m2(&self) { 'okay: loop { break 'okay; } }
- fn m3(&self) { 'okay: { break 'okay; } }
- fn m4(&self) { 'okay: { break 'okay; } }
-}
-
-
-pub fn main() {
- let s = S;
- s.m1();
- s.m2();
- s.m3();
- s.m4();
- foo();
-}
+++ /dev/null
-warning: label name `'fl` shadows a label name that is already in scope
- --> $DIR/loops-reject-duplicate-labels.rs:9:5
- |
-LL | 'fl: for _ in 0..10 { break; }
- | --- first declared here
-LL | 'fl: loop { break; }
- | ^^^ label `'fl` already in scope
-
-warning: label name `'lf` shadows a label name that is already in scope
- --> $DIR/loops-reject-duplicate-labels.rs:12:5
- |
-LL | 'lf: loop { break; }
- | --- first declared here
-LL | 'lf: for _ in 0..10 { break; }
- | ^^^ label `'lf` already in scope
-
-warning: label name `'wl` shadows a label name that is already in scope
- --> $DIR/loops-reject-duplicate-labels.rs:14:5
- |
-LL | 'wl: while 2 > 1 { break; }
- | --- first declared here
-LL | 'wl: loop { break; }
- | ^^^ label `'wl` already in scope
-
-warning: label name `'lw` shadows a label name that is already in scope
- --> $DIR/loops-reject-duplicate-labels.rs:16:5
- |
-LL | 'lw: loop { break; }
- | --- first declared here
-LL | 'lw: while 2 > 1 { break; }
- | ^^^ label `'lw` already in scope
-
-warning: label name `'fw` shadows a label name that is already in scope
- --> $DIR/loops-reject-duplicate-labels.rs:18:5
- |
-LL | 'fw: for _ in 0..10 { break; }
- | --- first declared here
-LL | 'fw: while 2 > 1 { break; }
- | ^^^ label `'fw` already in scope
-
-warning: label name `'wf` shadows a label name that is already in scope
- --> $DIR/loops-reject-duplicate-labels.rs:20:5
- |
-LL | 'wf: while 2 > 1 { break; }
- | --- first declared here
-LL | 'wf: for _ in 0..10 { break; }
- | ^^^ label `'wf` already in scope
-
-warning: label name `'tl` shadows a label name that is already in scope
- --> $DIR/loops-reject-duplicate-labels.rs:22:5
- |
-LL | 'tl: while let Some(_) = None::<i32> { break; }
- | --- first declared here
-LL | 'tl: loop { break; }
- | ^^^ label `'tl` already in scope
-
-warning: label name `'lt` shadows a label name that is already in scope
- --> $DIR/loops-reject-duplicate-labels.rs:24:5
- |
-LL | 'lt: loop { break; }
- | --- first declared here
-LL | 'lt: while let Some(_) = None::<i32> { break; }
- | ^^^ label `'lt` already in scope
-
-warning: label name `'bl` shadows a label name that is already in scope
- --> $DIR/loops-reject-duplicate-labels.rs:27:5
- |
-LL | 'bl: {}
- | --- first declared here
-LL | 'bl: {}
- | ^^^ label `'bl` already in scope
-
-warning: 9 warnings emitted
-
+++ /dev/null
-// Issue #21633: reject duplicate loop labels in function bodies.
-// This is testing interaction between lifetime-params and labels.
-
-// check-pass
-
-#![allow(dead_code, unused_variables)]
-
-fn foo() {
- fn foo<'a>() {
- 'a: loop { break 'a; }
- //~^ WARN label name `'a` shadows a lifetime name that is already in scope
- }
-
- struct Struct<'b, 'c> { _f: &'b i8, _g: &'c i8 }
- enum Enum<'d, 'e> { A(&'d i8), B(&'e i8) }
-
- impl<'d, 'e> Struct<'d, 'e> {
- fn meth_okay() {
- 'a: loop { break 'a; }
- 'b: loop { break 'b; }
- 'c: loop { break 'c; }
- }
- }
-
- impl <'d, 'e> Enum<'d, 'e> {
- fn meth_okay() {
- 'a: loop { break 'a; }
- 'b: loop { break 'b; }
- 'c: loop { break 'c; }
- }
- }
-
- impl<'bad, 'c> Struct<'bad, 'c> {
- fn meth_bad(&self) {
- 'bad: loop { break 'bad; }
- //~^ WARN label name `'bad` shadows a lifetime name that is already in scope
- }
- }
-
- impl<'b, 'bad> Struct<'b, 'bad> {
- fn meth_bad2(&self) {
- 'bad: loop { break 'bad; }
- //~^ WARN label name `'bad` shadows a lifetime name that is already in scope
- }
- }
-
- impl<'b, 'c> Struct<'b, 'c> {
- fn meth_bad3<'bad>(x: &'bad i8) {
- 'bad: loop { break 'bad; }
- //~^ WARN label name `'bad` shadows a lifetime name that is already in scope
- }
-
- fn meth_bad4<'a,'bad>(x: &'a i8, y: &'bad i8) {
- 'bad: loop { break 'bad; }
- //~^ WARN label name `'bad` shadows a lifetime name that is already in scope
- }
- }
-
- impl <'bad, 'e> Enum<'bad, 'e> {
- fn meth_bad(&self) {
- 'bad: loop { break 'bad; }
- //~^ WARN label name `'bad` shadows a lifetime name that is already in scope
- }
- }
- impl <'d, 'bad> Enum<'d, 'bad> {
- fn meth_bad2(&self) {
- 'bad: loop { break 'bad; }
- //~^ WARN label name `'bad` shadows a lifetime name that is already in scope
- }
- }
- impl <'d, 'e> Enum<'d, 'e> {
- fn meth_bad3<'bad>(x: &'bad i8) {
- 'bad: loop { break 'bad; }
- //~^ WARN label name `'bad` shadows a lifetime name that is already in scope
- }
-
- fn meth_bad4<'a,'bad>(x: &'bad i8) {
- 'bad: loop { break 'bad; }
- //~^ WARN label name `'bad` shadows a lifetime name that is already in scope
- }
- }
-
- trait HasDefaultMethod1<'bad> {
- fn meth_okay() {
- 'c: loop { break 'c; }
- }
- fn meth_bad(&self) {
- 'bad: loop { break 'bad; }
- //~^ WARN label name `'bad` shadows a lifetime name that is already in scope
- }
- }
- trait HasDefaultMethod2<'a,'bad> {
- fn meth_bad(&self) {
- 'bad: loop { break 'bad; }
- //~^ WARN label name `'bad` shadows a lifetime name that is already in scope
- }
- }
- trait HasDefaultMethod3<'a,'b> {
- fn meth_bad<'bad>(&self) {
- 'bad: loop { break 'bad; }
- //~^ WARN label name `'bad` shadows a lifetime name that is already in scope
- }
- }
-}
-
-
-pub fn main() {
- foo();
-}
+++ /dev/null
-warning: label name `'a` shadows a lifetime name that is already in scope
- --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:10:9
- |
-LL | fn foo<'a>() {
- | -- first declared here
-LL | 'a: loop { break 'a; }
- | ^^ lifetime `'a` already in scope
-
-warning: label name `'bad` shadows a lifetime name that is already in scope
- --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:35:13
- |
-LL | impl<'bad, 'c> Struct<'bad, 'c> {
- | ---- first declared here
-LL | fn meth_bad(&self) {
-LL | 'bad: loop { break 'bad; }
- | ^^^^ lifetime `'bad` already in scope
-
-warning: label name `'bad` shadows a lifetime name that is already in scope
- --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:42:13
- |
-LL | impl<'b, 'bad> Struct<'b, 'bad> {
- | ---- first declared here
-LL | fn meth_bad2(&self) {
-LL | 'bad: loop { break 'bad; }
- | ^^^^ lifetime `'bad` already in scope
-
-warning: label name `'bad` shadows a lifetime name that is already in scope
- --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:49:13
- |
-LL | fn meth_bad3<'bad>(x: &'bad i8) {
- | ---- first declared here
-LL | 'bad: loop { break 'bad; }
- | ^^^^ lifetime `'bad` already in scope
-
-warning: label name `'bad` shadows a lifetime name that is already in scope
- --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:54:13
- |
-LL | fn meth_bad4<'a,'bad>(x: &'a i8, y: &'bad i8) {
- | ---- first declared here
-LL | 'bad: loop { break 'bad; }
- | ^^^^ lifetime `'bad` already in scope
-
-warning: label name `'bad` shadows a lifetime name that is already in scope
- --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:61:13
- |
-LL | impl <'bad, 'e> Enum<'bad, 'e> {
- | ---- first declared here
-LL | fn meth_bad(&self) {
-LL | 'bad: loop { break 'bad; }
- | ^^^^ lifetime `'bad` already in scope
-
-warning: label name `'bad` shadows a lifetime name that is already in scope
- --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:67:13
- |
-LL | impl <'d, 'bad> Enum<'d, 'bad> {
- | ---- first declared here
-LL | fn meth_bad2(&self) {
-LL | 'bad: loop { break 'bad; }
- | ^^^^ lifetime `'bad` already in scope
-
-warning: label name `'bad` shadows a lifetime name that is already in scope
- --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:73:13
- |
-LL | fn meth_bad3<'bad>(x: &'bad i8) {
- | ---- first declared here
-LL | 'bad: loop { break 'bad; }
- | ^^^^ lifetime `'bad` already in scope
-
-warning: label name `'bad` shadows a lifetime name that is already in scope
- --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:78:13
- |
-LL | fn meth_bad4<'a,'bad>(x: &'bad i8) {
- | ---- first declared here
-LL | 'bad: loop { break 'bad; }
- | ^^^^ lifetime `'bad` already in scope
-
-warning: label name `'bad` shadows a lifetime name that is already in scope
- --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:88:13
- |
-LL | trait HasDefaultMethod1<'bad> {
- | ---- first declared here
-...
-LL | 'bad: loop { break 'bad; }
- | ^^^^ lifetime `'bad` already in scope
-
-warning: label name `'bad` shadows a lifetime name that is already in scope
- --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:94:13
- |
-LL | trait HasDefaultMethod2<'a,'bad> {
- | ---- first declared here
-LL | fn meth_bad(&self) {
-LL | 'bad: loop { break 'bad; }
- | ^^^^ lifetime `'bad` already in scope
-
-warning: label name `'bad` shadows a lifetime name that is already in scope
- --> $DIR/loops-reject-labels-shadowing-lifetimes.rs:100:13
- |
-LL | fn meth_bad<'bad>(&self) {
- | ---- first declared here
-LL | 'bad: loop { break 'bad; }
- | ^^^^ lifetime `'bad` already in scope
-
-warning: 12 warnings emitted
-
+++ /dev/null
-// check-pass
-#![feature(label_break_value)]
-#![allow(dead_code, unused_variables)]
-
-// Issue #21633: reject duplicate loop labels and block labels in function bodies.
-//
-// Test rejection of lifetimes in *expressions* that shadow labels.
-
-fn foo() {
- // Reusing lifetime `'a` in function item is okay.
- fn foo<'a>(x: &'a i8) -> i8 { *x }
-
- // So is reusing `'a` in struct item
- struct S1<'a> { x: &'a i8 } impl<'a> S1<'a> { fn m(&self) {} }
- // and a method item
- struct S2; impl S2 { fn m<'a>(&self) {} }
-
- let z = 3_i8;
-
- 'a: loop {
- let b = Box::new(|x: &i8| *x) as Box<dyn for <'a> Fn(&'a i8) -> i8>;
- //~^ WARN lifetime name `'a` shadows a label name that is already in scope
- assert_eq!((*b)(&z), z);
- break 'a;
- }
-
- 'b: {
- let b = Box::new(|x: &()| ()) as Box<dyn for <'b> Fn(&'b ())>;
- //~^ WARN lifetime name `'b` shadows a label name that is already in scope
- break 'b;
- }
-}
-
-pub fn main() {
- foo();
-}
+++ /dev/null
-warning: lifetime name `'a` shadows a label name that is already in scope
- --> $DIR/loops-reject-lifetime-shadowing-label.rs:21:55
- |
-LL | 'a: loop {
- | -- first declared here
-LL | let b = Box::new(|x: &i8| *x) as Box<dyn for <'a> Fn(&'a i8) -> i8>;
- | ^^ label `'a` already in scope
-
-warning: lifetime name `'b` shadows a label name that is already in scope
- --> $DIR/loops-reject-lifetime-shadowing-label.rs:28:55
- |
-LL | 'b: {
- | -- first declared here
-LL | let b = Box::new(|x: &()| ()) as Box<dyn for <'b> Fn(&'b ())>;
- | ^^ label `'b` already in scope
-
-warning: 2 warnings emitted
-
}
macro_rules! br2 {
($b:lifetime) => {
- 'b: loop { //~ WARNING `'b` shadows a label name that is already in scope
+ 'b: loop {
break $b; // this $b should refer to the outer loop.
}
}
+++ /dev/null
-warning: label name `'b` shadows a label name that is already in scope
- --> $DIR/macro-lifetime-used-with-labels.rs:21:9
- |
-LL | 'b: loop {
- | ^^ label `'b` already in scope
-...
-LL | 'b: loop {
- | -- first declared here
-LL | br2!('b);
- | -------- in this macro invocation
- |
- = note: this warning originates in the macro `br2` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: 1 warning emitted
-
--- /dev/null
+fn main() {
+ match Some(10) {
+ //~^ NOTE `match` arms have incompatible types
+ Some(5) => false,
+ //~^ NOTE this is found to be of type `bool`
+ Some(2) => true,
+ //~^ NOTE this is found to be of type `bool`
+ None => (),
+ //~^ ERROR `match` arms have incompatible types
+ //~| NOTE expected `bool`, found `()`
+ _ => true
+ }
+}
--- /dev/null
+error[E0308]: `match` arms have incompatible types
+ --> $DIR/issue-11319.rs:8:20
+ |
+LL | / match Some(10) {
+LL | |
+LL | | Some(5) => false,
+ | | ----- this is found to be of type `bool`
+LL | |
+LL | | Some(2) => true,
+ | | ---- this is found to be of type `bool`
+LL | |
+LL | | None => (),
+ | | ^^ expected `bool`, found `()`
+... |
+LL | | _ => true
+LL | | }
+ | |_____- `match` arms have incompatible types
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--> $DIR/match-unresolved-one-arm.rs:4:9
|
LL | let x = match () {
- | ^ consider giving `x` a type
+ | ^
+ |
+help: consider giving `x` an explicit type
+ |
+LL | let x: _ = match () {
+ | +++
error: aborting due to previous error
error[E0282]: type annotations needed for `Vec<T>`
- --> $DIR/method-ambig-one-trait-unknown-int-type.rs:24:17
+ --> $DIR/method-ambig-one-trait-unknown-int-type.rs:24:9
|
LL | let mut x = Vec::new();
- | ----- ^^^^^^^^ cannot infer type for type parameter `T`
- | |
- | consider giving `x` the explicit type `Vec<T>`, where the type parameter `T` is specified
+ | ^^^^^
+ |
+help: consider giving `x` an explicit type, where the type for type parameter `T` is specified
+ |
+LL | let mut x: Vec<T> = Vec::new();
+ | ++++++++
error[E0283]: type annotations needed
--> $DIR/method-ambig-one-trait-unknown-int-type.rs:26:7
| ^^^
|
help: you must specify a type for this binding, like `i32`
+ --> $DIR/auxiliary/macro-in-other-crate.rs:3:29
|
LL | ($ident:ident) => { let $ident: i32 = 42; }
| ~~~~~~~~~~~
--> $DIR/missing-type-parameter.rs:4:5
|
LL | foo();
- | ^^^ cannot infer type for type parameter `X` declared on the function `foo`
+ | ^^^ cannot infer type of the type parameter `X` declared on the function `foo`
|
-help: type parameter declared here
- --> $DIR/missing-type-parameter.rs:1:8
+help: consider specifying the generic argument
|
-LL | fn foo<X>() { }
- | ^
+LL | foo::<X>();
+ | +++++
error: aborting due to previous error
fn main() {
Mod::FakeVariant::<i32>(0);
Mod::<i32>::FakeVariant(0);
- //~^ ERROR type arguments are not allowed for this type [E0109]
+ //~^ ERROR type arguments are not allowed on module `Mod` [E0109]
}
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on module `Mod`
--> $DIR/mod-subitem-as-enum-variant.rs:7:11
|
LL | Mod::<i32>::FakeVariant(0);
- | ^^^ type argument not allowed
+ | --- ^^^ type argument not allowed
+ | |
+ | not allowed on this
error: aborting due to previous error
(t, t) //~ use of moved value: `t`
}
-fn duplicate_custom<T: Trait + Copy>(t: S<T>) -> (S<T>, S<T>) {
+fn duplicate_custom<T: Copy + Trait>(t: S<T>) -> (S<T>, S<T>) {
//~^ HELP consider restricting type parameter `T`
(t, t) //~ use of moved value: `t`
}
trait B {}
// Test where bounds are added with different bound placements
-fn duplicate_custom_1<T: Trait + Copy>(t: S<T>) -> (S<T>, S<T>) where {
+fn duplicate_custom_1<T: Copy + Trait>(t: S<T>) -> (S<T>, S<T>) where {
//~^ HELP consider restricting type parameter `T`
(t, t) //~ use of moved value: `t`
}
fn duplicate_custom_2<T>(t: S<T>) -> (S<T>, S<T>)
where
- T: A + Trait + Copy,
+ T: A + Copy + Trait,
//~^ HELP consider further restricting this bound
{
(t, t) //~ use of moved value: `t`
fn duplicate_custom_3<T>(t: S<T>) -> (S<T>, S<T>)
where
- T: A + Trait + Copy,
+ T: A + Copy + Trait,
//~^ HELP consider further restricting this bound
T: B,
{
(t, t) //~ use of moved value: `t`
}
-fn duplicate_custom_4<T: A + Trait + Copy>(t: S<T>) -> (S<T>, S<T>)
+fn duplicate_custom_4<T: A + Copy + Trait>(t: S<T>) -> (S<T>, S<T>)
//~^ HELP consider further restricting this bound
where
T: B,
|
help: consider restricting type parameter `T`
|
-LL | fn duplicate_custom<T: Trait + Copy>(t: S<T>) -> (S<T>, S<T>) {
+LL | fn duplicate_custom<T: Copy + Trait>(t: S<T>) -> (S<T>, S<T>) {
| ++++++++++++++
error[E0382]: use of moved value: `t`
|
help: consider restricting type parameter `T`
|
-LL | fn duplicate_custom_1<T: Trait + Copy>(t: S<T>) -> (S<T>, S<T>) where {
+LL | fn duplicate_custom_1<T: Copy + Trait>(t: S<T>) -> (S<T>, S<T>) where {
| ++++++++++++++
error[E0382]: use of moved value: `t`
|
help: consider further restricting this bound
|
-LL | T: A + Trait + Copy,
+LL | T: A + Copy + Trait,
| ++++++++++++++
error[E0382]: use of moved value: `t`
|
help: consider further restricting this bound
|
-LL | T: A + Trait + Copy,
+LL | T: A + Copy + Trait,
| ++++++++++++++
error[E0382]: use of moved value: `t`
|
help: consider further restricting this bound
|
-LL | fn duplicate_custom_4<T: A + Trait + Copy>(t: S<T>) -> (S<T>, S<T>)
+LL | fn duplicate_custom_4<T: A + Copy + Trait>(t: S<T>) -> (S<T>, S<T>)
| ++++++++++++++
error[E0382]: use of moved value: `t`
LL | self.y = b.z
| ^^^
|
-note: ...the reference is valid for the lifetime `'_` as defined here...
+note: ...the reference is valid for the anonymous lifetime as defined here...
--> $DIR/issue-52742.rs:15:10
|
LL | impl Foo<'_, '_> {
--> $DIR/issue-52742.rs:17:9
|
LL | fn take_bar(&mut self, b: Bar<'_>) {
- | --------- -- let's call this `'1`
+ | --------- - has type `Bar<'1>`
| |
| has type `&mut Foo<'_, '2>`
LL | self.y = b.z
|
LL | Foo { bar }
| ^^^
-note: but, the lifetime must be valid for the lifetime `'_` as defined here...
+note: but, the lifetime must be valid for the anonymous lifetime as defined here...
--> $DIR/issue-55394.rs:11:10
|
LL | impl Foo<'_> {
--- /dev/null
+// run-pass
+// pretty-expanded FIXME #23616
+
+#![feature(fn_traits, unboxed_closures)]
+
+trait Foo { fn dummy(&self) { }}
+
+struct Bar;
+
+impl<'a> std::ops::Fn<(&'a (dyn Foo+'a),)> for Bar {
+ extern "rust-call" fn call(&self, _: (&'a dyn Foo,)) {}
+}
+
+impl<'a> std::ops::FnMut<(&'a (dyn Foo+'a),)> for Bar {
+ extern "rust-call" fn call_mut(&mut self, a: (&'a dyn Foo,)) { self.call(a) }
+}
+
+impl<'a> std::ops::FnOnce<(&'a (dyn Foo+'a),)> for Bar {
+ type Output = ();
+ extern "rust-call" fn call_once(self, a: (&'a dyn Foo,)) { self.call(a) }
+}
+
+struct Baz;
+
+impl Foo for Baz {}
+
+fn main() {
+ let bar = Bar;
+ let baz = &Baz;
+ bar(baz);
+}
--- /dev/null
+macro_rules! x {
+ ($($c:tt)*) => {
+ $($c)ö* {} //~ ERROR missing condition for `if` expression
+ }; //~| ERROR mismatched types
+}
+
+fn main() {
+ x!(if);
+}
--- /dev/null
+error: missing condition for `if` expression
+ --> $DIR/issue-68091-unicode-ident-after-if.rs:3:14
+ |
+LL | $($c)ö* {}
+ | ^ expected if condition here
+
+error[E0308]: mismatched types
+ --> $DIR/issue-68091-unicode-ident-after-if.rs:3:17
+ |
+LL | $($c)ö* {}
+ | ^^ expected `bool`, found `()`
+...
+LL | x!(if);
+ | ------ in this macro invocation
+ |
+ = note: this error originates in the macro `x` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+macro_rules! x {
+ ($($c:tt)*) => {
+ $($c)ö* //~ ERROR macro expansion ends with an incomplete expression: expected expression
+ };
+}
+
+fn main() {
+ x!(!);
+}
--- /dev/null
+error: macro expansion ends with an incomplete expression: expected expression
+ --> $DIR/issue-68092-unicode-ident-after-incomplete-expr.rs:3:14
+ |
+LL | $($c)ö*
+ | ^ expected expression
+
+error: aborting due to previous error
+
--> $DIR/issue-67377-invalid-syntax-in-enum-discriminant.rs:26:14
|
LL | V = [Vec::new; { [0].len() ].len() as isize,
- | ^^^^^^^^ cannot infer type for type parameter `T`
+ | ^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Vec`
+ |
+help: consider specifying the generic argument
+ |
+LL | V = [Vec::<T>::new; { [0].len() ].len() as isize,
+ | +++++
error: aborting due to 14 previous errors
| +
error[E0282]: type annotations needed for `Vec<T>`
- --> $DIR/missing-closing-angle-bracket-eq-constraint.rs:7:25
+ --> $DIR/missing-closing-angle-bracket-eq-constraint.rs:7:7
|
LL | let v : Vec<(u32,_) = vec![];
- | - ^^^^^^ cannot infer type for type parameter `T`
- | |
- | consider giving `v` the explicit type `Vec<T>`, where the type parameter `T` is specified
+ | ^
+ |
+help: consider giving `v` an explicit type, where the type for type parameter `T` is specified
|
- = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
+LL | let v: Vec<T> : Vec<(u32,_) = vec![];
+ | ++++++++
error[E0282]: type annotations needed for `Vec<T>`
- --> $DIR/missing-closing-angle-bracket-eq-constraint.rs:18:20
+ --> $DIR/missing-closing-angle-bracket-eq-constraint.rs:18:7
|
LL | let v : Vec<'a = vec![];
- | - ^^^^^^ cannot infer type for type parameter `T`
- | |
- | consider giving `v` the explicit type `Vec<T>`, where the type parameter `T` is specified
+ | ^
+ |
+help: consider giving `v` an explicit type, where the type for type parameter `T` is specified
|
- = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
+LL | let v: Vec<T> : Vec<'a = vec![];
+ | ++++++++
error: aborting due to 5 previous errors
fn main() {
- let x;
+ let x; //~ ERROR type annotations needed
match x {
- (..) => {} //~ ERROR type annotations needed
+ (..) => {}
_ => {}
}
error[E0282]: type annotations needed
- --> $DIR/pat-tuple-bad-type.rs:5:9
+ --> $DIR/pat-tuple-bad-type.rs:2:9
|
LL | let x;
- | - consider giving `x` a type
-...
-LL | (..) => {}
- | ^^^^ cannot infer type
+ | ^
|
= note: type must be known at this point
+help: consider giving `x` an explicit type
+ |
+LL | let x: _;
+ | +++
error[E0308]: mismatched types
--> $DIR/pat-tuple-bad-type.rs:10:9
--> $DIR/rest-pat-semantic-disallowed.rs:33:9
|
LL | let x @ ..;
- | ^^^^^^ consider giving this pattern a type
+ | ^^^^^^
+ |
+help: consider giving this pattern a type
+ |
+LL | let x @ ..: _;
+ | +++
error: aborting due to 23 previous errors
|
LL | pub(in bad::path) mod m1 {}
| ^^^ maybe a missing crate `bad`?
+ |
+ = help: consider adding `extern crate bad` to use the `bad` crate
error[E0742]: visibilities can only be restricted to ancestor modules
--> $DIR/test.rs:51:12
#[proc_macro]
pub fn expand_expr_is(input: TokenStream) -> TokenStream {
- expand_expr_is_inner(input, false)
-}
-
-#[proc_macro]
-pub fn expand_expr_is_trim(input: TokenStream) -> TokenStream {
- expand_expr_is_inner(input, true)
-}
-
-fn expand_expr_is_inner(input: TokenStream, trim_invisible: bool) -> TokenStream {
let mut iter = input.into_iter();
let mut expected_tts = Vec::new();
loop {
}
}
- // If requested, trim the "invisible" delimiters at the start and end.
- let expected = expected_tts.into_iter().collect::<TokenStream>().to_string();
- let expected = if trim_invisible {
- let len1 = "/*«*/ ".len();
- let len2 = " /*»*/".len();
- &expected[len1..expected.len() - len2]
- } else {
- &expected[..]
- };
- let expanded = iter.collect::<TokenStream>().expand_expr().unwrap().to_string();
-
- assert_eq!(expected, expanded);
+ let expected = expected_tts.into_iter().collect::<TokenStream>();
+ let expanded = iter.collect::<TokenStream>().expand_expr().expect("expand_expr failed");
+ assert!(
+ expected.to_string() == expanded.to_string(),
+ "assert failed\nexpected: `{}`\nexpanded: `{}`",
+ expected.to_string(),
+ expanded.to_string()
+ );
TokenStream::new()
}
PRINT-BANG INPUT (DISPLAY): self
-PRINT-BANG RE-COLLECTED (DISPLAY): /*«*/ self /*»*/
PRINT-BANG INPUT (DEBUG): TokenStream [
Group {
delimiter: None,
]
PRINT-BANG INPUT (DISPLAY): 1 + 1, { "a" }, let a = 1;, String, my_name, 'a, my_val = 30,
std::option::Option, pub(in some::path) , [a b c], -30
-PRINT-BANG RE-COLLECTED (DISPLAY): /*«*/ 1 + 1 /*»*/, /*«*/ { "a" } /*»*/, /*«*/ let a = 1 /*»*/, /*«*/
-String /*»*/, my_name, /*«*/ 'a /*»*/, /*«*/ my_val = 30 /*»*/, /*«*/
-std :: option :: Option /*»*/, /*«*/ pub(in some :: path) /*»*/, [a b c],
-/*«*/ - 30 /*»*/
+PRINT-BANG RE-COLLECTED (DISPLAY): 1 + 1, { "a" }, let a = 1, String, my_name, 'a, my_val = 30,
+std :: option :: Option, pub(in some :: path), [a b c], - 30
PRINT-BANG INPUT (DEBUG): TokenStream [
Group {
delimiter: None,
},
]
PRINT-BANG INPUT (DISPLAY): (a, b)
-PRINT-BANG RE-COLLECTED (DISPLAY): /*«*/ (a, b) /*»*/
PRINT-BANG INPUT (DEBUG): TokenStream [
Group {
delimiter: None,
PRINT-BANG INPUT (DISPLAY): Vec<u8>
-PRINT-BANG RE-COLLECTED (DISPLAY): /*«*/ Vec < u8 > /*»*/
+PRINT-BANG RE-COLLECTED (DISPLAY): Vec < u8 >
PRINT-BANG INPUT (DEBUG): TokenStream [
Group {
delimiter: None,
extern crate expand_expr;
-use expand_expr::{check_expand_expr_file, echo_pm, expand_expr_fail, expand_expr_is};
-use expand_expr::{expand_expr_is_trim, recursive_expand};
-
+use expand_expr::{
+ check_expand_expr_file, echo_pm, expand_expr_fail, expand_expr_is, recursive_expand,
+};
// Check builtin macros can be expanded.
macro_rules! simple_lit {
($l:literal) => {
- expand_expr_is_trim!($l, $l);
- expand_expr_is_trim!($l, echo_lit!($l));
- expand_expr_is_trim!($l, echo_expr!($l));
- expand_expr_is_trim!($l, echo_tts!($l));
- expand_expr_is_trim!($l, echo_pm!($l));
+ expand_expr_is!($l, $l);
+ expand_expr_is!($l, echo_lit!($l));
+ expand_expr_is!($l, echo_expr!($l));
+ expand_expr_is!($l, echo_tts!($l));
+ expand_expr_is!($l, echo_pm!($l));
const _: () = {
macro_rules! mac {
() => {
$l
};
}
- expand_expr_is_trim!($l, mac!());
- expand_expr_is_trim!($l, echo_expr!(mac!()));
- expand_expr_is_trim!($l, echo_tts!(mac!()));
- expand_expr_is_trim!($l, echo_pm!(mac!()));
+ expand_expr_is!($l, mac!());
+ expand_expr_is!($l, echo_expr!(mac!()));
+ expand_expr_is!($l, echo_tts!(mac!()));
+ expand_expr_is!($l, echo_pm!(mac!()));
};
};
}
PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = #[allow(warnings)] 0 ; 0 }, }
-PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E
-{ V = { let _ = /*«*/ #[allow(warnings)] #[allow(warnings)] 0 /*»*/ ; 0 }, }
+PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = #[allow(warnings)] #[allow(warnings)] 0 ; 0 }, }
PRINT-DERIVE INPUT (DEBUG): TokenStream [
Ident {
ident: "enum",
},
]
PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { 0; } ; 0 }, }
-PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { /*«*/ 0 /*»*/ } ; 0 }, }
+PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { 0 } ; 0 }, }
PRINT-DERIVE INPUT (DEBUG): TokenStream [
Ident {
ident: "enum",
},
]
PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { {} } ; 0 }, }
-PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { /*«*/ {} /*»*/ } ; 0 }, }
PRINT-DERIVE INPUT (DEBUG): TokenStream [
Ident {
ident: "enum",
},
]
PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { PATH; } ; 0 }, }
-PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { /*«*/ PATH /*»*/ } ; 0 }, }
+PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { PATH } ; 0 }, }
PRINT-DERIVE INPUT (DEBUG): TokenStream [
Ident {
ident: "enum",
},
]
PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { 0 + 1; } ; 0 }, }
-PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { /*«*/ 0 + 1 /*»*/ } ; 0 }, }
+PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { 0 + 1 } ; 0 }, }
PRINT-DERIVE INPUT (DEBUG): TokenStream [
Ident {
ident: "enum",
},
]
PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { PATH + 1; } ; 0 }, }
-PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { /*«*/ PATH + 1 /*»*/ } ; 0 }, }
+PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { PATH + 1 } ; 0 }, }
PRINT-DERIVE INPUT (DEBUG): TokenStream [
Ident {
ident: "enum",
},
]
PRINT-BANG INPUT (DISPLAY): 1 + 1 * 2
-PRINT-BANG RE-COLLECTED (DISPLAY): /*«*/ 1 + 1 /*»*/ * 2
PRINT-BANG INPUT (DEBUG): TokenStream [
Group {
delimiter: None,
PRINT-BANG INPUT (DISPLAY): foo! { #[fake_attr] mod bar {
#![doc = r" Foo"]
} }
-PRINT-BANG DEEP-RE-COLLECTED (DISPLAY): foo! { #[fake_attr] /*«*/ mod bar { #! [doc = r" Foo"] } /*»*/ }
+PRINT-BANG DEEP-RE-COLLECTED (DISPLAY): foo! { #[fake_attr] mod bar { #! [doc = r" Foo"] } }
PRINT-BANG INPUT (DEBUG): TokenStream [
Ident {
ident: "foo",
PRINT-BANG INPUT (DISPLAY): ;
-PRINT-BANG RE-COLLECTED (DISPLAY): /*«*/ ; /*»*/
PRINT-BANG INPUT (DEBUG): TokenStream [
Group {
delimiter: None,
PRINT-BANG INPUT (DISPLAY): 0 + 1 + 2 + 3
-PRINT-BANG RE-COLLECTED (DISPLAY): /*«*/ 0 + 1 + 2 /*»*/ + 3
-PRINT-BANG DEEP-RE-COLLECTED (DISPLAY): /*«*/ /*«*/ /*«*/ 0 /*»*/ + 1 /*»*/ + 2 /*»*/ + 3
PRINT-BANG INPUT (DEBUG): TokenStream [
Group {
delimiter: None,
PRINT-BANG INPUT (DISPLAY): "hi" 1 + (25) + 1 (1 + 1)
-PRINT-BANG RE-COLLECTED (DISPLAY): "hi" /*«*/ 1 + (25) + 1 /*»*/ (1 + 1)
PRINT-BANG INPUT (DEBUG): TokenStream [
Literal {
kind: Str,
},
]
PRINT-BANG INPUT (DISPLAY): "hi" "hello".len() + "world".len() (1 + 1)
-PRINT-BANG RE-COLLECTED (DISPLAY): "hi" /*«*/ "hello".len() + "world".len() /*»*/ (1 + 1)
-PRINT-BANG DEEP-RE-COLLECTED (DISPLAY): "hi" /*«*/ /*«*/ "hello".len() /*»*/ + /*«*/ "world".len() /*»*/ /*»*/
-(1 + 1)
PRINT-BANG INPUT (DEBUG): TokenStream [
Literal {
kind: Str,
PRINT-ATTR_ARGS INPUT (DISPLAY): a, line!(), b
-PRINT-ATTR_ARGS RE-COLLECTED (DISPLAY): a, /*«*/ line! () /*»*/, b
+PRINT-ATTR_ARGS RE-COLLECTED (DISPLAY): a, line! (), b
PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
Ident {
ident: "a",
PRINT-BANG INPUT (DISPLAY): struct S;
-PRINT-BANG RE-COLLECTED (DISPLAY): /*«*/ struct S ; /*»*/
+PRINT-BANG RE-COLLECTED (DISPLAY): struct S ;
PRINT-BANG INPUT (DEBUG): TokenStream [
Group {
delimiter: None,
macro one($a:expr, $b:expr) {
two!($a, $b);
- //~^ ERROR first parent: /*«*/ "hello" /*»*/
- //~| ERROR second parent: /*«*/ "world" /*»*/
+ //~^ ERROR first parent: "hello"
+ //~| ERROR second parent: "world"
}
macro two($a:expr, $b:expr) {
three!($a, $b);
- //~^ ERROR first final: /*«*/ "hello" /*»*/
- //~| ERROR second final: /*«*/ "world" /*»*/
- //~| ERROR first final: /*«*/ "yay" /*»*/
- //~| ERROR second final: /*«*/ "rust" /*»*/
+ //~^ ERROR first final: "hello"
+ //~| ERROR second final: "world"
+ //~| ERROR first final: "yay"
+ //~| ERROR second final: "rust"
}
// forwarding tokens directly doesn't create a new source chain
fn main() {
one!("hello", "world");
- //~^ ERROR first grandparent: /*«*/ "hello" /*»*/
- //~| ERROR second grandparent: /*«*/ "world" /*»*/
- //~| ERROR first source: /*«*/ "hello" /*»*/
- //~| ERROR second source: /*«*/ "world" /*»*/
+ //~^ ERROR first grandparent: "hello"
+ //~| ERROR second grandparent: "world"
+ //~| ERROR first source: "hello"
+ //~| ERROR second source: "world"
two!("yay", "rust");
- //~^ ERROR first parent: /*«*/ "yay" /*»*/
- //~| ERROR second parent: /*«*/ "rust" /*»*/
- //~| ERROR first source: /*«*/ "yay" /*»*/
- //~| ERROR second source: /*«*/ "rust" /*»*/
+ //~^ ERROR first parent: "yay"
+ //~| ERROR second parent: "rust"
+ //~| ERROR first source: "yay"
+ //~| ERROR second source: "rust"
three!("hip", "hop");
//~^ ERROR first final: "hip"
-error: first final: /*«*/ "hello" /*»*/
+error: first final: "hello"
--> $DIR/parent-source-spans.rs:16:12
|
LL | three!($a, $b);
|
= note: this error originates in the macro `two` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: second final: /*«*/ "world" /*»*/
+error: second final: "world"
--> $DIR/parent-source-spans.rs:16:16
|
LL | three!($a, $b);
|
= note: this error originates in the macro `two` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: first parent: /*«*/ "hello" /*»*/
+error: first parent: "hello"
--> $DIR/parent-source-spans.rs:10:5
|
LL | two!($a, $b);
|
= note: this error originates in the macro `one` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: second parent: /*«*/ "world" /*»*/
+error: second parent: "world"
--> $DIR/parent-source-spans.rs:10:5
|
LL | two!($a, $b);
|
= note: this error originates in the macro `one` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: first grandparent: /*«*/ "hello" /*»*/
+error: first grandparent: "hello"
--> $DIR/parent-source-spans.rs:36:5
|
LL | one!("hello", "world");
| ^^^^^^^^^^^^^^^^^^^^^^
-error: second grandparent: /*«*/ "world" /*»*/
+error: second grandparent: "world"
--> $DIR/parent-source-spans.rs:36:5
|
LL | one!("hello", "world");
| ^^^^^^^^^^^^^^^^^^^^^^
-error: first source: /*«*/ "hello" /*»*/
+error: first source: "hello"
--> $DIR/parent-source-spans.rs:36:5
|
LL | one!("hello", "world");
| ^^^^^^^^^^^^^^^^^^^^^^
-error: second source: /*«*/ "world" /*»*/
+error: second source: "world"
--> $DIR/parent-source-spans.rs:36:5
|
LL | one!("hello", "world");
| ^^^^^^^^^^^^^^^^^^^^^^
-error: first final: /*«*/ "yay" /*»*/
+error: first final: "yay"
--> $DIR/parent-source-spans.rs:16:12
|
LL | three!($a, $b);
|
= note: this error originates in the macro `two` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: second final: /*«*/ "rust" /*»*/
+error: second final: "rust"
--> $DIR/parent-source-spans.rs:16:16
|
LL | three!($a, $b);
|
= note: this error originates in the macro `two` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: first parent: /*«*/ "yay" /*»*/
+error: first parent: "yay"
--> $DIR/parent-source-spans.rs:42:5
|
LL | two!("yay", "rust");
| ^^^^^^^^^^^^^^^^^^^
-error: second parent: /*«*/ "rust" /*»*/
+error: second parent: "rust"
--> $DIR/parent-source-spans.rs:42:5
|
LL | two!("yay", "rust");
| ^^^^^^^^^^^^^^^^^^^
-error: first source: /*«*/ "yay" /*»*/
+error: first source: "yay"
--> $DIR/parent-source-spans.rs:42:5
|
LL | two!("yay", "rust");
| ^^^^^^^^^^^^^^^^^^^
-error: second source: /*«*/ "rust" /*»*/
+error: second source: "rust"
--> $DIR/parent-source-spans.rs:42:5
|
LL | two!("yay", "rust");
-struct Foo<'a, 'a> { //~ ERROR lifetime name `'a` declared twice
- x: &'a isize
+struct Foo<'a, 'a> {
+ //~^ ERROR the name `'a` is already used for a generic parameter
+ x: &'a isize,
}
fn main() {}
-error[E0263]: lifetime name `'a` declared twice in the same scope
+error[E0403]: the name `'a` is already used for a generic parameter in this item's generic parameters
--> $DIR/regions-name-duplicated.rs:1:16
|
LL | struct Foo<'a, 'a> {
- | -- ^^ declared twice
+ | -- ^^ already used
| |
- | previous declaration here
+ | first use of `'a`
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0263`.
+For more information about this error, try `rustc --explain E0403`.
|
LL | fn global_inner(_: ::nonexistant::Foo) {
| ^^^^^^^^^^^ maybe a missing crate `nonexistant`?
+ |
+ = help: consider adding `extern crate nonexistant` to use the `nonexistant` crate
error[E0433]: failed to resolve: maybe a missing crate `nonexistant`?
--> $DIR/editions-crate-root-2015.rs:7:30
|
LL | fn crate_inner(_: crate::nonexistant::Foo) {
| ^^^^^^^^^^^ maybe a missing crate `nonexistant`?
+ |
+ = help: consider adding `extern crate nonexistant` to use the `nonexistant` crate
error[E0412]: cannot find type `nonexistant` in the crate root
--> $DIR/editions-crate-root-2015.rs:11:25
|
LL | use extern_prelude::S;
| ^^^^^^^^^^^^^^ maybe a missing crate `extern_prelude`?
+ |
+ = help: consider adding `extern crate extern_prelude` to use the `extern_prelude` crate
error[E0433]: failed to resolve: maybe a missing crate `extern_prelude`?
--> $DIR/extern-prelude-fail.rs:8:15
|
LL | let s = ::extern_prelude::S;
| ^^^^^^^^^^^^^^ maybe a missing crate `extern_prelude`?
+ |
+ = help: consider adding `extern crate extern_prelude` to use the `extern_prelude` crate
error: aborting due to 2 previous errors
|
LL | use x::y::z;
| ^ maybe a missing crate `x`?
+ |
+ = help: consider adding `extern crate x` to use the `x` crate
error[E0599]: no function or associated item named `z` found for struct `Box<_, _>` in the current scope
--> $DIR/issue-82865.rs:8:10
--> $DIR/issue-85348.rs:6:13
|
LL | let mut N;
- | ^^^^^ consider giving `N` a type
+ | ^^^^^
+ |
+help: consider giving `N` an explicit type
+ |
+LL | let mut N: _;
+ | +++
error: aborting due to 3 previous errors
|
LL | pub(in nonexistent) struct G;
| ^^^^^^^^^^^ maybe a missing crate `nonexistent`?
+ |
+ = help: consider adding `extern crate nonexistent` to use the `nonexistent` crate
error[E0433]: failed to resolve: maybe a missing crate `too_soon`?
--> $DIR/resolve-bad-visibility.rs:8:8
|
LL | pub(in too_soon) struct H;
| ^^^^^^^^ maybe a missing crate `too_soon`?
+ |
+ = help: consider adding `extern crate too_soon` to use the `too_soon` crate
error: aborting due to 5 previous errors
--- /dev/null
+// compile-flags: --test
+// run-pass
+
+// `generic_assert` is completely unimplemented and doesn't generate any logic, thus the
+// reason why this test currently passes
+#![feature(core_intrinsics, generic_assert, generic_assert_internals)]
+
+use std::fmt::{Debug, Formatter};
+
+#[derive(Clone, Copy, PartialEq)]
+struct CopyDebug(i32);
+
+impl Debug for CopyDebug {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
+ f.write_str("With great power comes great electricity bills")
+ }
+}
+
+#[test]
+fn test() {
+ let _copy_debug = CopyDebug(1);
+ assert!(_copy_debug == CopyDebug(3));
+}
+
+fn main() {
+}
/// Bar
//~^ ERROR documentation comments cannot be applied to function
#[must_use]
- //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+ //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
/// Baz
//~^ ERROR documentation comments cannot be applied to function
#[no_mangle] b: i32,
- //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+ //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
);
}
/// Bar
//~^ ERROR documentation comments cannot be applied to function
#[must_use]
- //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+ //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
/// Baz
//~^ ERROR documentation comments cannot be applied to function
#[no_mangle] b: i32,
- //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+ //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
);
pub fn foo(
/// Bar
//~^ ERROR documentation comments cannot be applied to function
#[must_use]
- //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+ //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
/// Baz
//~^ ERROR documentation comments cannot be applied to function
#[no_mangle] b: i32,
- //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+ //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
) {}
struct SelfStruct {}
/// Baz
//~^ ERROR documentation comments cannot be applied to function
#[must_use]
- //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+ //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
/// Qux
//~^ ERROR documentation comments cannot be applied to function
#[no_mangle] b: i32,
- //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+ //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
) {}
fn issue_64682_associated_fn(
/// Baz
//~^ ERROR documentation comments cannot be applied to function
#[must_use]
- //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+ //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
/// Qux
//~^ ERROR documentation comments cannot be applied to function
#[no_mangle] b: i32,
- //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+ //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
) {}
}
/// Baz
//~^ ERROR documentation comments cannot be applied to function
#[must_use]
- //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+ //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
/// Qux
//~^ ERROR documentation comments cannot be applied to function
#[no_mangle] b: i32,
- //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+ //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
) {}
}
trait RefTrait {
/// Baz
//~^ ERROR documentation comments cannot be applied to function
#[must_use]
- //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+ //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
/// Qux
//~^ ERROR documentation comments cannot be applied to function
#[no_mangle] b: i32,
- //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+ //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
) {}
fn issue_64682_associated_fn(
/// Baz
//~^ ERROR documentation comments cannot be applied to function
#[must_use]
- //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+ //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
/// Qux
//~^ ERROR documentation comments cannot be applied to function
#[no_mangle] b: i32,
- //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+ //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
) {}
}
/// Baz
//~^ ERROR documentation comments cannot be applied to function
#[must_use]
- //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+ //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
/// Qux
//~^ ERROR documentation comments cannot be applied to function
#[no_mangle] b: i32,
- //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+ //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
) {}
}
/// Bar
//~^ ERROR documentation comments cannot be applied to function
#[must_use]
- //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+ //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
/// Baz
//~^ ERROR documentation comments cannot be applied to function
#[no_mangle] b: i32
- //~^ ERROR allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in
+ //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
| {};
}
LL | /// Bar
| ^^^^^^^ doc comments are not allowed here
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
--> $DIR/param-attrs-builtin-attrs.rs:9:9
|
LL | #[must_use]
LL | /// Baz
| ^^^^^^^ doc comments are not allowed here
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
--> $DIR/param-attrs-builtin-attrs.rs:13:9
|
LL | #[no_mangle] b: i32,
LL | /// Bar
| ^^^^^^^ doc comments are not allowed here
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
--> $DIR/param-attrs-builtin-attrs.rs:25:5
|
LL | #[must_use]
LL | /// Baz
| ^^^^^^^ doc comments are not allowed here
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
--> $DIR/param-attrs-builtin-attrs.rs:29:5
|
LL | #[no_mangle] b: i32,
LL | /// Bar
| ^^^^^^^ doc comments are not allowed here
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
--> $DIR/param-attrs-builtin-attrs.rs:40:5
|
LL | #[must_use]
LL | /// Baz
| ^^^^^^^ doc comments are not allowed here
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
--> $DIR/param-attrs-builtin-attrs.rs:44:5
|
LL | #[no_mangle] b: i32,
LL | /// Baz
| ^^^^^^^ doc comments are not allowed here
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
--> $DIR/param-attrs-builtin-attrs.rs:60:9
|
LL | #[must_use]
LL | /// Qux
| ^^^^^^^ doc comments are not allowed here
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
--> $DIR/param-attrs-builtin-attrs.rs:64:9
|
LL | #[no_mangle] b: i32,
LL | /// Baz
| ^^^^^^^ doc comments are not allowed here
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
--> $DIR/param-attrs-builtin-attrs.rs:75:9
|
LL | #[must_use]
LL | /// Qux
| ^^^^^^^ doc comments are not allowed here
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
--> $DIR/param-attrs-builtin-attrs.rs:79:9
|
LL | #[no_mangle] b: i32,
LL | /// Baz
| ^^^^^^^ doc comments are not allowed here
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
--> $DIR/param-attrs-builtin-attrs.rs:96:9
|
LL | #[must_use]
LL | /// Qux
| ^^^^^^^ doc comments are not allowed here
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
--> $DIR/param-attrs-builtin-attrs.rs:100:9
|
LL | #[no_mangle] b: i32,
LL | /// Baz
| ^^^^^^^ doc comments are not allowed here
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
--> $DIR/param-attrs-builtin-attrs.rs:115:9
|
LL | #[must_use]
LL | /// Qux
| ^^^^^^^ doc comments are not allowed here
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
--> $DIR/param-attrs-builtin-attrs.rs:119:9
|
LL | #[no_mangle] b: i32,
LL | /// Baz
| ^^^^^^^ doc comments are not allowed here
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
--> $DIR/param-attrs-builtin-attrs.rs:130:9
|
LL | #[must_use]
LL | /// Qux
| ^^^^^^^ doc comments are not allowed here
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
--> $DIR/param-attrs-builtin-attrs.rs:134:9
|
LL | #[no_mangle] b: i32,
LL | /// Baz
| ^^^^^^^ doc comments are not allowed here
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
--> $DIR/param-attrs-builtin-attrs.rs:150:9
|
LL | #[must_use]
LL | /// Qux
| ^^^^^^^ doc comments are not allowed here
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
--> $DIR/param-attrs-builtin-attrs.rs:154:9
|
LL | #[no_mangle] b: i32,
LL | /// Bar
| ^^^^^^^ doc comments are not allowed here
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
--> $DIR/param-attrs-builtin-attrs.rs:167:9
|
LL | #[must_use]
LL | /// Baz
| ^^^^^^^ doc comments are not allowed here
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
--> $DIR/param-attrs-builtin-attrs.rs:171:9
|
LL | #[no_mangle] b: i32
-error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
--> $DIR/check-doc-alias-attr-location.rs:22:12
|
LL | fn foo(#[doc(alias = "qux")] _x: u32) -> Self::X {
--> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:48
|
LL | async fn f(self: Pin<&Self>) -> impl Clone { self }
- | - ^^^^^^^^
+ | ----- ^^^^^^^^
| |
- | hidden type `Pin<&Foo>` captures the lifetime `'_` as defined here
+ | hidden type `Pin<&Foo>` captures the anonymous lifetime defined here
|
help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound
|
| ---- ---- ^ ...but data from `f` is returned here
| |
| this parameter and the return type are declared with different lifetimes...
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn a<'a>(self: Pin<&'a Foo>, f: &'a Foo) -> &Foo { f }
+ | ++++ ++ ++
error[E0623]: lifetime mismatch
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:15:82
| ---- ----------------- ^ ...but data from `f` is returned here
| |
| this parameter and the return type are declared with different lifetimes...
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn c<'a>(self: Pin<&'a Self>, f: &'a Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
+ | ++++ ++ ++
error[E0623]: lifetime mismatch
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:22:64
| | |
| | let's call the lifetime of this reference `'1`
| let's call the lifetime of this reference `'2`
+ |
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn a<'a>(self: Pin<&'a Foo>, f: &'a Foo) -> &Foo { f }
+ | ++++ ++ ++
error: lifetime may not live long enough
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:15:75
| | |
| | let's call the lifetime of this reference `'1`
| let's call the lifetime of this reference `'2`
+ |
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn c<'a>(self: Pin<&'a Self>, f: &'a Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
+ | ++++ ++ ++
error: lifetime may not live long enough
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:22:64
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error[E0623]: lifetime mismatch
--> $DIR/lt-ref-self-async.rs:24:9
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error[E0623]: lifetime mismatch
--> $DIR/lt-ref-self-async.rs:30:9
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error[E0623]: lifetime mismatch
--> $DIR/lt-ref-self-async.rs:36:9
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error[E0623]: lifetime mismatch
--> $DIR/lt-ref-self-async.rs:42:9
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn box_box_ref_Self<'a>(self: Box<Box<&'a Self>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error[E0623]: lifetime mismatch
--> $DIR/lt-ref-self-async.rs:48:9
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn box_pin_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error: aborting due to 6 previous errors
| let's call the lifetime of this reference `'2`
LL | f
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ |
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error: lifetime may not live long enough
--> $DIR/lt-ref-self-async.rs:24:9
| let's call the lifetime of this reference `'2`
LL | f
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ |
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error: lifetime may not live long enough
--> $DIR/lt-ref-self-async.rs:30:9
| let's call the lifetime of this reference `'2`
LL | f
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ |
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error: lifetime may not live long enough
--> $DIR/lt-ref-self-async.rs:36:9
| let's call the lifetime of this reference `'2`
LL | f
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ |
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error: lifetime may not live long enough
--> $DIR/lt-ref-self-async.rs:42:9
| let's call the lifetime of this reference `'2`
LL | f
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ |
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn box_box_ref_Self<'a>(self: Box<Box<&'a Self>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error: lifetime may not live long enough
--> $DIR/lt-ref-self-async.rs:48:9
| let's call the lifetime of this reference `'2`
LL | f
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ |
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn box_pin_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error: aborting due to 6 previous errors
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn ref_self<'a>(&'a mut self, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error[E0623]: lifetime mismatch
--> $DIR/ref-mut-self-async.rs:24:9
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn ref_Self<'a>(self: &'a mut Self, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error[E0623]: lifetime mismatch
--> $DIR/ref-mut-self-async.rs:30:9
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn box_ref_Self<'a>(self: Box<&'a mut Self>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error[E0623]: lifetime mismatch
--> $DIR/ref-mut-self-async.rs:36:9
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn pin_ref_Self<'a>(self: Pin<&'a mut Self>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error[E0623]: lifetime mismatch
--> $DIR/ref-mut-self-async.rs:42:9
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn box_box_ref_Self<'a>(self: Box<Box<&'a mut Self>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error[E0623]: lifetime mismatch
--> $DIR/ref-mut-self-async.rs:48:9
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn box_pin_ref_Self<'a>(self: Box<Pin<&'a mut Self>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error: aborting due to 6 previous errors
| let's call the lifetime of this reference `'2`
LL | f
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ |
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn ref_self<'a>(&'a mut self, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error: lifetime may not live long enough
--> $DIR/ref-mut-self-async.rs:24:9
| let's call the lifetime of this reference `'2`
LL | f
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ |
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn ref_Self<'a>(self: &'a mut Self, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error: lifetime may not live long enough
--> $DIR/ref-mut-self-async.rs:30:9
| let's call the lifetime of this reference `'2`
LL | f
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ |
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn box_ref_Self<'a>(self: Box<&'a mut Self>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error: lifetime may not live long enough
--> $DIR/ref-mut-self-async.rs:36:9
| let's call the lifetime of this reference `'2`
LL | f
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ |
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn pin_ref_Self<'a>(self: Pin<&'a mut Self>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error: lifetime may not live long enough
--> $DIR/ref-mut-self-async.rs:42:9
| let's call the lifetime of this reference `'2`
LL | f
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ |
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn box_box_ref_Self<'a>(self: Box<Box<&'a mut Self>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error: lifetime may not live long enough
--> $DIR/ref-mut-self-async.rs:48:9
| let's call the lifetime of this reference `'2`
LL | f
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ |
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn box_pin_ref_Self<'a>(self: Box<Pin<&'a mut Self>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error: aborting due to 6 previous errors
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn ref_Struct<'a>(self: &'a mut Struct, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error[E0623]: lifetime mismatch
--> $DIR/ref-mut-struct-async.rs:22:9
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn box_ref_Struct<'a>(self: Box<&'a mut Struct>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error[E0623]: lifetime mismatch
--> $DIR/ref-mut-struct-async.rs:28:9
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn pin_ref_Struct<'a>(self: Pin<&'a mut Struct>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error[E0623]: lifetime mismatch
--> $DIR/ref-mut-struct-async.rs:34:9
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn box_box_ref_Struct<'a>(self: Box<Box<&'a mut Struct>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error[E0623]: lifetime mismatch
--> $DIR/ref-mut-struct-async.rs:40:9
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn box_pin_ref_Struct<'a>(self: Box<Pin<&'a mut Struct>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error: aborting due to 5 previous errors
| let's call the lifetime of this reference `'2`
LL | f
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ |
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn ref_Struct<'a>(self: &'a mut Struct, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error: lifetime may not live long enough
--> $DIR/ref-mut-struct-async.rs:22:9
| let's call the lifetime of this reference `'2`
LL | f
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ |
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn box_ref_Struct<'a>(self: Box<&'a mut Struct>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error: lifetime may not live long enough
--> $DIR/ref-mut-struct-async.rs:28:9
| let's call the lifetime of this reference `'2`
LL | f
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ |
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn pin_ref_Struct<'a>(self: Pin<&'a mut Struct>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error: lifetime may not live long enough
--> $DIR/ref-mut-struct-async.rs:34:9
| let's call the lifetime of this reference `'2`
LL | f
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ |
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn box_box_ref_Struct<'a>(self: Box<Box<&'a mut Struct>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error: lifetime may not live long enough
--> $DIR/ref-mut-struct-async.rs:40:9
| let's call the lifetime of this reference `'2`
LL | f
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ |
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn box_pin_ref_Struct<'a>(self: Box<Pin<&'a mut Struct>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error: aborting due to 5 previous errors
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error[E0623]: lifetime mismatch
--> $DIR/ref-self-async.rs:34:9
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error[E0623]: lifetime mismatch
--> $DIR/ref-self-async.rs:40:9
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error[E0623]: lifetime mismatch
--> $DIR/ref-self-async.rs:46:9
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error[E0623]: lifetime mismatch
--> $DIR/ref-self-async.rs:52:9
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn box_box_ref_Self<'a>(self: Box<Box<&'a Self>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error[E0623]: lifetime mismatch
--> $DIR/ref-self-async.rs:58:9
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn box_pin_ref_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error[E0623]: lifetime mismatch
--> $DIR/ref-self-async.rs:64:9
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn wrap_ref_Self_Self<'a>(self: Wrap<&'a Self, Self>, f: &'a u8) -> &u8 {
+ | ++++ ++ ++
error: aborting due to 7 previous errors
| let's call the lifetime of this reference `'2`
LL | f
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ |
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error: lifetime may not live long enough
--> $DIR/ref-self-async.rs:34:9
| let's call the lifetime of this reference `'2`
LL | f
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ |
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error: lifetime may not live long enough
--> $DIR/ref-self-async.rs:40:9
| let's call the lifetime of this reference `'2`
LL | f
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ |
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error: lifetime may not live long enough
--> $DIR/ref-self-async.rs:46:9
| let's call the lifetime of this reference `'2`
LL | f
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ |
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error: lifetime may not live long enough
--> $DIR/ref-self-async.rs:52:9
| let's call the lifetime of this reference `'2`
LL | f
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ |
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn box_box_ref_Self<'a>(self: Box<Box<&'a Self>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error: lifetime may not live long enough
--> $DIR/ref-self-async.rs:58:9
| let's call the lifetime of this reference `'2`
LL | f
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ |
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn box_pin_ref_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error: lifetime may not live long enough
--> $DIR/ref-self-async.rs:64:9
| let's call the lifetime of this reference `'2`
LL | f
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ |
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn wrap_ref_Self_Self<'a>(self: Wrap<&'a Self, Self>, f: &'a u8) -> &u8 {
+ | ++++ ++ ++
error: aborting due to 7 previous errors
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn ref_Struct<'a>(self: &'a Struct, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error[E0623]: lifetime mismatch
--> $DIR/ref-struct-async.rs:22:9
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn box_ref_Struct<'a>(self: Box<&'a Struct>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error[E0623]: lifetime mismatch
--> $DIR/ref-struct-async.rs:28:9
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn pin_ref_Struct<'a>(self: Pin<&'a Struct>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error[E0623]: lifetime mismatch
--> $DIR/ref-struct-async.rs:34:9
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn box_box_ref_Struct<'a>(self: Box<Box<&'a Struct>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error[E0623]: lifetime mismatch
--> $DIR/ref-struct-async.rs:40:9
| this parameter and the return type are declared with different lifetimes...
LL | f
| ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn box_pin_Struct<'a>(self: Box<Pin<&'a Struct>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error: aborting due to 5 previous errors
| let's call the lifetime of this reference `'2`
LL | f
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ |
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn ref_Struct<'a>(self: &'a Struct, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error: lifetime may not live long enough
--> $DIR/ref-struct-async.rs:22:9
| let's call the lifetime of this reference `'2`
LL | f
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ |
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn box_ref_Struct<'a>(self: Box<&'a Struct>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error: lifetime may not live long enough
--> $DIR/ref-struct-async.rs:28:9
| let's call the lifetime of this reference `'2`
LL | f
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ |
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn pin_ref_Struct<'a>(self: Pin<&'a Struct>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error: lifetime may not live long enough
--> $DIR/ref-struct-async.rs:34:9
| let's call the lifetime of this reference `'2`
LL | f
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ |
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn box_box_ref_Struct<'a>(self: Box<Box<&'a Struct>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error: lifetime may not live long enough
--> $DIR/ref-struct-async.rs:40:9
| let's call the lifetime of this reference `'2`
LL | f
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ |
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | async fn box_pin_Struct<'a>(self: Box<Pin<&'a Struct>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
error: aborting due to 5 previous errors
|
LL | use core::simd::intrinsics;
| ^^^^ maybe a missing crate `core`?
+ |
+ = help: consider adding `extern crate core` to use the `core` crate
error[E0432]: unresolved import `std::simd::intrinsics`
--> $DIR/portable-intrinsics-arent-exposed.rs:5:5
-error[E0282]: type annotations needed for `Option<_>`
- --> $DIR/issue-42234-unknown-receiver-type.rs:10:7
+error[E0282]: type annotations needed
+ --> $DIR/issue-42234-unknown-receiver-type.rs:9:24
|
LL | let x: Option<_> = None;
- | - consider giving `x` the explicit type `Option<_>`, where the type parameter `T` is specified
-LL | x.unwrap().method_that_could_exist_on_some_type();
- | ^^^^^^ cannot infer type for type parameter `T`
+ | ^^^^ cannot infer type of the type parameter `T` declared on the enum `Option`
|
= note: type must be known at this point
+help: consider specifying the generic argument
+ |
+LL | let x: Option<_> = None::<T>;
+ | +++++
error[E0282]: type annotations needed
- --> $DIR/issue-42234-unknown-receiver-type.rs:16:10
+ --> $DIR/issue-42234-unknown-receiver-type.rs:15:10
|
LL | .sum::<_>()
- | ^^^ cannot infer type
+ | ^^^ cannot infer type of the type parameter `S` declared on the associated function `sum`
|
= note: type must be known at this point
+help: consider specifying the generic argument
+ |
+LL | .sum::<_>()
+ | ~~~~~
error: aborting due to 2 previous errors
-error[E0282]: type annotations needed for `Option<_>`
- --> $DIR/issue-42234-unknown-receiver-type.rs:10:7
+error[E0282]: type annotations needed
+ --> $DIR/issue-42234-unknown-receiver-type.rs:9:24
|
LL | let x: Option<_> = None;
- | - consider giving `x` the explicit type `Option<_>`, where the type parameter `T` is specified
-LL | x.unwrap().method_that_could_exist_on_some_type();
- | ^^^^^^ cannot infer type for type parameter `T`
+ | ^^^^ cannot infer type of the type parameter `T` declared on the enum `Option`
|
= note: type must be known at this point
+help: consider specifying the generic argument
+ |
+LL | let x: Option<_> = None::<T>;
+ | +++++
error[E0282]: type annotations needed
- --> $DIR/issue-42234-unknown-receiver-type.rs:16:16
+ --> $DIR/issue-42234-unknown-receiver-type.rs:15:10
|
LL | .sum::<_>()
- | ^ cannot infer type for type parameter `S` declared on the associated function `sum`
+ | ^^^ cannot infer type of the type parameter `S` declared on the associated function `sum`
|
= note: type must be known at this point
+help: consider specifying the generic argument
+ |
+LL | .sum::<S>()
+ | ~~~~~
error: aborting due to 2 previous errors
// the fix of which this tests).
fn shines_a_beacon_through_the_darkness() {
- let x: Option<_> = None;
+ let x: Option<_> = None; //~ ERROR type annotations needed
x.unwrap().method_that_could_exist_on_some_type();
- //~^ ERROR type annotations needed
}
fn courier_to_des_moines_and_points_west(data: &[u32]) -> String {
fn main() {
let mut x = Default::default();
- x.0;
//~^ ERROR type annotations needed
+ x.0;
x = 1;
}
fn foo() {
let mut x = Default::default();
- x[0];
//~^ ERROR type annotations needed
+ x[0];
x = 1;
}
error[E0282]: type annotations needed
- --> $DIR/method-and-field-eager-resolution.rs:5:5
+ --> $DIR/method-and-field-eager-resolution.rs:4:9
|
LL | let mut x = Default::default();
- | ----- consider giving `x` a type
-LL | x.0;
- | ^ cannot infer type
+ | ^^^^^
|
= note: type must be known at this point
+help: consider giving `x` an explicit type
+ |
+LL | let mut x: _ = Default::default();
+ | +++
error[E0282]: type annotations needed
- --> $DIR/method-and-field-eager-resolution.rs:12:5
+ --> $DIR/method-and-field-eager-resolution.rs:11:9
|
LL | let mut x = Default::default();
- | ----- consider giving `x` a type
-LL | x[0];
- | ^ cannot infer type
+ | ^^^^^
|
= note: type must be known at this point
+help: consider giving `x` an explicit type
+ |
+LL | let mut x: _ = Default::default();
+ | +++
error: aborting due to 2 previous errors
--> $DIR/type-annotations-needed-expr.rs:2:39
|
LL | let _ = (vec![1,2,3]).into_iter().sum() as f64;
- | ^^^ cannot infer type for type parameter `S` declared on the associated function `sum`
+ | ^^^ cannot infer type of the type parameter `S` declared on the associated function `sum`
|
= note: type must be known at this point
-help: consider specifying the type argument in the method call
+help: consider specifying the generic argument
|
LL | let _ = (vec![1,2,3]).into_iter().sum::<S>() as f64;
| +++++
//~^ ERROR expected struct, variant or union type, found associated type
let z = T::A::<u8> {};
//~^ ERROR expected struct, variant or union type, found associated type
- //~| ERROR type arguments are not allowed for this type
+ //~| ERROR type arguments are not allowed on this type
match S {
T::A {} => {}
//~^ ERROR expected struct, variant or union type, found associated type
fn g<T: Tr<A = S>>() {
let s = T::A {}; // OK
- let z = T::A::<u8> {}; //~ ERROR type arguments are not allowed for this type
+ let z = T::A::<u8> {}; //~ ERROR type arguments are not allowed on this type
match S {
T::A {} => {} // OK
}
LL | let s = T::A {};
| ^^^^ not a struct
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
--> $DIR/struct-path-associated-type.rs:14:20
|
LL | let z = T::A::<u8> {};
- | ^^ type argument not allowed
+ | - ^^ type argument not allowed
+ | |
+ | not allowed on this
error[E0071]: expected struct, variant or union type, found associated type
--> $DIR/struct-path-associated-type.rs:14:13
LL | T::A {} => {}
| ^^^^ not a struct
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
--> $DIR/struct-path-associated-type.rs:25:20
|
LL | let z = T::A::<u8> {};
- | ^^ type argument not allowed
+ | - ^^ type argument not allowed
+ | |
+ | not allowed on this
error[E0223]: ambiguous associated type
--> $DIR/struct-path-associated-type.rs:32:13
//~^ ERROR expected struct, variant or union type, found type parameter
let z = Self::<u8> {};
//~^ ERROR expected struct, variant or union type, found type parameter
- //~| ERROR type arguments are not allowed for this type
+ //~| ERROR type arguments are not allowed on self type
match s {
Self { .. } => {}
//~^ ERROR expected struct, variant or union type, found type parameter
impl Tr for S {
fn f() {
let s = Self {}; // OK
- let z = Self::<u8> {}; //~ ERROR type arguments are not allowed for this type
+ let z = Self::<u8> {}; //~ ERROR type arguments are not allowed on self type
match s {
Self { .. } => {} // OK
}
impl S {
fn g() {
let s = Self {}; // OK
- let z = Self::<u8> {}; //~ ERROR type arguments are not allowed for this type
+ let z = Self::<u8> {}; //~ ERROR type arguments are not allowed on self type
match s {
Self { .. } => {} // OK
}
LL | let s = Self {};
| ^^^^ not a struct
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on self type
--> $DIR/struct-path-self.rs:7:24
|
LL | let z = Self::<u8> {};
- | ^^ type argument not allowed
+ | ---- ^^ type argument not allowed
+ | |
+ | not allowed on this
+ |
+help: the `Self` type doesn't accept type parameters
+ |
+LL - let z = Self::<u8> {};
+LL + let z = Self {};
+ |
error[E0071]: expected struct, variant or union type, found type parameter `Self`
--> $DIR/struct-path-self.rs:7:17
LL | Self { .. } => {}
| ^^^^ not a struct
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on self type
--> $DIR/struct-path-self.rs:20:24
|
LL | let z = Self::<u8> {};
- | ^^ type argument not allowed
+ | ---- ^^ type argument not allowed
+ | |
+ | not allowed on this
+ |
+note: `Self` is of type `S`
+ --> $DIR/struct-path-self.rs:1:8
+ |
+LL | struct S;
+ | ^ `Self` corresponds to this type, which doesn't have generic parameters
+...
+LL | impl Tr for S {
+ | ------------- `Self` is on type `S` in this `impl`
+help: the `Self` type doesn't accept type parameters
+ |
+LL - let z = Self::<u8> {};
+LL + let z = Self {};
+ |
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on self type
--> $DIR/struct-path-self.rs:30:24
|
LL | let z = Self::<u8> {};
- | ^^ type argument not allowed
+ | ---- ^^ type argument not allowed
+ | |
+ | not allowed on this
+ |
+note: `Self` is of type `S`
+ --> $DIR/struct-path-self.rs:1:8
+ |
+LL | struct S;
+ | ^ `Self` corresponds to this type, which doesn't have generic parameters
+...
+LL | impl S {
+ | ------ `Self` is on type `S` in this `impl`
+help: the `Self` type doesn't accept type parameters
+ |
+LL - let z = Self::<u8> {};
+LL + let z = Self {};
+ |
error: aborting due to 6 previous errors
--- /dev/null
+// compile-flags: --edition=2021
+// run-rustfix
+
+#![allow(unused)]
+
+struct Foo;
+
+impl Foo {
+ fn get(&self) -> u8 {
+ 42
+ }
+}
+
+fn test_result_in_result() -> Result<(), ()> {
+ let res: Result<_, ()> = Ok(Foo);
+ res?.get();
+ //~^ ERROR no method named `get` found for enum `Result` in the current scope
+ //~| HELP use the `?` operator
+ Ok(())
+}
+
+async fn async_test_result_in_result() -> Result<(), ()> {
+ let res: Result<_, ()> = Ok(Foo);
+ res?.get();
+ //~^ ERROR no method named `get` found for enum `Result` in the current scope
+ //~| HELP use the `?` operator
+ Ok(())
+}
+
+fn test_result_in_unit_return() {
+ let res: Result<_, ()> = Ok(Foo);
+ res.expect("REASON").get();
+ //~^ ERROR no method named `get` found for enum `Result` in the current scope
+ //~| HELP consider using `Result::expect` to unwrap the `Foo` value, panicking if the value is a `Result::Err`
+}
+
+async fn async_test_result_in_unit_return() {
+ let res: Result<_, ()> = Ok(Foo);
+ res.expect("REASON").get();
+ //~^ ERROR no method named `get` found for enum `Result` in the current scope
+ //~| HELP consider using `Result::expect` to unwrap the `Foo` value, panicking if the value is a `Result::Err`
+}
+
+fn test_option_in_option() -> Option<()> {
+ let res: Option<_> = Some(Foo);
+ res?.get();
+ //~^ ERROR no method named `get` found for enum `Option` in the current scope
+ //~| HELP use the `?` operator
+ Some(())
+}
+
+fn test_option_in_unit_return() {
+ let res: Option<_> = Some(Foo);
+ res.expect("REASON").get();
+ //~^ ERROR no method named `get` found for enum `Option` in the current scope
+ //~| HELP consider using `Option::expect` to unwrap the `Foo` value, panicking if the value is an `Option::None`
+}
+
+fn main() {}
--- /dev/null
+// compile-flags: --edition=2021
+// run-rustfix
+
+#![allow(unused)]
+
+struct Foo;
+
+impl Foo {
+ fn get(&self) -> u8 {
+ 42
+ }
+}
+
+fn test_result_in_result() -> Result<(), ()> {
+ let res: Result<_, ()> = Ok(Foo);
+ res.get();
+ //~^ ERROR no method named `get` found for enum `Result` in the current scope
+ //~| HELP use the `?` operator
+ Ok(())
+}
+
+async fn async_test_result_in_result() -> Result<(), ()> {
+ let res: Result<_, ()> = Ok(Foo);
+ res.get();
+ //~^ ERROR no method named `get` found for enum `Result` in the current scope
+ //~| HELP use the `?` operator
+ Ok(())
+}
+
+fn test_result_in_unit_return() {
+ let res: Result<_, ()> = Ok(Foo);
+ res.get();
+ //~^ ERROR no method named `get` found for enum `Result` in the current scope
+ //~| HELP consider using `Result::expect` to unwrap the `Foo` value, panicking if the value is a `Result::Err`
+}
+
+async fn async_test_result_in_unit_return() {
+ let res: Result<_, ()> = Ok(Foo);
+ res.get();
+ //~^ ERROR no method named `get` found for enum `Result` in the current scope
+ //~| HELP consider using `Result::expect` to unwrap the `Foo` value, panicking if the value is a `Result::Err`
+}
+
+fn test_option_in_option() -> Option<()> {
+ let res: Option<_> = Some(Foo);
+ res.get();
+ //~^ ERROR no method named `get` found for enum `Option` in the current scope
+ //~| HELP use the `?` operator
+ Some(())
+}
+
+fn test_option_in_unit_return() {
+ let res: Option<_> = Some(Foo);
+ res.get();
+ //~^ ERROR no method named `get` found for enum `Option` in the current scope
+ //~| HELP consider using `Option::expect` to unwrap the `Foo` value, panicking if the value is an `Option::None`
+}
+
+fn main() {}
--- /dev/null
+error[E0599]: no method named `get` found for enum `Result` in the current scope
+ --> $DIR/enum-method-probe.rs:24:9
+ |
+LL | res.get();
+ | ^^^ method not found in `Result<Foo, ()>`
+ |
+note: the method `get` exists on the type `Foo`
+ --> $DIR/enum-method-probe.rs:9:5
+ |
+LL | fn get(&self) -> u8 {
+ | ^^^^^^^^^^^^^^^^^^^
+help: use the `?` operator to extract the `Foo` value, propagating a `Result::Err` value to the caller
+ |
+LL | res?.get();
+ | +
+
+error[E0599]: no method named `get` found for enum `Result` in the current scope
+ --> $DIR/enum-method-probe.rs:39:9
+ |
+LL | res.get();
+ | ^^^ method not found in `Result<Foo, ()>`
+ |
+note: the method `get` exists on the type `Foo`
+ --> $DIR/enum-method-probe.rs:9:5
+ |
+LL | fn get(&self) -> u8 {
+ | ^^^^^^^^^^^^^^^^^^^
+help: consider using `Result::expect` to unwrap the `Foo` value, panicking if the value is a `Result::Err`
+ |
+LL | res.expect("REASON").get();
+ | +++++++++++++++++
+
+error[E0599]: no method named `get` found for enum `Result` in the current scope
+ --> $DIR/enum-method-probe.rs:16:9
+ |
+LL | res.get();
+ | ^^^ method not found in `Result<Foo, ()>`
+ |
+note: the method `get` exists on the type `Foo`
+ --> $DIR/enum-method-probe.rs:9:5
+ |
+LL | fn get(&self) -> u8 {
+ | ^^^^^^^^^^^^^^^^^^^
+help: use the `?` operator to extract the `Foo` value, propagating a `Result::Err` value to the caller
+ |
+LL | res?.get();
+ | +
+
+error[E0599]: no method named `get` found for enum `Result` in the current scope
+ --> $DIR/enum-method-probe.rs:32:9
+ |
+LL | res.get();
+ | ^^^ method not found in `Result<Foo, ()>`
+ |
+note: the method `get` exists on the type `Foo`
+ --> $DIR/enum-method-probe.rs:9:5
+ |
+LL | fn get(&self) -> u8 {
+ | ^^^^^^^^^^^^^^^^^^^
+help: consider using `Result::expect` to unwrap the `Foo` value, panicking if the value is a `Result::Err`
+ |
+LL | res.expect("REASON").get();
+ | +++++++++++++++++
+
+error[E0599]: no method named `get` found for enum `Option` in the current scope
+ --> $DIR/enum-method-probe.rs:46:9
+ |
+LL | res.get();
+ | ^^^ method not found in `Option<Foo>`
+ |
+note: the method `get` exists on the type `Foo`
+ --> $DIR/enum-method-probe.rs:9:5
+ |
+LL | fn get(&self) -> u8 {
+ | ^^^^^^^^^^^^^^^^^^^
+help: use the `?` operator to extract the `Foo` value, propagating an `Option::None` value to the caller
+ |
+LL | res?.get();
+ | +
+
+error[E0599]: no method named `get` found for enum `Option` in the current scope
+ --> $DIR/enum-method-probe.rs:54:9
+ |
+LL | res.get();
+ | ^^^ method not found in `Option<Foo>`
+ |
+note: the method `get` exists on the type `Foo`
+ --> $DIR/enum-method-probe.rs:9:5
+ |
+LL | fn get(&self) -> u8 {
+ | ^^^^^^^^^^^^^^^^^^^
+help: consider using `Option::expect` to unwrap the `Foo` value, panicking if the value is an `Option::None`
+ |
+LL | res.expect("REASON").get();
+ | +++++++++++++++++
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
fn f<A>() -> A { unimplemented!() }
fn foo() {
- let _ = f; //~ ERROR type annotations needed for `fn() -> A`
+ let _ = f;
+ //~^ ERROR type annotations needed
+ //~| HELP consider specifying the generic argument
}
fn main() {}
-error[E0282]: type annotations needed for `fn() -> A`
+error[E0282]: type annotations needed
--> $DIR/fn-needing-specified-return-type-param.rs:3:13
|
LL | let _ = f;
- | - ^ cannot infer type for type parameter `A` declared on the function `f`
- | |
- | consider giving this pattern the explicit type `fn() -> A`, where the type parameter `A` is specified
+ | ^ cannot infer type of the type parameter `A` declared on the function `f`
|
-help: type parameter declared here
- --> $DIR/fn-needing-specified-return-type-param.rs:1:6
+help: consider specifying the generic argument
|
-LL | fn f<A>() -> A { unimplemented!() }
- | ^
+LL | let _ = f::<A>;
+ | +++++
error: aborting due to previous error
--- /dev/null
+// run-rustfix
+use std::fmt::Debug;
+
+#[derive(Debug, Copy, Clone)]
+pub struct Vector2<T: Debug + Copy + Clone>{
+ pub x: T,
+ pub y: T
+}
+
+#[derive(Debug, Copy, Clone)]
+pub struct AABB<K: Debug + std::marker::Copy>{
+ pub loc: Vector2<K>, //~ ERROR the trait bound `K: Copy` is not satisfied
+ pub size: Vector2<K>
+}
+
+fn main() {}
--- /dev/null
+// run-rustfix
+use std::fmt::Debug;
+
+#[derive(Debug, Copy, Clone)]
+pub struct Vector2<T: Debug + Copy + Clone>{
+ pub x: T,
+ pub y: T
+}
+
+#[derive(Debug, Copy, Clone)]
+pub struct AABB<K: Debug>{
+ pub loc: Vector2<K>, //~ ERROR the trait bound `K: Copy` is not satisfied
+ pub size: Vector2<K>
+}
+
+fn main() {}
--- /dev/null
+error[E0277]: the trait bound `K: Copy` is not satisfied
+ --> $DIR/missing-bound-in-derive-copy-impl-2.rs:12:14
+ |
+LL | pub loc: Vector2<K>,
+ | ^^^^^^^^^^ the trait `Copy` is not implemented for `K`
+ |
+note: required by a bound in `Vector2`
+ --> $DIR/missing-bound-in-derive-copy-impl-2.rs:5:31
+ |
+LL | pub struct Vector2<T: Debug + Copy + Clone>{
+ | ^^^^ required by this bound in `Vector2`
+help: consider further restricting this bound
+ |
+LL | pub struct AABB<K: Debug + std::marker::Copy>{
+ | +++++++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+//run-rustfix
+use std::fmt::Debug;
+
+#[derive(Debug, Copy, Clone)]
+pub struct Vector2<T: Debug + Copy + Clone>{
+ pub x: T,
+ pub y: T
+}
+
+#[derive(Debug, Copy, Clone)] //~ ERROR the trait `Copy` may not be implemented for this type
+pub struct AABB<K: Copy + Debug>{
+ pub loc: Vector2<K>,
+ pub size: Vector2<K>
+}
+
+fn main() {}
--- /dev/null
+//run-rustfix
+use std::fmt::Debug;
+
+#[derive(Debug, Copy, Clone)]
+pub struct Vector2<T: Debug + Copy + Clone>{
+ pub x: T,
+ pub y: T
+}
+
+#[derive(Debug, Copy, Clone)] //~ ERROR the trait `Copy` may not be implemented for this type
+pub struct AABB<K: Copy>{
+ pub loc: Vector2<K>,
+ pub size: Vector2<K>
+}
+
+fn main() {}
--- /dev/null
+error[E0204]: the trait `Copy` may not be implemented for this type
+ --> $DIR/missing-bound-in-derive-copy-impl-3.rs:10:17
+ |
+LL | #[derive(Debug, Copy, Clone)]
+ | ^^^^
+LL | pub struct AABB<K: Copy>{
+LL | pub loc: Vector2<K>,
+ | ------------------- this field does not implement `Copy`
+LL | pub size: Vector2<K>
+ | -------------------- this field does not implement `Copy`
+ |
+note: the `Copy` impl for `Vector2<K>` requires that `K: Debug`
+ --> $DIR/missing-bound-in-derive-copy-impl-3.rs:12:14
+ |
+LL | pub loc: Vector2<K>,
+ | ^^^^^^^^^^
+LL | pub size: Vector2<K>
+ | ^^^^^^^^^^
+ = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider further restricting this bound
+ |
+LL | pub struct AABB<K: Copy + Debug>{
+ | +++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0204`.
--- /dev/null
+use std::fmt::Debug;
+
+#[derive(Debug, Copy, Clone)]
+pub struct Vector2<T: Debug + Copy + Clone>{
+ pub x: T,
+ pub y: T
+}
+
+#[derive(Debug, Copy, Clone)] //~ ERROR the trait `Copy` may not be implemented for this type
+pub struct AABB<K>{
+ pub loc: Vector2<K>,
+ pub size: Vector2<K>
+}
+
+fn main() {}
--- /dev/null
+error[E0204]: the trait `Copy` may not be implemented for this type
+ --> $DIR/missing-bound-in-derive-copy-impl.rs:9:17
+ |
+LL | #[derive(Debug, Copy, Clone)]
+ | ^^^^
+LL | pub struct AABB<K>{
+LL | pub loc: Vector2<K>,
+ | ------------------- this field does not implement `Copy`
+LL | pub size: Vector2<K>
+ | -------------------- this field does not implement `Copy`
+ |
+note: the `Copy` impl for `Vector2<K>` requires that `K: Debug`
+ --> $DIR/missing-bound-in-derive-copy-impl.rs:11:14
+ |
+LL | pub loc: Vector2<K>,
+ | ^^^^^^^^^^
+LL | pub size: Vector2<K>
+ | ^^^^^^^^^^
+ = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider restricting type parameter `K`
+ |
+LL | pub struct AABB<K: Debug>{
+ | +++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0204`.
+fn unbound_drop(_: impl Sized) {}
+
fn main() {
- let _v = || -> _ { [] }; //~ ERROR type annotations needed for the closure
+ unbound_drop(|| -> _ { [] });
+ //~^ ERROR type annotations needed for `[_; 0]`
+ //~| HELP try giving this closure an explicit return type
}
-error[E0282]: type annotations needed for the closure `fn() -> [_; 0]`
- --> $DIR/suggest-closure-return-type-1.rs:2:24
+error[E0282]: type annotations needed for `[_; 0]`
+ --> $DIR/suggest-closure-return-type-1.rs:4:18
|
-LL | let _v = || -> _ { [] };
- | ^^ cannot infer type
+LL | unbound_drop(|| -> _ { [] });
+ | ^^^^^^^
|
-help: give this closure an explicit return type without `_` placeholders
+help: try giving this closure an explicit return type
|
-LL | let _v = || -> [_; 0] { [] };
- | ~~~~~~
+LL | unbound_drop(|| -> [_; 0] { [] });
+ | ~~~~~~
error: aborting due to previous error
+fn unbound_drop(_: impl Sized) {}
+
fn main() {
- let _v = || { [] }; //~ ERROR type annotations needed for the closure
+ unbound_drop(|| { [] })
+ //~^ ERROR type annotations needed for `[_; 0]`
+ //~| HELP try giving this closure an explicit return type
}
-error[E0282]: type annotations needed for the closure `fn() -> [_; 0]`
- --> $DIR/suggest-closure-return-type-2.rs:2:19
+error[E0282]: type annotations needed for `[_; 0]`
+ --> $DIR/suggest-closure-return-type-2.rs:4:18
|
-LL | let _v = || { [] };
- | ^^ cannot infer type
+LL | unbound_drop(|| { [] })
+ | ^^
|
-help: give this closure an explicit return type without `_` placeholders
+help: try giving this closure an explicit return type
|
-LL | let _v = || -> [_; 0] { [] };
- | +++++++++
+LL | unbound_drop(|| -> [_; 0] { [] })
+ | +++++++++
error: aborting due to previous error
+fn unbound_drop(_: impl Sized) {}
+
fn main() {
- let _v = || []; //~ ERROR type annotations needed for the closure
+ unbound_drop(|| []);
+ //~^ ERROR type annotations needed for `[_; 0]`
+ //~| HELP try giving this closure an explicit return type
}
-error[E0282]: type annotations needed for the closure `fn() -> [_; 0]`
- --> $DIR/suggest-closure-return-type-3.rs:2:17
+error[E0282]: type annotations needed for `[_; 0]`
+ --> $DIR/suggest-closure-return-type-3.rs:4:18
|
-LL | let _v = || [];
- | ^^ cannot infer type
+LL | unbound_drop(|| []);
+ | ^^
|
-help: give this closure an explicit return type without `_` placeholders
+help: try giving this closure an explicit return type
|
-LL | let _v = || -> [_; 0] { [] };
- | +++++++++++ +
+LL | unbound_drop(|| -> [_; 0] { [] });
+ | +++++++++++ +
error: aborting due to previous error
--> $DIR/do-not-mention-type-params-by-name-in-suggestion-issue-96292.rs:17:11
|
LL | thing.method(42);
- | ------^^^^^^----
- | | |
- | | cannot infer type for type parameter `T` declared on the trait `Method`
- | this method call resolves to `T`
+ | ^^^^^^
+ |
+help: try using a fully qualified path to specify the expected types
+ |
+LL | <Thing<bool> as Method<T>>::method(thing, 42);
+ | +++++++++++++++++++++++++++++++++++ ~
error[E0283]: type annotations needed
--> $DIR/do-not-mention-type-params-by-name-in-suggestion-issue-96292.rs:17:11
|
LL | thing.method(42);
- | ------^^^^^^----
- | | |
- | | cannot infer type for type parameter `T` declared on the trait `Method`
- | this method call resolves to `T`
+ | ^^^^^^
|
note: multiple `impl`s satisfying `Thing<bool>: Method<_>` found
--> $DIR/do-not-mention-type-params-by-name-in-suggestion-issue-96292.rs:7:1
...
LL | impl<X> Method<u32> for Thing<X> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: use the fully qualified path for the potential candidates
+help: try using a fully qualified path to specify the expected types
|
-LL | <Thing<_> as Method<i32>>::method(thing, 42);
- | ++++++++++++++++++++++++++++++++++ ~
-LL | <Thing<_> as Method<u32>>::method(thing, 42);
- | ++++++++++++++++++++++++++++++++++ ~
+LL | <Thing<bool> as Method<T>>::method(thing, 42);
+ | +++++++++++++++++++++++++++++++++++ ~
error: aborting due to 2 previous errors
--> $DIR/issue-77982.rs:8:10
|
LL | opts.get(opt.as_ref());
- | ^^^ ------------ this method call resolves to `&T`
- | |
- | cannot infer type for type parameter `Q` declared on the associated function `get`
+ | ^^^ cannot infer type of the type parameter `Q` declared on the associated function `get`
|
= note: multiple `impl`s satisfying `String: Borrow<_>` found in the following crates: `alloc`, `core`:
- impl Borrow<str> for String;
|
LL | K: Borrow<Q>,
| ^^^^^^^^^ required by this bound in `HashMap::<K, V, S>::get`
+help: consider specifying the generic argument
+ |
+LL | opts.get::<Q>(opt.as_ref());
+ | +++++
help: consider specifying the type argument in the function call
|
LL | opts.get::<Q>(opt.as_ref());
| +++++
error[E0283]: type annotations needed
- --> $DIR/issue-77982.rs:8:18
+ --> $DIR/issue-77982.rs:8:10
|
LL | opts.get(opt.as_ref());
- | ----^^^^^^--
- | | |
- | | cannot infer type for type parameter `T` declared on the trait `AsRef`
- | this method call resolves to `&T`
+ | ^^^ cannot infer type of the type parameter `Q` declared on the associated function `get`
|
= note: multiple `impl`s satisfying `String: AsRef<_>` found in the following crates: `alloc`, `std`:
- impl AsRef<OsStr> for String;
- impl AsRef<Path> for String;
- impl AsRef<[u8]> for String;
- impl AsRef<str> for String;
-help: use the fully qualified path for the potential candidates
- |
-LL | opts.get(<String as AsRef<OsStr>>::as_ref(opt));
- | +++++++++++++++++++++++++++++++++ ~
-LL | opts.get(<String as AsRef<Path>>::as_ref(opt));
- | ++++++++++++++++++++++++++++++++ ~
-LL | opts.get(<String as AsRef<[u8]>>::as_ref(opt));
- | ++++++++++++++++++++++++++++++++ ~
-LL | opts.get(<String as AsRef<str>>::as_ref(opt));
- | +++++++++++++++++++++++++++++++ ~
- and 4 other candidates
+help: consider specifying the generic argument
+ |
+LL | opts.get::<Q>(opt.as_ref());
+ | +++++
error[E0283]: type annotations needed
- --> $DIR/issue-77982.rs:13:44
+ --> $DIR/issue-77982.rs:13:59
|
LL | let ips: Vec<_> = (0..100_000).map(|_| u32::from(0u32.into())).collect();
- | ^^^^^^^^^ ----------- this method call resolves to `T`
- | |
- | cannot infer type for type parameter `T` declared on the trait `From`
+ | ^^^^
|
= note: multiple `impl`s satisfying `u32: From<_>` found in the following crates: `core`, `std`:
- impl From<Ipv4Addr> for u32;
- impl From<bool> for u32;
- impl From<char> for u32;
and 3 more
+help: try using a fully qualified path to specify the expected types
+ |
+LL | let ips: Vec<_> = (0..100_000).map(|_| u32::from(<u32 as Into<T>>::into(0u32))).collect();
+ | +++++++++++++++++++++++ ~
error[E0283]: type annotations needed for `Box<T>`
- --> $DIR/issue-77982.rs:36:16
+ --> $DIR/issue-77982.rs:36:9
|
LL | let _ = ().foo();
- | - ^^^ cannot infer type for type parameter `T` declared on the trait `Foo`
- | |
- | consider giving this pattern the explicit type `Box<T>`, where the type parameter `T` is specified
+ | ^
|
note: multiple `impl`s satisfying `(): Foo<'_, _>` found
--> $DIR/issue-77982.rs:29:1
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | impl<'a> Foo<'a, i16> for () {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider giving this pattern a type, where the type for type parameter `T` is specified
+ |
+LL | let _: Box<T> = ().foo();
+ | ++++++++
error[E0283]: type annotations needed for `Box<T>`
- --> $DIR/issue-77982.rs:40:19
+ --> $DIR/issue-77982.rs:40:9
|
LL | let _ = (&()).bar();
- | - ^^^ cannot infer type for type parameter `T` declared on the trait `Bar`
- | |
- | consider giving this pattern the explicit type `Box<T>`, where the type parameter `T` is specified
+ | ^
|
note: multiple `impl`s satisfying `&(): Bar<'_, _>` found
--> $DIR/issue-77982.rs:32:1
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | impl<'a> Bar<'a, i16> for &'a () {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider giving this pattern a type, where the type for type parameter `T` is specified
+ |
+LL | let _: Box<T> = (&()).bar();
+ | ++++++++
error: aborting due to 5 previous errors
--- /dev/null
+// Test that duplicate methods in impls are not allowed
+
+struct Foo;
+
+trait Bar {
+ fn bar(&self) -> isize;
+}
+
+impl Bar for Foo {
+ fn bar(&self) -> isize {1}
+ fn bar(&self) -> isize {2} //~ ERROR duplicate definitions
+}
+
+fn main() {
+ println!("{}", Foo.bar());
+}
--- /dev/null
+error[E0201]: duplicate definitions with name `bar`:
+ --> $DIR/issue-8153.rs:11:5
+ |
+LL | fn bar(&self) -> isize {1}
+ | -------------------------- previous definition of `bar` here
+LL | fn bar(&self) -> isize {2}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definition
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0201`.
--- /dev/null
+struct Foo {
+ bar: String,
+}
+
+impl Foo {
+ pub fn new(bar: impl ToString) -> Self {
+ Self {
+ bar: bar.into(), //~ ERROR the trait bound `String: From<impl ToString>` is not satisfied
+ }
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0277]: the trait bound `String: From<impl ToString>` is not satisfied
+ --> $DIR/issue-97576.rs:8:22
+ |
+LL | bar: bar.into(),
+ | ^^^^ the trait `From<impl ToString>` is not implemented for `String`
+ |
+ = note: required because of the requirements on the impl of `Into<String>` for `impl ToString`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// compile-flags: -Zinline-mir --emit=mir
+// build-pass
+
+pub trait Associate {
+ type Associated;
+}
+
+pub struct Wrap<'a> {
+ pub field: &'a i32,
+}
+
+pub trait Create<T> {
+ fn create() -> Self;
+}
+
+pub fn oh_no<'a, T>()
+where
+ Wrap<'a>: Associate,
+ <Wrap<'a> as Associate>::Associated: Create<T>,
+{
+ <Wrap<'a> as Associate>::Associated::create();
+}
+
+pub fn main() {}
--> $DIR/multidispatch-convert-ambig-dest.rs:26:5
|
LL | test(22, std::default::Default::default());
- | ^^^^ cannot infer type for type parameter `U` declared on the function `test`
+ | ^^^^ cannot infer type of the type parameter `U` declared on the function `test`
|
-help: type parameter declared here
- --> $DIR/multidispatch-convert-ambig-dest.rs:20:11
+help: consider specifying the generic arguments
|
-LL | fn test<T,U>(_: T, _: U)
- | ^
+LL | test::<i32, U>(22, std::default::Default::default());
+ | ++++++++++
error[E0283]: type annotations needed
--> $DIR/multidispatch-convert-ambig-dest.rs:26:5
|
LL | test(22, std::default::Default::default());
- | ^^^^ cannot infer type for type parameter `U` declared on the function `test`
- |
-help: type parameter declared here
- --> $DIR/multidispatch-convert-ambig-dest.rs:20:11
+ | ^^^^ cannot infer type of the type parameter `U` declared on the function `test`
|
-LL | fn test<T,U>(_: T, _: U)
- | ^
note: multiple `impl`s satisfying `i32: Convert<_>` found
--> $DIR/multidispatch-convert-ambig-dest.rs:8:1
|
| ---- required by a bound in this
LL | where T : Convert<U>
| ^^^^^^^^^^ required by this bound in `test`
+help: consider specifying the generic arguments
+ |
+LL | test::<i32, U>(22, std::default::Default::default());
+ | ++++++++++
help: consider specifying the type arguments in the function call
|
LL | test::<T, U>(22, std::default::Default::default());
--> $DIR/not-suggest-non-existing-fully-qualified-path.rs:21:7
|
LL | a.method();
- | --^^^^^^--
- | | |
- | | cannot infer type for type parameter `U` declared on the trait `V`
- | this method call resolves to `U`
+ | ^^^^^^
+ |
+help: try using a fully qualified path to specify the expected types
+ |
+LL | <A<B> as V<U>>::method(a);
+ | +++++++++++++++++++++++ ~
error[E0283]: type annotations needed
--> $DIR/not-suggest-non-existing-fully-qualified-path.rs:21:7
|
LL | a.method();
- | --^^^^^^--
- | | |
- | | cannot infer type for type parameter `U`
- | this method call resolves to `U`
- |
-help: type parameter declared here
- --> $DIR/not-suggest-non-existing-fully-qualified-path.rs:12:9
+ | ^^^^^^
|
-LL | impl<T, U> V<U> for A<T>
- | ^
note: multiple `impl`s satisfying `B: I<_>` found
--> $DIR/not-suggest-non-existing-fully-qualified-path.rs:5:1
|
|
LL | impl<T, U> V<U> for A<T>
| ^^^^ ^^^^
+help: try using a fully qualified path to specify the expected types
+ |
+LL | <A<B> as V<U>>::method(a);
+ | +++++++++++++++++++++++ ~
error: aborting due to 2 previous errors
--- /dev/null
+use std::ops::{Deref, DerefMut};
+
+struct Thing;
+
+trait Method<T> {
+ fn method(&self) -> T;
+ fn mut_method(&mut self) -> T;
+}
+
+impl Method<i32> for Thing {
+ fn method(&self) -> i32 { 0 }
+ fn mut_method(&mut self) -> i32 { 0 }
+}
+
+impl Method<u32> for Thing {
+ fn method(&self) -> u32 { 0 }
+ fn mut_method(&mut self) -> u32 { 0 }
+}
+trait MethodRef<T> {
+ fn by_self(self);
+}
+impl MethodRef<i32> for &Thing {
+ fn by_self(self) {}
+}
+impl MethodRef<u32> for &Thing {
+ fn by_self(self) {}
+}
+
+
+struct DerefsTo<T>(T);
+impl<T> Deref for DerefsTo<T> {
+ type Target = T;
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+impl<T> DerefMut for DerefsTo<T> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.0
+ }
+}
+
+fn main() {
+ let mut thing = Thing;
+ thing.method();
+ //~^ ERROR type annotations needed
+ //~| ERROR type annotations needed
+ thing.mut_method(); //~ ERROR type annotations needed
+ thing.by_self(); //~ ERROR type annotations needed
+
+ let mut deref_to = DerefsTo(Thing);
+ deref_to.method(); //~ ERROR type annotations needed
+ deref_to.mut_method(); //~ ERROR type annotations needed
+ deref_to.by_self(); //~ ERROR type annotations needed
+
+ let mut deref_deref_to = DerefsTo(DerefsTo(Thing));
+ deref_deref_to.method(); //~ ERROR type annotations needed
+ deref_deref_to.mut_method(); //~ ERROR type annotations needed
+ deref_deref_to.by_self(); //~ ERROR type annotations needed
+}
--- /dev/null
+error[E0282]: type annotations needed
+ --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:45:11
+ |
+LL | thing.method();
+ | ^^^^^^
+ |
+help: try using a fully qualified path to specify the expected types
+ |
+LL | <Thing as Method<T>>::method(&thing);
+ | ++++++++++++++++++++++++++++++ ~
+
+error[E0283]: type annotations needed
+ --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:45:11
+ |
+LL | thing.method();
+ | ^^^^^^
+ |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+ --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:10:1
+ |
+LL | impl Method<i32> for Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+ |
+LL | <Thing as Method<T>>::method(&thing);
+ | ++++++++++++++++++++++++++++++ ~
+
+error[E0283]: type annotations needed
+ --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:48:11
+ |
+LL | thing.mut_method();
+ | ^^^^^^^^^^
+ |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+ --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:10:1
+ |
+LL | impl Method<i32> for Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+ |
+LL | <Thing as Method<T>>::mut_method(&mut thing);
+ | +++++++++++++++++++++++++++++++++++++ ~
+
+error[E0283]: type annotations needed
+ --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:49:11
+ |
+LL | thing.by_self();
+ | ^^^^^^^
+ |
+note: multiple `impl`s satisfying `&Thing: MethodRef<_>` found
+ --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:22:1
+ |
+LL | impl MethodRef<i32> for &Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl MethodRef<u32> for &Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+ |
+LL | <&Thing as MethodRef<T>>::by_self(&thing);
+ | +++++++++++++++++++++++++++++++++++ ~
+
+error[E0283]: type annotations needed
+ --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:52:14
+ |
+LL | deref_to.method();
+ | ^^^^^^
+ |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+ --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:10:1
+ |
+LL | impl Method<i32> for Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+ |
+LL | <Thing as Method<T>>::method(&deref_to);
+ | ++++++++++++++++++++++++++++++ ~
+
+error[E0283]: type annotations needed
+ --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:53:14
+ |
+LL | deref_to.mut_method();
+ | ^^^^^^^^^^
+ |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+ --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:10:1
+ |
+LL | impl Method<i32> for Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+ |
+LL | <Thing as Method<T>>::mut_method(&mut deref_to);
+ | +++++++++++++++++++++++++++++++++++++ ~
+
+error[E0283]: type annotations needed
+ --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:54:14
+ |
+LL | deref_to.by_self();
+ | ^^^^^^^
+ |
+note: multiple `impl`s satisfying `&Thing: MethodRef<_>` found
+ --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:22:1
+ |
+LL | impl MethodRef<i32> for &Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl MethodRef<u32> for &Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+ |
+LL | <&Thing as MethodRef<T>>::by_self(&deref_to);
+ | +++++++++++++++++++++++++++++++++++ ~
+
+error[E0283]: type annotations needed
+ --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:57:20
+ |
+LL | deref_deref_to.method();
+ | ^^^^^^
+ |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+ --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:10:1
+ |
+LL | impl Method<i32> for Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+ |
+LL | <Thing as Method<T>>::method(&deref_deref_to);
+ | ++++++++++++++++++++++++++++++ ~
+
+error[E0283]: type annotations needed
+ --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:58:20
+ |
+LL | deref_deref_to.mut_method();
+ | ^^^^^^^^^^
+ |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+ --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:10:1
+ |
+LL | impl Method<i32> for Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+ |
+LL | <Thing as Method<T>>::mut_method(&mut deref_deref_to);
+ | +++++++++++++++++++++++++++++++++++++ ~
+
+error[E0283]: type annotations needed
+ --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:59:20
+ |
+LL | deref_deref_to.by_self();
+ | ^^^^^^^
+ |
+note: multiple `impl`s satisfying `&Thing: MethodRef<_>` found
+ --> $DIR/suggest-fully-qualified-path-with-adjustment.rs:22:1
+ |
+LL | impl MethodRef<i32> for &Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl MethodRef<u32> for &Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+ |
+LL | <&Thing as MethodRef<T>>::by_self(&deref_deref_to);
+ | +++++++++++++++++++++++++++++++++++ ~
+
+error: aborting due to 10 previous errors
+
+Some errors have detailed explanations: E0282, E0283.
+For more information about an error, try `rustc --explain E0282`.
+++ /dev/null
-struct Thing;
-
-trait Method<T> {
- fn method(&self) -> T;
- fn mut_method(&mut self) -> T;
-}
-
-impl Method<i32> for Thing {
- fn method(&self) -> i32 { 0 }
- fn mut_method(&mut self) -> i32 { 0 }
-}
-
-impl Method<u32> for Thing {
- fn method(&self) -> u32 { 0 }
- fn mut_method(&mut self) -> u32 { 0 }
-}
-
-fn main() {
- let thing = Thing;
- thing.method();
- //~^ ERROR type annotations needed
- //~| ERROR type annotations needed
- thing.mut_method(); //~ ERROR type annotations needed
-}
+++ /dev/null
-error[E0282]: type annotations needed
- --> $DIR/suggest-fully-qualified-path-with-appropriate-params.rs:20:11
- |
-LL | thing.method();
- | ------^^^^^^--
- | | |
- | | cannot infer type for type parameter `T` declared on the trait `Method`
- | this method call resolves to `T`
-
-error[E0283]: type annotations needed
- --> $DIR/suggest-fully-qualified-path-with-appropriate-params.rs:20:11
- |
-LL | thing.method();
- | ------^^^^^^--
- | | |
- | | cannot infer type for type parameter `T` declared on the trait `Method`
- | this method call resolves to `T`
- |
-note: multiple `impl`s satisfying `Thing: Method<_>` found
- --> $DIR/suggest-fully-qualified-path-with-appropriate-params.rs:8:1
- |
-LL | impl Method<i32> for Thing {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
-...
-LL | impl Method<u32> for Thing {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: use the fully qualified path for the potential candidates
- |
-LL | <Thing as Method<i32>>::method(&thing);
- | ++++++++++++++++++++++++++++++++ ~
-LL | <Thing as Method<u32>>::method(&thing);
- | ++++++++++++++++++++++++++++++++ ~
-
-error[E0283]: type annotations needed
- --> $DIR/suggest-fully-qualified-path-with-appropriate-params.rs:23:11
- |
-LL | thing.mut_method();
- | ------^^^^^^^^^^--
- | | |
- | | cannot infer type for type parameter `T` declared on the trait `Method`
- | this method call resolves to `T`
- |
-note: multiple `impl`s satisfying `Thing: Method<_>` found
- --> $DIR/suggest-fully-qualified-path-with-appropriate-params.rs:8:1
- |
-LL | impl Method<i32> for Thing {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
-...
-LL | impl Method<u32> for Thing {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: use the fully qualified path for the potential candidates
- |
-LL | <Thing as Method<i32>>::mut_method(&mut thing);
- | +++++++++++++++++++++++++++++++++++++++ ~
-LL | <Thing as Method<u32>>::mut_method(&mut thing);
- | +++++++++++++++++++++++++++++++++++++++ ~
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0282, E0283.
-For more information about an error, try `rustc --explain E0282`.
--- /dev/null
+use std::ops::{Deref, DerefMut};
+
+struct Thing;
+
+trait Method<T> {
+ fn method(&self) -> T;
+ fn mut_method(&mut self) -> T;
+}
+
+impl Method<i32> for Thing {
+ fn method(&self) -> i32 { 0 }
+ fn mut_method(&mut self) -> i32 { 0 }
+}
+
+impl Method<u32> for Thing {
+ fn method(&self) -> u32 { 0 }
+ fn mut_method(&mut self) -> u32 { 0 }
+}
+
+trait MethodRef<T> {
+ fn by_self(self);
+}
+impl MethodRef<i32> for &Thing {
+ fn by_self(self) {}
+}
+impl MethodRef<u32> for &Thing {
+ fn by_self(self) {}
+}
+
+struct DerefsTo<T>(T);
+impl<T> Deref for DerefsTo<T> {
+ type Target = T;
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+impl<T> DerefMut for DerefsTo<T> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.0
+ }
+}
+
+fn main() {
+ let mut ref_thing = &Thing;
+ ref_thing.method();
+ //~^ ERROR type annotations needed
+ //~| ERROR type annotations needed
+ ref_thing.by_self(); //~ ERROR type annotations needed
+
+ let mut mut_thing = &mut Thing;
+ mut_thing.method(); //~ ERROR type annotations needed
+ mut_thing.mut_method(); //~ ERROR type annotations needed
+ mut_thing.by_self(); //~ ERROR type annotations needed
+
+ let mut deref_to = &DerefsTo(Thing);
+ deref_to.method(); //~ ERROR type annotations needed
+ deref_to.mut_method(); //~ ERROR type annotations needed
+ deref_to.by_self(); //~ ERROR type annotations needed
+
+ let mut deref_deref_to = &DerefsTo(DerefsTo(Thing));
+ deref_deref_to.method(); //~ ERROR type annotations needed
+ deref_deref_to.mut_method(); //~ ERROR type annotations needed
+ deref_deref_to.by_self(); //~ ERROR type annotations needed
+}
--- /dev/null
+error[E0282]: type annotations needed
+ --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:45:15
+ |
+LL | ref_thing.method();
+ | ^^^^^^
+ |
+help: try using a fully qualified path to specify the expected types
+ |
+LL | <Thing as Method<T>>::method(ref_thing);
+ | +++++++++++++++++++++++++++++ ~
+
+error[E0283]: type annotations needed
+ --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:45:15
+ |
+LL | ref_thing.method();
+ | ^^^^^^
+ |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+ --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:10:1
+ |
+LL | impl Method<i32> for Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+ |
+LL | <Thing as Method<T>>::method(ref_thing);
+ | +++++++++++++++++++++++++++++ ~
+
+error[E0283]: type annotations needed
+ --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:48:15
+ |
+LL | ref_thing.by_self();
+ | ^^^^^^^
+ |
+note: multiple `impl`s satisfying `&Thing: MethodRef<_>` found
+ --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:23:1
+ |
+LL | impl MethodRef<i32> for &Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl MethodRef<u32> for &Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+ |
+LL | <&Thing as MethodRef<T>>::by_self(ref_thing);
+ | ++++++++++++++++++++++++++++++++++ ~
+
+error[E0283]: type annotations needed
+ --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:51:15
+ |
+LL | mut_thing.method();
+ | ^^^^^^
+ |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+ --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:10:1
+ |
+LL | impl Method<i32> for Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+ |
+LL | <Thing as Method<T>>::method(mut_thing);
+ | +++++++++++++++++++++++++++++ ~
+
+error[E0283]: type annotations needed
+ --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:52:15
+ |
+LL | mut_thing.mut_method();
+ | ^^^^^^^^^^
+ |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+ --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:10:1
+ |
+LL | impl Method<i32> for Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+ |
+LL | <Thing as Method<T>>::mut_method(mut_thing);
+ | +++++++++++++++++++++++++++++++++ ~
+
+error[E0283]: type annotations needed
+ --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:53:15
+ |
+LL | mut_thing.by_self();
+ | ^^^^^^^
+ |
+note: multiple `impl`s satisfying `&Thing: MethodRef<_>` found
+ --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:23:1
+ |
+LL | impl MethodRef<i32> for &Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl MethodRef<u32> for &Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+ |
+LL | <&Thing as MethodRef<T>>::by_self(mut_thing);
+ | ++++++++++++++++++++++++++++++++++ ~
+
+error[E0283]: type annotations needed
+ --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:56:14
+ |
+LL | deref_to.method();
+ | ^^^^^^
+ |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+ --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:10:1
+ |
+LL | impl Method<i32> for Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+ |
+LL | <Thing as Method<T>>::method(deref_to);
+ | +++++++++++++++++++++++++++++ ~
+
+error[E0283]: type annotations needed
+ --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:57:14
+ |
+LL | deref_to.mut_method();
+ | ^^^^^^^^^^
+ |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+ --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:10:1
+ |
+LL | impl Method<i32> for Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+ |
+LL | <Thing as Method<T>>::mut_method(deref_to);
+ | +++++++++++++++++++++++++++++++++ ~
+
+error[E0283]: type annotations needed
+ --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:58:14
+ |
+LL | deref_to.by_self();
+ | ^^^^^^^
+ |
+note: multiple `impl`s satisfying `&Thing: MethodRef<_>` found
+ --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:23:1
+ |
+LL | impl MethodRef<i32> for &Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl MethodRef<u32> for &Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+ |
+LL | <&Thing as MethodRef<T>>::by_self(deref_to);
+ | ++++++++++++++++++++++++++++++++++ ~
+
+error[E0283]: type annotations needed
+ --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:61:20
+ |
+LL | deref_deref_to.method();
+ | ^^^^^^
+ |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+ --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:10:1
+ |
+LL | impl Method<i32> for Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+ |
+LL | <Thing as Method<T>>::method(deref_deref_to);
+ | +++++++++++++++++++++++++++++ ~
+
+error[E0283]: type annotations needed
+ --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:62:20
+ |
+LL | deref_deref_to.mut_method();
+ | ^^^^^^^^^^
+ |
+note: multiple `impl`s satisfying `Thing: Method<_>` found
+ --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:10:1
+ |
+LL | impl Method<i32> for Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Method<u32> for Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+ |
+LL | <Thing as Method<T>>::mut_method(deref_deref_to);
+ | +++++++++++++++++++++++++++++++++ ~
+
+error[E0283]: type annotations needed
+ --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:63:20
+ |
+LL | deref_deref_to.by_self();
+ | ^^^^^^^
+ |
+note: multiple `impl`s satisfying `&Thing: MethodRef<_>` found
+ --> $DIR/suggest-fully-qualified-path-without-adjustment.rs:23:1
+ |
+LL | impl MethodRef<i32> for &Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl MethodRef<u32> for &Thing {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+ |
+LL | <&Thing as MethodRef<T>>::by_self(deref_deref_to);
+ | ++++++++++++++++++++++++++++++++++ ~
+
+error: aborting due to 12 previous errors
+
+Some errors have detailed explanations: E0282, E0283.
+For more information about an error, try `rustc --explain E0282`.
Self::TSVariant(());
//~^ ERROR mismatched types [E0308]
Self::TSVariant::<()>(());
- //~^ ERROR type arguments are not allowed for this type [E0109]
+ //~^ ERROR type arguments are not allowed on this type [E0109]
Self::<()>::TSVariant(());
- //~^ ERROR type arguments are not allowed for this type [E0109]
+ //~^ ERROR type arguments are not allowed on self type [E0109]
//~| ERROR mismatched types [E0308]
Self::<()>::TSVariant::<()>(());
- //~^ ERROR type arguments are not allowed for this type [E0109]
- //~| ERROR type arguments are not allowed for this type [E0109]
+ //~^ ERROR type arguments are not allowed on self type [E0109]
+ //~| ERROR type arguments are not allowed on this type [E0109]
}
fn s_variant() {
Self::SVariant { v: () };
//~^ ERROR mismatched types [E0308]
Self::SVariant::<()> { v: () };
- //~^ ERROR type arguments are not allowed for this type [E0109]
+ //~^ ERROR type arguments are not allowed on this type [E0109]
//~| ERROR mismatched types [E0308]
Self::<()>::SVariant { v: () };
- //~^ ERROR type arguments are not allowed for this type [E0109]
+ //~^ ERROR type arguments are not allowed on self type [E0109]
//~| ERROR mismatched types [E0308]
Self::<()>::SVariant::<()> { v: () };
- //~^ ERROR type arguments are not allowed for this type [E0109]
- //~| ERROR type arguments are not allowed for this type [E0109]
+ //~^ ERROR type arguments are not allowed on self type [E0109]
+ //~| ERROR type arguments are not allowed on this type [E0109]
//~| ERROR mismatched types [E0308]
}
fn u_variant() {
Self::UVariant::<()>;
- //~^ ERROR type arguments are not allowed for this type [E0109]
+ //~^ ERROR type arguments are not allowed on this type [E0109]
Self::<()>::UVariant;
- //~^ ERROR type arguments are not allowed for this type [E0109]
+ //~^ ERROR type arguments are not allowed on self type [E0109]
Self::<()>::UVariant::<()>;
- //~^ ERROR type arguments are not allowed for this type [E0109]
- //~| ERROR type arguments are not allowed for this type [E0109]
+ //~^ ERROR type arguments are not allowed on self type [E0109]
+ //~| ERROR type arguments are not allowed on this type [E0109]
}
}
// Tuple struct variant
Enum::<()>::TSVariant::<()>(());
- //~^ ERROR type arguments are not allowed for this type [E0109]
+ //~^ ERROR type arguments are not allowed on this type [E0109]
Alias::TSVariant::<()>(());
- //~^ ERROR type arguments are not allowed for this type [E0109]
+ //~^ ERROR type arguments are not allowed on this type [E0109]
Alias::<()>::TSVariant::<()>(());
- //~^ ERROR type arguments are not allowed for this type [E0109]
+ //~^ ERROR type arguments are not allowed on this type [E0109]
AliasFixed::TSVariant::<()>(());
- //~^ ERROR type arguments are not allowed for this type [E0109]
+ //~^ ERROR type arguments are not allowed on this type [E0109]
AliasFixed::<()>::TSVariant(());
//~^ ERROR this type alias takes 0 generic arguments but 1 generic argument was supplied [E0107]
AliasFixed::<()>::TSVariant::<()>(());
- //~^ ERROR type arguments are not allowed for this type [E0109]
+ //~^ ERROR type arguments are not allowed on this type [E0109]
//~| ERROR this type alias takes 0 generic arguments but 1 generic argument was supplied [E0107]
// Struct variant
Enum::<()>::SVariant::<()> { v: () };
- //~^ ERROR type arguments are not allowed for this type [E0109]
+ //~^ ERROR type arguments are not allowed on this type [E0109]
Alias::SVariant::<()> { v: () };
- //~^ ERROR type arguments are not allowed for this type [E0109]
+ //~^ ERROR type arguments are not allowed on this type [E0109]
Alias::<()>::SVariant::<()> { v: () };
- //~^ ERROR type arguments are not allowed for this type [E0109]
+ //~^ ERROR type arguments are not allowed on this type [E0109]
AliasFixed::SVariant::<()> { v: () };
- //~^ ERROR type arguments are not allowed for this type [E0109]
+ //~^ ERROR type arguments are not allowed on this type [E0109]
AliasFixed::<()>::SVariant { v: () };
//~^ ERROR this type alias takes 0 generic arguments but 1 generic argument was supplied [E0107]
AliasFixed::<()>::SVariant::<()> { v: () };
- //~^ ERROR type arguments are not allowed for this type [E0109]
+ //~^ ERROR type arguments are not allowed on this type [E0109]
//~| ERROR this type alias takes 0 generic arguments but 1 generic argument was supplied [E0107]
// Unit variant
Enum::<()>::UVariant::<()>;
- //~^ ERROR type arguments are not allowed for this type [E0109]
+ //~^ ERROR type arguments are not allowed on this type [E0109]
Alias::UVariant::<()>;
- //~^ ERROR type arguments are not allowed for this type [E0109]
+ //~^ ERROR type arguments are not allowed on this type [E0109]
Alias::<()>::UVariant::<()>;
- //~^ ERROR type arguments are not allowed for this type [E0109]
+ //~^ ERROR type arguments are not allowed on this type [E0109]
AliasFixed::UVariant::<()>;
- //~^ ERROR type arguments are not allowed for this type [E0109]
+ //~^ ERROR type arguments are not allowed on this type [E0109]
AliasFixed::<()>::UVariant;
//~^ ERROR this type alias takes 0 generic arguments but 1 generic argument was supplied [E0107]
AliasFixed::<()>::UVariant::<()>;
- //~^ ERROR type arguments are not allowed for this type [E0109]
+ //~^ ERROR type arguments are not allowed on this type [E0109]
//~| ERROR this type alias takes 0 generic arguments but 1 generic argument was supplied [E0107]
}
LL | enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
| ^^^^^^^^^
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
--> $DIR/enum-variant-generic-args.rs:15:27
|
LL | Self::TSVariant::<()>(());
- | ^^ type argument not allowed
+ | --------- ^^ type argument not allowed
+ | |
+ | not allowed on this
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on self type
--> $DIR/enum-variant-generic-args.rs:17:16
|
LL | Self::<()>::TSVariant(());
- | ^^ type argument not allowed
+ | ---- ^^ type argument not allowed
+ | |
+ | not allowed on this
+ |
+note: `Self` is of type `Enum<T>`
+ --> $DIR/enum-variant-generic-args.rs:7:6
+ |
+LL | enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
+ | ^^^^ `Self` corresponds to this type
+...
+LL | impl<T> Enum<T> {
+ | --------------- `Self` is on type `Enum` in this `impl`
+help: the `Self` type doesn't accept type parameters, use the concrete type's name `Enum` instead if you want to specify its type parameters
+ |
+LL | Enum::<()>::TSVariant(());
+ | ~~~~
error[E0308]: mismatched types
--> $DIR/enum-variant-generic-args.rs:17:31
LL | enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
| ^^^^^^^^^
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on self type
--> $DIR/enum-variant-generic-args.rs:20:16
|
LL | Self::<()>::TSVariant::<()>(());
- | ^^ type argument not allowed
+ | ---- ^^ type argument not allowed
+ | |
+ | not allowed on this
+ |
+note: `Self` is of type `Enum<T>`
+ --> $DIR/enum-variant-generic-args.rs:7:6
+ |
+LL | enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
+ | ^^^^ `Self` corresponds to this type
+...
+LL | impl<T> Enum<T> {
+ | --------------- `Self` is on type `Enum` in this `impl`
+help: the `Self` type doesn't accept type parameters, use the concrete type's name `Enum` instead if you want to specify its type parameters
+ |
+LL | Enum::<()>::TSVariant::<()>(());
+ | ~~~~
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
--> $DIR/enum-variant-generic-args.rs:20:33
|
LL | Self::<()>::TSVariant::<()>(());
- | ^^ type argument not allowed
+ | --------- ^^ type argument not allowed
+ | |
+ | not allowed on this
error[E0308]: mismatched types
--> $DIR/enum-variant-generic-args.rs:26:29
= note: expected type parameter `T`
found unit type `()`
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
--> $DIR/enum-variant-generic-args.rs:28:26
|
LL | Self::SVariant::<()> { v: () };
- | ^^ type argument not allowed
+ | -------- ^^ type argument not allowed
+ | |
+ | not allowed on this
+ |
+ = note: enum variants can't have type parameters
+help: you might have meant to specity type parameters on enum `Enum`
+ |
+LL - Self::SVariant::<()> { v: () };
+LL + Enum::<()>::SVariant { v: () };
+ |
error[E0308]: mismatched types
--> $DIR/enum-variant-generic-args.rs:28:35
= note: expected type parameter `T`
found unit type `()`
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on self type
--> $DIR/enum-variant-generic-args.rs:31:16
|
LL | Self::<()>::SVariant { v: () };
- | ^^ type argument not allowed
+ | ---- ^^ type argument not allowed
+ | |
+ | not allowed on this
+ |
+note: `Self` is of type `Enum<T>`
+ --> $DIR/enum-variant-generic-args.rs:7:6
+ |
+LL | enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
+ | ^^^^ `Self` corresponds to this type
+...
+LL | impl<T> Enum<T> {
+ | --------------- `Self` is on type `Enum` in this `impl`
+help: the `Self` type doesn't accept type parameters, use the concrete type's name `Enum` instead if you want to specify its type parameters
+ |
+LL | Enum::<()>::SVariant { v: () };
+ | ~~~~
error[E0308]: mismatched types
--> $DIR/enum-variant-generic-args.rs:31:35
= note: expected type parameter `T`
found unit type `()`
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on self type
--> $DIR/enum-variant-generic-args.rs:34:16
|
LL | Self::<()>::SVariant::<()> { v: () };
- | ^^ type argument not allowed
+ | ---- ^^ type argument not allowed
+ | |
+ | not allowed on this
+ |
+note: `Self` is of type `Enum<T>`
+ --> $DIR/enum-variant-generic-args.rs:7:6
+ |
+LL | enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
+ | ^^^^ `Self` corresponds to this type
+...
+LL | impl<T> Enum<T> {
+ | --------------- `Self` is on type `Enum` in this `impl`
+help: the `Self` type doesn't accept type parameters, use the concrete type's name `Enum` instead if you want to specify its type parameters
+ |
+LL | Enum::<()>::SVariant::<()> { v: () };
+ | ~~~~
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
--> $DIR/enum-variant-generic-args.rs:34:32
|
LL | Self::<()>::SVariant::<()> { v: () };
- | ^^ type argument not allowed
+ | -------- ^^ type argument not allowed
+ | |
+ | not allowed on this
+ |
+ = note: enum variants can't have type parameters
+help: you might have meant to specity type parameters on enum `Enum`
+ |
+LL - Self::<()>::SVariant::<()> { v: () };
+LL + Enum::<()>::SVariant { v: () };
+ |
error[E0308]: mismatched types
--> $DIR/enum-variant-generic-args.rs:34:41
= note: expected type parameter `T`
found unit type `()`
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
--> $DIR/enum-variant-generic-args.rs:41:26
|
LL | Self::UVariant::<()>;
- | ^^ type argument not allowed
+ | -------- ^^ type argument not allowed
+ | |
+ | not allowed on this
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on self type
--> $DIR/enum-variant-generic-args.rs:43:16
|
LL | Self::<()>::UVariant;
- | ^^ type argument not allowed
+ | ---- ^^ type argument not allowed
+ | |
+ | not allowed on this
+ |
+note: `Self` is of type `Enum<T>`
+ --> $DIR/enum-variant-generic-args.rs:7:6
+ |
+LL | enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
+ | ^^^^ `Self` corresponds to this type
+...
+LL | impl<T> Enum<T> {
+ | --------------- `Self` is on type `Enum` in this `impl`
+help: the `Self` type doesn't accept type parameters, use the concrete type's name `Enum` instead if you want to specify its type parameters
+ |
+LL | Enum::<()>::UVariant;
+ | ~~~~
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on self type
--> $DIR/enum-variant-generic-args.rs:45:16
|
LL | Self::<()>::UVariant::<()>;
- | ^^ type argument not allowed
+ | ---- ^^ type argument not allowed
+ | |
+ | not allowed on this
+ |
+note: `Self` is of type `Enum<T>`
+ --> $DIR/enum-variant-generic-args.rs:7:6
+ |
+LL | enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
+ | ^^^^ `Self` corresponds to this type
+...
+LL | impl<T> Enum<T> {
+ | --------------- `Self` is on type `Enum` in this `impl`
+help: the `Self` type doesn't accept type parameters, use the concrete type's name `Enum` instead if you want to specify its type parameters
+ |
+LL | Enum::<()>::UVariant::<()>;
+ | ~~~~
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
--> $DIR/enum-variant-generic-args.rs:45:32
|
LL | Self::<()>::UVariant::<()>;
- | ^^ type argument not allowed
+ | -------- ^^ type argument not allowed
+ | |
+ | not allowed on this
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
--> $DIR/enum-variant-generic-args.rs:54:29
|
LL | Enum::<()>::TSVariant::<()>(());
- | ^^ type argument not allowed
+ | --------- ^^ type argument not allowed
+ | |
+ | not allowed on this
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
--> $DIR/enum-variant-generic-args.rs:57:24
|
LL | Alias::TSVariant::<()>(());
- | ^^ type argument not allowed
+ | --------- ^^ type argument not allowed
+ | |
+ | not allowed on this
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
--> $DIR/enum-variant-generic-args.rs:59:30
|
LL | Alias::<()>::TSVariant::<()>(());
- | ^^ type argument not allowed
+ | --------- ^^ type argument not allowed
+ | |
+ | not allowed on this
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
--> $DIR/enum-variant-generic-args.rs:62:29
|
LL | AliasFixed::TSVariant::<()>(());
- | ^^ type argument not allowed
+ | --------- ^^ type argument not allowed
+ | |
+ | not allowed on this
error[E0107]: this type alias takes 0 generic arguments but 1 generic argument was supplied
--> $DIR/enum-variant-generic-args.rs:64:5
LL | type AliasFixed = Enum<()>;
| ^^^^^^^^^^
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
--> $DIR/enum-variant-generic-args.rs:66:35
|
LL | AliasFixed::<()>::TSVariant::<()>(());
- | ^^ type argument not allowed
+ | --------- ^^ type argument not allowed
+ | |
+ | not allowed on this
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
--> $DIR/enum-variant-generic-args.rs:72:28
|
LL | Enum::<()>::SVariant::<()> { v: () };
- | ^^ type argument not allowed
+ | -------- ^^ type argument not allowed
+ | |
+ | not allowed on this
+ |
+ = note: enum variants can't have type parameters
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
--> $DIR/enum-variant-generic-args.rs:75:23
|
LL | Alias::SVariant::<()> { v: () };
- | ^^ type argument not allowed
+ | -------- ^^ type argument not allowed
+ | |
+ | not allowed on this
+ |
+ = note: enum variants can't have type parameters
+help: you might have meant to specity type parameters on enum `Enum`
+ |
+LL - Alias::SVariant::<()> { v: () };
+LL + Alias::<()>::SVariant { v: () };
+ |
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
--> $DIR/enum-variant-generic-args.rs:77:29
|
LL | Alias::<()>::SVariant::<()> { v: () };
- | ^^ type argument not allowed
+ | -------- ^^ type argument not allowed
+ | |
+ | not allowed on this
+ |
+ = note: enum variants can't have type parameters
+help: you might have meant to specity type parameters on enum `Enum`
+ |
+LL - Alias::<()>::SVariant::<()> { v: () };
+LL + Alias::<()>::SVariant { v: () };
+ |
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
--> $DIR/enum-variant-generic-args.rs:80:28
|
LL | AliasFixed::SVariant::<()> { v: () };
- | ^^ type argument not allowed
+ | -------- ^^ type argument not allowed
+ | |
+ | not allowed on this
+ |
+ = note: enum variants can't have type parameters
+help: you might have meant to specity type parameters on enum `Enum`
+ |
+LL - AliasFixed::SVariant::<()> { v: () };
+LL + AliasFixed::<()>::SVariant { v: () };
+ |
error[E0107]: this type alias takes 0 generic arguments but 1 generic argument was supplied
--> $DIR/enum-variant-generic-args.rs:82:5
LL | type AliasFixed = Enum<()>;
| ^^^^^^^^^^
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
--> $DIR/enum-variant-generic-args.rs:84:34
|
LL | AliasFixed::<()>::SVariant::<()> { v: () };
- | ^^ type argument not allowed
+ | -------- ^^ type argument not allowed
+ | |
+ | not allowed on this
+ |
+ = note: enum variants can't have type parameters
+help: you might have meant to specity type parameters on enum `Enum`
+ |
+LL - AliasFixed::<()>::SVariant::<()> { v: () };
+LL + AliasFixed::<()>::SVariant { v: () };
+ |
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
--> $DIR/enum-variant-generic-args.rs:90:28
|
LL | Enum::<()>::UVariant::<()>;
- | ^^ type argument not allowed
+ | -------- ^^ type argument not allowed
+ | |
+ | not allowed on this
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
--> $DIR/enum-variant-generic-args.rs:93:23
|
LL | Alias::UVariant::<()>;
- | ^^ type argument not allowed
+ | -------- ^^ type argument not allowed
+ | |
+ | not allowed on this
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
--> $DIR/enum-variant-generic-args.rs:95:29
|
LL | Alias::<()>::UVariant::<()>;
- | ^^ type argument not allowed
+ | -------- ^^ type argument not allowed
+ | |
+ | not allowed on this
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
--> $DIR/enum-variant-generic-args.rs:98:28
|
LL | AliasFixed::UVariant::<()>;
- | ^^ type argument not allowed
+ | -------- ^^ type argument not allowed
+ | |
+ | not allowed on this
error[E0107]: this type alias takes 0 generic arguments but 1 generic argument was supplied
--> $DIR/enum-variant-generic-args.rs:100:5
LL | type AliasFixed = Enum<()>;
| ^^^^^^^^^^
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
--> $DIR/enum-variant-generic-args.rs:102:34
|
LL | AliasFixed::<()>::UVariant::<()>;
- | ^^ type argument not allowed
+ | -------- ^^ type argument not allowed
+ | |
+ | not allowed on this
error: aborting due to 39 previous errors
let _ = Option::<u8>::None; // OK
let _ = Option::None::<u8>; // OK (Lint in future!)
let _ = Alias::<u8>::None; // OK
- let _ = Alias::None::<u8>; //~ ERROR type arguments are not allowed for this type
+ let _ = Alias::None::<u8>; //~ ERROR type arguments are not allowed on this type
}
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
--> $DIR/no-type-application-on-aliased-enum-variant.rs:13:27
|
LL | let _ = Alias::None::<u8>;
- | ^^ type argument not allowed
+ | ---- ^^ type argument not allowed
+ | |
+ | not allowed on this
error: aborting due to previous error
--> $DIR/closures_in_branches.rs:21:10
|
LL | |x| x.len()
- | ^ consider giving this closure parameter a type
+ | ^
|
= note: type must be known at this point
+help: consider giving this closure parameter an explicit type
+ |
+LL | |x: _| x.len()
+ | +++
error: aborting due to previous error
--> $DIR/incomplete-inference.rs:6:5
|
LL | None
- | ^^^^ cannot infer type for type parameter `T` declared on the enum `Option`
+ | ^^^^ cannot infer type of the type parameter `T` declared on the enum `Option`
+ |
+help: consider specifying the generic argument
+ |
+LL | None::<T>
+ | +++++
error: aborting due to previous error
--- /dev/null
+// check-pass
+// pretty-expanded FIXME #23616
+
+pub type BigRat<T = isize> = T;
+
+fn main() {}
-error[E0282]: type annotations needed
- --> $DIR/or_else-multiple-type-params.rs:7:10
+error[E0282]: type annotations needed for `Result<Child, F>`
+ --> $DIR/or_else-multiple-type-params.rs:7:18
|
LL | .or_else(|err| {
- | ^^^^^^^ cannot infer type for type parameter `F` declared on the associated function `or_else`
+ | ^^^^^
|
-help: consider specifying the type arguments in the method call
+help: try giving this closure an explicit return type
|
-LL | .or_else::<F, O>(|err| {
- | ++++++++
+LL | .or_else(|err| -> Result<Child, F> {
+ | +++++++++++++++++++
error: aborting due to previous error
error[E0282]: type annotations needed
- --> $DIR/sort_by_key.rs:3:9
+ --> $DIR/sort_by_key.rs:3:40
|
LL | lst.sort_by_key(|&(v, _)| v.iter().sum());
- | ^^^^^^^^^^^ cannot infer type for type parameter `K` declared on the associated function `sort_by_key`
+ | ^^^ cannot infer type of the type parameter `S` declared on the associated function `sum`
|
-help: consider specifying the type argument in the method call
+help: consider specifying the generic argument
|
LL | lst.sort_by_key(|&(v, _)| v.iter().sum::<S>());
| +++++
error[E0282]: type annotations needed
- --> $DIR/unbounded-associated-type.rs:15:5
+ --> $DIR/unbounded-associated-type.rs:15:7
|
-LL | type A;
- | ------- `<Self as T>::A` defined here
-...
LL | S(std::marker::PhantomData).foo();
- | ^--------------------------------
- | |
- | this method call resolves to `<Self as T>::A`
- | cannot infer type for type parameter `X` declared on the struct `S`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `PhantomData`
+ |
+help: consider specifying the generic argument
+ |
+LL | S(std::marker::PhantomData::<T>).foo();
+ | +++++
error: aborting due to previous error
--> $DIR/unbounded-type-param-in-fn-with-assoc-type.rs:8:5
|
LL | foo();
- | ^^^ cannot infer type for type parameter `T` declared on the function `foo`
+ | ^^^ cannot infer type of the type parameter `T` declared on the function `foo`
|
-help: type parameter declared here
- --> $DIR/unbounded-type-param-in-fn-with-assoc-type.rs:3:8
+help: consider specifying the generic arguments
|
-LL | fn foo<T, U = u64>() -> (T, U) {
- | ^
+LL | foo::<T, U>();
+ | ++++++++
error: aborting due to previous error
--> $DIR/unbounded-type-param-in-fn.rs:6:5
|
LL | foo();
- | ^^^ cannot infer type for type parameter `T` declared on the function `foo`
+ | ^^^ cannot infer type of the type parameter `T` declared on the function `foo`
|
-help: type parameter declared here
- --> $DIR/unbounded-type-param-in-fn.rs:1:8
+help: consider specifying the generic argument
|
-LL | fn foo<T>() -> T {
- | ^
+LL | foo::<T>();
+ | +++++
error: aborting due to previous error
-error: expected type, found `<[_]>::into_vec(box [0, 1])`
+error: expected type, found `<[_]>::into_vec(#[rustc_box] ::alloc::boxed::Box::new([0, 1]))`
--> $DIR/issue-47666.rs:3:25
|
LL | let _ = Option:Some(vec![0, 1]);
// error-pattern: this file contains an unclosed delimiter
// error-pattern: cannot find type `ţ` in this scope
// error-pattern: parenthesized type parameters may only be used with a `Fn` trait
-// error-pattern: type arguments are not allowed for this type
+// error-pattern: type arguments are not allowed on this type
// error-pattern: mismatched types
// ignore-tidy-trailing-newlines
// `ţ` must be the last character in this file, it cannot be followed by a newline
LL | 0: u8(ţ
| ^^^^ only `Fn` traits may use parentheses
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
--> $DIR/issue-91268.rs:9:11
|
LL | 0: u8(ţ
- | ^ type argument not allowed
+ | -- ^ type argument not allowed
+ | |
+ | not allowed on this
+ |
+help: primitive type `u8` doesn't have generic parameters
+ |
+LL - 0: u8(ţ
+LL + 0: u8
+ |
error[E0308]: mismatched types
--> $DIR/issue-91268.rs:9:5
--> $DIR/type-annotation-needed.rs:6:5
|
LL | foo(42);
- | ^^^ cannot infer type for type parameter `T` declared on the function `foo`
+ | ^^^ cannot infer type of the type parameter `T` declared on the function `foo`
|
-help: type parameter declared here
- --> $DIR/type-annotation-needed.rs:1:8
- |
-LL | fn foo<T: Into<String>>(x: i32) {}
- | ^
= note: cannot satisfy `_: Into<String>`
note: required by a bound in `foo`
--> $DIR/type-annotation-needed.rs:1:11
|
LL | fn foo<T: Into<String>>(x: i32) {}
| ^^^^^^^^^^^^ required by this bound in `foo`
+help: consider specifying the generic argument
+ |
+LL | foo::<T>(42);
+ | +++++
help: consider specifying the type argument in the function call
|
LL | foo::<T>(42);
error[E0282]: type annotations needed for `[_; 0]`
- --> $DIR/cannot_infer_local_or_array.rs:2:13
+ --> $DIR/cannot_infer_local_or_array.rs:2:9
|
LL | let x = [];
- | - ^^ cannot infer type
- | |
- | consider giving `x` the explicit type `[_; 0]`, with the type parameters specified
+ | ^
+ |
+help: consider giving `x` an explicit type, where the placeholders `_` are specified
+ |
+LL | let x: [_; 0] = [];
+ | ++++++++
error: aborting due to previous error
error[E0282]: type annotations needed for `Vec<T>`
- --> $DIR/cannot_infer_local_or_vec.rs:2:13
+ --> $DIR/cannot_infer_local_or_vec.rs:2:9
|
LL | let x = vec![];
- | - ^^^^^^ cannot infer type for type parameter `T`
- | |
- | consider giving `x` the explicit type `Vec<T>`, where the type parameter `T` is specified
+ | ^
|
- = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider giving `x` an explicit type, where the type for type parameter `T` is specified
+ |
+LL | let x: Vec<T> = vec![];
+ | ++++++++
error: aborting due to previous error
error[E0282]: type annotations needed for `(Vec<T>,)`
- --> $DIR/cannot_infer_local_or_vec_in_tuples.rs:2:18
+ --> $DIR/cannot_infer_local_or_vec_in_tuples.rs:2:9
|
LL | let (x, ) = (vec![], );
- | ----- ^^^^^^ cannot infer type for type parameter `T`
- | |
- | consider giving this pattern the explicit type `(Vec<T>,)`, where the type parameter `T` is specified
+ | ^^^^^
|
- = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider giving this pattern a type, where the type for type parameter `T` is specified
+ |
+LL | let (x, ): (Vec<T>,) = (vec![], );
+ | +++++++++++
error: aborting due to previous error
}
fn ambig_return() {
- let x = || -> Vec<_> { Vec::new() }; //~ ERROR type annotations needed for the closure `fn() -> Vec<_>`
+ let x = || -> Vec<_> { Vec::new() }; //~ ERROR type annotations needed
}
fn main() {}
-error[E0282]: type annotations needed for `Vec<_>`
- --> $DIR/unknown_type_for_closure.rs:2:14
+error[E0282]: type annotations needed
+ --> $DIR/unknown_type_for_closure.rs:2:13
|
LL | let x = |b: Vec<_>| {};
- | ^ consider giving this closure parameter a type
+ | ^^^^^^^^^^^^^^ cannot infer type for struct `Vec<_>`
error[E0282]: type annotations needed
--> $DIR/unknown_type_for_closure.rs:6:14
|
LL | let x = |_| {};
- | ^ consider giving this closure parameter a type
+ | ^
+ |
+help: consider giving this closure parameter an explicit type
+ |
+LL | let x = |_: _| {};
+ | +++
error[E0282]: type annotations needed
--> $DIR/unknown_type_for_closure.rs:10:14
|
LL | let x = |k: _| {};
- | ^ consider giving this closure parameter a type
+ | ^ cannot infer type
-error[E0282]: type annotations needed for the closure `fn() -> Vec<_>`
+error[E0282]: type annotations needed
--> $DIR/unknown_type_for_closure.rs:14:28
|
LL | let x = || -> Vec<_> { Vec::new() };
- | ^^^^^^^^ cannot infer type for type parameter `T`
+ | ^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Vec`
|
-help: give this closure an explicit return type without `_` placeholders
+help: consider specifying the generic argument
|
-LL | let x = || -> Vec<_> { Vec::new() };
- | ~~~~~~
+LL | let x = || -> Vec<_> { Vec::<T>::new() };
+ | +++++
error: aborting due to 4 previous errors
--> $DIR/type-path-err-node-types.rs:23:14
|
LL | let _ = |a, b: _| -> _ { 0 };
- | ^ consider giving this closure parameter a type
+ | ^
+ |
+help: consider giving this closure parameter an explicit type
+ |
+LL | let _ = |a: _, b: _| -> _ { 0 };
+ | +++
error: aborting due to 5 previous errors
--- /dev/null
+trait FromStructReader<'a> { }
+trait ResponseHook {
+ fn get(&self);
+}
+fn foo(res : Box<dyn ResponseHook>) { res.get } //~ ERROR attempted to take value of method
+fn main() {}
--- /dev/null
+error[E0615]: attempted to take value of method `get` on type `Box<(dyn ResponseHook + 'static)>`
+ --> $DIR/issue-13853-2.rs:5:43
+ |
+LL | fn foo(res : Box<dyn ResponseHook>) { res.get }
+ | ^^^ method, not a field
+ |
+help: use parentheses to call the method
+ |
+LL | fn foo(res : Box<dyn ResponseHook>) { res.get() }
+ | ++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0615`.
--- /dev/null
+trait Deserializer<'a> { }
+
+trait Deserializable {
+ fn deserialize_token<'a, D: Deserializer<'a>>(_: D, _: &'a str) -> Self;
+}
+
+impl<'a, T: Deserializable> Deserializable for &'a str {
+ //~^ ERROR type parameter `T` is not constrained
+ fn deserialize_token<D: Deserializer<'a>>(_x: D, _y: &'a str) -> &'a str {
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
+ --> $DIR/issue-13853-5.rs:7:10
+ |
+LL | impl<'a, T: Deserializable> Deserializable for &'a str {
+ | ^ unconstrained type parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0207`.
--- /dev/null
+trait Node {
+ fn zomg();
+}
+
+trait Graph<N: Node> {
+ fn nodes<'a, I: Iterator<Item=&'a N>>(&'a self) -> I
+ where N: 'a;
+}
+
+impl<N: Node> Graph<N> for Vec<N> {
+ fn nodes<'a, I: Iterator<Item=&'a N>>(&self) -> I
+ where N: 'a
+ {
+ self.iter() //~ ERROR mismatched types
+ }
+}
+
+struct Stuff;
+
+impl Node for Stuff {
+ fn zomg() {
+ println!("zomg");
+ }
+}
+
+fn iterate<N: Node, G: Graph<N>>(graph: &G) {
+ for node in graph.iter() { //~ ERROR no method named `iter` found
+ node.zomg();
+ }
+}
+
+pub fn main() {
+ let graph = Vec::new();
+
+ graph.push(Stuff);
+
+ iterate(graph); //~ ERROR mismatched types
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-13853.rs:14:9
+ |
+LL | fn nodes<'a, I: Iterator<Item=&'a N>>(&self) -> I
+ | - this type parameter - expected `I` because of return type
+...
+LL | self.iter()
+ | ^^^^^^^^^^^ expected type parameter `I`, found struct `std::slice::Iter`
+ |
+ = note: expected type parameter `I`
+ found struct `std::slice::Iter<'_, N>`
+
+error[E0599]: no method named `iter` found for reference `&G` in the current scope
+ --> $DIR/issue-13853.rs:27:23
+ |
+LL | for node in graph.iter() {
+ | ^^^^ method not found in `&G`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-13853.rs:37:13
+ |
+LL | iterate(graph);
+ | ------- ^^^^^
+ | | |
+ | | expected reference, found struct `Vec`
+ | | help: consider borrowing here: `&graph`
+ | arguments to this function are incorrect
+ |
+ = note: expected reference `&_`
+ found struct `Vec<Stuff>`
+note: function defined here
+ --> $DIR/issue-13853.rs:26:4
+ |
+LL | fn iterate<N: Node, G: Graph<N>>(graph: &G) {
+ | ^^^^^^^ ---------
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0308, E0599.
+For more information about an error, try `rustc --explain E0308`.
error[E0282]: type annotations needed
- --> $DIR/issue-65611.rs:59:20
+ --> $DIR/issue-65611.rs:59:13
|
LL | let x = buffer.last().unwrap().0.clone();
- | -------^^^^--
- | | |
- | | cannot infer type for type parameter `T`
- | this method call resolves to `Option<&T>`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T`
|
= note: type must be known at this point
--- /dev/null
+// run-rustfix
+fn main() {
+
+let _x: isize; //~ ERROR type arguments are not allowed on this type
+let _x: i8; //~ ERROR type arguments are not allowed on this type
+let _x: i16; //~ ERROR type arguments are not allowed on this type
+let _x: i32; //~ ERROR type arguments are not allowed on this type
+let _x: i64; //~ ERROR type arguments are not allowed on this type
+let _x: usize; //~ ERROR type arguments are not allowed on this type
+let _x: u8; //~ ERROR type arguments are not allowed on this type
+let _x: u16; //~ ERROR type arguments are not allowed on this type
+let _x: u32; //~ ERROR type arguments are not allowed on this type
+let _x: u64; //~ ERROR type arguments are not allowed on this type
+let _x: char; //~ ERROR type arguments are not allowed on this type
+
+let _x: isize; //~ ERROR lifetime arguments are not allowed on this type
+let _x: i8; //~ ERROR lifetime arguments are not allowed on this type
+let _x: i16; //~ ERROR lifetime arguments are not allowed on this type
+let _x: i32; //~ ERROR lifetime arguments are not allowed on this type
+let _x: i64; //~ ERROR lifetime arguments are not allowed on this type
+let _x: usize; //~ ERROR lifetime arguments are not allowed on this type
+let _x: u8; //~ ERROR lifetime arguments are not allowed on this type
+let _x: u16; //~ ERROR lifetime arguments are not allowed on this type
+let _x: u32; //~ ERROR lifetime arguments are not allowed on this type
+let _x: u64; //~ ERROR lifetime arguments are not allowed on this type
+let _x: char; //~ ERROR lifetime arguments are not allowed on this type
+
+}
+// run-rustfix
fn main() {
-let x: isize<isize>; //~ ERROR type arguments are not allowed for this type
-let x: i8<isize>; //~ ERROR type arguments are not allowed for this type
-let x: i16<isize>; //~ ERROR type arguments are not allowed for this type
-let x: i32<isize>; //~ ERROR type arguments are not allowed for this type
-let x: i64<isize>; //~ ERROR type arguments are not allowed for this type
-let x: usize<isize>; //~ ERROR type arguments are not allowed for this type
-let x: u8<isize>; //~ ERROR type arguments are not allowed for this type
-let x: u16<isize>; //~ ERROR type arguments are not allowed for this type
-let x: u32<isize>; //~ ERROR type arguments are not allowed for this type
-let x: u64<isize>; //~ ERROR type arguments are not allowed for this type
-let x: char<isize>; //~ ERROR type arguments are not allowed for this type
+let _x: isize<isize>; //~ ERROR type arguments are not allowed on this type
+let _x: i8<isize>; //~ ERROR type arguments are not allowed on this type
+let _x: i16<isize>; //~ ERROR type arguments are not allowed on this type
+let _x: i32<isize>; //~ ERROR type arguments are not allowed on this type
+let _x: i64<isize>; //~ ERROR type arguments are not allowed on this type
+let _x: usize<isize>; //~ ERROR type arguments are not allowed on this type
+let _x: u8<isize>; //~ ERROR type arguments are not allowed on this type
+let _x: u16<isize>; //~ ERROR type arguments are not allowed on this type
+let _x: u32<isize>; //~ ERROR type arguments are not allowed on this type
+let _x: u64<isize>; //~ ERROR type arguments are not allowed on this type
+let _x: char<isize>; //~ ERROR type arguments are not allowed on this type
-let x: isize<'static>; //~ ERROR lifetime arguments are not allowed for this type
-let x: i8<'static>; //~ ERROR lifetime arguments are not allowed for this type
-let x: i16<'static>; //~ ERROR lifetime arguments are not allowed for this type
-let x: i32<'static>; //~ ERROR lifetime arguments are not allowed for this type
-let x: i64<'static>; //~ ERROR lifetime arguments are not allowed for this type
-let x: usize<'static>; //~ ERROR lifetime arguments are not allowed for this type
-let x: u8<'static>; //~ ERROR lifetime arguments are not allowed for this type
-let x: u16<'static>; //~ ERROR lifetime arguments are not allowed for this type
-let x: u32<'static>; //~ ERROR lifetime arguments are not allowed for this type
-let x: u64<'static>; //~ ERROR lifetime arguments are not allowed for this type
-let x: char<'static>; //~ ERROR lifetime arguments are not allowed for this type
+let _x: isize<'static>; //~ ERROR lifetime arguments are not allowed on this type
+let _x: i8<'static>; //~ ERROR lifetime arguments are not allowed on this type
+let _x: i16<'static>; //~ ERROR lifetime arguments are not allowed on this type
+let _x: i32<'static>; //~ ERROR lifetime arguments are not allowed on this type
+let _x: i64<'static>; //~ ERROR lifetime arguments are not allowed on this type
+let _x: usize<'static>; //~ ERROR lifetime arguments are not allowed on this type
+let _x: u8<'static>; //~ ERROR lifetime arguments are not allowed on this type
+let _x: u16<'static>; //~ ERROR lifetime arguments are not allowed on this type
+let _x: u32<'static>; //~ ERROR lifetime arguments are not allowed on this type
+let _x: u64<'static>; //~ ERROR lifetime arguments are not allowed on this type
+let _x: char<'static>; //~ ERROR lifetime arguments are not allowed on this type
}
-error[E0109]: type arguments are not allowed for this type
- --> $DIR/prim-with-args.rs:3:14
+error[E0109]: type arguments are not allowed on this type
+ --> $DIR/prim-with-args.rs:4:15
|
-LL | let x: isize<isize>;
- | ^^^^^ type argument not allowed
-
-error[E0109]: type arguments are not allowed for this type
- --> $DIR/prim-with-args.rs:4:11
+LL | let _x: isize<isize>;
+ | ----- ^^^^^ type argument not allowed
+ | |
+ | not allowed on this
+ |
+help: primitive type `isize` doesn't have generic parameters
|
-LL | let x: i8<isize>;
- | ^^^^^ type argument not allowed
+LL - let _x: isize<isize>;
+LL + let _x: isize;
+ |
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
--> $DIR/prim-with-args.rs:5:12
|
-LL | let x: i16<isize>;
- | ^^^^^ type argument not allowed
+LL | let _x: i8<isize>;
+ | -- ^^^^^ type argument not allowed
+ | |
+ | not allowed on this
+ |
+help: primitive type `i8` doesn't have generic parameters
+ |
+LL - let _x: i8<isize>;
+LL + let _x: i8;
+ |
-error[E0109]: type arguments are not allowed for this type
- --> $DIR/prim-with-args.rs:6:12
+error[E0109]: type arguments are not allowed on this type
+ --> $DIR/prim-with-args.rs:6:13
+ |
+LL | let _x: i16<isize>;
+ | --- ^^^^^ type argument not allowed
+ | |
+ | not allowed on this
+ |
+help: primitive type `i16` doesn't have generic parameters
|
-LL | let x: i32<isize>;
- | ^^^^^ type argument not allowed
+LL - let _x: i16<isize>;
+LL + let _x: i16;
+ |
-error[E0109]: type arguments are not allowed for this type
- --> $DIR/prim-with-args.rs:7:12
+error[E0109]: type arguments are not allowed on this type
+ --> $DIR/prim-with-args.rs:7:13
|
-LL | let x: i64<isize>;
- | ^^^^^ type argument not allowed
+LL | let _x: i32<isize>;
+ | --- ^^^^^ type argument not allowed
+ | |
+ | not allowed on this
+ |
+help: primitive type `i32` doesn't have generic parameters
+ |
+LL - let _x: i32<isize>;
+LL + let _x: i32;
+ |
-error[E0109]: type arguments are not allowed for this type
- --> $DIR/prim-with-args.rs:8:14
+error[E0109]: type arguments are not allowed on this type
+ --> $DIR/prim-with-args.rs:8:13
+ |
+LL | let _x: i64<isize>;
+ | --- ^^^^^ type argument not allowed
+ | |
+ | not allowed on this
|
-LL | let x: usize<isize>;
- | ^^^^^ type argument not allowed
+help: primitive type `i64` doesn't have generic parameters
+ |
+LL - let _x: i64<isize>;
+LL + let _x: i64;
+ |
-error[E0109]: type arguments are not allowed for this type
- --> $DIR/prim-with-args.rs:9:11
+error[E0109]: type arguments are not allowed on this type
+ --> $DIR/prim-with-args.rs:9:15
+ |
+LL | let _x: usize<isize>;
+ | ----- ^^^^^ type argument not allowed
+ | |
+ | not allowed on this
+ |
+help: primitive type `usize` doesn't have generic parameters
|
-LL | let x: u8<isize>;
- | ^^^^^ type argument not allowed
+LL - let _x: usize<isize>;
+LL + let _x: usize;
+ |
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
--> $DIR/prim-with-args.rs:10:12
|
-LL | let x: u16<isize>;
- | ^^^^^ type argument not allowed
+LL | let _x: u8<isize>;
+ | -- ^^^^^ type argument not allowed
+ | |
+ | not allowed on this
+ |
+help: primitive type `u8` doesn't have generic parameters
+ |
+LL - let _x: u8<isize>;
+LL + let _x: u8;
+ |
-error[E0109]: type arguments are not allowed for this type
- --> $DIR/prim-with-args.rs:11:12
+error[E0109]: type arguments are not allowed on this type
+ --> $DIR/prim-with-args.rs:11:13
+ |
+LL | let _x: u16<isize>;
+ | --- ^^^^^ type argument not allowed
+ | |
+ | not allowed on this
|
-LL | let x: u32<isize>;
- | ^^^^^ type argument not allowed
+help: primitive type `u16` doesn't have generic parameters
+ |
+LL - let _x: u16<isize>;
+LL + let _x: u16;
+ |
-error[E0109]: type arguments are not allowed for this type
- --> $DIR/prim-with-args.rs:12:12
+error[E0109]: type arguments are not allowed on this type
+ --> $DIR/prim-with-args.rs:12:13
+ |
+LL | let _x: u32<isize>;
+ | --- ^^^^^ type argument not allowed
+ | |
+ | not allowed on this
+ |
+help: primitive type `u32` doesn't have generic parameters
|
-LL | let x: u64<isize>;
- | ^^^^^ type argument not allowed
+LL - let _x: u32<isize>;
+LL + let _x: u32;
+ |
-error[E0109]: type arguments are not allowed for this type
+error[E0109]: type arguments are not allowed on this type
--> $DIR/prim-with-args.rs:13:13
|
-LL | let x: char<isize>;
- | ^^^^^ type argument not allowed
+LL | let _x: u64<isize>;
+ | --- ^^^^^ type argument not allowed
+ | |
+ | not allowed on this
+ |
+help: primitive type `u64` doesn't have generic parameters
+ |
+LL - let _x: u64<isize>;
+LL + let _x: u64;
+ |
-error[E0109]: lifetime arguments are not allowed for this type
- --> $DIR/prim-with-args.rs:15:14
+error[E0109]: type arguments are not allowed on this type
+ --> $DIR/prim-with-args.rs:14:14
+ |
+LL | let _x: char<isize>;
+ | ---- ^^^^^ type argument not allowed
+ | |
+ | not allowed on this
|
-LL | let x: isize<'static>;
- | ^^^^^^^ lifetime argument not allowed
+help: primitive type `char` doesn't have generic parameters
+ |
+LL - let _x: char<isize>;
+LL + let _x: char;
+ |
-error[E0109]: lifetime arguments are not allowed for this type
- --> $DIR/prim-with-args.rs:16:11
+error[E0109]: lifetime arguments are not allowed on this type
+ --> $DIR/prim-with-args.rs:16:15
+ |
+LL | let _x: isize<'static>;
+ | ----- ^^^^^^^ lifetime argument not allowed
+ | |
+ | not allowed on this
|
-LL | let x: i8<'static>;
- | ^^^^^^^ lifetime argument not allowed
+help: primitive type `isize` doesn't have generic parameters
+ |
+LL - let _x: isize<'static>;
+LL + let _x: isize;
+ |
-error[E0109]: lifetime arguments are not allowed for this type
+error[E0109]: lifetime arguments are not allowed on this type
--> $DIR/prim-with-args.rs:17:12
|
-LL | let x: i16<'static>;
- | ^^^^^^^ lifetime argument not allowed
+LL | let _x: i8<'static>;
+ | -- ^^^^^^^ lifetime argument not allowed
+ | |
+ | not allowed on this
+ |
+help: primitive type `i8` doesn't have generic parameters
+ |
+LL - let _x: i8<'static>;
+LL + let _x: i8;
+ |
-error[E0109]: lifetime arguments are not allowed for this type
- --> $DIR/prim-with-args.rs:18:12
+error[E0109]: lifetime arguments are not allowed on this type
+ --> $DIR/prim-with-args.rs:18:13
|
-LL | let x: i32<'static>;
- | ^^^^^^^ lifetime argument not allowed
+LL | let _x: i16<'static>;
+ | --- ^^^^^^^ lifetime argument not allowed
+ | |
+ | not allowed on this
+ |
+help: primitive type `i16` doesn't have generic parameters
+ |
+LL - let _x: i16<'static>;
+LL + let _x: i16;
+ |
-error[E0109]: lifetime arguments are not allowed for this type
- --> $DIR/prim-with-args.rs:19:12
+error[E0109]: lifetime arguments are not allowed on this type
+ --> $DIR/prim-with-args.rs:19:13
+ |
+LL | let _x: i32<'static>;
+ | --- ^^^^^^^ lifetime argument not allowed
+ | |
+ | not allowed on this
|
-LL | let x: i64<'static>;
- | ^^^^^^^ lifetime argument not allowed
+help: primitive type `i32` doesn't have generic parameters
+ |
+LL - let _x: i32<'static>;
+LL + let _x: i32;
+ |
-error[E0109]: lifetime arguments are not allowed for this type
- --> $DIR/prim-with-args.rs:20:14
+error[E0109]: lifetime arguments are not allowed on this type
+ --> $DIR/prim-with-args.rs:20:13
+ |
+LL | let _x: i64<'static>;
+ | --- ^^^^^^^ lifetime argument not allowed
+ | |
+ | not allowed on this
+ |
+help: primitive type `i64` doesn't have generic parameters
|
-LL | let x: usize<'static>;
- | ^^^^^^^ lifetime argument not allowed
+LL - let _x: i64<'static>;
+LL + let _x: i64;
+ |
-error[E0109]: lifetime arguments are not allowed for this type
- --> $DIR/prim-with-args.rs:21:11
+error[E0109]: lifetime arguments are not allowed on this type
+ --> $DIR/prim-with-args.rs:21:15
|
-LL | let x: u8<'static>;
- | ^^^^^^^ lifetime argument not allowed
+LL | let _x: usize<'static>;
+ | ----- ^^^^^^^ lifetime argument not allowed
+ | |
+ | not allowed on this
+ |
+help: primitive type `usize` doesn't have generic parameters
+ |
+LL - let _x: usize<'static>;
+LL + let _x: usize;
+ |
-error[E0109]: lifetime arguments are not allowed for this type
+error[E0109]: lifetime arguments are not allowed on this type
--> $DIR/prim-with-args.rs:22:12
|
-LL | let x: u16<'static>;
- | ^^^^^^^ lifetime argument not allowed
+LL | let _x: u8<'static>;
+ | -- ^^^^^^^ lifetime argument not allowed
+ | |
+ | not allowed on this
+ |
+help: primitive type `u8` doesn't have generic parameters
+ |
+LL - let _x: u8<'static>;
+LL + let _x: u8;
+ |
-error[E0109]: lifetime arguments are not allowed for this type
- --> $DIR/prim-with-args.rs:23:12
+error[E0109]: lifetime arguments are not allowed on this type
+ --> $DIR/prim-with-args.rs:23:13
+ |
+LL | let _x: u16<'static>;
+ | --- ^^^^^^^ lifetime argument not allowed
+ | |
+ | not allowed on this
+ |
+help: primitive type `u16` doesn't have generic parameters
|
-LL | let x: u32<'static>;
- | ^^^^^^^ lifetime argument not allowed
+LL - let _x: u16<'static>;
+LL + let _x: u16;
+ |
-error[E0109]: lifetime arguments are not allowed for this type
- --> $DIR/prim-with-args.rs:24:12
+error[E0109]: lifetime arguments are not allowed on this type
+ --> $DIR/prim-with-args.rs:24:13
|
-LL | let x: u64<'static>;
- | ^^^^^^^ lifetime argument not allowed
+LL | let _x: u32<'static>;
+ | --- ^^^^^^^ lifetime argument not allowed
+ | |
+ | not allowed on this
+ |
+help: primitive type `u32` doesn't have generic parameters
+ |
+LL - let _x: u32<'static>;
+LL + let _x: u32;
+ |
-error[E0109]: lifetime arguments are not allowed for this type
+error[E0109]: lifetime arguments are not allowed on this type
--> $DIR/prim-with-args.rs:25:13
|
-LL | let x: char<'static>;
- | ^^^^^^^ lifetime argument not allowed
+LL | let _x: u64<'static>;
+ | --- ^^^^^^^ lifetime argument not allowed
+ | |
+ | not allowed on this
+ |
+help: primitive type `u64` doesn't have generic parameters
+ |
+LL - let _x: u64<'static>;
+LL + let _x: u64;
+ |
+
+error[E0109]: lifetime arguments are not allowed on this type
+ --> $DIR/prim-with-args.rs:26:14
+ |
+LL | let _x: char<'static>;
+ | ---- ^^^^^^^ lifetime argument not allowed
+ | |
+ | not allowed on this
+ |
+help: primitive type `char` doesn't have generic parameters
+ |
+LL - let _x: char<'static>;
+LL + let _x: char;
+ |
error: aborting due to 22 previous errors
fn a() {
let mut closure0 = None;
+ //~^ ERROR type annotations needed
let vec = vec![1, 2, 3];
loop {
match closure0.take() {
Some(c) => {
return c();
- //~^ ERROR type annotations needed
}
None => { }
}
error[E0282]: type annotations needed for `Option<T>`
- --> $DIR/unboxed-closures-failed-recursive-fn-2.rs:16:32
+ --> $DIR/unboxed-closures-failed-recursive-fn-2.rs:8:9
|
LL | let mut closure0 = None;
- | ------------ consider giving `closure0` the explicit type `Option<T>`, with the type parameters specified
-...
-LL | return c();
- | ^^^ cannot infer type
+ | ^^^^^^^^^^^^
|
= note: type must be known at this point
+help: consider giving `closure0` an explicit type, where the placeholders `_` are specified
+ |
+LL | let mut closure0: Option<T> = None;
+ | +++++++++++
error: aborting due to previous error
--> $DIR/unconstrained-none.rs:4:5
|
LL | None;
- | ^^^^ cannot infer type for type parameter `T` declared on the enum `Option`
+ | ^^^^ cannot infer type of the type parameter `T` declared on the enum `Option`
+ |
+help: consider specifying the generic argument
+ |
+LL | None::<T>;
+ | +++++
error: aborting due to previous error
--> $DIR/unconstrained-ref.rs:6:5
|
LL | S { o: &None };
- | ^ cannot infer type for type parameter `T` declared on the struct `S`
+ | ^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `S`
+ |
+help: consider specifying the generic argument
+ |
+LL | S::<T> { o: &None };
+ | +++++
error: aborting due to previous error
| ^^^^
|
note: the `Copy` impl for `ManuallyDrop<String>` requires that `String: Copy`
- --> $DIR/union-copy.rs:8:5
+ --> $DIR/union-copy.rs:8:8
|
LL | a: std::mem::ManuallyDrop<String>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
|
LL | use not_existing_crate::*;
| ^^^^^^^^^^^^^^^^^^ maybe a missing crate `not_existing_crate`?
+ |
+ = help: consider adding `extern crate not_existing_crate` to use the `not_existing_crate` crate
error: aborting due to previous error
use foo::bar; //~ ERROR unresolved import `foo` [E0432]
//~^ maybe a missing crate `foo`?
+ //~| HELP consider adding `extern crate foo` to use the `foo` crate
use bar::Baz as x; //~ ERROR unresolved import `bar::Baz` [E0432]
//~| no `Baz` in `bar`
|
LL | use foo::bar;
| ^^^ maybe a missing crate `foo`?
+ |
+ = help: consider adding `extern crate foo` to use the `foo` crate
error[E0432]: unresolved import `bar::Baz`
- --> $DIR/unresolved-import.rs:4:5
+ --> $DIR/unresolved-import.rs:5:5
|
LL | use bar::Baz as x;
| ^^^^^---^^^^^
| no `Baz` in `bar`
error[E0432]: unresolved import `food::baz`
- --> $DIR/unresolved-import.rs:9:5
+ --> $DIR/unresolved-import.rs:10:5
|
LL | use food::baz;
| ^^^^^^---
| no `baz` in `food`
error[E0432]: unresolved import `food::beens`
- --> $DIR/unresolved-import.rs:14:12
+ --> $DIR/unresolved-import.rs:15:12
|
LL | use food::{beens as Foo};
| -----^^^^^^^
| help: a similar name exists in the module: `beans`
error[E0432]: unresolved import `MyEnum`
- --> $DIR/unresolved-import.rs:38:9
+ --> $DIR/unresolved-import.rs:39:9
|
LL | use MyEnum::*;
| ^^^^^^ help: a similar path exists: `self::MyEnum`
error[E0432]: unresolved import `Enum`
- --> $DIR/unresolved-import.rs:48:9
+ --> $DIR/unresolved-import.rs:49:9
|
LL | use Enum::*;
| ^^^^ help: a similar path exists: `self::Enum`
fn foo() {
- let x: usize<foo>; //~ ERROR const arguments are not allowed for this type
+ let x: usize<foo>; //~ ERROR const arguments are not allowed on this type
}
fn main() {}
-error[E0109]: const arguments are not allowed for this type
+error[E0109]: const arguments are not allowed on this type
--> $DIR/usize-generic-argument-parent.rs:2:18
|
LL | let x: usize<foo>;
- | ^^^ const argument not allowed
+ | ----- ^^^ const argument not allowed
+ | |
+ | not allowed on this
+ |
+help: primitive type `usize` doesn't have generic parameters
+ |
+LL - let x: usize<foo>;
+LL + let x: usize;
+ |
error: aborting due to previous error
-Subproject commit 39ad1039d9e3e1746177bf5d134af4c164f95528
+Subproject commit 38472bc19f2f76e245eba54a6e97ee6821b3c1db
if let Some(ref lt) = *lifetime {
if lt.name == LifetimeName::Static {
self.lts.push(RefLt::Static);
- } else if let LifetimeName::Param(ParamName::Fresh(_)) = lt.name {
+ } else if let LifetimeName::Param(_, ParamName::Fresh) = lt.name {
// Fresh lifetimes generated should be ignored.
} else if lt.is_elided() {
self.lts.push(RefLt::Unnamed);
use fmt::Write;
f.write_char('&')?;
match self.lt {
- LifetimeName::Param(ParamName::Plain(name)) => {
+ LifetimeName::Param(_, ParamName::Plain(name)) => {
name.fmt(f)?;
f.write_char(' ')?;
},
&& Lrc::ptr_eq(&unsafe_line.sf, &comment_start_line.sf)
&& let Some(src) = unsafe_line.sf.src.as_deref()
{
- comment_start_line.line < unsafe_line.line && text_has_safety_comment(
- src,
- &unsafe_line.sf.lines[comment_start_line.line + 1..=unsafe_line.line],
- unsafe_line.sf.start_pos.to_usize(),
- )
+ unsafe_line.sf.lines(|lines| {
+ comment_start_line.line < unsafe_line.line && text_has_safety_comment(
+ src,
+ &lines[comment_start_line.line + 1..=unsafe_line.line],
+ unsafe_line.sf.start_pos.to_usize(),
+ )
+ })
} else {
// Problem getting source text. Pretend a comment was found.
true
&& Lrc::ptr_eq(&unsafe_line.sf, ¯o_line.sf)
&& let Some(src) = unsafe_line.sf.src.as_deref()
{
- macro_line.line < unsafe_line.line && text_has_safety_comment(
- src,
- &unsafe_line.sf.lines[macro_line.line + 1..=unsafe_line.line],
- unsafe_line.sf.start_pos.to_usize(),
- )
+ unsafe_line.sf.lines(|lines| {
+ macro_line.line < unsafe_line.line && text_has_safety_comment(
+ src,
+ &lines[macro_line.line + 1..=unsafe_line.line],
+ unsafe_line.sf.start_pos.to_usize(),
+ )
+ })
} else {
// Problem getting source text. Pretend a comment was found.
true
// Get the text from the start of function body to the unsafe block.
// fn foo() { some_stuff; unsafe { stuff }; other_stuff; }
// ^-------------^
- body_line.line < unsafe_line.line && text_has_safety_comment(
- src,
- &unsafe_line.sf.lines[body_line.line + 1..=unsafe_line.line],
- unsafe_line.sf.start_pos.to_usize(),
- )
+ unsafe_line.sf.lines(|lines| {
+ body_line.line < unsafe_line.line && text_has_safety_comment(
+ src,
+ &lines[body_line.line + 1..=unsafe_line.line],
+ unsafe_line.sf.start_pos.to_usize(),
+ )
+ })
} else {
// Problem getting source text. Pretend a comment was found.
true
{
let split_idx = MAX_SUGGESTION_HIGHLIGHT_LINES / 2;
let span_upper = sm.span_until_char(
- sp.with_hi(line_upper.sf.lines[line_upper.line + split_idx]),
+ sp.with_hi(line_upper.sf.lines(|lines| lines[line_upper.line + split_idx])),
'\n',
);
- let span_bottom = sp.with_lo(line_bottom.sf.lines[line_bottom.line - split_idx]);
+ let span_bottom = sp.with_lo(line_bottom.sf.lines(|lines| lines[line_bottom.line - split_idx]));
let sugg_lines_vec = sugg.lines().collect::<Vec<&str>>();
let sugg_upper = sugg_lines_vec[..split_idx].join("\n");
pub fn hash_lifetime(&mut self, lifetime: Lifetime) {
std::mem::discriminant(&lifetime.name).hash(&mut self.s);
- if let LifetimeName::Param(ref name) = lifetime.name {
+ if let LifetimeName::Param(param_id, ref name) = lifetime.name {
std::mem::discriminant(name).hash(&mut self.s);
+ param_id.hash(&mut self.s);
match name {
ParamName::Plain(ref ident) => {
ident.name.hash(&mut self.s);
},
- ParamName::Fresh(ref size) => {
- size.hash(&mut self.s);
- },
- ParamName::Error => {},
+ ParamName::Fresh | ParamName::Error => {},
}
}
}
let span = original_sp(span, DUMMY_SP);
let source_map_and_line = cx.sess().source_map().lookup_line(span.lo()).unwrap();
let line_no = source_map_and_line.line;
- let line_start = source_map_and_line.sf.lines[line_no];
+ let line_start = source_map_and_line.sf.lines(|lines| lines[line_no]);
span.with_lo(line_start)
}
Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => {
check_place(tcx, *place, span, body)
},
- Rvalue::Cast(CastKind::Misc, operand, cast_ty) => {
- use rustc_middle::ty::cast::CastTy;
- let cast_in = CastTy::from_ty(operand.ty(body, tcx)).expect("bad input type for cast");
- let cast_out = CastTy::from_ty(*cast_ty).expect("bad output type for cast");
- match (cast_in, cast_out) {
- (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) => {
- Err((span, "casting pointers to ints is unstable in const fn".into()))
- },
- _ => check_operand(tcx, operand, span, body),
- }
+ Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => {
+ Err((span, "casting pointers to ints is unstable in const fn".into()))
+ },
+ Rvalue::Cast(CastKind::Misc, operand, _) => {
+ check_operand(tcx, operand, span, body)
},
- Rvalue::Cast(CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer), operand, _) => {
+ Rvalue::Cast(
+ CastKind::PointerFromExposedAddress
+ | CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer),
+ operand,
+ _
+ ) => {
check_operand(tcx, operand, span, body)
},
Rvalue::Cast(
-Subproject commit 065ff89e33b67b3527fcdd56cf8b432e593e32d4
+Subproject commit 749efd29565a9b8f47afb441aaacfcc10bc145d7
-Subproject commit 5d5bbec9b60010dd7389a084c56693baf6bda780
+Subproject commit f94fa62d69faf5bd63b3772d3ec4f0c76cf2db57
const ENTRY_LIMIT: usize = 1000;
// FIXME: The following limits should be reduced eventually.
-const ROOT_ENTRY_LIMIT: usize = 971;
-const ISSUES_ENTRY_LIMIT: usize = 2234;
+const ROOT_ENTRY_LIMIT: usize = 969;
+const ISSUES_ENTRY_LIMIT: usize = 2211;
fn check_entries(path: &Path, bad: &mut bool) {
let dirs = walkdir::WalkDir::new(&path.join("test/ui"))
"""
message_on_remove = "Issue #{number}'s nomination request has been removed."
+[notify-zulip."I-types-nominated"]
+zulip_stream = 326866 # #T-types/nominated
+topic = "#{number}: {title}"
+message_on_add = """\
+@*T-types* issue #{number} "{title}" has been nominated for team discussion.
+"""
+message_on_remove = "Issue #{number}'s nomination has been removed. Thanks all for participating!"
+message_on_close = "Issue #{number} has been closed. Thanks for participating!"
+message_on_reopen = "Issue #{number} has been reopened. Pinging @*T-types*."
+
[notify-zulip."A-edition-2021"]
required_labels = ["C-bug"]
zulip_stream = 268952 # #edition 2021