[[package]]
name = "curl"
-version = "0.4.39"
+version = "0.4.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aaa3b8db7f3341ddef15786d250106334d4a6c4b0ae4a46cd77082777d9849b9"
+checksum = "877cc2f9b8367e32b6dabb9d581557e651cb3aa693a37f8679091bbf42687d5d"
dependencies = [
"curl-sys",
"libc",
[[package]]
name = "curl-sys"
-version = "0.4.49+curl-7.79.1"
+version = "0.4.50+curl-7.79.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0f44960aea24a786a46907b8824ebc0e66ca06bf4e4978408c7499620343483"
+checksum = "4856b76919dd599f31236bb18db5f5bd36e2ce131e64f857ca5c259665b76171"
dependencies = [
"cc",
"libc",
pub template: Vec<InlineAsmTemplatePiece>,
pub template_strs: Box<[(Symbol, Option<Symbol>, Span)]>,
pub operands: Vec<(InlineAsmOperand, Span)>,
- pub clobber_abi: Option<(Symbol, Span)>,
+ pub clobber_abis: Vec<(Symbol, Span)>,
pub options: InlineAsmOptions,
pub line_spans: Vec<Span>,
}
}
#[derive(Clone, Encodable, Decodable, Debug)]
-pub struct TraitKind(
- pub IsAuto,
- pub Unsafe,
- pub Generics,
- pub GenericBounds,
- pub Vec<P<AssocItem>>,
-);
+pub struct Trait {
+ pub unsafety: Unsafe,
+ pub is_auto: IsAuto,
+ pub generics: Generics,
+ pub bounds: GenericBounds,
+ pub items: Vec<P<AssocItem>>,
+}
#[derive(Clone, Encodable, Decodable, Debug)]
-pub struct TyAliasKind(pub Defaultness, pub Generics, pub GenericBounds, pub Option<P<Ty>>);
+pub struct TyAlias {
+ pub defaultness: Defaultness,
+ pub generics: Generics,
+ pub bounds: GenericBounds,
+ pub ty: Option<P<Ty>>,
+}
#[derive(Clone, Encodable, Decodable, Debug)]
-pub struct ImplKind {
- pub unsafety: Unsafe,
- pub polarity: ImplPolarity,
+pub struct Impl {
pub defaultness: Defaultness,
- pub constness: Const,
+ pub unsafety: Unsafe,
pub generics: Generics,
-
+ pub constness: Const,
+ pub polarity: ImplPolarity,
/// The trait being implemented, if any.
pub of_trait: Option<TraitRef>,
-
pub self_ty: P<Ty>,
pub items: Vec<P<AssocItem>>,
}
#[derive(Clone, Encodable, Decodable, Debug)]
-pub struct FnKind(pub Defaultness, pub FnSig, pub Generics, pub Option<P<Block>>);
+pub struct Fn {
+ pub defaultness: Defaultness,
+ pub generics: Generics,
+ pub sig: FnSig,
+ pub body: Option<P<Block>>,
+}
#[derive(Clone, Encodable, Decodable, Debug)]
pub enum ItemKind {
/// A function declaration (`fn`).
///
/// E.g., `fn foo(bar: usize) -> usize { .. }`.
- Fn(Box<FnKind>),
+ Fn(Box<Fn>),
/// A module declaration (`mod`).
///
/// E.g., `mod foo;` or `mod foo { .. }`.
/// E.g., `extern {}` or `extern "C" {}`.
ForeignMod(ForeignMod),
/// Module-level inline assembly (from `global_asm!()`).
- GlobalAsm(InlineAsm),
+ GlobalAsm(Box<InlineAsm>),
/// A type alias (`type`).
///
/// E.g., `type Foo = Bar<u8>;`.
- TyAlias(Box<TyAliasKind>),
+ TyAlias(Box<TyAlias>),
/// An enum definition (`enum`).
///
/// E.g., `enum Foo<A, B> { C<A>, D<B> }`.
/// A trait declaration (`trait`).
///
/// E.g., `trait Foo { .. }`, `trait Foo<T> { .. }` or `auto trait Foo {}`.
- Trait(Box<TraitKind>),
+ Trait(Box<Trait>),
/// Trait alias
///
/// E.g., `trait Foo = Bar + Quux;`.
/// An implementation.
///
/// E.g., `impl<A> Foo<A> { .. }` or `impl<A> Trait for Foo<A> { .. }`.
- Impl(Box<ImplKind>),
+ Impl(Box<Impl>),
/// A macro invocation.
///
/// E.g., `foo!(..)`.
pub fn generics(&self) -> Option<&Generics> {
match self {
- Self::Fn(box FnKind(_, _, generics, _))
- | Self::TyAlias(box TyAliasKind(_, generics, ..))
+ Self::Fn(box Fn { generics, .. })
+ | Self::TyAlias(box TyAlias { generics, .. })
| Self::Enum(_, generics)
| Self::Struct(_, generics)
| Self::Union(_, generics)
- | Self::Trait(box TraitKind(_, _, generics, ..))
+ | Self::Trait(box Trait { generics, .. })
| Self::TraitAlias(generics, _)
- | Self::Impl(box ImplKind { generics, .. }) => Some(generics),
+ | Self::Impl(box Impl { generics, .. }) => Some(generics),
_ => None,
}
}
/// If `def` is parsed, then the constant is provided, and otherwise required.
Const(Defaultness, P<Ty>, Option<P<Expr>>),
/// An associated function.
- Fn(Box<FnKind>),
+ Fn(Box<Fn>),
/// An associated type.
- TyAlias(Box<TyAliasKind>),
+ TyAlias(Box<TyAlias>),
/// A macro expanding to associated items.
MacCall(MacCall),
}
impl AssocItemKind {
pub fn defaultness(&self) -> Defaultness {
match *self {
- Self::Const(def, ..)
- | Self::Fn(box FnKind(def, ..))
- | Self::TyAlias(box TyAliasKind(def, ..)) => def,
+ Self::Const(defaultness, ..)
+ | Self::Fn(box Fn { defaultness, .. })
+ | Self::TyAlias(box TyAlias { defaultness, .. }) => defaultness,
Self::MacCall(..) => Defaultness::Final,
}
}
/// A foreign static item (`static FOO: u8`).
Static(P<Ty>, Mutability, Option<P<Expr>>),
/// An foreign function.
- Fn(Box<FnKind>),
+ Fn(Box<Fn>),
/// An foreign type.
- TyAlias(Box<TyAliasKind>),
+ TyAlias(Box<TyAlias>),
/// A macro expanding to foreign items.
MacCall(MacCall),
}
vis.visit_mt(mt);
}
TyKind::BareFn(bft) => {
- let BareFnTy { unsafety: _, ext: _, generic_params, decl } = bft.deref_mut();
+ let BareFnTy { unsafety, ext: _, generic_params, decl } = bft.deref_mut();
+ visit_unsafety(unsafety, vis);
generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
vis.visit_fn_decl(decl);
}
}
pub fn noop_visit_foreign_mod<T: MutVisitor>(foreign_mod: &mut ForeignMod, vis: &mut T) {
- let ForeignMod { unsafety: _, abi: _, items } = foreign_mod;
+ let ForeignMod { unsafety, abi: _, items } = foreign_mod;
+ visit_unsafety(unsafety, vis);
items.flat_map_in_place(|item| vis.flat_map_foreign_item(item));
}
}
}
+// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
+pub fn visit_defaultness<T: MutVisitor>(defaultness: &mut Defaultness, vis: &mut T) {
+ match defaultness {
+ Defaultness::Default(span) => vis.visit_span(span),
+ Defaultness::Final => {}
+ }
+}
+
+// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
+pub fn visit_unsafety<T: MutVisitor>(unsafety: &mut Unsafe, vis: &mut T) {
+ match unsafety {
+ Unsafe::Yes(span) => vis.visit_span(span),
+ Unsafe::No => {}
+ }
+}
+
+// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
+pub fn visit_polarity<T: MutVisitor>(polarity: &mut ImplPolarity, vis: &mut T) {
+ match polarity {
+ ImplPolarity::Positive => {}
+ ImplPolarity::Negative(span) => vis.visit_span(span),
+ }
+}
+
+// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
+pub fn visit_constness<T: MutVisitor>(constness: &mut Const, vis: &mut T) {
+ match constness {
+ Const::Yes(span) => vis.visit_span(span),
+ Const::No => {}
+ }
+}
+
pub fn noop_visit_asyncness<T: MutVisitor>(asyncness: &mut Async, vis: &mut T) {
match asyncness {
Async::Yes { span: _, closure_id, return_impl_trait_id } => {
match kind {
ItemKind::ExternCrate(_orig_name) => {}
ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree),
- ItemKind::Static(ty, _, expr) | ItemKind::Const(_, ty, expr) => {
+ ItemKind::Static(ty, _, expr) => {
vis.visit_ty(ty);
visit_opt(expr, |expr| vis.visit_expr(expr));
}
- ItemKind::Fn(box FnKind(_, sig, generics, body)) => {
+ ItemKind::Const(defaultness, ty, expr) => {
+ visit_defaultness(defaultness, vis);
+ vis.visit_ty(ty);
+ visit_opt(expr, |expr| vis.visit_expr(expr));
+ }
+ ItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
+ visit_defaultness(defaultness, vis);
visit_fn_sig(sig, vis);
vis.visit_generics(generics);
visit_opt(body, |body| vis.visit_block(body));
}
- ItemKind::Mod(_unsafety, mod_kind) => match mod_kind {
- ModKind::Loaded(items, _inline, inner_span) => {
- vis.visit_span(inner_span);
- items.flat_map_in_place(|item| vis.flat_map_item(item));
+ ItemKind::Mod(unsafety, mod_kind) => {
+ visit_unsafety(unsafety, vis);
+ match mod_kind {
+ ModKind::Loaded(items, _inline, inner_span) => {
+ vis.visit_span(inner_span);
+ items.flat_map_in_place(|item| vis.flat_map_item(item));
+ }
+ ModKind::Unloaded => {}
}
- ModKind::Unloaded => {}
- },
+ }
ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm),
ItemKind::GlobalAsm(asm) => noop_visit_inline_asm(asm, vis),
- ItemKind::TyAlias(box TyAliasKind(_, generics, bounds, ty)) => {
+ ItemKind::TyAlias(box TyAlias { defaultness, generics, bounds, ty }) => {
+ visit_defaultness(defaultness, vis);
vis.visit_generics(generics);
visit_bounds(bounds, vis);
visit_opt(ty, |ty| vis.visit_ty(ty));
vis.visit_variant_data(variant_data);
vis.visit_generics(generics);
}
- ItemKind::Impl(box ImplKind {
- unsafety: _,
- polarity: _,
- defaultness: _,
- constness: _,
+ ItemKind::Impl(box Impl {
+ defaultness,
+ unsafety,
generics,
+ constness,
+ polarity,
of_trait,
self_ty,
items,
}) => {
+ visit_defaultness(defaultness, vis);
+ visit_unsafety(unsafety, vis);
vis.visit_generics(generics);
+ visit_constness(constness, vis);
+ visit_polarity(polarity, vis);
visit_opt(of_trait, |trait_ref| vis.visit_trait_ref(trait_ref));
vis.visit_ty(self_ty);
items.flat_map_in_place(|item| vis.flat_map_impl_item(item));
}
- ItemKind::Trait(box TraitKind(.., generics, bounds, items)) => {
+ ItemKind::Trait(box Trait { unsafety, is_auto: _, generics, bounds, items }) => {
+ visit_unsafety(unsafety, vis);
vis.visit_generics(generics);
visit_bounds(bounds, vis);
items.flat_map_in_place(|item| vis.flat_map_trait_item(item));
visitor.visit_vis(vis);
visit_attrs(attrs, visitor);
match kind {
- AssocItemKind::Const(_, ty, expr) => {
+ AssocItemKind::Const(defaultness, ty, expr) => {
+ visit_defaultness(defaultness, visitor);
visitor.visit_ty(ty);
visit_opt(expr, |expr| visitor.visit_expr(expr));
}
- AssocItemKind::Fn(box FnKind(_, sig, generics, body)) => {
+ AssocItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
+ visit_defaultness(defaultness, visitor);
visitor.visit_generics(generics);
visit_fn_sig(sig, visitor);
visit_opt(body, |body| visitor.visit_block(body));
}
- AssocItemKind::TyAlias(box TyAliasKind(_, generics, bounds, ty)) => {
+ AssocItemKind::TyAlias(box TyAlias { defaultness, generics, bounds, ty }) => {
+ visit_defaultness(defaultness, visitor);
visitor.visit_generics(generics);
visit_bounds(bounds, visitor);
visit_opt(ty, |ty| visitor.visit_ty(ty));
}
pub fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) {
- let FnHeader { unsafety: _, asyncness, constness: _, ext: _ } = header;
+ let FnHeader { unsafety, asyncness, constness, ext: _ } = header;
+ visit_constness(constness, vis);
vis.visit_asyncness(asyncness);
+ visit_unsafety(unsafety, vis);
}
// FIXME: Avoid visiting the crate as a `Mod` item, flat map only the inner items if possible,
visitor.visit_ty(ty);
visit_opt(expr, |expr| visitor.visit_expr(expr));
}
- ForeignItemKind::Fn(box FnKind(_, sig, generics, body)) => {
+ ForeignItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
+ visit_defaultness(defaultness, visitor);
visitor.visit_generics(generics);
visit_fn_sig(sig, visitor);
visit_opt(body, |body| visitor.visit_block(body));
}
- ForeignItemKind::TyAlias(box TyAliasKind(_, generics, bounds, ty)) => {
+ ForeignItemKind::TyAlias(box TyAlias { defaultness, generics, bounds, ty }) => {
+ visit_defaultness(defaultness, visitor);
visitor.visit_generics(generics);
visit_bounds(bounds, visitor);
visit_opt(ty, |ty| visitor.visit_ty(ty));
i += 1;
}
// like the first, a last line of all stars should be omitted
- if j > i && lines[j - 1].chars().skip(1).all(|c| c == '*') {
+ if j > i && !lines[j - 1].is_empty() && lines[j - 1].chars().all(|c| c == '*') {
j -= 1;
}
if let Some(mut idx) = token_text.find('\n') {
code_to_the_left = false;
while let Some(next_newline) = &token_text[idx + 1..].find('\n') {
- idx = idx + 1 + next_newline;
+ idx += 1 + next_newline;
comments.push(Comment {
style: CommentStyle::BlankLine,
lines: vec![],
/// parentheses while having a high degree of confidence on the correctness of the suggestion.
pub fn can_continue_expr_unambiguously(&self) -> bool {
use AssocOp::*;
- match self {
+ matches!(
+ self,
BitXor | // `{ 42 } ^ 3`
Assign | // `{ 42 } = { 42 }`
Divide | // `{ 42 } / 42`
As | // `{ 42 } as usize`
// Equal | // `{ 42 } == { 42 }` Accepting these here would regress incorrect
// NotEqual | // `{ 42 } != { 42 } struct literals parser recovery.
- Colon => true, // `{ 42 }: usize`
- _ => false,
- }
+ Colon, // `{ 42 }: usize`
+ )
}
}
visitor.visit_ty(typ);
walk_list!(visitor, visit_expr, expr);
}
- ItemKind::Fn(box FnKind(_, ref sig, ref generics, ref body)) => {
+ ItemKind::Fn(box Fn { defaultness: _, ref generics, ref sig, ref body }) => {
visitor.visit_generics(generics);
let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref());
visitor.visit_fn(kind, item.span, item.id)
walk_list!(visitor, visit_foreign_item, &foreign_module.items);
}
ItemKind::GlobalAsm(ref asm) => walk_inline_asm(visitor, asm),
- ItemKind::TyAlias(box TyAliasKind(_, ref generics, ref bounds, ref ty)) => {
+ ItemKind::TyAlias(box TyAlias { defaultness: _, ref generics, ref bounds, ref ty }) => {
visitor.visit_generics(generics);
walk_list!(visitor, visit_param_bound, bounds);
walk_list!(visitor, visit_ty, ty);
visitor.visit_generics(generics);
visitor.visit_enum_def(enum_definition, generics, item.id, item.span)
}
- ItemKind::Impl(box ImplKind {
- unsafety: _,
- polarity: _,
+ ItemKind::Impl(box Impl {
defaultness: _,
- constness: _,
+ unsafety: _,
ref generics,
+ constness: _,
+ polarity: _,
ref of_trait,
ref self_ty,
ref items,
visitor.visit_generics(generics);
visitor.visit_variant_data(struct_definition);
}
- ItemKind::Trait(box TraitKind(.., ref generics, ref bounds, ref items)) => {
+ ItemKind::Trait(box Trait {
+ unsafety: _,
+ is_auto: _,
+ ref generics,
+ ref bounds,
+ ref items,
+ }) => {
visitor.visit_generics(generics);
walk_list!(visitor, visit_param_bound, bounds);
walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Trait);
visitor.visit_ty(ty);
walk_list!(visitor, visit_expr, expr);
}
- ForeignItemKind::Fn(box FnKind(_, sig, generics, body)) => {
+ ForeignItemKind::Fn(box Fn { defaultness: _, ref generics, ref sig, ref body }) => {
visitor.visit_generics(generics);
let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, body.as_deref());
visitor.visit_fn(kind, span, id);
}
- ForeignItemKind::TyAlias(box TyAliasKind(_, generics, bounds, ty)) => {
+ ForeignItemKind::TyAlias(box TyAlias { defaultness: _, generics, bounds, ty }) => {
visitor.visit_generics(generics);
walk_list!(visitor, visit_param_bound, bounds);
walk_list!(visitor, visit_ty, ty);
visitor.visit_ty(ty);
walk_list!(visitor, visit_expr, expr);
}
- AssocItemKind::Fn(box FnKind(_, sig, generics, body)) => {
+ AssocItemKind::Fn(box Fn { defaultness: _, ref generics, ref sig, ref body }) => {
visitor.visit_generics(generics);
let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, body.as_deref());
visitor.visit_fn(kind, span, id);
}
- AssocItemKind::TyAlias(box TyAliasKind(_, generics, bounds, ty)) => {
+ AssocItemKind::TyAlias(box TyAlias { defaultness: _, generics, bounds, ty }) => {
visitor.visit_generics(generics);
walk_list!(visitor, visit_param_bound, bounds);
walk_list!(visitor, visit_ty, ty);
use rustc_ast::*;
use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::stable_set::FxHashSet;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
-use rustc_span::{Span, Symbol};
+use rustc_session::parse::feature_err;
+use rustc_span::{sym, Span, Symbol};
use rustc_target::asm;
use std::collections::hash_map::Entry;
use std::fmt::Write;
struct_span_err!(self.sess, sp, E0472, "inline assembly is unsupported on this target")
.emit();
}
+ if let Some(asm_arch) = asm_arch {
+ // Inline assembly is currently only stable for these architectures.
+ let is_stable = matches!(
+ asm_arch,
+ asm::InlineAsmArch::X86
+ | asm::InlineAsmArch::X86_64
+ | asm::InlineAsmArch::Arm
+ | asm::InlineAsmArch::AArch64
+ | asm::InlineAsmArch::RiscV32
+ | asm::InlineAsmArch::RiscV64
+ );
+ if !is_stable && !self.sess.features_untracked().asm_experimental_arch {
+ feature_err(
+ &self.sess.parse_sess,
+ sym::asm_experimental_arch,
+ sp,
+ "inline assembly is not stable yet on this architecture",
+ )
+ .emit();
+ }
+ }
if asm.options.contains(InlineAsmOptions::ATT_SYNTAX)
&& !matches!(asm_arch, Some(asm::InlineAsmArch::X86 | asm::InlineAsmArch::X86_64))
&& !self.sess.opts.actually_rustdoc
.emit();
}
- let mut clobber_abi = None;
+ let mut clobber_abis = FxHashMap::default();
if let Some(asm_arch) = asm_arch {
- if let Some((abi_name, abi_span)) = asm.clobber_abi {
- match asm::InlineAsmClobberAbi::parse(asm_arch, &self.sess.target, abi_name) {
- Ok(abi) => clobber_abi = Some((abi, abi_span)),
+ for (abi_name, abi_span) in &asm.clobber_abis {
+ match asm::InlineAsmClobberAbi::parse(asm_arch, &self.sess.target, *abi_name) {
+ Ok(abi) => {
+ // If the abi was already in the list, emit an error
+ match clobber_abis.get(&abi) {
+ Some((prev_name, prev_sp)) => {
+ let mut err = self.sess.struct_span_err(
+ *abi_span,
+ &format!("`{}` ABI specified multiple times", prev_name),
+ );
+ err.span_label(*prev_sp, "previously specified here");
+
+ // Multiple different abi names may actually be the same ABI
+ // If the specified ABIs are not the same name, alert the user that they resolve to the same ABI
+ let source_map = self.sess.source_map();
+ if source_map.span_to_snippet(*prev_sp)
+ != source_map.span_to_snippet(*abi_span)
+ {
+ err.note("these ABIs are equivalent on the current target");
+ }
+
+ err.emit();
+ }
+ None => {
+ clobber_abis.insert(abi, (abi_name, *abi_span));
+ }
+ }
+ }
Err(&[]) => {
self.sess
.struct_span_err(
- abi_span,
+ *abi_span,
"`clobber_abi` is not supported on this target",
)
.emit();
}
Err(supported_abis) => {
let mut err =
- self.sess.struct_span_err(abi_span, "invalid ABI for `clobber_abi`");
+ self.sess.struct_span_err(*abi_span, "invalid ABI for `clobber_abi`");
let mut abis = format!("`{}`", supported_abis[0]);
for m in &supported_abis[1..] {
let _ = write!(abis, ", `{}`", m);
out_expr: out_expr.as_ref().map(|expr| self.lower_expr_mut(expr)),
}
}
- InlineAsmOperand::Const { ref anon_const } => hir::InlineAsmOperand::Const {
- anon_const: self.lower_anon_const(anon_const),
- },
+ InlineAsmOperand::Const { ref anon_const } => {
+ if !self.sess.features_untracked().asm_const {
+ feature_err(
+ &self.sess.parse_sess,
+ sym::asm_const,
+ *op_sp,
+ "const operands for inline assembly are unstable",
+ )
+ .emit();
+ }
+ hir::InlineAsmOperand::Const {
+ anon_const: self.lower_anon_const(anon_const),
+ }
+ }
InlineAsmOperand::Sym { ref expr } => {
+ if !self.sess.features_untracked().asm_sym {
+ feature_err(
+ &self.sess.parse_sess,
+ sym::asm_sym,
+ *op_sp,
+ "sym operands for inline assembly are unstable",
+ )
+ .emit();
+ }
hir::InlineAsmOperand::Sym { expr: self.lower_expr_mut(expr) }
}
};
// If a clobber_abi is specified, add the necessary clobbers to the
// operands list.
- if let Some((abi, abi_span)) = clobber_abi {
+ let mut clobbered = FxHashSet::default();
+ for (abi, (_, abi_span)) in clobber_abis {
for &clobber in abi.clobbered_regs() {
+ // Don't emit a clobber for a register already clobbered
+ if clobbered.contains(&clobber) {
+ continue;
+ }
+
let mut output_used = false;
clobber.overlapping_regs(|reg| {
if used_output_regs.contains_key(®) {
},
self.lower_span(abi_span),
));
+ clobbered.insert(clobber);
}
}
}
self.lctx.with_parent_item_lifetime_defs(hir_id, |this| {
let this = &mut ItemLowerer { lctx: this };
match item.kind {
- ItemKind::Impl(box ImplKind { ref of_trait, .. }) => {
+ ItemKind::Impl(box Impl { ref of_trait, .. }) => {
this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item));
}
_ => visit::walk_item(this, item),
let (ty, body_id) = self.lower_const_item(t, span, e.as_deref());
hir::ItemKind::Const(ty, body_id)
}
- ItemKind::Fn(box FnKind(
- _,
- FnSig { ref decl, header, span: fn_sig_span },
+ ItemKind::Fn(box Fn {
+ sig: FnSig { ref decl, header, span: fn_sig_span },
ref generics,
ref body,
- )) => {
+ ..
+ }) => {
let fn_def_id = self.resolver.local_def_id(id);
self.with_new_scopes(|this| {
this.current_item = Some(ident.span);
ItemKind::GlobalAsm(ref asm) => {
hir::ItemKind::GlobalAsm(self.lower_inline_asm(span, asm))
}
- ItemKind::TyAlias(box TyAliasKind(_, ref gen, _, Some(ref ty))) => {
+ ItemKind::TyAlias(box TyAlias { ref generics, ty: Some(ref ty), .. }) => {
// We lower
//
// type Foo = impl Trait
capturable_lifetimes: &mut FxHashSet::default(),
},
);
- let generics = self.lower_generics(gen, ImplTraitContext::disallowed());
+ let generics = self.lower_generics(generics, ImplTraitContext::disallowed());
hir::ItemKind::TyAlias(ty, generics)
}
- ItemKind::TyAlias(box TyAliasKind(_, ref generics, _, None)) => {
+ ItemKind::TyAlias(box TyAlias { ref generics, ty: None, .. }) => {
let ty = self.arena.alloc(self.ty(span, hir::TyKind::Err));
let generics = self.lower_generics(generics, ImplTraitContext::disallowed());
hir::ItemKind::TyAlias(ty, generics)
self.lower_generics(generics, ImplTraitContext::disallowed()),
)
}
- ItemKind::Impl(box ImplKind {
+ ItemKind::Impl(box Impl {
unsafety,
polarity,
defaultness,
items: new_impl_items,
})
}
- ItemKind::Trait(box TraitKind(
+ ItemKind::Trait(box Trait {
is_auto,
unsafety,
ref generics,
ref bounds,
ref items,
- )) => {
+ }) => {
let bounds = self.lower_param_bounds(bounds, ImplTraitContext::disallowed());
let items = self
.arena
def_id,
ident: self.lower_ident(i.ident),
kind: match i.kind {
- ForeignItemKind::Fn(box FnKind(_, ref sig, ref generics, _)) => {
+ ForeignItemKind::Fn(box Fn { ref sig, ref generics, .. }) => {
let fdec = &sig.decl;
let (generics, (fn_dec, fn_args)) = self.add_in_band_defs(
generics,
let body = default.as_ref().map(|x| self.lower_const_body(i.span, Some(x)));
(hir::Generics::empty(), hir::TraitItemKind::Const(ty, body))
}
- AssocItemKind::Fn(box FnKind(_, ref sig, ref generics, None)) => {
+ AssocItemKind::Fn(box Fn { ref sig, ref generics, body: None, .. }) => {
let names = self.lower_fn_params_to_names(&sig.decl);
let (generics, sig) =
self.lower_method_sig(generics, sig, trait_item_def_id, false, None);
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)))
}
- AssocItemKind::Fn(box FnKind(_, ref sig, ref generics, Some(ref body))) => {
+ AssocItemKind::Fn(box Fn { ref sig, ref generics, body: Some(ref body), .. }) => {
let asyncness = sig.header.asyncness;
let body_id =
self.lower_maybe_async_body(i.span, &sig.decl, asyncness, Some(&body));
);
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)))
}
- AssocItemKind::TyAlias(box TyAliasKind(_, ref generics, ref bounds, ref default)) => {
- let ty = default.as_ref().map(|x| self.lower_ty(x, ImplTraitContext::disallowed()));
+ AssocItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. }) => {
+ let ty = ty.as_ref().map(|x| self.lower_ty(x, ImplTraitContext::disallowed()));
let generics = self.lower_generics(generics, ImplTraitContext::disallowed());
let kind = hir::TraitItemKind::Type(
self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
fn lower_trait_item_ref(&mut self, i: &AssocItem) -> hir::TraitItemRef {
let (kind, has_default) = match &i.kind {
AssocItemKind::Const(_, _, default) => (hir::AssocItemKind::Const, default.is_some()),
- AssocItemKind::TyAlias(box TyAliasKind(_, _, _, default)) => {
- (hir::AssocItemKind::Type, default.is_some())
+ AssocItemKind::TyAlias(box TyAlias { ty, .. }) => {
+ (hir::AssocItemKind::Type, ty.is_some())
}
- AssocItemKind::Fn(box FnKind(_, sig, _, default)) => {
- (hir::AssocItemKind::Fn { has_self: sig.decl.has_self() }, default.is_some())
+ AssocItemKind::Fn(box Fn { sig, body, .. }) => {
+ (hir::AssocItemKind::Fn { has_self: sig.decl.has_self() }, body.is_some())
}
AssocItemKind::MacCall(..) => unimplemented!(),
};
hir::ImplItemKind::Const(ty, self.lower_const_body(i.span, expr.as_deref())),
)
}
- AssocItemKind::Fn(box FnKind(_, sig, generics, body)) => {
+ AssocItemKind::Fn(box Fn { sig, generics, body, .. }) => {
self.current_item = Some(i.span);
let asyncness = sig.header.asyncness;
let body_id =
(generics, hir::ImplItemKind::Fn(sig, body_id))
}
- AssocItemKind::TyAlias(box TyAliasKind(_, generics, _, ty)) => {
+ AssocItemKind::TyAlias(box TyAlias { generics, ty, .. }) => {
let generics = self.lower_generics(generics, ImplTraitContext::disallowed());
let kind = match ty {
None => {
kind: match &i.kind {
AssocItemKind::Const(..) => hir::AssocItemKind::Const,
AssocItemKind::TyAlias(..) => hir::AssocItemKind::Type,
- AssocItemKind::Fn(box FnKind(_, sig, ..)) => {
+ AssocItemKind::Fn(box Fn { sig, .. }) => {
hir::AssocItemKind::Fn { has_self: sig.decl.has_self() }
}
AssocItemKind::MacCall(..) => unimplemented!(),
}
match item.kind {
- ItemKind::Impl(box ImplKind {
+ ItemKind::Impl(box Impl {
unsafety,
polarity,
defaultness: _,
});
return; // Avoid visiting again.
}
- ItemKind::Impl(box ImplKind {
+ ItemKind::Impl(box Impl {
unsafety,
polarity,
defaultness,
.emit();
}
}
- ItemKind::Fn(box FnKind(def, ref sig, ref generics, ref body)) => {
- self.check_defaultness(item.span, def);
+ ItemKind::Fn(box Fn { defaultness, ref sig, ref generics, ref body }) => {
+ self.check_defaultness(item.span, defaultness);
if body.is_none() {
let msg = "free function without a body";
}
}
}
- ItemKind::Trait(box TraitKind(
- is_auto,
- _,
- ref generics,
- ref bounds,
- ref trait_items,
- )) => {
+ ItemKind::Trait(box Trait { is_auto, ref generics, ref bounds, ref items, .. }) => {
if is_auto == IsAuto::Yes {
// Auto traits cannot have generics, super traits nor contain items.
self.deny_generic_params(generics, item.ident.span);
self.deny_super_traits(bounds, item.ident.span);
self.deny_where_clause(&generics.where_clause, item.ident.span);
- self.deny_items(trait_items, item.ident.span);
+ self.deny_items(items, item.ident.span);
}
self.no_questions_in_bounds(bounds, "supertraits", true);
self.visit_ident(item.ident);
self.visit_generics(generics);
self.with_banned_tilde_const(|this| walk_list!(this, visit_param_bound, bounds));
- walk_list!(self, visit_assoc_item, trait_items, AssocCtxt::Trait);
+ walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait);
walk_list!(self, visit_attribute, &item.attrs);
return;
}
let msg = "free static item without body";
self.error_item_without_body(item.span, "static", msg, " = <expr>;");
}
- ItemKind::TyAlias(box TyAliasKind(def, _, ref bounds, ref body)) => {
- self.check_defaultness(item.span, def);
- if body.is_none() {
+ ItemKind::TyAlias(box TyAlias { defaultness, ref bounds, ref ty, .. }) => {
+ self.check_defaultness(item.span, defaultness);
+ if ty.is_none() {
let msg = "free type alias without body";
self.error_item_without_body(item.span, "type", msg, " = <type>;");
}
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
match &fi.kind {
- ForeignItemKind::Fn(box FnKind(def, sig, _, body)) => {
- self.check_defaultness(fi.span, *def);
+ ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => {
+ self.check_defaultness(fi.span, *defaultness);
self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
self.check_foreign_item_ascii_only(fi.ident);
}
- ForeignItemKind::TyAlias(box TyAliasKind(def, generics, bounds, body)) => {
- self.check_defaultness(fi.span, *def);
- self.check_foreign_kind_bodyless(fi.ident, "type", body.as_ref().map(|b| b.span));
+ ForeignItemKind::TyAlias(box TyAlias { defaultness, generics, bounds, ty, .. }) => {
+ self.check_defaultness(fi.span, *defaultness);
+ self.check_foreign_kind_bodyless(fi.ident, "type", ty.as_ref().map(|b| b.span));
self.check_type_no_bounds(bounds, "`extern` blocks");
self.check_foreign_ty_genericless(generics);
self.check_foreign_item_ascii_only(fi.ident);
AssocItemKind::Const(_, _, body) => {
self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
}
- AssocItemKind::Fn(box FnKind(_, _, _, body)) => {
+ AssocItemKind::Fn(box Fn { body, .. }) => {
self.check_impl_item_provided(item.span, body, "function", " { <body> }");
}
- AssocItemKind::TyAlias(box TyAliasKind(_, _, bounds, body)) => {
- self.check_impl_item_provided(item.span, body, "type", " = <type>;");
+ AssocItemKind::TyAlias(box TyAlias { bounds, ty, .. }) => {
+ self.check_impl_item_provided(item.span, ty, "type", " = <type>;");
self.check_type_no_bounds(bounds, "`impl`s");
}
_ => {}
if ctxt == AssocCtxt::Trait || self.in_trait_impl {
self.invalid_visibility(&item.vis, None);
- if let AssocItemKind::Fn(box FnKind(_, sig, _, _)) = &item.kind {
+ if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
self.check_trait_fn_not_const(sig.header.constness);
self.check_trait_fn_not_async(item.span, sig.header.asyncness);
}
}
match item.kind {
- AssocItemKind::TyAlias(box TyAliasKind(_, ref generics, ref bounds, ref ty))
+ AssocItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. })
if ctxt == AssocCtxt::Trait =>
{
self.visit_vis(&item.vis);
});
walk_list!(self, visit_ty, ty);
}
- AssocItemKind::Fn(box FnKind(_, ref sig, ref generics, ref body))
+ AssocItemKind::Fn(box Fn { ref sig, ref generics, ref body, .. })
if self.in_const_trait_impl
|| ctxt == AssocCtxt::Trait
|| matches!(sig.header.constness, Const::Yes(_)) =>
use rustc_ast::{AssocTyConstraint, AssocTyConstraintKind, NodeId};
use rustc_ast::{PatKind, RangeEnd, VariantData};
use rustc_errors::struct_span_err;
-use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP};
+use rustc_feature::{AttributeGate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
use rustc_feature::{Features, GateIssue};
use rustc_session::parse::{feature_err, feature_err_issue};
use rustc_session::Session;
impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
fn visit_attribute(&mut self, attr: &ast::Attribute) {
- let attr_info =
- attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)).map(|a| **a);
+ let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
// Check feature gates for built-in attributes.
- if let Some((.., AttributeGate::Gated(_, name, descr, has_feature))) = attr_info {
- gate_feature_fn!(self, has_feature, attr.span, name, descr);
+ if let Some(BuiltinAttribute {
+ gate: AttributeGate::Gated(_, name, descr, has_feature),
+ ..
+ }) = attr_info
+ {
+ gate_feature_fn!(self, has_feature, attr.span, *name, descr);
}
// Check unstable flavors of the `#[doc]` attribute.
if attr.has_name(sym::doc) {
}
}
- ast::ItemKind::Impl(box ast::ImplKind {
- polarity, defaultness, ref of_trait, ..
- }) => {
+ ast::ItemKind::Impl(box ast::Impl { polarity, defaultness, ref of_trait, .. }) => {
if let ast::ImplPolarity::Negative(span) = polarity {
gate_feature_post!(
&self,
}
}
- ast::ItemKind::Trait(box ast::TraitKind(ast::IsAuto::Yes, ..)) => {
+ ast::ItemKind::Trait(box ast::Trait { is_auto: ast::IsAuto::Yes, .. }) => {
gate_feature_post!(
&self,
auto_traits,
gate_feature_post!(&self, decl_macro, i.span, msg);
}
- ast::ItemKind::TyAlias(box ast::TyAliasKind(_, _, _, Some(ref ty))) => {
+ ast::ItemKind::TyAlias(box ast::TyAlias { ty: Some(ref ty), .. }) => {
self.check_impl_trait(&ty)
}
ast::ExprKind::TryBlock(_) => {
gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental");
}
- ast::ExprKind::Block(_, opt_label) => {
- if let Some(label) = opt_label {
- gate_feature_post!(
- &self,
- label_break_value,
- label.ident.span,
- "labels on blocks are unstable"
- );
- }
+ ast::ExprKind::Block(_, Some(label)) => {
+ gate_feature_post!(
+ &self,
+ label_break_value,
+ label.ident.span,
+ "labels on blocks are unstable"
+ );
}
_ => {}
}
fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) {
let is_fn = match i.kind {
ast::AssocItemKind::Fn(_) => true,
- ast::AssocItemKind::TyAlias(box ast::TyAliasKind(_, ref generics, _, ref ty)) => {
+ ast::AssocItemKind::TyAlias(box ast::TyAlias { ref generics, ref ty, .. }) => {
if let (Some(_), AssocCtxt::Trait) = (ty, ctxt) {
gate_feature_post!(
&self,
self.maybe_print_comment(span.lo());
self.print_outer_attributes(attrs);
match kind {
- ast::ForeignItemKind::Fn(box ast::FnKind(def, sig, gen, body)) => {
- self.print_fn_full(sig, ident, gen, vis, *def, body.as_deref(), attrs);
+ ast::ForeignItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
+ self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
}
ast::ForeignItemKind::Static(ty, mutbl, body) => {
let def = ast::Defaultness::Final;
self.print_item_const(ident, Some(*mutbl), ty, body.as_deref(), vis, def);
}
- ast::ForeignItemKind::TyAlias(box ast::TyAliasKind(def, generics, bounds, ty)) => {
- self.print_associated_type(ident, generics, bounds, ty.as_deref(), vis, *def);
+ ast::ForeignItemKind::TyAlias(box ast::TyAlias {
+ defaultness,
+ generics,
+ bounds,
+ ty,
+ }) => {
+ self.print_associated_type(
+ ident,
+ generics,
+ bounds,
+ ty.as_deref(),
+ vis,
+ *defaultness,
+ );
}
ast::ForeignItemKind::MacCall(m) => {
self.print_mac(m);
ast::ItemKind::Const(def, ref ty, ref body) => {
self.print_item_const(item.ident, None, ty, body.as_deref(), &item.vis, def);
}
- ast::ItemKind::Fn(box ast::FnKind(def, ref sig, ref gen, ref body)) => {
+ ast::ItemKind::Fn(box ast::Fn { defaultness, ref sig, ref generics, ref body }) => {
let body = body.as_deref();
- self.print_fn_full(sig, item.ident, gen, &item.vis, def, body, &item.attrs);
+ self.print_fn_full(
+ sig,
+ item.ident,
+ generics,
+ &item.vis,
+ defaultness,
+ body,
+ &item.attrs,
+ );
}
ast::ItemKind::Mod(unsafety, ref mod_kind) => {
self.head(self.to_string(|s| {
self.print_inline_asm(asm);
self.end();
}
- ast::ItemKind::TyAlias(box ast::TyAliasKind(def, ref generics, ref bounds, ref ty)) => {
+ ast::ItemKind::TyAlias(box ast::TyAlias {
+ defaultness,
+ ref generics,
+ ref bounds,
+ ref ty,
+ }) => {
let ty = ty.as_deref();
- self.print_associated_type(item.ident, generics, bounds, ty, &item.vis, def);
+ self.print_associated_type(
+ item.ident,
+ generics,
+ bounds,
+ ty,
+ &item.vis,
+ defaultness,
+ );
}
ast::ItemKind::Enum(ref enum_definition, ref params) => {
self.print_enum_def(enum_definition, params, item.ident, item.span, &item.vis);
self.head(visibility_qualified(&item.vis, "union"));
self.print_struct(struct_def, generics, item.ident, item.span, true);
}
- ast::ItemKind::Impl(box ast::ImplKind {
+ ast::ItemKind::Impl(box ast::Impl {
unsafety,
polarity,
defaultness,
}
self.bclose(item.span);
}
- ast::ItemKind::Trait(box ast::TraitKind(
+ ast::ItemKind::Trait(box ast::Trait {
is_auto,
unsafety,
ref generics,
ref bounds,
- ref trait_items,
- )) => {
+ ref items,
+ ..
+ }) => {
self.head("");
self.print_visibility(&item.vis);
self.print_unsafety(unsafety);
self.s.word(" ");
self.bopen();
self.print_inner_attributes(&item.attrs);
- for trait_item in trait_items {
+ for trait_item in items {
self.print_assoc_item(trait_item);
}
self.bclose(item.span);
}
}
- crate fn print_record_struct_body(
- &mut self,
- fields: &Vec<ast::FieldDef>,
- span: rustc_span::Span,
- ) {
+ crate fn print_record_struct_body(&mut self, fields: &[ast::FieldDef], span: rustc_span::Span) {
self.nbsp();
self.bopen();
self.hardbreak_if_not_bol();
self.maybe_print_comment(span.lo());
self.print_outer_attributes(attrs);
match kind {
- ast::AssocItemKind::Fn(box ast::FnKind(def, sig, gen, body)) => {
- self.print_fn_full(sig, ident, gen, vis, *def, body.as_deref(), attrs);
+ ast::AssocItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
+ self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
}
ast::AssocItemKind::Const(def, ty, body) => {
self.print_item_const(ident, None, ty, body.as_deref(), vis, *def);
}
- ast::AssocItemKind::TyAlias(box ast::TyAliasKind(def, generics, bounds, ty)) => {
- self.print_associated_type(ident, generics, bounds, ty.as_deref(), vis, *def);
+ ast::AssocItemKind::TyAlias(box ast::TyAlias { defaultness, generics, bounds, ty }) => {
+ self.print_associated_type(
+ ident,
+ generics,
+ bounds,
+ ty.as_deref(),
+ vis,
+ *defaultness,
+ );
}
ast::AssocItemKind::MacCall(m) => {
self.print_mac(m);
let mut args = vec![AsmArg::Template(InlineAsmTemplatePiece::to_string(&asm.template))];
args.extend(asm.operands.iter().map(|(o, _)| AsmArg::Operand(o)));
- if let Some((abi, _)) = asm.clobber_abi {
- args.push(AsmArg::ClobberAbi(abi));
+ for (abi, _) in &asm.clobber_abis {
+ args.push(AsmArg::ClobberAbi(*abi));
}
if !asm.options.is_empty() {
args.push(AsmArg::Options(asm.options));
// We generally shouldn't have errors here because the query was
// already run, but there's no point using `delay_span_bug`
// when we're going to emit an error here anyway.
- let _errors = fulfill_cx.select_all_or_error(infcx).err().unwrap_or_else(Vec::new);
+ let _errors = fulfill_cx.select_all_or_error(infcx);
let (sub_region, cause) = infcx.with_region_constraints(|region_constraints| {
debug!("{:#?}", region_constraints);
let param = generics.type_param(¶m_ty, tcx);
if let Some(generics) = tcx
.hir()
- .get_generics(tcx.closure_base_def_id(self.mir_def_id().to_def_id()))
+ .get_generics(tcx.typeck_root_def_id(self.mir_def_id().to_def_id()))
{
suggest_constraining_type_param(
tcx,
impl BorrowExplanation {
pub(crate) fn is_explained(&self) -> bool {
- match self {
- BorrowExplanation::Unexplained => false,
- _ => true,
- }
+ !matches!(self, BorrowExplanation::Unexplained)
}
pub(crate) fn add_explanation_to_diagnostic<'tcx>(
&self,
errors_buffer: &mut Vec<Diagnostic>,
) {
let tcx = infcx.tcx;
- let base_def_id = tcx.closure_base_def_id(body.source.def_id());
+ let base_def_id = tcx.typeck_root_def_id(body.source.def_id());
if !tcx.has_attr(base_def_id, sym::rustc_regions) {
return;
}
// to store those. Otherwise, we'll pass in `None` to the
// functions below, which will trigger them to report errors
// eagerly.
- let mut outlives_requirements = infcx.tcx.is_closure(mir_def_id).then(Vec::new);
+ let mut outlives_requirements = infcx.tcx.is_typeck_child(mir_def_id).then(Vec::new);
self.check_type_tests(infcx, body, outlives_requirements.as_mut(), &mut errors_buffer);
_ => constraint_sup_scc != target_scc,
}
} else {
- match categorized_path[*i].category {
+ !matches!(
+ categorized_path[*i].category,
ConstraintCategory::OpaqueType
- | ConstraintCategory::Boring
- | ConstraintCategory::BoringNoLocation
- | ConstraintCategory::Internal
- | ConstraintCategory::Predicate(_) => false,
- _ => true,
- }
+ | ConstraintCategory::Boring
+ | ConstraintCategory::BoringNoLocation
+ | ConstraintCategory::Internal
+ | ConstraintCategory::Predicate(_)
+ )
}
};
tcx,
closure_substs,
self.num_external_vids,
- tcx.closure_base_def_id(closure_def_id),
+ tcx.typeck_root_def_id(closure_def_id),
);
debug!("apply_requirements: closure_mapping={:?}", closure_mapping);
use rustc_data_structures::vec_map::VecMap;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
+use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::lang_items::LangItem;
use rustc_index::vec::{Idx, IndexVec};
// If the region is live at at least one location in the promoted MIR,
// then add a liveness constraint to the main MIR for this region
// at the location provided as an argument to this method
- if let Some(_) = liveness_constraints.get_elements(region).next() {
+ if liveness_constraints.get_elements(region).next().is_some() {
self.cx
.borrowck_context
.constraints
// though.
let category = match place.as_local() {
Some(RETURN_PLACE) => {
- if let BorrowCheckContext {
- universal_regions:
- UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. },
- ..
- } = self.borrowck_context
- {
- if tcx.is_static(*def_id) {
+ let defining_ty = &self.borrowck_context.universal_regions.defining_ty;
+ if defining_ty.is_const() {
+ if tcx.is_static(defining_ty.def_id()) {
ConstraintCategory::UseAsStatic
} else {
ConstraintCategory::UseAsConst
}
}
TerminatorKind::SwitchInt { ref discr, switch_ty, .. } => {
+ self.check_operand(discr, term_location);
+
let discr_ty = discr.ty(body, tcx);
if let Err(terr) = self.sub_types(
discr_ty,
// FIXME: check the values
}
TerminatorKind::Call { ref func, ref args, ref destination, from_hir_call, .. } => {
+ self.check_operand(func, term_location);
+ for arg in args {
+ self.check_operand(arg, term_location);
+ }
+
let func_ty = func.ty(body, tcx);
debug!("check_terminator: call, func_ty={:?}", func_ty);
let sig = match func_ty.kind() {
self.check_call_inputs(body, term, &sig, args, term_location, from_hir_call);
}
TerminatorKind::Assert { ref cond, ref msg, .. } => {
+ self.check_operand(cond, term_location);
+
let cond_ty = cond.ty(body, tcx);
if cond_ty != tcx.types.bool {
span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty);
}
}
TerminatorKind::Yield { ref value, .. } => {
+ self.check_operand(value, term_location);
+
let value_ty = value.ty(body, tcx);
match body.yield_ty() {
None => span_mirbug!(self, term, "yield in non-generator"),
Some(RETURN_PLACE) => {
if let BorrowCheckContext {
universal_regions:
- UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. },
+ UniversalRegions {
+ defining_ty:
+ DefiningTy::Const(def_id, _)
+ | DefiningTy::InlineConst(def_id, _),
+ ..
+ },
..
} = self.borrowck_context
{
}
}
+ fn check_operand(&mut self, op: &Operand<'tcx>, location: Location) {
+ if let Operand::Constant(constant) = op {
+ let maybe_uneval = match constant.literal {
+ ConstantKind::Ty(ct) => match ct.val {
+ ty::ConstKind::Unevaluated(uv) => Some(uv),
+ _ => None,
+ },
+ _ => None,
+ };
+ if let Some(uv) = maybe_uneval {
+ if uv.promoted.is_none() {
+ let tcx = self.tcx();
+ let def_id = uv.def.def_id_for_type_of();
+ if tcx.def_kind(def_id) == DefKind::InlineConst {
+ let predicates = self.prove_closure_bounds(
+ tcx,
+ def_id.expect_local(),
+ uv.substs(tcx),
+ location,
+ );
+ self.normalize_and_prove_instantiated_predicates(
+ def_id,
+ predicates,
+ location.to_locations(),
+ );
+ }
+ }
+ }
+ }
+ }
+
fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) {
let tcx = self.tcx();
match rvalue {
Rvalue::Aggregate(ak, ops) => {
+ for op in ops {
+ self.check_operand(op, location);
+ }
self.check_aggregate_rvalue(&body, rvalue, ak, ops, location)
}
Rvalue::Repeat(operand, len) => {
+ self.check_operand(operand, location);
+
// If the length cannot be evaluated we must assume that the length can be larger
// than 1.
// If the length is larger than 1, the repeat expression will need to copy the
}
}
- Rvalue::NullaryOp(_, ty) | Rvalue::ShallowInitBox(_, ty) => {
+ Rvalue::NullaryOp(_, ty) => {
+ let trait_ref = ty::TraitRef {
+ def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
+ substs: tcx.mk_substs_trait(ty, &[]),
+ };
+
+ self.prove_trait_ref(
+ trait_ref,
+ location.to_locations(),
+ ConstraintCategory::SizedBound,
+ );
+ }
+
+ Rvalue::ShallowInitBox(operand, ty) => {
+ self.check_operand(operand, location);
+
let trait_ref = ty::TraitRef {
def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
substs: tcx.mk_substs_trait(ty, &[]),
}
Rvalue::Cast(cast_kind, op, ty) => {
+ self.check_operand(op, location);
+
match cast_kind {
CastKind::Pointer(PointerCast::ReifyFnPointer) => {
let fn_sig = op.ty(body, tcx).fn_sig(tcx);
BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge,
box (left, right),
) => {
+ self.check_operand(left, location);
+ self.check_operand(right, location);
+
let ty_left = left.ty(body, tcx);
match ty_left.kind() {
// Types with regions are comparable if they have a common super-type.
}
}
+ Rvalue::Use(operand) | Rvalue::UnaryOp(_, operand) => {
+ self.check_operand(operand, location);
+ }
+
+ Rvalue::BinaryOp(_, box (left, right))
+ | Rvalue::CheckedBinaryOp(_, box (left, right)) => {
+ self.check_operand(left, location);
+ self.check_operand(right, location);
+ }
+
Rvalue::AddressOf(..)
| Rvalue::ThreadLocalRef(..)
- | Rvalue::Use(..)
| Rvalue::Len(..)
- | Rvalue::BinaryOp(..)
- | Rvalue::CheckedBinaryOp(..)
- | Rvalue::UnaryOp(..)
| Rvalue::Discriminant(..) => {}
}
}
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
-use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt};
+use rustc_middle::ty::{self, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt};
use std::iter;
use crate::nll::ToRegionVid;
/// is that it has no inputs and a single return value, which is
/// the value of the constant.
Const(DefId, SubstsRef<'tcx>),
+
+ /// The MIR represents an inline const. The signature has no inputs and a
+ /// single return value found via `InlineConstSubsts::ty`.
+ InlineConst(DefId, SubstsRef<'tcx>),
}
impl<'tcx> DefiningTy<'tcx> {
DefiningTy::Generator(_, substs, _) => {
Either::Right(Either::Left(substs.as_generator().upvar_tys()))
}
- DefiningTy::FnDef(..) | DefiningTy::Const(..) => {
+ DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => {
Either::Right(Either::Right(iter::empty()))
}
}
pub fn implicit_inputs(self) -> usize {
match self {
DefiningTy::Closure(..) | DefiningTy::Generator(..) => 1,
- DefiningTy::FnDef(..) | DefiningTy::Const(..) => 0,
+ DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => 0,
}
}
pub fn is_fn_def(&self) -> bool {
- match *self {
- DefiningTy::FnDef(..) => true,
- _ => false,
- }
+ matches!(*self, DefiningTy::FnDef(..))
}
pub fn is_const(&self) -> bool {
- match *self {
- DefiningTy::Const(..) => true,
- _ => false,
- }
+ matches!(*self, DefiningTy::Const(..) | DefiningTy::InlineConst(..))
}
pub fn def_id(&self) -> DefId {
DefiningTy::Closure(def_id, ..)
| DefiningTy::Generator(def_id, ..)
| DefiningTy::FnDef(def_id, ..)
- | DefiningTy::Const(def_id, ..) => def_id,
+ | DefiningTy::Const(def_id, ..)
+ | DefiningTy::InlineConst(def_id, ..) => def_id,
}
}
}
tcx: TyCtxt<'tcx>,
closure_substs: SubstsRef<'tcx>,
expected_num_vars: usize,
- closure_base_def_id: DefId,
+ typeck_root_def_id: DefId,
) -> IndexVec<RegionVid, ty::Region<'tcx>> {
let mut region_mapping = IndexVec::with_capacity(expected_num_vars);
region_mapping.push(tcx.lifetimes.re_static);
region_mapping.push(fr);
});
- for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| {
+ for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
region_mapping.push(r);
});
// tests, and the resulting print-outs include def-ids
// and other things that are not stable across tests!
// So we just include the region-vid. Annoying.
- let closure_base_def_id = tcx.closure_base_def_id(def_id);
- for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| {
+ let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
+ for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),));
});
}
// FIXME: As above, we'd like to print out the region
// `r` but doing so is not stable across architectures
// and so forth.
- let closure_base_def_id = tcx.closure_base_def_id(def_id);
- for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| {
+ let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
+ for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),));
});
}
tcx.def_path_str_with_substs(def_id, substs),
));
}
+ DefiningTy::InlineConst(def_id, substs) => {
+ err.note(&format!(
+ "defining inline constant type: {}",
+ tcx.def_path_str_with_substs(def_id, substs),
+ ));
+ }
}
}
}
let mut indices = self.compute_indices(fr_static, defining_ty);
debug!("build: indices={:?}", indices);
- let closure_base_def_id = self.infcx.tcx.closure_base_def_id(self.mir_def.did.to_def_id());
+ let typeck_root_def_id = self.infcx.tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
// If this is a closure or generator, then the late-bound regions from the enclosing
// function are actually external regions to us. For example, here, 'a is not local
// fn foo<'a>() {
// let c = || { let x: &'a u32 = ...; }
// }
- if self.mir_def.did.to_def_id() != closure_base_def_id {
+ if self.mir_def.did.to_def_id() != typeck_root_def_id {
self.infcx
.replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices)
}
);
// Converse of above, if this is a function then the late-bound regions declared on its
// signature are local to the fn.
- if self.mir_def.did.to_def_id() == closure_base_def_id {
+ if self.mir_def.did.to_def_id() == typeck_root_def_id {
self.infcx
.replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices);
}
/// see `DefiningTy` for details.
fn defining_ty(&self) -> DefiningTy<'tcx> {
let tcx = self.infcx.tcx;
- let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did.to_def_id());
+ let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
match tcx.hir().body_owner_kind(self.mir_hir_id) {
BodyOwnerKind::Closure | BodyOwnerKind::Fn => {
- let defining_ty = if self.mir_def.did.to_def_id() == closure_base_def_id {
- tcx.type_of(closure_base_def_id)
+ let defining_ty = if self.mir_def.did.to_def_id() == typeck_root_def_id {
+ tcx.type_of(typeck_root_def_id)
} else {
let tables = tcx.typeck(self.mir_def.did);
tables.node_type(self.mir_hir_id)
}
BodyOwnerKind::Const | BodyOwnerKind::Static(..) => {
- assert_eq!(self.mir_def.did.to_def_id(), closure_base_def_id);
- let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
- let substs =
- self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs);
- DefiningTy::Const(self.mir_def.did.to_def_id(), substs)
+ let identity_substs = InternalSubsts::identity_for_item(tcx, typeck_root_def_id);
+ if self.mir_def.did.to_def_id() == typeck_root_def_id {
+ let substs =
+ self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs);
+ DefiningTy::Const(self.mir_def.did.to_def_id(), substs)
+ } else {
+ let ty = tcx.typeck(self.mir_def.did).node_type(self.mir_hir_id);
+ let substs = InlineConstSubsts::new(
+ tcx,
+ InlineConstSubstsParts { parent_substs: identity_substs, ty },
+ )
+ .substs;
+ let substs = self.infcx.replace_free_regions_with_nll_infer_vars(FR, substs);
+ DefiningTy::InlineConst(self.mir_def.did.to_def_id(), substs)
+ }
}
}
}
defining_ty: DefiningTy<'tcx>,
) -> UniversalRegionIndices<'tcx> {
let tcx = self.infcx.tcx;
- let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did.to_def_id());
- let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
+ let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
+ let identity_substs = InternalSubsts::identity_for_item(tcx, typeck_root_def_id);
let fr_substs = match defining_ty {
- DefiningTy::Closure(_, ref substs) | DefiningTy::Generator(_, ref substs, _) => {
+ DefiningTy::Closure(_, ref substs)
+ | DefiningTy::Generator(_, ref substs, _)
+ | DefiningTy::InlineConst(_, ref substs) => {
// In the case of closures, we rely on the fact that
// the first N elements in the ClosureSubsts are
- // inherited from the `closure_base_def_id`.
+ // inherited from the `typeck_root_def_id`.
// Therefore, when we zip together (below) with
// `identity_substs`, we will get only those regions
// that correspond to early-bound regions declared on
- // the `closure_base_def_id`.
+ // the `typeck_root_def_id`.
assert!(substs.len() >= identity_substs.len());
assert_eq!(substs.regions().count(), identity_substs.regions().count());
substs
let ty = indices.fold_to_region_vids(tcx, ty);
ty::Binder::dummy(tcx.intern_type_list(&[ty]))
}
+
+ DefiningTy::InlineConst(def_id, substs) => {
+ assert_eq!(self.mir_def.did.to_def_id(), def_id);
+ let ty = substs.as_inline_const().ty();
+ ty::Binder::dummy(tcx.intern_type_list(&[ty]))
+ }
}
}
}
indices: &mut UniversalRegionIndices<'tcx>,
) {
debug!("replace_late_bound_regions_with_nll_infer_vars(mir_def_id={:?})", mir_def_id);
- let closure_base_def_id = self.tcx.closure_base_def_id(mir_def_id.to_def_id());
- for_each_late_bound_region_defined_on(self.tcx, closure_base_def_id, |r| {
+ let typeck_root_def_id = self.tcx.typeck_root_def_id(mir_def_id.to_def_id());
+ for_each_late_bound_region_defined_on(self.tcx, typeck_root_def_id, |r| {
debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r);
if !indices.indices.contains_key(&r) {
let region_vid = self.next_nll_region_var(FR);
operands: Vec<(ast::InlineAsmOperand, Span)>,
named_args: FxHashMap<Symbol, usize>,
reg_args: FxHashSet<usize>,
- clobber_abi: Option<(Symbol, Span)>,
+ clobber_abis: Vec<(Symbol, Span)>,
options: ast::InlineAsmOptions,
options_spans: Vec<Span>,
}
operands: vec![],
named_args: FxHashMap::default(),
reg_args: FxHashSet::default(),
- clobber_abi: None,
+ clobber_abis: Vec::new(),
options: ast::InlineAsmOptions::empty(),
options_spans: vec![],
};
.span_labels(args.options_spans.clone(), "previous options")
.span_label(span, "argument")
.emit();
- } else if let Some((_, abi_span)) = args.clobber_abi {
+ } else if let Some((_, abi_span)) = args.clobber_abis.last() {
ecx.struct_span_err(span, "arguments are not allowed after clobber_abi")
- .span_label(abi_span, "clobber_abi")
+ .span_label(*abi_span, "clobber_abi")
.span_label(span, "argument")
.emit();
}
// Bail out now since this is likely to confuse MIR
return Err(err);
}
- if let Some((_, abi_span)) = args.clobber_abi {
+
+ if args.clobber_abis.len() > 0 {
if is_global_asm {
- let err =
- ecx.struct_span_err(abi_span, "`clobber_abi` cannot be used with `global_asm!`");
+ let err = ecx.struct_span_err(
+ args.clobber_abis.iter().map(|(_, span)| *span).collect::<Vec<Span>>(),
+ "`clobber_abi` cannot be used with `global_asm!`",
+ );
// Bail out now since this is likely to confuse later stages
return Err(err);
regclass_outputs.clone(),
"asm with `clobber_abi` must specify explicit registers for outputs",
)
- .span_label(abi_span, "clobber_abi")
+ .span_labels(
+ args.clobber_abis.iter().map(|(_, span)| *span).collect::<Vec<Span>>(),
+ "clobber_abi",
+ )
.span_labels(regclass_outputs, "generic outputs")
.emit();
}
p.expect(&token::OpenDelim(token::DelimToken::Paren))?;
- let clobber_abi = match p.parse_str_lit() {
- Ok(str_lit) => str_lit.symbol_unescaped,
- Err(opt_lit) => {
- let span = opt_lit.map_or(p.token.span, |lit| lit.span);
- let mut err = p.sess.span_diagnostic.struct_span_err(span, "expected string literal");
- err.span_label(span, "not a string literal");
- return Err(err);
- }
- };
+ if p.eat(&token::CloseDelim(token::DelimToken::Paren)) {
+ let err = p.sess.span_diagnostic.struct_span_err(
+ p.token.span,
+ "at least one abi must be provided as an argument to `clobber_abi`",
+ );
+ return Err(err);
+ }
- p.expect(&token::CloseDelim(token::DelimToken::Paren))?;
+ let mut new_abis = Vec::new();
+ loop {
+ match p.parse_str_lit() {
+ Ok(str_lit) => {
+ new_abis.push((str_lit.symbol_unescaped, str_lit.span));
+ }
+ Err(opt_lit) => {
+ // If the non-string literal is a closing paren then it's the end of the list and is fine
+ if p.eat(&token::CloseDelim(token::DelimToken::Paren)) {
+ break;
+ }
+ let span = opt_lit.map_or(p.token.span, |lit| lit.span);
+ let mut err =
+ p.sess.span_diagnostic.struct_span_err(span, "expected string literal");
+ err.span_label(span, "not a string literal");
+ return Err(err);
+ }
+ };
- let new_span = span_start.to(p.prev_token.span);
+ // Allow trailing commas
+ if p.eat(&token::CloseDelim(token::DelimToken::Paren)) {
+ break;
+ }
+ p.expect(&token::Comma)?;
+ }
- if let Some((_, prev_span)) = args.clobber_abi {
- let mut err = p
- .sess
- .span_diagnostic
- .struct_span_err(new_span, "clobber_abi specified multiple times");
- err.span_label(prev_span, "clobber_abi previously specified here");
- return Err(err);
- } else if !args.options_spans.is_empty() {
+ let full_span = span_start.to(p.prev_token.span);
+
+ if !args.options_spans.is_empty() {
let mut err = p
.sess
.span_diagnostic
- .struct_span_err(new_span, "clobber_abi is not allowed after options");
+ .struct_span_err(full_span, "clobber_abi is not allowed after options");
err.span_labels(args.options_spans.clone(), "options");
return Err(err);
}
- args.clobber_abi = Some((clobber_abi, new_span));
+ match &new_abis[..] {
+ // should have errored above during parsing
+ [] => unreachable!(),
+ [(abi, _span)] => args.clobber_abis.push((*abi, full_span)),
+ [abis @ ..] => {
+ for (abi, span) in abis {
+ args.clobber_abis.push((*abi, *span));
+ }
+ }
+ }
Ok(())
}
if let Some(snippet) = &template_snippet {
if let Some(pos) = snippet.find(needle) {
let end = pos
- + &snippet[pos..]
+ + snippet[pos..]
.find(|c| matches!(c, '\n' | ';' | '\\' | '"'))
.unwrap_or(snippet[pos..].len() - 1);
let inner = InnerSpan::new(pos, end);
template,
template_strs: template_strs.into_boxed_slice(),
operands: args.operands,
- clobber_abi: args.clobber_abi,
+ clobber_abis: args.clobber_abis,
options: args.options,
line_spans,
})
ident: Ident::empty(),
attrs: Vec::new(),
id: ast::DUMMY_NODE_ID,
- kind: ast::ItemKind::GlobalAsm(inline_asm),
+ kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)),
vis: ast::Visibility {
span: sp.shrink_to_lo(),
kind: ast::VisibilityKind::Inherited,
tokens: None,
},
attrs: Vec::new(),
- kind: ast::AssocItemKind::TyAlias(Box::new(ast::TyAliasKind(
- ast::Defaultness::Final,
- Generics::default(),
- Vec::new(),
- Some(type_def.to_ty(cx, self.span, type_ident, generics)),
- ))),
+ kind: ast::AssocItemKind::TyAlias(Box::new(ast::TyAlias {
+ defaultness: ast::Defaultness::Final,
+ generics: Generics::default(),
+ bounds: Vec::new(),
+ ty: Some(type_def.to_ty(cx, self.span, type_ident, generics)),
+ })),
tokens: None,
})
});
self.span,
Ident::empty(),
a,
- ast::ItemKind::Impl(Box::new(ast::ImplKind {
+ ast::ItemKind::Impl(Box::new(ast::Impl {
unsafety,
polarity: ast::ImplPolarity::Positive,
defaultness: ast::Defaultness::Final,
decl: fn_decl,
span: trait_.span,
};
- let def = ast::Defaultness::Final;
+ let defaultness = ast::Defaultness::Final;
// Create the method.
P(ast::AssocItem {
tokens: None,
},
ident: method_ident,
- kind: ast::AssocItemKind::Fn(Box::new(ast::FnKind(
- def,
+ kind: ast::AssocItemKind::Fn(Box::new(ast::Fn {
+ defaultness,
sig,
- fn_generics,
- Some(body_block),
- ))),
+ generics: fn_generics,
+ body: Some(body_block),
+ })),
tokens: None,
})
}
use rustc_ast as ast;
use rustc_ast::ptr::P;
-use rustc_ast::{ImplKind, ItemKind, MetaItem};
+use rustc_ast::{Impl, ItemKind, MetaItem};
use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier};
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::Span;
span,
Ident::empty(),
attrs,
- ItemKind::Impl(Box::new(ImplKind {
+ ItemKind::Impl(Box::new(Impl {
unsafety: ast::Unsafe::No,
polarity: ast::ImplPolarity::Positive,
defaultness: ast::Defaultness::Final,
/// Actually builds the expression which the format_args! block will be
/// expanded to.
fn into_expr(self) -> P<ast::Expr> {
- let mut locals =
- Vec::with_capacity((0..self.args.len()).map(|i| self.arg_unique_types[i].len()).sum());
- let mut counts = Vec::with_capacity(self.count_args.len());
- let mut pats = Vec::with_capacity(self.args.len());
+ let mut args = Vec::with_capacity(
+ self.arg_unique_types.iter().map(|v| v.len()).sum::<usize>() + self.count_args.len(),
+ );
let mut heads = Vec::with_capacity(self.args.len());
- let names_pos: Vec<_> = (0..self.args.len())
- .map(|i| Ident::from_str_and_span(&format!("arg{}", i), self.macsp))
- .collect();
-
// First, build up the static array which will become our precompiled
// format "string"
let pieces = self.ecx.expr_vec_slice(self.fmtsp, self.str_pieces);
// of each variable because we don't want to move out of the arguments
// passed to this function.
for (i, e) in self.args.into_iter().enumerate() {
- let name = names_pos[i];
- let span = self.ecx.with_def_site_ctxt(e.span);
- pats.push(self.ecx.pat_ident(span, name));
for arg_ty in self.arg_unique_types[i].iter() {
- locals.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, name));
+ args.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, i));
}
heads.push(self.ecx.expr_addr_of(e.span, e));
}
Exact(i) => i,
_ => panic!("should never happen"),
};
- let name = names_pos[index];
let span = spans_pos[index];
- counts.push(Context::format_arg(self.ecx, self.macsp, span, &Count, name));
+ args.push(Context::format_arg(self.ecx, self.macsp, span, &Count, index));
}
- // Now create a vector containing all the arguments
- let args = locals.into_iter().chain(counts.into_iter());
-
- let args_array = self.ecx.expr_vec(self.macsp, args.collect());
+ let args_array = self.ecx.expr_vec(self.macsp, args);
// Constructs an AST equivalent to:
//
// But the nested match expression is proved to perform not as well
// as series of let's; the first approach does.
let args_match = {
- let pat = self.ecx.pat_tuple(self.macsp, pats);
+ let pat = self.ecx.pat_ident(self.macsp, Ident::new(sym::_args, self.macsp));
let arm = self.ecx.arm(self.macsp, pat, args_array);
let head = self.ecx.expr(self.macsp, ast::ExprKind::Tup(heads));
self.ecx.expr_match(self.macsp, head, vec![arm])
macsp: Span,
mut sp: Span,
ty: &ArgumentType,
- arg: Ident,
+ arg_index: usize,
) -> P<ast::Expr> {
sp = ecx.with_def_site_ctxt(sp);
- let arg = ecx.expr_ident(sp, arg);
+ let arg = ecx.expr_ident(sp, Ident::new(sym::_args, sp));
+ let arg = ecx.expr(sp, ast::ExprKind::Field(arg, Ident::new(sym::integer(arg_index), sp)));
let trait_ = match *ty {
Placeholder(trait_) if trait_ == "<invalid>" => return DummyResult::raw_expr(sp, true),
Placeholder(trait_) => trait_,
};
use rustc_ast::ptr::P;
use rustc_ast::{self as ast, Attribute, Expr, FnHeader, FnSig, Generics, Param, StmtKind};
-use rustc_ast::{FnKind, ItemKind, Mutability, Stmt, Ty, TyKind, Unsafe};
+use rustc_ast::{Fn, ItemKind, Mutability, Stmt, Ty, TyKind, Unsafe};
use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::Span;
let decl = self.cx.fn_decl(abi_args, ast::FnRetTy::Ty(output_ty));
let header = FnHeader { unsafety: Unsafe::Yes(self.span), ..FnHeader::default() };
let sig = FnSig { decl, header, span: self.span };
- let block = Some(self.cx.block_expr(output_expr));
- let kind = ItemKind::Fn(Box::new(FnKind(
- ast::Defaultness::Final,
+ let body = Some(self.cx.block_expr(output_expr));
+ let kind = ItemKind::Fn(Box::new(Fn {
+ defaultness: ast::Defaultness::Final,
sig,
- Generics::default(),
- block,
- )));
+ generics: Generics::default(),
+ body,
+ }));
let item = self.cx.item(
self.span,
Ident::from_str_and_span(&self.kind.fn_name(method.name), self.span),
fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
let has_should_panic_attr = cx.sess.contains_name(&i.attrs, sym::should_panic);
let sd = &cx.sess.parse_sess.span_diagnostic;
- if let ast::ItemKind::Fn(box ast::FnKind(_, ref sig, ref generics, _)) = i.kind {
+ if let ast::ItemKind::Fn(box ast::Fn { ref sig, ref generics, .. }) = i.kind {
if let ast::Unsafe::Yes(span) = sig.header.unsafety {
sd.struct_span_err(i.span, "unsafe functions cannot be used for tests")
.span_label(span, "`unsafe` because of this")
}
fn has_bench_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
- let has_sig = if let ast::ItemKind::Fn(box ast::FnKind(_, ref sig, _, _)) = i.kind {
+ let has_sig = if let ast::ItemKind::Fn(box ast::Fn { ref sig, .. }) = i.kind {
// N.B., inadequate check, but we're running
// well before resolve, can't get too deep.
sig.decl.inputs.len() == 1
let decl = ecx.fn_decl(vec![], ast::FnRetTy::Ty(main_ret_ty));
let sig = ast::FnSig { decl, header: ast::FnHeader::default(), span: sp };
- let def = ast::Defaultness::Final;
- let main = ast::ItemKind::Fn(Box::new(ast::FnKind(
- def,
+ let defaultness = ast::Defaultness::Final;
+ let main = ast::ItemKind::Fn(Box::new(ast::Fn {
+ defaultness,
sig,
- ast::Generics::default(),
- Some(main_body),
- )));
+ generics: ast::Generics::default(),
+ body: Some(main_body),
+ }));
// Honor the reexport_test_harness_main attribute
let main_id = match cx.reexport_test_harness_main {
};
use rustc_codegen_ssa::traits::*;
use rustc_codegen_ssa::{CompiledModule, ModuleCodegen};
+use rustc_data_structures::profiling::SelfProfilerRef;
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_errors::{FatalError, Handler, Level};
use rustc_fs_util::{link_or_copy, path_to_c_string};
output: &Path,
dwo_output: Option<&Path>,
file_type: llvm::FileType,
+ self_profiler_ref: &SelfProfilerRef,
) -> Result<(), FatalError> {
unsafe {
let output_c = path_to_c_string(output);
file_type,
)
};
+
+ // Record artifact sizes for self-profiling
+ if result == llvm::LLVMRustResult::Success {
+ let artifact_kind = match file_type {
+ llvm::FileType::ObjectFile => "object_file",
+ llvm::FileType::AssemblyFile => "assembly_file",
+ };
+ record_artifact_size(self_profiler_ref, artifact_kind, output);
+ if let Some(dwo_file) = dwo_output {
+ record_artifact_size(self_profiler_ref, "dwo_file", dwo_file);
+ }
+ }
+
result.into_result().map_err(|()| {
let msg = format!("could not write output to {}", output.display());
llvm_err(handler, &msg)
cookie = 0;
}
let level = match level {
- llvm::DiagnosticLevel::Error => Level::Error,
+ llvm::DiagnosticLevel::Error => Level::Error { lint: false },
llvm::DiagnosticLevel::Warning => Level::Warning,
llvm::DiagnosticLevel::Note | llvm::DiagnosticLevel::Remark => Level::Note,
};
let thin = ThinBuffer::new(llmod);
let data = thin.data();
+ if let Some(bitcode_filename) = bc_out.file_name() {
+ cgcx.prof.artifact_size(
+ "llvm_bitcode",
+ bitcode_filename.to_string_lossy(),
+ data.len() as u64,
+ );
+ }
+
if config.emit_bc || config.emit_obj == EmitObj::Bitcode {
let _timer = cgcx.prof.generic_activity_with_arg(
"LLVM_module_codegen_emit_bitcode",
}
let result = llvm::LLVMRustPrintModule(llmod, out_c.as_ptr(), demangle_callback);
+
+ if result == llvm::LLVMRustResult::Success {
+ record_artifact_size(&cgcx.prof, "llvm_ir", &out);
+ }
+
result.into_result().map_err(|()| {
let msg = format!("failed to write LLVM IR to {}", out.display());
llvm_err(diag_handler, &msg)
&path,
None,
llvm::FileType::AssemblyFile,
+ &cgcx.prof,
)
})?;
}
&obj_out,
dwo_out,
llvm::FileType::ObjectFile,
+ &cgcx.prof,
)
})?;
}
symbol_name.starts_with(b"__llvm_profile_")
}
}
+
+fn record_artifact_size(
+ self_profiler_ref: &SelfProfilerRef,
+ artifact_kind: &'static str,
+ path: &Path,
+) {
+ // Don't stat the file if we are not going to record its size.
+ if !self_profiler_ref.enabled() {
+ return;
+ }
+
+ if let Some(artifact_name) = path.file_name() {
+ let file_size = std::fs::metadata(path).map(|m| m.len()).unwrap_or(0);
+ self_profiler_ref.artifact_size(artifact_kind, artifact_name.to_string_lossy(), file_size);
+ }
+}
type_names::push_item_name(self.tcx(), def_id, false, &mut name);
// Find the enclosing function, in case this is a closure.
- let enclosing_fn_def_id = self.tcx().closure_base_def_id(def_id);
+ let enclosing_fn_def_id = self.tcx().typeck_root_def_id(def_id);
// Get_template_parameters() will append a `<...>` clause to the function
// name if necessary.
use rustc_middle::ty::{self, Ty};
use rustc_middle::{bug, span_bug};
use rustc_span::{sym, symbol::kw, Span, Symbol};
-use rustc_target::abi::{self, HasDataLayout, Primitive};
+use rustc_target::abi::{self, Align, HasDataLayout, Primitive};
use rustc_target::spec::{HasTargetSpec, PanicStrategy};
use std::cmp::Ordering;
let arg_tys = sig.inputs();
if name == sym::simd_select_bitmask {
- let in_ty = arg_tys[0];
- let m_len = match in_ty.kind() {
- // Note that this `.unwrap()` crashes for isize/usize, that's sort
- // of intentional as there's not currently a use case for that.
- ty::Int(i) => i.bit_width().unwrap(),
- ty::Uint(i) => i.bit_width().unwrap(),
- _ => return_error!("`{}` is not an integral type", in_ty),
- };
require_simd!(arg_tys[1], "argument");
- let (v_len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
- require!(
- // Allow masks for vectors with fewer than 8 elements to be
- // represented with a u8 or i8.
- m_len == v_len || (m_len == 8 && v_len < 8),
- "mismatched lengths: mask length `{}` != other vector length `{}`",
- m_len,
- v_len
- );
+ let (len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
+
+ let expected_int_bits = (len.max(8) - 1).next_power_of_two();
+ let expected_bytes = len / 8 + ((len % 8 > 0) as u64);
+
+ let mask_ty = arg_tys[0];
+ let mask = match mask_ty.kind() {
+ ty::Int(i) if i.bit_width() == Some(expected_int_bits) => args[0].immediate(),
+ ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => args[0].immediate(),
+ ty::Array(elem, len)
+ if matches!(elem.kind(), ty::Uint(ty::UintTy::U8))
+ && len.try_eval_usize(bx.tcx, ty::ParamEnv::reveal_all())
+ == Some(expected_bytes) =>
+ {
+ let place = PlaceRef::alloca(bx, args[0].layout);
+ args[0].val.store(bx, place);
+ let int_ty = bx.type_ix(expected_bytes * 8);
+ let ptr = bx.pointercast(place.llval, bx.cx.type_ptr_to(int_ty));
+ bx.load(int_ty, ptr, Align::ONE)
+ }
+ _ => return_error!(
+ "invalid bitmask `{}`, expected `u{}` or `[u8; {}]`",
+ mask_ty,
+ expected_int_bits,
+ expected_bytes
+ ),
+ };
+
let i1 = bx.type_i1();
- let im = bx.type_ix(v_len);
- let i1xn = bx.type_vector(i1, v_len);
- let m_im = bx.trunc(args[0].immediate(), im);
+ let im = bx.type_ix(len);
+ let i1xn = bx.type_vector(i1, len);
+ let m_im = bx.trunc(mask, im);
let m_i1s = bx.bitcast(m_im, i1xn);
return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate()));
}
if name == sym::simd_bitmask {
// The `fn simd_bitmask(vector) -> unsigned integer` intrinsic takes a
- // vector mask and returns an unsigned integer containing the most
- // significant bit (MSB) of each lane.
-
- // If the vector has less than 8 lanes, a u8 is returned with zeroed
- // trailing bits.
+ // vector mask and returns the most significant bit (MSB) of each lane in the form
+ // of either:
+ // * an unsigned integer
+ // * an array of `u8`
+ // If the vector has less than 8 lanes, a u8 is returned with zeroed trailing bits.
+ //
+ // The bit order of the result depends on the byte endianness, LSB-first for little
+ // endian and MSB-first for big endian.
let expected_int_bits = in_len.max(8);
- match ret_ty.kind() {
- ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => (),
- _ => return_error!("bitmask `{}`, expected `u{}`", ret_ty, expected_int_bits),
- }
+ let expected_bytes = expected_int_bits / 8 + ((expected_int_bits % 8 > 0) as u64);
// Integer vector <i{in_bitwidth} x in_len>:
let (i_xn, in_elem_bitwidth) = match in_elem.kind() {
let i1xn = bx.trunc(i_xn_msb, bx.type_vector(bx.type_i1(), in_len));
// Bitcast <i1 x N> to iN:
let i_ = bx.bitcast(i1xn, bx.type_ix(in_len));
- // Zero-extend iN to the bitmask type:
- return Ok(bx.zext(i_, bx.type_ix(expected_int_bits)));
+
+ match ret_ty.kind() {
+ ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => {
+ // Zero-extend iN to the bitmask type:
+ return Ok(bx.zext(i_, bx.type_ix(expected_int_bits)));
+ }
+ ty::Array(elem, len)
+ if matches!(elem.kind(), ty::Uint(ty::UintTy::U8))
+ && len.try_eval_usize(bx.tcx, ty::ParamEnv::reveal_all())
+ == Some(expected_bytes) =>
+ {
+ // Zero-extend iN to the array lengh:
+ let ze = bx.zext(i_, bx.type_ix(expected_bytes * 8));
+
+ // Convert the integer to a byte array
+ let ptr = bx.alloca(bx.type_ix(expected_bytes * 8), Align::ONE);
+ bx.store(ze, ptr, Align::ONE);
+ let array_ty = bx.type_array(bx.type_i8(), expected_bytes);
+ let ptr = bx.pointercast(ptr, bx.cx.type_ptr_to(array_ty));
+ return Ok(bx.load(array_ty, ptr, Align::ONE));
+ }
+ _ => return_error!(
+ "cannot return `{}`, expected `u{}` or `[u8; {}]`",
+ ret_ty,
+ expected_int_bits,
+ expected_bytes
+ ),
+ }
}
fn simd_simple_float_intrinsic(
if sess.opts.json_artifact_notifications {
sess.parse_sess.span_diagnostic.emit_artifact_notification(&out_filename, "link");
}
+
+ if sess.prof.enabled() {
+ if let Some(artifact_name) = out_filename.file_name() {
+ // Record size for self-profiling
+ let file_size = std::fs::metadata(&out_filename).map(|m| m.len()).unwrap_or(0);
+
+ sess.prof.artifact_size(
+ "linked_artifact",
+ artifact_name.to_string_lossy(),
+ file_size,
+ );
+ }
+ }
}
}
}
fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {
- fn find_sanitizer_runtime(sess: &Session, filename: &String) -> PathBuf {
+ fn find_sanitizer_runtime(sess: &Session, filename: &str) -> PathBuf {
let session_tlib =
filesearch::make_target_lib_path(&sess.sysroot, sess.opts.target_triple.triple());
- let path = session_tlib.join(&filename);
+ let path = session_tlib.join(filename);
if path.exists() {
return session_tlib;
} else {
let msg = msg.strip_prefix("error: ").unwrap_or(&msg);
let mut err = match level {
- Level::Error => sess.struct_err(&msg),
+ Level::Error { lint: false } => sess.struct_err(&msg),
Level::Warning => sess.struct_warn(&msg),
Level::Note => sess.struct_note_without_error(&msg),
_ => bug!("Invalid inline asm diagnostic level"),
// info for MSVC debugger. However, wrapping these types' names in a synthetic type
// causes the .natvis engine for WinDbg to fail to display their data, so we opt these
// types out to aid debugging in MSVC.
- let is_slice_or_str = match *inner_type.kind() {
- ty::Slice(_) | ty::Str => true,
- _ => false,
- };
+ let is_slice_or_str = matches!(*inner_type.kind(), ty::Slice(_) | ty::Str);
if !cpp_like_names {
output.push('&');
("aes", Some(sym::arm_target_feature)),
("sha2", Some(sym::arm_target_feature)),
("i8mm", Some(sym::arm_target_feature)),
+ ("dotprod", Some(sym::arm_target_feature)),
("v5te", Some(sym::arm_target_feature)),
("v6", Some(sym::arm_target_feature)),
("v6k", Some(sym::arm_target_feature)),
impl MachineStopType for ConstEvalErrKind {
fn is_hard_err(&self) -> bool {
- match self {
- Self::Panic { .. } => true,
- _ => false,
- }
+ matches!(self, Self::Panic { .. })
}
}
| DefKind::Static
| DefKind::ConstParam
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::AssocConst
),
"Unexpected DefKind: {:?}",
// If the function itself is not annotated with `const`, it may still be a `const fn`
// if it resides in a const trait impl.
is_parent_const_impl_raw(tcx, hir_id)
- } else if let hir::Node::Ctor(_) = node {
- true
} else {
- false
+ matches!(node, hir::Node::Ctor(_))
}
}
args: &[GenericArg<'tcx>],
) -> Result<Self::Path, Self::Error> {
self = print_prefix(self)?;
- let args = args.iter().cloned().filter(|arg| match arg.unpack() {
- GenericArgKind::Lifetime(_) => false,
- _ => true,
- });
+ let args =
+ args.iter().cloned().filter(|arg| !matches!(arg.unpack(), GenericArgKind::Lifetime(_)));
if args.clone().next().is_some() {
self.generic_delimiters(|cx| cx.comma_sep(args))
} else {
/// Whether to enforce the validity invariant
fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
+ /// Whether to enforce validity (e.g., initialization and not having ptr provenance)
+ /// of integers and floats.
+ fn enforce_number_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
+
/// Whether function calls should be [ABI](Abi)-checked.
fn enforce_abi(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
true
false // for now, we don't enforce validity
}
+ #[inline(always)]
+ fn enforce_number_validity(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
+ true
+ }
+
#[inline(always)]
fn call_extra_fn(
_ecx: &mut InterpCx<$mir, $tcx, Self>,
// Figure out how to pass which arguments.
// The Rust ABI is special: ZST get skipped.
- let rust_abi = match caller_abi {
- Abi::Rust | Abi::RustCall => true,
- _ => false,
- };
+ let rust_abi = matches!(caller_abi, Abi::Rust | Abi::RustCall);
+
// We have two iterators: Where the arguments come from,
// and where they go to.
let value = self.read_scalar(value)?;
// NOTE: Keep this in sync with the array optimization for int/float
// types below!
- if self.ctfe_mode.is_some() {
+ if M::enforce_number_validity(self.ecx) {
// Integers/floats in CTFE: Must be scalar bits, pointers are dangerous
let is_bits = value.check_init().map_or(false, |v| v.try_to_int().is_ok());
if !is_bits {
{ "{}", value } expected { "initialized plain (non-pointer) bytes" }
)
}
- } else {
- // At run-time, for now, we accept *anything* for these types, including
- // uninit. We should fix that, but let's start low.
}
Ok(true)
}
}
};
+ let allow_uninit_and_ptr = !M::enforce_number_validity(self.ecx);
match alloc.check_bytes(
alloc_range(Size::ZERO, size),
- /*allow_uninit_and_ptr*/ self.ctfe_mode.is_none(),
+ allow_uninit_and_ptr,
) {
// In the happy case, we needn't check anything else.
Ok(()) => {}
.body
.basic_blocks()
.iter_enumerated()
- .find(|(_, block)| match block.terminator().kind {
- TerminatorKind::Return => true,
- _ => false,
- })
+ .find(|(_, block)| matches!(block.terminator().kind, TerminatorKind::Return))
.map(|(bb, _)| bb);
let return_block = match return_block {
let mut fulfillment_cx = traits::FulfillmentContext::new();
let sync_def_id = tcx.require_lang_item(LangItem::Sync, Some(body.span));
fulfillment_cx.register_bound(&infcx, ty::ParamEnv::empty(), ty, sync_def_id, cause);
- if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
- infcx.report_fulfillment_errors(&err, None, false);
+ let errors = fulfillment_cx.select_all_or_error(&infcx);
+ if !errors.is_empty() {
+ infcx.report_fulfillment_errors(&errors, None, false);
}
});
}
let mut selcx = SelectionContext::with_constness(&infcx, hir::Constness::Const);
selcx.select(&obligation)
});
- match implsrc {
- Ok(Some(ImplSource::ConstDrop(_)))
- | Ok(Some(ImplSource::Param(_, ty::BoundConstness::ConstIfConst))) => false,
- _ => true,
- }
+ !matches!(
+ implsrc,
+ Ok(Some(
+ ImplSource::ConstDrop(_) | ImplSource::Param(_, ty::BoundConstness::ConstIfConst)
+ ))
+ )
}
fn in_adt_inherently(cx: &ConstCx<'_, 'tcx>, adt: &'tcx AdtDef, _: SubstsRef<'tcx>) -> bool {
#[track_caller]
pub fn borrow(&self) -> MappedReadGuard<'_, T> {
let borrow = self.value.borrow();
- if let None = &*borrow {
+ if borrow.is_none() {
panic!("attempted to read from stolen value: {}", std::any::type_name::<T>());
}
ReadGuard::map(borrow, |opt| opt.as_ref().unwrap())
None,
compiler.output_dir(),
compiler.output_file(),
+ compiler.temps_dir(),
);
if should_stop == Compilation::Stop {
Some(compiler.input()),
compiler.output_dir(),
compiler.output_file(),
+ compiler.temps_dir(),
)
.and_then(|| {
RustcDefaultCalls::list_metadata(
input: Option<&Input>,
odir: &Option<PathBuf>,
ofile: &Option<PathBuf>,
+ temps_dir: &Option<PathBuf>,
) -> Compilation {
use rustc_session::config::PrintRequest::*;
// PrintRequest::NativeStaticLibs is special - printed during linking
});
let attrs = attrs.as_ref().unwrap();
let t_outputs = rustc_interface::util::build_output_filenames(
- input, odir, ofile, attrs, sess,
+ input, odir, ofile, temps_dir, attrs, sess,
);
let id = rustc_session::output::find_crate_name(sess, attrs, input);
if *req == PrintRequest::CrateName {
E0783: include_str!("./error_codes/E0783.md"),
E0784: include_str!("./error_codes/E0784.md"),
E0785: include_str!("./error_codes/E0785.md"),
+E0786: include_str!("./error_codes/E0786.md"),
;
// E0006, // merged with E0005
// E0008, // cannot bind by-move into a pattern guard
Erroneous code example:
```compile_fail,E0206
-type Foo = [u8; 256];
-impl Copy for Foo { } // error!
-
#[derive(Copy, Clone)]
struct Bar;
impl Copy for &'static mut Bar { } // error!
```
-You can only implement `Copy` for a struct or an enum. Both of the previous
-examples will fail, because neither `[u8; 256]` nor `&'static mut Bar`
-(mutable reference to `Bar`) is a struct or enum.
+You can only implement `Copy` for a struct or an enum.
+The previous example will fail because `&'static mut Bar`
+is not a struct or enum.
--- /dev/null
+A metadata file was invalid.
+
+Erroneous code example:
+
+```ignore (needs extern files)
+use ::foo; // error: found invalid metadata files for crate `foo`
+```
+
+When loading crates, each crate must have a valid metadata file.
+Invalid files could be caused by filesystem corruption,
+an IO error while reading the file, or (rarely) a bug in the compiler itself.
+
+Consider deleting the file and recreating it,
+or reporting a bug against the compiler.
/// Maps `Diagnostic::Level` to `snippet::AnnotationType`
fn annotation_type_for_level(level: Level) -> AnnotationType {
match level {
- Level::Bug | Level::Fatal | Level::Error => AnnotationType::Error,
+ Level::Bug | Level::Fatal | Level::Error { .. } => AnnotationType::Error,
Level::Warning => AnnotationType::Warning,
Level::Note => AnnotationType::Note,
Level::Help => AnnotationType::Help,
pub fn is_error(&self) -> bool {
match self.level {
- Level::Bug | Level::Fatal | Level::Error | Level::FailureNote => true,
+ Level::Bug | Level::Fatal | Level::Error { .. } | Level::FailureNote => true,
Level::Warning | Level::Note | Level::Help | Level::Cancelled | Level::Allow => false,
}
/// as well as inconsistent state observation.
struct HandlerInner {
flags: HandlerFlags,
+ /// The number of lint errors that have been emitted.
+ lint_err_count: usize,
/// The number of errors that have been emitted, including duplicates.
///
/// This is not necessarily the count that's reported to the user once
flags,
inner: Lock::new(HandlerInner {
flags,
+ lint_err_count: 0,
err_count: 0,
warn_count: 0,
deduplicated_err_count: 0,
/// Construct a builder at the `Error` level with the `msg`.
// FIXME: This method should be removed (every error should have an associated error code).
pub fn struct_err(&self, msg: &str) -> DiagnosticBuilder<'_> {
- DiagnosticBuilder::new(self, Level::Error, msg)
+ DiagnosticBuilder::new(self, Level::Error { lint: false }, msg)
+ }
+
+ /// This should only be used by `rustc_middle::lint::struct_lint_level`. Do not use it for hard errors.
+ #[doc(hidden)]
+ pub fn struct_err_lint(&self, msg: &str) -> DiagnosticBuilder<'_> {
+ DiagnosticBuilder::new(self, Level::Error { lint: true }, msg)
}
/// Construct a builder at the `Error` level with the `msg` and the `code`.
}
pub fn span_err(&self, span: impl Into<MultiSpan>, msg: &str) {
- self.emit_diag_at_span(Diagnostic::new(Error, msg), span);
+ self.emit_diag_at_span(Diagnostic::new(Error { lint: false }, msg), span);
}
pub fn span_err_with_code(&self, span: impl Into<MultiSpan>, msg: &str, code: DiagnosticId) {
- self.emit_diag_at_span(Diagnostic::new_with_code(Error, Some(code), msg), span);
+ self.emit_diag_at_span(
+ Diagnostic::new_with_code(Error { lint: false }, Some(code), msg),
+ span,
+ );
}
pub fn span_warn(&self, span: impl Into<MultiSpan>, msg: &str) {
pub fn has_errors(&self) -> bool {
self.inner.borrow().has_errors()
}
+ pub fn has_errors_or_lint_errors(&self) -> bool {
+ self.inner.borrow().has_errors_or_lint_errors()
+ }
pub fn has_errors_or_delayed_span_bugs(&self) -> bool {
self.inner.borrow().has_errors_or_delayed_span_bugs()
}
}
}
if diagnostic.is_error() {
- self.bump_err_count();
+ if matches!(diagnostic.level, Level::Error { lint: true }) {
+ self.bump_lint_err_count();
+ } else {
+ self.bump_err_count();
+ }
} else {
self.bump_warn_count();
}
fn has_errors(&self) -> bool {
self.err_count() > 0
}
+ fn has_errors_or_lint_errors(&self) -> bool {
+ self.has_errors() || self.lint_err_count > 0
+ }
fn has_errors_or_delayed_span_bugs(&self) -> bool {
self.has_errors() || !self.delayed_span_bugs.is_empty()
}
fn has_any_message(&self) -> bool {
- self.err_count() > 0 || self.warn_count > 0
+ self.err_count() > 0 || self.lint_err_count > 0 || self.warn_count > 0
}
fn abort_if_errors(&mut self) {
}
fn err(&mut self, msg: &str) {
- self.emit_error(Error, msg);
+ self.emit_error(Error { lint: false }, msg);
}
/// Emit an error; level should be `Error` or `Fatal`.
}
}
+ fn bump_lint_err_count(&mut self) {
+ self.lint_err_count += 1;
+ self.panic_if_treat_err_as_bug();
+ }
+
fn bump_err_count(&mut self) {
self.err_count += 1;
self.panic_if_treat_err_as_bug();
pub enum Level {
Bug,
Fatal,
- Error,
+ Error {
+ /// If this error comes from a lint, don't abort compilation even when abort_if_errors() is called.
+ lint: bool,
+ },
Warning,
Note,
Help,
fn color(self) -> ColorSpec {
let mut spec = ColorSpec::new();
match self {
- Bug | Fatal | Error => {
+ Bug | Fatal | Error { .. } => {
spec.set_fg(Some(Color::Red)).set_intense(true);
}
Warning => {
pub fn to_str(self) -> &'static str {
match self {
Bug => "error: internal compiler error",
- Fatal | Error => "error",
+ Fatal | Error { .. } => "error",
Warning => "warning",
Note => "note",
Help => "help",
span: Span,
input: TokenStream,
) -> Result<TokenStream, ErrorReported> {
+ let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
let server = proc_macro_server::Rustc::new(ecx);
- self.client.run(&EXEC_STRATEGY, server, input, ecx.ecfg.proc_macro_backtrace).map_err(|e| {
+ self.client.run(&EXEC_STRATEGY, server, input, proc_macro_backtrace).map_err(|e| {
let mut err = ecx.struct_span_err(span, "proc macro panicked");
if let Some(s) = e.as_str() {
err.help(&format!("message: {}", s));
annotation: TokenStream,
annotated: TokenStream,
) -> Result<TokenStream, ErrorReported> {
+ let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
let server = proc_macro_server::Rustc::new(ecx);
self.client
- .run(&EXEC_STRATEGY, server, annotation, annotated, ecx.ecfg.proc_macro_backtrace)
+ .run(&EXEC_STRATEGY, server, annotation, annotated, proc_macro_backtrace)
.map_err(|e| {
let mut err = ecx.struct_span_err(span, "custom attribute panicked");
if let Some(s) = e.as_str() {
nt_to_tokenstream(&item, &ecx.sess.parse_sess, CanSynthesizeMissingTokens::No)
};
+ let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
let server = proc_macro_server::Rustc::new(ecx);
- let stream =
- match self.client.run(&EXEC_STRATEGY, server, input, ecx.ecfg.proc_macro_backtrace) {
- Ok(stream) => stream,
- Err(e) => {
- let mut err = ecx.struct_span_err(span, "proc-macro derive panicked");
- if let Some(s) = e.as_str() {
- err.help(&format!("message: {}", s));
- }
- err.emit();
- return ExpandResult::Ready(vec![]);
+ let stream = match self.client.run(&EXEC_STRATEGY, server, input, proc_macro_backtrace) {
+ Ok(stream) => stream,
+ Err(e) => {
+ let mut err = ecx.struct_span_err(span, "proc-macro derive panicked");
+ if let Some(s) = e.as_str() {
+ err.help(&format!("message: {}", s));
}
- };
+ err.emit();
+ return ExpandResult::Ready(vec![]);
+ }
+ };
let error_count_before = ecx.sess.parse_sess.span_diagnostic.err_count();
let mut parser =
-use crate::base::{ExtCtxt, ResolverExpand};
+use crate::base::ExtCtxt;
use rustc_ast as ast;
use rustc_ast::token::{self, Nonterminal, NtIdent};
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::Lrc;
-use rustc_errors::Diagnostic;
+use rustc_errors::{Diagnostic, PResult};
use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT;
use rustc_lint_defs::BuiltinLintDiagnostics;
use rustc_parse::lexer::nfc_normalize;
}
}
-impl FromInternal<(TreeAndSpacing, &'_ mut Vec<Self>, &mut Rustc<'_>)>
+impl FromInternal<(TreeAndSpacing, &'_ mut Vec<Self>, &mut Rustc<'_, '_>)>
for TokenTree<Group, Punct, Ident, Literal>
{
fn from_internal(
- ((tree, spacing), stack, rustc): (TreeAndSpacing, &mut Vec<Self>, &mut Rustc<'_>),
+ ((tree, spacing), stack, rustc): (TreeAndSpacing, &mut Vec<Self>, &mut Rustc<'_, '_>),
) -> Self {
use rustc_ast::token::*;
SingleQuote => op!('\''),
Ident(name, false) if name == kw::DollarCrate => tt!(Ident::dollar_crate()),
- Ident(name, is_raw) => tt!(Ident::new(rustc.sess, name, is_raw)),
+ Ident(name, is_raw) => tt!(Ident::new(rustc.sess(), name, is_raw)),
Lifetime(name) => {
let ident = symbol::Ident::new(name, span).without_first_quote();
- stack.push(tt!(Ident::new(rustc.sess, ident.name, false)));
+ stack.push(tt!(Ident::new(rustc.sess(), ident.name, false)));
tt!(Punct::new('\'', true))
}
Literal(lit) => tt!(Literal { lit }),
Interpolated(nt)
if let Some((name, is_raw)) = ident_name_compatibility_hack(&nt, span, rustc) =>
{
- TokenTree::Ident(Ident::new(rustc.sess, name.name, is_raw, name.span))
+ TokenTree::Ident(Ident::new(rustc.sess(), name.name, is_raw, name.span))
}
Interpolated(nt) => {
- let stream = nt_to_tokenstream(&nt, rustc.sess, CanSynthesizeMissingTokens::No);
+ let stream = nt_to_tokenstream(&nt, rustc.sess(), CanSynthesizeMissingTokens::No);
TokenTree::Group(Group {
delimiter: Delimiter::None,
stream,
span: DelimSpan::from_single(span),
- flatten: crate::base::pretty_printing_compatibility_hack(&nt, rustc.sess),
+ flatten: crate::base::pretty_printing_compatibility_hack(&nt, rustc.sess()),
})
}
impl ToInternal<rustc_errors::Level> for Level {
fn to_internal(self) -> rustc_errors::Level {
match self {
- Level::Error => rustc_errors::Level::Error,
+ Level::Error => rustc_errors::Level::Error { lint: false },
Level::Warning => rustc_errors::Level::Warning,
Level::Note => rustc_errors::Level::Note,
Level::Help => rustc_errors::Level::Help,
span: Span,
}
-pub(crate) struct Rustc<'a> {
- resolver: &'a dyn ResolverExpand,
- sess: &'a ParseSess,
+pub(crate) struct Rustc<'a, 'b> {
+ ecx: &'a mut ExtCtxt<'b>,
def_site: Span,
call_site: Span,
mixed_site: Span,
- span_debug: bool,
krate: CrateNum,
rebased_spans: FxHashMap<usize, Span>,
}
-impl<'a> Rustc<'a> {
- pub fn new(cx: &'a ExtCtxt<'_>) -> Self {
- let expn_data = cx.current_expansion.id.expn_data();
+impl<'a, 'b> Rustc<'a, 'b> {
+ pub fn new(ecx: &'a mut ExtCtxt<'b>) -> Self {
+ let expn_data = ecx.current_expansion.id.expn_data();
Rustc {
- resolver: cx.resolver,
- sess: cx.parse_sess(),
- def_site: cx.with_def_site_ctxt(expn_data.def_site),
- call_site: cx.with_call_site_ctxt(expn_data.call_site),
- mixed_site: cx.with_mixed_site_ctxt(expn_data.call_site),
- span_debug: cx.ecfg.span_debug,
+ def_site: ecx.with_def_site_ctxt(expn_data.def_site),
+ call_site: ecx.with_call_site_ctxt(expn_data.call_site),
+ mixed_site: ecx.with_mixed_site_ctxt(expn_data.call_site),
krate: expn_data.macro_def_id.unwrap().krate,
rebased_spans: FxHashMap::default(),
+ ecx,
}
}
+ fn sess(&self) -> &ParseSess {
+ self.ecx.parse_sess()
+ }
+
fn lit(&mut self, kind: token::LitKind, symbol: Symbol, suffix: Option<Symbol>) -> Literal {
Literal { lit: token::Lit::new(kind, symbol, suffix), span: server::Span::call_site(self) }
}
}
-impl server::Types for Rustc<'_> {
+impl server::Types for Rustc<'_, '_> {
type FreeFunctions = FreeFunctions;
type TokenStream = TokenStream;
type TokenStreamBuilder = tokenstream::TokenStreamBuilder;
type Span = Span;
}
-impl server::FreeFunctions for Rustc<'_> {
+impl server::FreeFunctions for Rustc<'_, '_> {
fn track_env_var(&mut self, var: &str, value: Option<&str>) {
- self.sess.env_depinfo.borrow_mut().insert((Symbol::intern(var), value.map(Symbol::intern)));
+ self.sess()
+ .env_depinfo
+ .borrow_mut()
+ .insert((Symbol::intern(var), value.map(Symbol::intern)));
}
fn track_path(&mut self, path: &str) {
- self.sess.file_depinfo.borrow_mut().insert(Symbol::intern(path));
+ self.sess().file_depinfo.borrow_mut().insert(Symbol::intern(path));
}
}
-impl server::TokenStream for Rustc<'_> {
+impl server::TokenStream for Rustc<'_, '_> {
fn new(&mut self) -> Self::TokenStream {
TokenStream::default()
}
parse_stream_from_source_str(
FileName::proc_macro_source_code(src),
src.to_string(),
- self.sess,
+ self.sess(),
Some(self.call_site),
)
}
fn to_string(&mut self, stream: &Self::TokenStream) -> String {
pprust::tts_to_string(stream)
}
+ fn expand_expr(&mut self, stream: &Self::TokenStream) -> Result<Self::TokenStream, ()> {
+ // Parse the expression from our tokenstream.
+ let expr: PResult<'_, _> = try {
+ let mut p = rustc_parse::stream_to_parser(
+ self.sess(),
+ stream.clone(),
+ Some("proc_macro expand expr"),
+ );
+ let expr = p.parse_expr()?;
+ if p.token != token::Eof {
+ p.unexpected()?;
+ }
+ expr
+ };
+ let expr = expr.map_err(|mut err| err.emit())?;
+
+ // Perform eager expansion on the expression.
+ let expr = self
+ .ecx
+ .expander()
+ .fully_expand_fragment(crate::expand::AstFragment::Expr(expr))
+ .make_expr();
+
+ // NOTE: For now, limit `expand_expr` to exclusively expand to literals.
+ // This may be relaxed in the future.
+ // We don't use `nt_to_tokenstream` as the tokenstream currently cannot
+ // be recovered in the general case.
+ match &expr.kind {
+ ast::ExprKind::Lit(l) => {
+ Ok(tokenstream::TokenTree::token(token::Literal(l.token), l.span).into())
+ }
+ ast::ExprKind::Unary(ast::UnOp::Neg, e) => match &e.kind {
+ ast::ExprKind::Lit(l) => match l.token {
+ token::Lit { kind: token::Integer | token::Float, .. } => {
+ Ok(std::array::IntoIter::new([
+ // FIXME: The span of the `-` token is lost when
+ // parsing, so we cannot faithfully recover it here.
+ tokenstream::TokenTree::token(token::BinOp(token::Minus), e.span),
+ tokenstream::TokenTree::token(token::Literal(l.token), l.span),
+ ])
+ .collect())
+ }
+ _ => Err(()),
+ },
+ _ => Err(()),
+ },
+ _ => Err(()),
+ }
+ }
fn from_token_tree(
&mut self,
tree: TokenTree<Self::Group, Self::Punct, Self::Ident, Self::Literal>,
}
}
-impl server::TokenStreamBuilder for Rustc<'_> {
+impl server::TokenStreamBuilder for Rustc<'_, '_> {
fn new(&mut self) -> Self::TokenStreamBuilder {
tokenstream::TokenStreamBuilder::new()
}
}
}
-impl server::TokenStreamIter for Rustc<'_> {
+impl server::TokenStreamIter for Rustc<'_, '_> {
fn next(
&mut self,
iter: &mut Self::TokenStreamIter,
}
}
-impl server::Group for Rustc<'_> {
+impl server::Group for Rustc<'_, '_> {
fn new(&mut self, delimiter: Delimiter, stream: Self::TokenStream) -> Self::Group {
Group {
delimiter,
}
}
-impl server::Punct for Rustc<'_> {
+impl server::Punct for Rustc<'_, '_> {
fn new(&mut self, ch: char, spacing: Spacing) -> Self::Punct {
Punct::new(ch, spacing == Spacing::Joint, server::Span::call_site(self))
}
}
}
-impl server::Ident for Rustc<'_> {
+impl server::Ident for Rustc<'_, '_> {
fn new(&mut self, string: &str, span: Self::Span, is_raw: bool) -> Self::Ident {
- Ident::new(self.sess, Symbol::intern(string), is_raw, span)
+ Ident::new(self.sess(), Symbol::intern(string), is_raw, span)
}
fn span(&mut self, ident: Self::Ident) -> Self::Span {
ident.span
}
}
-impl server::Literal for Rustc<'_> {
+impl server::Literal for Rustc<'_, '_> {
fn from_str(&mut self, s: &str) -> Result<Self::Literal, ()> {
let name = FileName::proc_macro_source_code(s);
- let mut parser = rustc_parse::new_parser_from_source_str(self.sess, name, s.to_owned());
+ let mut parser = rustc_parse::new_parser_from_source_str(self.sess(), name, s.to_owned());
let first_span = parser.token.span.data();
let minus_present = parser.eat(&token::BinOp(token::Minus));
}
}
-impl server::SourceFile for Rustc<'_> {
+impl server::SourceFile for Rustc<'_, '_> {
fn eq(&mut self, file1: &Self::SourceFile, file2: &Self::SourceFile) -> bool {
Lrc::ptr_eq(file1, file2)
}
}
}
-impl server::MultiSpan for Rustc<'_> {
+impl server::MultiSpan for Rustc<'_, '_> {
fn new(&mut self) -> Self::MultiSpan {
vec![]
}
}
}
-impl server::Diagnostic for Rustc<'_> {
+impl server::Diagnostic for Rustc<'_, '_> {
fn new(&mut self, level: Level, msg: &str, spans: Self::MultiSpan) -> Self::Diagnostic {
let mut diag = Diagnostic::new(level.to_internal(), msg);
diag.set_span(MultiSpan::from_spans(spans));
diag.sub(level.to_internal(), msg, MultiSpan::from_spans(spans), None);
}
fn emit(&mut self, diag: Self::Diagnostic) {
- self.sess.span_diagnostic.emit_diagnostic(&diag);
+ self.sess().span_diagnostic.emit_diagnostic(&diag);
}
}
-impl server::Span for Rustc<'_> {
+impl server::Span for Rustc<'_, '_> {
fn debug(&mut self, span: Self::Span) -> String {
- if self.span_debug {
+ if self.ecx.ecfg.span_debug {
format!("{:?}", span)
} else {
format!("{:?} bytes({}..{})", span.ctxt(), span.lo().0, span.hi().0)
self.mixed_site
}
fn source_file(&mut self, span: Self::Span) -> Self::SourceFile {
- self.sess.source_map().lookup_char_pos(span.lo()).file
+ self.sess().source_map().lookup_char_pos(span.lo()).file
}
fn parent(&mut self, span: Self::Span) -> Option<Self::Span> {
span.parent_callsite()
span.source_callsite()
}
fn start(&mut self, span: Self::Span) -> LineColumn {
- let loc = self.sess.source_map().lookup_char_pos(span.lo());
+ let loc = self.sess().source_map().lookup_char_pos(span.lo());
LineColumn { line: loc.line, column: loc.col.to_usize() }
}
fn end(&mut self, span: Self::Span) -> LineColumn {
- let loc = self.sess.source_map().lookup_char_pos(span.hi());
+ let loc = self.sess().source_map().lookup_char_pos(span.hi());
LineColumn { line: loc.line, column: loc.col.to_usize() }
}
fn before(&mut self, span: Self::Span) -> Self::Span {
span.shrink_to_hi()
}
fn join(&mut self, first: Self::Span, second: Self::Span) -> Option<Self::Span> {
- let self_loc = self.sess.source_map().lookup_char_pos(first.lo());
- let other_loc = self.sess.source_map().lookup_char_pos(second.lo());
+ let self_loc = self.sess().source_map().lookup_char_pos(first.lo());
+ let other_loc = self.sess().source_map().lookup_char_pos(second.lo());
if self_loc.file.name != other_loc.file.name {
return None;
span.with_ctxt(at.ctxt())
}
fn source_text(&mut self, span: Self::Span) -> Option<String> {
- self.sess.source_map().span_to_snippet(span).ok()
+ self.sess().source_map().span_to_snippet(span).ok()
}
/// Saves the provided span into the metadata of
/// *the crate we are currently compiling*, which must
/// since we've loaded `my_proc_macro` from disk in order to execute it).
/// In this way, we have obtained a span pointing into `my_proc_macro`
fn save_span(&mut self, span: Self::Span) -> usize {
- self.sess.save_proc_macro_span(span)
+ self.sess().save_proc_macro_span(span)
}
fn recover_proc_macro_span(&mut self, id: usize) -> Self::Span {
- let (resolver, krate, def_site) = (self.resolver, self.krate, self.def_site);
+ let (resolver, krate, def_site) = (&*self.ecx.resolver, self.krate, self.def_site);
*self.rebased_spans.entry(id).or_insert_with(|| {
// FIXME: `SyntaxContext` for spans from proc macro crates is lost during encoding,
// replace it with a def-site context until we are encoding it properly.
fn ident_name_compatibility_hack(
nt: &Nonterminal,
orig_span: Span,
- rustc: &mut Rustc<'_>,
+ rustc: &mut Rustc<'_, '_>,
) -> Option<(rustc_span::symbol::Ident, bool)> {
if let NtIdent(ident, is_raw) = nt {
if let ExpnKind::Macro(_, macro_name) = orig_span.ctxt().outer_expn_data().kind {
- let source_map = rustc.sess.source_map();
+ let source_map = rustc.sess().source_map();
let filename = source_map.span_to_filename(orig_span);
if let FileName::Real(RealFileName::LocalPath(path)) = filename {
let matches_prefix = |prefix, filename| {
let snippet = source_map.span_to_snippet(orig_span);
if snippet.as_deref() == Ok("$name") {
if time_macros_impl {
- rustc.sess.buffer_lint_with_diagnostic(
+ rustc.sess().buffer_lint_with_diagnostic(
&PROC_MACRO_BACK_COMPAT,
orig_span,
ast::CRATE_NODE_ID,
.and_then(|c| c.parse::<u32>().ok())
.map_or(false, |v| v < 40)
{
- rustc.sess.buffer_lint_with_diagnostic(
+ rustc.sess().buffer_lint_with_diagnostic(
&PROC_MACRO_BACK_COMPAT,
orig_span,
ast::CRATE_NODE_ID,
source_map.span_to_filename(rustc.def_site)
{
if macro_path.to_string_lossy().contains("pin-project-internal-0.") {
- rustc.sess.buffer_lint_with_diagnostic(
+ rustc.sess().buffer_lint_with_diagnostic(
&PROC_MACRO_BACK_COMPAT,
orig_span,
ast::CRATE_NODE_ID,
/// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.
(active, doc_auto_cfg, "1.58.0", Some(43781), None),
+ /// Allows using `const` operands in inline assembly.
+ (active, asm_const, "1.58.0", Some(72016), None),
+
+ /// Allows using `sym` operands in inline assembly.
+ (active, asm_sym, "1.58.0", Some(72016), None),
+
+ /// Enables experimental inline assembly support for additional architectures.
+ (active, asm_experimental_arch, "1.58.0", Some(72016), None),
+
// -------------------------------------------------------------------------
// feature-group-end: actual feature gates
// -------------------------------------------------------------------------
macro_rules! ungated {
($attr:ident, $typ:expr, $tpl:expr $(,)?) => {
- (sym::$attr, $typ, $tpl, Ungated)
+ BuiltinAttribute { name: sym::$attr, type_: $typ, template: $tpl, gate: Ungated }
};
}
macro_rules! gated {
($attr:ident, $typ:expr, $tpl:expr, $gate:ident, $msg:expr $(,)?) => {
- (sym::$attr, $typ, $tpl, Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate)))
+ BuiltinAttribute {
+ name: sym::$attr,
+ type_: $typ,
+ template: $tpl,
+ gate: Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate)),
+ }
};
($attr:ident, $typ:expr, $tpl:expr, $msg:expr $(,)?) => {
- (sym::$attr, $typ, $tpl, Gated(Stability::Unstable, sym::$attr, $msg, cfg_fn!($attr)))
+ BuiltinAttribute {
+ name: sym::$attr,
+ type_: $typ,
+ template: $tpl,
+ gate: Gated(Stability::Unstable, sym::$attr, $msg, cfg_fn!($attr)),
+ }
};
}
)
};
($attr:ident, $typ:expr, $tpl:expr, $msg:expr $(,)?) => {
- (
- sym::$attr,
- $typ,
- $tpl,
- Gated(Stability::Unstable, sym::rustc_attrs, $msg, cfg_fn!(rustc_attrs)),
- )
+ BuiltinAttribute {
+ name: sym::$attr,
+ type_: $typ,
+ template: $tpl,
+ gate: Gated(Stability::Unstable, sym::rustc_attrs, $msg, cfg_fn!(rustc_attrs)),
+ }
};
}
const IMPL_DETAIL: &str = "internal implementation detail";
const INTERNAL_UNSTABLE: &str = "this is an internal attribute that will never be stable";
-pub type BuiltinAttribute = (Symbol, AttributeType, AttributeTemplate, AttributeGate);
+pub struct BuiltinAttribute {
+ pub name: Symbol,
+ pub type_: AttributeType,
+ pub template: AttributeTemplate,
+ pub gate: AttributeGate,
+}
/// Attributes that have a special meaning to rustc or rustdoc.
#[rustfmt::skip]
),
// Plugins:
- (
- sym::plugin, CrateLevel, template!(List: "name"),
- Gated(
+ BuiltinAttribute {
+ name: sym::plugin,
+ type_: CrateLevel,
+ template: template!(List: "name"),
+ gate: Gated(
Stability::Deprecated(
"https://github.com/rust-lang/rust/pull/64675",
Some("may be removed in a future compiler version"),
sym::plugin,
"compiler plugins are deprecated",
cfg_fn!(plugin)
- )
- ),
+ ),
+ },
// Testing:
gated!(allow_fail, Normal, template!(Word), experimental!(allow_fail)),
lang, Normal, template!(NameValueStr: "name"), lang_items,
"language items are subject to change",
),
- (
- sym::rustc_diagnostic_item,
- Normal,
- template!(NameValueStr: "name"),
- Gated(
+ BuiltinAttribute {
+ name: sym::rustc_diagnostic_item,
+ type_: Normal,
+ template: template!(NameValueStr: "name"),
+ gate: Gated(
Stability::Unstable,
sym::rustc_attrs,
"diagnostic items compiler internal support for linting",
cfg_fn!(rustc_attrs),
),
- ),
+ },
gated!(
// Used in resolve:
prelude_import, Normal, template!(Word),
];
pub fn deprecated_attributes() -> Vec<&'static BuiltinAttribute> {
- BUILTIN_ATTRIBUTES.iter().filter(|(.., gate)| gate.is_deprecated()).collect()
+ BUILTIN_ATTRIBUTES.iter().filter(|attr| attr.gate.is_deprecated()).collect()
}
pub fn is_builtin_attr_name(name: Symbol) -> bool {
SyncLazy::new(|| {
let mut map = FxHashMap::default();
for attr in BUILTIN_ATTRIBUTES.iter() {
- if map.insert(attr.0, attr).is_some() {
- panic!("duplicate builtin attribute `{}`", attr.0);
+ if map.insert(attr.name, attr).is_some() {
+ panic!("duplicate builtin attribute `{}`", attr.name);
}
}
map
Use,
/// An `extern` block.
ForeignMod,
- /// Anonymous constant, e.g. the `1 + 2` in `[u8; 1 + 2]`, or `const { 1 + 2}`
+ /// Anonymous constant, e.g. the `1 + 2` in `[u8; 1 + 2]`
AnonConst,
+ /// An inline constant, e.g. `const { 1 + 2 }`
+ InlineConst,
/// Opaque type, aka `impl Trait`.
OpaqueTy,
Field,
DefKind::Use => "import",
DefKind::ForeignMod => "foreign module",
DefKind::AnonConst => "constant expression",
+ DefKind::InlineConst => "inline constant",
DefKind::Field => "field",
DefKind::Impl => "implementation",
DefKind::Closure => "closure",
| DefKind::OpaqueTy
| DefKind::Impl
| DefKind::Use
+ | DefKind::InlineConst
| DefKind::ExternCrate => "an",
DefKind::Macro(macro_kind) => macro_kind.article(),
_ => "a",
// Not namespaced.
DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::Field
| DefKind::LifetimeParam
| DefKind::ExternCrate
pub fn staging_dep_graph_path(sess: &Session) -> PathBuf {
in_incr_comp_dir_sess(sess, STAGING_DEP_GRAPH_FILENAME)
}
-pub fn dep_graph_path_from(incr_comp_session_dir: &Path) -> PathBuf {
- in_incr_comp_dir(incr_comp_session_dir, DEP_GRAPH_FILENAME)
-}
pub fn work_products_path(sess: &Session) -> PathBuf {
in_incr_comp_dir_sess(sess, WORK_PRODUCTS_FILENAME)
// Calling `sess.incr_comp_session_dir()` will panic if `sess.opts.incremental.is_none()`.
// Fortunately, we just checked that this isn't the case.
- let path = dep_graph_path_from(&sess.incr_comp_session_dir());
+ let path = dep_graph_path(&sess);
let report_incremental_info = sess.opts.debugging_opts.incremental_info;
let expected_hash = sess.opts.dep_tracking_hash(false);
let tcx = self.tcx;
// Select everything, returning errors.
- let true_errors = fulfill_cx.select_where_possible(self).err().unwrap_or_else(Vec::new);
+ let true_errors = fulfill_cx.select_where_possible(self);
debug!("true_errors = {:#?}", true_errors);
if !true_errors.is_empty() {
}
// Anything left unselected *now* must be an ambiguity.
- let ambig_errors = fulfill_cx.select_all_or_error(self).err().unwrap_or_else(Vec::new);
+ let ambig_errors = fulfill_cx.select_all_or_error(self);
debug!("ambig_errors = {:#?}", ambig_errors);
let region_obligations = self.take_registered_region_obligations();
let mut returned_async_output_error = false;
for &sp in values {
if sp.is_desugaring(DesugaringKind::Async) && !returned_async_output_error {
- if &[sp] != err.span.primary_spans() {
+ if [sp] != err.span.primary_spans() {
let mut span: MultiSpan = sp.into();
span.push_span_label(
sp,
if let Some(SubregionOrigin::CompareImplMethodObligation {
span,
- item_name,
impl_item_def_id,
trait_item_def_id,
}) = origin
{
return self.report_extra_impl_obligation(
span,
- item_name,
impl_item_def_id,
trait_item_def_id,
&format!("`{}: {}`", bound_kind, sub),
{
if let SubregionOrigin::CompareImplTypeObligation {
span,
- item_name,
impl_item_def_id,
trait_item_def_id,
} = origin
{
- self.emit_associated_type_err(span, item_name, impl_item_def_id, trait_item_def_id);
+ self.emit_associated_type_err(
+ span,
+ self.infcx.tcx.item_name(impl_item_def_id),
+ impl_item_def_id,
+ trait_item_def_id,
+ );
return Some(ErrorReported);
}
}
);
err
}
- infer::CompareImplMethodObligation {
- span,
- item_name,
- impl_item_def_id,
- trait_item_def_id,
- } => self.report_extra_impl_obligation(
- span,
- item_name,
- impl_item_def_id,
- trait_item_def_id,
- &format!("`{}: {}`", sup, sub),
- ),
- infer::CompareImplTypeObligation {
- span,
- item_name,
- impl_item_def_id,
- trait_item_def_id,
- } => self.report_extra_impl_obligation(
- span,
- item_name,
- impl_item_def_id,
- trait_item_def_id,
- &format!("`{}: {}`", sup, sub),
- ),
+ infer::CompareImplMethodObligation { span, impl_item_def_id, trait_item_def_id } => {
+ self.report_extra_impl_obligation(
+ span,
+ impl_item_def_id,
+ trait_item_def_id,
+ &format!("`{}: {}`", sup, sub),
+ )
+ }
+ infer::CompareImplTypeObligation { span, impl_item_def_id, trait_item_def_id } => self
+ .report_extra_impl_obligation(
+ span,
+ impl_item_def_id,
+ trait_item_def_id,
+ &format!("`{}: {}`", sup, sub),
+ ),
}
}
/// Comparing the signature and requirements of an impl method against
/// the containing trait.
- CompareImplMethodObligation {
- span: Span,
- item_name: Symbol,
- impl_item_def_id: DefId,
- trait_item_def_id: DefId,
- },
+ CompareImplMethodObligation { span: Span, impl_item_def_id: DefId, trait_item_def_id: DefId },
/// Comparing the signature and requirements of an impl associated type
/// against the containing trait
- CompareImplTypeObligation {
- span: Span,
- item_name: Symbol,
- impl_item_def_id: DefId,
- trait_item_def_id: DefId,
- },
+ CompareImplTypeObligation { span: Span, impl_item_def_id: DefId, trait_item_def_id: DefId },
}
// `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger.
}
traits::ObligationCauseCode::CompareImplMethodObligation {
- item_name,
impl_item_def_id,
trait_item_def_id,
} => SubregionOrigin::CompareImplMethodObligation {
span: cause.span,
- item_name,
impl_item_def_id,
trait_item_def_id,
},
traits::ObligationCauseCode::CompareImplTypeObligation {
- item_name,
impl_item_def_id,
trait_item_def_id,
} => SubregionOrigin::CompareImplTypeObligation {
span: cause.span,
- item_name,
impl_item_def_id,
trait_item_def_id,
},
/// function. We can then add implied bounds and the like from the
/// closure arguments into the environment -- these should only
/// apply in the closure body, so once we exit, we invoke
- /// `pop_snapshot_post_closure` to remove them.
+ /// `pop_snapshot_post_typeck_child` to remove them.
///
/// Example:
///
/// seems like it'd be readily fixed if we wanted. There are
/// similar leaks around givens that seem equally suspicious, to
/// be honest. --nmatsakis
- pub fn push_snapshot_pre_closure(&self) -> usize {
+ pub fn push_snapshot_pre_typeck_child(&self) -> usize {
self.region_bound_pairs_accum.len()
}
- /// See `push_snapshot_pre_closure`.
- pub fn pop_snapshot_post_closure(&mut self, len: usize) {
+ /// See `push_snapshot_pre_typeck_child`.
+ pub fn pop_snapshot_post_typeck_child(&mut self, len: usize) {
self.region_bound_pairs_accum.truncate(len);
}
obligation: PredicateObligation<'tcx>,
);
- fn select_all_or_error(
- &mut self,
- infcx: &InferCtxt<'_, 'tcx>,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>>;
+ fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>>;
fn select_all_with_constness_or_error(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
_constness: hir::Constness,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+ ) -> Vec<FulfillmentError<'tcx>> {
self.select_all_or_error(infcx)
}
- fn select_where_possible(
- &mut self,
- infcx: &InferCtxt<'_, 'tcx>,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>>;
+ fn select_where_possible(&mut self, infcx: &InferCtxt<'_, 'tcx>)
+ -> Vec<FulfillmentError<'tcx>>;
// FIXME(fee1-dead) this should not provide a default body for chalk as chalk should be updated
fn select_with_constness_where_possible(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
_constness: hir::Constness,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+ ) -> Vec<FulfillmentError<'tcx>> {
self.select_where_possible(infcx)
}
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::TyCtxt;
-use rustc_span::symbol::Symbol;
use rustc_span::{MultiSpan, Span};
use std::fmt;
use std::iter;
pub fn report_extra_impl_obligation(
&self,
error_span: Span,
- item_name: Symbol,
- _impl_item_def_id: DefId,
+ impl_item_def_id: DefId,
trait_item_def_id: DefId,
requirement: &dyn fmt::Display,
) -> DiagnosticBuilder<'tcx> {
if let Some(trait_item_span) = self.tcx.hir().span_if_local(trait_item_def_id) {
let span = self.tcx.sess.source_map().guess_head_span(trait_item_span);
+ let item_name = self.tcx.item_name(impl_item_def_id);
err.span_label(span, format!("definition of `{}` from trait", item_name));
}
pub(crate) input_path: Option<PathBuf>,
pub(crate) output_dir: Option<PathBuf>,
pub(crate) output_file: Option<PathBuf>,
+ pub(crate) temps_dir: Option<PathBuf>,
pub(crate) register_lints: Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>,
pub(crate) override_queries:
Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::ExternProviders)>,
pub fn output_file(&self) -> &Option<PathBuf> {
&self.output_file
}
+ pub fn temps_dir(&self) -> &Option<PathBuf> {
+ &self.temps_dir
+ }
pub fn register_lints(&self) -> &Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>> {
&self.register_lints
}
sess: &Session,
attrs: &[ast::Attribute],
) -> OutputFilenames {
- util::build_output_filenames(&self.input, &self.output_dir, &self.output_file, attrs, sess)
+ util::build_output_filenames(
+ &self.input,
+ &self.output_dir,
+ &self.output_file,
+ &self.temps_dir,
+ attrs,
+ sess,
+ )
}
}
);
}
+ let temps_dir = sess.opts.debugging_opts.temps_dir.as_ref().map(|o| PathBuf::from(&o));
+
let compiler = Compiler {
sess,
codegen_backend,
input_path: config.input_path,
output_dir: config.output_dir,
output_file: config.output_file,
+ temps_dir,
register_lints: config.register_lints,
override_queries: config.override_queries,
};
use std::io::{self, BufWriter, Write};
use std::lazy::SyncLazy;
use std::marker::PhantomPinned;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
use std::pin::Pin;
use std::rc::Rc;
use std::{env, fs, iter};
None
}
-fn output_contains_path(output_paths: &[PathBuf], input_path: &PathBuf) -> bool {
+fn output_contains_path(output_paths: &[PathBuf], input_path: &Path) -> bool {
let input_path = input_path.canonicalize().ok();
if input_path.is_none() {
return false;
check_output(output_paths, check)
}
-fn escape_dep_filename(filename: &String) -> String {
+fn escape_dep_filename(filename: &str) -> String {
// Apparently clang and gcc *only* escape spaces:
// https://llvm.org/klaus/clang/commit/9d50634cfc268ecc9a7250226dd5ca0e945240d4
filename.replace(" ", "\\ ")
&compiler.input,
&compiler.output_dir,
&compiler.output_file,
+ &compiler.temps_dir,
&krate.attrs,
sess,
);
}
}
+ if let Some(ref dir) = compiler.temps_dir {
+ if fs::create_dir_all(dir).is_err() {
+ sess.err("failed to find or create the directory specified by `--temps-dir`");
+ return Err(ErrorReported);
+ }
+ }
+
write_out_deps(sess, boxed_resolver, &outputs, &output_paths);
let only_dep_info = sess.opts.output_types.contains_key(&OutputType::DepInfo)
untracked!(span_debug, true);
untracked!(span_free_formats, true);
untracked!(strip, Strip::Debuginfo);
+ untracked!(temps_dir, Some(String::from("abc")));
untracked!(terminal_width, Some(80));
untracked!(threads, 99);
untracked!(time, true);
input: &Input,
odir: &Option<PathBuf>,
ofile: &Option<PathBuf>,
+ temps_dir: &Option<PathBuf>,
attrs: &[ast::Attribute],
sess: &Session,
) -> OutputFilenames {
dirpath,
stem,
None,
+ temps_dir.clone(),
sess.opts.cg.extra_filename.clone(),
sess.opts.output_types.clone(),
)
out_file.parent().unwrap_or_else(|| Path::new("")).to_path_buf(),
out_file.file_stem().unwrap_or_default().to_str().unwrap().to_string(),
ofile,
+ temps_dir.clone(),
sess.opts.cg.extra_filename.clone(),
sess.opts.output_types.clone(),
)
fn visit_item_kind(&mut self, i: &mut ast::ItemKind) {
let is_const = match i {
ast::ItemKind::Static(..) | ast::ItemKind::Const(..) => true,
- ast::ItemKind::Fn(box ast::FnKind(_, ref sig, _, _)) => Self::is_sig_const(sig),
+ ast::ItemKind::Fn(box ast::Fn { ref sig, .. }) => Self::is_sig_const(sig),
_ => false,
};
self.run(is_const, |s| noop_visit_item_kind(i, s))
fn flat_map_trait_item(&mut self, i: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
let is_const = match i.kind {
ast::AssocItemKind::Const(..) => true,
- ast::AssocItemKind::Fn(box ast::FnKind(_, ref sig, _, _)) => Self::is_sig_const(sig),
+ ast::AssocItemKind::Fn(box ast::Fn { ref sig, .. }) => Self::is_sig_const(sig),
_ => false,
};
self.run(is_const, |s| noop_flat_map_assoc_item(i, s))
impl EscapeError {
/// Returns true for actual errors, as opposed to warnings.
pub fn is_fatal(&self) -> bool {
- match self {
- EscapeError::UnskippedWhitespaceWarning => false,
- EscapeError::MultipleSkippedLinesWarning => false,
- _ => true,
- }
+ !matches!(
+ self,
+ EscapeError::UnskippedWhitespaceWarning | EscapeError::MultipleSkippedLinesWarning
+ )
}
}
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString};
-use rustc_feature::{deprecated_attributes, AttributeGate, AttributeTemplate, AttributeType};
-use rustc_feature::{GateIssue, Stability};
+use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID};
fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
match it.kind {
- ast::ItemKind::Trait(box ast::TraitKind(_, ast::Unsafe::Yes(_), ..)) => self
+ ast::ItemKind::Trait(box ast::Trait { unsafety: ast::Unsafe::Yes(_), .. }) => self
.report_unsafe(cx, it.span, |lint| {
lint.build("declaration of an `unsafe` trait").emit()
}),
- ast::ItemKind::Impl(box ast::ImplKind { unsafety: ast::Unsafe::Yes(_), .. }) => self
+ ast::ItemKind::Impl(box ast::Impl { unsafety: ast::Unsafe::Yes(_), .. }) => self
.report_unsafe(cx, it.span, |lint| {
lint.build("implementation of an `unsafe` trait").emit()
}),
// This is a hard error in future editions; avoid linting and erroring
return;
}
- if let ast::AssocItemKind::Fn(box FnKind(_, ref sig, _, _)) = it.kind {
+ if let ast::AssocItemKind::Fn(box Fn { ref sig, .. }) = it.kind {
for arg in sig.decl.inputs.iter() {
if let ast::PatKind::Ident(_, ident, None) = arg.pat.kind {
if ident.name == kw::Empty {
pub struct DeprecatedAttr {
// This is not free to compute, so we want to keep it around, rather than
// compute it for every attribute.
- depr_attrs: Vec<&'static (Symbol, AttributeType, AttributeTemplate, AttributeGate)>,
+ depr_attrs: Vec<&'static BuiltinAttribute>,
}
impl_lint_pass!(DeprecatedAttr => []);
impl EarlyLintPass for DeprecatedAttr {
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
- for &&(n, _, _, ref g) in &self.depr_attrs {
- if attr.ident().map(|ident| ident.name) == Some(n) {
+ for BuiltinAttribute { name, gate, .. } in &self.depr_attrs {
+ if attr.ident().map(|ident| ident.name) == Some(*name) {
if let &AttributeGate::Gated(
Stability::Deprecated(link, suggestion),
name,
reason,
_,
- ) = g
+ ) = gate
{
let msg =
format!("use of deprecated attribute `{}`: {}. See {}", name, reason, link);
false
}
- if let rustc_hir::ExprKind::Unary(ref un_op, ref expr_deref) = expr.kind {
- if let rustc_hir::UnOp::Deref = un_op {
- if is_null_ptr(cx, expr_deref) {
- cx.struct_span_lint(DEREF_NULLPTR, expr.span, |lint| {
- let mut err = lint.build("dereferencing a null pointer");
- err.span_label(
- expr.span,
- "this code causes undefined behavior when executed",
- );
- err.emit();
- });
- }
+ if let rustc_hir::ExprKind::Unary(rustc_hir::UnOp::Deref, expr_deref) = expr.kind {
+ if is_null_ptr(cx, expr_deref) {
+ cx.struct_span_lint(DEREF_NULLPTR, expr.span, |lint| {
+ let mut err = lint.build("dereferencing a null pointer");
+ err.span_label(expr.span, "this code causes undefined behavior when executed");
+ err.emit();
+ });
}
}
}
let snippet = template_snippet.as_str();
if let Some(pos) = snippet.find(needle) {
let end = pos
- + &snippet[pos..]
+ + snippet[pos..]
.find(|c| c == ':')
.unwrap_or(snippet[pos..].len() - 1);
let inner = InnerSpan::new(pos, end);
fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx Ty<'tcx>) {
match &ty.kind {
- TyKind::Path(qpath) => {
- if let QPath::Resolved(_, path) = qpath {
- if let Some(last) = path.segments.iter().last() {
- if lint_ty_kind_usage(cx, last) {
- cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, |lint| {
- lint.build("usage of `ty::TyKind`")
- .help("try using `Ty` instead")
- .emit();
- })
- } else {
- if ty.span.from_expansion() {
- return;
- }
- if let Some(t) = is_ty_or_ty_ctxt(cx, ty) {
- if path.segments.len() > 1 {
- cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, |lint| {
- lint.build(&format!("usage of qualified `ty::{}`", t))
- .span_suggestion(
- path.span,
- "try using it unqualified",
- t,
- // The import probably needs to be changed
- Applicability::MaybeIncorrect,
- )
- .emit();
- })
- }
+ TyKind::Path(QPath::Resolved(_, path)) => {
+ if let Some(last) = path.segments.iter().last() {
+ if lint_ty_kind_usage(cx, last) {
+ cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, |lint| {
+ lint.build("usage of `ty::TyKind`")
+ .help("try using `Ty` instead")
+ .emit();
+ })
+ } else {
+ if ty.span.from_expansion() {
+ return;
+ }
+ if let Some(t) = is_ty_or_ty_ctxt(cx, ty) {
+ if path.segments.len() > 1 {
+ cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, |lint| {
+ lint.build(&format!("usage of qualified `ty::{}`", t))
+ .span_suggestion(
+ path.span,
+ "try using it unqualified",
+ t,
+ // The import probably needs to be changed
+ Applicability::MaybeIncorrect,
+ )
+ .emit();
+ })
}
}
}
}
fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, ty: &Ty<'_>) -> Option<String> {
- if let TyKind::Path(qpath) = &ty.kind {
- if let QPath::Resolved(_, path) = qpath {
- match path.res {
- Res::Def(_, def_id) => {
- if let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(def_id)
- {
- return Some(format!(
- "{}{}",
- name,
- gen_args(path.segments.last().unwrap())
- ));
- }
+ if let TyKind::Path(QPath::Resolved(_, path)) = &ty.kind {
+ match path.res {
+ Res::Def(_, def_id) => {
+ if let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(def_id) {
+ return Some(format!("{}{}", name, gen_args(path.segments.last().unwrap())));
}
- // Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait.
- Res::SelfTy(None, Some((did, _))) => {
- if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() {
- if let Some(name @ (sym::Ty | sym::TyCtxt)) =
- cx.tcx.get_diagnostic_name(adt.did)
- {
- // NOTE: This path is currently unreachable as `Ty<'tcx>` is
- // defined as a type alias meaning that `impl<'tcx> Ty<'tcx>`
- // is not actually allowed.
- //
- // I(@lcnr) still kept this branch in so we don't miss this
- // if we ever change it in the future.
- return Some(format!("{}<{}>", name, substs[0]));
- }
+ }
+ // Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait.
+ Res::SelfTy(None, Some((did, _))) => {
+ if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() {
+ if let Some(name @ (sym::Ty | sym::TyCtxt)) =
+ cx.tcx.get_diagnostic_name(adt.did)
+ {
+ // NOTE: This path is currently unreachable as `Ty<'tcx>` is
+ // defined as a type alias meaning that `impl<'tcx> Ty<'tcx>`
+ // is not actually allowed.
+ //
+ // I(@lcnr) still kept this branch in so we don't miss this
+ // if we ever change it in the future.
+ return Some(format!("{}<{}>", name, substs[0]));
}
}
- _ => (),
}
+ _ => (),
}
}
impl EarlyLintPass for LintPassImpl {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
- if let ast::ItemKind::Impl(box ast::ImplKind { of_trait: Some(lint_pass), .. }) = &item.kind
- {
+ if let ast::ItemKind::Impl(box ast::Impl { of_trait: Some(lint_pass), .. }) = &item.kind {
if let Some(last) = lint_pass.path.segments.last() {
if last.ident.name == sym::LintPass {
let expn_data = lint_pass.path.span.ctxt().outer_expn_data();
OptimizerLastEPCallbacks.push_back(
[SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) {
MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>());
- MPM.addPass(ModuleAddressSanitizerPass(
- /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover));
#if LLVM_VERSION_GE(14, 0)
- AddressSanitizerOptions opts(/*CompileKernel=*/false,
- SanitizerOptions->SanitizeAddressRecover,
- /*UseAfterScope=*/true,
- AsanDetectStackUseAfterReturnMode::Runtime);
- MPM.addPass(createModuleToFunctionPassAdaptor(AddressSanitizerPass(opts)));
+ AddressSanitizerOptions opts = AddressSanitizerOptions{
+ /*CompileKernel=*/false,
+ SanitizerOptions->SanitizeAddressRecover,
+ /*UseAfterScope=*/true,
+ AsanDetectStackUseAfterReturnMode::Runtime,
+ };
+ MPM.addPass(ModuleAddressSanitizerPass(opts));
#else
+ MPM.addPass(ModuleAddressSanitizerPass(
+ /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover));
MPM.addPass(createModuleToFunctionPassAdaptor(AddressSanitizerPass(
/*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover,
/*UseAfterScope=*/true)));
}
if meta.path().is_ident("project") {
if let Meta::List(list) = meta {
- if let Some(nested) = list.nested.iter().next() {
- if let NestedMeta::Meta(meta) = nested {
- attrs.project = meta.path().get_ident().cloned();
- any_attr = true;
- }
+ if let Some(NestedMeta::Meta(meta)) = list.nested.iter().next() {
+ attrs.project = meta.path().get_ident().cloned();
+ any_attr = true;
}
}
}
use proc_macro::bridge::client::ProcMacro;
use std::collections::BTreeMap;
+use std::ops::Fn;
use std::path::Path;
use std::{cmp, env};
use tracing::{debug, info};
self.crate_rejections.via_kind.clear();
self.crate_rejections.via_version.clear();
self.crate_rejections.via_filename.clear();
+ self.crate_rejections.via_invalid.clear();
}
crate fn maybe_load_library_crate(&mut self) -> Result<Option<Library>, CrateError> {
continue;
}
}
- Err(err) => {
+ Err(MetadataError::LoadFailure(err)) => {
+ info!("no metadata found: {}", err);
+ // The file was present and created by the same compiler version, but we
+ // couldn't load it for some reason. Give a hard error instead of silently
+ // ignoring it, but only if we would have given an error anyway.
+ self.crate_rejections
+ .via_invalid
+ .push(CrateMismatch { path: lib, got: err });
+ continue;
+ }
+ Err(err @ MetadataError::NotPresent(_)) => {
info!("no metadata found: {}", err);
continue;
}
fn get_metadata_section(
target: &Target,
flavor: CrateFlavor,
- filename: &Path,
+ filename: &'p Path,
loader: &dyn MetadataLoader,
-) -> Result<MetadataBlob, String> {
+) -> Result<MetadataBlob, MetadataError<'p>> {
if !filename.exists() {
- return Err(format!("no such file: '{}'", filename.display()));
+ return Err(MetadataError::NotPresent(filename));
}
let raw_bytes: MetadataRef = match flavor {
- CrateFlavor::Rlib => loader.get_rlib_metadata(target, filename)?,
+ CrateFlavor::Rlib => {
+ loader.get_rlib_metadata(target, filename).map_err(MetadataError::LoadFailure)?
+ }
CrateFlavor::Dylib => {
- let buf = loader.get_dylib_metadata(target, filename)?;
+ let buf =
+ loader.get_dylib_metadata(target, filename).map_err(MetadataError::LoadFailure)?;
// The header is uncompressed
let header_len = METADATA_HEADER.len();
debug!("checking {} bytes of metadata-version stamp", header_len);
let header = &buf[..cmp::min(header_len, buf.len())];
if header != METADATA_HEADER {
- return Err(format!(
- "incompatible metadata version found: '{}'",
+ return Err(MetadataError::LoadFailure(format!(
+ "invalid metadata version found: {}",
filename.display()
- ));
+ )));
}
// Header is okay -> inflate the actual metadata
match FrameDecoder::new(compressed_bytes).read_to_end(&mut inflated) {
Ok(_) => rustc_erase_owner!(OwningRef::new(inflated).map_owner_box()),
Err(_) => {
- return Err(format!("failed to decompress metadata: {}", filename.display()));
+ return Err(MetadataError::LoadFailure(format!(
+ "failed to decompress metadata: {}",
+ filename.display()
+ )));
}
}
}
CrateFlavor::Rmeta => {
// mmap the file, because only a small fraction of it is read.
- let file = std::fs::File::open(filename)
- .map_err(|_| format!("failed to open rmeta metadata: '{}'", filename.display()))?;
+ let file = std::fs::File::open(filename).map_err(|_| {
+ MetadataError::LoadFailure(format!(
+ "failed to open rmeta metadata: '{}'",
+ filename.display()
+ ))
+ })?;
let mmap = unsafe { Mmap::map(file) };
- let mmap = mmap
- .map_err(|_| format!("failed to mmap rmeta metadata: '{}'", filename.display()))?;
+ let mmap = mmap.map_err(|_| {
+ MetadataError::LoadFailure(format!(
+ "failed to mmap rmeta metadata: '{}'",
+ filename.display()
+ ))
+ })?;
rustc_erase_owner!(OwningRef::new(mmap).map_owner_box())
}
if blob.is_compatible() {
Ok(blob)
} else {
- Err(format!("incompatible metadata version found: '{}'", filename.display()))
+ Err(MetadataError::LoadFailure(format!(
+ "invalid metadata version found: {}",
+ filename.display()
+ )))
}
}
via_kind: Vec<CrateMismatch>,
via_version: Vec<CrateMismatch>,
via_filename: Vec<CrateMismatch>,
+ via_invalid: Vec<CrateMismatch>,
}
/// Candidate rejection reasons collected during crate search.
NonDylibPlugin(Symbol),
}
+enum MetadataError<'a> {
+ /// The file was missing.
+ NotPresent(&'a Path),
+ /// The file was present and invalid.
+ LoadFailure(String),
+}
+
+impl fmt::Display for MetadataError<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ MetadataError::NotPresent(filename) => {
+ f.write_str(&format!("no such file: '{}'", filename.display()))
+ }
+ MetadataError::LoadFailure(msg) => f.write_str(msg),
+ }
+ }
+}
+
impl CrateError {
crate fn report(self, sess: &Session, span: Span, missing_core: bool) -> ! {
let mut err = match self {
}
err.note(&msg);
err
+ } else if !locator.crate_rejections.via_invalid.is_empty() {
+ let mut err = struct_span_err!(
+ sess,
+ span,
+ E0786,
+ "found invalid metadata files for crate `{}`{}",
+ crate_name,
+ add,
+ );
+ for CrateMismatch { path: _, got } in locator.crate_rejections.via_invalid {
+ err.note(&got);
+ }
+ err
} else {
let mut err = struct_span_err!(
sess,
.libs
.iter()
.filter_map(|lib| lib.name.as_ref())
- .any(|n| &n.as_str() == &lib.name);
+ .any(|n| n.as_str() == lib.name);
if new_name.is_empty() {
self.tcx.sess.err(&format!(
"an empty renaming target was specified for library `{}`",
let ctor_res =
Res::Def(DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id);
let mut vis = self.get_visibility(ctor_def_id.index);
- if ctor_def_id == def_id && vis == ty::Visibility::Public {
+ if ctor_def_id == def_id && vis.is_public() {
// For non-exhaustive variants lower the constructor visibility to
// within the crate. We only need this for fictive constructors,
// for other constructors correct visibilities
}
let mut add_child = |bfs_queue: &mut VecDeque<_>, child: &Export, parent: DefId| {
- if child.vis != ty::Visibility::Public {
+ if !child.vis.is_public() {
return;
}
| DefKind::ConstParam
| DefKind::LifetimeParam
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::GlobalAsm
| DefKind::Closure
| DefKind::Generator
DefKind::Use
| DefKind::LifetimeParam
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::GlobalAsm
| DefKind::Closure
| DefKind::Generator
(true, mir_opt_base)
}
// Constants
- DefKind::AnonConst | DefKind::AssocConst | DefKind::Static | DefKind::Const => {
- (true, false)
- }
+ DefKind::AnonConst
+ | DefKind::InlineConst
+ | DefKind::AssocConst
+ | DefKind::Static
+ | DefKind::Const => (true, false),
// Full-fledged functions
DefKind::AssocFn | DefKind::Fn => {
let generics = tcx.generics_of(def_id);
| DefKind::Use
| DefKind::LifetimeParam
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::GlobalAsm
| DefKind::Closure
| DefKind::Generator
| DefKind::AssocFn
| DefKind::AssocConst
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::OpaqueTy
| DefKind::Impl
| DefKind::Field
result[header + 2] = (pos >> 8) as u8;
result[header + 3] = (pos >> 0) as u8;
+ // Record metadata size for self-profiling
+ tcx.prof.artifact_size("crate_metadata", "crate_metadata", result.len() as u64);
+
EncodedMetadata { raw_data: result }
}
};
DefKind::Ctor(ctor_of, def::CtorKind::from_hir(variant_data))
}
- Node::AnonConst(_) => DefKind::AnonConst,
+ Node::AnonConst(_) => {
+ let inline = match self.find(self.get_parent_node(hir_id)) {
+ Some(Node::Expr(&Expr {
+ kind: ExprKind::ConstBlock(ref anon_const), ..
+ })) if anon_const.hir_id == hir_id => true,
+ _ => false,
+ };
+ if inline { DefKind::InlineConst } else { DefKind::AnonConst }
+ }
Node::Field(_) => DefKind::Field,
Node::Expr(expr) => match expr.kind {
ExprKind::Closure(.., None) => DefKind::Closure,
(Level::Warn, None) => sess.struct_warn(""),
(Level::ForceWarn, Some(span)) => sess.struct_span_force_warn(span, ""),
(Level::ForceWarn, None) => sess.struct_force_warn(""),
- (Level::Deny | Level::Forbid, Some(span)) => sess.struct_span_err(span, ""),
- (Level::Deny | Level::Forbid, None) => sess.struct_err(""),
+ (Level::Deny | Level::Forbid, Some(span)) => {
+ let mut builder = sess.diagnostic().struct_err_lint("");
+ builder.set_span(span);
+ builder
+ }
+ (Level::Deny | Level::Forbid, None) => sess.diagnostic().struct_err_lint(""),
};
// If this code originates in a foreign macro, aka something that this crate
/// To avoid performance issues, there are places where we want to be sure to never raise these formatting errors,
/// so this method lets us detect them and `bug!` on unexpected errors.
pub fn formatted_string(&self) -> bool {
- match self {
+ matches!(
+ self,
InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_))
- | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationFailure { .. })
- | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_)) => true,
- _ => false,
- }
+ | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationFailure { .. })
+ | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_))
+ )
}
/// Should this error be reported as a hard error, preventing compilation, or a soft error,
mut self,
mut f: impl FnMut(UserTypeProjection) -> UserTypeProjection,
) -> Self {
- self.contents = self.contents.drain(..).map(|(proj, span)| (f(proj), span)).collect();
+ self.contents = self.contents.into_iter().map(|(proj, span)| (f(proj), span)).collect();
self
}
write!(w, "static {}", if tcx.is_mutable_static(def_id) { "mut " } else { "" })?
}
(_, _) if is_function => write!(w, "fn ")?,
- (DefKind::AnonConst, _) => {} // things like anon const, not an item
+ (DefKind::AnonConst | DefKind::InlineConst, _) => {} // things like anon const, not an item
_ => bug!("Unexpected def kind {:?}", kind),
}
/// additional requirements that the closure's creator must verify.
query mir_borrowck(key: LocalDefId) -> &'tcx mir::BorrowCheckResult<'tcx> {
desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key.to_def_id()) }
- cache_on_disk_if(tcx) { tcx.is_closure(key.to_def_id()) }
+ cache_on_disk_if(tcx) { tcx.is_typeck_child(key.to_def_id()) }
}
query mir_borrowck_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::BorrowCheckResult<'tcx> {
desc {
desc { "check for overlap between inherent impls defined in this crate" }
}
+ /// Checks whether all impls in the crate pass the overlap check, returning
+ /// which impls fail it. If all impls are correct, the returned slice is empty.
+ query orphan_check_crate(_: ()) -> &'tcx [LocalDefId] {
+ desc {
+ "checking whether the immpl in the this crate follow the orphan rules",
+ }
+ }
+
/// Check whether the function has any recursion that could cause the inliner to trigger
/// a cycle. Returns the call stack causing the cycle. The call stack does not contain the
/// current function, just all intermediate functions.
}
/// Return all `impl` blocks in the current crate.
- ///
- /// To allow caching this between crates, you must pass in [`LOCAL_CRATE`] as the crate number.
- /// Passing in any other crate will cause an ICE.
- ///
- /// [`LOCAL_CRATE`]: rustc_hir::def_id::LOCAL_CRATE
query all_local_trait_impls(_: ()) -> &'tcx BTreeMap<DefId, Vec<LocalDefId>> {
desc { "local trait impls" }
}
/// Error derived when matching traits/impls; see ObligationCause for more details
CompareImplMethodObligation {
- item_name: Symbol,
impl_item_def_id: DefId,
trait_item_def_id: DefId,
},
/// Error derived when matching traits/impls; see ObligationCause for more details
CompareImplTypeObligation {
- item_name: Symbol,
impl_item_def_id: DefId,
trait_item_def_id: DefId,
},
use crate::mir::interpret::ConstValue;
use crate::mir::interpret::{LitToConstInput, Scalar};
-use crate::ty::{self, Ty, TyCtxt};
-use crate::ty::{ParamEnv, ParamEnvAnd};
+use crate::ty::{
+ self, InlineConstSubsts, InlineConstSubstsParts, InternalSubsts, ParamEnv, ParamEnvAnd, Ty,
+ TyCtxt, TypeFoldable,
+};
use rustc_errors::ErrorReported;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
let ty = tcx.type_of(def.def_id_for_type_of());
+ match Self::try_eval_lit_or_param(tcx, ty, expr) {
+ Some(v) => v,
+ None => tcx.mk_const(ty::Const {
+ val: ty::ConstKind::Unevaluated(ty::Unevaluated {
+ def: def.to_global(),
+ substs_: None,
+ promoted: None,
+ }),
+ ty,
+ }),
+ }
+ }
+
+ fn try_eval_lit_or_param(
+ tcx: TyCtxt<'tcx>,
+ ty: Ty<'tcx>,
+ expr: &'tcx hir::Expr<'tcx>,
+ ) -> Option<&'tcx Self> {
let lit_input = match expr.kind {
hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => match expr.kind {
// If an error occurred, ignore that it's a literal and leave reporting the error up to
// mir.
if let Ok(c) = tcx.at(expr.span).lit_to_const(lit_input) {
- return c;
+ return Some(c);
} else {
tcx.sess.delay_span_bug(expr.span, "Const::from_anon_const: couldn't lit_to_const");
}
};
use hir::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath};
- let val = match expr.kind {
+ match expr.kind {
ExprKind::Path(QPath::Resolved(_, &Path { res: Res::Def(ConstParam, def_id), .. })) => {
// Find the name and index of the const parameter by indexing the generics of
// the parent item and construct a `ParamConst`.
let generics = tcx.generics_of(item_def_id.to_def_id());
let index = generics.param_def_id_to_index[&def_id];
let name = tcx.hir().name(hir_id);
- ty::ConstKind::Param(ty::ParamConst::new(index, name))
+ Some(tcx.mk_const(ty::Const {
+ val: ty::ConstKind::Param(ty::ParamConst::new(index, name)),
+ ty,
+ }))
}
- _ => ty::ConstKind::Unevaluated(ty::Unevaluated {
- def: def.to_global(),
- substs_: None,
- promoted: None,
- }),
+ _ => None,
+ }
+ }
+
+ pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx Self {
+ debug!("Const::from_inline_const(def_id={:?})", def_id);
+
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+
+ let body_id = match tcx.hir().get(hir_id) {
+ hir::Node::AnonConst(ac) => ac.body,
+ _ => span_bug!(
+ tcx.def_span(def_id.to_def_id()),
+ "from_inline_const can only process anonymous constants"
+ ),
};
- tcx.mk_const(ty::Const { val, ty })
+ let expr = &tcx.hir().body(body_id).value;
+
+ let ty = tcx.typeck(def_id).node_type(hir_id);
+
+ let ret = match Self::try_eval_lit_or_param(tcx, ty, expr) {
+ Some(v) => v,
+ None => {
+ let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id());
+ let parent_substs =
+ tcx.erase_regions(InternalSubsts::identity_for_item(tcx, typeck_root_def_id));
+ let substs =
+ InlineConstSubsts::new(tcx, InlineConstSubstsParts { parent_substs, ty })
+ .substs;
+ tcx.mk_const(ty::Const {
+ val: ty::ConstKind::Unevaluated(ty::Unevaluated {
+ def: ty::WithOptConstParam::unknown(def_id).to_global(),
+ substs_: Some(substs),
+ promoted: None,
+ }),
+ ty,
+ })
+ }
+ };
+ debug_assert!(!ret.has_free_regions(tcx));
+ ret
}
/// Interns the given value as a constant.
TupleSize(ExpectedFound<usize>),
FixedArraySize(ExpectedFound<u64>),
ArgCount,
+ FieldMisMatch(Symbol, Symbol),
RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>),
RegionsInsufficientlyPolymorphic(BoundRegionKind, Region<'tcx>),
pluralize!(values.found)
),
ArgCount => write!(f, "incorrect number of function parameters"),
+ FieldMisMatch(adt, field) => write!(f, "field type mismatch: {}.{}", adt, field),
RegionsDoesNotOutlive(..) => write!(f, "lifetime mismatch"),
RegionsInsufficientlyPolymorphic(br, _) => write!(
f,
| ArgumentMutability(_)
| TupleSize(_)
| ArgCount
+ | FieldMisMatch(..)
| RegionsDoesNotOutlive(..)
| RegionsInsufficientlyPolymorphic(..)
| RegionsOverlyPolymorphic(..)
Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar, BoundVariableKind,
CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstVid, EarlyBoundRegion,
ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, FreeRegion, GenSig,
- GeneratorSubsts, GeneratorSubstsParts, ParamConst, ParamTy, PolyExistentialProjection,
- PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, ProjectionTy, Region, RegionKind,
- RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts, VarianceDiagInfo, VarianceDiagMutKind,
+ GeneratorSubsts, GeneratorSubstsParts, InlineConstSubsts, InlineConstSubstsParts, ParamConst,
+ ParamTy, PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyGenSig,
+ PolyTraitRef, ProjectionTy, Region, RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut,
+ UpvarSubsts, VarianceDiagInfo, VarianceDiagMutKind,
};
pub use self::trait_def::TraitDef;
Visibility::Invisible => false,
}
}
+
+ pub fn is_public(self) -> bool {
+ matches!(self, Visibility::Public)
+ }
}
/// The crate variances map is computed during typeck and contains the
| DefKind::Static
| DefKind::AssocConst
| DefKind::Ctor(..)
- | DefKind::AnonConst => self.mir_for_ctfe_opt_const_arg(def),
+ | DefKind::AnonConst
+ | DefKind::InlineConst => self.mir_for_ctfe_opt_const_arg(def),
// If the caller wants `mir_for_ctfe` of a function they should not be using
// `instance_mir`, so we'll assume const fn also wants the optimized version.
_ => {
// Iterate external crate defs but be mindful about visibility
while let Some(def) = queue.pop() {
for child in tcx.item_children(def).iter() {
- if child.vis != ty::Visibility::Public {
+ if !child.vis.is_public() {
continue;
}
})
.enumerate()
.map(|(i, r)| match r {
- Err(TypeError::Sorts(exp_found)) => Err(TypeError::ArgumentSorts(exp_found, i)),
- Err(TypeError::Mutability) => Err(TypeError::ArgumentMutability(i)),
+ Err(TypeError::Sorts(exp_found) | TypeError::ArgumentSorts(exp_found, _)) => {
+ Err(TypeError::ArgumentSorts(exp_found, i))
+ }
+ Err(TypeError::Mutability | TypeError::ArgumentMutability(_)) => {
+ Err(TypeError::ArgumentMutability(i))
+ }
r => r,
});
Ok(ty::FnSig {
TupleSize(x) => TupleSize(x),
FixedArraySize(x) => FixedArraySize(x),
ArgCount => ArgCount,
+ FieldMisMatch(x, y) => FieldMisMatch(x, y),
RegionsDoesNotOutlive(a, b) => {
return tcx.lift((a, b)).map(|(a, b)| RegionsDoesNotOutlive(a, b));
}
}
}
+/// An inline const is modeled like
+///
+/// const InlineConst<'l0...'li, T0...Tj, R>: R;
+///
+/// where:
+///
+/// - 'l0...'li and T0...Tj are the generic parameters
+/// inherited from the item that defined the inline const,
+/// - R represents the type of the constant.
+///
+/// When the inline const is instantiated, `R` is substituted as the actual inferred
+/// type of the constant. The reason that `R` is represented as an extra type parameter
+/// is the same reason that [`ClosureSubsts`] have `CS` and `U` as type parameters:
+/// inline const can reference lifetimes that are internal to the creating function.
+#[derive(Copy, Clone, Debug, TypeFoldable)]
+pub struct InlineConstSubsts<'tcx> {
+ /// Generic parameters from the enclosing item,
+ /// concatenated with the inferred type of the constant.
+ pub substs: SubstsRef<'tcx>,
+}
+
+/// Struct returned by `split()`.
+pub struct InlineConstSubstsParts<'tcx, T> {
+ pub parent_substs: &'tcx [GenericArg<'tcx>],
+ pub ty: T,
+}
+
+impl<'tcx> InlineConstSubsts<'tcx> {
+ /// Construct `InlineConstSubsts` from `InlineConstSubstsParts`.
+ pub fn new(
+ tcx: TyCtxt<'tcx>,
+ parts: InlineConstSubstsParts<'tcx, Ty<'tcx>>,
+ ) -> InlineConstSubsts<'tcx> {
+ InlineConstSubsts {
+ substs: tcx.mk_substs(
+ parts.parent_substs.iter().copied().chain(std::iter::once(parts.ty.into())),
+ ),
+ }
+ }
+
+ /// Divides the inline const substs into their respective components.
+ /// The ordering assumed here must match that used by `InlineConstSubsts::new` above.
+ fn split(self) -> InlineConstSubstsParts<'tcx, GenericArg<'tcx>> {
+ match self.substs[..] {
+ [ref parent_substs @ .., ty] => InlineConstSubstsParts { parent_substs, ty },
+ _ => bug!("inline const substs missing synthetics"),
+ }
+ }
+
+ /// Returns the substitutions of the inline const's parent.
+ pub fn parent_substs(self) -> &'tcx [GenericArg<'tcx>] {
+ self.split().parent_substs
+ }
+
+ /// Returns the type of this inline const.
+ pub fn ty(self) -> Ty<'tcx> {
+ self.split().ty.expect_ty()
+ }
+}
+
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, TyEncodable, TyDecodable)]
#[derive(HashStable, TypeFoldable)]
pub enum ExistentialPredicate<'tcx> {
use crate::mir;
use crate::ty::codec::{TyDecoder, TyEncoder};
use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
-use crate::ty::sty::{ClosureSubsts, GeneratorSubsts};
+use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts};
use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt};
use rustc_hir::def_id::DefId;
GeneratorSubsts { substs: self }
}
+ /// Interpret these substitutions as the substitutions of an inline const.
+ /// Inline const substitutions have a particular structure controlled by the
+ /// compiler that encodes information like the inferred type;
+ /// see `ty::InlineConstSubsts` struct for more comments.
+ pub fn as_inline_const(&'tcx self) -> InlineConstSubsts<'tcx> {
+ InlineConstSubsts { substs: self }
+ }
+
/// Creates an `InternalSubsts` that maps each generic parameter to itself.
pub fn identity_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx> {
Self::for_item(tcx, def_id, |param, _| tcx.mk_param_from_def(param))
matches!(self.def_kind(def_id), DefKind::Closure | DefKind::Generator)
}
+ /// Returns `true` if `def_id` refers to a definition that does not have its own
+ /// type-checking context, i.e. closure, generator or inline const.
+ pub fn is_typeck_child(self, def_id: DefId) -> bool {
+ matches!(
+ self.def_kind(def_id),
+ DefKind::Closure | DefKind::Generator | DefKind::InlineConst
+ )
+ }
+
/// Returns `true` if `def_id` refers to a trait (i.e., `trait Foo { ... }`).
pub fn is_trait(self, def_id: DefId) -> bool {
self.def_kind(def_id) == DefKind::Trait
matches!(self.def_kind(def_id), DefKind::Ctor(..))
}
- /// Given the def-ID of a fn or closure, returns the def-ID of
- /// the innermost fn item that the closure is contained within.
- /// This is a significant `DefId` because, when we do
- /// type-checking, we type-check this fn item and all of its
- /// (transitive) closures together. Therefore, when we fetch the
+ /// Given the `DefId`, returns the `DefId` of the innermost item that
+ /// has its own type-checking context or "inference enviornment".
+ ///
+ /// For example, a closure has its own `DefId`, but it is type-checked
+ /// with the containing item. Similarly, an inline const block has its
+ /// own `DefId` but it is type-checked together with the containing item.
+ ///
+ /// Therefore, when we fetch the
/// `typeck` the closure, for example, we really wind up
/// fetching the `typeck` the enclosing fn item.
- pub fn closure_base_def_id(self, def_id: DefId) -> DefId {
+ pub fn typeck_root_def_id(self, def_id: DefId) -> DefId {
let mut def_id = def_id;
- while self.is_closure(def_id) {
+ while self.is_typeck_child(def_id) {
def_id = self.parent(def_id).unwrap_or_else(|| {
bug!("closure {:?} has no parent", def_id);
});
let rv = f();
let duration = start.elapsed();
let mut accu = accu.lock();
- *accu = *accu + duration;
+ *accu += duration;
rv
}
hir::ExprKind::ConstBlock(ref anon_const) => {
let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
- let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id);
+ let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id);
ExprKind::ConstBlock { value }
}
let (lit, neg) = match expr.kind {
hir::ExprKind::ConstBlock(ref anon_const) => {
let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
- let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id);
+ let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id);
if matches!(value.val, ConstKind::Param(_)) {
let span = self.tcx.hir().span(anon_const.hir_id);
self.errors.push(PatternError::ConstParamInPattern(span));
/// expands it.
fn push(&mut self, row: PatStack<'p, 'tcx>) {
if !row.is_empty() && row.head().is_or_pat() {
- for row in row.expand_or_pat() {
- self.patterns.push(row);
- }
+ self.patterns.extend(row.expand_or_pat());
} else {
self.patterns.push(row);
}
return ret;
}
- assert!(rows.iter().all(|r| r.len() == v.len()));
+ debug_assert!(rows.iter().all(|r| r.len() == v.len()));
let ty = v.head().ty();
let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty);
// Non-code expressions are injected into the coverage map, without generating executable code.
fn inject_intermediate_expression(mir_body: &mut mir::Body<'tcx>, expression: CoverageKind) {
- debug_assert!(if let CoverageKind::Expression { .. } = expression { true } else { false });
+ debug_assert!(matches!(expression, CoverageKind::Expression { .. }));
debug!(" injecting non-code expression {:?}", expression);
let inject_in_bb = mir::START_BLOCK;
let data = &mut mir_body[inject_in_bb];
stmt_index: usize,
) -> Self {
let is_closure = match statement.kind {
- StatementKind::Assign(box (_, Rvalue::Aggregate(box ref kind, _))) => match kind {
- AggregateKind::Closure(_, _) | AggregateKind::Generator(_, _, _) => true,
- _ => false,
- },
+ StatementKind::Assign(box (_, Rvalue::Aggregate(box ref kind, _))) => {
+ matches!(kind, AggregateKind::Closure(_, _) | AggregateKind::Generator(_, _, _))
+ }
_ => false,
};
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// This pass must run before inlining, since we insert callee bodies in RevealAll mode.
// Do not apply this transformation to generators.
- if (tcx.sess.mir_opt_level() >= 3 || !super::inline::is_enabled(tcx))
+ if (tcx.sess.mir_opt_level() >= 3 || super::inline::is_enabled(tcx))
&& body.generator.is_none()
{
let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
match self_ty.kind() {
_ if is_copy => builder.copy_shim(),
- ty::Array(ty, len) => builder.array_shim(dest, src, ty, len),
ty::Closure(_, substs) => {
builder.tuple_like_shim(dest, src, substs.as_closure().upvar_tys())
}
);
}
- fn loop_header(
- &mut self,
- beg: Place<'tcx>,
- end: Place<'tcx>,
- loop_body: BasicBlock,
- loop_end: BasicBlock,
- is_cleanup: bool,
- ) {
- let tcx = self.tcx;
-
- let cond = self.make_place(Mutability::Mut, tcx.types.bool);
- let compute_cond = self.make_statement(StatementKind::Assign(Box::new((
- cond,
- Rvalue::BinaryOp(BinOp::Ne, Box::new((Operand::Copy(end), Operand::Copy(beg)))),
- ))));
-
- // `if end != beg { goto loop_body; } else { goto loop_end; }`
- self.block(
- vec![compute_cond],
- TerminatorKind::if_(tcx, Operand::Move(cond), loop_body, loop_end),
- is_cleanup,
- );
- }
-
- fn make_usize(&self, value: u64) -> Box<Constant<'tcx>> {
- Box::new(Constant {
- span: self.span,
- user_ty: None,
- literal: ty::Const::from_usize(self.tcx, value).into(),
- })
- }
-
- fn array_shim(
- &mut self,
- dest: Place<'tcx>,
- src: Place<'tcx>,
- ty: Ty<'tcx>,
- len: &'tcx ty::Const<'tcx>,
- ) {
- let tcx = self.tcx;
- let span = self.span;
-
- let beg = self.local_decls.push(LocalDecl::new(tcx.types.usize, span));
- let end = self.make_place(Mutability::Not, tcx.types.usize);
-
- // BB #0
- // `let mut beg = 0;`
- // `let end = len;`
- // `goto #1;`
- let inits = vec![
- self.make_statement(StatementKind::Assign(Box::new((
- Place::from(beg),
- Rvalue::Use(Operand::Constant(self.make_usize(0))),
- )))),
- self.make_statement(StatementKind::Assign(Box::new((
- end,
- Rvalue::Use(Operand::Constant(Box::new(Constant {
- span: self.span,
- user_ty: None,
- literal: len.into(),
- }))),
- )))),
- ];
- self.block(inits, TerminatorKind::Goto { target: BasicBlock::new(1) }, false);
-
- // BB #1: loop {
- // BB #2;
- // BB #3;
- // }
- // BB #4;
- self.loop_header(Place::from(beg), end, BasicBlock::new(2), BasicBlock::new(4), false);
-
- // BB #2
- // `dest[i] = Clone::clone(src[beg])`;
- // Goto #3 if ok, #5 if unwinding happens.
- let dest_field = self.tcx.mk_place_index(dest, beg);
- let src_field = self.tcx.mk_place_index(src, beg);
- self.make_clone_call(dest_field, src_field, ty, BasicBlock::new(3), BasicBlock::new(5));
-
- // BB #3
- // `beg = beg + 1;`
- // `goto #1`;
- let statements = vec![self.make_statement(StatementKind::Assign(Box::new((
- Place::from(beg),
- Rvalue::BinaryOp(
- BinOp::Add,
- Box::new((Operand::Copy(Place::from(beg)), Operand::Constant(self.make_usize(1)))),
- ),
- ))))];
- self.block(statements, TerminatorKind::Goto { target: BasicBlock::new(1) }, false);
-
- // BB #4
- // `return dest;`
- self.block(vec![], TerminatorKind::Return, false);
-
- // BB #5 (cleanup)
- // `let end = beg;`
- // `let mut beg = 0;`
- // goto #6;
- let end = beg;
- let beg = self.local_decls.push(LocalDecl::new(tcx.types.usize, span));
- let init = self.make_statement(StatementKind::Assign(Box::new((
- Place::from(beg),
- Rvalue::Use(Operand::Constant(self.make_usize(0))),
- ))));
- self.block(vec![init], TerminatorKind::Goto { target: BasicBlock::new(6) }, true);
-
- // BB #6 (cleanup): loop {
- // BB #7;
- // BB #8;
- // }
- // BB #9;
- self.loop_header(
- Place::from(beg),
- Place::from(end),
- BasicBlock::new(7),
- BasicBlock::new(9),
- true,
- );
-
- // BB #7 (cleanup)
- // `drop(dest[beg])`;
- self.block(
- vec![],
- TerminatorKind::Drop {
- place: self.tcx.mk_place_index(dest, beg),
- target: BasicBlock::new(8),
- unwind: None,
- },
- true,
- );
-
- // BB #8 (cleanup)
- // `beg = beg + 1;`
- // `goto #6;`
- let statement = self.make_statement(StatementKind::Assign(Box::new((
- Place::from(beg),
- Rvalue::BinaryOp(
- BinOp::Add,
- Box::new((Operand::Copy(Place::from(beg)), Operand::Constant(self.make_usize(1)))),
- ),
- ))));
- self.block(vec![statement], TerminatorKind::Goto { target: BasicBlock::new(6) }, true);
-
- // BB #9 (resume)
- self.block(vec![], TerminatorKind::Resume, true);
- }
-
fn tuple_like_shim<I>(&mut self, dest: Place<'tcx>, src: Place<'tcx>, tys: I)
where
I: Iterator<Item = Ty<'tcx>>,
// This is a temporary solution that handles possibly diverging asm statements.
// Accompanying testcases: mir-opt/unreachable_asm.rs and mir-opt/unreachable_asm_2.rs
let asm_stmt_in_block = || {
- bb_data.statements.iter().any(|stmt: &Statement<'_>| match stmt.kind {
- StatementKind::LlvmInlineAsm(..) => true,
- _ => false,
+ bb_data.statements.iter().any(|stmt: &Statement<'_>| {
+ matches!(stmt.kind, StatementKind::LlvmInlineAsm(..))
})
};
)
});
+ if tcx.prof.enabled() {
+ // Record CGU size estimates for self-profiling.
+ for cgu in codegen_units {
+ tcx.prof.artifact_size(
+ "codegen_unit_size_estimate",
+ &cgu.name().as_str()[..],
+ cgu.size_estimate() as u64,
+ );
+ }
+ }
+
let mono_items: DefIdSet = items
.iter()
.filter_map(|mono_item| match *mono_item {
| DefKind::Use
| DefKind::ForeignMod
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::OpaqueTy
| DefKind::Field
| DefKind::LifetimeParam
generics: &'tcx ty::Generics,
unused_parameters: &FiniteBitSet<u32>,
) {
- let base_def_id = tcx.closure_base_def_id(def_id);
+ let base_def_id = tcx.typeck_root_def_id(def_id);
if !tcx.get_attrs(base_def_id).iter().any(|a| a.has_name(sym::rustc_polymorphize_error)) {
return;
}
ControlFlow::CONTINUE
}
ty::ConstKind::Unevaluated(uv)
- if self.tcx.def_kind(uv.def.did) == DefKind::AnonConst =>
+ if matches!(self.tcx.def_kind(uv.def.did), DefKind::AnonConst | DefKind::InlineConst) =>
{
self.visit_child_body(uv.def.did, uv.substs(self.tcx));
ControlFlow::CONTINUE
} else if self.check_fn_front_matter(def_final) {
// FUNCTION ITEM
let (ident, sig, generics, body) = self.parse_fn(attrs, req_name, lo)?;
- (ident, ItemKind::Fn(Box::new(FnKind(def(), sig, generics, body))))
+ (ident, ItemKind::Fn(Box::new(Fn { defaultness: def(), sig, generics, body })))
} else if self.eat_keyword(kw::Extern) {
if self.eat_keyword(kw::Crate) {
// EXTERN CRATE
};
let trait_ref = TraitRef { path, ref_id: ty_first.id };
- ItemKind::Impl(Box::new(ImplKind {
+ ItemKind::Impl(Box::new(Impl {
unsafety,
polarity,
defaultness,
}
None => {
// impl Type
- ItemKind::Impl(Box::new(ImplKind {
+ ItemKind::Impl(Box::new(Impl {
unsafety,
polarity,
defaultness,
self.expect_keyword(kw::Trait)?;
let ident = self.parse_ident()?;
- let mut tps = self.parse_generics()?;
+ let mut generics = self.parse_generics()?;
// Parse optional colon and supertrait bounds.
let had_colon = self.eat(&token::Colon);
}
let bounds = self.parse_generic_bounds(None)?;
- tps.where_clause = self.parse_where_clause()?;
+ generics.where_clause = self.parse_where_clause()?;
self.expect_semi()?;
let whole_span = lo.to(self.prev_token.span);
self.sess.gated_spans.gate(sym::trait_alias, whole_span);
- Ok((ident, ItemKind::TraitAlias(tps, bounds)))
+ Ok((ident, ItemKind::TraitAlias(generics, bounds)))
} else {
// It's a normal trait.
- tps.where_clause = self.parse_where_clause()?;
+ generics.where_clause = self.parse_where_clause()?;
let items = self.parse_item_list(attrs, |p| p.parse_trait_item(ForceCollect::No))?;
- Ok((ident, ItemKind::Trait(Box::new(TraitKind(is_auto, unsafety, tps, bounds, items)))))
+ Ok((
+ ident,
+ ItemKind::Trait(Box::new(Trait { is_auto, unsafety, generics, bounds, items })),
+ ))
}
}
/// TypeAlias = "type" Ident Generics {":" GenericBounds}? {"=" Ty}? ";" ;
/// ```
/// The `"type"` has already been eaten.
- fn parse_type_alias(&mut self, def: Defaultness) -> PResult<'a, ItemInfo> {
+ fn parse_type_alias(&mut self, defaultness: Defaultness) -> PResult<'a, ItemInfo> {
let ident = self.parse_ident()?;
let mut generics = self.parse_generics()?;
if self.eat(&token::Colon) { self.parse_generic_bounds(None)? } else { Vec::new() };
generics.where_clause = self.parse_where_clause()?;
- let default = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None };
+ let ty = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None };
self.expect_semi()?;
- Ok((ident, ItemKind::TyAlias(Box::new(TyAliasKind(def, generics, bounds, default)))))
+ Ok((ident, ItemKind::TyAlias(Box::new(TyAlias { defaultness, generics, bounds, ty }))))
}
/// Parses a `UseTree`.
};
match impl_info.1 {
- ItemKind::Impl(box ImplKind {
- of_trait: Some(ref trai), ref mut constness, ..
- }) => {
+ ItemKind::Impl(box Impl { of_trait: Some(ref trai), ref mut constness, .. }) => {
*constness = Const::Yes(const_span);
let before_trait = trai.path.span.shrink_to_lo();
use rustc_ast::tokenstream::{DelimSpan, TokenTree};
use rustc_ast::{self as ast, Attribute, MacArgs, MacDelimiter, MetaItem, MetaItemKind};
use rustc_errors::{Applicability, FatalError, PResult};
-use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP};
+use rustc_feature::{AttributeTemplate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
use rustc_session::parse::ParseSess;
use rustc_span::{sym, Symbol};
return;
}
- let attr_info =
- attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)).map(|a| **a);
+ let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
// Check input tokens for built-in and key-value attributes.
match attr_info {
// `rustc_dummy` doesn't have any restrictions specific to built-in attributes.
- Some((name, _, template, _)) if name != sym::rustc_dummy => {
- check_builtin_attribute(sess, attr, name, template)
+ Some(BuiltinAttribute { name, template, .. }) if *name != sym::rustc_dummy => {
+ check_builtin_attribute(sess, attr, *name, *template)
}
_ if let MacArgs::Eq(..) = attr.get_normal_item().args => {
// All key-value attributes are restricted to meta-item syntax.
attr: &Attribute,
name: Symbol,
) -> ! {
- let template = BUILTIN_ATTRIBUTE_MAP.get(&name).expect("builtin attr defined").2;
+ let template = BUILTIN_ATTRIBUTE_MAP.get(&name).expect("builtin attr defined").template;
emit_malformed_attribute(sess, attr, name, template);
// This is fatal, otherwise it will likely cause a cascade of other errors
// (and an error here is expected to be very rare).
use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, NestedMetaItem};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{pluralize, struct_span_err, Applicability};
-use rustc_feature::{AttributeType, BUILTIN_ATTRIBUTE_MAP};
+use rustc_feature::{AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
}
if hir_id != CRATE_HIR_ID {
- if let Some((_, AttributeType::CrateLevel, ..)) =
+ if let Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) =
attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name))
{
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
required_gates.iter().copied().filter(|&g| !features.enabled(g)).collect();
match missing_gates.as_slice() {
- &[] => struct_span_err!(tcx.sess, span, E0744, "{}", msg).emit(),
+ [] => struct_span_err!(tcx.sess, span, E0744, "{}", msg).emit(),
- &[missing_primary, ref missing_secondary @ ..] => {
- let mut err = feature_err(&tcx.sess.parse_sess, missing_primary, span, &msg);
+ [missing_primary, ref missing_secondary @ ..] => {
+ let mut err = feature_err(&tcx.sess.parse_sess, *missing_primary, span, &msg);
// If multiple feature gates would be required to enable this expression, include
// them as help messages. Don't emit a separate error for each missing feature gate.
// properly, we can't miss any types.
match expr.kind {
- // Manually recurse over closures, because they are the only
+ // Manually recurse over closures and inline consts, because they are the only
// case of nested bodies that share the parent environment.
- hir::ExprKind::Closure(.., body, _, _) => {
+ hir::ExprKind::Closure(.., body, _, _)
+ | hir::ExprKind::ConstBlock(hir::AnonConst { body, .. }) => {
let body = visitor.tcx.hir().body(body);
visitor.visit_body(body);
}
}
fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree {
- let closure_base_def_id = tcx.closure_base_def_id(def_id);
- if closure_base_def_id != def_id {
- return tcx.region_scope_tree(closure_base_def_id);
+ let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
+ if typeck_root_def_id != def_id {
+ return tcx.region_scope_tree(typeck_root_def_id);
}
let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
module: LocalDefId,
) {
let level = Some(AccessLevel::Reachable);
- if let ty::Visibility::Public = vis {
+ if vis.is_public() {
self.update(def_id, level);
}
match def_kind {
DefKind::Struct | DefKind::Union => {
// While structs and unions have type privacy, their fields do not.
- if let ty::Visibility::Public = vis {
+ if vis.is_public() {
let item =
self.tcx.hir().expect_item(self.tcx.hir().local_def_id_to_hir_id(def_id));
if let hir::ItemKind::Struct(ref struct_def, _)
| DefKind::Use
| DefKind::ForeignMod
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::Field
| DefKind::GlobalAsm
| DefKind::Impl
let def_id = self.tcx.hir().local_def_id(id);
if let Some(exports) = self.tcx.module_exports(def_id) {
for export in exports.iter() {
- if export.vis == ty::Visibility::Public {
+ if export.vis.is_public() {
if let Some(def_id) = export.res.opt_def_id() {
if let Some(def_id) = def_id.as_local() {
self.update(def_id, Some(AccessLevel::Exported));
/// 1. It's contained within a public type
/// 2. It comes from a private crate
fn leaks_private_dep(&self, item_id: DefId) -> bool {
- let ret = self.required_visibility == ty::Visibility::Public
- && self.tcx.is_private_dep(item_id.krate);
+ let ret = self.required_visibility.is_public() && self.tcx.is_private_dep(item_id.krate);
tracing::debug!("leaks_private_dep(item_id={:?})={}", item_id, ret);
ret
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
if let Some(result) = result {
+ let prev_fingerprint = tcx
+ .dep_context()
+ .dep_graph()
+ .prev_fingerprint_of(dep_node)
+ .unwrap_or(Fingerprint::ZERO);
// If `-Zincremental-verify-ich` is specified, re-hash results from
// the cache and make sure that they have the expected fingerprint.
- if unlikely!(tcx.dep_context().sess().opts.debugging_opts.incremental_verify_ich) {
+ //
+ // If not, we still seek to verify a subset of fingerprints loaded
+ // from disk. Re-hashing results is fairly expensive, so we can't
+ // currently afford to verify every hash. This subset should still
+ // give us some coverage of potential bugs though.
+ let try_verify = prev_fingerprint.as_value().1 % 32 == 0;
+ if unlikely!(
+ try_verify || tcx.dep_context().sess().opts.debugging_opts.incremental_verify_ich
+ ) {
incremental_verify_ich(*tcx.dep_context(), &result, dep_node, query);
}
use rustc_ast::visit::{self, AssocCtxt, Visitor};
use rustc_ast::{self as ast, AssocItem, AssocItemKind, MetaItemKind, StmtKind};
-use rustc_ast::{Block, FnKind, ForeignItem, ForeignItemKind, ImplKind, Item, ItemKind, NodeId};
+use rustc_ast::{Block, Fn, ForeignItem, ForeignItemKind, Impl, Item, ItemKind, NodeId};
use rustc_ast_lowering::ResolverAstLowering;
use rustc_attr as attr;
use rustc_data_structures::sync::Lrc;
}
// These items do not add names to modules.
- ItemKind::Impl(box ImplKind { of_trait: Some(..), .. }) => {
+ ItemKind::Impl(box Impl { of_trait: Some(..), .. }) => {
self.r.trait_impl_items.insert(local_def_id);
}
ItemKind::Impl { .. } | ItemKind::ForeignMod(..) | ItemKind::GlobalAsm(..) => {}
| DefKind::Use
| DefKind::ForeignMod
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::Field
| DefKind::LifetimeParam
| DefKind::GlobalAsm
// Mark the given macro as unused unless its name starts with `_`.
// Macro uses will remove items from this set, and the remaining
// items will be reported as `unused_macros`.
- fn insert_unused_macro(
- &mut self,
- ident: Ident,
- def_id: LocalDefId,
- node_id: NodeId,
- span: Span,
- ) {
+ fn insert_unused_macro(&mut self, ident: Ident, def_id: LocalDefId, node_id: NodeId) {
if !ident.as_str().starts_with('_') {
- self.r.unused_macros.insert(def_id, (node_id, span));
+ self.r.unused_macros.insert(def_id, (node_id, ident));
}
}
self.r.define(module, ident, MacroNS, (res, vis, span, expansion, IsMacroExport));
} else {
self.r.check_reserved_macro_name(ident, res);
- self.insert_unused_macro(ident, def_id, item.id, span);
+ self.insert_unused_macro(ident, def_id, item.id);
}
self.r.visibilities.insert(def_id, vis);
self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Binding(
_ => self.resolve_visibility(&item.vis),
};
if vis != ty::Visibility::Public {
- self.insert_unused_macro(ident, def_id, item.id, span);
+ self.insert_unused_macro(ident, def_id, item.id);
}
self.r.define(module, ident, MacroNS, (res, vis, span, expansion));
self.r.visibilities.insert(def_id, vis);
if ctxt == AssocCtxt::Trait {
let (def_kind, ns) = match item.kind {
AssocItemKind::Const(..) => (DefKind::AssocConst, ValueNS),
- AssocItemKind::Fn(box FnKind(_, ref sig, _, _)) => {
+ AssocItemKind::Fn(box Fn { ref sig, .. }) => {
if sig.decl.has_self() {
self.r.has_self.insert(def_id);
}
use rustc_ast_lowering::ResolverAstLowering;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::pluralize;
-use rustc_middle::ty;
use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_IMPORTS};
use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_span::{MultiSpan, Span, DUMMY_SP};
for import in self.potentially_unused_imports.iter() {
match import.kind {
_ if import.used.get()
- || import.vis.get() == ty::Visibility::Public
+ || import.vis.get().is_public()
|| import.span.is_dummy() =>
{
if let ImportKind::MacroUse = import.kind {
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::PrimTy;
use rustc_middle::bug;
-use rustc_middle::ty::{self, DefIdTree};
+use rustc_middle::ty::DefIdTree;
use rustc_session::Session;
use rustc_span::hygiene::MacroKind;
use rustc_span::lev_distance::find_best_match_for_name;
suggestions.extend(
BUILTIN_ATTRIBUTES
.iter()
- .map(|(name, ..)| TypoSuggestion::typo_from_res(*name, res)),
+ .map(|attr| TypoSuggestion::typo_from_res(attr.name, res)),
);
}
}
);
let def_span = self.session.source_map().guess_head_span(binding.span);
let mut note_span = MultiSpan::from_span(def_span);
- if !first && binding.vis == ty::Visibility::Public {
+ if !first && binding.vis.is_public() {
note_span.push_span_label(def_span, "consider importing it directly".into());
}
err.span_note(note_span, &msg);
import: Import { kind: ImportKind::ExternCrate { .. }, .. },
..
},
- ) => import.vis.get() == ty::Visibility::Public,
+ ) => import.vis.get().is_public(),
_ => false,
}
}
}
fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
match foreign_item.kind {
- ForeignItemKind::Fn(box FnKind(_, _, ref generics, _))
- | ForeignItemKind::TyAlias(box TyAliasKind(_, ref generics, ..)) => {
+ ForeignItemKind::Fn(box Fn { ref generics, .. })
+ | ForeignItemKind::TyAlias(box TyAlias { ref generics, .. }) => {
self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
visit::walk_foreign_item(this, foreign_item);
});
debug!("(resolving item) resolving {} ({:?})", name, item.kind);
match item.kind {
- ItemKind::TyAlias(box TyAliasKind(_, ref generics, _, _))
- | ItemKind::Fn(box FnKind(_, _, ref generics, _)) => {
+ ItemKind::TyAlias(box TyAlias { ref generics, .. })
+ | ItemKind::Fn(box Fn { ref generics, .. }) => {
self.compute_num_lifetime_params(item.id, generics);
self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
visit::walk_item(this, item)
self.resolve_adt(item, generics);
}
- ItemKind::Impl(box ImplKind {
+ ItemKind::Impl(box Impl {
ref generics,
ref of_trait,
ref self_ty,
self.resolve_implementation(generics, of_trait, &self_ty, item.id, impl_items);
}
- ItemKind::Trait(box TraitKind(.., ref generics, ref bounds, ref trait_items)) => {
+ ItemKind::Trait(box Trait { ref generics, ref bounds, ref items, .. }) => {
self.compute_num_lifetime_params(item.id, generics);
// Create a new rib for the trait-wide type parameters.
self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
});
};
- this.with_trait_items(trait_items, |this| {
- for item in trait_items {
+ this.with_trait_items(items, |this| {
+ for item in items {
match &item.kind {
AssocItemKind::Const(_, ty, default) => {
this.visit_ty(ty);
);
}
}
- AssocItemKind::Fn(box FnKind(_, _, generics, _)) => {
+ AssocItemKind::Fn(box Fn { generics, .. }) => {
walk_assoc_item(this, generics, item);
}
- AssocItemKind::TyAlias(box TyAliasKind(_, generics, _, _)) => {
+ AssocItemKind::TyAlias(box TyAlias { generics, .. }) => {
walk_assoc_item(this, generics, item);
}
AssocItemKind::MacCall(_) => {
},
);
}
- AssocItemKind::Fn(box FnKind(.., generics, _)) => {
+ AssocItemKind::Fn(box Fn { generics, .. }) => {
debug!("resolve_implementation AssocItemKind::Fn");
// We also need a new scope for the impl item type parameters.
this.with_generic_param_rib(
},
);
}
- AssocItemKind::TyAlias(box TyAliasKind(
- _,
- generics,
- _,
- _,
- )) => {
+ AssocItemKind::TyAlias(box TyAlias {
+ generics, ..
+ }) => {
debug!("resolve_implementation AssocItemKind::TyAlias");
// We also need a new scope for the impl item type parameters.
this.with_generic_param_rib(
let candidates = self
.r
.lookup_import_candidates(ident, ns, &self.parent_scope, is_expected)
- .drain(..)
+ .into_iter()
.filter(|ImportSuggestion { did, .. }| {
match (did, res.and_then(|res| res.opt_def_id())) {
(Some(suggestion_did), Some(actual_did)) => *suggestion_did != actual_did,
if assoc_item.ident == ident {
return Some(match &assoc_item.kind {
ast::AssocItemKind::Const(..) => AssocSuggestion::AssocConst,
- ast::AssocItemKind::Fn(box ast::FnKind(_, sig, ..))
- if sig.decl.has_self() =>
- {
+ ast::AssocItemKind::Fn(box ast::Fn { sig, .. }) if sig.decl.has_self() => {
AssocSuggestion::MethodWithSelf
}
ast::AssocItemKind::Fn(..) => AssocSuggestion::AssocFn,
} else {
// Search in module.
let mod_path = &path[..path.len() - 1];
- if let PathResult::Module(module) =
+ if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
self.resolve_path(mod_path, Some(TypeNS), false, span, CrateLint::No)
{
- if let ModuleOrUniformRoot::Module(module) = module {
- self.r.add_module_candidates(module, &mut names, &filter_fn);
- }
+ self.r.add_module_candidates(module, &mut names, &filter_fn);
}
}
if suggest_only_tuple_variants {
// Suggest only tuple variants regardless of whether they have fields and do not
// suggest path with added parentheses.
- let mut suggestable_variants = variants
+ let suggestable_variants = variants
.iter()
.filter(|(.., kind)| *kind == CtorKind::Fn)
.map(|(variant, ..)| path_names_to_string(variant))
err.span_suggestions(
span,
&msg,
- suggestable_variants.drain(..),
+ suggestable_variants.into_iter(),
Applicability::MaybeIncorrect,
);
}
);
}
- let mut suggestable_variants_with_placeholders = variants
+ let suggestable_variants_with_placeholders = variants
.iter()
.filter(|(_, def_id, kind)| needs_placeholder(*def_id, *kind))
.map(|(variant, _, kind)| (path_names_to_string(variant), kind))
err.span_suggestions(
span,
msg,
- suggestable_variants_with_placeholders.drain(..),
+ suggestable_variants_with_placeholders.into_iter(),
Applicability::HasPlaceholders,
);
}
def_id: LocalDefId,
) -> Option<(LocalDefId, &'tcx FxHashSet<ItemLocalId>)> {
match tcx.def_kind(def_id) {
- DefKind::AnonConst => {
+ DefKind::AnonConst | DefKind::InlineConst => {
let mut def_id = tcx
.parent(def_id.to_def_id())
.unwrap_or_else(|| bug!("anon const or closure without a parent"));
let (lifetimes, binders): (FxIndexMap<hir::ParamName, Region>, Vec<_>) = c
.generic_params
.iter()
- .filter_map(|param| match param.kind {
- GenericParamKind::Lifetime { .. } => Some(param),
- _ => None,
- })
+ .filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. }))
.enumerate()
.map(|(late_bound_idx, param)| {
let pair = Region::late(late_bound_idx as u32, &self.tcx.hir(), param);
let (lifetimes, binders): (FxIndexMap<hir::ParamName, Region>, Vec<_>) =
bound_generic_params
.iter()
- .filter_map(|param| match param.kind {
- GenericParamKind::Lifetime { .. } => Some(param),
- _ => None,
+ .filter(|param| {
+ matches!(param.kind, GenericParamKind::Lifetime { .. })
})
.enumerate()
.map(|(late_bound_idx, param)| {
let binders_iter = trait_ref
.bound_generic_params
.iter()
- .filter_map(|param| match param.kind {
- GenericParamKind::Lifetime { .. } => Some(param),
- _ => None,
- })
+ .filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. }))
.enumerate()
.map(|(late_bound_idx, param)| {
let pair = Region::late(
break;
}
}
- hir::TyKind::Path(ref qpath) => {
- if let QPath::Resolved(_, path) = qpath {
- let last_segment = &path.segments[path.segments.len() - 1];
- let generics = last_segment.args();
- for arg in generics.args.iter() {
- if let GenericArg::Lifetime(lt) = arg {
- if lt.name.ident() == name {
- elide_use = Some(lt.span);
- break;
- }
+ hir::TyKind::Path(QPath::Resolved(_, path)) => {
+ let last_segment = &path.segments[path.segments.len() - 1];
+ let generics = last_segment.args();
+ for arg in generics.args.iter() {
+ if let GenericArg::Lifetime(lt) = arg {
+ if lt.name.ident() == name {
+ elide_use = Some(lt.span);
+ break;
}
}
- break;
}
+ break;
}
_ => {}
}
let binders: Vec<_> = generics
.params
.iter()
- .filter_map(|param| match param.kind {
- GenericParamKind::Lifetime { .. }
- if self.map.late_bound.contains(¶m.hir_id) =>
- {
- Some(param)
- }
- _ => None,
+ .filter(|param| {
+ matches!(param.kind, GenericParamKind::Lifetime { .. })
+ && self.map.late_bound.contains(¶m.hir_id)
})
.enumerate()
.map(|(late_bound_idx, param)| {
let pair = Region::late(late_bound_idx as u32, &self.tcx.hir(), param);
- let r = late_region_as_bound_region(self.tcx, &pair.1);
- r
+ late_region_as_bound_region(self.tcx, &pair.1)
})
.collect();
self.map.late_bound_vars.insert(hir_id, binders);
non_macro_attr: Lrc<SyntaxExtension>,
local_macro_def_scopes: FxHashMap<LocalDefId, Module<'a>>,
ast_transform_scopes: FxHashMap<LocalExpnId, Module<'a>>,
- unused_macros: FxHashMap<LocalDefId, (NodeId, Span)>,
+ unused_macros: FxHashMap<LocalDefId, (NodeId, Ident)>,
proc_macro_stubs: FxHashSet<LocalDefId>,
/// Traces collected during macro resolution and validated when it's complete.
single_segment_macro_resolutions:
}
fn check_unused_macros(&mut self) {
- for (_, &(node_id, span)) in self.unused_macros.iter() {
- self.lint_buffer.buffer_lint(UNUSED_MACROS, node_id, span, "unused macro definition");
+ for (_, &(node_id, ident)) in self.unused_macros.iter() {
+ self.lint_buffer.buffer_lint(
+ UNUSED_MACROS,
+ node_id,
+ ident.span,
+ &format!("unused macro definition: `{}`", ident.as_str()),
+ );
}
}
| HirDefKind::ForeignMod
| HirDefKind::LifetimeParam
| HirDefKind::AnonConst
+ | HirDefKind::InlineConst
| HirDefKind::Use
| HirDefKind::Field
| HirDefKind::GlobalAsm
pub out_directory: PathBuf,
filestem: String,
pub single_output_file: Option<PathBuf>,
+ pub temps_directory: Option<PathBuf>,
pub outputs: OutputTypes,
}
out_directory: PathBuf,
out_filestem: String,
single_output_file: Option<PathBuf>,
+ temps_directory: Option<PathBuf>,
extra: String,
outputs: OutputTypes,
) -> Self {
OutputFilenames {
out_directory,
single_output_file,
+ temps_directory,
outputs,
filestem: format!("{}{}", out_filestem, extra),
}
.get(&flavor)
.and_then(|p| p.to_owned())
.or_else(|| self.single_output_file.clone())
- .unwrap_or_else(|| self.temp_path(flavor, None))
+ .unwrap_or_else(|| self.output_path(flavor))
+ }
+
+ /// Gets the output path where a compilation artifact of the given type
+ /// should be placed on disk.
+ pub fn output_path(&self, flavor: OutputType) -> PathBuf {
+ let extension = flavor.extension();
+ self.with_directory_and_extension(&self.out_directory, &extension)
}
/// Gets the path where a compilation artifact of the given type for the
extension.push_str(ext);
}
- self.with_extension(&extension)
+ let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory);
+
+ self.with_directory_and_extension(&temps_directory, &extension)
}
pub fn with_extension(&self, extension: &str) -> PathBuf {
- let mut path = self.out_directory.join(&self.filestem);
+ self.with_directory_and_extension(&self.out_directory, extension)
+ }
+
+ fn with_directory_and_extension(&self, directory: &PathBuf, extension: &str) -> PathBuf {
+ let mut path = directory.join(&self.filestem);
path.set_extension(extension);
path
}
pub(super) fn build_target_config(
opts: &Options,
target_override: Option<Target>,
- sysroot: &PathBuf,
+ sysroot: &Path,
) -> Target {
let target_result = target_override.map_or_else(
|| Target::search(&opts.target_triple, sysroot),
match v {
Some(s) => {
if !slot.is_empty() {
- slot.push_str(",");
+ slot.push(',');
}
slot.push_str(s);
true
"which mangling version to use for symbol names ('legacy' (default) or 'v0')"),
teach: bool = (false, parse_bool, [TRACKED],
"show extended diagnostic help (default: no)"),
+ temps_dir: Option<String> = (None, parse_opt_string, [UNTRACKED],
+ "the directory the intermediate files are written to"),
terminal_width: Option<usize> = (None, parse_opt_number, [UNTRACKED],
"set the current terminal width"),
tune_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
self.diagnostic().abort_if_errors();
}
pub fn compile_status(&self) -> Result<(), ErrorReported> {
- if self.has_errors() {
+ if self.diagnostic().has_errors_or_lint_errors() {
self.diagnostic().emit_stashed_diagnostics();
Err(ErrorReported)
} else {
encoder.emit_enum(|encoder| match *self {
RealFileName::LocalPath(ref local_path) => {
encoder.emit_enum_variant("LocalPath", 0, 1, |encoder| {
- Ok({
- encoder
- .emit_enum_variant_arg(true, |encoder| local_path.encode(encoder))?;
- })
+ encoder.emit_enum_variant_arg(true, |encoder| local_path.encode(encoder))?;
+ Ok(())
})
}
// 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());
- Ok({
- encoder
- .emit_enum_variant_arg(true, |encoder| local_path.encode(encoder))?;
- encoder
- .emit_enum_variant_arg(false, |encoder| virtual_name.encode(encoder))?;
- })
+ encoder.emit_enum_variant_arg(true, |encoder| local_path.encode(encoder))?;
+ encoder.emit_enum_variant_arg(false, |encoder| virtual_name.encode(encoder))?;
+ Ok(())
}),
})
}
__S,
__next,
__try_var,
+ _args,
_d,
_e,
_task_context,
as_ptr,
as_str,
asm,
+ asm_const,
+ asm_experimental_arch,
+ asm_sym,
assert,
assert_inhabited,
assert_macro,
-use crate::spec::{LinkArgs, LinkerFlavor, PanicStrategy, RelocModel, Target, TargetOptions};
+use crate::spec::{LinkArgs, LinkerFlavor, RelocModel, Target, TargetOptions};
/// A base target for Nintendo 3DS devices using the devkitARM toolchain.
///
features: "+vfp2".to_string(),
pre_link_args,
exe_suffix: ".elf".to_string(),
- panic_strategy: PanicStrategy::Abort,
..Default::default()
},
}
/// JSON decoding.
pub fn search(
target_triple: &TargetTriple,
- sysroot: &PathBuf,
+ sysroot: &Path,
) -> Result<(Target, TargetWarnings), String> {
use rustc_serialize::json;
use std::env;
},
cause,
);
- if let Err(e) = fulfillcx.select_where_possible(&self.infcx) {
+ let errors = fulfillcx.select_where_possible(&self.infcx);
+ if !errors.is_empty() {
// This shouldn't happen, except for evaluate/fulfill mismatches,
// but that's not a reason for an ICE (`predicate_may_hold` is conservative
// by design).
- debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling", e);
+ debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling", errors);
return None;
}
let obligations = fulfillcx.pending_obligations();
// an additional sanity check.
let mut fulfill = FulfillmentContext::new();
fulfill.register_bound(&infcx, full_env, ty, trait_did, ObligationCause::dummy());
- fulfill.select_all_or_error(&infcx).unwrap_or_else(|e| {
- panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, e)
- });
+ let errors = fulfill.select_all_or_error(&infcx);
+
+ if !errors.is_empty() {
+ panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors);
+ }
let body_id_map: FxHashMap<_, _> = infcx
.inner
self.obligations.insert(obligation);
}
- fn select_all_or_error(
- &mut self,
- infcx: &InferCtxt<'_, 'tcx>,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
- self.select_where_possible(infcx)?;
-
- if self.obligations.is_empty() {
- Ok(())
- } else {
- let errors = self
- .obligations
- .iter()
- .map(|obligation| FulfillmentError {
- obligation: obligation.clone(),
- code: FulfillmentErrorCode::CodeAmbiguity,
- // FIXME - does Chalk have a notation of 'root obligation'?
- // This is just for diagnostics, so it's okay if this is wrong
- root_obligation: obligation.clone(),
- })
- .collect();
- Err(errors)
+ fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>> {
+ {
+ let errors = self.select_where_possible(infcx);
+
+ if !errors.is_empty() {
+ return errors;
+ }
}
+
+ // any remaining obligations are errors
+ self.obligations
+ .iter()
+ .map(|obligation| FulfillmentError {
+ obligation: obligation.clone(),
+ code: FulfillmentErrorCode::CodeAmbiguity,
+ // FIXME - does Chalk have a notation of 'root obligation'?
+ // This is just for diagnostics, so it's okay if this is wrong
+ root_obligation: obligation.clone(),
+ })
+ .collect()
}
fn select_where_possible(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+ ) -> Vec<FulfillmentError<'tcx>> {
assert!(!infcx.is_in_snapshot());
let mut errors = Vec::new();
}
}
- if errors.is_empty() { Ok(()) } else { Err(errors) }
+ errors
}
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
// In principle, we only need to do this so long as `result`
// contains unbound type parameters. It could be a slight
// optimization to stop iterating early.
- if let Err(errors) = fulfill_cx.select_all_or_error(infcx) {
+ let errors = fulfill_cx.select_all_or_error(infcx);
+ if !errors.is_empty() {
infcx.tcx.sess.delay_span_bug(
rustc_span::DUMMY_SP,
&format!("Encountered errors `{:?}` resolving bounds after type-checking", errors),
if concrete.is_ok() && uv.substs(infcx.tcx).definitely_has_param_types_or_consts(infcx.tcx) {
match infcx.tcx.def_kind(uv.def.did) {
- DefKind::AnonConst => {
+ DefKind::AnonConst | DefKind::InlineConst => {
let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def);
if mir_body.is_polymorphic {
// we want to look into them or treat them as opaque projections.
//
// Right now we do neither of that and simply always fail to unify them.
- DefKind::AnonConst => (),
+ DefKind::AnonConst | DefKind::InlineConst => (),
_ => return Ok(None),
}
}
}
if let ObligationCauseCode::CompareImplMethodObligation {
- item_name,
impl_item_def_id,
trait_item_def_id,
}
| ObligationCauseCode::CompareImplTypeObligation {
- item_name,
impl_item_def_id,
trait_item_def_id,
} = obligation.cause.code
{
self.report_extra_impl_obligation(
span,
- item_name,
impl_item_def_id,
trait_item_def_id,
&format!("`{}`", obligation.predicate),
let sized_trait = self.tcx.lang_items().sized_trait();
debug!("maybe_suggest_unsized_generics: generics.params={:?}", generics.params);
debug!("maybe_suggest_unsized_generics: generics.where_clause={:?}", generics.where_clause);
- let param = generics
- .params
- .iter()
- .filter(|param| param.span == span)
- .filter(|param| {
- // Check that none of the explicit trait bounds is `Sized`. Assume that an explicit
- // `Sized` bound is there intentionally and we don't need to suggest relaxing it.
- param
- .bounds
- .iter()
- .all(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) != sized_trait)
- })
- .next();
+ let param = generics.params.iter().filter(|param| param.span == span).find(|param| {
+ // Check that none of the explicit trait bounds is `Sized`. Assume that an explicit
+ // `Sized` bound is there intentionally and we don't need to suggest relaxing it.
+ param
+ .bounds
+ .iter()
+ .all(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) != sized_trait)
+ });
let param = match param {
Some(param) => param,
_ => return,
let span = self.tcx.def_span(generator_did);
let in_progress_typeck_results = self.in_progress_typeck_results.map(|t| t.borrow());
- let generator_did_root = self.tcx.closure_base_def_id(generator_did);
+ let generator_did_root = self.tcx.typeck_root_def_id(generator_did);
debug!(
"maybe_note_obligation_cause_for_async_await: generator_did={:?} \
generator_did_root={:?} in_progress_typeck_results.hir_owner={:?} span={:?}",
)
});
}
- ObligationCauseCode::CompareImplMethodObligation {
- item_name,
- trait_item_def_id,
- ..
- } => {
+ ObligationCauseCode::CompareImplMethodObligation { trait_item_def_id, .. } => {
+ let item_name = self.tcx.item_name(trait_item_def_id);
let msg = format!(
"the requirement `{}` appears on the impl method `{}` but not on the \
corresponding trait method",
}
err.span_note(assoc_span, &msg);
}
- ObligationCauseCode::CompareImplTypeObligation {
- item_name, trait_item_def_id, ..
- } => {
+ ObligationCauseCode::CompareImplTypeObligation { trait_item_def_id, .. } => {
+ let item_name = self.tcx.item_name(trait_item_def_id);
let msg = format!(
"the requirement `{}` appears on the associated impl type `{}` but not on the \
corresponding associated trait type",
}
/// Attempts to select obligations using `selcx`.
- fn select(
- &mut self,
- selcx: &mut SelectionContext<'a, 'tcx>,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+ fn select(&mut self, selcx: &mut SelectionContext<'a, 'tcx>) -> Vec<FulfillmentError<'tcx>> {
let span = debug_span!("select", obligation_forest_size = ?self.predicates.len());
let _enter = span.enter();
errors.len()
);
- if errors.is_empty() { Ok(()) } else { Err(errors) }
+ errors
}
}
.register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] });
}
- fn select_all_or_error(
- &mut self,
- infcx: &InferCtxt<'_, 'tcx>,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
- self.select_where_possible(infcx)?;
-
- let errors: Vec<_> = self
- .predicates
- .to_errors(CodeAmbiguity)
- .into_iter()
- .map(to_fulfillment_error)
- .collect();
- if errors.is_empty() { Ok(()) } else { Err(errors) }
+ fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>> {
+ {
+ let errors = self.select_where_possible(infcx);
+ if !errors.is_empty() {
+ return errors;
+ }
+ }
+
+ self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect()
}
fn select_all_with_constness_or_error(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
constness: rustc_hir::Constness,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
- self.select_with_constness_where_possible(infcx, constness)?;
-
- let errors: Vec<_> = self
- .predicates
- .to_errors(CodeAmbiguity)
- .into_iter()
- .map(to_fulfillment_error)
- .collect();
- if errors.is_empty() { Ok(()) } else { Err(errors) }
+ ) -> Vec<FulfillmentError<'tcx>> {
+ {
+ let errors = self.select_with_constness_where_possible(infcx, constness);
+ if !errors.is_empty() {
+ return errors;
+ }
+ }
+
+ self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect()
}
fn select_where_possible(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+ ) -> Vec<FulfillmentError<'tcx>> {
let mut selcx = SelectionContext::new(infcx);
self.select(&mut selcx)
}
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
constness: hir::Constness,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+ ) -> Vec<FulfillmentError<'tcx>> {
let mut selcx = SelectionContext::with_constness(infcx, constness);
self.select(&mut selcx)
}
| ty::Char
| ty::RawPtr(..)
| ty::Never
- | ty::Ref(_, _, hir::Mutability::Not) => return Ok(()),
+ | ty::Ref(_, _, hir::Mutability::Not)
+ | ty::Array(..) => return Ok(()),
ty::Adt(adt, substs) => (adt, substs),
// Note: we only assume something is `Copy` if we can
// *definitively* show that it implements `Copy`. Otherwise,
// assume it is move; linear is always ok.
- match fulfill_cx.select_all_or_error(infcx) {
- Ok(()) => {
+ match fulfill_cx.select_all_or_error(infcx).as_slice() {
+ [] => {
debug!(
"type_known_to_meet_bound_modulo_regions: ty={:?} bound={} success",
ty,
);
true
}
- Err(e) => {
+ errors => {
debug!(
- "type_known_to_meet_bound_modulo_regions: ty={:?} bound={} errors={:?}",
- ty,
- infcx.tcx.def_path_str(def_id),
- e
+ ?ty,
+ bound = %infcx.tcx.def_path_str(def_id),
+ ?errors,
+ "type_known_to_meet_bound_modulo_regions"
);
false
}
}
debug!("fully_normalize: select_all_or_error start");
- fulfill_cx.select_all_or_error(infcx)?;
+ let errors = fulfill_cx.select_all_or_error(infcx);
+ if !errors.is_empty() {
+ return Err(errors);
+ }
debug!("fully_normalize: select_all_or_error complete");
let resolved_value = infcx.resolve_vars_if_possible(normalized_value);
debug!("fully_normalize: resolved_value={:?}", resolved_value);
fulfill_cx.register_predicate_obligation(&infcx, obligation);
}
- fulfill_cx.select_all_or_error(&infcx).is_err()
+ let errors = fulfill_cx.select_all_or_error(&infcx);
+
+ !errors.is_empty()
});
debug!("impossible_predicates = {:?}", result);
result
let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?;
debug_assert!(obligations.iter().all(|o| o.cause.body_id == dummy_body_id));
fulfill_cx.register_predicate_obligations(infcx, obligations);
- if let Err(e) = fulfill_cx.select_all_or_error(infcx) {
+ let errors = fulfill_cx.select_all_or_error(infcx);
+ if !errors.is_empty() {
infcx.tcx.sess.diagnostic().delay_span_bug(
DUMMY_SP,
- &format!("errors selecting obligation during MIR typeck: {:?}", e),
+ &format!("errors selecting obligation during MIR typeck: {:?}", errors),
);
}
/// Returns `true` if the trait predicate is considerd `const` to this selection context.
pub fn is_trait_predicate_const(&self, pred: ty::TraitPredicate<'_>) -> bool {
- match pred.constness {
- ty::BoundConstness::ConstIfConst if self.is_in_const_context => true,
- _ => false,
- }
+ matches!(pred.constness, ty::BoundConstness::ConstIfConst) && self.is_in_const_context
}
/// Returns `true` if the predicate is considered `const` to
| ty::Char
| ty::RawPtr(..)
| ty::Never
- | ty::Ref(_, _, hir::Mutability::Not) => {
+ | ty::Ref(_, _, hir::Mutability::Not)
+ | ty::Array(..) => {
// Implementations provided in libcore
None
}
| ty::Foreign(..)
| ty::Ref(_, _, hir::Mutability::Mut) => None,
- ty::Array(element_ty, _) => {
- // (*) binder moved here
- Where(obligation.predicate.rebind(vec![element_ty]))
- }
-
ty::Tuple(tys) => {
// (*) binder moved here
Where(obligation.predicate.rebind(tys.iter().map(|k| k.expect_ty()).collect()))
for oblig in obligations.chain(more_obligations) {
fulfill_cx.register_predicate_obligation(&infcx, oblig);
}
- match fulfill_cx.select_all_or_error(infcx) {
- Err(errors) => {
+ match fulfill_cx.select_all_or_error(infcx).as_slice() {
+ [] => {
+ debug!(
+ "fulfill_implication: an impl for {:?} specializes {:?}",
+ source_trait_ref, target_trait_ref
+ );
+
+ // Now resolve the *substitution* we built for the target earlier, replacing
+ // the inference variables inside with whatever we got from fulfillment.
+ Ok(infcx.resolve_vars_if_possible(target_substs))
+ }
+ errors => {
// no dice!
debug!(
"fulfill_implication: for impls on {:?} and {:?}, \
);
Err(())
}
-
- Ok(()) => {
- debug!(
- "fulfill_implication: an impl for {:?} specializes {:?}",
- source_trait_ref, target_trait_ref
- );
-
- // Now resolve the *substitution* we built for the target earlier, replacing
- // the inference variables inside with whatever we got from fulfillment.
- Ok(infcx.resolve_vars_if_possible(target_substs))
- }
}
})
}
sg
}
+// This function is only used when
+// encountering errors and inlining
+// it negatively impacts perf.
+#[cold]
+#[inline(never)]
fn report_overlap_conflict(
tcx: TyCtxt<'_>,
overlap: OverlapError,
match used_to_be_allowed {
None => {
sg.has_errored = true;
- let err = struct_span_err!(tcx.sess, impl_span, E0119, "");
- decorate(LintDiagnosticBuilder::new(err));
+ if overlap.with_impl.is_local() || !tcx.orphan_check_crate(()).contains(&impl_def_id) {
+ let err = struct_span_err!(tcx.sess, impl_span, E0119, "");
+ decorate(LintDiagnosticBuilder::new(err));
+ } else {
+ tcx.sess.delay_span_bug(impl_span, "impl should have failed the orphan check");
+ }
}
Some(kind) => {
let lint = match kind {
//
// 2. We are sometimes doing future-incompatibility lints for
// now, so we do not want unconditional errors here.
- fulfillment_cx.select_all_or_error(infcx).is_ok()
+ fulfillment_cx.select_all_or_error(infcx).is_empty()
}
/// This implements the traversal over the structure of a given type to try to
// Ensure that those obligations that we had to solve
// get solved *here*.
- match fulfill_cx.select_all_or_error(infcx) {
- Ok(()) => Ok(implied_bounds),
- Err(_) => Err(NoSolution),
+ match fulfill_cx.select_all_or_error(infcx).as_slice() {
+ [] => Ok(implied_bounds),
+ _ => Err(NoSolution),
}
}
let is_copy = self_ty.is_copy_modulo_regions(tcx.at(DUMMY_SP), param_env);
match self_ty.kind() {
_ if is_copy => (),
- ty::Array(..) | ty::Closure(..) | ty::Tuple(..) => {}
+ ty::Closure(..) | ty::Tuple(..) => {}
_ => return Ok(None),
};
err.span_label(span, "explicit generic argument not allowed");
}
+ err.note(
+ "see issue #83701 <https://github.com/rust-lang/rust/issues/83701> \
+ for more information",
+ );
+ if tcx.sess.is_nightly_build() {
+ err.help(
+ "add `#![feature(explicit_generic_args_with_impl_trait)]` \
+ to the crate attributes to enable",
+ );
+ }
+
err.emit();
}
// Very crude check to see whether the expression must be wrapped
// in parentheses for the suggestion to work (issue #89497).
// Can/should be extended in the future.
- let needs_parens = !has_parens
- && match self.expr.kind {
- hir::ExprKind::Cast(..) => true,
- _ => false,
- };
+ let needs_parens =
+ !has_parens && matches!(self.expr.kind, hir::ExprKind::Cast(..));
let mut suggestion = vec![(self.expr.span.shrink_to_lo(), sugg)];
if needs_parens {
// Check that all obligations are satisfied by the implementation's
// version.
- if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
- infcx.report_fulfillment_errors(errors, None, false);
+ let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx);
+ if !errors.is_empty() {
+ infcx.report_fulfillment_errors(&errors, None, false);
}
// Finally, resolve all regions. This catches wily misuses of
let parent_substs = InternalSubsts::identity_for_item(
self.tcx,
- self.tcx.closure_base_def_id(expr_def_id.to_def_id()),
+ self.tcx.typeck_root_def_id(expr_def_id.to_def_id()),
);
let tupled_upvars_ty = self.infcx.next_ty_var(TypeVariableOrigin {
};
let mut fcx = traits::FulfillmentContext::new_in_snapshot();
fcx.register_predicate_obligations(self, ok.obligations);
- fcx.select_where_possible(&self).is_ok()
+ fcx.select_where_possible(&self).is_empty()
})
}
impl_m_span,
impl_m_hir_id,
ObligationCauseCode::CompareImplMethodObligation {
- item_name: impl_m.ident.name,
impl_item_def_id: impl_m.def_id,
trait_item_def_id: trait_m.def_id,
},
// Check that all obligations are satisfied by the implementation's
// version.
- if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
- infcx.report_fulfillment_errors(errors, None, false);
+ let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx);
+ if !errors.is_empty() {
+ infcx.report_fulfillment_errors(&errors, None, false);
return Err(ErrorReported);
}
Ok(())
}
+#[instrument(level = "debug", skip(infcx))]
fn extract_spans_for_error_reporting<'a, 'tcx>(
infcx: &infer::InferCtxt<'a, 'tcx>,
terr: &TypeError<'_>,
// Check that all obligations are satisfied by the implementation's
// version.
- if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
- infcx.report_fulfillment_errors(errors, None, false);
+ let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx);
+ if !errors.is_empty() {
+ infcx.report_fulfillment_errors(&errors, None, false);
return;
}
impl_ty_span,
impl_ty_hir_id,
ObligationCauseCode::CompareImplTypeObligation {
- item_name: impl_ty.ident.name,
impl_item_def_id: impl_ty.def_id,
trait_item_def_id: trait_ty.def_id,
},
// Check that all obligations are satisfied by the implementation's
// version.
- if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
- infcx.report_fulfillment_errors(errors, None, false);
+ let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx);
+ if !errors.is_empty() {
+ infcx.report_fulfillment_errors(&errors, None, false);
return Err(ErrorReported);
}
// Check that all obligations are satisfied by the implementation's
// version.
- if let Err(ref errors) =
- inh.fulfillment_cx.borrow_mut().select_all_with_constness_or_error(&infcx, constness)
- {
- infcx.report_fulfillment_errors(errors, None, false);
+ let errors =
+ inh.fulfillment_cx.borrow_mut().select_all_with_constness_or_error(&infcx, constness);
+ if !errors.is_empty() {
+ infcx.report_fulfillment_errors(&errors, None, false);
return Err(ErrorReported);
}
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
) {
self.annotate_expected_due_to_let_ty(err, expr);
+ self.suggest_box_deref(err, expr, expected, expr_ty);
self.suggest_compatible_variants(err, expr, expected, expr_ty);
self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr);
if self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) {
}
}
+ fn suggest_box_deref(
+ &self,
+ err: &mut DiagnosticBuilder<'_>,
+ expr: &hir::Expr<'_>,
+ expected: Ty<'tcx>,
+ expr_ty: Ty<'tcx>,
+ ) {
+ if expr_ty.is_box() && expr_ty.boxed_ty() == expected {
+ err.span_suggestion_verbose(
+ expr.span.shrink_to_lo(),
+ "try dereferencing the `Box`",
+ "*".to_string(),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+
/// If the expected type is an enum (Issue #55250) with any variants whose
/// sole field is of the found type, suggest such variants. (Issue #42764)
fn suggest_compatible_variants(
(&ty::Str, &ty::Array(arr, _) | &ty::Slice(arr)) if arr == self.tcx.types.u8 => {
if let hir::ExprKind::Lit(_) = expr.kind {
if let Ok(src) = sm.span_to_snippet(sp) {
- if let Some(_) = replace_prefix(&src, "b\"", "\"") {
+ if replace_prefix(&src, "b\"", "\"").is_some() {
let pos = sp.lo() + BytePos(1);
return Some((
sp.with_hi(pos),
(&ty::Array(arr, _) | &ty::Slice(arr), &ty::Str) if arr == self.tcx.types.u8 => {
if let hir::ExprKind::Lit(_) = expr.kind {
if let Ok(src) = sm.span_to_snippet(sp) {
- if let Some(_) = replace_prefix(&src, "\"", "b\"") {
+ if replace_prefix(&src, "\"", "b\"").is_some() {
return Some((
sp.shrink_to_lo(),
"consider adding a leading `b`",
}
}
- if let Err(ref errors) = fulfillment_cx.select_all_or_error(&infcx) {
+ let errors = fulfillment_cx.select_all_or_error(&infcx);
+ if !errors.is_empty() {
// this could be reached when we get lazy normalization
- infcx.report_fulfillment_errors(errors, None, false);
+ infcx.report_fulfillment_errors(&errors, None, false);
return Err(ErrorReported);
}
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::Visitor;
use rustc_hir::{ExprKind, QPath};
use rustc_infer::infer;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_middle::ty;
+use rustc_infer::infer::InferOk;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
+use rustc_middle::ty::error::TypeError::{FieldMisMatch, Sorts};
+use rustc_middle::ty::relate::expected_found_bool;
use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::Ty;
-use rustc_middle::ty::TypeFoldable;
-use rustc_middle::ty::{AdtKind, Visibility};
+use rustc_middle::ty::{self, AdtKind, Ty, TypeFoldable};
+use rustc_session::parse::feature_err;
use rustc_span::edition::LATEST_STABLE_EDITION;
use rustc_span::hygiene::DesugaringKind;
use rustc_span::lev_distance::find_best_match_for_name;
}
ExprKind::DropTemps(e) => self.check_expr_with_expectation(e, expected),
ExprKind::Array(args) => self.check_expr_array(args, expected, expr),
- ExprKind::ConstBlock(ref anon_const) => self.to_const(anon_const).ty,
+ ExprKind::ConstBlock(ref anon_const) => {
+ self.check_expr_const_block(anon_const, expected, expr)
+ }
ExprKind::Repeat(element, ref count) => {
self.check_expr_repeat(element, count, expected, expr)
}
self.tcx.mk_array(element_ty, args.len() as u64)
}
+ fn check_expr_const_block(
+ &self,
+ anon_const: &'tcx hir::AnonConst,
+ expected: Expectation<'tcx>,
+ _expr: &'tcx hir::Expr<'tcx>,
+ ) -> Ty<'tcx> {
+ let body = self.tcx.hir().body(anon_const.body);
+
+ // Create a new function context.
+ let fcx = FnCtxt::new(self, self.param_env, body.value.hir_id);
+ crate::check::GatherLocalsVisitor::new(&fcx).visit_body(body);
+
+ let ty = fcx.check_expr_with_expectation(&body.value, expected);
+ fcx.require_type_is_sized(ty, body.value.span, traits::ConstSized);
+ fcx.write_ty(anon_const.hir_id, ty);
+ ty
+ }
+
fn check_expr_repeat(
&self,
element: &'tcx hir::Expr<'tcx>,
.emit_err(StructExprNonExhaustive { span: expr.span, what: adt.variant_descr() });
}
- let error_happened = self.check_expr_struct_fields(
+ self.check_expr_struct_fields(
adt_ty,
expected,
expr.hir_id,
qpath.span(),
variant,
fields,
- base_expr.is_none(),
+ base_expr,
expr.span,
);
- if let Some(base_expr) = base_expr {
- // If check_expr_struct_fields hit an error, do not attempt to populate
- // the fields with the base_expr. This could cause us to hit errors later
- // when certain fields are assumed to exist that in fact do not.
- if !error_happened {
- self.check_expr_has_type_or_error(base_expr, adt_ty, |_| {});
- match adt_ty.kind() {
- ty::Adt(adt, substs) if adt.is_struct() => {
- let fru_field_types = adt
- .non_enum_variant()
- .fields
- .iter()
- .map(|f| {
- self.normalize_associated_types_in(
- expr.span,
- f.ty(self.tcx, substs),
- )
- })
- .collect();
-
- self.typeck_results
- .borrow_mut()
- .fru_field_types_mut()
- .insert(expr.hir_id, fru_field_types);
- }
- _ => {
- self.tcx
- .sess
- .emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span });
- }
- }
- }
- }
+
self.require_type_is_sized(adt_ty, expr.span, traits::StructInitializerSized);
adt_ty
}
span: Span,
variant: &'tcx ty::VariantDef,
ast_fields: &'tcx [hir::ExprField<'tcx>],
- check_completeness: bool,
+ base_expr: &'tcx Option<&'tcx hir::Expr<'tcx>>,
expr_span: Span,
- ) -> bool {
+ ) {
let tcx = self.tcx;
let adt_ty_hint = self
)
.emit();
}
- } else if check_completeness && !error_happened && !remaining_fields.is_empty() {
+ }
+
+ // If check_expr_struct_fields hit an error, do not attempt to populate
+ // the fields with the base_expr. This could cause us to hit errors later
+ // when certain fields are assumed to exist that in fact do not.
+ if error_happened {
+ return;
+ }
+
+ if let Some(base_expr) = base_expr {
+ // FIXME: We are currently creating two branches here in order to maintain
+ // consistency. But they should be merged as much as possible.
+ let fru_tys = if self.tcx.features().type_changing_struct_update {
+ let base_ty = self.check_expr(base_expr);
+ match adt_ty.kind() {
+ ty::Adt(adt, substs) if adt.is_struct() => {
+ match base_ty.kind() {
+ ty::Adt(base_adt, base_subs) if adt == base_adt => {
+ variant
+ .fields
+ .iter()
+ .map(|f| {
+ let fru_ty = self.normalize_associated_types_in(
+ expr_span,
+ self.field_ty(base_expr.span, f, base_subs),
+ );
+ let ident = self.tcx.adjust_ident(f.ident, variant.def_id);
+ if let Some(_) = remaining_fields.remove(&ident) {
+ let target_ty =
+ self.field_ty(base_expr.span, f, substs);
+ let cause = self.misc(base_expr.span);
+ match self
+ .at(&cause, self.param_env)
+ .sup(target_ty, fru_ty)
+ {
+ Ok(InferOk { obligations, value: () }) => {
+ self.register_predicates(obligations)
+ }
+ // FIXME: Need better diagnostics for `FieldMisMatch` error
+ Err(_) => self
+ .report_mismatched_types(
+ &cause,
+ target_ty,
+ fru_ty,
+ FieldMisMatch(
+ variant.ident.name,
+ ident.name,
+ ),
+ )
+ .emit(),
+ }
+ }
+ fru_ty
+ })
+ .collect()
+ }
+ _ => {
+ return self
+ .report_mismatched_types(
+ &self.misc(base_expr.span),
+ adt_ty,
+ base_ty,
+ Sorts(expected_found_bool(true, adt_ty, base_ty)),
+ )
+ .emit();
+ }
+ }
+ }
+ _ => {
+ return self
+ .tcx
+ .sess
+ .emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span });
+ }
+ }
+ } else {
+ self.check_expr_has_type_or_error(base_expr, adt_ty, |_| {
+ let base_ty = self.check_expr(base_expr);
+ let same_adt = match (adt_ty.kind(), base_ty.kind()) {
+ (ty::Adt(adt, _), ty::Adt(base_adt, _)) if adt == base_adt => true,
+ _ => false,
+ };
+ if self.tcx.sess.is_nightly_build() && same_adt {
+ feature_err(
+ &self.tcx.sess.parse_sess,
+ sym::type_changing_struct_update,
+ base_expr.span,
+ "type changing struct updating is experimental",
+ )
+ .emit();
+ }
+ });
+ match adt_ty.kind() {
+ ty::Adt(adt, substs) if adt.is_struct() => variant
+ .fields
+ .iter()
+ .map(|f| {
+ self.normalize_associated_types_in(expr_span, f.ty(self.tcx, substs))
+ })
+ .collect(),
+ _ => {
+ return self
+ .tcx
+ .sess
+ .emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span });
+ }
+ }
+ };
+ self.typeck_results.borrow_mut().fru_field_types_mut().insert(expr_id, fru_tys);
+ } else if kind_name != "union" && !remaining_fields.is_empty() {
let inaccessible_remaining_fields = remaining_fields.iter().any(|(_, (_, field))| {
!field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx)
});
self.report_missing_fields(adt_ty, span, remaining_fields);
}
}
-
- error_happened
}
fn check_struct_fields_on_error(
.filter_map(|field| {
// ignore already set fields and private fields from non-local crates
if skip.iter().any(|&x| x == field.ident.name)
- || (!variant.def_id.is_local() && field.vis != Visibility::Public)
+ || (!variant.def_id.is_local() && !field.vis.is_public())
{
None
} else {
// Save the index of all fields regardless of their visibility in case
// of error recovery.
self.write_field_index(expr.hir_id, index);
+ let adjustments = self.adjust_steps(&autoderef);
if field.vis.is_accessible_from(def_scope, self.tcx) {
- let adjustments = self.adjust_steps(&autoderef);
self.apply_adjustments(base, adjustments);
self.register_predicates(autoderef.into_obligations());
self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None);
return field_ty;
}
- private_candidate = Some((base_def.did, field_ty));
+ private_candidate = Some((adjustments, base_def.did, field_ty));
}
}
ty::Tuple(tys) => {
}
self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
- if let Some((did, field_ty)) = private_candidate {
+ if let Some((adjustments, did, field_ty)) = private_candidate {
+ // (#90483) apply adjustments to avoid ExprUseVisitor from
+ // creating erroneous projection.
+ self.apply_adjustments(base, adjustments);
self.ban_private_field_access(expr, expr_t, field, did);
return field_ty;
}
) -> Option<(&Vec<ty::FieldDef>, SubstsRef<'tcx>)> {
debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_t);
- let mut autoderef = self.autoderef(span, base_t);
- while let Some((base_t, _)) = autoderef.next() {
+ for (base_t, _) in self.autoderef(span, base_t) {
match base_t.kind() {
ty::Adt(base_def, substs) if !base_def.is_enum() => {
let fields = &base_def.non_enum_variant().fields;
.type_var_origin(ty)
.map(|origin| origin.span)
.unwrap_or(rustc_span::DUMMY_SP);
- let oty = self.inner.borrow().opaque_types_vars.get(ty).map(|v| *v);
+ let oty = self.inner.borrow().opaque_types_vars.get(ty).copied();
if let Some(opaque_ty) = oty {
debug!(
"fallback_opaque_type_vars(ty={:?}): falling back to opaque type {:?}",
#[instrument(skip(self), level = "debug")]
pub(in super::super) fn select_all_obligations_or_error(&self) {
- if let Err(errors) = self
+ let errors = self
.fulfillment_cx
.borrow_mut()
- .select_all_with_constness_or_error(&self, self.inh.constness)
- {
+ .select_all_with_constness_or_error(&self, self.inh.constness);
+
+ if !errors.is_empty() {
self.report_fulfillment_errors(&errors, self.inh.body_id, false);
}
}
fallback_has_occurred: bool,
mutate_fulfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>),
) {
- let result = self
+ let mut result = self
.fulfillment_cx
.borrow_mut()
.select_with_constness_where_possible(self, self.inh.constness);
- if let Err(mut errors) = result {
- mutate_fulfillment_errors(&mut errors);
- self.report_fulfillment_errors(&errors, self.inh.body_id, fallback_has_occurred);
+ if !result.is_empty() {
+ mutate_fulfillment_errors(&mut result);
+ self.report_fulfillment_errors(&result, self.inh.body_id, fallback_has_occurred);
}
}
// we can. We don't care if some things turn
// out unconstrained or ambiguous, as we're
// just trying to get hints here.
- self.save_and_restore_in_snapshot_flag(|_| {
+ let errors = self.save_and_restore_in_snapshot_flag(|_| {
let mut fulfill = <dyn TraitEngine<'_>>::new(self.tcx);
for obligation in ok.obligations {
fulfill.register_predicate_obligation(self, obligation);
}
fulfill.select_where_possible(self)
- })
- .map_err(|_| ())?;
+ });
+
+ if !errors.is_empty() {
+ return Err(());
+ }
}
Err(_) => return Err(()),
}
call_expr: &'tcx hir::Expr<'tcx>,
) {
if let hir::ExprKind::Call(path, _) = &call_expr.kind {
- if let hir::ExprKind::Path(qpath) = &path.kind {
- if let hir::QPath::Resolved(_, path) = &qpath {
- for error in errors {
- if let ty::PredicateKind::Trait(predicate) =
- error.obligation.predicate.kind().skip_binder()
+ if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = &path.kind {
+ for error in errors {
+ if let ty::PredicateKind::Trait(predicate) =
+ error.obligation.predicate.kind().skip_binder()
+ {
+ // If any of the type arguments in this path segment caused the
+ // `FulfillmentError`, point at its span (#61860).
+ for arg in path
+ .segments
+ .iter()
+ .filter_map(|seg| seg.args.as_ref())
+ .flat_map(|a| a.args.iter())
{
- // If any of the type arguments in this path segment caused the
- // `FulfillmentError`, point at its span (#61860).
- for arg in path
- .segments
- .iter()
- .filter_map(|seg| seg.args.as_ref())
- .flat_map(|a| a.args.iter())
- {
- if let hir::GenericArg::Type(hir_ty) = &arg {
- if let hir::TyKind::Path(hir::QPath::TypeRelative(..)) =
- &hir_ty.kind
- {
- // Avoid ICE with associated types. As this is best
- // effort only, it's ok to ignore the case. It
- // would trigger in `is_send::<T::AssocType>();`
- // from `typeck-default-trait-impl-assoc-type.rs`.
- } else {
- let ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, hir_ty);
- let ty = self.resolve_vars_if_possible(ty);
- if ty == predicate.self_ty() {
- error.obligation.cause.make_mut().span = hir_ty.span;
- }
+ if let hir::GenericArg::Type(hir_ty) = &arg {
+ if let hir::TyKind::Path(hir::QPath::TypeRelative(..)) =
+ &hir_ty.kind
+ {
+ // Avoid ICE with associated types. As this is best
+ // effort only, it's ok to ignore the case. It
+ // would trigger in `is_send::<T::AssocType>();`
+ // from `typeck-default-trait-impl-assoc-type.rs`.
+ } else {
+ let ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, hir_ty);
+ let ty = self.resolve_vars_if_possible(ty);
+ if ty == predicate.self_ty() {
+ error.obligation.cause.make_mut().span = hir_ty.span;
}
}
}
let edition_fix = candidates
.iter()
.find(|did| self.tcx.is_diagnostic_item(sym::TryInto, **did))
- .map(|&d| d);
+ .copied();
err.help("items from traits can only be used if the trait is in scope");
let msg = format!(
}
}
// We only want to suggest public or local traits (#45781).
- item.vis == ty::Visibility::Public || info.def_id.is_local()
+ item.vis.is_public() || info.def_id.is_local()
})
.is_some()
})
fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
// Closures' typeck results come from their outermost function,
// as they are part of the same "inference environment".
- let outer_def_id = tcx.closure_base_def_id(def_id);
- if outer_def_id != def_id {
- return tcx.has_typeck_results(outer_def_id);
+ let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
+ if typeck_root_def_id != def_id {
+ return tcx.has_typeck_results(typeck_root_def_id);
}
if let Some(def_id) = def_id.as_local() {
) -> &'tcx ty::TypeckResults<'tcx> {
// Closures' typeck results come from their outermost function,
// as they are part of the same "inference environment".
- let outer_def_id = tcx.closure_base_def_id(def_id.to_def_id()).expect_local();
- if outer_def_id != def_id {
- return tcx.typeck(outer_def_id);
+ let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
+ if typeck_root_def_id != def_id {
+ return tcx.typeck(typeck_root_def_id);
}
let id = tcx.hir().local_def_id_to_hir_id(def_id);
}
};
if let Ref(_, rty, _) = lhs_ty.kind() {
- if {
- self.infcx.type_is_copy_modulo_regions(self.param_env, rty, lhs_expr.span)
- && self
- .lookup_op_method(rty, &[rhs_ty], Op::Binary(op, is_assign))
- .is_ok()
- } {
+ if self.infcx.type_is_copy_modulo_regions(self.param_env, rty, lhs_expr.span)
+ && self.lookup_op_method(rty, &[rhs_ty], Op::Binary(op, is_assign)).is_ok()
+ {
if let Ok(lstring) = source_map.span_to_snippet(lhs_expr.span) {
let msg = &format!(
"`{}{}` can be used on `{}`, you can dereference `{}`",
self.obligation_for_method(span, trait_did, lhs_ty, Some(other_tys));
let mut fulfill = <dyn TraitEngine<'_>>::new(self.tcx);
fulfill.register_predicate_obligation(self, obligation);
- Err(match fulfill.select_where_possible(&self.infcx) {
- Err(errors) => errors,
- _ => vec![],
- })
+ Err(fulfill.select_where_possible(&self.infcx))
}
}
}
// String and byte-string literals result in types `&str` and `&[u8]` respectively.
// All other literals result in non-reference types.
// As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo {}`.
- PatKind::Lit(lt) => match self.check_expr(lt).kind() {
+ //
+ // Call `resolve_vars_if_possible` here for inline const blocks.
+ PatKind::Lit(lt) => match self.resolve_vars_if_possible(self.check_expr(lt)).kind() {
ty::Ref(..) => AdjustMode::Pass,
_ => AdjustMode::Peel,
},
self.visit_region_obligations(body_id.hir_id);
}
+ fn visit_inline_const(&mut self, id: hir::HirId, body: &'tcx hir::Body<'tcx>) {
+ debug!("visit_inline_const(id={:?})", id);
+
+ // Save state of current function. We will restore afterwards.
+ let old_body_id = self.body_id;
+ let old_body_owner = self.body_owner;
+ let env_snapshot = self.outlives_environment.push_snapshot_pre_typeck_child();
+
+ let body_id = body.id();
+ self.body_id = body_id.hir_id;
+ self.body_owner = self.tcx.hir().body_owner_def_id(body_id);
+
+ self.outlives_environment.save_implied_bounds(body_id.hir_id);
+
+ self.visit_body(body);
+ self.visit_region_obligations(body_id.hir_id);
+
+ // Restore state from previous function.
+ self.outlives_environment.pop_snapshot_post_typeck_child(env_snapshot);
+ self.body_id = old_body_id;
+ self.body_owner = old_body_owner;
+ }
+
fn visit_region_obligations(&mut self, hir_id: hir::HirId) {
debug!("visit_region_obligations: hir_id={:?}", hir_id);
// `visit_fn_body`. We will restore afterwards.
let old_body_id = self.body_id;
let old_body_owner = self.body_owner;
- let env_snapshot = self.outlives_environment.push_snapshot_pre_closure();
+ let env_snapshot = self.outlives_environment.push_snapshot_pre_typeck_child();
let body = self.tcx.hir().body(body_id);
self.visit_fn_body(hir_id, body, span);
// Restore state from previous function.
- self.outlives_environment.pop_snapshot_post_closure(env_snapshot);
+ self.outlives_environment.pop_snapshot_post_typeck_child(env_snapshot);
self.body_id = old_body_id;
self.body_owner = old_body_owner;
}
intravisit::walk_expr(self, expr);
}
+ hir::ExprKind::ConstBlock(anon_const) => {
+ let body = self.tcx.hir().body(anon_const.body);
+ self.visit_inline_const(anon_const.hir_id, body);
+ }
+
_ => intravisit::walk_expr(self, expr),
}
}
}
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
- if let hir::ExprKind::Closure(cc, _, body_id, _, _) = expr.kind {
- let body = self.fcx.tcx.hir().body(body_id);
- self.visit_body(body);
- self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, cc);
+ match expr.kind {
+ hir::ExprKind::Closure(cc, _, body_id, _, _) => {
+ let body = self.fcx.tcx.hir().body(body_id);
+ self.visit_body(body);
+ self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, cc);
+ }
+ hir::ExprKind::ConstBlock(anon_const) => {
+ let body = self.fcx.tcx.hir().body(anon_const.body);
+ self.visit_body(body);
+ }
+ _ => {}
}
intravisit::walk_expr(self, expr);
let written_predicates: ty::GenericPredicates<'_> =
tcx.explicit_predicates_of(trait_item.def_id);
let mut clauses: Vec<_> = clauses
- .drain_filter(|clause| {
- written_predicates.predicates.iter().find(|p| &p.0 == clause).is_none()
- })
+ .drain_filter(|clause| !written_predicates.predicates.iter().any(|p| &p.0 == clause))
.map(|clause| format!("{}", clause))
.collect();
// We sort so that order is predictable
hir::ExprKind::Field(..) => {
self.visit_field_id(e.hir_id);
}
+ hir::ExprKind::ConstBlock(anon_const) => {
+ self.visit_node_id(e.span, anon_const.hir_id);
+
+ let body = self.tcx().hir().body(anon_const.body);
+ self.visit_body(body);
+ }
_ => {}
}
let coerced_fields = fields
.iter()
- .filter_map(|field| {
+ .filter(|field| {
let ty_a = field.ty(tcx, substs_a);
let ty_b = field.ty(tcx, substs_b);
if let Ok(layout) = tcx.layout_of(param_env.and(ty_a)) {
if layout.is_zst() && layout.align.abi.bytes() == 1 {
// ignore ZST fields with alignment of 1 byte
- return None;
+ return false;
}
}
))
.emit();
- return None;
+ return false;
}
}
- Some(field)
+ return true;
})
.collect::<Vec<_>>();
}
// Check that all transitive obligations are satisfied.
- if let Err(errors) = fulfill_cx.select_all_or_error(&infcx) {
+ let errors = fulfill_cx.select_all_or_error(&infcx);
+ if !errors.is_empty() {
infcx.report_fulfillment_errors(&errors, None, false);
}
fulfill_cx.register_predicate_obligation(&infcx, predicate);
// Check that all transitive obligations are satisfied.
- if let Err(errors) = fulfill_cx.select_all_or_error(&infcx) {
+ let errors = fulfill_cx.select_all_or_error(&infcx);
+ if !errors.is_empty() {
infcx.report_fulfillment_errors(&errors, None, false);
}
use self::builtin::coerce_unsized_info;
use self::inherent_impls::{crate_inherent_impls, inherent_impls};
use self::inherent_impls_overlap::crate_inherent_impls_overlap_check;
+ use self::orphan::orphan_check_crate;
*providers = Providers {
coherent_trait,
inherent_impls,
crate_inherent_impls_overlap_check,
coerce_unsized_info,
+ orphan_check_crate,
..*providers
};
}
}
pub fn check_coherence(tcx: TyCtxt<'_>) {
+ tcx.sess.time("unsafety_checking", || unsafety::check(tcx));
+ tcx.ensure().orphan_check_crate(());
+
for &trait_def_id in tcx.all_local_trait_impls(()).keys() {
tcx.ensure().coherent_trait(trait_def_id);
}
- tcx.sess.time("unsafety_checking", || unsafety::check(tcx));
- tcx.sess.time("orphan_checking", || orphan::check(tcx));
-
// these queries are executed for side-effects (error reporting):
tcx.ensure().crate_inherent_impls(());
tcx.ensure().crate_inherent_impls_overlap_check(());
//! crate or pertains to a type defined in this crate.
use rustc_errors::struct_span_err;
+use rustc_errors::ErrorReported;
use rustc_hir as hir;
-use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::ty::{self, TyCtxt};
+use rustc_span::def_id::LocalDefId;
+use rustc_span::Span;
use rustc_trait_selection::traits;
-pub fn check(tcx: TyCtxt<'_>) {
- let mut orphan = OrphanChecker { tcx };
- tcx.hir().visit_all_item_likes(&mut orphan);
+pub(super) fn orphan_check_crate(tcx: TyCtxt<'_>, (): ()) -> &[LocalDefId] {
+ let mut errors = Vec::new();
+ for (_trait, impls_of_trait) in tcx.all_local_trait_impls(()) {
+ for &impl_of_trait in impls_of_trait {
+ match orphan_check_impl(tcx, impl_of_trait) {
+ Ok(()) => {}
+ Err(ErrorReported) => errors.push(impl_of_trait),
+ }
+ }
+ }
+ tcx.arena.alloc_slice(&errors)
}
-struct OrphanChecker<'tcx> {
- tcx: TyCtxt<'tcx>,
-}
+#[instrument(skip(tcx), level = "debug")]
+fn orphan_check_impl(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorReported> {
+ let trait_ref = tcx.impl_trait_ref(def_id).unwrap();
+ let trait_def_id = trait_ref.def_id;
-impl ItemLikeVisitor<'v> for OrphanChecker<'tcx> {
- /// Checks exactly one impl for orphan rules and other such
- /// restrictions. In this fn, it can happen that multiple errors
- /// apply to a specific impl, so just return after reporting one
- /// to prevent inundating the user with a bunch of similar error
- /// reports.
- fn visit_item(&mut self, item: &hir::Item<'_>) {
- // "Trait" impl
- if let hir::ItemKind::Impl(hir::Impl {
- generics, of_trait: Some(ref tr), self_ty, ..
- }) = &item.kind
- {
- debug!(
- "coherence2::orphan check: trait impl {}",
- self.tcx.hir().node_to_string(item.hir_id())
- );
- let trait_ref = self.tcx.impl_trait_ref(item.def_id).unwrap();
- let trait_def_id = trait_ref.def_id;
- let sm = self.tcx.sess.source_map();
- let sp = sm.guess_head_span(item.span);
- match traits::orphan_check(self.tcx, item.def_id.to_def_id()) {
- Ok(()) => {}
- Err(traits::OrphanCheckErr::NonLocalInputType(tys)) => {
- let mut err = struct_span_err!(
- self.tcx.sess,
- sp,
- E0117,
- "only traits defined in the current crate can be implemented for \
- arbitrary types"
- );
- err.span_label(sp, "impl doesn't use only types from inside the current crate");
- for (ty, is_target_ty) in &tys {
- let mut ty = *ty;
- self.tcx.infer_ctxt().enter(|infcx| {
- // Remove the lifetimes unnecessary for this error.
- ty = infcx.freshen(ty);
- });
- ty = match ty.kind() {
- // Remove the type arguments from the output, as they are not relevant.
- // You can think of this as the reverse of `resolve_vars_if_possible`.
- // That way if we had `Vec<MyType>`, we will properly attribute the
- // problem to `Vec<T>` and avoid confusing the user if they were to see
- // `MyType` in the error.
- ty::Adt(def, _) => self.tcx.mk_adt(def, ty::List::empty()),
- _ => ty,
- };
- let this = "this".to_string();
- let (ty, postfix) = match &ty.kind() {
- ty::Slice(_) => (this, " because slices are always foreign"),
- ty::Array(..) => (this, " because arrays are always foreign"),
- ty::Tuple(..) => (this, " because tuples are always foreign"),
- _ => (format!("`{}`", ty), ""),
- };
- let msg = format!("{} is not defined in the current crate{}", ty, postfix);
- if *is_target_ty {
- // Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
- err.span_label(self_ty.span, &msg);
- } else {
- // Point at `C<B>` in `impl<A, B> for C<B> in D<A>`
- err.span_label(tr.path.span, &msg);
- }
- }
- err.note("define and implement a trait or new type instead");
- err.emit();
- return;
- }
- Err(traits::OrphanCheckErr::UncoveredTy(param_ty, local_type)) => {
- let mut sp = sp;
- for param in generics.params {
- if param.name.ident().to_string() == param_ty.to_string() {
- sp = param.span;
- }
- }
+ let item = tcx.hir().item(hir::ItemId { def_id });
+ let impl_ = match item.kind {
+ hir::ItemKind::Impl(ref impl_) => impl_,
+ _ => bug!("{:?} is not an impl: {:?}", def_id, item),
+ };
+ let sp = tcx.sess.source_map().guess_head_span(item.span);
+ let tr = impl_.of_trait.as_ref().unwrap();
+ match traits::orphan_check(tcx, item.def_id.to_def_id()) {
+ Ok(()) => {}
+ Err(err) => emit_orphan_check_error(
+ tcx,
+ sp,
+ tr.path.span,
+ impl_.self_ty.span,
+ &impl_.generics,
+ err,
+ )?,
+ }
+
+ // In addition to the above rules, we restrict impls of auto traits
+ // so that they can only be implemented on nominal types, such as structs,
+ // enums or foreign types. To see why this restriction exists, consider the
+ // following example (#22978). Imagine that crate A defines an auto trait
+ // `Foo` and a fn that operates on pairs of types:
+ //
+ // ```
+ // // Crate A
+ // auto trait Foo { }
+ // fn two_foos<A:Foo,B:Foo>(..) {
+ // one_foo::<(A,B)>(..)
+ // }
+ // fn one_foo<T:Foo>(..) { .. }
+ // ```
+ //
+ // This type-checks fine; in particular the fn
+ // `two_foos` is able to conclude that `(A,B):Foo`
+ // because `A:Foo` and `B:Foo`.
+ //
+ // Now imagine that crate B comes along and does the following:
+ //
+ // ```
+ // struct A { }
+ // struct B { }
+ // impl Foo for A { }
+ // impl Foo for B { }
+ // impl !Send for (A, B) { }
+ // ```
+ //
+ // This final impl is legal according to the orphan
+ // rules, but it invalidates the reasoning from
+ // `two_foos` above.
+ debug!(
+ "trait_ref={:?} trait_def_id={:?} trait_is_auto={}",
+ trait_ref,
+ trait_def_id,
+ tcx.trait_is_auto(trait_def_id)
+ );
+
+ if tcx.trait_is_auto(trait_def_id) && !trait_def_id.is_local() {
+ let self_ty = trait_ref.self_ty();
+ let opt_self_def_id = match *self_ty.kind() {
+ ty::Adt(self_def, _) => Some(self_def.did),
+ ty::Foreign(did) => Some(did),
+ _ => None,
+ };
- match local_type {
- Some(local_type) => {
- struct_span_err!(
- self.tcx.sess,
- sp,
- E0210,
- "type parameter `{}` must be covered by another type \
- when it appears before the first local type (`{}`)",
- param_ty,
- local_type
- )
- .span_label(
- sp,
- format!(
- "type parameter `{}` must be covered by another type \
- when it appears before the first local type (`{}`)",
- param_ty, local_type
- ),
- )
- .note(
- "implementing a foreign trait is only possible if at \
- least one of the types for which it is implemented is local, \
- and no uncovered type parameters appear before that first \
- local type",
- )
- .note(
- "in this case, 'before' refers to the following order: \
- `impl<..> ForeignTrait<T1, ..., Tn> for T0`, \
- where `T0` is the first and `Tn` is the last",
- )
- .emit();
- }
- None => {
- struct_span_err!(
- self.tcx.sess,
- sp,
- E0210,
- "type parameter `{}` must be used as the type parameter for some \
- local type (e.g., `MyStruct<{}>`)",
- param_ty,
- param_ty
- ).span_label(sp, format!(
- "type parameter `{}` must be used as the type parameter for some \
- local type",
- param_ty,
- )).note("implementing a foreign trait is only possible if at \
- least one of the types for which it is implemented is local"
- ).note("only traits defined in the current crate can be \
- implemented for a type parameter"
- ).emit();
- }
- };
- return;
+ let msg = match opt_self_def_id {
+ // We only want to permit nominal types, but not *all* nominal types.
+ // They must be local to the current crate, so that people
+ // can't do `unsafe impl Send for Rc<SomethingLocal>` or
+ // `impl !Send for Box<SomethingLocalAndSend>`.
+ Some(self_def_id) => {
+ if self_def_id.is_local() {
+ None
+ } else {
+ Some((
+ format!(
+ "cross-crate traits with a default impl, like `{}`, \
+ can only be implemented for a struct/enum type \
+ defined in the current crate",
+ tcx.def_path_str(trait_def_id)
+ ),
+ "can't implement cross-crate trait for type in another crate",
+ ))
}
}
+ _ => Some((
+ format!(
+ "cross-crate traits with a default impl, like `{}`, can \
+ only be implemented for a struct/enum type, not `{}`",
+ tcx.def_path_str(trait_def_id),
+ self_ty
+ ),
+ "can't implement cross-crate trait with a default impl for \
+ non-struct/enum type",
+ )),
+ };
- // In addition to the above rules, we restrict impls of auto traits
- // so that they can only be implemented on nominal types, such as structs,
- // enums or foreign types. To see why this restriction exists, consider the
- // following example (#22978). Imagine that crate A defines an auto trait
- // `Foo` and a fn that operates on pairs of types:
- //
- // ```
- // // Crate A
- // auto trait Foo { }
- // fn two_foos<A:Foo,B:Foo>(..) {
- // one_foo::<(A,B)>(..)
- // }
- // fn one_foo<T:Foo>(..) { .. }
- // ```
- //
- // This type-checks fine; in particular the fn
- // `two_foos` is able to conclude that `(A,B):Foo`
- // because `A:Foo` and `B:Foo`.
- //
- // Now imagine that crate B comes along and does the following:
- //
- // ```
- // struct A { }
- // struct B { }
- // impl Foo for A { }
- // impl Foo for B { }
- // impl !Send for (A, B) { }
- // ```
- //
- // This final impl is legal according to the orphan
- // rules, but it invalidates the reasoning from
- // `two_foos` above.
- debug!(
- "trait_ref={:?} trait_def_id={:?} trait_is_auto={}",
- trait_ref,
- trait_def_id,
- self.tcx.trait_is_auto(trait_def_id)
+ if let Some((msg, label)) = msg {
+ struct_span_err!(tcx.sess, sp, E0321, "{}", msg).span_label(sp, label).emit();
+ return Err(ErrorReported);
+ }
+ }
+
+ if let ty::Opaque(def_id, _) = *trait_ref.self_ty().kind() {
+ tcx.sess
+ .struct_span_err(sp, "cannot implement trait on type alias impl trait")
+ .span_note(tcx.def_span(def_id), "type alias impl trait defined here")
+ .emit();
+ return Err(ErrorReported);
+ }
+
+ Ok(())
+}
+
+fn emit_orphan_check_error(
+ tcx: TyCtxt<'tcx>,
+ sp: Span,
+ trait_span: Span,
+ self_ty_span: Span,
+ generics: &hir::Generics<'tcx>,
+ err: traits::OrphanCheckErr<'tcx>,
+) -> Result<!, ErrorReported> {
+ match err {
+ traits::OrphanCheckErr::NonLocalInputType(tys) => {
+ let mut err = struct_span_err!(
+ tcx.sess,
+ sp,
+ E0117,
+ "only traits defined in the current crate can be implemented for \
+ arbitrary types"
);
- if self.tcx.trait_is_auto(trait_def_id) && !trait_def_id.is_local() {
- let self_ty = trait_ref.self_ty();
- let opt_self_def_id = match *self_ty.kind() {
- ty::Adt(self_def, _) => Some(self_def.did),
- ty::Foreign(did) => Some(did),
- _ => None,
+ err.span_label(sp, "impl doesn't use only types from inside the current crate");
+ for (ty, is_target_ty) in &tys {
+ let mut ty = *ty;
+ tcx.infer_ctxt().enter(|infcx| {
+ // Remove the lifetimes unnecessary for this error.
+ ty = infcx.freshen(ty);
+ });
+ ty = match ty.kind() {
+ // Remove the type arguments from the output, as they are not relevant.
+ // You can think of this as the reverse of `resolve_vars_if_possible`.
+ // That way if we had `Vec<MyType>`, we will properly attribute the
+ // problem to `Vec<T>` and avoid confusing the user if they were to see
+ // `MyType` in the error.
+ ty::Adt(def, _) => tcx.mk_adt(def, ty::List::empty()),
+ _ => ty,
};
-
- let msg = match opt_self_def_id {
- // We only want to permit nominal types, but not *all* nominal types.
- // They must be local to the current crate, so that people
- // can't do `unsafe impl Send for Rc<SomethingLocal>` or
- // `impl !Send for Box<SomethingLocalAndSend>`.
- Some(self_def_id) => {
- if self_def_id.is_local() {
- None
- } else {
- Some((
- format!(
- "cross-crate traits with a default impl, like `{}`, \
- can only be implemented for a struct/enum type \
- defined in the current crate",
- self.tcx.def_path_str(trait_def_id)
- ),
- "can't implement cross-crate trait for type in another crate",
- ))
- }
- }
- _ => Some((
- format!(
- "cross-crate traits with a default impl, like `{}`, can \
- only be implemented for a struct/enum type, not `{}`",
- self.tcx.def_path_str(trait_def_id),
- self_ty
- ),
- "can't implement cross-crate trait with a default impl for \
- non-struct/enum type",
- )),
+ let this = "this".to_string();
+ let (ty, postfix) = match &ty.kind() {
+ ty::Slice(_) => (this, " because slices are always foreign"),
+ ty::Array(..) => (this, " because arrays are always foreign"),
+ ty::Tuple(..) => (this, " because tuples are always foreign"),
+ _ => (format!("`{}`", ty), ""),
};
-
- if let Some((msg, label)) = msg {
- struct_span_err!(self.tcx.sess, sp, E0321, "{}", msg)
- .span_label(sp, label)
- .emit();
- return;
+ let msg = format!("{} is not defined in the current crate{}", ty, postfix);
+ if *is_target_ty {
+ // Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
+ err.span_label(self_ty_span, &msg);
+ } else {
+ // Point at `C<B>` in `impl<A, B> for C<B> in D<A>`
+ err.span_label(trait_span, &msg);
+ }
+ }
+ err.note("define and implement a trait or new type instead");
+ err.emit()
+ }
+ traits::OrphanCheckErr::UncoveredTy(param_ty, local_type) => {
+ let mut sp = sp;
+ for param in generics.params {
+ if param.name.ident().to_string() == param_ty.to_string() {
+ sp = param.span;
}
}
- if let ty::Opaque(def_id, _) = *trait_ref.self_ty().kind() {
- self.tcx
- .sess
- .struct_span_err(sp, "cannot implement trait on type alias impl trait")
- .span_note(self.tcx.def_span(def_id), "type alias impl trait defined here")
- .emit();
+ match local_type {
+ Some(local_type) => struct_span_err!(
+ tcx.sess,
+ sp,
+ E0210,
+ "type parameter `{}` must be covered by another type \
+ when it appears before the first local type (`{}`)",
+ param_ty,
+ local_type
+ )
+ .span_label(
+ sp,
+ format!(
+ "type parameter `{}` must be covered by another type \
+ when it appears before the first local type (`{}`)",
+ param_ty, local_type
+ ),
+ )
+ .note(
+ "implementing a foreign trait is only possible if at \
+ least one of the types for which it is implemented is local, \
+ and no uncovered type parameters appear before that first \
+ local type",
+ )
+ .note(
+ "in this case, 'before' refers to the following order: \
+ `impl<..> ForeignTrait<T1, ..., Tn> for T0`, \
+ where `T0` is the first and `Tn` is the last",
+ )
+ .emit(),
+ None => struct_span_err!(
+ tcx.sess,
+ sp,
+ E0210,
+ "type parameter `{}` must be used as the type parameter for some \
+ local type (e.g., `MyStruct<{}>`)",
+ param_ty,
+ param_ty
+ )
+ .span_label(
+ sp,
+ format!(
+ "type parameter `{}` must be used as the type parameter for some \
+ local type",
+ param_ty,
+ ),
+ )
+ .note(
+ "implementing a foreign trait is only possible if at \
+ least one of the types for which it is implemented is local",
+ )
+ .note(
+ "only traits defined in the current crate can be \
+ implemented for a type parameter",
+ )
+ .emit(),
}
}
}
- fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
-
- fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
-
- fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {}
+ Err(ErrorReported)
}
{
Some(parent_def_id.to_def_id())
}
-
+ Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) => {
+ Some(tcx.typeck_root_def_id(def_id))
+ }
_ => None,
}
}
}
Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => {
- Some(tcx.closure_base_def_id(def_id))
+ Some(tcx.typeck_root_def_id(def_id))
}
Node::Item(item) => match item.kind {
ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn, .. }) => {
}));
}
+ // provide junk type parameter defs for const blocks.
+ if let Node::AnonConst(_) = node {
+ let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
+ if let Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) = parent_node {
+ params.push(ty::GenericParamDef {
+ index: type_start,
+ name: Symbol::intern("<const_ty>"),
+ def_id,
+ pure_wrt_drop: false,
+ kind: ty::GenericParamDefKind::Type {
+ has_default: false,
+ object_lifetime_default: rl::Set1::Empty,
+ synthetic: None,
+ },
+ });
+ }
+ }
+
let param_def_id_to_index = params.iter().map(|param| (param.def_id, param.index)).collect();
ty::Generics {
Node::Expr(&Expr { kind: ExprKind::ConstBlock(ref anon_const), .. })
if anon_const.hir_id == hir_id =>
{
- tcx.typeck(def_id).node_type(anon_const.hir_id)
+ let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
+ substs.as_inline_const().ty()
}
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
),
);
- if let Err(errors) = fulfill.select_all_or_error(&infcx) {
+ let errors = fulfill.select_all_or_error(&infcx);
+ if !errors.is_empty() {
tracing::debug!("Wf-check got errors for {:?}: {:?}", ty, errors);
for error in errors {
if error.obligation.predicate == self.predicate {
}
}
- match fulfill_cx.select_all_or_error(infcx) {
- Ok(()) => true,
- Err(errors) => {
- infcx.report_fulfillment_errors(&errors, None, false);
+ match fulfill_cx.select_all_or_error(infcx).as_slice() {
+ [] => true,
+ errors => {
+ infcx.report_fulfillment_errors(errors, None, false);
false
}
}
term_id,
cause,
);
- if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
- infcx.report_fulfillment_errors(&err, None, false);
+ let errors = fulfillment_cx.select_all_or_error(&infcx);
+ if !errors.is_empty() {
+ infcx.report_fulfillment_errors(&errors, None, false);
error = true;
}
});
// variables. Process these constraints.
let mut fulfill_cx = FulfillmentContext::new();
fulfill_cx.register_predicate_obligations(self, result.obligations);
- if fulfill_cx.select_all_or_error(self).is_err() {
+ let errors = fulfill_cx.select_all_or_error(self);
+ if !errors.is_empty() {
self.tcx.sess.delay_span_bug(
span,
"implied_outlives_bounds failed to solve obligations from instantiation",
hir::TyKind::Path(hir::QPath::Resolved(
None,
hir::Path { res: hir::def::Res::Def(_, id), .. },
- )) if *id == def_id => true,
+ )) => *id == def_id,
_ => false,
})
})
#[lang = "owned_box"]
#[fundamental]
#[stable(feature = "rust1", since = "1.0.0")]
+// The declaration of the `Box` struct must be kept in sync with the
+// `alloc::alloc::box_free` function or ICEs will happen. See the comment
+// on `box_free` for more details.
pub struct Box<
T: ?Sized,
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
#[macro_use]
mod macros;
+mod raw_vec;
+
// Heaps provided for low-level allocation strategies
pub mod alloc;
pub mod borrow;
pub mod collections;
pub mod fmt;
-pub mod raw_vec;
pub mod rc;
pub mod slice;
pub mod str;
-#![unstable(feature = "raw_vec_internals", reason = "implementation detail", issue = "none")]
-#![doc(hidden)]
+#![unstable(feature = "raw_vec_internals", reason = "unstable const warnings", issue = "none")]
use core::alloc::LayoutError;
use core::cmp;
/// `usize::MAX`. This means that you need to be careful when round-tripping this type with a
/// `Box<[T]>`, since `capacity()` won't yield the length.
#[allow(missing_debug_implementations)]
-pub struct RawVec<T, A: Allocator = Global> {
+pub(crate) struct RawVec<T, A: Allocator = Global> {
ptr: Unique<T>,
cap: usize,
alloc: A,
/// # Aborts
///
/// Aborts on OOM.
- #[cfg(not(no_global_oom_handling))]
+ #[cfg(not(any(no_global_oom_handling, test)))]
#[must_use]
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
}
/// Like `with_capacity`, but guarantees the buffer is zeroed.
- #[cfg(not(no_global_oom_handling))]
+ #[cfg(not(any(no_global_oom_handling, test)))]
#[must_use]
#[inline]
pub fn with_capacity_zeroed(capacity: usize) -> Self {
Self::with_capacity_zeroed_in(capacity, Global)
}
-
- /// Reconstitutes a `RawVec` from a pointer and capacity.
- ///
- /// # Safety
- ///
- /// The `ptr` must be allocated (on the system heap), and with the given `capacity`.
- /// The `capacity` cannot exceed `isize::MAX` for sized types. (only a concern on 32-bit
- /// systems). ZST vectors may have a capacity up to `usize::MAX`.
- /// If the `ptr` and `capacity` come from a `RawVec`, then this is guaranteed.
- #[inline]
- pub unsafe fn from_raw_parts(ptr: *mut T, capacity: usize) -> Self {
- unsafe { Self::from_raw_parts_in(ptr, capacity, Global) }
- }
}
impl<T, A: Allocator> RawVec<T, A> {
Self::allocate_in(capacity, AllocInit::Zeroed, alloc)
}
- /// Converts a `Box<[T]>` into a `RawVec<T>`.
- pub fn from_box(slice: Box<[T], A>) -> Self {
- unsafe {
- let (slice, alloc) = Box::into_raw_with_allocator(slice);
- RawVec::from_raw_parts_in(slice.as_mut_ptr(), slice.len(), alloc)
- }
- }
-
/// Converts the entire buffer into `Box<[MaybeUninit<T>]>` with the specified `len`.
///
/// Note that this will correctly reconstitute any `cap` changes
/// # Aborts
///
/// Aborts on OOM.
- ///
- /// # Examples
- ///
- /// ```
- /// # #![feature(raw_vec_internals)]
- /// # extern crate alloc;
- /// # use std::ptr;
- /// # use alloc::raw_vec::RawVec;
- /// struct MyVec<T> {
- /// buf: RawVec<T>,
- /// len: usize,
- /// }
- ///
- /// impl<T: Clone> MyVec<T> {
- /// pub fn push_all(&mut self, elems: &[T]) {
- /// self.buf.reserve(self.len, elems.len());
- /// // reserve would have aborted or panicked if the len exceeded
- /// // `isize::MAX` so this is safe to do unchecked now.
- /// for x in elems {
- /// unsafe {
- /// ptr::write(self.buf.ptr().add(self.len), x.clone());
- /// }
- /// self.len += 1;
- /// }
- /// }
- /// }
- /// # fn main() {
- /// # let mut vector = MyVec { buf: RawVec::new(), len: 0 };
- /// # vector.push_all(&[1, 3, 5, 7, 9]);
- /// # }
- /// ```
#[cfg(not(no_global_oom_handling))]
#[inline]
pub fn reserve(&mut self, len: usize, additional: usize) {
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> !marker::Send for Rc<T> {}
+
+// Note that this negative impl isn't strictly necessary for correctness,
+// as `Rc` transitively contains a `Cell`, which is itself `!Sync`.
+// However, given how important `Rc`'s `!Sync`-ness is,
+// having an explicit negative impl is nice for documentation purposes
+// and results in nicer error messages.
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> !marker::Sync for Rc<T> {}
-Subproject commit 7f14f76c8ba6945c052fab77022e6e768b58e0b4
+Subproject commit b02ed04a7e915659eea6fb1607df469b84a30638
}
}
+#[cfg(not(bootstrap))]
+#[stable(feature = "copy_clone_array_lib", since = "1.58.0")]
+impl<T: Copy, const N: usize> Copy for [T; N] {}
+
+#[cfg(not(bootstrap))]
+#[stable(feature = "copy_clone_array_lib", since = "1.58.0")]
+impl<T: Clone, const N: usize> Clone for [T; N] {
+ #[inline]
+ fn clone(&self) -> Self {
+ SpecArrayClone::clone(self)
+ }
+
+ #[inline]
+ fn clone_from(&mut self, other: &Self) {
+ self.clone_from_slice(other);
+ }
+}
+
+#[cfg(not(bootstrap))]
+trait SpecArrayClone: Clone {
+ fn clone<const N: usize>(array: &[Self; N]) -> [Self; N];
+}
+
+#[cfg(not(bootstrap))]
+impl<T: Clone> SpecArrayClone for T {
+ #[inline]
+ default fn clone<const N: usize>(array: &[T; N]) -> [T; N] {
+ // SAFETY: we know for certain that this iterator will yield exactly `N`
+ // items.
+ unsafe { collect_into_array_unchecked(&mut array.iter().cloned()) }
+ }
+}
+
+#[cfg(not(bootstrap))]
+impl<T: Copy> SpecArrayClone for T {
+ #[inline]
+ fn clone<const N: usize>(array: &[T; N]) -> [T; N] {
+ *array
+ }
+}
+
// The Default impls cannot be done with const generics because `[T; 0]` doesn't
// require Default to be implemented, and having different impl blocks for
// different numbers isn't supported yet.
#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<T: ?Sized> Send for Cell<T> where T: Send {}
+// Note that this negative impl isn't strictly necessary for correctness,
+// as `Cell` wraps `UnsafeCell`, which is itself `!Sync`.
+// However, given how important `Cell`'s `!Sync`-ness is,
+// having an explicit negative impl is nice for documentation purposes
+// and results in nicer error messages.
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> !Sync for Cell<T> {}
///
/// * Function item types (i.e., the distinct types defined for each function)
/// * Function pointer types (e.g., `fn() -> i32`)
-/// * Array types, for all sizes, if the item type also implements `Clone` (e.g., `[i32; 123456]`)
/// * Tuple types, if each component also implements `Clone` (e.g., `()`, `(i32, bool)`)
/// * Closure types, if they capture no value from the environment
/// or if all such captured values implement `Clone` themselves.
!ptr.is_null() && ptr as usize % mem::align_of::<T>() == 0
}
+/// Checks whether the regions of memory starting at `src` and `dst` of size
+/// `count * size_of::<T>()` do *not* overlap.
+#[cfg(debug_assertions)]
+pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -> bool {
+ let src_usize = src as usize;
+ let dst_usize = dst as usize;
+ let size = mem::size_of::<T>().checked_mul(count).unwrap();
+ let diff = if src_usize > dst_usize { src_usize - dst_usize } else { dst_usize - src_usize };
+ // If the absolute distance between the ptrs is at least as big as the size of the buffer,
+ // they do not overlap.
+ diff >= size
+}
+
/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
/// and destination must *not* overlap.
///
pub fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
}
- // FIXME: Perform these checks only at run time
- /*if cfg!(debug_assertions)
- && !(is_aligned_and_not_null(src)
- && is_aligned_and_not_null(dst)
- && is_nonoverlapping(src, dst, count))
- {
- // Not panicking to keep codegen impact smaller.
- abort();
- }*/
+ #[cfg(debug_assertions)]
+ fn runtime_check<T>(src: *const T, dst: *mut T, count: usize) {
+ if !is_aligned_and_not_null(src)
+ || !is_aligned_and_not_null(dst)
+ || !is_nonoverlapping(src, dst, count)
+ {
+ // Not panicking to keep codegen impact smaller.
+ abort();
+ }
+ }
+ #[cfg(debug_assertions)]
+ const fn compiletime_check<T>(_src: *const T, _dst: *mut T, _count: usize) {}
+ #[cfg(debug_assertions)]
+ // SAFETY: runtime debug-assertions are a best-effort basis; it's fine to
+ // not do them during compile time
+ unsafe {
+ const_eval_select((src, dst, count), compiletime_check, runtime_check);
+ }
// SAFETY: the safety contract for `copy_nonoverlapping` must be
// upheld by the caller.
fn copy<T>(src: *const T, dst: *mut T, count: usize);
}
- // FIXME: Perform these checks only at run time
- /*if cfg!(debug_assertions) && !(is_aligned_and_not_null(src) && is_aligned_and_not_null(dst)) {
- // Not panicking to keep codegen impact smaller.
- abort();
- }*/
+ #[cfg(debug_assertions)]
+ fn runtime_check<T>(src: *const T, dst: *mut T) {
+ if !is_aligned_and_not_null(src) || !is_aligned_and_not_null(dst) {
+ // Not panicking to keep codegen impact smaller.
+ abort();
+ }
+ }
+ #[cfg(debug_assertions)]
+ const fn compiletime_check<T>(_src: *const T, _dst: *mut T) {}
+ #[cfg(debug_assertions)]
+ // SAFETY: runtime debug-assertions are a best-effort basis; it's fine to
+ // not do them during compile time
+ unsafe {
+ const_eval_select((src, dst), compiletime_check, runtime_check);
+ }
// SAFETY: the safety contract for `copy` must be upheld by the caller.
unsafe { copy(src, dst, count) }
#![feature(const_caller_location)]
#![feature(const_cell_into_inner)]
#![feature(const_discriminant)]
-#![cfg_attr(not(bootstrap), feature(const_eval_select))]
+#![feature(const_eval_select)]
#![feature(const_float_bits_conv)]
#![feature(const_float_classify)]
#![feature(const_fmt_arguments_new)]
#![feature(try_blocks)]
#![feature(unboxed_closures)]
#![feature(unsized_fn_params)]
+#![cfg_attr(not(bootstrap), feature(asm_const))]
//
// Target features:
#![feature(aarch64_target_feature)]
}
}
+// Pull in the `core_simd` crate directly into libcore. The contents of
+// `core_simd` are in a different repository: rust-lang/portable-simd.
+//
+// `core_simd` depends on libcore, but the contents of this module are
+// set up in such a way that directly pulling it here works such that the
+// crate uses this crate as its libcore.
+#[path = "../../portable-simd/crates/core_simd/src/mod.rs"]
+#[allow(missing_debug_implementations, dead_code, unsafe_op_in_unsafe_fn, unused_unsafe)]
+#[allow(rustdoc::bare_urls)]
+#[unstable(feature = "portable_simd", issue = "86656")]
+#[cfg(not(bootstrap))]
+mod core_simd;
+
+#[doc = include_str!("../../portable-simd/crates/core_simd/src/core_simd_docs.md")]
+#[unstable(feature = "portable_simd", issue = "86656")]
+#[cfg(not(bootstrap))]
+pub mod simd {
+ #[unstable(feature = "portable_simd", issue = "86656")]
+ pub use crate::core_simd::simd::*;
+}
+
include!("primitive_docs.rs");
///
/// # Panics
///
-/// This will always [`panic!`].
+/// This will always [`panic!`] because `unreachable!` is just a shorthand for `panic!` with a
+/// fixed, specific message.
+///
+/// Like `panic!`, this macro has a second form for displaying custom values.
///
/// # Examples
///
/// if 3*i < i { panic!("u32 overflow"); }
/// if x < 3*i { return i-1; }
/// }
-/// unreachable!();
+/// unreachable!("The loop should always return");
/// }
/// ```
#[macro_export]
///
/// * Function item types (i.e., the distinct types defined for each function)
/// * Function pointer types (e.g., `fn() -> i32`)
-/// * Array types, for all sizes, if the item type also implements `Copy` (e.g., `[i32; 123456]`)
/// * Tuple types, if each component also implements `Copy` (e.g., `()`, `(i32, bool)`)
/// * Closure types, if they capture no value from the environment
/// or if all such captured values implement `Copy` themselves.
///
/// [`ptr::swap`]: crate::ptr::swap()
#[stable(feature = "pointer_methods", since = "1.26.0")]
+ #[rustc_const_unstable(feature = "const_swap", issue = "83163")]
#[inline(always)]
- pub unsafe fn swap(self, with: *mut T)
+ pub const unsafe fn swap(self, with: *mut T)
where
T: Sized,
{
/// assert!(v == ["a", "b", "e", "d", "c"]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_swap", issue = "83163")]
#[inline]
- pub fn swap(&mut self, a: usize, b: usize) {
+ pub const fn swap(&mut self, a: usize, b: usize) {
let _ = &self[a];
let _ = &self[b];
/// [`swap`]: slice::swap
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
#[unstable(feature = "slice_swap_unchecked", issue = "88539")]
- pub unsafe fn swap_unchecked(&mut self, a: usize, b: usize) {
+ #[rustc_const_unstable(feature = "const_swap", issue = "83163")]
+ pub const unsafe fn swap_unchecked(&mut self, a: usize, b: usize) {
#[cfg(debug_assertions)]
{
let _ = &self[a];
#![feature(never_type)]
#![feature(unwrap_infallible)]
#![feature(result_into_ok_or_err)]
+#![cfg_attr(not(bootstrap), feature(portable_simd))]
#![feature(ptr_metadata)]
#![feature(once_cell)]
#![feature(unsized_tuple_coercion)]
mod pin;
mod ptr;
mod result;
+#[cfg(not(bootstrap))]
+mod simd;
mod slice;
mod str;
mod str_lossy;
--- /dev/null
+use core::simd::f32x4;
+
+#[test]
+fn testing() {
+ let x = f32x4::from_array([1.0, 1.0, 1.0, 1.0]);
+ let y = -x;
+
+ let h = x * 0.5;
+
+ let r = y.abs();
+ assert_eq!(x, r);
+ assert_eq!(h, f32x4::splat(0.5));
+}
--- /dev/null
+---
+name: Blank Issue
+about: Create a blank issue.
+---
--- /dev/null
+---
+name: Bug Report
+about: Create a bug report for Rust.
+labels: C-bug
+---
+<!--
+Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
+along with any information you feel relevant to replicating the bug.
+-->
+
+I tried this code:
+
+```rust
+<code>
+```
+
+I expected to see this happen: *explanation*
+
+Instead, this happened: *explanation*
+
+### Meta
+
+`rustc --version --verbose`:
+```
+<version>
+```
+
+
+`crate version in Cargo.toml`:
+```toml
+[dependencies]
+stdsimd =
+```
+<!-- If this specifies the repo at HEAD, please include the latest commit. -->
+
+
+<!--
+If a backtrace is available, please include a backtrace in the code block by
+setting `RUST_BACKTRACE=1` in your environment. e.g.
+`RUST_BACKTRACE=1 cargo build`.
+-->
+<details><summary>Backtrace</summary>
+<p>
+
+```
+<backtrace>
+```
+
+</p>
+</details>
--- /dev/null
+# This only controls whether a tiny, hard-to-find "open a blank issue" link appears at the end of
+# the template list.
+blank_issues_enabled: true
+contact_links:
+ - name: Intrinsic Support
+ url: https://github.com/rust-lang/stdarch/issues
+ about: Please direct issues about Rust's support for vendor intrinsics to core::arch
+ - name: Internal Compiler Error
+ url: https://github.com/rust-lang/rust/issues
+ about: Please report ICEs to the rustc repository
--- /dev/null
+---
+name: Feature Request
+about: Request an addition to the core::simd API
+labels: C-feature-request
+---
+<!--
+ Hello!
+
+ We are very interested in any feature requests you may have.
+
+ However, please be aware that core::simd exists to address concerns with creating a portable SIMD API for Rust.
+ Requests for extensions to compiler features, such as `target_feature`, binary versioning for SIMD APIs, or
+ improving specific compilation issues in general should be discussed at https://internals.rust-lang.org/
+-->
--- /dev/null
+Hello, welcome to `std::simd`!
+
+It seems this pull request template checklist was created while a lot of vector math ops were being implemented, and only really applies to ops. Feel free to delete everything here if it's not applicable, or ask for help if you're not sure what it means!
+
+For a given vector math operation on TxN, please add tests for interactions with:
+ - [ ] `T::MAX`
+ - [ ] `T::MIN`
+ - [ ] -1
+ - [ ] 1
+ - [ ] 0
+
+
+For a given vector math operation on TxN where T is a float, please add tests for test interactions with:
+ - [ ] a really large number, larger than the mantissa
+ - [ ] a really small "subnormal" number
+ - [ ] NaN
+ - [ ] Infinity
+ - [ ] Negative Infinity
--- /dev/null
+name: CI
+
+on:
+ pull_request:
+ push:
+ branches:
+ - master
+
+env:
+ CARGO_NET_RETRY: 10
+ RUSTUP_MAX_RETRIES: 10
+
+jobs:
+ rustfmt:
+ name: "rustfmt"
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Setup Rust
+ run: |
+ rustup update nightly --no-self-update
+ rustup default nightly
+ rustup component add rustfmt
+ - name: Run rustfmt
+ run: cargo fmt --all -- --check
+
+ clippy:
+ name: "clippy on ${{ matrix.target }}"
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ target:
+ # We shouldn't really have any OS-specific code, so think of this as a list of architectures
+ - x86_64-unknown-linux-gnu
+ - i686-unknown-linux-gnu
+ - i586-unknown-linux-gnu
+ - aarch64-unknown-linux-gnu
+ - armv7-unknown-linux-gnueabihf
+ - mips-unknown-linux-gnu
+ - mips64-unknown-linux-gnuabi64
+ - powerpc-unknown-linux-gnu
+ - powerpc64-unknown-linux-gnu
+ - riscv64gc-unknown-linux-gnu
+ - s390x-unknown-linux-gnu
+ - sparc64-unknown-linux-gnu
+ - wasm32-unknown-unknown
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Setup Rust
+ run: |
+ rustup update nightly --no-self-update
+ rustup default nightly
+ rustup target add ${{ matrix.target }}
+ rustup component add clippy
+ - name: Run Clippy
+ run: cargo clippy --all-targets --target ${{ matrix.target }}
+
+ x86-tests:
+ name: "${{ matrix.target_feature }} on ${{ matrix.target }}"
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ target: [x86_64-pc-windows-msvc, i686-pc-windows-msvc, i586-pc-windows-msvc, x86_64-unknown-linux-gnu, x86_64-apple-darwin]
+ # `default` means we use the default target config for the target,
+ # `native` means we run with `-Ctarget-cpu=native`, and anything else is
+ # an arg to `-Ctarget-feature`
+ target_feature: [default, native, +sse3, +ssse3, +sse4.1, +sse4.2, +avx, +avx2]
+
+ exclude:
+ # The macos runners seem to only reliably support up to `avx`.
+ - { target: x86_64-apple-darwin, target_feature: +avx2 }
+ # These features are statically known to be present for all 64 bit
+ # macs, and thus are covered by the `default` test
+ - { target: x86_64-apple-darwin, target_feature: +sse3 }
+ - { target: x86_64-apple-darwin, target_feature: +ssse3 }
+ # -Ctarget-cpu=native sounds like bad-news if target != host
+ - { target: i686-pc-windows-msvc, target_feature: native }
+ - { target: i586-pc-windows-msvc, target_feature: native }
+
+ include:
+ # Populate the `matrix.os` field
+ - { target: x86_64-apple-darwin, os: macos-latest }
+ - { target: x86_64-unknown-linux-gnu, os: ubuntu-latest }
+ - { target: x86_64-pc-windows-msvc, os: windows-latest }
+ - { target: i686-pc-windows-msvc, os: windows-latest }
+ - { target: i586-pc-windows-msvc, os: windows-latest }
+
+ # These are globally available on all the other targets.
+ - { target: i586-pc-windows-msvc, target_feature: +sse, os: windows-latest }
+ - { target: i586-pc-windows-msvc, target_feature: +sse2, os: windows-latest }
+
+ # Annoyingly, the x86_64-unknown-linux-gnu runner *almost* always has
+ # avx512vl, but occasionally doesn't. Maybe one day we can enable it.
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Setup Rust
+ run: |
+ rustup update nightly --no-self-update
+ rustup default nightly
+ rustup target add ${{ matrix.target }}
+
+ - name: Configure RUSTFLAGS
+ shell: bash
+ run: |
+ case "${{ matrix.target_feature }}" in
+ default)
+ echo "RUSTFLAGS=-Dwarnings" >> $GITHUB_ENV;;
+ native)
+ echo "RUSTFLAGS=-Dwarnings -Ctarget-cpu=native" >> $GITHUB_ENV
+ ;;
+ *)
+ echo "RUSTFLAGS=-Dwarnings -Ctarget-feature=${{ matrix.target_feature }}" >> $GITHUB_ENV
+ ;;
+ esac
+
+ # Super useful for debugging why a SIGILL occurred.
+ - name: Dump target configuration and support
+ run: |
+ rustc -Vv
+
+ echo "Caveat: not all target features are expected to be logged"
+
+ echo "## Requested target configuration (RUSTFLAGS=$RUSTFLAGS)"
+ rustc --print=cfg --target=${{ matrix.target }} $RUSTFLAGS
+
+ echo "## Supported target configuration for --target=${{ matrix.target }}"
+ rustc --print=cfg --target=${{ matrix.target }} -Ctarget-cpu=native
+
+ echo "## Natively supported target configuration"
+ rustc --print=cfg -Ctarget-cpu=native
+
+ - name: Test (debug)
+ run: cargo test --verbose --target=${{ matrix.target }}
+
+ - name: Test (release)
+ run: cargo test --verbose --target=${{ matrix.target }} --release
+
+ wasm-tests:
+ name: "wasm (firefox, ${{ matrix.name }})"
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ include:
+ - { name: default, RUSTFLAGS: "" }
+ - { name: simd128, RUSTFLAGS: "-C target-feature=+simd128" }
+ steps:
+ - uses: actions/checkout@v2
+ - name: Setup Rust
+ run: |
+ rustup update nightly --no-self-update
+ rustup default nightly
+ - name: Install wasm-pack
+ run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
+ - name: Test (debug)
+ run: wasm-pack test --firefox --headless crates/core_simd
+ env:
+ RUSTFLAGS: ${{ matrix.rustflags }}
+ - name: Test (release)
+ run: wasm-pack test --firefox --headless crates/core_simd --release
+ env:
+ RUSTFLAGS: ${{ matrix.rustflags }}
+
+ cross-tests:
+ name: "${{ matrix.target }} (via cross)"
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ # TODO: Sadly, we cant configure target-feature in a meaningful way
+ # because `cross` doesn't tell qemu to enable any non-default cpu
+ # features, nor does it give us a way to do so.
+ #
+ # Ultimately, we'd like to do something like [rust-lang/stdarch][stdarch].
+ # This is a lot more complex... but in practice it's likely that we can just
+ # snarf the docker config from around [here][1000-dockerfiles].
+ #
+ # [stdarch]: https://github.com/rust-lang/stdarch/blob/a5db4eaf/.github/workflows/main.yml#L67
+ # [1000-dockerfiles]: https://github.com/rust-lang/stdarch/tree/a5db4eaf/ci/docker
+
+ matrix:
+ target:
+ - i586-unknown-linux-gnu
+ # 32-bit arm has a few idiosyncracies like having subnormal flushing
+ # to zero on by default. Ideally we'd set
+ - armv7-unknown-linux-gnueabihf
+ - aarch64-unknown-linux-gnu
+ # Note: The issue above means neither of these mips targets will use
+ # MSA (mips simd) but MIPS uses a nonstandard binary representation
+ # for NaNs which makes it worth testing on despite that.
+ - mips-unknown-linux-gnu
+ - mips64-unknown-linux-gnuabi64
+ - riscv64gc-unknown-linux-gnu
+ # TODO this test works, but it appears to time out
+ # - powerpc-unknown-linux-gnu
+ # TODO this test is broken, but it appears to be a problem with QEMU, not us.
+ # - powerpc64le-unknown-linux-gnu
+ # TODO enable this once a new version of cross is released
+ # - powerpc64-unknown-linux-gnu
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Setup Rust
+ run: |
+ rustup update nightly --no-self-update
+ rustup default nightly
+ rustup target add ${{ matrix.target }}
+ rustup component add rust-src
+
+ - name: Install Cross
+ # Equivalent to `cargo install cross`, but downloading a prebuilt
+ # binary. Ideally we wouldn't hardcode a version, but the version number
+ # being part of the tarball means we can't just use the download/latest
+ # URL :(
+ run: |
+ CROSS_URL=https://github.com/rust-embedded/cross/releases/download/v0.2.1/cross-v0.2.1-x86_64-unknown-linux-gnu.tar.gz
+ mkdir -p "$HOME/.bin"
+ curl -sfSL --retry-delay 10 --retry 5 "${CROSS_URL}" | tar zxf - -C "$HOME/.bin"
+ echo "$HOME/.bin" >> $GITHUB_PATH
+
+ - name: Test (debug)
+ run: cross test --verbose --target=${{ matrix.target }}
+
+ - name: Test (release)
+ run: cross test --verbose --target=${{ matrix.target }} --release
+
+ features:
+ name: "Check cargo features (${{ matrix.simd }} × ${{ matrix.features }})"
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ simd:
+ - ""
+ - "avx512"
+ features:
+ - ""
+ - "--features std"
+ - "--features generic_const_exprs"
+ - "--features std --features generic_const_exprs"
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Setup Rust
+ run: |
+ rustup update nightly --no-self-update
+ rustup default nightly
+ - name: Detect AVX512
+ run: echo "CPU_FEATURE=$(lscpu | grep -o avx512[a-z]* | sed s/avx/+avx/ | tr '\n' ',' )" >> $GITHUB_ENV
+ - name: Check build
+ if: ${{ matrix.simd == '' }}
+ run: RUSTFLAGS="-Dwarnings" cargo check --all-targets --no-default-features ${{ matrix.features }}
+ - name: Check AVX
+ if: ${{ matrix.simd == 'avx512' && contains(env.CPU_FEATURE, 'avx512') }}
+ run: |
+ echo "Found AVX features: $CPU_FEATURE"
+ RUSTFLAGS="-Dwarnings -Ctarget-feature=$CPU_FEATURE" cargo check --all-targets --no-default-features ${{ matrix.features }}
--- /dev/null
+name: Documentation
+
+on:
+ push:
+ branches:
+ - master
+
+jobs:
+ release:
+ name: Deploy Documentation
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout Repository
+ uses: actions/checkout@v1
+
+ - name: Setup Rust
+ run: |
+ rustup update nightly --no-self-update
+ rustup default nightly
+
+ - name: Build Documentation
+ run: cargo doc --no-deps
+
+ - name: Deploy Documentation
+ uses: peaceiris/actions-gh-pages@v3
+ with:
+ github_token: ${{ secrets.GITHUB_TOKEN }}
+ publish_branch: gh-pages
+ publish_dir: ./target/doc
--- /dev/null
+/target
+Cargo.lock
--- /dev/null
+# Contributing to `std::simd`
+
+Simple version:
+1. Fork it and `git clone` it
+2. Create your feature branch: `git checkout -b my-branch`
+3. Write your changes.
+4. Test it: `cargo test`. Remember to enable whatever SIMD features you intend to test by setting `RUSTFLAGS`.
+5. Commit your changes: `git commit add ./path/to/changes && git commit -m 'Fix some bug'`
+6. Push the branch: `git push --set-upstream origin my-branch`
+7. Submit a pull request!
+
+## Taking on an Issue
+
+SIMD can be quite complex, and even a "simple" issue can be huge. If an issue is organized like a tracking issue, with an itemized list of items that don't necessarily have to be done in a specific order, please take the issue one item at a time. This will help by letting work proceed apace on the rest of the issue. If it's a (relatively) small issue, feel free to announce your intention to solve it on the issue tracker and take it in one go!
+
+## CI
+
+We currently have 2 CI matrices through Travis CI and GitHub Actions that will automatically build and test your change in order to verify that `std::simd`'s portable API is, in fact, portable. If your change builds locally, but does not build on either, this is likely due to a platform-specific concern that your code has not addressed. Please consult the build logs and address the error, or ask for help if you need it.
+
+## Beyond stdsimd
+
+A large amount of the core SIMD implementation is found in the rustc_codegen_* crates in the [main rustc repo](https://github.com/rust-lang/rust). In addition, actual platform-specific functions are implemented in [stdarch]. Not all changes to `std::simd` require interacting with either of these, but if you're wondering where something is and it doesn't seem to be in this repository, those might be where to start looking.
+
+## Questions? Concerns? Need Help?
+
+Please feel free to ask in the [#project-portable-simd][zulip-portable-simd] stream on the [rust-lang Zulip][zulip] for help with making changes to `std::simd`!
+If your changes include directly modifying the compiler, it might also be useful to ask in [#t-compiler/help][zulip-compiler-help].
+
+[zulip-portable-simd]: https://rust-lang.zulipchat.com/#narrow/stream/257879-project-portable-simd
+[zulip-compiler-help]: https://rust-lang.zulipchat.com/#narrow/stream/182449-t-compiler.2Fhelp
+[zulip]: https://rust-lang.zulipchat.com
+[stdarch]: https://github.com/rust-lang/stdarch
--- /dev/null
+[workspace]
+
+members = [
+ "crates/core_simd",
+ "crates/test_helpers",
+]
--- /dev/null
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
--- /dev/null
+Copyright (c) 2020 The Rust Project Developers
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
--- /dev/null
+# The Rust standard library's portable SIMD API
+[![Build Status](https://travis-ci.com/rust-lang/portable-simd.svg?branch=master)](https://travis-ci.com/rust-lang/portable-simd)
+
+Code repository for the [Portable SIMD Project Group](https://github.com/rust-lang/project-portable-simd).
+Please refer to [CONTRIBUTING.md](./CONTRIBUTING.md) for our contributing guidelines.
+
+The docs for this crate are published from the main branch.
+You can [read them here][docs].
+
+If you have questions about SIMD, we have begun writing a [guide][simd-guide].
+We can also be found on [Zulip][zulip-project-portable-simd].
+
+If you are interested in support for a specific architecture, you may want [stdarch] instead.
+
+## Hello World
+
+Now we're gonna dip our toes into this world with a small SIMD "Hello, World!" example. Make sure your compiler is up to date and using `nightly`. We can do that by running
+
+```bash
+rustup update -- nightly
+```
+
+or by setting up `rustup default nightly` or else with `cargo +nightly {build,test,run}`. After updating, run
+```bash
+cargo new hellosimd
+```
+to create a new crate. Edit `hellosimd/Cargo.toml` to be
+```toml
+[package]
+name = "hellosimd"
+version = "0.1.0"
+edition = "2018"
+[dependencies]
+core_simd = { git = "https://github.com/rust-lang/portable-simd" }
+```
+
+and finally write this in `src/main.rs`:
+```rust
+use core_simd::*;
+fn main() {
+ let a = f32x4::splat(10.0);
+ let b = f32x4::from_array([1.0, 2.0, 3.0, 4.0]);
+ println!("{:?}", a + b);
+}
+```
+
+Explanation: We import all the bindings from the crate with the first line. Then, we construct our SIMD vectors with methods like `splat` or `from_array`. Finally, we can use operators on them like `+` and the appropriate SIMD instructions will be carried out. When we run `cargo run` you should get `[11.0, 12.0, 13.0, 14.0]`.
+
+## Code Organization
+
+Currently the crate is organized so that each element type is a file, and then the 64-bit, 128-bit, 256-bit, and 512-bit vectors using those types are contained in said file.
+
+All types are then exported as a single, flat module.
+
+Depending on the size of the primitive type, the number of lanes the vector will have varies. For example, 128-bit vectors have four `f32` lanes and two `f64` lanes.
+
+The supported element types are as follows:
+* **Floating Point:** `f32`, `f64`
+* **Signed Integers:** `i8`, `i16`, `i32`, `i64`, `i128`, `isize`
+* **Unsigned Integers:** `u8`, `u16`, `u32`, `u64`, `u128`, `usize`
+* **Masks:** `mask8`, `mask16`, `mask32`, `mask64`, `mask128`, `masksize`
+
+Floating point, signed integers, and unsigned integers are the [primitive types](https://doc.rust-lang.org/core/primitive/index.html) you're already used to.
+The `mask` types are "truthy" values, but they use the number of bits in their name instead of just 1 bit like a normal `bool` uses.
+
+[simd-guide]: ./beginners-guide.md
+[zulip-project-portable-simd]: https://rust-lang.zulipchat.com/#narrow/stream/257879-project-portable-simd
+[stdarch]: https://github.com/rust-lang/stdarch
+[docs]: https://rust-lang.github.io/portable-simd/core_simd
--- /dev/null
+
+# Beginner's Guide To SIMD
+
+Hello and welcome to our SIMD basics guide!
+
+Because SIMD is a subject that many programmers haven't worked with before, we thought that it's best to outline some terms and other basics for you to get started with.
+
+## Quick Background
+
+**SIMD** stands for *Single Instruction, Multiple Data*. In other words, SIMD is when the CPU performs a single action on more than one logical piece of data at the same time. Instead of adding two registers that each contain one `f32` value and getting an `f32` as the result, you might add two registers that each contain `f32x4` (128 bits of data) and then you get an `f32x4` as the output.
+
+This might seem a tiny bit weird at first, but there's a good reason for it. Back in the day, as CPUs got faster and faster, eventually they got so fast that the CPU would just melt itself. The heat management (heat sinks, fans, etc) simply couldn't keep up with how much electricity was going through the metal. Two main strategies were developed to help get around the limits of physics.
+* One of them you're probably familiar with: Multi-core processors. By giving a processor more than one core, each core can do its own work, and because they're physically distant (at least on the CPU's scale) the heat can still be managed. Unfortunately, not all tasks can just be split up across cores in an efficient way.
+* The second strategy is SIMD. If you can't make the register go any faster, you can still make the register *wider*. This lets you process more data at a time, which is *almost* as good as just having a faster CPU. As with multi-core programming, SIMD doesn't fit every kind of task, so you have to know when it will improve your program.
+
+## Terms
+
+SIMD has a few special vocabulary terms you should know:
+
+* **Vector:** A SIMD value is called a vector. This shouldn't be confused with the `Vec<T>` type. A SIMD vector has a fixed size, known at compile time. All of the elements within the vector are of the same type. This makes vectors *similar to* arrays. One difference is that a vector is generally aligned to its *entire* size (eg: 16 bytes, 32 bytes, etc), not just the size of an individual element. Sometimes vector data is called "packed" data.
+
+* **Vectorize**: An operation that uses SIMD instructions to operate over a vector is often referred to as "vectorized".
+
+* **Autovectorization**: Also known as _implicit vectorization_. This is when a compiler can automatically recognize a situation where scalar instructions may be replaced with SIMD instructions, and use those instead.
+
+* **Scalar:** "Scalar" in mathematical contexts refers to values that can be represented as a single element, mostly numbers like 6, 3.14, or -2. It can also be used to describe "scalar operations" that use strictly scalar values, like addition. This term is mostly used to differentiate between vectorized operations that use SIMD instructions and scalar operations that don't.
+
+* **Lane:** A single element position within a vector is called a lane. If you have `N` lanes available then they're numbered from `0` to `N-1` when referring to them, again like an array. The biggest difference between an array element and a vector lane is that in general is *relatively costly* to access an individual lane value. On most architectures, the vector has to be pushed out of the SIMD register onto the stack, then an individual lane is accessed while it's on the stack (and possibly the stack value is read back into a register). For this reason, when working with SIMD you should avoid reading or writing the value of an individual lane during hot loops.
+
+* **Bit Widths:** When talking about SIMD, the bit widths used are the bit size of the vectors involved, *not* the individual elements. So "128-bit SIMD" has 128-bit vectors, and that might be `f32x4`, `i32x4`, `i16x8`, or other variations. While 128-bit SIMD is the most common, there's also 64-bit, 256-bit, and even 512-bit on the newest CPUs.
+
+* **Vector Register:** The extra-wide registers that are used for SIMD operations are commonly called vector registers, though you may also see "SIMD registers", vendor names for specific features, or even "floating-point register" as it is common for the same registers to be used with both scalar and vectorized floating-point operations.
+
+* **Vertical:** When an operation is "vertical", each lane processes individually without regard to the other lanes in the same vector. For example, a "vertical add" between two vectors would add lane 0 in `a` with lane 0 in `b`, with the total in lane 0 of `out`, and then the same thing for lanes 1, 2, etc. Most SIMD operations are vertical operations, so if your problem is a vertical problem then you can probably solve it with SIMD.
+
+* **Horizontal:** When an operation is "horizontal", the lanes within a single vector interact in some way. A "horizontal add" might add up lane 0 of `a` with lane 1 of `a`, with the total in lane 0 of `out`.
+
+* **Target Feature:** Rust calls a CPU architecture extension a `target_feature`. Proper SIMD requires various CPU extensions to be enabled (details below). Don't confuse this with `feature`, which is a Cargo crate concept.
+
+## Target Features
+
+When using SIMD, you should be familiar with the CPU feature set that you're targeting.
+
+On `arm` and `aarch64` it's fairly simple. There's just one CPU feature that controls if SIMD is available: `neon` (or "NEON", all caps, as the ARM docs often put it). Neon registers can be used as 64-bit or 128-bit. When doing 128-bit operations it just uses two 64-bit registers as a single 128-bit register.
+
+> By default, the `aarch64`, `arm`, and `thumb` Rust targets generally do not enable `neon` unless it's in the target string.
+
+On `x86` and `x86_64` it's slightly more complicated. The SIMD support is split into many levels:
+* 128-bit: `sse`, `sse2`, `sse3`, `ssse3` (not a typo!), `sse4.1`, `sse4.2`, `sse4a` (AMD only)
+* 256-bit (mostly): `avx`, `avx2`, `fma`
+* 512-bit (mostly): a *wide* range of `avx512` variations
+
+The list notes the bit widths available at each feature level, though the operations of the more advanced features can generally be used with the smaller register sizes as well. For example, new operations introduced in `avx` generally have a 128-bit form as well as a 256-bit form. This means that even if you only do 128-bit work you can still benefit from the later feature levels.
+
+> By default, the `i686` and `x86_64` Rust targets enable `sse` and `sse2`.
+
+### Selecting Additional Target Features
+
+If you want to enable support for a target feature within your build, generally you should use a [target-feature](https://rust-lang.github.io/packed_simd/perf-guide/target-feature/rustflags.html#target-feature) setting within you `RUSTFLAGS` setting.
+
+If you know that you're targeting a specific CPU you can instead use the [target-cpu](https://rust-lang.github.io/packed_simd/perf-guide/target-feature/rustflags.html#target-cpu) flag and the compiler will enable the correct set of features for that CPU.
+
+The [Steam Hardware Survey](https://store.steampowered.com/hwsurvey/Steam-Hardware-Software-Survey-Welcome-to-Steam) is one of the few places with data on how common various CPU features are. The dataset is limited to "the kinds of computers owned by people who play computer games", so the info only covers `x86`/`x86_64`, and it also probably skews to slightly higher quality computers than average. Still, we can see that the `sse` levels have very high support, `avx` and `avx2` are quite common as well, and the `avx-512` family is still so early in adoption you can barely find it in consumer grade stuff.
+
+## Running a program compiled for a CPU feature level that the CPU doesn't support is automatic undefined behavior.
+
+This means that if you build your program with `avx` support enabled and run it on a CPU without `avx` support, it's **instantly** undefined behavior.
+
+Even without an `unsafe` block in sight.
+
+This is no bug in Rust, or soundness hole in the type system. You just plain can't make a CPU do what it doesn't know how to do.
+
+This is why the various Rust targets *don't* enable many CPU feature flags by default: requiring a more advanced CPU makes the final binary *less* portable.
+
+So please select an appropriate CPU feature level when building your programs.
+
+## Size, Alignment, and Unsafe Code
+
+Most of the portable SIMD API is designed to allow the user to gloss over the details of different architectures and avoid using unsafe code. However, there are plenty of reasons to want to use unsafe code with these SIMD types, such as using an intrinsic function from `core::arch` to further accelerate particularly specialized SIMD operations on a given platform, while still using the portable API elsewhere. For these cases, there are some rules to keep in mind.
+
+Fortunately, most SIMD types have a fairly predictable size. `i32x4` is bit-equivalent to `[i32; 4]` and so can be bitcast to it, e.g. using [`mem::transmute`], though the API usually offers a safe cast you can use instead.
+
+However, this is not the same as alignment. Computer architectures generally prefer aligned accesses, especially when moving data between memory and vector registers, and while some support specialized operations that can bend the rules to help with this, unaligned access is still typically slow, or even undefined behavior. In addition, different architectures can require different alignments when interacting with their native SIMD types. For this reason, any `#[repr(simd)]` type has a non-portable alignment. If it is necessary to directly interact with the alignment of these types, it should be via [`mem::align_of`].
+
+[`mem::transmute`]: https://doc.rust-lang.org/core/mem/fn.transmute.html
+[`mem::align_of`]: https://doc.rust-lang.org/core/mem/fn.align_of.html
\ No newline at end of file
--- /dev/null
+[package]
+name = "core_simd"
+version = "0.1.0"
+edition = "2021"
+homepage = "https://github.com/rust-lang/portable-simd"
+repository = "https://github.com/rust-lang/portable-simd"
+keywords = ["core", "simd", "intrinsics"]
+categories = ["hardware-support", "no-std"]
+license = "MIT OR Apache-2.0"
+
+[features]
+default = ["std", "generic_const_exprs"]
+std = []
+generic_const_exprs = []
+
+[target.'cfg(target_arch = "wasm32")'.dev-dependencies.wasm-bindgen]
+version = "0.2"
+
+[dev-dependencies.wasm-bindgen-test]
+version = "0.3"
+
+[dev-dependencies.proptest]
+version = "0.10"
+default-features = false
+features = ["alloc"]
+
+[dev-dependencies.test_helpers]
+path = "../test_helpers"
--- /dev/null
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
--- /dev/null
+Copyright (c) 2020 The Rust Project Developers
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
--- /dev/null
+//! 4x4 matrix inverse
+// Code ported from the `packed_simd` crate
+// Run this code with `cargo test --example matrix_inversion`
+#![feature(array_chunks, portable_simd)]
+use core_simd::simd::*;
+use Which::*;
+
+// Gotta define our own 4x4 matrix since Rust doesn't ship multidim arrays yet :^)
+#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
+pub struct Matrix4x4([[f32; 4]; 4]);
+
+#[allow(clippy::too_many_lines)]
+pub fn scalar_inv4x4(m: Matrix4x4) -> Option<Matrix4x4> {
+ let m = m.0;
+
+ #[rustfmt::skip]
+ let mut inv = [
+ // row 0:
+ [
+ // 0,0:
+ m[1][1] * m[2][2] * m[3][3] -
+ m[1][1] * m[2][3] * m[3][2] -
+ m[2][1] * m[1][2] * m[3][3] +
+ m[2][1] * m[1][3] * m[3][2] +
+ m[3][1] * m[1][2] * m[2][3] -
+ m[3][1] * m[1][3] * m[2][2],
+ // 0,1:
+ -m[0][1] * m[2][2] * m[3][3] +
+ m[0][1] * m[2][3] * m[3][2] +
+ m[2][1] * m[0][2] * m[3][3] -
+ m[2][1] * m[0][3] * m[3][2] -
+ m[3][1] * m[0][2] * m[2][3] +
+ m[3][1] * m[0][3] * m[2][2],
+ // 0,2:
+ m[0][1] * m[1][2] * m[3][3] -
+ m[0][1] * m[1][3] * m[3][2] -
+ m[1][1] * m[0][2] * m[3][3] +
+ m[1][1] * m[0][3] * m[3][2] +
+ m[3][1] * m[0][2] * m[1][3] -
+ m[3][1] * m[0][3] * m[1][2],
+ // 0,3:
+ -m[0][1] * m[1][2] * m[2][3] +
+ m[0][1] * m[1][3] * m[2][2] +
+ m[1][1] * m[0][2] * m[2][3] -
+ m[1][1] * m[0][3] * m[2][2] -
+ m[2][1] * m[0][2] * m[1][3] +
+ m[2][1] * m[0][3] * m[1][2],
+ ],
+ // row 1
+ [
+ // 1,0:
+ -m[1][0] * m[2][2] * m[3][3] +
+ m[1][0] * m[2][3] * m[3][2] +
+ m[2][0] * m[1][2] * m[3][3] -
+ m[2][0] * m[1][3] * m[3][2] -
+ m[3][0] * m[1][2] * m[2][3] +
+ m[3][0] * m[1][3] * m[2][2],
+ // 1,1:
+ m[0][0] * m[2][2] * m[3][3] -
+ m[0][0] * m[2][3] * m[3][2] -
+ m[2][0] * m[0][2] * m[3][3] +
+ m[2][0] * m[0][3] * m[3][2] +
+ m[3][0] * m[0][2] * m[2][3] -
+ m[3][0] * m[0][3] * m[2][2],
+ // 1,2:
+ -m[0][0] * m[1][2] * m[3][3] +
+ m[0][0] * m[1][3] * m[3][2] +
+ m[1][0] * m[0][2] * m[3][3] -
+ m[1][0] * m[0][3] * m[3][2] -
+ m[3][0] * m[0][2] * m[1][3] +
+ m[3][0] * m[0][3] * m[1][2],
+ // 1,3:
+ m[0][0] * m[1][2] * m[2][3] -
+ m[0][0] * m[1][3] * m[2][2] -
+ m[1][0] * m[0][2] * m[2][3] +
+ m[1][0] * m[0][3] * m[2][2] +
+ m[2][0] * m[0][2] * m[1][3] -
+ m[2][0] * m[0][3] * m[1][2],
+ ],
+ // row 2
+ [
+ // 2,0:
+ m[1][0] * m[2][1] * m[3][3] -
+ m[1][0] * m[2][3] * m[3][1] -
+ m[2][0] * m[1][1] * m[3][3] +
+ m[2][0] * m[1][3] * m[3][1] +
+ m[3][0] * m[1][1] * m[2][3] -
+ m[3][0] * m[1][3] * m[2][1],
+ // 2,1:
+ -m[0][0] * m[2][1] * m[3][3] +
+ m[0][0] * m[2][3] * m[3][1] +
+ m[2][0] * m[0][1] * m[3][3] -
+ m[2][0] * m[0][3] * m[3][1] -
+ m[3][0] * m[0][1] * m[2][3] +
+ m[3][0] * m[0][3] * m[2][1],
+ // 2,2:
+ m[0][0] * m[1][1] * m[3][3] -
+ m[0][0] * m[1][3] * m[3][1] -
+ m[1][0] * m[0][1] * m[3][3] +
+ m[1][0] * m[0][3] * m[3][1] +
+ m[3][0] * m[0][1] * m[1][3] -
+ m[3][0] * m[0][3] * m[1][1],
+ // 2,3:
+ -m[0][0] * m[1][1] * m[2][3] +
+ m[0][0] * m[1][3] * m[2][1] +
+ m[1][0] * m[0][1] * m[2][3] -
+ m[1][0] * m[0][3] * m[2][1] -
+ m[2][0] * m[0][1] * m[1][3] +
+ m[2][0] * m[0][3] * m[1][1],
+ ],
+ // row 3
+ [
+ // 3,0:
+ -m[1][0] * m[2][1] * m[3][2] +
+ m[1][0] * m[2][2] * m[3][1] +
+ m[2][0] * m[1][1] * m[3][2] -
+ m[2][0] * m[1][2] * m[3][1] -
+ m[3][0] * m[1][1] * m[2][2] +
+ m[3][0] * m[1][2] * m[2][1],
+ // 3,1:
+ m[0][0] * m[2][1] * m[3][2] -
+ m[0][0] * m[2][2] * m[3][1] -
+ m[2][0] * m[0][1] * m[3][2] +
+ m[2][0] * m[0][2] * m[3][1] +
+ m[3][0] * m[0][1] * m[2][2] -
+ m[3][0] * m[0][2] * m[2][1],
+ // 3,2:
+ -m[0][0] * m[1][1] * m[3][2] +
+ m[0][0] * m[1][2] * m[3][1] +
+ m[1][0] * m[0][1] * m[3][2] -
+ m[1][0] * m[0][2] * m[3][1] -
+ m[3][0] * m[0][1] * m[1][2] +
+ m[3][0] * m[0][2] * m[1][1],
+ // 3,3:
+ m[0][0] * m[1][1] * m[2][2] -
+ m[0][0] * m[1][2] * m[2][1] -
+ m[1][0] * m[0][1] * m[2][2] +
+ m[1][0] * m[0][2] * m[2][1] +
+ m[2][0] * m[0][1] * m[1][2] -
+ m[2][0] * m[0][2] * m[1][1],
+ ],
+ ];
+
+ let det = m[0][0] * inv[0][0] + m[0][1] * inv[1][0] + m[0][2] * inv[2][0] + m[0][3] * inv[3][0];
+ if det == 0. {
+ return None;
+ }
+
+ let det_inv = 1. / det;
+
+ for row in &mut inv {
+ for elem in row.iter_mut() {
+ *elem *= det_inv;
+ }
+ }
+
+ Some(Matrix4x4(inv))
+}
+
+pub fn simd_inv4x4(m: Matrix4x4) -> Option<Matrix4x4> {
+ let m = m.0;
+ let m_0 = f32x4::from_array(m[0]);
+ let m_1 = f32x4::from_array(m[1]);
+ let m_2 = f32x4::from_array(m[2]);
+ let m_3 = f32x4::from_array(m[3]);
+
+ const SHUFFLE01: [Which; 4] = [First(0), First(1), Second(0), Second(1)];
+ const SHUFFLE02: [Which; 4] = [First(0), First(2), Second(0), Second(2)];
+ const SHUFFLE13: [Which; 4] = [First(1), First(3), Second(1), Second(3)];
+ const SHUFFLE23: [Which; 4] = [First(2), First(3), Second(2), Second(3)];
+
+ let tmp = simd_swizzle!(m_0, m_1, SHUFFLE01);
+ let row1 = simd_swizzle!(m_2, m_3, SHUFFLE01);
+
+ let row0 = simd_swizzle!(tmp, row1, SHUFFLE02);
+ let row1 = simd_swizzle!(row1, tmp, SHUFFLE13);
+
+ let tmp = simd_swizzle!(m_0, m_1, SHUFFLE23);
+ let row3 = simd_swizzle!(m_2, m_3, SHUFFLE23);
+ let row2 = simd_swizzle!(tmp, row3, SHUFFLE02);
+ let row3 = simd_swizzle!(row3, tmp, SHUFFLE13);
+
+ let tmp = (row2 * row3).reverse().rotate_lanes_right::<2>();
+ let minor0 = row1 * tmp;
+ let minor1 = row0 * tmp;
+ let tmp = tmp.rotate_lanes_right::<2>();
+ let minor0 = (row1 * tmp) - minor0;
+ let minor1 = (row0 * tmp) - minor1;
+ let minor1 = minor1.rotate_lanes_right::<2>();
+
+ let tmp = (row1 * row2).reverse().rotate_lanes_right::<2>();
+ let minor0 = (row3 * tmp) + minor0;
+ let minor3 = row0 * tmp;
+ let tmp = tmp.rotate_lanes_right::<2>();
+
+ let minor0 = minor0 - row3 * tmp;
+ let minor3 = row0 * tmp - minor3;
+ let minor3 = minor3.rotate_lanes_right::<2>();
+
+ let tmp = (row3 * row1.rotate_lanes_right::<2>())
+ .reverse()
+ .rotate_lanes_right::<2>();
+ let row2 = row2.rotate_lanes_right::<2>();
+ let minor0 = row2 * tmp + minor0;
+ let minor2 = row0 * tmp;
+ let tmp = tmp.rotate_lanes_right::<2>();
+ let minor0 = minor0 - row2 * tmp;
+ let minor2 = row0 * tmp - minor2;
+ let minor2 = minor2.rotate_lanes_right::<2>();
+
+ let tmp = (row0 * row1).reverse().rotate_lanes_right::<2>();
+ let minor2 = minor2 + row3 * tmp;
+ let minor3 = row2 * tmp - minor3;
+ let tmp = tmp.rotate_lanes_right::<2>();
+ let minor2 = row3 * tmp - minor2;
+ let minor3 = minor3 - row2 * tmp;
+
+ let tmp = (row0 * row3).reverse().rotate_lanes_right::<2>();
+ let minor1 = minor1 - row2 * tmp;
+ let minor2 = row1 * tmp + minor2;
+ let tmp = tmp.rotate_lanes_right::<2>();
+ let minor1 = row2 * tmp + minor1;
+ let minor2 = minor2 - row1 * tmp;
+
+ let tmp = (row0 * row2).reverse().rotate_lanes_right::<2>();
+ let minor1 = row3 * tmp + minor1;
+ let minor3 = minor3 - row1 * tmp;
+ let tmp = tmp.rotate_lanes_right::<2>();
+ let minor1 = minor1 - row3 * tmp;
+ let minor3 = row1 * tmp + minor3;
+
+ let det = row0 * minor0;
+ let det = det.rotate_lanes_right::<2>() + det;
+ let det = det.reverse().rotate_lanes_right::<2>() + det;
+
+ if det.horizontal_sum() == 0. {
+ return None;
+ }
+ // calculate the reciprocal
+ let tmp = f32x4::splat(1.0) / det;
+ let det = tmp + tmp - det * tmp * tmp;
+
+ let res0 = minor0 * det;
+ let res1 = minor1 * det;
+ let res2 = minor2 * det;
+ let res3 = minor3 * det;
+
+ let mut m = m;
+
+ m[0] = res0.to_array();
+ m[1] = res1.to_array();
+ m[2] = res2.to_array();
+ m[3] = res3.to_array();
+
+ Some(Matrix4x4(m))
+}
+
+#[cfg(test)]
+#[rustfmt::skip]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test() {
+ let tests: &[(Matrix4x4, Option<Matrix4x4>)] = &[
+ // Identity:
+ (Matrix4x4([
+ [1., 0., 0., 0.],
+ [0., 1., 0., 0.],
+ [0., 0., 1., 0.],
+ [0., 0., 0., 1.],
+ ]),
+ Some(Matrix4x4([
+ [1., 0., 0., 0.],
+ [0., 1., 0., 0.],
+ [0., 0., 1., 0.],
+ [0., 0., 0., 1.],
+ ]))
+ ),
+ // None:
+ (Matrix4x4([
+ [1., 2., 3., 4.],
+ [12., 11., 10., 9.],
+ [5., 6., 7., 8.],
+ [16., 15., 14., 13.],
+ ]),
+ None
+ ),
+ // Other:
+ (Matrix4x4([
+ [1., 1., 1., 0.],
+ [0., 3., 1., 2.],
+ [2., 3., 1., 0.],
+ [1., 0., 2., 1.],
+ ]),
+ Some(Matrix4x4([
+ [-3., -0.5, 1.5, 1.0],
+ [ 1., 0.25, -0.25, -0.5],
+ [ 3., 0.25, -1.25, -0.5],
+ [-3., 0.0, 1.0, 1.0],
+ ]))
+ ),
+
+
+ ];
+
+ for &(input, output) in tests {
+ assert_eq!(scalar_inv4x4(input), output);
+ assert_eq!(simd_inv4x4(input), output);
+ }
+ }
+}
+
+fn main() {
+ // Empty main to make cargo happy
+}
--- /dev/null
+#![cfg_attr(feature = "std", feature(portable_simd))]
+
+/// Benchmarks game nbody code
+/// Taken from the `packed_simd` crate
+/// Run this benchmark with `cargo test --example nbody`
+#[cfg(feature = "std")]
+mod nbody {
+ use core_simd::*;
+
+ use std::f64::consts::PI;
+ const SOLAR_MASS: f64 = 4.0 * PI * PI;
+ const DAYS_PER_YEAR: f64 = 365.24;
+
+ #[derive(Debug, Clone, Copy)]
+ struct Body {
+ pub x: f64x4,
+ pub v: f64x4,
+ pub mass: f64,
+ }
+
+ const N_BODIES: usize = 5;
+ const BODIES: [Body; N_BODIES] = [
+ // sun:
+ Body {
+ x: f64x4::from_array([0., 0., 0., 0.]),
+ v: f64x4::from_array([0., 0., 0., 0.]),
+ mass: SOLAR_MASS,
+ },
+ // jupiter:
+ Body {
+ x: f64x4::from_array([
+ 4.84143144246472090e+00,
+ -1.16032004402742839e+00,
+ -1.03622044471123109e-01,
+ 0.,
+ ]),
+ v: f64x4::from_array([
+ 1.66007664274403694e-03 * DAYS_PER_YEAR,
+ 7.69901118419740425e-03 * DAYS_PER_YEAR,
+ -6.90460016972063023e-05 * DAYS_PER_YEAR,
+ 0.,
+ ]),
+ mass: 9.54791938424326609e-04 * SOLAR_MASS,
+ },
+ // saturn:
+ Body {
+ x: f64x4::from_array([
+ 8.34336671824457987e+00,
+ 4.12479856412430479e+00,
+ -4.03523417114321381e-01,
+ 0.,
+ ]),
+ v: f64x4::from_array([
+ -2.76742510726862411e-03 * DAYS_PER_YEAR,
+ 4.99852801234917238e-03 * DAYS_PER_YEAR,
+ 2.30417297573763929e-05 * DAYS_PER_YEAR,
+ 0.,
+ ]),
+ mass: 2.85885980666130812e-04 * SOLAR_MASS,
+ },
+ // uranus:
+ Body {
+ x: f64x4::from_array([
+ 1.28943695621391310e+01,
+ -1.51111514016986312e+01,
+ -2.23307578892655734e-01,
+ 0.,
+ ]),
+ v: f64x4::from_array([
+ 2.96460137564761618e-03 * DAYS_PER_YEAR,
+ 2.37847173959480950e-03 * DAYS_PER_YEAR,
+ -2.96589568540237556e-05 * DAYS_PER_YEAR,
+ 0.,
+ ]),
+ mass: 4.36624404335156298e-05 * SOLAR_MASS,
+ },
+ // neptune:
+ Body {
+ x: f64x4::from_array([
+ 1.53796971148509165e+01,
+ -2.59193146099879641e+01,
+ 1.79258772950371181e-01,
+ 0.,
+ ]),
+ v: f64x4::from_array([
+ 2.68067772490389322e-03 * DAYS_PER_YEAR,
+ 1.62824170038242295e-03 * DAYS_PER_YEAR,
+ -9.51592254519715870e-05 * DAYS_PER_YEAR,
+ 0.,
+ ]),
+ mass: 5.15138902046611451e-05 * SOLAR_MASS,
+ },
+ ];
+
+ fn offset_momentum(bodies: &mut [Body; N_BODIES]) {
+ let (sun, rest) = bodies.split_at_mut(1);
+ let sun = &mut sun[0];
+ for body in rest {
+ let m_ratio = body.mass / SOLAR_MASS;
+ sun.v -= body.v * m_ratio;
+ }
+ }
+
+ fn energy(bodies: &[Body; N_BODIES]) -> f64 {
+ let mut e = 0.;
+ for i in 0..N_BODIES {
+ let bi = &bodies[i];
+ e += bi.mass * (bi.v * bi.v).horizontal_sum() * 0.5;
+ for bj in bodies.iter().take(N_BODIES).skip(i + 1) {
+ let dx = bi.x - bj.x;
+ e -= bi.mass * bj.mass / (dx * dx).horizontal_sum().sqrt()
+ }
+ }
+ e
+ }
+
+ fn advance(bodies: &mut [Body; N_BODIES], dt: f64) {
+ const N: usize = N_BODIES * (N_BODIES - 1) / 2;
+
+ // compute distance between bodies:
+ let mut r = [f64x4::splat(0.); N];
+ {
+ let mut i = 0;
+ for j in 0..N_BODIES {
+ for k in j + 1..N_BODIES {
+ r[i] = bodies[j].x - bodies[k].x;
+ i += 1;
+ }
+ }
+ }
+
+ let mut mag = [0.0; N];
+ for i in (0..N).step_by(2) {
+ let d2s = f64x2::from_array([
+ (r[i] * r[i]).horizontal_sum(),
+ (r[i + 1] * r[i + 1]).horizontal_sum(),
+ ]);
+ let dmags = f64x2::splat(dt) / (d2s * d2s.sqrt());
+ mag[i] = dmags[0];
+ mag[i + 1] = dmags[1];
+ }
+
+ let mut i = 0;
+ for j in 0..N_BODIES {
+ for k in j + 1..N_BODIES {
+ let f = r[i] * mag[i];
+ bodies[j].v -= f * bodies[k].mass;
+ bodies[k].v += f * bodies[j].mass;
+ i += 1
+ }
+ }
+ for body in bodies {
+ body.x += dt * body.v
+ }
+ }
+
+ pub fn run(n: usize) -> (f64, f64) {
+ let mut bodies = BODIES;
+ offset_momentum(&mut bodies);
+ let energy_before = energy(&bodies);
+ for _ in 0..n {
+ advance(&mut bodies, 0.01);
+ }
+ let energy_after = energy(&bodies);
+
+ (energy_before, energy_after)
+ }
+}
+
+#[cfg(feature = "std")]
+#[cfg(test)]
+mod tests {
+ // Good enough for demonstration purposes, not going for strictness here.
+ fn approx_eq_f64(a: f64, b: f64) -> bool {
+ (a - b).abs() < 0.00001
+ }
+ #[test]
+ fn test() {
+ const OUTPUT: [f64; 2] = [-0.169075164, -0.169087605];
+ let (energy_before, energy_after) = super::nbody::run(1000);
+ assert!(approx_eq_f64(energy_before, OUTPUT[0]));
+ assert!(approx_eq_f64(energy_after, OUTPUT[1]));
+ }
+}
+
+fn main() {
+ #[cfg(feature = "std")]
+ {
+ let (energy_before, energy_after) = nbody::run(1000);
+ println!("Energy before: {}", energy_before);
+ println!("Energy after: {}", energy_after);
+ }
+}
--- /dev/null
+use crate::simd::intrinsics;
+use crate::simd::{LaneCount, Mask, Simd, SimdElement, SupportedLaneCount};
+
+impl<T, const LANES: usize> Simd<T, LANES>
+where
+ T: SimdElement + PartialEq,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ /// Test if each lane is equal to the corresponding lane in `other`.
+ #[inline]
+ pub fn lanes_eq(self, other: Self) -> Mask<T::Mask, LANES> {
+ unsafe { Mask::from_int_unchecked(intrinsics::simd_eq(self, other)) }
+ }
+
+ /// Test if each lane is not equal to the corresponding lane in `other`.
+ #[inline]
+ pub fn lanes_ne(self, other: Self) -> Mask<T::Mask, LANES> {
+ unsafe { Mask::from_int_unchecked(intrinsics::simd_ne(self, other)) }
+ }
+}
+
+impl<T, const LANES: usize> Simd<T, LANES>
+where
+ T: SimdElement + PartialOrd,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ /// Test if each lane is less than the corresponding lane in `other`.
+ #[inline]
+ pub fn lanes_lt(self, other: Self) -> Mask<T::Mask, LANES> {
+ unsafe { Mask::from_int_unchecked(intrinsics::simd_lt(self, other)) }
+ }
+
+ /// Test if each lane is greater than the corresponding lane in `other`.
+ #[inline]
+ pub fn lanes_gt(self, other: Self) -> Mask<T::Mask, LANES> {
+ unsafe { Mask::from_int_unchecked(intrinsics::simd_gt(self, other)) }
+ }
+
+ /// Test if each lane is less than or equal to the corresponding lane in `other`.
+ #[inline]
+ pub fn lanes_le(self, other: Self) -> Mask<T::Mask, LANES> {
+ unsafe { Mask::from_int_unchecked(intrinsics::simd_le(self, other)) }
+ }
+
+ /// Test if each lane is greater than or equal to the corresponding lane in `other`.
+ #[inline]
+ pub fn lanes_ge(self, other: Self) -> Mask<T::Mask, LANES> {
+ unsafe { Mask::from_int_unchecked(intrinsics::simd_ge(self, other)) }
+ }
+}
--- /dev/null
+Portable SIMD module.
+
+This module offers a portable abstraction for SIMD operations
+that is not bound to any particular hardware architecture.
--- /dev/null
+use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount};
+use core::fmt;
+
+macro_rules! impl_fmt_trait {
+ { $($trait:ident,)* } => {
+ $(
+ impl<T, const LANES: usize> fmt::$trait for Simd<T, LANES>
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ T: SimdElement + fmt::$trait,
+ {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ #[repr(transparent)]
+ struct Wrapper<'a, T: fmt::$trait>(&'a T);
+
+ impl<T: fmt::$trait> fmt::Debug for Wrapper<'_, T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.0.fmt(f)
+ }
+ }
+
+ f.debug_list()
+ .entries(self.as_array().iter().map(|x| Wrapper(x)))
+ .finish()
+ }
+ }
+ )*
+ }
+}
+
+impl_fmt_trait! {
+ Debug,
+ Binary,
+ LowerExp,
+ UpperExp,
+ Octal,
+ LowerHex,
+ UpperHex,
+}
--- /dev/null
+//! This module contains the LLVM intrinsics bindings that provide the functionality for this
+//! crate.
+//!
+//! The LLVM assembly language is documented here: <https://llvm.org/docs/LangRef.html>
+
+/// These intrinsics aren't linked directly from LLVM and are mostly undocumented, however they are
+/// simply lowered to the matching LLVM instructions by the compiler. The associated instruction
+/// is documented alongside each intrinsic.
+extern "platform-intrinsic" {
+ /// add/fadd
+ pub(crate) fn simd_add<T>(x: T, y: T) -> T;
+
+ /// sub/fsub
+ pub(crate) fn simd_sub<T>(x: T, y: T) -> T;
+
+ /// mul/fmul
+ pub(crate) fn simd_mul<T>(x: T, y: T) -> T;
+
+ /// udiv/sdiv/fdiv
+ pub(crate) fn simd_div<T>(x: T, y: T) -> T;
+
+ /// urem/srem/frem
+ pub(crate) fn simd_rem<T>(x: T, y: T) -> T;
+
+ /// shl
+ pub(crate) fn simd_shl<T>(x: T, y: T) -> T;
+
+ /// lshr/ashr
+ pub(crate) fn simd_shr<T>(x: T, y: T) -> T;
+
+ /// and
+ pub(crate) fn simd_and<T>(x: T, y: T) -> T;
+
+ /// or
+ pub(crate) fn simd_or<T>(x: T, y: T) -> T;
+
+ /// xor
+ pub(crate) fn simd_xor<T>(x: T, y: T) -> T;
+
+ /// fptoui/fptosi/uitofp/sitofp
+ pub(crate) fn simd_cast<T, U>(x: T) -> U;
+
+ /// neg/fneg
+ pub(crate) fn simd_neg<T>(x: T) -> T;
+
+ /// fabs
+ pub(crate) fn simd_fabs<T>(x: T) -> T;
+
+ pub(crate) fn simd_eq<T, U>(x: T, y: T) -> U;
+ pub(crate) fn simd_ne<T, U>(x: T, y: T) -> U;
+ pub(crate) fn simd_lt<T, U>(x: T, y: T) -> U;
+ pub(crate) fn simd_le<T, U>(x: T, y: T) -> U;
+ pub(crate) fn simd_gt<T, U>(x: T, y: T) -> U;
+ pub(crate) fn simd_ge<T, U>(x: T, y: T) -> U;
+
+ // shufflevector
+ pub(crate) fn simd_shuffle<T, U, V>(x: T, y: T, idx: U) -> V;
+
+ pub(crate) fn simd_gather<T, U, V>(val: T, ptr: U, mask: V) -> T;
+ pub(crate) fn simd_scatter<T, U, V>(val: T, ptr: U, mask: V);
+
+ // {s,u}add.sat
+ pub(crate) fn simd_saturating_add<T>(x: T, y: T) -> T;
+
+ // {s,u}sub.sat
+ pub(crate) fn simd_saturating_sub<T>(x: T, y: T) -> T;
+
+ // reductions
+ pub(crate) fn simd_reduce_add_ordered<T, U>(x: T, y: U) -> U;
+ pub(crate) fn simd_reduce_mul_ordered<T, U>(x: T, y: U) -> U;
+ #[allow(unused)]
+ pub(crate) fn simd_reduce_all<T>(x: T) -> bool;
+ #[allow(unused)]
+ pub(crate) fn simd_reduce_any<T>(x: T) -> bool;
+ pub(crate) fn simd_reduce_max<T, U>(x: T) -> U;
+ pub(crate) fn simd_reduce_min<T, U>(x: T) -> U;
+ pub(crate) fn simd_reduce_and<T, U>(x: T) -> U;
+ pub(crate) fn simd_reduce_or<T, U>(x: T) -> U;
+ pub(crate) fn simd_reduce_xor<T, U>(x: T) -> U;
+
+ // truncate integer vector to bitmask
+ #[allow(unused)]
+ pub(crate) fn simd_bitmask<T, U>(x: T) -> U;
+
+ // select
+ pub(crate) fn simd_select<M, T>(m: M, a: T, b: T) -> T;
+ #[allow(unused)]
+ pub(crate) fn simd_select_bitmask<M, T>(m: M, a: T, b: T) -> T;
+}
+
+#[cfg(feature = "std")]
+mod std {
+ extern "platform-intrinsic" {
+ // ceil
+ pub(crate) fn simd_ceil<T>(x: T) -> T;
+
+ // floor
+ pub(crate) fn simd_floor<T>(x: T) -> T;
+
+ // round
+ pub(crate) fn simd_round<T>(x: T) -> T;
+
+ // trunc
+ pub(crate) fn simd_trunc<T>(x: T) -> T;
+
+ // fsqrt
+ pub(crate) fn simd_fsqrt<T>(x: T) -> T;
+
+ // fma
+ pub(crate) fn simd_fma<T>(x: T, y: T, z: T) -> T;
+ }
+}
+
+#[cfg(feature = "std")]
+pub(crate) use crate::simd::intrinsics::std::*;
--- /dev/null
+use crate::simd::{LaneCount, Simd, SupportedLaneCount};
+use core::{
+ iter::{Product, Sum},
+ ops::{Add, Mul},
+};
+
+macro_rules! impl_traits {
+ { $type:ty } => {
+ impl<const LANES: usize> Sum<Self> for Simd<$type, LANES>
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
+ iter.fold(Simd::splat(0 as $type), Add::add)
+ }
+ }
+
+ impl<const LANES: usize> Product<Self> for Simd<$type, LANES>
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
+ iter.fold(Simd::splat(1 as $type), Mul::mul)
+ }
+ }
+
+ impl<'a, const LANES: usize> Sum<&'a Self> for Simd<$type, LANES>
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
+ iter.fold(Simd::splat(0 as $type), Add::add)
+ }
+ }
+
+ impl<'a, const LANES: usize> Product<&'a Self> for Simd<$type, LANES>
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ fn product<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
+ iter.fold(Simd::splat(1 as $type), Mul::mul)
+ }
+ }
+ }
+}
+
+impl_traits! { f32 }
+impl_traits! { f64 }
+impl_traits! { u8 }
+impl_traits! { u16 }
+impl_traits! { u32 }
+impl_traits! { u64 }
+impl_traits! { usize }
+impl_traits! { i8 }
+impl_traits! { i16 }
+impl_traits! { i32 }
+impl_traits! { i64 }
+impl_traits! { isize }
--- /dev/null
+mod sealed {
+ pub trait Sealed {}
+}
+use sealed::Sealed;
+
+/// A type representing a vector lane count.
+pub struct LaneCount<const LANES: usize>;
+
+impl<const LANES: usize> LaneCount<LANES> {
+ /// The number of bytes in a bitmask with this many lanes.
+ pub const BITMASK_LEN: usize = (LANES + 7) / 8;
+}
+
+/// Helper trait for vector lane counts.
+pub trait SupportedLaneCount: Sealed {
+ #[doc(hidden)]
+ type BitMask: Copy + Default + AsRef<[u8]> + AsMut<[u8]>;
+
+ #[doc(hidden)]
+ type IntBitMask;
+}
+
+impl<const LANES: usize> Sealed for LaneCount<LANES> {}
+
+impl SupportedLaneCount for LaneCount<1> {
+ type BitMask = [u8; 1];
+ type IntBitMask = u8;
+}
+impl SupportedLaneCount for LaneCount<2> {
+ type BitMask = [u8; 1];
+ type IntBitMask = u8;
+}
+impl SupportedLaneCount for LaneCount<4> {
+ type BitMask = [u8; 1];
+ type IntBitMask = u8;
+}
+impl SupportedLaneCount for LaneCount<8> {
+ type BitMask = [u8; 1];
+ type IntBitMask = u8;
+}
+impl SupportedLaneCount for LaneCount<16> {
+ type BitMask = [u8; 2];
+ type IntBitMask = u16;
+}
+impl SupportedLaneCount for LaneCount<32> {
+ type BitMask = [u8; 4];
+ type IntBitMask = u32;
+}
--- /dev/null
+#![cfg_attr(not(feature = "std"), no_std)]
+#![feature(
+ const_fn_trait_bound,
+ decl_macro,
+ platform_intrinsics,
+ repr_simd,
+ simd_ffi,
+ staged_api,
+ stdsimd
+)]
+#![cfg_attr(feature = "generic_const_exprs", feature(generic_const_exprs))]
+#![cfg_attr(feature = "generic_const_exprs", allow(incomplete_features))]
+#![warn(missing_docs)]
+#![deny(unsafe_op_in_unsafe_fn)]
+#![unstable(feature = "portable_simd", issue = "86656")]
+//! Portable SIMD module.
+
+#[path = "mod.rs"]
+mod core_simd;
+pub use self::core_simd::simd;
+pub use simd::*;
--- /dev/null
+//! Types and traits associated with masking lanes of vectors.
+//! Types representing
+#![allow(non_camel_case_types)]
+
+#[cfg_attr(
+ not(all(target_arch = "x86_64", target_feature = "avx512f")),
+ path = "masks/full_masks.rs"
+)]
+#[cfg_attr(
+ all(target_arch = "x86_64", target_feature = "avx512f"),
+ path = "masks/bitmask.rs"
+)]
+mod mask_impl;
+
+use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount};
+use core::cmp::Ordering;
+use core::fmt;
+
+mod sealed {
+ use super::*;
+
+ /// Not only does this seal the `MaskElement` trait, but these functions prevent other traits
+ /// from bleeding into the parent bounds.
+ ///
+ /// For example, `eq` could be provided by requiring `MaskElement: PartialEq`, but that would
+ /// prevent us from ever removing that bound, or from implementing `MaskElement` on
+ /// non-`PartialEq` types in the future.
+ pub trait Sealed {
+ fn valid<const LANES: usize>(values: Simd<Self, LANES>) -> bool
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ Self: SimdElement;
+
+ fn eq(self, other: Self) -> bool;
+
+ const TRUE: Self;
+
+ const FALSE: Self;
+ }
+}
+use sealed::Sealed;
+
+/// Marker trait for types that may be used as SIMD mask elements.
+pub unsafe trait MaskElement: SimdElement + Sealed {}
+
+macro_rules! impl_element {
+ { $ty:ty } => {
+ impl Sealed for $ty {
+ fn valid<const LANES: usize>(value: Simd<Self, LANES>) -> bool
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ (value.lanes_eq(Simd::splat(0)) | value.lanes_eq(Simd::splat(-1))).all()
+ }
+
+ fn eq(self, other: Self) -> bool { self == other }
+
+ const TRUE: Self = -1;
+ const FALSE: Self = 0;
+ }
+
+ unsafe impl MaskElement for $ty {}
+ }
+}
+
+impl_element! { i8 }
+impl_element! { i16 }
+impl_element! { i32 }
+impl_element! { i64 }
+impl_element! { isize }
+
+/// A SIMD vector mask for `LANES` elements of width specified by `Element`.
+///
+/// The layout of this type is unspecified.
+#[repr(transparent)]
+pub struct Mask<T, const LANES: usize>(mask_impl::Mask<T, LANES>)
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount;
+
+impl<T, const LANES: usize> Copy for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+}
+
+impl<T, const LANES: usize> Clone for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+impl<T, const LANES: usize> Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ /// Construct a mask by setting all lanes to the given value.
+ pub fn splat(value: bool) -> Self {
+ Self(mask_impl::Mask::splat(value))
+ }
+
+ /// Converts an array to a SIMD vector.
+ pub fn from_array(array: [bool; LANES]) -> Self {
+ let mut vector = Self::splat(false);
+ for (i, v) in array.iter().enumerate() {
+ vector.set(i, *v);
+ }
+ vector
+ }
+
+ /// Converts a SIMD vector to an array.
+ pub fn to_array(self) -> [bool; LANES] {
+ let mut array = [false; LANES];
+ for (i, v) in array.iter_mut().enumerate() {
+ *v = self.test(i);
+ }
+ array
+ }
+
+ /// Converts a vector of integers to a mask, where 0 represents `false` and -1
+ /// represents `true`.
+ ///
+ /// # Safety
+ /// All lanes must be either 0 or -1.
+ #[inline]
+ pub unsafe fn from_int_unchecked(value: Simd<T, LANES>) -> Self {
+ unsafe { Self(mask_impl::Mask::from_int_unchecked(value)) }
+ }
+
+ /// Converts a vector of integers to a mask, where 0 represents `false` and -1
+ /// represents `true`.
+ ///
+ /// # Panics
+ /// Panics if any lane is not 0 or -1.
+ #[inline]
+ pub fn from_int(value: Simd<T, LANES>) -> Self {
+ assert!(T::valid(value), "all values must be either 0 or -1",);
+ unsafe { Self::from_int_unchecked(value) }
+ }
+
+ /// Converts the mask to a vector of integers, where 0 represents `false` and -1
+ /// represents `true`.
+ #[inline]
+ pub fn to_int(self) -> Simd<T, LANES> {
+ self.0.to_int()
+ }
+
+ /// Tests the value of the specified lane.
+ ///
+ /// # Safety
+ /// `lane` must be less than `LANES`.
+ #[inline]
+ pub unsafe fn test_unchecked(&self, lane: usize) -> bool {
+ unsafe { self.0.test_unchecked(lane) }
+ }
+
+ /// Tests the value of the specified lane.
+ ///
+ /// # Panics
+ /// Panics if `lane` is greater than or equal to the number of lanes in the vector.
+ #[inline]
+ pub fn test(&self, lane: usize) -> bool {
+ assert!(lane < LANES, "lane index out of range");
+ unsafe { self.test_unchecked(lane) }
+ }
+
+ /// Sets the value of the specified lane.
+ ///
+ /// # Safety
+ /// `lane` must be less than `LANES`.
+ #[inline]
+ pub unsafe fn set_unchecked(&mut self, lane: usize, value: bool) {
+ unsafe {
+ self.0.set_unchecked(lane, value);
+ }
+ }
+
+ /// Sets the value of the specified lane.
+ ///
+ /// # Panics
+ /// Panics if `lane` is greater than or equal to the number of lanes in the vector.
+ #[inline]
+ pub fn set(&mut self, lane: usize, value: bool) {
+ assert!(lane < LANES, "lane index out of range");
+ unsafe {
+ self.set_unchecked(lane, value);
+ }
+ }
+
+ /// Convert this mask to a bitmask, with one bit set per lane.
+ #[cfg(feature = "generic_const_exprs")]
+ pub fn to_bitmask(self) -> [u8; LaneCount::<LANES>::BITMASK_LEN] {
+ self.0.to_bitmask()
+ }
+
+ /// Convert a bitmask to a mask.
+ #[cfg(feature = "generic_const_exprs")]
+ pub fn from_bitmask(bitmask: [u8; LaneCount::<LANES>::BITMASK_LEN]) -> Self {
+ Self(mask_impl::Mask::from_bitmask(bitmask))
+ }
+
+ /// Returns true if any lane is set, or false otherwise.
+ #[inline]
+ pub fn any(self) -> bool {
+ self.0.any()
+ }
+
+ /// Returns true if all lanes are set, or false otherwise.
+ #[inline]
+ pub fn all(self) -> bool {
+ self.0.all()
+ }
+}
+
+// vector/array conversion
+impl<T, const LANES: usize> From<[bool; LANES]> for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ fn from(array: [bool; LANES]) -> Self {
+ Self::from_array(array)
+ }
+}
+
+impl<T, const LANES: usize> From<Mask<T, LANES>> for [bool; LANES]
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ fn from(vector: Mask<T, LANES>) -> Self {
+ vector.to_array()
+ }
+}
+
+impl<T, const LANES: usize> Default for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ #[inline]
+ fn default() -> Self {
+ Self::splat(false)
+ }
+}
+
+impl<T, const LANES: usize> PartialEq for Mask<T, LANES>
+where
+ T: MaskElement + PartialEq,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ #[inline]
+ fn eq(&self, other: &Self) -> bool {
+ self.0 == other.0
+ }
+}
+
+impl<T, const LANES: usize> PartialOrd for Mask<T, LANES>
+where
+ T: MaskElement + PartialOrd,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ #[inline]
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ self.0.partial_cmp(&other.0)
+ }
+}
+
+impl<T, const LANES: usize> fmt::Debug for Mask<T, LANES>
+where
+ T: MaskElement + fmt::Debug,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_list()
+ .entries((0..LANES).map(|lane| self.test(lane)))
+ .finish()
+ }
+}
+
+impl<T, const LANES: usize> core::ops::BitAnd for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ type Output = Self;
+ #[inline]
+ fn bitand(self, rhs: Self) -> Self {
+ Self(self.0 & rhs.0)
+ }
+}
+
+impl<T, const LANES: usize> core::ops::BitAnd<bool> for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ type Output = Self;
+ #[inline]
+ fn bitand(self, rhs: bool) -> Self {
+ self & Self::splat(rhs)
+ }
+}
+
+impl<T, const LANES: usize> core::ops::BitAnd<Mask<T, LANES>> for bool
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ type Output = Mask<T, LANES>;
+ #[inline]
+ fn bitand(self, rhs: Mask<T, LANES>) -> Mask<T, LANES> {
+ Mask::splat(self) & rhs
+ }
+}
+
+impl<T, const LANES: usize> core::ops::BitOr for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ type Output = Self;
+ #[inline]
+ fn bitor(self, rhs: Self) -> Self {
+ Self(self.0 | rhs.0)
+ }
+}
+
+impl<T, const LANES: usize> core::ops::BitOr<bool> for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ type Output = Self;
+ #[inline]
+ fn bitor(self, rhs: bool) -> Self {
+ self | Self::splat(rhs)
+ }
+}
+
+impl<T, const LANES: usize> core::ops::BitOr<Mask<T, LANES>> for bool
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ type Output = Mask<T, LANES>;
+ #[inline]
+ fn bitor(self, rhs: Mask<T, LANES>) -> Mask<T, LANES> {
+ Mask::splat(self) | rhs
+ }
+}
+
+impl<T, const LANES: usize> core::ops::BitXor for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ type Output = Self;
+ #[inline]
+ fn bitxor(self, rhs: Self) -> Self::Output {
+ Self(self.0 ^ rhs.0)
+ }
+}
+
+impl<T, const LANES: usize> core::ops::BitXor<bool> for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ type Output = Self;
+ #[inline]
+ fn bitxor(self, rhs: bool) -> Self::Output {
+ self ^ Self::splat(rhs)
+ }
+}
+
+impl<T, const LANES: usize> core::ops::BitXor<Mask<T, LANES>> for bool
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ type Output = Mask<T, LANES>;
+ #[inline]
+ fn bitxor(self, rhs: Mask<T, LANES>) -> Self::Output {
+ Mask::splat(self) ^ rhs
+ }
+}
+
+impl<T, const LANES: usize> core::ops::Not for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ type Output = Mask<T, LANES>;
+ #[inline]
+ fn not(self) -> Self::Output {
+ Self(!self.0)
+ }
+}
+
+impl<T, const LANES: usize> core::ops::BitAndAssign for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ #[inline]
+ fn bitand_assign(&mut self, rhs: Self) {
+ self.0 = self.0 & rhs.0;
+ }
+}
+
+impl<T, const LANES: usize> core::ops::BitAndAssign<bool> for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ #[inline]
+ fn bitand_assign(&mut self, rhs: bool) {
+ *self &= Self::splat(rhs);
+ }
+}
+
+impl<T, const LANES: usize> core::ops::BitOrAssign for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ #[inline]
+ fn bitor_assign(&mut self, rhs: Self) {
+ self.0 = self.0 | rhs.0;
+ }
+}
+
+impl<T, const LANES: usize> core::ops::BitOrAssign<bool> for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ #[inline]
+ fn bitor_assign(&mut self, rhs: bool) {
+ *self |= Self::splat(rhs);
+ }
+}
+
+impl<T, const LANES: usize> core::ops::BitXorAssign for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ #[inline]
+ fn bitxor_assign(&mut self, rhs: Self) {
+ self.0 = self.0 ^ rhs.0;
+ }
+}
+
+impl<T, const LANES: usize> core::ops::BitXorAssign<bool> for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ #[inline]
+ fn bitxor_assign(&mut self, rhs: bool) {
+ *self ^= Self::splat(rhs);
+ }
+}
+
+/// Vector of eight 8-bit masks
+pub type mask8x8 = Mask<i8, 8>;
+
+/// Vector of 16 8-bit masks
+pub type mask8x16 = Mask<i8, 16>;
+
+/// Vector of 32 8-bit masks
+pub type mask8x32 = Mask<i8, 32>;
+
+/// Vector of 16 8-bit masks
+pub type mask8x64 = Mask<i8, 64>;
+
+/// Vector of four 16-bit masks
+pub type mask16x4 = Mask<i16, 4>;
+
+/// Vector of eight 16-bit masks
+pub type mask16x8 = Mask<i16, 8>;
+
+/// Vector of 16 16-bit masks
+pub type mask16x16 = Mask<i16, 16>;
+
+/// Vector of 32 16-bit masks
+pub type mask16x32 = Mask<i32, 32>;
+
+/// Vector of two 32-bit masks
+pub type mask32x2 = Mask<i32, 2>;
+
+/// Vector of four 32-bit masks
+pub type mask32x4 = Mask<i32, 4>;
+
+/// Vector of eight 32-bit masks
+pub type mask32x8 = Mask<i32, 8>;
+
+/// Vector of 16 32-bit masks
+pub type mask32x16 = Mask<i32, 16>;
+
+/// Vector of two 64-bit masks
+pub type mask64x2 = Mask<i64, 2>;
+
+/// Vector of four 64-bit masks
+pub type mask64x4 = Mask<i64, 4>;
+
+/// Vector of eight 64-bit masks
+pub type mask64x8 = Mask<i64, 8>;
+
+/// Vector of two pointer-width masks
+pub type masksizex2 = Mask<isize, 2>;
+
+/// Vector of four pointer-width masks
+pub type masksizex4 = Mask<isize, 4>;
+
+/// Vector of eight pointer-width masks
+pub type masksizex8 = Mask<isize, 8>;
+
+macro_rules! impl_from {
+ { $from:ty => $($to:ty),* } => {
+ $(
+ impl<const LANES: usize> From<Mask<$from, LANES>> for Mask<$to, LANES>
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ fn from(value: Mask<$from, LANES>) -> Self {
+ Self(value.0.convert())
+ }
+ }
+ )*
+ }
+}
+impl_from! { i8 => i16, i32, i64, isize }
+impl_from! { i16 => i32, i64, isize, i8 }
+impl_from! { i32 => i64, isize, i8, i16 }
+impl_from! { i64 => isize, i8, i16, i32 }
+impl_from! { isize => i8, i16, i32, i64 }
--- /dev/null
+use super::MaskElement;
+use crate::simd::intrinsics;
+use crate::simd::{LaneCount, Simd, SupportedLaneCount};
+use core::marker::PhantomData;
+
+/// A mask where each lane is represented by a single bit.
+#[repr(transparent)]
+pub struct Mask<T, const LANES: usize>(
+ <LaneCount<LANES> as SupportedLaneCount>::BitMask,
+ PhantomData<T>,
+)
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount;
+
+impl<T, const LANES: usize> Copy for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+}
+
+impl<T, const LANES: usize> Clone for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+impl<T, const LANES: usize> PartialEq for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ fn eq(&self, other: &Self) -> bool {
+ self.0.as_ref() == other.0.as_ref()
+ }
+}
+
+impl<T, const LANES: usize> PartialOrd for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
+ self.0.as_ref().partial_cmp(other.0.as_ref())
+ }
+}
+
+impl<T, const LANES: usize> Eq for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+}
+
+impl<T, const LANES: usize> Ord for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ fn cmp(&self, other: &Self) -> core::cmp::Ordering {
+ self.0.as_ref().cmp(other.0.as_ref())
+ }
+}
+
+impl<T, const LANES: usize> Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ #[inline]
+ pub fn splat(value: bool) -> Self {
+ let mut mask = <LaneCount<LANES> as SupportedLaneCount>::BitMask::default();
+ if value {
+ mask.as_mut().fill(u8::MAX)
+ } else {
+ mask.as_mut().fill(u8::MIN)
+ }
+ if LANES % 8 > 0 {
+ *mask.as_mut().last_mut().unwrap() &= u8::MAX >> (8 - LANES % 8);
+ }
+ Self(mask, PhantomData)
+ }
+
+ #[inline]
+ pub unsafe fn test_unchecked(&self, lane: usize) -> bool {
+ (self.0.as_ref()[lane / 8] >> (lane % 8)) & 0x1 > 0
+ }
+
+ #[inline]
+ pub unsafe fn set_unchecked(&mut self, lane: usize, value: bool) {
+ unsafe {
+ self.0.as_mut()[lane / 8] ^= ((value ^ self.test_unchecked(lane)) as u8) << (lane % 8)
+ }
+ }
+
+ #[inline]
+ pub fn to_int(self) -> Simd<T, LANES> {
+ unsafe {
+ let mask: <LaneCount<LANES> as SupportedLaneCount>::IntBitMask =
+ core::mem::transmute_copy(&self);
+ intrinsics::simd_select_bitmask(mask, Simd::splat(T::TRUE), Simd::splat(T::FALSE))
+ }
+ }
+
+ #[inline]
+ pub unsafe fn from_int_unchecked(value: Simd<T, LANES>) -> Self {
+ // TODO remove the transmute when rustc is more flexible
+ assert_eq!(
+ core::mem::size_of::<<LaneCount::<LANES> as SupportedLaneCount>::BitMask>(),
+ core::mem::size_of::<<LaneCount::<LANES> as SupportedLaneCount>::IntBitMask>(),
+ );
+ unsafe {
+ let mask: <LaneCount<LANES> as SupportedLaneCount>::IntBitMask =
+ intrinsics::simd_bitmask(value);
+ Self(core::mem::transmute_copy(&mask), PhantomData)
+ }
+ }
+
+ #[cfg(feature = "generic_const_exprs")]
+ #[inline]
+ pub fn to_bitmask(self) -> [u8; LaneCount::<LANES>::BITMASK_LEN] {
+ // Safety: these are the same type and we are laundering the generic
+ unsafe { core::mem::transmute_copy(&self.0) }
+ }
+
+ #[cfg(feature = "generic_const_exprs")]
+ #[inline]
+ pub fn from_bitmask(bitmask: [u8; LaneCount::<LANES>::BITMASK_LEN]) -> Self {
+ // Safety: these are the same type and we are laundering the generic
+ Self(unsafe { core::mem::transmute_copy(&bitmask) }, PhantomData)
+ }
+
+ #[inline]
+ pub fn convert<U>(self) -> Mask<U, LANES>
+ where
+ U: MaskElement,
+ {
+ unsafe { core::mem::transmute_copy(&self) }
+ }
+
+ #[inline]
+ pub fn any(self) -> bool {
+ self != Self::splat(false)
+ }
+
+ #[inline]
+ pub fn all(self) -> bool {
+ self == Self::splat(true)
+ }
+}
+
+impl<T, const LANES: usize> core::ops::BitAnd for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+ <LaneCount<LANES> as SupportedLaneCount>::BitMask: AsRef<[u8]> + AsMut<[u8]>,
+{
+ type Output = Self;
+ #[inline]
+ fn bitand(mut self, rhs: Self) -> Self {
+ for (l, r) in self.0.as_mut().iter_mut().zip(rhs.0.as_ref().iter()) {
+ *l &= r;
+ }
+ self
+ }
+}
+
+impl<T, const LANES: usize> core::ops::BitOr for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+ <LaneCount<LANES> as SupportedLaneCount>::BitMask: AsRef<[u8]> + AsMut<[u8]>,
+{
+ type Output = Self;
+ #[inline]
+ fn bitor(mut self, rhs: Self) -> Self {
+ for (l, r) in self.0.as_mut().iter_mut().zip(rhs.0.as_ref().iter()) {
+ *l |= r;
+ }
+ self
+ }
+}
+
+impl<T, const LANES: usize> core::ops::BitXor for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ type Output = Self;
+ #[inline]
+ fn bitxor(mut self, rhs: Self) -> Self::Output {
+ for (l, r) in self.0.as_mut().iter_mut().zip(rhs.0.as_ref().iter()) {
+ *l ^= r;
+ }
+ self
+ }
+}
+
+impl<T, const LANES: usize> core::ops::Not for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ type Output = Self;
+ #[inline]
+ fn not(mut self) -> Self::Output {
+ for x in self.0.as_mut() {
+ *x = !*x;
+ }
+ if LANES % 8 > 0 {
+ *self.0.as_mut().last_mut().unwrap() &= u8::MAX >> (8 - LANES % 8);
+ }
+ self
+ }
+}
--- /dev/null
+//! Masks that take up full SIMD vector registers.
+
+use super::MaskElement;
+use crate::simd::intrinsics;
+use crate::simd::{LaneCount, Simd, SupportedLaneCount};
+
+#[repr(transparent)]
+pub struct Mask<T, const LANES: usize>(Simd<T, LANES>)
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount;
+
+impl<T, const LANES: usize> Copy for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+}
+
+impl<T, const LANES: usize> Clone for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ #[inline]
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+impl<T, const LANES: usize> PartialEq for Mask<T, LANES>
+where
+ T: MaskElement + PartialEq,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ fn eq(&self, other: &Self) -> bool {
+ self.0.eq(&other.0)
+ }
+}
+
+impl<T, const LANES: usize> PartialOrd for Mask<T, LANES>
+where
+ T: MaskElement + PartialOrd,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
+ self.0.partial_cmp(&other.0)
+ }
+}
+
+impl<T, const LANES: usize> Eq for Mask<T, LANES>
+where
+ T: MaskElement + Eq,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+}
+
+impl<T, const LANES: usize> Ord for Mask<T, LANES>
+where
+ T: MaskElement + Ord,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ fn cmp(&self, other: &Self) -> core::cmp::Ordering {
+ self.0.cmp(&other.0)
+ }
+}
+
+impl<T, const LANES: usize> Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ pub fn splat(value: bool) -> Self {
+ Self(Simd::splat(if value { T::TRUE } else { T::FALSE }))
+ }
+
+ #[inline]
+ pub unsafe fn test_unchecked(&self, lane: usize) -> bool {
+ T::eq(self.0[lane], T::TRUE)
+ }
+
+ #[inline]
+ pub unsafe fn set_unchecked(&mut self, lane: usize, value: bool) {
+ self.0[lane] = if value { T::TRUE } else { T::FALSE }
+ }
+
+ #[inline]
+ pub fn to_int(self) -> Simd<T, LANES> {
+ self.0
+ }
+
+ #[inline]
+ pub unsafe fn from_int_unchecked(value: Simd<T, LANES>) -> Self {
+ Self(value)
+ }
+
+ #[inline]
+ pub fn convert<U>(self) -> Mask<U, LANES>
+ where
+ U: MaskElement,
+ {
+ unsafe { Mask(intrinsics::simd_cast(self.0)) }
+ }
+
+ #[cfg(feature = "generic_const_exprs")]
+ #[inline]
+ pub fn to_bitmask(self) -> [u8; LaneCount::<LANES>::BITMASK_LEN] {
+ unsafe {
+ // TODO remove the transmute when rustc can use arrays of u8 as bitmasks
+ assert_eq!(
+ core::mem::size_of::<<LaneCount::<LANES> as SupportedLaneCount>::IntBitMask>(),
+ LaneCount::<LANES>::BITMASK_LEN,
+ );
+ let bitmask: <LaneCount<LANES> as SupportedLaneCount>::IntBitMask =
+ intrinsics::simd_bitmask(self.0);
+ let mut bitmask: [u8; LaneCount::<LANES>::BITMASK_LEN] =
+ core::mem::transmute_copy(&bitmask);
+
+ // There is a bug where LLVM appears to implement this operation with the wrong
+ // bit order.
+ // TODO fix this in a better way
+ if cfg!(target_endian = "big") {
+ for x in bitmask.as_mut() {
+ *x = x.reverse_bits();
+ }
+ }
+
+ bitmask
+ }
+ }
+
+ #[cfg(feature = "generic_const_exprs")]
+ #[inline]
+ pub fn from_bitmask(mut bitmask: [u8; LaneCount::<LANES>::BITMASK_LEN]) -> Self {
+ unsafe {
+ // There is a bug where LLVM appears to implement this operation with the wrong
+ // bit order.
+ // TODO fix this in a better way
+ if cfg!(target_endian = "big") {
+ for x in bitmask.as_mut() {
+ *x = x.reverse_bits();
+ }
+ }
+
+ // TODO remove the transmute when rustc can use arrays of u8 as bitmasks
+ assert_eq!(
+ core::mem::size_of::<<LaneCount::<LANES> as SupportedLaneCount>::IntBitMask>(),
+ LaneCount::<LANES>::BITMASK_LEN,
+ );
+ let bitmask: <LaneCount<LANES> as SupportedLaneCount>::IntBitMask =
+ core::mem::transmute_copy(&bitmask);
+
+ Self::from_int_unchecked(intrinsics::simd_select_bitmask(
+ bitmask,
+ Self::splat(true).to_int(),
+ Self::splat(false).to_int(),
+ ))
+ }
+ }
+
+ #[inline]
+ pub fn any(self) -> bool {
+ unsafe { intrinsics::simd_reduce_any(self.to_int()) }
+ }
+
+ #[inline]
+ pub fn all(self) -> bool {
+ unsafe { intrinsics::simd_reduce_all(self.to_int()) }
+ }
+}
+
+impl<T, const LANES: usize> core::convert::From<Mask<T, LANES>> for Simd<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ fn from(value: Mask<T, LANES>) -> Self {
+ value.0
+ }
+}
+
+impl<T, const LANES: usize> core::ops::BitAnd for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ type Output = Self;
+ #[inline]
+ fn bitand(self, rhs: Self) -> Self {
+ unsafe { Self(intrinsics::simd_and(self.0, rhs.0)) }
+ }
+}
+
+impl<T, const LANES: usize> core::ops::BitOr for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ type Output = Self;
+ #[inline]
+ fn bitor(self, rhs: Self) -> Self {
+ unsafe { Self(intrinsics::simd_or(self.0, rhs.0)) }
+ }
+}
+
+impl<T, const LANES: usize> core::ops::BitXor for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ type Output = Self;
+ #[inline]
+ fn bitxor(self, rhs: Self) -> Self {
+ unsafe { Self(intrinsics::simd_xor(self.0, rhs.0)) }
+ }
+}
+
+impl<T, const LANES: usize> core::ops::Not for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ type Output = Self;
+ #[inline]
+ fn not(self) -> Self::Output {
+ Self::splat(true) ^ self
+ }
+}
--- /dev/null
+use crate::simd::intrinsics::{simd_saturating_add, simd_saturating_sub};
+use crate::simd::{LaneCount, Simd, SupportedLaneCount};
+
+macro_rules! impl_uint_arith {
+ ($($ty:ty),+) => {
+ $( impl<const LANES: usize> Simd<$ty, LANES> where LaneCount<LANES>: SupportedLaneCount {
+
+ /// Lanewise saturating add.
+ ///
+ /// # Examples
+ /// ```
+ /// # #![feature(portable_simd)]
+ /// # #[cfg(feature = "std")] use core_simd::Simd;
+ /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+ #[doc = concat!("# use core::", stringify!($ty), "::MAX;")]
+ /// let x = Simd::from_array([2, 1, 0, MAX]);
+ /// let max = Simd::splat(MAX);
+ /// let unsat = x + max;
+ /// let sat = x.saturating_add(max);
+ /// assert_eq!(x - 1, unsat);
+ /// assert_eq!(sat, max);
+ /// ```
+ #[inline]
+ pub fn saturating_add(self, second: Self) -> Self {
+ unsafe { simd_saturating_add(self, second) }
+ }
+
+ /// Lanewise saturating subtract.
+ ///
+ /// # Examples
+ /// ```
+ /// # #![feature(portable_simd)]
+ /// # #[cfg(feature = "std")] use core_simd::Simd;
+ /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+ #[doc = concat!("# use core::", stringify!($ty), "::MAX;")]
+ /// let x = Simd::from_array([2, 1, 0, MAX]);
+ /// let max = Simd::splat(MAX);
+ /// let unsat = x - max;
+ /// let sat = x.saturating_sub(max);
+ /// assert_eq!(unsat, x + 1);
+ /// assert_eq!(sat, Simd::splat(0));
+ #[inline]
+ pub fn saturating_sub(self, second: Self) -> Self {
+ unsafe { simd_saturating_sub(self, second) }
+ }
+ })+
+ }
+}
+
+macro_rules! impl_int_arith {
+ ($($ty:ty),+) => {
+ $( impl<const LANES: usize> Simd<$ty, LANES> where LaneCount<LANES>: SupportedLaneCount {
+
+ /// Lanewise saturating add.
+ ///
+ /// # Examples
+ /// ```
+ /// # #![feature(portable_simd)]
+ /// # #[cfg(feature = "std")] use core_simd::Simd;
+ /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+ #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")]
+ /// let x = Simd::from_array([MIN, 0, 1, MAX]);
+ /// let max = Simd::splat(MAX);
+ /// let unsat = x + max;
+ /// let sat = x.saturating_add(max);
+ /// assert_eq!(unsat, Simd::from_array([-1, MAX, MIN, -2]));
+ /// assert_eq!(sat, Simd::from_array([-1, MAX, MAX, MAX]));
+ /// ```
+ #[inline]
+ pub fn saturating_add(self, second: Self) -> Self {
+ unsafe { simd_saturating_add(self, second) }
+ }
+
+ /// Lanewise saturating subtract.
+ ///
+ /// # Examples
+ /// ```
+ /// # #![feature(portable_simd)]
+ /// # #[cfg(feature = "std")] use core_simd::Simd;
+ /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+ #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")]
+ /// let x = Simd::from_array([MIN, -2, -1, MAX]);
+ /// let max = Simd::splat(MAX);
+ /// let unsat = x - max;
+ /// let sat = x.saturating_sub(max);
+ /// assert_eq!(unsat, Simd::from_array([1, MAX, MIN, 0]));
+ /// assert_eq!(sat, Simd::from_array([MIN, MIN, MIN, 0]));
+ #[inline]
+ pub fn saturating_sub(self, second: Self) -> Self {
+ unsafe { simd_saturating_sub(self, second) }
+ }
+
+ /// Lanewise absolute value, implemented in Rust.
+ /// Every lane becomes its absolute value.
+ ///
+ /// # Examples
+ /// ```
+ /// # #![feature(portable_simd)]
+ /// # #[cfg(feature = "std")] use core_simd::Simd;
+ /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+ #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")]
+ /// let xs = Simd::from_array([MIN, MIN +1, -5, 0]);
+ /// assert_eq!(xs.abs(), Simd::from_array([MIN, MAX, 5, 0]));
+ /// ```
+ #[inline]
+ pub fn abs(self) -> Self {
+ const SHR: $ty = <$ty>::BITS as $ty - 1;
+ let m = self >> SHR;
+ (self^m) - m
+ }
+
+ /// Lanewise saturating absolute value, implemented in Rust.
+ /// As abs(), except the MIN value becomes MAX instead of itself.
+ ///
+ /// # Examples
+ /// ```
+ /// # #![feature(portable_simd)]
+ /// # #[cfg(feature = "std")] use core_simd::Simd;
+ /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+ #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")]
+ /// let xs = Simd::from_array([MIN, -2, 0, 3]);
+ /// let unsat = xs.abs();
+ /// let sat = xs.saturating_abs();
+ /// assert_eq!(unsat, Simd::from_array([MIN, 2, 0, 3]));
+ /// assert_eq!(sat, Simd::from_array([MAX, 2, 0, 3]));
+ /// ```
+ #[inline]
+ pub fn saturating_abs(self) -> Self {
+ // arith shift for -1 or 0 mask based on sign bit, giving 2s complement
+ const SHR: $ty = <$ty>::BITS as $ty - 1;
+ let m = self >> SHR;
+ (self^m).saturating_sub(m)
+ }
+
+ /// Lanewise saturating negation, implemented in Rust.
+ /// As neg(), except the MIN value becomes MAX instead of itself.
+ ///
+ /// # Examples
+ /// ```
+ /// # #![feature(portable_simd)]
+ /// # #[cfg(feature = "std")] use core_simd::Simd;
+ /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+ #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")]
+ /// let x = Simd::from_array([MIN, -2, 3, MAX]);
+ /// let unsat = -x;
+ /// let sat = x.saturating_neg();
+ /// assert_eq!(unsat, Simd::from_array([MIN, 2, -3, MIN + 1]));
+ /// assert_eq!(sat, Simd::from_array([MAX, 2, -3, MIN + 1]));
+ /// ```
+ #[inline]
+ pub fn saturating_neg(self) -> Self {
+ Self::splat(0).saturating_sub(self)
+ }
+ })+
+ }
+}
+
+impl_uint_arith! { u8, u16, u32, u64, usize }
+impl_int_arith! { i8, i16, i32, i64, isize }
--- /dev/null
+#[macro_use]
+mod reduction;
+
+#[macro_use]
+mod swizzle;
+
+pub(crate) mod intrinsics;
+
+#[cfg(feature = "generic_const_exprs")]
+mod to_bytes;
+
+mod comparisons;
+mod fmt;
+mod iter;
+mod lane_count;
+mod masks;
+mod math;
+mod ops;
+mod round;
+mod select;
+mod vector;
+mod vendor;
+
+#[doc = include_str!("core_simd_docs.md")]
+pub mod simd {
+ pub(crate) use crate::core_simd::intrinsics;
+
+ pub use crate::core_simd::lane_count::{LaneCount, SupportedLaneCount};
+ pub use crate::core_simd::masks::*;
+ pub use crate::core_simd::select::Select;
+ pub use crate::core_simd::swizzle::*;
+ pub use crate::core_simd::vector::*;
+}
--- /dev/null
+use crate::simd::intrinsics;
+use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount};
+
+impl<I, T, const LANES: usize> core::ops::Index<I> for Simd<T, LANES>
+where
+ T: SimdElement,
+ LaneCount<LANES>: SupportedLaneCount,
+ I: core::slice::SliceIndex<[T]>,
+{
+ type Output = I::Output;
+ fn index(&self, index: I) -> &Self::Output {
+ &self.as_array()[index]
+ }
+}
+
+impl<I, T, const LANES: usize> core::ops::IndexMut<I> for Simd<T, LANES>
+where
+ T: SimdElement,
+ LaneCount<LANES>: SupportedLaneCount,
+ I: core::slice::SliceIndex<[T]>,
+{
+ fn index_mut(&mut self, index: I) -> &mut Self::Output {
+ &mut self.as_mut_array()[index]
+ }
+}
+
+/// Checks if the right-hand side argument of a left- or right-shift would cause overflow.
+fn invalid_shift_rhs<T>(rhs: T) -> bool
+where
+ T: Default + PartialOrd + core::convert::TryFrom<usize>,
+ <T as core::convert::TryFrom<usize>>::Error: core::fmt::Debug,
+{
+ let bits_in_type = T::try_from(8 * core::mem::size_of::<T>()).unwrap();
+ rhs < T::default() || rhs >= bits_in_type
+}
+
+/// Automatically implements operators over references in addition to the provided operator.
+macro_rules! impl_ref_ops {
+ // binary op
+ {
+ impl<const $lanes:ident: usize> core::ops::$trait:ident<$rhs:ty> for $type:ty
+ where
+ LaneCount<$lanes2:ident>: SupportedLaneCount,
+ {
+ type Output = $output:ty;
+
+ $(#[$attrs:meta])*
+ fn $fn:ident($self_tok:ident, $rhs_arg:ident: $rhs_arg_ty:ty) -> Self::Output $body:tt
+ }
+ } => {
+ impl<const $lanes: usize> core::ops::$trait<$rhs> for $type
+ where
+ LaneCount<$lanes2>: SupportedLaneCount,
+ {
+ type Output = $output;
+
+ $(#[$attrs])*
+ fn $fn($self_tok, $rhs_arg: $rhs_arg_ty) -> Self::Output $body
+ }
+
+ impl<const $lanes: usize> core::ops::$trait<&'_ $rhs> for $type
+ where
+ LaneCount<$lanes2>: SupportedLaneCount,
+ {
+ type Output = <$type as core::ops::$trait<$rhs>>::Output;
+
+ $(#[$attrs])*
+ fn $fn($self_tok, $rhs_arg: &$rhs) -> Self::Output {
+ core::ops::$trait::$fn($self_tok, *$rhs_arg)
+ }
+ }
+
+ impl<const $lanes: usize> core::ops::$trait<$rhs> for &'_ $type
+ where
+ LaneCount<$lanes2>: SupportedLaneCount,
+ {
+ type Output = <$type as core::ops::$trait<$rhs>>::Output;
+
+ $(#[$attrs])*
+ fn $fn($self_tok, $rhs_arg: $rhs) -> Self::Output {
+ core::ops::$trait::$fn(*$self_tok, $rhs_arg)
+ }
+ }
+
+ impl<const $lanes: usize> core::ops::$trait<&'_ $rhs> for &'_ $type
+ where
+ LaneCount<$lanes2>: SupportedLaneCount,
+ {
+ type Output = <$type as core::ops::$trait<$rhs>>::Output;
+
+ $(#[$attrs])*
+ fn $fn($self_tok, $rhs_arg: &$rhs) -> Self::Output {
+ core::ops::$trait::$fn(*$self_tok, *$rhs_arg)
+ }
+ }
+ };
+
+ // binary assignment op
+ {
+ impl<const $lanes:ident: usize> core::ops::$trait:ident<$rhs:ty> for $type:ty
+ where
+ LaneCount<$lanes2:ident>: SupportedLaneCount,
+ {
+ $(#[$attrs:meta])*
+ fn $fn:ident(&mut $self_tok:ident, $rhs_arg:ident: $rhs_arg_ty:ty) $body:tt
+ }
+ } => {
+ impl<const $lanes: usize> core::ops::$trait<$rhs> for $type
+ where
+ LaneCount<$lanes2>: SupportedLaneCount,
+ {
+ $(#[$attrs])*
+ fn $fn(&mut $self_tok, $rhs_arg: $rhs_arg_ty) $body
+ }
+
+ impl<const $lanes: usize> core::ops::$trait<&'_ $rhs> for $type
+ where
+ LaneCount<$lanes2>: SupportedLaneCount,
+ {
+ $(#[$attrs])*
+ fn $fn(&mut $self_tok, $rhs_arg: &$rhs_arg_ty) {
+ core::ops::$trait::$fn($self_tok, *$rhs_arg)
+ }
+ }
+ };
+
+ // unary op
+ {
+ impl<const $lanes:ident: usize> core::ops::$trait:ident for $type:ty
+ where
+ LaneCount<$lanes2:ident>: SupportedLaneCount,
+ {
+ type Output = $output:ty;
+ fn $fn:ident($self_tok:ident) -> Self::Output $body:tt
+ }
+ } => {
+ impl<const $lanes: usize> core::ops::$trait for $type
+ where
+ LaneCount<$lanes2>: SupportedLaneCount,
+ {
+ type Output = $output;
+ fn $fn($self_tok) -> Self::Output $body
+ }
+
+ impl<const $lanes: usize> core::ops::$trait for &'_ $type
+ where
+ LaneCount<$lanes2>: SupportedLaneCount,
+ {
+ type Output = <$type as core::ops::$trait>::Output;
+ fn $fn($self_tok) -> Self::Output {
+ core::ops::$trait::$fn(*$self_tok)
+ }
+ }
+ }
+}
+
+/// Automatically implements operators over vectors and scalars for a particular vector.
+macro_rules! impl_op {
+ { impl Add for $scalar:ty } => {
+ impl_op! { @binary $scalar, Add::add, AddAssign::add_assign, simd_add }
+ };
+ { impl Sub for $scalar:ty } => {
+ impl_op! { @binary $scalar, Sub::sub, SubAssign::sub_assign, simd_sub }
+ };
+ { impl Mul for $scalar:ty } => {
+ impl_op! { @binary $scalar, Mul::mul, MulAssign::mul_assign, simd_mul }
+ };
+ { impl Div for $scalar:ty } => {
+ impl_op! { @binary $scalar, Div::div, DivAssign::div_assign, simd_div }
+ };
+ { impl Rem for $scalar:ty } => {
+ impl_op! { @binary $scalar, Rem::rem, RemAssign::rem_assign, simd_rem }
+ };
+ { impl Shl for $scalar:ty } => {
+ impl_op! { @binary $scalar, Shl::shl, ShlAssign::shl_assign, simd_shl }
+ };
+ { impl Shr for $scalar:ty } => {
+ impl_op! { @binary $scalar, Shr::shr, ShrAssign::shr_assign, simd_shr }
+ };
+ { impl BitAnd for $scalar:ty } => {
+ impl_op! { @binary $scalar, BitAnd::bitand, BitAndAssign::bitand_assign, simd_and }
+ };
+ { impl BitOr for $scalar:ty } => {
+ impl_op! { @binary $scalar, BitOr::bitor, BitOrAssign::bitor_assign, simd_or }
+ };
+ { impl BitXor for $scalar:ty } => {
+ impl_op! { @binary $scalar, BitXor::bitxor, BitXorAssign::bitxor_assign, simd_xor }
+ };
+
+ { impl Not for $scalar:ty } => {
+ impl_ref_ops! {
+ impl<const LANES: usize> core::ops::Not for Simd<$scalar, LANES>
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ type Output = Self;
+ fn not(self) -> Self::Output {
+ self ^ Self::splat(!<$scalar>::default())
+ }
+ }
+ }
+ };
+
+ { impl Neg for $scalar:ty } => {
+ impl_ref_ops! {
+ impl<const LANES: usize> core::ops::Neg for Simd<$scalar, LANES>
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ type Output = Self;
+ fn neg(self) -> Self::Output {
+ unsafe { intrinsics::simd_neg(self) }
+ }
+ }
+ }
+ };
+
+ // generic binary op with assignment when output is `Self`
+ { @binary $scalar:ty, $trait:ident :: $trait_fn:ident, $assign_trait:ident :: $assign_trait_fn:ident, $intrinsic:ident } => {
+ impl_ref_ops! {
+ impl<const LANES: usize> core::ops::$trait<Self> for Simd<$scalar, LANES>
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ type Output = Self;
+
+ #[inline]
+ fn $trait_fn(self, rhs: Self) -> Self::Output {
+ unsafe {
+ intrinsics::$intrinsic(self, rhs)
+ }
+ }
+ }
+ }
+
+ impl_ref_ops! {
+ impl<const LANES: usize> core::ops::$trait<$scalar> for Simd<$scalar, LANES>
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ type Output = Self;
+
+ #[inline]
+ fn $trait_fn(self, rhs: $scalar) -> Self::Output {
+ core::ops::$trait::$trait_fn(self, Self::splat(rhs))
+ }
+ }
+ }
+
+ impl_ref_ops! {
+ impl<const LANES: usize> core::ops::$trait<Simd<$scalar, LANES>> for $scalar
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ type Output = Simd<$scalar, LANES>;
+
+ #[inline]
+ fn $trait_fn(self, rhs: Simd<$scalar, LANES>) -> Self::Output {
+ core::ops::$trait::$trait_fn(Simd::splat(self), rhs)
+ }
+ }
+ }
+
+ impl_ref_ops! {
+ impl<const LANES: usize> core::ops::$assign_trait<Self> for Simd<$scalar, LANES>
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ #[inline]
+ fn $assign_trait_fn(&mut self, rhs: Self) {
+ unsafe {
+ *self = intrinsics::$intrinsic(*self, rhs);
+ }
+ }
+ }
+ }
+
+ impl_ref_ops! {
+ impl<const LANES: usize> core::ops::$assign_trait<$scalar> for Simd<$scalar, LANES>
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ #[inline]
+ fn $assign_trait_fn(&mut self, rhs: $scalar) {
+ core::ops::$assign_trait::$assign_trait_fn(self, Self::splat(rhs));
+ }
+ }
+ }
+ };
+}
+
+/// Implements floating-point operators for the provided types.
+macro_rules! impl_float_ops {
+ { $($scalar:ty),* } => {
+ $(
+ impl_op! { impl Add for $scalar }
+ impl_op! { impl Sub for $scalar }
+ impl_op! { impl Mul for $scalar }
+ impl_op! { impl Div for $scalar }
+ impl_op! { impl Rem for $scalar }
+ impl_op! { impl Neg for $scalar }
+ )*
+ };
+}
+
+/// Implements unsigned integer operators for the provided types.
+macro_rules! impl_unsigned_int_ops {
+ { $($scalar:ty),* } => {
+ $(
+ impl_op! { impl Add for $scalar }
+ impl_op! { impl Sub for $scalar }
+ impl_op! { impl Mul for $scalar }
+ impl_op! { impl BitAnd for $scalar }
+ impl_op! { impl BitOr for $scalar }
+ impl_op! { impl BitXor for $scalar }
+ impl_op! { impl Not for $scalar }
+
+ // Integers panic on divide by 0
+ impl_ref_ops! {
+ impl<const LANES: usize> core::ops::Div<Self> for Simd<$scalar, LANES>
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ type Output = Self;
+
+ #[inline]
+ fn div(self, rhs: Self) -> Self::Output {
+ if rhs.as_array()
+ .iter()
+ .any(|x| *x == 0)
+ {
+ panic!("attempt to divide by zero");
+ }
+
+ // Guards for div(MIN, -1),
+ // this check only applies to signed ints
+ if <$scalar>::MIN != 0 && self.as_array().iter()
+ .zip(rhs.as_array().iter())
+ .any(|(x,y)| *x == <$scalar>::MIN && *y == -1 as _) {
+ panic!("attempt to divide with overflow");
+ }
+ unsafe { intrinsics::simd_div(self, rhs) }
+ }
+ }
+ }
+
+ impl_ref_ops! {
+ impl<const LANES: usize> core::ops::Div<$scalar> for Simd<$scalar, LANES>
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ type Output = Self;
+
+ #[inline]
+ fn div(self, rhs: $scalar) -> Self::Output {
+ if rhs == 0 {
+ panic!("attempt to divide by zero");
+ }
+ if <$scalar>::MIN != 0 &&
+ self.as_array().iter().any(|x| *x == <$scalar>::MIN) &&
+ rhs == -1 as _ {
+ panic!("attempt to divide with overflow");
+ }
+ let rhs = Self::splat(rhs);
+ unsafe { intrinsics::simd_div(self, rhs) }
+ }
+ }
+ }
+
+ impl_ref_ops! {
+ impl<const LANES: usize> core::ops::Div<Simd<$scalar, LANES>> for $scalar
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ type Output = Simd<$scalar, LANES>;
+
+ #[inline]
+ fn div(self, rhs: Simd<$scalar, LANES>) -> Self::Output {
+ Simd::splat(self) / rhs
+ }
+ }
+ }
+
+ impl_ref_ops! {
+ impl<const LANES: usize> core::ops::DivAssign<Self> for Simd<$scalar, LANES>
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ #[inline]
+ fn div_assign(&mut self, rhs: Self) {
+ *self = *self / rhs;
+ }
+ }
+ }
+
+ impl_ref_ops! {
+ impl<const LANES: usize> core::ops::DivAssign<$scalar> for Simd<$scalar, LANES>
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ #[inline]
+ fn div_assign(&mut self, rhs: $scalar) {
+ *self = *self / rhs;
+ }
+ }
+ }
+
+ // remainder panics on zero divisor
+ impl_ref_ops! {
+ impl<const LANES: usize> core::ops::Rem<Self> for Simd<$scalar, LANES>
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ type Output = Self;
+
+ #[inline]
+ fn rem(self, rhs: Self) -> Self::Output {
+ if rhs.as_array()
+ .iter()
+ .any(|x| *x == 0)
+ {
+ panic!("attempt to calculate the remainder with a divisor of zero");
+ }
+
+ // Guards for rem(MIN, -1)
+ // this branch applies the check only to signed ints
+ if <$scalar>::MIN != 0 && self.as_array().iter()
+ .zip(rhs.as_array().iter())
+ .any(|(x,y)| *x == <$scalar>::MIN && *y == -1 as _) {
+ panic!("attempt to calculate the remainder with overflow");
+ }
+ unsafe { intrinsics::simd_rem(self, rhs) }
+ }
+ }
+ }
+
+ impl_ref_ops! {
+ impl<const LANES: usize> core::ops::Rem<$scalar> for Simd<$scalar, LANES>
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ type Output = Self;
+
+ #[inline]
+ fn rem(self, rhs: $scalar) -> Self::Output {
+ if rhs == 0 {
+ panic!("attempt to calculate the remainder with a divisor of zero");
+ }
+ if <$scalar>::MIN != 0 &&
+ self.as_array().iter().any(|x| *x == <$scalar>::MIN) &&
+ rhs == -1 as _ {
+ panic!("attempt to calculate the remainder with overflow");
+ }
+ let rhs = Self::splat(rhs);
+ unsafe { intrinsics::simd_rem(self, rhs) }
+ }
+ }
+ }
+
+ impl_ref_ops! {
+ impl<const LANES: usize> core::ops::Rem<Simd<$scalar, LANES>> for $scalar
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ type Output = Simd<$scalar, LANES>;
+
+ #[inline]
+ fn rem(self, rhs: Simd<$scalar, LANES>) -> Self::Output {
+ Simd::splat(self) % rhs
+ }
+ }
+ }
+
+ impl_ref_ops! {
+ impl<const LANES: usize> core::ops::RemAssign<Self> for Simd<$scalar, LANES>
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ #[inline]
+ fn rem_assign(&mut self, rhs: Self) {
+ *self = *self % rhs;
+ }
+ }
+ }
+
+ impl_ref_ops! {
+ impl<const LANES: usize> core::ops::RemAssign<$scalar> for Simd<$scalar, LANES>
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ #[inline]
+ fn rem_assign(&mut self, rhs: $scalar) {
+ *self = *self % rhs;
+ }
+ }
+ }
+
+ // shifts panic on overflow
+ impl_ref_ops! {
+ impl<const LANES: usize> core::ops::Shl<Self> for Simd<$scalar, LANES>
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ type Output = Self;
+
+ #[inline]
+ fn shl(self, rhs: Self) -> Self::Output {
+ // TODO there is probably a better way of doing this
+ if rhs.as_array()
+ .iter()
+ .copied()
+ .any(invalid_shift_rhs)
+ {
+ panic!("attempt to shift left with overflow");
+ }
+ unsafe { intrinsics::simd_shl(self, rhs) }
+ }
+ }
+ }
+
+ impl_ref_ops! {
+ impl<const LANES: usize> core::ops::Shl<$scalar> for Simd<$scalar, LANES>
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ type Output = Self;
+
+ #[inline]
+ fn shl(self, rhs: $scalar) -> Self::Output {
+ if invalid_shift_rhs(rhs) {
+ panic!("attempt to shift left with overflow");
+ }
+ let rhs = Self::splat(rhs);
+ unsafe { intrinsics::simd_shl(self, rhs) }
+ }
+ }
+ }
+
+
+ impl_ref_ops! {
+ impl<const LANES: usize> core::ops::ShlAssign<Self> for Simd<$scalar, LANES>
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ #[inline]
+ fn shl_assign(&mut self, rhs: Self) {
+ *self = *self << rhs;
+ }
+ }
+ }
+
+ impl_ref_ops! {
+ impl<const LANES: usize> core::ops::ShlAssign<$scalar> for Simd<$scalar, LANES>
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ #[inline]
+ fn shl_assign(&mut self, rhs: $scalar) {
+ *self = *self << rhs;
+ }
+ }
+ }
+
+ impl_ref_ops! {
+ impl<const LANES: usize> core::ops::Shr<Self> for Simd<$scalar, LANES>
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ type Output = Self;
+
+ #[inline]
+ fn shr(self, rhs: Self) -> Self::Output {
+ // TODO there is probably a better way of doing this
+ if rhs.as_array()
+ .iter()
+ .copied()
+ .any(invalid_shift_rhs)
+ {
+ panic!("attempt to shift with overflow");
+ }
+ unsafe { intrinsics::simd_shr(self, rhs) }
+ }
+ }
+ }
+
+ impl_ref_ops! {
+ impl<const LANES: usize> core::ops::Shr<$scalar> for Simd<$scalar, LANES>
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ type Output = Self;
+
+ #[inline]
+ fn shr(self, rhs: $scalar) -> Self::Output {
+ if invalid_shift_rhs(rhs) {
+ panic!("attempt to shift with overflow");
+ }
+ let rhs = Self::splat(rhs);
+ unsafe { intrinsics::simd_shr(self, rhs) }
+ }
+ }
+ }
+
+
+ impl_ref_ops! {
+ impl<const LANES: usize> core::ops::ShrAssign<Self> for Simd<$scalar, LANES>
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ #[inline]
+ fn shr_assign(&mut self, rhs: Self) {
+ *self = *self >> rhs;
+ }
+ }
+ }
+
+ impl_ref_ops! {
+ impl<const LANES: usize> core::ops::ShrAssign<$scalar> for Simd<$scalar, LANES>
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ #[inline]
+ fn shr_assign(&mut self, rhs: $scalar) {
+ *self = *self >> rhs;
+ }
+ }
+ }
+ )*
+ };
+}
+
+/// Implements unsigned integer operators for the provided types.
+macro_rules! impl_signed_int_ops {
+ { $($scalar:ty),* } => {
+ impl_unsigned_int_ops! { $($scalar),* }
+ $( // scalar
+ impl_op! { impl Neg for $scalar }
+ )*
+ };
+}
+
+impl_unsigned_int_ops! { u8, u16, u32, u64, usize }
+impl_signed_int_ops! { i8, i16, i32, i64, isize }
+impl_float_ops! { f32, f64 }
--- /dev/null
+use crate::simd::intrinsics::{
+ simd_reduce_add_ordered, simd_reduce_and, simd_reduce_max, simd_reduce_min,
+ simd_reduce_mul_ordered, simd_reduce_or, simd_reduce_xor,
+};
+use crate::simd::{LaneCount, Simd, SupportedLaneCount};
+
+macro_rules! impl_integer_reductions {
+ { $scalar:ty } => {
+ impl<const LANES: usize> Simd<$scalar, LANES>
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ /// Horizontal wrapping add. Returns the sum of the lanes of the vector, with wrapping addition.
+ #[inline]
+ pub fn horizontal_sum(self) -> $scalar {
+ unsafe { simd_reduce_add_ordered(self, 0) }
+ }
+
+ /// Horizontal wrapping multiply. Returns the product of the lanes of the vector, with wrapping multiplication.
+ #[inline]
+ pub fn horizontal_product(self) -> $scalar {
+ unsafe { simd_reduce_mul_ordered(self, 1) }
+ }
+
+ /// Horizontal bitwise "and". Returns the cumulative bitwise "and" across the lanes of
+ /// the vector.
+ #[inline]
+ pub fn horizontal_and(self) -> $scalar {
+ unsafe { simd_reduce_and(self) }
+ }
+
+ /// Horizontal bitwise "or". Returns the cumulative bitwise "or" across the lanes of
+ /// the vector.
+ #[inline]
+ pub fn horizontal_or(self) -> $scalar {
+ unsafe { simd_reduce_or(self) }
+ }
+
+ /// Horizontal bitwise "xor". Returns the cumulative bitwise "xor" across the lanes of
+ /// the vector.
+ #[inline]
+ pub fn horizontal_xor(self) -> $scalar {
+ unsafe { simd_reduce_xor(self) }
+ }
+
+ /// Horizontal maximum. Returns the maximum lane in the vector.
+ #[inline]
+ pub fn horizontal_max(self) -> $scalar {
+ unsafe { simd_reduce_max(self) }
+ }
+
+ /// Horizontal minimum. Returns the minimum lane in the vector.
+ #[inline]
+ pub fn horizontal_min(self) -> $scalar {
+ unsafe { simd_reduce_min(self) }
+ }
+ }
+ }
+}
+
+impl_integer_reductions! { i8 }
+impl_integer_reductions! { i16 }
+impl_integer_reductions! { i32 }
+impl_integer_reductions! { i64 }
+impl_integer_reductions! { isize }
+impl_integer_reductions! { u8 }
+impl_integer_reductions! { u16 }
+impl_integer_reductions! { u32 }
+impl_integer_reductions! { u64 }
+impl_integer_reductions! { usize }
+
+macro_rules! impl_float_reductions {
+ { $scalar:ty } => {
+ impl<const LANES: usize> Simd<$scalar, LANES>
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+
+ /// Horizontal add. Returns the sum of the lanes of the vector.
+ #[inline]
+ pub fn horizontal_sum(self) -> $scalar {
+ // LLVM sum is inaccurate on i586
+ if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) {
+ self.as_array().iter().sum()
+ } else {
+ unsafe { simd_reduce_add_ordered(self, 0.) }
+ }
+ }
+
+ /// Horizontal multiply. Returns the product of the lanes of the vector.
+ #[inline]
+ pub fn horizontal_product(self) -> $scalar {
+ // LLVM product is inaccurate on i586
+ if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) {
+ self.as_array().iter().product()
+ } else {
+ unsafe { simd_reduce_mul_ordered(self, 1.) }
+ }
+ }
+
+ /// Horizontal maximum. Returns the maximum lane in the vector.
+ ///
+ /// Returns values based on equality, so a vector containing both `0.` and `-0.` may
+ /// return either. This function will not return `NaN` unless all lanes are `NaN`.
+ #[inline]
+ pub fn horizontal_max(self) -> $scalar {
+ unsafe { simd_reduce_max(self) }
+ }
+
+ /// Horizontal minimum. Returns the minimum lane in the vector.
+ ///
+ /// Returns values based on equality, so a vector containing both `0.` and `-0.` may
+ /// return either. This function will not return `NaN` unless all lanes are `NaN`.
+ #[inline]
+ pub fn horizontal_min(self) -> $scalar {
+ unsafe { simd_reduce_min(self) }
+ }
+ }
+ }
+}
+
+impl_float_reductions! { f32 }
+impl_float_reductions! { f64 }
--- /dev/null
+use crate::simd::intrinsics;
+use crate::simd::{LaneCount, Simd, SupportedLaneCount};
+
+macro_rules! implement {
+ {
+ $type:ty, $int_type:ty
+ } => {
+ #[cfg(feature = "std")]
+ impl<const LANES: usize> Simd<$type, LANES>
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ /// Returns the smallest integer greater than or equal to each lane.
+ #[must_use = "method returns a new vector and does not mutate the original value"]
+ #[inline]
+ pub fn ceil(self) -> Self {
+ unsafe { intrinsics::simd_ceil(self) }
+ }
+
+ /// Returns the largest integer value less than or equal to each lane.
+ #[must_use = "method returns a new vector and does not mutate the original value"]
+ #[inline]
+ pub fn floor(self) -> Self {
+ unsafe { intrinsics::simd_floor(self) }
+ }
+
+ /// Rounds to the nearest integer value. Ties round toward zero.
+ #[must_use = "method returns a new vector and does not mutate the original value"]
+ #[inline]
+ pub fn round(self) -> Self {
+ unsafe { intrinsics::simd_round(self) }
+ }
+
+ /// Returns the floating point's integer value, with its fractional part removed.
+ #[must_use = "method returns a new vector and does not mutate the original value"]
+ #[inline]
+ pub fn trunc(self) -> Self {
+ unsafe { intrinsics::simd_trunc(self) }
+ }
+
+ /// Returns the floating point's fractional value, with its integer part removed.
+ #[must_use = "method returns a new vector and does not mutate the original value"]
+ #[inline]
+ pub fn fract(self) -> Self {
+ self - self.trunc()
+ }
+ }
+
+ impl<const LANES: usize> Simd<$type, LANES>
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ /// Rounds toward zero and converts to the same-width integer type, assuming that
+ /// the value is finite and fits in that type.
+ ///
+ /// # Safety
+ /// The value must:
+ ///
+ /// * Not be NaN
+ /// * Not be infinite
+ /// * Be representable in the return type, after truncating off its fractional part
+ #[inline]
+ pub unsafe fn to_int_unchecked(self) -> Simd<$int_type, LANES> {
+ unsafe { intrinsics::simd_cast(self) }
+ }
+
+ /// Creates a floating-point vector from an integer vector. Rounds values that are
+ /// not exactly representable.
+ #[inline]
+ pub fn round_from_int(value: Simd<$int_type, LANES>) -> Self {
+ unsafe { intrinsics::simd_cast(value) }
+ }
+ }
+ }
+}
+
+implement! { f32, i32 }
+implement! { f64, i64 }
--- /dev/null
+use crate::simd::intrinsics;
+use crate::simd::{LaneCount, Mask, MaskElement, Simd, SimdElement, SupportedLaneCount};
+
+mod sealed {
+ pub trait Sealed<Mask> {
+ fn select(mask: Mask, true_values: Self, false_values: Self) -> Self;
+ }
+}
+use sealed::Sealed;
+
+/// Supporting trait for vector `select` function
+pub trait Select<Mask>: Sealed<Mask> {}
+
+impl<T, const LANES: usize> Sealed<Mask<T::Mask, LANES>> for Simd<T, LANES>
+where
+ T: SimdElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ #[inline]
+ fn select(mask: Mask<T::Mask, LANES>, true_values: Self, false_values: Self) -> Self {
+ unsafe { intrinsics::simd_select(mask.to_int(), true_values, false_values) }
+ }
+}
+
+impl<T, const LANES: usize> Select<Mask<T::Mask, LANES>> for Simd<T, LANES>
+where
+ T: SimdElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+}
+
+impl<T, const LANES: usize> Sealed<Self> for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ #[inline]
+ fn select(mask: Self, true_values: Self, false_values: Self) -> Self {
+ mask & true_values | !mask & false_values
+ }
+}
+
+impl<T, const LANES: usize> Select<Self> for Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+}
+
+impl<T, const LANES: usize> Mask<T, LANES>
+where
+ T: MaskElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ /// Choose lanes from two vectors.
+ ///
+ /// For each lane in the mask, choose the corresponding lane from `true_values` if
+ /// that lane mask is true, and `false_values` if that lane mask is false.
+ ///
+ /// ```
+ /// # #![feature(portable_simd)]
+ /// # #[cfg(feature = "std")] use core_simd::{Simd, Mask};
+ /// # #[cfg(not(feature = "std"))] use core::simd::{Simd, Mask};
+ /// let a = Simd::from_array([0, 1, 2, 3]);
+ /// let b = Simd::from_array([4, 5, 6, 7]);
+ /// let mask = Mask::from_array([true, false, false, true]);
+ /// let c = mask.select(a, b);
+ /// assert_eq!(c.to_array(), [0, 5, 6, 3]);
+ /// ```
+ ///
+ /// `select` can also be used on masks:
+ /// ```
+ /// # #![feature(portable_simd)]
+ /// # #[cfg(feature = "std")] use core_simd::Mask;
+ /// # #[cfg(not(feature = "std"))] use core::simd::Mask;
+ /// let a = Mask::<i32, 4>::from_array([true, true, false, false]);
+ /// let b = Mask::<i32, 4>::from_array([false, false, true, true]);
+ /// let mask = Mask::<i32, 4>::from_array([true, false, false, true]);
+ /// let c = mask.select(a, b);
+ /// assert_eq!(c.to_array(), [true, false, true, false]);
+ /// ```
+ #[inline]
+ pub fn select<S: Select<Self>>(self, true_values: S, false_values: S) -> S {
+ S::select(self, true_values, false_values)
+ }
+}
--- /dev/null
+use crate::simd::intrinsics;
+use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount};
+
+/// Constructs a new vector by selecting values from the lanes of the source vector or vectors to use.
+///
+/// When swizzling one vector, the indices of the result vector are indicated by a `const` array
+/// of `usize`, like [`Swizzle`].
+/// When swizzling two vectors, the indices are indicated by a `const` array of [`Which`], like
+/// [`Swizzle2`].
+///
+/// # Examples
+/// ## One source vector
+/// ```
+/// # #![feature(portable_simd)]
+/// # #[cfg(feature = "std")] use core_simd::{Simd, simd_swizzle};
+/// # #[cfg(not(feature = "std"))] use core::simd::{Simd, simd_swizzle};
+/// let v = Simd::<f32, 4>::from_array([0., 1., 2., 3.]);
+///
+/// // Keeping the same size
+/// let r = simd_swizzle!(v, [3, 0, 1, 2]);
+/// assert_eq!(r.to_array(), [3., 0., 1., 2.]);
+///
+/// // Changing the number of lanes
+/// let r = simd_swizzle!(v, [3, 1]);
+/// assert_eq!(r.to_array(), [3., 1.]);
+/// ```
+///
+/// ## Two source vectors
+/// ```
+/// # #![feature(portable_simd)]
+/// # #[cfg(feature = "std")] use core_simd::{Simd, simd_swizzle, Which};
+/// # #[cfg(not(feature = "std"))] use core::simd::{Simd, simd_swizzle, Which};
+/// use Which::*;
+/// let a = Simd::<f32, 4>::from_array([0., 1., 2., 3.]);
+/// let b = Simd::<f32, 4>::from_array([4., 5., 6., 7.]);
+///
+/// // Keeping the same size
+/// let r = simd_swizzle!(a, b, [First(0), First(1), Second(2), Second(3)]);
+/// assert_eq!(r.to_array(), [0., 1., 6., 7.]);
+///
+/// // Changing the number of lanes
+/// let r = simd_swizzle!(a, b, [First(0), Second(0)]);
+/// assert_eq!(r.to_array(), [0., 4.]);
+/// ```
+#[allow(unused_macros)]
+pub macro simd_swizzle {
+ (
+ $vector:expr, $index:expr $(,)?
+ ) => {
+ {
+ use $crate::simd::Swizzle;
+ struct Impl;
+ impl<const LANES: usize> Swizzle<LANES, {$index.len()}> for Impl {
+ const INDEX: [usize; {$index.len()}] = $index;
+ }
+ Impl::swizzle($vector)
+ }
+ },
+ (
+ $first:expr, $second:expr, $index:expr $(,)?
+ ) => {
+ {
+ use $crate::simd::{Which, Swizzle2};
+ struct Impl;
+ impl<const LANES: usize> Swizzle2<LANES, {$index.len()}> for Impl {
+ const INDEX: [Which; {$index.len()}] = $index;
+ }
+ Impl::swizzle2($first, $second)
+ }
+ }
+}
+
+/// An index into one of two vectors.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub enum Which {
+ /// Indexes the first vector.
+ First(usize),
+ /// Indexes the second vector.
+ Second(usize),
+}
+
+/// Create a vector from the elements of another vector.
+pub trait Swizzle<const INPUT_LANES: usize, const OUTPUT_LANES: usize> {
+ /// Map from the lanes of the input vector to the output vector.
+ const INDEX: [usize; OUTPUT_LANES];
+
+ /// Create a new vector from the lanes of `vector`.
+ ///
+ /// Lane `i` of the output is `vector[Self::INDEX[i]]`.
+ fn swizzle<T>(vector: Simd<T, INPUT_LANES>) -> Simd<T, OUTPUT_LANES>
+ where
+ T: SimdElement,
+ LaneCount<INPUT_LANES>: SupportedLaneCount,
+ LaneCount<OUTPUT_LANES>: SupportedLaneCount,
+ {
+ unsafe { intrinsics::simd_shuffle(vector, vector, Self::INDEX_IMPL) }
+ }
+}
+
+/// Create a vector from the elements of two other vectors.
+pub trait Swizzle2<const INPUT_LANES: usize, const OUTPUT_LANES: usize> {
+ /// Map from the lanes of the input vectors to the output vector
+ const INDEX: [Which; OUTPUT_LANES];
+
+ /// Create a new vector from the lanes of `first` and `second`.
+ ///
+ /// Lane `i` is `first[j]` when `Self::INDEX[i]` is `First(j)`, or `second[j]` when it is
+ /// `Second(j)`.
+ fn swizzle2<T>(
+ first: Simd<T, INPUT_LANES>,
+ second: Simd<T, INPUT_LANES>,
+ ) -> Simd<T, OUTPUT_LANES>
+ where
+ T: SimdElement,
+ LaneCount<INPUT_LANES>: SupportedLaneCount,
+ LaneCount<OUTPUT_LANES>: SupportedLaneCount,
+ {
+ unsafe { intrinsics::simd_shuffle(first, second, Self::INDEX_IMPL) }
+ }
+}
+
+/// The `simd_shuffle` intrinsic expects `u32`, so do error checking and conversion here.
+/// This trait hides `INDEX_IMPL` from the public API.
+trait SwizzleImpl<const INPUT_LANES: usize, const OUTPUT_LANES: usize> {
+ const INDEX_IMPL: [u32; OUTPUT_LANES];
+}
+
+impl<T, const INPUT_LANES: usize, const OUTPUT_LANES: usize> SwizzleImpl<INPUT_LANES, OUTPUT_LANES>
+ for T
+where
+ T: Swizzle<INPUT_LANES, OUTPUT_LANES> + ?Sized,
+{
+ const INDEX_IMPL: [u32; OUTPUT_LANES] = {
+ let mut output = [0; OUTPUT_LANES];
+ let mut i = 0;
+ while i < OUTPUT_LANES {
+ let index = Self::INDEX[i];
+ assert!(index as u32 as usize == index);
+ assert!(index < INPUT_LANES, "source lane exceeds input lane count",);
+ output[i] = index as u32;
+ i += 1;
+ }
+ output
+ };
+}
+
+/// The `simd_shuffle` intrinsic expects `u32`, so do error checking and conversion here.
+/// This trait hides `INDEX_IMPL` from the public API.
+trait Swizzle2Impl<const INPUT_LANES: usize, const OUTPUT_LANES: usize> {
+ const INDEX_IMPL: [u32; OUTPUT_LANES];
+}
+
+impl<T, const INPUT_LANES: usize, const OUTPUT_LANES: usize> Swizzle2Impl<INPUT_LANES, OUTPUT_LANES>
+ for T
+where
+ T: Swizzle2<INPUT_LANES, OUTPUT_LANES> + ?Sized,
+{
+ const INDEX_IMPL: [u32; OUTPUT_LANES] = {
+ let mut output = [0; OUTPUT_LANES];
+ let mut i = 0;
+ while i < OUTPUT_LANES {
+ let (offset, index) = match Self::INDEX[i] {
+ Which::First(index) => (false, index),
+ Which::Second(index) => (true, index),
+ };
+ assert!(index < INPUT_LANES, "source lane exceeds input lane count",);
+
+ // lanes are indexed by the first vector, then second vector
+ let index = if offset { index + INPUT_LANES } else { index };
+ assert!(index as u32 as usize == index);
+ output[i] = index as u32;
+ i += 1;
+ }
+ output
+ };
+}
+
+impl<T, const LANES: usize> Simd<T, LANES>
+where
+ T: SimdElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ /// Reverse the order of the lanes in the vector.
+ #[inline]
+ pub fn reverse(self) -> Self {
+ const fn reverse_index<const LANES: usize>() -> [usize; LANES] {
+ let mut index = [0; LANES];
+ let mut i = 0;
+ while i < LANES {
+ index[i] = LANES - i - 1;
+ i += 1;
+ }
+ index
+ }
+
+ struct Reverse;
+
+ impl<const LANES: usize> Swizzle<LANES, LANES> for Reverse {
+ const INDEX: [usize; LANES] = reverse_index::<LANES>();
+ }
+
+ Reverse::swizzle(self)
+ }
+
+ /// Rotates the vector such that the first `OFFSET` elements of the slice move to the end
+ /// while the last `LANES - OFFSET` elements move to the front. After calling `rotate_lanes_left`,
+ /// the element previously in lane `OFFSET` will become the first element in the slice.
+ #[inline]
+ pub fn rotate_lanes_left<const OFFSET: usize>(self) -> Self {
+ const fn rotate_index<const OFFSET: usize, const LANES: usize>() -> [usize; LANES] {
+ let offset = OFFSET % LANES;
+ let mut index = [0; LANES];
+ let mut i = 0;
+ while i < LANES {
+ index[i] = (i + offset) % LANES;
+ i += 1;
+ }
+ index
+ }
+
+ struct Rotate<const OFFSET: usize>;
+
+ impl<const OFFSET: usize, const LANES: usize> Swizzle<LANES, LANES> for Rotate<OFFSET> {
+ const INDEX: [usize; LANES] = rotate_index::<OFFSET, LANES>();
+ }
+
+ Rotate::<OFFSET>::swizzle(self)
+ }
+
+ /// Rotates the vector such that the first `LANES - OFFSET` elements of the vector move to
+ /// the end while the last `OFFSET` elements move to the front. After calling `rotate_lanes_right`,
+ /// the element previously at index `LANES - OFFSET` will become the first element in the slice.
+ #[inline]
+ pub fn rotate_lanes_right<const OFFSET: usize>(self) -> Self {
+ const fn rotate_index<const OFFSET: usize, const LANES: usize>() -> [usize; LANES] {
+ let offset = LANES - OFFSET % LANES;
+ let mut index = [0; LANES];
+ let mut i = 0;
+ while i < LANES {
+ index[i] = (i + offset) % LANES;
+ i += 1;
+ }
+ index
+ }
+
+ struct Rotate<const OFFSET: usize>;
+
+ impl<const OFFSET: usize, const LANES: usize> Swizzle<LANES, LANES> for Rotate<OFFSET> {
+ const INDEX: [usize; LANES] = rotate_index::<OFFSET, LANES>();
+ }
+
+ Rotate::<OFFSET>::swizzle(self)
+ }
+
+ /// Interleave two vectors.
+ ///
+ /// Produces two vectors with lanes taken alternately from `self` and `other`.
+ ///
+ /// The first result contains the first `LANES / 2` lanes from `self` and `other`,
+ /// alternating, starting with the first lane of `self`.
+ ///
+ /// The second result contains the last `LANES / 2` lanes from `self` and `other`,
+ /// alternating, starting with the lane `LANES / 2` from the start of `self`.
+ ///
+ /// ```
+ /// #![feature(portable_simd)]
+ /// # #[cfg(feature = "std")] use core_simd::Simd;
+ /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+ /// let a = Simd::from_array([0, 1, 2, 3]);
+ /// let b = Simd::from_array([4, 5, 6, 7]);
+ /// let (x, y) = a.interleave(b);
+ /// assert_eq!(x.to_array(), [0, 4, 1, 5]);
+ /// assert_eq!(y.to_array(), [2, 6, 3, 7]);
+ /// ```
+ #[inline]
+ pub fn interleave(self, other: Self) -> (Self, Self) {
+ const fn lo<const LANES: usize>() -> [Which; LANES] {
+ let mut idx = [Which::First(0); LANES];
+ let mut i = 0;
+ while i < LANES {
+ let offset = i / 2;
+ idx[i] = if i % 2 == 0 {
+ Which::First(offset)
+ } else {
+ Which::Second(offset)
+ };
+ i += 1;
+ }
+ idx
+ }
+ const fn hi<const LANES: usize>() -> [Which; LANES] {
+ let mut idx = [Which::First(0); LANES];
+ let mut i = 0;
+ while i < LANES {
+ let offset = (LANES + i) / 2;
+ idx[i] = if i % 2 == 0 {
+ Which::First(offset)
+ } else {
+ Which::Second(offset)
+ };
+ i += 1;
+ }
+ idx
+ }
+
+ struct Lo;
+ struct Hi;
+
+ impl<const LANES: usize> Swizzle2<LANES, LANES> for Lo {
+ const INDEX: [Which; LANES] = lo::<LANES>();
+ }
+
+ impl<const LANES: usize> Swizzle2<LANES, LANES> for Hi {
+ const INDEX: [Which; LANES] = hi::<LANES>();
+ }
+
+ (Lo::swizzle2(self, other), Hi::swizzle2(self, other))
+ }
+
+ /// Deinterleave two vectors.
+ ///
+ /// The first result takes every other lane of `self` and then `other`, starting with
+ /// the first lane.
+ ///
+ /// The second result takes every other lane of `self` and then `other`, starting with
+ /// the second lane.
+ ///
+ /// ```
+ /// #![feature(portable_simd)]
+ /// # #[cfg(feature = "std")] use core_simd::Simd;
+ /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+ /// let a = Simd::from_array([0, 4, 1, 5]);
+ /// let b = Simd::from_array([2, 6, 3, 7]);
+ /// let (x, y) = a.deinterleave(b);
+ /// assert_eq!(x.to_array(), [0, 1, 2, 3]);
+ /// assert_eq!(y.to_array(), [4, 5, 6, 7]);
+ /// ```
+ #[inline]
+ pub fn deinterleave(self, other: Self) -> (Self, Self) {
+ const fn even<const LANES: usize>() -> [Which; LANES] {
+ let mut idx = [Which::First(0); LANES];
+ let mut i = 0;
+ while i < LANES / 2 {
+ idx[i] = Which::First(2 * i);
+ idx[i + LANES / 2] = Which::Second(2 * i);
+ i += 1;
+ }
+ idx
+ }
+ const fn odd<const LANES: usize>() -> [Which; LANES] {
+ let mut idx = [Which::First(0); LANES];
+ let mut i = 0;
+ while i < LANES / 2 {
+ idx[i] = Which::First(2 * i + 1);
+ idx[i + LANES / 2] = Which::Second(2 * i + 1);
+ i += 1;
+ }
+ idx
+ }
+
+ struct Even;
+ struct Odd;
+
+ impl<const LANES: usize> Swizzle2<LANES, LANES> for Even {
+ const INDEX: [Which; LANES] = even::<LANES>();
+ }
+
+ impl<const LANES: usize> Swizzle2<LANES, LANES> for Odd {
+ const INDEX: [Which; LANES] = odd::<LANES>();
+ }
+
+ (Even::swizzle2(self, other), Odd::swizzle2(self, other))
+ }
+}
--- /dev/null
+macro_rules! impl_to_bytes {
+ { $ty:ty, $size:literal } => {
+ impl<const LANES: usize> crate::simd::Simd<$ty, LANES>
+ where
+ crate::simd::LaneCount<LANES>: crate::simd::SupportedLaneCount,
+ crate::simd::LaneCount<{{ $size * LANES }}>: crate::simd::SupportedLaneCount,
+ {
+ /// Return the memory representation of this integer as a byte array in native byte
+ /// order.
+ pub fn to_ne_bytes(self) -> crate::simd::Simd<u8, {{ $size * LANES }}> {
+ unsafe { core::mem::transmute_copy(&self) }
+ }
+
+ /// Create a native endian integer value from its memory representation as a byte array
+ /// in native endianness.
+ pub fn from_ne_bytes(bytes: crate::simd::Simd<u8, {{ $size * LANES }}>) -> Self {
+ unsafe { core::mem::transmute_copy(&bytes) }
+ }
+ }
+ }
+}
+
+impl_to_bytes! { u8, 1 }
+impl_to_bytes! { u16, 2 }
+impl_to_bytes! { u32, 4 }
+impl_to_bytes! { u64, 8 }
+#[cfg(target_pointer_width = "32")]
+impl_to_bytes! { usize, 4 }
+#[cfg(target_pointer_width = "64")]
+impl_to_bytes! { usize, 8 }
+
+impl_to_bytes! { i8, 1 }
+impl_to_bytes! { i16, 2 }
+impl_to_bytes! { i32, 4 }
+impl_to_bytes! { i64, 8 }
+#[cfg(target_pointer_width = "32")]
+impl_to_bytes! { isize, 4 }
+#[cfg(target_pointer_width = "64")]
+impl_to_bytes! { isize, 8 }
--- /dev/null
+mod float;
+mod int;
+mod uint;
+
+pub use float::*;
+pub use int::*;
+pub use uint::*;
+
+// Vectors of pointers are not for public use at the current time.
+pub(crate) mod ptr;
+
+use crate::simd::intrinsics;
+use crate::simd::{LaneCount, Mask, MaskElement, SupportedLaneCount};
+
+/// A SIMD vector of `LANES` elements of type `T`.
+#[repr(simd)]
+pub struct Simd<T, const LANES: usize>([T; LANES])
+where
+ T: SimdElement,
+ LaneCount<LANES>: SupportedLaneCount;
+
+impl<T, const LANES: usize> Simd<T, LANES>
+where
+ LaneCount<LANES>: SupportedLaneCount,
+ T: SimdElement,
+{
+ /// Number of lanes in this vector.
+ pub const LANES: usize = LANES;
+
+ /// Get the number of lanes in this vector.
+ pub const fn lanes(&self) -> usize {
+ LANES
+ }
+
+ /// Construct a SIMD vector by setting all lanes to the given value.
+ pub const fn splat(value: T) -> Self {
+ Self([value; LANES])
+ }
+
+ /// Returns an array reference containing the entire SIMD vector.
+ pub const fn as_array(&self) -> &[T; LANES] {
+ &self.0
+ }
+
+ /// Returns a mutable array reference containing the entire SIMD vector.
+ pub fn as_mut_array(&mut self) -> &mut [T; LANES] {
+ &mut self.0
+ }
+
+ /// Converts an array to a SIMD vector.
+ pub const fn from_array(array: [T; LANES]) -> Self {
+ Self(array)
+ }
+
+ /// Converts a SIMD vector to an array.
+ pub const fn to_array(self) -> [T; LANES] {
+ self.0
+ }
+
+ /// Converts a slice to a SIMD vector containing `slice[..LANES]`
+ /// # Panics
+ /// `from_slice` will panic if the slice's `len` is less than the vector's `Simd::LANES`.
+ #[must_use]
+ pub const fn from_slice(slice: &[T]) -> Self {
+ assert!(
+ slice.len() >= LANES,
+ "slice length must be at least the number of lanes"
+ );
+ let mut array = [slice[0]; LANES];
+ let mut i = 0;
+ while i < LANES {
+ array[i] = slice[i];
+ i += 1;
+ }
+ Self(array)
+ }
+
+ /// Reads from potentially discontiguous indices in `slice` to construct a SIMD vector.
+ /// If an index is out-of-bounds, the lane is instead selected from the `or` vector.
+ ///
+ /// # Examples
+ /// ```
+ /// # #![feature(portable_simd)]
+ /// # #[cfg(feature = "std")] use core_simd::Simd;
+ /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+ /// let vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
+ /// let idxs = Simd::from_array([9, 3, 0, 5]);
+ /// let alt = Simd::from_array([-5, -4, -3, -2]);
+ ///
+ /// let result = Simd::gather_or(&vec, idxs, alt); // Note the lane that is out-of-bounds.
+ /// assert_eq!(result, Simd::from_array([-5, 13, 10, 15]));
+ /// ```
+ #[must_use]
+ #[inline]
+ pub fn gather_or(slice: &[T], idxs: Simd<usize, LANES>, or: Self) -> Self {
+ Self::gather_select(slice, Mask::splat(true), idxs, or)
+ }
+
+ /// Reads from potentially discontiguous indices in `slice` to construct a SIMD vector.
+ /// If an index is out-of-bounds, the lane is set to the default value for the type.
+ ///
+ /// # Examples
+ /// ```
+ /// # #![feature(portable_simd)]
+ /// # #[cfg(feature = "std")] use core_simd::Simd;
+ /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+ /// let vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
+ /// let idxs = Simd::from_array([9, 3, 0, 5]);
+ ///
+ /// let result = Simd::gather_or_default(&vec, idxs); // Note the lane that is out-of-bounds.
+ /// assert_eq!(result, Simd::from_array([0, 13, 10, 15]));
+ /// ```
+ #[must_use]
+ #[inline]
+ pub fn gather_or_default(slice: &[T], idxs: Simd<usize, LANES>) -> Self
+ where
+ T: Default,
+ {
+ Self::gather_or(slice, idxs, Self::splat(T::default()))
+ }
+
+ /// Reads from potentially discontiguous indices in `slice` to construct a SIMD vector.
+ /// The mask `enable`s all `true` lanes and disables all `false` lanes.
+ /// If an index is disabled or is out-of-bounds, the lane is selected from the `or` vector.
+ ///
+ /// # Examples
+ /// ```
+ /// # #![feature(portable_simd)]
+ /// # #[cfg(feature = "std")] use core_simd::{Simd, Mask};
+ /// # #[cfg(not(feature = "std"))] use core::simd::{Simd, Mask};
+ /// let vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
+ /// let idxs = Simd::from_array([9, 3, 0, 5]);
+ /// let alt = Simd::from_array([-5, -4, -3, -2]);
+ /// let enable = Mask::from_array([true, true, true, false]); // Note the mask of the last lane.
+ ///
+ /// let result = Simd::gather_select(&vec, enable, idxs, alt); // Note the lane that is out-of-bounds.
+ /// assert_eq!(result, Simd::from_array([-5, 13, 10, -2]));
+ /// ```
+ #[must_use]
+ #[inline]
+ pub fn gather_select(
+ slice: &[T],
+ enable: Mask<isize, LANES>,
+ idxs: Simd<usize, LANES>,
+ or: Self,
+ ) -> Self {
+ let enable: Mask<isize, LANES> = enable & idxs.lanes_lt(Simd::splat(slice.len()));
+ // SAFETY: We have masked-off out-of-bounds lanes.
+ unsafe { Self::gather_select_unchecked(slice, enable, idxs, or) }
+ }
+
+ /// Reads from potentially discontiguous indices in `slice` to construct a SIMD vector.
+ /// The mask `enable`s all `true` lanes and disables all `false` lanes.
+ /// If an index is disabled, the lane is selected from the `or` vector.
+ ///
+ /// # Safety
+ ///
+ /// Calling this function with an `enable`d out-of-bounds index is *[undefined behavior]*
+ /// even if the resulting value is not used.
+ ///
+ /// # Examples
+ /// ```
+ /// # #![feature(portable_simd)]
+ /// # #[cfg(feature = "std")] use core_simd::{Simd, Mask};
+ /// # #[cfg(not(feature = "std"))] use core::simd::{Simd, Mask};
+ /// let vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
+ /// let idxs = Simd::from_array([9, 3, 0, 5]);
+ /// let alt = Simd::from_array([-5, -4, -3, -2]);
+ /// let enable = Mask::from_array([true, true, true, false]); // Note the final mask lane.
+ /// // If this mask was used to gather, it would be unsound. Let's fix that.
+ /// let enable = enable & idxs.lanes_lt(Simd::splat(vec.len()));
+ ///
+ /// // We have masked the OOB lane, so it's safe to gather now.
+ /// let result = unsafe { Simd::gather_select_unchecked(&vec, enable, idxs, alt) };
+ /// assert_eq!(result, Simd::from_array([-5, 13, 10, -2]));
+ /// ```
+ /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+ #[must_use]
+ #[inline]
+ pub unsafe fn gather_select_unchecked(
+ slice: &[T],
+ enable: Mask<isize, LANES>,
+ idxs: Simd<usize, LANES>,
+ or: Self,
+ ) -> Self {
+ let base_ptr = crate::simd::ptr::SimdConstPtr::splat(slice.as_ptr());
+ // Ferris forgive me, I have done pointer arithmetic here.
+ let ptrs = base_ptr.wrapping_add(idxs);
+ // SAFETY: The ptrs have been bounds-masked to prevent memory-unsafe reads insha'allah
+ unsafe { intrinsics::simd_gather(or, ptrs, enable.to_int()) }
+ }
+
+ /// Writes the values in a SIMD vector to potentially discontiguous indices in `slice`.
+ /// If two lanes in the scattered vector would write to the same index
+ /// only the last lane is guaranteed to actually be written.
+ ///
+ /// # Examples
+ /// ```
+ /// # #![feature(portable_simd)]
+ /// # #[cfg(feature = "std")] use core_simd::Simd;
+ /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+ /// let mut vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
+ /// let idxs = Simd::from_array([9, 3, 0, 0]);
+ /// let vals = Simd::from_array([-27, 82, -41, 124]);
+ ///
+ /// vals.scatter(&mut vec, idxs); // index 0 receives two writes.
+ /// assert_eq!(vec, vec![124, 11, 12, 82, 14, 15, 16, 17, 18]);
+ /// ```
+ #[inline]
+ pub fn scatter(self, slice: &mut [T], idxs: Simd<usize, LANES>) {
+ self.scatter_select(slice, Mask::splat(true), idxs)
+ }
+
+ /// Writes the values in a SIMD vector to multiple potentially discontiguous indices in `slice`.
+ /// The mask `enable`s all `true` lanes and disables all `false` lanes.
+ /// If an enabled index is out-of-bounds, the lane is not written.
+ /// If two enabled lanes in the scattered vector would write to the same index,
+ /// only the last lane is guaranteed to actually be written.
+ ///
+ /// # Examples
+ /// ```
+ /// # #![feature(portable_simd)]
+ /// # #[cfg(feature = "std")] use core_simd::{Simd, Mask};
+ /// # #[cfg(not(feature = "std"))] use core::simd::{Simd, Mask};
+ /// let mut vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
+ /// let idxs = Simd::from_array([9, 3, 0, 0]);
+ /// let vals = Simd::from_array([-27, 82, -41, 124]);
+ /// let enable = Mask::from_array([true, true, true, false]); // Note the mask of the last lane.
+ ///
+ /// vals.scatter_select(&mut vec, enable, idxs); // index 0's second write is masked, thus omitted.
+ /// assert_eq!(vec, vec![-41, 11, 12, 82, 14, 15, 16, 17, 18]);
+ /// ```
+ #[inline]
+ pub fn scatter_select(
+ self,
+ slice: &mut [T],
+ enable: Mask<isize, LANES>,
+ idxs: Simd<usize, LANES>,
+ ) {
+ let enable: Mask<isize, LANES> = enable & idxs.lanes_lt(Simd::splat(slice.len()));
+ // SAFETY: We have masked-off out-of-bounds lanes.
+ unsafe { self.scatter_select_unchecked(slice, enable, idxs) }
+ }
+
+ /// Writes the values in a SIMD vector to multiple potentially discontiguous indices in `slice`.
+ /// The mask `enable`s all `true` lanes and disables all `false` lanes.
+ /// If two enabled lanes in the scattered vector would write to the same index,
+ /// only the last lane is guaranteed to actually be written.
+ ///
+ /// # Safety
+ ///
+ /// Calling this function with an enabled out-of-bounds index is *[undefined behavior]*,
+ /// and may lead to memory corruption.
+ ///
+ /// # Examples
+ /// ```
+ /// # #![feature(portable_simd)]
+ /// # #[cfg(feature = "std")] use core_simd::{Simd, Mask};
+ /// # #[cfg(not(feature = "std"))] use core::simd::{Simd, Mask};
+ /// let mut vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
+ /// let idxs = Simd::from_array([9, 3, 0, 0]);
+ /// let vals = Simd::from_array([-27, 82, -41, 124]);
+ /// let enable = Mask::from_array([true, true, true, false]); // Note the mask of the last lane.
+ /// // If this mask was used to scatter, it would be unsound. Let's fix that.
+ /// let enable = enable & idxs.lanes_lt(Simd::splat(vec.len()));
+ ///
+ /// // We have masked the OOB lane, so it's safe to scatter now.
+ /// unsafe { vals.scatter_select_unchecked(&mut vec, enable, idxs); }
+ /// // index 0's second write is masked, thus was omitted.
+ /// assert_eq!(vec, vec![-41, 11, 12, 82, 14, 15, 16, 17, 18]);
+ /// ```
+ /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+ #[inline]
+ pub unsafe fn scatter_select_unchecked(
+ self,
+ slice: &mut [T],
+ enable: Mask<isize, LANES>,
+ idxs: Simd<usize, LANES>,
+ ) {
+ // SAFETY: This block works with *mut T derived from &mut 'a [T],
+ // which means it is delicate in Rust's borrowing model, circa 2021:
+ // &mut 'a [T] asserts uniqueness, so deriving &'a [T] invalidates live *mut Ts!
+ // Even though this block is largely safe methods, it must be exactly this way
+ // to prevent invalidating the raw ptrs while they're live.
+ // Thus, entering this block requires all values to use being already ready:
+ // 0. idxs we want to write to, which are used to construct the mask.
+ // 1. enable, which depends on an initial &'a [T] and the idxs.
+ // 2. actual values to scatter (self).
+ // 3. &mut [T] which will become our base ptr.
+ unsafe {
+ // Now Entering ☢️ *mut T Zone
+ let base_ptr = crate::simd::ptr::SimdMutPtr::splat(slice.as_mut_ptr());
+ // Ferris forgive me, I have done pointer arithmetic here.
+ let ptrs = base_ptr.wrapping_add(idxs);
+ // The ptrs have been bounds-masked to prevent memory-unsafe writes insha'allah
+ intrinsics::simd_scatter(self, ptrs, enable.to_int())
+ // Cleared ☢️ *mut T Zone
+ }
+ }
+}
+
+impl<T, const LANES: usize> Copy for Simd<T, LANES>
+where
+ T: SimdElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+}
+
+impl<T, const LANES: usize> Clone for Simd<T, LANES>
+where
+ T: SimdElement,
+ LaneCount<LANES>: SupportedLaneCount,
+{
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+impl<T, const LANES: usize> Default for Simd<T, LANES>
+where
+ LaneCount<LANES>: SupportedLaneCount,
+ T: SimdElement + Default,
+{
+ #[inline]
+ fn default() -> Self {
+ Self::splat(T::default())
+ }
+}
+
+impl<T, const LANES: usize> PartialEq for Simd<T, LANES>
+where
+ LaneCount<LANES>: SupportedLaneCount,
+ T: SimdElement + PartialEq,
+{
+ #[inline]
+ fn eq(&self, other: &Self) -> bool {
+ // TODO use SIMD equality
+ self.to_array() == other.to_array()
+ }
+}
+
+impl<T, const LANES: usize> PartialOrd for Simd<T, LANES>
+where
+ LaneCount<LANES>: SupportedLaneCount,
+ T: SimdElement + PartialOrd,
+{
+ #[inline]
+ fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
+ // TODO use SIMD equality
+ self.to_array().partial_cmp(other.as_ref())
+ }
+}
+
+impl<T, const LANES: usize> Eq for Simd<T, LANES>
+where
+ LaneCount<LANES>: SupportedLaneCount,
+ T: SimdElement + Eq,
+{
+}
+
+impl<T, const LANES: usize> Ord for Simd<T, LANES>
+where
+ LaneCount<LANES>: SupportedLaneCount,
+ T: SimdElement + Ord,
+{
+ #[inline]
+ fn cmp(&self, other: &Self) -> core::cmp::Ordering {
+ // TODO use SIMD equality
+ self.to_array().cmp(other.as_ref())
+ }
+}
+
+impl<T, const LANES: usize> core::hash::Hash for Simd<T, LANES>
+where
+ LaneCount<LANES>: SupportedLaneCount,
+ T: SimdElement + core::hash::Hash,
+{
+ #[inline]
+ fn hash<H>(&self, state: &mut H)
+ where
+ H: core::hash::Hasher,
+ {
+ self.as_array().hash(state)
+ }
+}
+
+// array references
+impl<T, const LANES: usize> AsRef<[T; LANES]> for Simd<T, LANES>
+where
+ LaneCount<LANES>: SupportedLaneCount,
+ T: SimdElement,
+{
+ #[inline]
+ fn as_ref(&self) -> &[T; LANES] {
+ &self.0
+ }
+}
+
+impl<T, const LANES: usize> AsMut<[T; LANES]> for Simd<T, LANES>
+where
+ LaneCount<LANES>: SupportedLaneCount,
+ T: SimdElement,
+{
+ #[inline]
+ fn as_mut(&mut self) -> &mut [T; LANES] {
+ &mut self.0
+ }
+}
+
+// slice references
+impl<T, const LANES: usize> AsRef<[T]> for Simd<T, LANES>
+where
+ LaneCount<LANES>: SupportedLaneCount,
+ T: SimdElement,
+{
+ #[inline]
+ fn as_ref(&self) -> &[T] {
+ &self.0
+ }
+}
+
+impl<T, const LANES: usize> AsMut<[T]> for Simd<T, LANES>
+where
+ LaneCount<LANES>: SupportedLaneCount,
+ T: SimdElement,
+{
+ #[inline]
+ fn as_mut(&mut self) -> &mut [T] {
+ &mut self.0
+ }
+}
+
+// vector/array conversion
+impl<T, const LANES: usize> From<[T; LANES]> for Simd<T, LANES>
+where
+ LaneCount<LANES>: SupportedLaneCount,
+ T: SimdElement,
+{
+ fn from(array: [T; LANES]) -> Self {
+ Self(array)
+ }
+}
+
+impl<T, const LANES: usize> From<Simd<T, LANES>> for [T; LANES]
+where
+ LaneCount<LANES>: SupportedLaneCount,
+ T: SimdElement,
+{
+ fn from(vector: Simd<T, LANES>) -> Self {
+ vector.to_array()
+ }
+}
+
+mod sealed {
+ pub trait Sealed {}
+}
+use sealed::Sealed;
+
+/// Marker trait for types that may be used as SIMD vector elements.
+/// SAFETY: This trait, when implemented, asserts the compiler can monomorphize
+/// `#[repr(simd)]` structs with the marked type as an element.
+/// Strictly, it is valid to impl if the vector will not be miscompiled.
+/// Practically, it is user-unfriendly to impl it if the vector won't compile,
+/// even when no soundness guarantees are broken by allowing the user to try.
+pub unsafe trait SimdElement: Sealed + Copy {
+ /// The mask element type corresponding to this element type.
+ type Mask: MaskElement;
+}
+
+impl Sealed for u8 {}
+unsafe impl SimdElement for u8 {
+ type Mask = i8;
+}
+
+impl Sealed for u16 {}
+unsafe impl SimdElement for u16 {
+ type Mask = i16;
+}
+
+impl Sealed for u32 {}
+unsafe impl SimdElement for u32 {
+ type Mask = i32;
+}
+
+impl Sealed for u64 {}
+unsafe impl SimdElement for u64 {
+ type Mask = i64;
+}
+
+impl Sealed for usize {}
+unsafe impl SimdElement for usize {
+ type Mask = isize;
+}
+
+impl Sealed for i8 {}
+unsafe impl SimdElement for i8 {
+ type Mask = i8;
+}
+
+impl Sealed for i16 {}
+unsafe impl SimdElement for i16 {
+ type Mask = i16;
+}
+
+impl Sealed for i32 {}
+unsafe impl SimdElement for i32 {
+ type Mask = i32;
+}
+
+impl Sealed for i64 {}
+unsafe impl SimdElement for i64 {
+ type Mask = i64;
+}
+
+impl Sealed for isize {}
+unsafe impl SimdElement for isize {
+ type Mask = isize;
+}
+
+impl Sealed for f32 {}
+unsafe impl SimdElement for f32 {
+ type Mask = i32;
+}
+
+impl Sealed for f64 {}
+unsafe impl SimdElement for f64 {
+ type Mask = i64;
+}
--- /dev/null
+#![allow(non_camel_case_types)]
+
+use crate::simd::intrinsics;
+use crate::simd::{LaneCount, Mask, Simd, SupportedLaneCount};
+
+/// Implements inherent methods for a float vector containing multiple
+/// `$lanes` of float `$type`, which uses `$bits_ty` as its binary
+/// representation.
+macro_rules! impl_float_vector {
+ { $type:ty, $bits_ty:ty, $mask_ty:ty } => {
+ impl<const LANES: usize> Simd<$type, LANES>
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ /// Raw transmutation to an unsigned integer vector type with the
+ /// same size and number of lanes.
+ #[inline]
+ pub fn to_bits(self) -> Simd<$bits_ty, LANES> {
+ assert_eq!(core::mem::size_of::<Self>(), core::mem::size_of::<Simd<$bits_ty, LANES>>());
+ unsafe { core::mem::transmute_copy(&self) }
+ }
+
+ /// Raw transmutation from an unsigned integer vector type with the
+ /// same size and number of lanes.
+ #[inline]
+ pub fn from_bits(bits: Simd<$bits_ty, LANES>) -> Self {
+ assert_eq!(core::mem::size_of::<Self>(), core::mem::size_of::<Simd<$bits_ty, LANES>>());
+ unsafe { core::mem::transmute_copy(&bits) }
+ }
+
+ /// Produces a vector where every lane has the absolute value of the
+ /// equivalently-indexed lane in `self`.
+ #[inline]
+ pub fn abs(self) -> Self {
+ unsafe { intrinsics::simd_fabs(self) }
+ }
+
+ /// Fused multiply-add. Computes `(self * a) + b` with only one rounding error,
+ /// yielding a more accurate result than an unfused multiply-add.
+ ///
+ /// Using `mul_add` *may* be more performant than an unfused multiply-add if the target
+ /// architecture has a dedicated `fma` CPU instruction. However, this is not always
+ /// true, and will be heavily dependent on designing algorithms with specific target
+ /// hardware in mind.
+ #[cfg(feature = "std")]
+ #[inline]
+ pub fn mul_add(self, a: Self, b: Self) -> Self {
+ unsafe { intrinsics::simd_fma(self, a, b) }
+ }
+
+ /// Produces a vector where every lane has the square root value
+ /// of the equivalently-indexed lane in `self`
+ #[inline]
+ #[cfg(feature = "std")]
+ pub fn sqrt(self) -> Self {
+ unsafe { intrinsics::simd_fsqrt(self) }
+ }
+
+ /// Takes the reciprocal (inverse) of each lane, `1/x`.
+ #[inline]
+ pub fn recip(self) -> Self {
+ Self::splat(1.0) / self
+ }
+
+ /// Converts each lane from radians to degrees.
+ #[inline]
+ pub fn to_degrees(self) -> Self {
+ // to_degrees uses a special constant for better precision, so extract that constant
+ self * Self::splat(<$type>::to_degrees(1.))
+ }
+
+ /// Converts each lane from degrees to radians.
+ #[inline]
+ pub fn to_radians(self) -> Self {
+ self * Self::splat(<$type>::to_radians(1.))
+ }
+
+ /// Returns true for each lane if it has a positive sign, including
+ /// `+0.0`, `NaN`s with positive sign bit and positive infinity.
+ #[inline]
+ pub fn is_sign_positive(self) -> Mask<$mask_ty, LANES> {
+ !self.is_sign_negative()
+ }
+
+ /// Returns true for each lane if it has a negative sign, including
+ /// `-0.0`, `NaN`s with negative sign bit and negative infinity.
+ #[inline]
+ pub fn is_sign_negative(self) -> Mask<$mask_ty, LANES> {
+ let sign_bits = self.to_bits() & Simd::splat((!0 >> 1) + 1);
+ sign_bits.lanes_gt(Simd::splat(0))
+ }
+
+ /// Returns true for each lane if its value is `NaN`.
+ #[inline]
+ pub fn is_nan(self) -> Mask<$mask_ty, LANES> {
+ self.lanes_ne(self)
+ }
+
+ /// Returns true for each lane if its value is positive infinity or negative infinity.
+ #[inline]
+ pub fn is_infinite(self) -> Mask<$mask_ty, LANES> {
+ self.abs().lanes_eq(Self::splat(<$type>::INFINITY))
+ }
+
+ /// Returns true for each lane if its value is neither infinite nor `NaN`.
+ #[inline]
+ pub fn is_finite(self) -> Mask<$mask_ty, LANES> {
+ self.abs().lanes_lt(Self::splat(<$type>::INFINITY))
+ }
+
+ /// Returns true for each lane if its value is subnormal.
+ #[inline]
+ pub fn is_subnormal(self) -> Mask<$mask_ty, LANES> {
+ self.abs().lanes_ne(Self::splat(0.0)) & (self.to_bits() & Self::splat(<$type>::INFINITY).to_bits()).lanes_eq(Simd::splat(0))
+ }
+
+ /// Returns true for each lane if its value is neither neither zero, infinite,
+ /// subnormal, or `NaN`.
+ #[inline]
+ pub fn is_normal(self) -> Mask<$mask_ty, LANES> {
+ !(self.abs().lanes_eq(Self::splat(0.0)) | self.is_nan() | self.is_subnormal() | self.is_infinite())
+ }
+
+ /// Replaces each lane with a number that represents its sign.
+ ///
+ /// * `1.0` if the number is positive, `+0.0`, or `INFINITY`
+ /// * `-1.0` if the number is negative, `-0.0`, or `NEG_INFINITY`
+ /// * `NAN` if the number is `NAN`
+ #[inline]
+ pub fn signum(self) -> Self {
+ self.is_nan().select(Self::splat(<$type>::NAN), Self::splat(1.0).copysign(self))
+ }
+
+ /// Returns each lane with the magnitude of `self` and the sign of `sign`.
+ ///
+ /// If any lane is a `NAN`, then a `NAN` with the sign of `sign` is returned.
+ #[inline]
+ pub fn copysign(self, sign: Self) -> Self {
+ let sign_bit = sign.to_bits() & Self::splat(-0.).to_bits();
+ let magnitude = self.to_bits() & !Self::splat(-0.).to_bits();
+ Self::from_bits(sign_bit | magnitude)
+ }
+
+ /// Returns the minimum of each lane.
+ ///
+ /// If one of the values is `NAN`, then the other value is returned.
+ #[inline]
+ pub fn min(self, other: Self) -> Self {
+ // TODO consider using an intrinsic
+ self.is_nan().select(
+ other,
+ self.lanes_ge(other).select(other, self)
+ )
+ }
+
+ /// Returns the maximum of each lane.
+ ///
+ /// If one of the values is `NAN`, then the other value is returned.
+ #[inline]
+ pub fn max(self, other: Self) -> Self {
+ // TODO consider using an intrinsic
+ self.is_nan().select(
+ other,
+ self.lanes_le(other).select(other, self)
+ )
+ }
+
+ /// Restrict each lane to a certain interval unless it is NaN.
+ ///
+ /// For each lane in `self`, returns the corresponding lane in `max` if the lane is
+ /// greater than `max`, and the corresponding lane in `min` if the lane is less
+ /// than `min`. Otherwise returns the lane in `self`.
+ #[inline]
+ pub fn clamp(self, min: Self, max: Self) -> Self {
+ assert!(
+ min.lanes_le(max).all(),
+ "each lane in `min` must be less than or equal to the corresponding lane in `max`",
+ );
+ let mut x = self;
+ x = x.lanes_lt(min).select(min, x);
+ x = x.lanes_gt(max).select(max, x);
+ x
+ }
+ }
+ };
+}
+
+impl_float_vector! { f32, u32, i32 }
+impl_float_vector! { f64, u64, i64 }
+
+/// Vector of two `f32` values
+pub type f32x2 = Simd<f32, 2>;
+
+/// Vector of four `f32` values
+pub type f32x4 = Simd<f32, 4>;
+
+/// Vector of eight `f32` values
+pub type f32x8 = Simd<f32, 8>;
+
+/// Vector of 16 `f32` values
+pub type f32x16 = Simd<f32, 16>;
+
+/// Vector of two `f64` values
+pub type f64x2 = Simd<f64, 2>;
+
+/// Vector of four `f64` values
+pub type f64x4 = Simd<f64, 4>;
+
+/// Vector of eight `f64` values
+pub type f64x8 = Simd<f64, 8>;
--- /dev/null
+#![allow(non_camel_case_types)]
+
+use crate::simd::{LaneCount, Mask, Simd, SupportedLaneCount};
+
+/// Implements additional integer traits (Eq, Ord, Hash) on the specified vector `$name`, holding multiple `$lanes` of `$type`.
+macro_rules! impl_integer_vector {
+ { $type:ty } => {
+ impl<const LANES: usize> Simd<$type, LANES>
+ where
+ LaneCount<LANES>: SupportedLaneCount,
+ {
+ /// Returns true for each positive lane and false if it is zero or negative.
+ #[inline]
+ pub fn is_positive(self) -> Mask<$type, LANES> {
+ self.lanes_gt(Self::splat(0))
+ }
+
+ /// Returns true for each negative lane and false if it is zero or positive.
+ #[inline]
+ pub fn is_negative(self) -> Mask<$type, LANES> {
+ self.lanes_lt(Self::splat(0))
+ }
+
+ /// Returns numbers representing the sign of each lane.
+ /// * `0` if the number is zero
+ /// * `1` if the number is positive
+ /// * `-1` if the number is negative
+ #[inline]
+ pub fn signum(self) -> Self {
+ self.is_positive().select(
+ Self::splat(1),
+ self.is_negative().select(Self::splat(-1), Self::splat(0))
+ )
+ }
+ }
+ }
+}
+
+impl_integer_vector! { isize }
+impl_integer_vector! { i16 }
+impl_integer_vector! { i32 }
+impl_integer_vector! { i64 }
+impl_integer_vector! { i8 }
+
+/// Vector of two `isize` values
+pub type isizex2 = Simd<isize, 2>;
+
+/// Vector of four `isize` values
+pub type isizex4 = Simd<isize, 4>;
+
+/// Vector of eight `isize` values
+pub type isizex8 = Simd<isize, 8>;
+
+/// Vector of two `i16` values
+pub type i16x2 = Simd<i16, 2>;
+
+/// Vector of four `i16` values
+pub type i16x4 = Simd<i16, 4>;
+
+/// Vector of eight `i16` values
+pub type i16x8 = Simd<i16, 8>;
+
+/// Vector of 16 `i16` values
+pub type i16x16 = Simd<i16, 16>;
+
+/// Vector of 32 `i16` values
+pub type i16x32 = Simd<i16, 32>;
+
+/// Vector of two `i32` values
+pub type i32x2 = Simd<i32, 2>;
+
+/// Vector of four `i32` values
+pub type i32x4 = Simd<i32, 4>;
+
+/// Vector of eight `i32` values
+pub type i32x8 = Simd<i32, 8>;
+
+/// Vector of 16 `i32` values
+pub type i32x16 = Simd<i32, 16>;
+
+/// Vector of two `i64` values
+pub type i64x2 = Simd<i64, 2>;
+
+/// Vector of four `i64` values
+pub type i64x4 = Simd<i64, 4>;
+
+/// Vector of eight `i64` values
+pub type i64x8 = Simd<i64, 8>;
+
+/// Vector of four `i8` values
+pub type i8x4 = Simd<i8, 4>;
+
+/// Vector of eight `i8` values
+pub type i8x8 = Simd<i8, 8>;
+
+/// Vector of 16 `i8` values
+pub type i8x16 = Simd<i8, 16>;
+
+/// Vector of 32 `i8` values
+pub type i8x32 = Simd<i8, 32>;
+
+/// Vector of 64 `i8` values
+pub type i8x64 = Simd<i8, 64>;
--- /dev/null
+//! Private implementation details of public gather/scatter APIs.
+use crate::simd::{LaneCount, Simd, SupportedLaneCount};
+use core::mem;
+
+/// A vector of *const T.
+#[derive(Debug, Copy, Clone)]
+#[repr(simd)]
+pub(crate) struct SimdConstPtr<T, const LANES: usize>([*const T; LANES]);
+
+impl<T, const LANES: usize> SimdConstPtr<T, LANES>
+where
+ LaneCount<LANES>: SupportedLaneCount,
+ T: Sized,
+{
+ #[inline]
+ #[must_use]
+ pub fn splat(ptr: *const T) -> Self {
+ Self([ptr; LANES])
+ }
+
+ #[inline]
+ #[must_use]
+ pub fn wrapping_add(self, addend: Simd<usize, LANES>) -> Self {
+ unsafe {
+ let x: Simd<usize, LANES> = mem::transmute_copy(&self);
+ mem::transmute_copy(&{ x + (addend * mem::size_of::<T>()) })
+ }
+ }
+}
+
+/// A vector of *mut T. Be very careful around potential aliasing.
+#[derive(Debug, Copy, Clone)]
+#[repr(simd)]
+pub(crate) struct SimdMutPtr<T, const LANES: usize>([*mut T; LANES]);
+
+impl<T, const LANES: usize> SimdMutPtr<T, LANES>
+where
+ LaneCount<LANES>: SupportedLaneCount,
+ T: Sized,
+{
+ #[inline]
+ #[must_use]
+ pub fn splat(ptr: *mut T) -> Self {
+ Self([ptr; LANES])
+ }
+
+ #[inline]
+ #[must_use]
+ pub fn wrapping_add(self, addend: Simd<usize, LANES>) -> Self {
+ unsafe {
+ let x: Simd<usize, LANES> = mem::transmute_copy(&self);
+ mem::transmute_copy(&{ x + (addend * mem::size_of::<T>()) })
+ }
+ }
+}
--- /dev/null
+#![allow(non_camel_case_types)]
+
+use crate::simd::Simd;
+
+/// Vector of two `usize` values
+pub type usizex2 = Simd<usize, 2>;
+
+/// Vector of four `usize` values
+pub type usizex4 = Simd<usize, 4>;
+
+/// Vector of eight `usize` values
+pub type usizex8 = Simd<usize, 8>;
+
+/// Vector of two `u16` values
+pub type u16x2 = Simd<u16, 2>;
+
+/// Vector of four `u16` values
+pub type u16x4 = Simd<u16, 4>;
+
+/// Vector of eight `u16` values
+pub type u16x8 = Simd<u16, 8>;
+
+/// Vector of 16 `u16` values
+pub type u16x16 = Simd<u16, 16>;
+
+/// Vector of 32 `u16` values
+pub type u16x32 = Simd<u16, 32>;
+
+/// Vector of two `u32` values
+pub type u32x2 = Simd<u32, 2>;
+
+/// Vector of four `u32` values
+pub type u32x4 = Simd<u32, 4>;
+
+/// Vector of eight `u32` values
+pub type u32x8 = Simd<u32, 8>;
+
+/// Vector of 16 `u32` values
+pub type u32x16 = Simd<u32, 16>;
+
+/// Vector of two `u64` values
+pub type u64x2 = Simd<u64, 2>;
+
+/// Vector of four `u64` values
+pub type u64x4 = Simd<u64, 4>;
+
+/// Vector of eight `u64` values
+pub type u64x8 = Simd<u64, 8>;
+
+/// Vector of four `u8` values
+pub type u8x4 = Simd<u8, 4>;
+
+/// Vector of eight `u8` values
+pub type u8x8 = Simd<u8, 8>;
+
+/// Vector of 16 `u8` values
+pub type u8x16 = Simd<u8, 16>;
+
+/// Vector of 32 `u8` values
+pub type u8x32 = Simd<u8, 32>;
+
+/// Vector of 64 `u8` values
+pub type u8x64 = Simd<u8, 64>;
--- /dev/null
+/// Provides implementations of `From<$a> for $b` and `From<$b> for $a` that transmutes the value.
+#[allow(unused)]
+macro_rules! from_transmute {
+ { unsafe $a:ty => $b:ty } => {
+ from_transmute!{ @impl $a => $b }
+ from_transmute!{ @impl $b => $a }
+ };
+ { @impl $from:ty => $to:ty } => {
+ impl core::convert::From<$from> for $to {
+ #[inline]
+ fn from(value: $from) -> $to {
+ unsafe { core::mem::transmute(value) }
+ }
+ }
+ };
+}
+
+/// Conversions to x86's SIMD types.
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+mod x86;
+
+#[cfg(any(target_arch = "wasm32"))]
+mod wasm32;
+
+#[cfg(any(target_arch = "aarch64", target_arch = "arm",))]
+mod arm;
+
+#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
+mod powerpc;
--- /dev/null
+#![allow(unused)]
+use crate::simd::*;
+
+#[cfg(target_arch = "arm")]
+use core::arch::arm::*;
+
+#[cfg(target_arch = "aarch64")]
+use core::arch::aarch64::*;
+
+#[cfg(any(
+ target_arch = "aarch64",
+ all(target_arch = "arm", target_feature = "v7"),
+))]
+mod neon {
+ use super::*;
+
+ from_transmute! { unsafe f32x2 => float32x2_t }
+ from_transmute! { unsafe f32x4 => float32x4_t }
+
+ from_transmute! { unsafe u8x8 => uint8x8_t }
+ from_transmute! { unsafe u8x16 => uint8x16_t }
+ from_transmute! { unsafe i8x8 => int8x8_t }
+ from_transmute! { unsafe i8x16 => int8x16_t }
+ from_transmute! { unsafe u8x8 => poly8x8_t }
+ from_transmute! { unsafe u8x16 => poly8x16_t }
+
+ from_transmute! { unsafe u16x4 => uint16x4_t }
+ from_transmute! { unsafe u16x8 => uint16x8_t }
+ from_transmute! { unsafe i16x4 => int16x4_t }
+ from_transmute! { unsafe i16x8 => int16x8_t }
+ from_transmute! { unsafe u16x4 => poly16x4_t }
+ from_transmute! { unsafe u16x8 => poly16x8_t }
+
+ from_transmute! { unsafe u32x2 => uint32x2_t }
+ from_transmute! { unsafe u32x4 => uint32x4_t }
+ from_transmute! { unsafe i32x2 => int32x2_t }
+ from_transmute! { unsafe i32x4 => int32x4_t }
+
+ from_transmute! { unsafe Simd<u64, 1> => uint64x1_t }
+ from_transmute! { unsafe u64x2 => uint64x2_t }
+ from_transmute! { unsafe Simd<i64, 1> => int64x1_t }
+ from_transmute! { unsafe i64x2 => int64x2_t }
+ from_transmute! { unsafe Simd<u64, 1> => poly64x1_t }
+ from_transmute! { unsafe u64x2 => poly64x2_t }
+}
+
+#[cfg(any(
+ all(target_feature = "v5te", not(target_feature = "mclass")),
+ all(target_feature = "mclass", target_feature = "dsp"),
+))]
+mod dsp {
+ use super::*;
+
+ from_transmute! { unsafe Simd<u16, 2> => uint16x2_t }
+ from_transmute! { unsafe Simd<i16, 2> => int16x2_t }
+}
+
+#[cfg(any(
+ all(target_feature = "v6", not(target_feature = "mclass")),
+ all(target_feature = "mclass", target_feature = "dsp"),
+))]
+mod simd32 {
+ use super::*;
+
+ from_transmute! { unsafe Simd<u8, 4> => uint8x4_t }
+ from_transmute! { unsafe Simd<i8, 4> => int8x4_t }
+}
+
+#[cfg(target_arch = "aarch64")]
+mod aarch64 {
+ use super::neon::*;
+ use super::*;
+
+ from_transmute! { unsafe Simd<f64, 1> => float64x1_t }
+ from_transmute! { unsafe f64x2 => float64x2_t }
+}
--- /dev/null
+use crate::simd::*;
+
+#[cfg(target_arch = "powerpc")]
+use core::arch::powerpc::*;
+
+#[cfg(target_arch = "powerpc64")]
+use core::arch::powerpc64::*;
+
+from_transmute! { unsafe f64x2 => vector_double }
+from_transmute! { unsafe i64x2 => vector_signed_long }
+from_transmute! { unsafe u64x2 => vector_unsigned_long }
--- /dev/null
+use crate::simd::*;
+use core::arch::wasm32::v128;
+
+from_transmute! { unsafe u8x16 => v128 }
+from_transmute! { unsafe i8x16 => v128 }
+
+from_transmute! { unsafe u16x8 => v128 }
+from_transmute! { unsafe i16x8 => v128 }
+
+from_transmute! { unsafe u32x4 => v128 }
+from_transmute! { unsafe i32x4 => v128 }
+from_transmute! { unsafe f32x4 => v128 }
+
+from_transmute! { unsafe u64x2 => v128 }
+from_transmute! { unsafe i64x2 => v128 }
+from_transmute! { unsafe f64x2 => v128 }
+
+#[cfg(target_pointer_width = "32")]
+mod p32 {
+ use super::*;
+ from_transmute! { unsafe usizex4 => v128 }
+ from_transmute! { unsafe isizex4 => v128 }
+}
+
+#[cfg(target_pointer_width = "64")]
+mod p64 {
+ use super::*;
+ from_transmute! { unsafe usizex2 => v128 }
+ from_transmute! { unsafe isizex2 => v128 }
+}
--- /dev/null
+use crate::simd::*;
+
+#[cfg(any(target_arch = "x86"))]
+use core::arch::x86::*;
+
+#[cfg(target_arch = "x86_64")]
+use core::arch::x86_64::*;
+
+from_transmute! { unsafe u8x16 => __m128i }
+from_transmute! { unsafe u8x32 => __m256i }
+//from_transmute! { unsafe u8x64 => __m512i }
+from_transmute! { unsafe i8x16 => __m128i }
+from_transmute! { unsafe i8x32 => __m256i }
+//from_transmute! { unsafe i8x64 => __m512i }
+
+from_transmute! { unsafe u16x8 => __m128i }
+from_transmute! { unsafe u16x16 => __m256i }
+from_transmute! { unsafe u16x32 => __m512i }
+from_transmute! { unsafe i16x8 => __m128i }
+from_transmute! { unsafe i16x16 => __m256i }
+from_transmute! { unsafe i16x32 => __m512i }
+
+from_transmute! { unsafe u32x4 => __m128i }
+from_transmute! { unsafe u32x8 => __m256i }
+from_transmute! { unsafe u32x16 => __m512i }
+from_transmute! { unsafe i32x4 => __m128i }
+from_transmute! { unsafe i32x8 => __m256i }
+from_transmute! { unsafe i32x16 => __m512i }
+from_transmute! { unsafe f32x4 => __m128 }
+from_transmute! { unsafe f32x8 => __m256 }
+from_transmute! { unsafe f32x16 => __m512 }
+
+from_transmute! { unsafe u64x2 => __m128i }
+from_transmute! { unsafe u64x4 => __m256i }
+from_transmute! { unsafe u64x8 => __m512i }
+from_transmute! { unsafe i64x2 => __m128i }
+from_transmute! { unsafe i64x4 => __m256i }
+from_transmute! { unsafe i64x8 => __m512i }
+from_transmute! { unsafe f64x2 => __m128d }
+from_transmute! { unsafe f64x4 => __m256d }
+from_transmute! { unsafe f64x8 => __m512d }
+
+#[cfg(target_pointer_width = "32")]
+mod p32 {
+ use super::*;
+ from_transmute! { unsafe usizex4 => __m128i }
+ from_transmute! { unsafe usizex8 => __m256i }
+ from_transmute! { unsafe Simd<usize, 16> => __m512i }
+ from_transmute! { unsafe isizex4 => __m128i }
+ from_transmute! { unsafe isizex8 => __m256i }
+ from_transmute! { unsafe Simd<isize, 16> => __m512i }
+}
+
+#[cfg(target_pointer_width = "64")]
+mod p64 {
+ use super::*;
+ from_transmute! { unsafe usizex2 => __m128i }
+ from_transmute! { unsafe usizex4 => __m256i }
+ from_transmute! { unsafe usizex8 => __m512i }
+ from_transmute! { unsafe isizex2 => __m128i }
+ from_transmute! { unsafe isizex4 => __m256i }
+ from_transmute! { unsafe isizex8 => __m512i }
+}
--- /dev/null
+#![feature(portable_simd)]
+
+#[macro_use]
+mod ops_macros;
+impl_float_tests! { f32, i32 }
--- /dev/null
+#![feature(portable_simd)]
+
+#[macro_use]
+mod ops_macros;
+impl_float_tests! { f64, i64 }
--- /dev/null
+#![feature(portable_simd)]
+
+#[macro_use]
+mod ops_macros;
+impl_signed_tests! { i16 }
--- /dev/null
+#![feature(portable_simd)]
+
+#[macro_use]
+mod ops_macros;
+impl_signed_tests! { i32 }
--- /dev/null
+#![feature(portable_simd)]
+
+#[macro_use]
+mod ops_macros;
+impl_signed_tests! { i64 }
--- /dev/null
+#![feature(portable_simd)]
+
+#[macro_use]
+mod ops_macros;
+impl_signed_tests! { i8 }
--- /dev/null
+#![feature(portable_simd)]
+
+#[macro_use]
+mod ops_macros;
+impl_signed_tests! { isize }
--- /dev/null
+#![feature(portable_simd)]
+
+mod mask_ops_impl;
--- /dev/null
+mask_tests! { mask16x4, 4 }
+mask_tests! { mask16x8, 8 }
+mask_tests! { mask16x16, 16 }
+mask_tests! { mask16x32, 32 }
--- /dev/null
+mask_tests! { mask32x2, 2 }
+mask_tests! { mask32x4, 4 }
+mask_tests! { mask32x8, 8 }
+mask_tests! { mask32x16, 16 }
--- /dev/null
+mask_tests! { mask64x2, 2 }
+mask_tests! { mask64x4, 4 }
+mask_tests! { mask64x8, 8 }
--- /dev/null
+mask_tests! { mask8x8, 8 }
+mask_tests! { mask8x16, 16 }
+mask_tests! { mask8x32, 32 }
--- /dev/null
+macro_rules! mask_tests {
+ { $vector:ident, $lanes:literal } => {
+ #[cfg(test)]
+ mod $vector {
+ use core_simd::$vector as Vector;
+ const LANES: usize = $lanes;
+
+ #[cfg(target_arch = "wasm32")]
+ use wasm_bindgen_test::*;
+
+ #[cfg(target_arch = "wasm32")]
+ wasm_bindgen_test_configure!(run_in_browser);
+
+ fn from_slice(slice: &[bool]) -> Vector {
+ let mut value = Vector::default();
+ for (i, b) in slice.iter().take(LANES).enumerate() {
+ value.set(i, *b);
+ }
+ value
+ }
+
+ fn apply_unary_lanewise(x: Vector, f: impl Fn(bool) -> bool) -> Vector {
+ let mut value = Vector::default();
+ for i in 0..LANES {
+ value.set(i, f(x.test(i)));
+ }
+ value
+ }
+
+ fn apply_binary_lanewise(x: Vector, y: Vector, f: impl Fn(bool, bool) -> bool) -> Vector {
+ let mut value = Vector::default();
+ for i in 0..LANES {
+ value.set(i, f(x.test(i), y.test(i)));
+ }
+ value
+ }
+
+ fn apply_binary_scalar_lhs_lanewise(x: bool, mut y: Vector, f: impl Fn(bool, bool) -> bool) -> Vector {
+ for i in 0..LANES {
+ y.set(i, f(x, y.test(i)));
+ }
+ y
+ }
+
+ fn apply_binary_scalar_rhs_lanewise(mut x: Vector, y: bool, f: impl Fn(bool, bool) -> bool) -> Vector {
+ for i in 0..LANES {
+ x.set(i, f(x.test(i), y));
+ }
+ x
+ }
+
+ const A: [bool; 64] = [
+ false, true, false, true, false, false, true, true,
+ false, true, false, true, false, false, true, true,
+ false, true, false, true, false, false, true, true,
+ false, true, false, true, false, false, true, true,
+ false, true, false, true, false, false, true, true,
+ false, true, false, true, false, false, true, true,
+ false, true, false, true, false, false, true, true,
+ false, true, false, true, false, false, true, true,
+ ];
+ const B: [bool; 64] = [
+ false, false, true, true, false, true, false, true,
+ false, false, true, true, false, true, false, true,
+ false, false, true, true, false, true, false, true,
+ false, false, true, true, false, true, false, true,
+ false, false, true, true, false, true, false, true,
+ false, false, true, true, false, true, false, true,
+ false, false, true, true, false, true, false, true,
+ false, false, true, true, false, true, false, true,
+ ];
+
+ #[test]
+ #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+ fn bitand() {
+ let a = from_slice(&A);
+ let b = from_slice(&B);
+ let expected = apply_binary_lanewise(a, b, core::ops::BitAnd::bitand);
+ assert_eq!(a & b, expected);
+ }
+
+ #[test]
+ #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+ fn bitand_assign() {
+ let mut a = from_slice(&A);
+ let b = from_slice(&B);
+ let expected = apply_binary_lanewise(a, b, core::ops::BitAnd::bitand);
+ a &= b;
+ assert_eq!(a, expected);
+ }
+
+ #[test]
+ #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+ fn bitand_scalar_rhs() {
+ let a = from_slice(&A);
+ let expected = a;
+ assert_eq!(a & true, expected);
+ assert_eq!(a & false, Vector::splat(false));
+ }
+
+ #[test]
+ #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+ fn bitand_scalar_lhs() {
+ let a = from_slice(&A);
+ let expected = a;
+ assert_eq!(true & a, expected);
+ assert_eq!(false & a, Vector::splat(false));
+ }
+
+ #[test]
+ #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+ fn bitand_assign_scalar() {
+ let mut a = from_slice(&A);
+ let expected = a;
+ a &= true;
+ assert_eq!(a, expected);
+ a &= false;
+ assert_eq!(a, Vector::splat(false));
+ }
+
+ #[test]
+ #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+ fn bitor() {
+ let a = from_slice(&A);
+ let b = from_slice(&B);
+ let expected = apply_binary_lanewise(a, b, core::ops::BitOr::bitor);
+ assert_eq!(a | b, expected);
+ }
+
+ #[test]
+ #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+ fn bitor_assign() {
+ let mut a = from_slice(&A);
+ let b = from_slice(&B);
+ let expected = apply_binary_lanewise(a, b, core::ops::BitOr::bitor);
+ a |= b;
+ assert_eq!(a, expected);
+ }
+
+ #[test]
+ #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+ fn bitor_scalar_rhs() {
+ let a = from_slice(&A);
+ assert_eq!(a | false, a);
+ assert_eq!(a | true, Vector::splat(true));
+ }
+
+ #[test]
+ #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+ fn bitor_scalar_lhs() {
+ let a = from_slice(&A);
+ assert_eq!(false | a, a);
+ assert_eq!(true | a, Vector::splat(true));
+ }
+
+ #[test]
+ #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+ fn bitor_assign_scalar() {
+ let mut a = from_slice(&A);
+ let expected = a;
+ a |= false;
+ assert_eq!(a, expected);
+ a |= true;
+ assert_eq!(a, Vector::splat(true));
+ }
+
+ #[test]
+ #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+ fn bitxor() {
+ let a = from_slice(&A);
+ let b = from_slice(&B);
+ let expected = apply_binary_lanewise(a, b, core::ops::BitXor::bitxor);
+ assert_eq!(a ^ b, expected);
+ }
+
+ #[test]
+ #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+ fn bitxor_assign() {
+ let mut a = from_slice(&A);
+ let b = from_slice(&B);
+ let expected = apply_binary_lanewise(a, b, core::ops::BitXor::bitxor);
+ a ^= b;
+ assert_eq!(a, expected);
+ }
+
+ #[test]
+ #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+ fn bitxor_scalar_rhs() {
+ let a = from_slice(&A);
+ let expected = apply_binary_scalar_rhs_lanewise(a, true, core::ops::BitXor::bitxor);
+ assert_eq!(a ^ false, a);
+ assert_eq!(a ^ true, expected);
+ }
+
+ #[test]
+ #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+ fn bitxor_scalar_lhs() {
+ let a = from_slice(&A);
+ let expected = apply_binary_scalar_lhs_lanewise(true, a, core::ops::BitXor::bitxor);
+ assert_eq!(false ^ a, a);
+ assert_eq!(true ^ a, expected);
+ }
+
+ #[test]
+ #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+ fn bitxor_assign_scalar() {
+ let mut a = from_slice(&A);
+ let expected_unset = a;
+ let expected_set = apply_binary_scalar_rhs_lanewise(a, true, core::ops::BitXor::bitxor);
+ a ^= false;
+ assert_eq!(a, expected_unset);
+ a ^= true;
+ assert_eq!(a, expected_set);
+ }
+
+ #[test]
+ #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+ fn not() {
+ let v = from_slice(&A);
+ let expected = apply_unary_lanewise(v, core::ops::Not::not);
+ assert_eq!(!v, expected);
+ }
+ }
+ }
+}
--- /dev/null
+mask_tests! { masksizex2, 2 }
+mask_tests! { masksizex4, 4 }
+mask_tests! { masksizex8, 8 }
--- /dev/null
+#[macro_use]
+mod mask_macros;
+
+#[rustfmt::skip]
+mod mask8;
+mod mask16;
+mod mask32;
+mod mask64;
+mod masksize;
--- /dev/null
+#![feature(portable_simd)]
+
+#[cfg(target_arch = "wasm32")]
+use wasm_bindgen_test::*;
+
+#[cfg(target_arch = "wasm32")]
+wasm_bindgen_test_configure!(run_in_browser);
+
+macro_rules! test_mask_api {
+ { $type:ident } => {
+ #[allow(non_snake_case)]
+ mod $type {
+ #[cfg(target_arch = "wasm32")]
+ use wasm_bindgen_test::*;
+
+ #[test]
+ #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+ fn set_and_test() {
+ let values = [true, false, false, true, false, false, true, false];
+ let mut mask = core_simd::Mask::<$type, 8>::splat(false);
+ for (lane, value) in values.iter().copied().enumerate() {
+ mask.set(lane, value);
+ }
+ for (lane, value) in values.iter().copied().enumerate() {
+ assert_eq!(mask.test(lane), value);
+ }
+ }
+
+ #[test]
+ #[should_panic]
+ fn set_invalid_lane() {
+ let mut mask = core_simd::Mask::<$type, 8>::splat(false);
+ mask.set(8, true);
+ let _ = mask;
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_invalid_lane() {
+ let mask = core_simd::Mask::<$type, 8>::splat(false);
+ let _ = mask.test(8);
+ }
+
+ #[test]
+ fn any() {
+ assert!(!core_simd::Mask::<$type, 8>::splat(false).any());
+ assert!(core_simd::Mask::<$type, 8>::splat(true).any());
+ let mut v = core_simd::Mask::<$type, 8>::splat(false);
+ v.set(2, true);
+ assert!(v.any());
+ }
+
+ #[test]
+ fn all() {
+ assert!(!core_simd::Mask::<$type, 8>::splat(false).all());
+ assert!(core_simd::Mask::<$type, 8>::splat(true).all());
+ let mut v = core_simd::Mask::<$type, 8>::splat(false);
+ v.set(2, true);
+ assert!(!v.all());
+ }
+
+ #[test]
+ fn roundtrip_int_conversion() {
+ let values = [true, false, false, true, false, false, true, false];
+ let mask = core_simd::Mask::<$type, 8>::from_array(values);
+ let int = mask.to_int();
+ assert_eq!(int.to_array(), [-1, 0, 0, -1, 0, 0, -1, 0]);
+ assert_eq!(core_simd::Mask::<$type, 8>::from_int(int), mask);
+ }
+
+ #[cfg(feature = "generic_const_exprs")]
+ #[test]
+ fn roundtrip_bitmask_conversion() {
+ let values = [
+ true, false, false, true, false, false, true, false,
+ true, true, false, false, false, false, false, true,
+ ];
+ let mask = core_simd::Mask::<$type, 16>::from_array(values);
+ let bitmask = mask.to_bitmask();
+ assert_eq!(bitmask, [0b01001001, 0b10000011]);
+ assert_eq!(core_simd::Mask::<$type, 16>::from_bitmask(bitmask), mask);
+ }
+ }
+ }
+}
+
+mod mask_api {
+ test_mask_api! { i8 }
+ test_mask_api! { i16 }
+ test_mask_api! { i32 }
+ test_mask_api! { i64 }
+ test_mask_api! { isize }
+}
+
+#[test]
+fn convert() {
+ let values = [true, false, false, true, false, false, true, false];
+ assert_eq!(
+ core_simd::Mask::<i8, 8>::from_array(values),
+ core_simd::Mask::<i32, 8>::from_array(values).into()
+ );
+}
--- /dev/null
+/// Implements a test on a unary operation using proptest.
+///
+/// Compares the vector operation to the equivalent scalar operation.
+#[macro_export]
+macro_rules! impl_unary_op_test {
+ { $scalar:ty, $trait:ident :: $fn:ident, $scalar_fn:expr } => {
+ test_helpers::test_lanes! {
+ fn $fn<const LANES: usize>() {
+ test_helpers::test_unary_elementwise(
+ &<core_simd::Simd<$scalar, LANES> as core::ops::$trait>::$fn,
+ &$scalar_fn,
+ &|_| true,
+ );
+ }
+ }
+ };
+ { $scalar:ty, $trait:ident :: $fn:ident } => {
+ impl_unary_op_test! { $scalar, $trait::$fn, <$scalar as core::ops::$trait>::$fn }
+ };
+}
+
+/// Implements a test on a binary operation using proptest.
+///
+/// Compares the vector operation to the equivalent scalar operation.
+#[macro_export]
+macro_rules! impl_binary_op_test {
+ { $scalar:ty, $trait:ident :: $fn:ident, $trait_assign:ident :: $fn_assign:ident, $scalar_fn:expr } => {
+ mod $fn {
+ use super::*;
+ use core_simd::Simd;
+
+ test_helpers::test_lanes! {
+ fn normal<const LANES: usize>() {
+ test_helpers::test_binary_elementwise(
+ &<Simd<$scalar, LANES> as core::ops::$trait>::$fn,
+ &$scalar_fn,
+ &|_, _| true,
+ );
+ }
+
+ fn scalar_rhs<const LANES: usize>() {
+ test_helpers::test_binary_scalar_rhs_elementwise(
+ &<Simd<$scalar, LANES> as core::ops::$trait<$scalar>>::$fn,
+ &$scalar_fn,
+ &|_, _| true,
+ );
+ }
+
+ fn scalar_lhs<const LANES: usize>() {
+ test_helpers::test_binary_scalar_lhs_elementwise(
+ &<$scalar as core::ops::$trait<Simd<$scalar, LANES>>>::$fn,
+ &$scalar_fn,
+ &|_, _| true,
+ );
+ }
+
+ fn assign<const LANES: usize>() {
+ test_helpers::test_binary_elementwise(
+ &|mut a, b| { <Simd<$scalar, LANES> as core::ops::$trait_assign>::$fn_assign(&mut a, b); a },
+ &$scalar_fn,
+ &|_, _| true,
+ );
+ }
+
+ fn assign_scalar_rhs<const LANES: usize>() {
+ test_helpers::test_binary_scalar_rhs_elementwise(
+ &|mut a, b| { <Simd<$scalar, LANES> as core::ops::$trait_assign<$scalar>>::$fn_assign(&mut a, b); a },
+ &$scalar_fn,
+ &|_, _| true,
+ );
+ }
+ }
+ }
+ };
+ { $scalar:ty, $trait:ident :: $fn:ident, $trait_assign:ident :: $fn_assign:ident } => {
+ impl_binary_op_test! { $scalar, $trait::$fn, $trait_assign::$fn_assign, <$scalar as core::ops::$trait>::$fn }
+ };
+}
+
+/// Implements a test on a binary operation using proptest.
+///
+/// Like `impl_binary_op_test`, but allows providing a function for rejecting particular inputs
+/// (like the `proptest_assume` macro).
+///
+/// Compares the vector operation to the equivalent scalar operation.
+#[macro_export]
+macro_rules! impl_binary_checked_op_test {
+ { $scalar:ty, $trait:ident :: $fn:ident, $trait_assign:ident :: $fn_assign:ident, $scalar_fn:expr, $check_fn:expr } => {
+ mod $fn {
+ use super::*;
+ use core_simd::Simd;
+
+ test_helpers::test_lanes! {
+ fn normal<const LANES: usize>() {
+ test_helpers::test_binary_elementwise(
+ &<Simd<$scalar, LANES> as core::ops::$trait>::$fn,
+ &$scalar_fn,
+ &|x, y| x.iter().zip(y.iter()).all(|(x, y)| $check_fn(*x, *y)),
+ );
+ }
+
+ fn scalar_rhs<const LANES: usize>() {
+ test_helpers::test_binary_scalar_rhs_elementwise(
+ &<Simd<$scalar, LANES> as core::ops::$trait<$scalar>>::$fn,
+ &$scalar_fn,
+ &|x, y| x.iter().all(|x| $check_fn(*x, y)),
+ );
+ }
+
+ fn scalar_lhs<const LANES: usize>() {
+ test_helpers::test_binary_scalar_lhs_elementwise(
+ &<$scalar as core::ops::$trait<Simd<$scalar, LANES>>>::$fn,
+ &$scalar_fn,
+ &|x, y| y.iter().all(|y| $check_fn(x, *y)),
+ );
+ }
+
+ fn assign<const LANES: usize>() {
+ test_helpers::test_binary_elementwise(
+ &|mut a, b| { <Simd<$scalar, LANES> as core::ops::$trait_assign>::$fn_assign(&mut a, b); a },
+ &$scalar_fn,
+ &|x, y| x.iter().zip(y.iter()).all(|(x, y)| $check_fn(*x, *y)),
+ )
+ }
+
+ fn assign_scalar_rhs<const LANES: usize>() {
+ test_helpers::test_binary_scalar_rhs_elementwise(
+ &|mut a, b| { <Simd<$scalar, LANES> as core::ops::$trait_assign<$scalar>>::$fn_assign(&mut a, b); a },
+ &$scalar_fn,
+ &|x, y| x.iter().all(|x| $check_fn(*x, y)),
+ )
+ }
+ }
+ }
+ };
+ { $scalar:ty, $trait:ident :: $fn:ident, $trait_assign:ident :: $fn_assign:ident, $check_fn:expr } => {
+ impl_binary_checked_op_test! { $scalar, $trait::$fn, $trait_assign::$fn_assign, <$scalar as core::ops::$trait>::$fn, $check_fn }
+ };
+}
+
+#[macro_export]
+macro_rules! impl_common_integer_tests {
+ { $vector:ident, $scalar:ident } => {
+ test_helpers::test_lanes! {
+ fn horizontal_sum<const LANES: usize>() {
+ test_helpers::test_1(&|x| {
+ test_helpers::prop_assert_biteq! (
+ $vector::<LANES>::from_array(x).horizontal_sum(),
+ x.iter().copied().fold(0 as $scalar, $scalar::wrapping_add),
+ );
+ Ok(())
+ });
+ }
+
+ fn horizontal_product<const LANES: usize>() {
+ test_helpers::test_1(&|x| {
+ test_helpers::prop_assert_biteq! (
+ $vector::<LANES>::from_array(x).horizontal_product(),
+ x.iter().copied().fold(1 as $scalar, $scalar::wrapping_mul),
+ );
+ Ok(())
+ });
+ }
+
+ fn horizontal_and<const LANES: usize>() {
+ test_helpers::test_1(&|x| {
+ test_helpers::prop_assert_biteq! (
+ $vector::<LANES>::from_array(x).horizontal_and(),
+ x.iter().copied().fold(-1i8 as $scalar, <$scalar as core::ops::BitAnd>::bitand),
+ );
+ Ok(())
+ });
+ }
+
+ fn horizontal_or<const LANES: usize>() {
+ test_helpers::test_1(&|x| {
+ test_helpers::prop_assert_biteq! (
+ $vector::<LANES>::from_array(x).horizontal_or(),
+ x.iter().copied().fold(0 as $scalar, <$scalar as core::ops::BitOr>::bitor),
+ );
+ Ok(())
+ });
+ }
+
+ fn horizontal_xor<const LANES: usize>() {
+ test_helpers::test_1(&|x| {
+ test_helpers::prop_assert_biteq! (
+ $vector::<LANES>::from_array(x).horizontal_xor(),
+ x.iter().copied().fold(0 as $scalar, <$scalar as core::ops::BitXor>::bitxor),
+ );
+ Ok(())
+ });
+ }
+
+ fn horizontal_max<const LANES: usize>() {
+ test_helpers::test_1(&|x| {
+ test_helpers::prop_assert_biteq! (
+ $vector::<LANES>::from_array(x).horizontal_max(),
+ x.iter().copied().max().unwrap(),
+ );
+ Ok(())
+ });
+ }
+
+ fn horizontal_min<const LANES: usize>() {
+ test_helpers::test_1(&|x| {
+ test_helpers::prop_assert_biteq! (
+ $vector::<LANES>::from_array(x).horizontal_min(),
+ x.iter().copied().min().unwrap(),
+ );
+ Ok(())
+ });
+ }
+ }
+ }
+}
+
+/// Implement tests for signed integers.
+#[macro_export]
+macro_rules! impl_signed_tests {
+ { $scalar:tt } => {
+ mod $scalar {
+ type Vector<const LANES: usize> = core_simd::Simd<Scalar, LANES>;
+ type Scalar = $scalar;
+
+ impl_common_integer_tests! { Vector, Scalar }
+
+ test_helpers::test_lanes! {
+ fn neg<const LANES: usize>() {
+ test_helpers::test_unary_elementwise(
+ &<Vector::<LANES> as core::ops::Neg>::neg,
+ &<Scalar as core::ops::Neg>::neg,
+ &|x| !x.contains(&Scalar::MIN),
+ );
+ }
+
+ fn is_positive<const LANES: usize>() {
+ test_helpers::test_unary_mask_elementwise(
+ &Vector::<LANES>::is_positive,
+ &Scalar::is_positive,
+ &|_| true,
+ );
+ }
+
+ fn is_negative<const LANES: usize>() {
+ test_helpers::test_unary_mask_elementwise(
+ &Vector::<LANES>::is_negative,
+ &Scalar::is_negative,
+ &|_| true,
+ );
+ }
+
+ fn signum<const LANES: usize>() {
+ test_helpers::test_unary_elementwise(
+ &Vector::<LANES>::signum,
+ &Scalar::signum,
+ &|_| true,
+ )
+ }
+
+ }
+
+ test_helpers::test_lanes_panic! {
+ fn div_min_overflow_panics<const LANES: usize>() {
+ let a = Vector::<LANES>::splat(Scalar::MIN);
+ let b = Vector::<LANES>::splat(-1);
+ let _ = a / b;
+ }
+
+ fn div_by_all_zeros_panics<const LANES: usize>() {
+ let a = Vector::<LANES>::splat(42);
+ let b = Vector::<LANES>::splat(0);
+ let _ = a / b;
+ }
+
+ fn div_by_one_zero_panics<const LANES: usize>() {
+ let a = Vector::<LANES>::splat(42);
+ let mut b = Vector::<LANES>::splat(21);
+ b[0] = 0 as _;
+ let _ = a / b;
+ }
+
+ fn rem_min_overflow_panic<const LANES: usize>() {
+ let a = Vector::<LANES>::splat(Scalar::MIN);
+ let b = Vector::<LANES>::splat(-1);
+ let _ = a % b;
+ }
+
+ fn rem_zero_panic<const LANES: usize>() {
+ let a = Vector::<LANES>::splat(42);
+ let b = Vector::<LANES>::splat(0);
+ let _ = a % b;
+ }
+ }
+
+ test_helpers::test_lanes! {
+ fn div_neg_one_no_panic<const LANES: usize>() {
+ let a = Vector::<LANES>::splat(42);
+ let b = Vector::<LANES>::splat(-1);
+ let _ = a / b;
+ }
+
+ fn rem_neg_one_no_panic<const LANES: usize>() {
+ let a = Vector::<LANES>::splat(42);
+ let b = Vector::<LANES>::splat(-1);
+ let _ = a % b;
+ }
+ }
+
+ impl_binary_op_test!(Scalar, Add::add, AddAssign::add_assign, Scalar::wrapping_add);
+ impl_binary_op_test!(Scalar, Sub::sub, SubAssign::sub_assign, Scalar::wrapping_sub);
+ impl_binary_op_test!(Scalar, Mul::mul, MulAssign::mul_assign, Scalar::wrapping_mul);
+
+ // Exclude Div and Rem panicking cases
+ impl_binary_checked_op_test!(Scalar, Div::div, DivAssign::div_assign, Scalar::wrapping_div, |x, y| y != 0 && !(x == Scalar::MIN && y == -1));
+ impl_binary_checked_op_test!(Scalar, Rem::rem, RemAssign::rem_assign, Scalar::wrapping_rem, |x, y| y != 0 && !(x == Scalar::MIN && y == -1));
+
+ impl_unary_op_test!(Scalar, Not::not);
+ impl_binary_op_test!(Scalar, BitAnd::bitand, BitAndAssign::bitand_assign);
+ impl_binary_op_test!(Scalar, BitOr::bitor, BitOrAssign::bitor_assign);
+ impl_binary_op_test!(Scalar, BitXor::bitxor, BitXorAssign::bitxor_assign);
+ }
+ }
+}
+
+/// Implement tests for unsigned integers.
+#[macro_export]
+macro_rules! impl_unsigned_tests {
+ { $scalar:tt } => {
+ mod $scalar {
+ type Vector<const LANES: usize> = core_simd::Simd<Scalar, LANES>;
+ type Scalar = $scalar;
+
+ impl_common_integer_tests! { Vector, Scalar }
+
+ test_helpers::test_lanes_panic! {
+ fn rem_zero_panic<const LANES: usize>() {
+ let a = Vector::<LANES>::splat(42);
+ let b = Vector::<LANES>::splat(0);
+ let _ = a % b;
+ }
+ }
+
+ impl_binary_op_test!(Scalar, Add::add, AddAssign::add_assign, Scalar::wrapping_add);
+ impl_binary_op_test!(Scalar, Sub::sub, SubAssign::sub_assign, Scalar::wrapping_sub);
+ impl_binary_op_test!(Scalar, Mul::mul, MulAssign::mul_assign, Scalar::wrapping_mul);
+
+ // Exclude Div and Rem panicking cases
+ impl_binary_checked_op_test!(Scalar, Div::div, DivAssign::div_assign, Scalar::wrapping_div, |_, y| y != 0);
+ impl_binary_checked_op_test!(Scalar, Rem::rem, RemAssign::rem_assign, Scalar::wrapping_rem, |_, y| y != 0);
+
+ impl_unary_op_test!(Scalar, Not::not);
+ impl_binary_op_test!(Scalar, BitAnd::bitand, BitAndAssign::bitand_assign);
+ impl_binary_op_test!(Scalar, BitOr::bitor, BitOrAssign::bitor_assign);
+ impl_binary_op_test!(Scalar, BitXor::bitxor, BitXorAssign::bitxor_assign);
+ }
+ }
+}
+
+/// Implement tests for floating point numbers.
+#[macro_export]
+macro_rules! impl_float_tests {
+ { $scalar:tt, $int_scalar:tt } => {
+ mod $scalar {
+ type Vector<const LANES: usize> = core_simd::Simd<Scalar, LANES>;
+ type Scalar = $scalar;
+
+ impl_unary_op_test!(Scalar, Neg::neg);
+ impl_binary_op_test!(Scalar, Add::add, AddAssign::add_assign);
+ impl_binary_op_test!(Scalar, Sub::sub, SubAssign::sub_assign);
+ impl_binary_op_test!(Scalar, Mul::mul, MulAssign::mul_assign);
+ impl_binary_op_test!(Scalar, Div::div, DivAssign::div_assign);
+ impl_binary_op_test!(Scalar, Rem::rem, RemAssign::rem_assign);
+
+ test_helpers::test_lanes! {
+ fn is_sign_positive<const LANES: usize>() {
+ test_helpers::test_unary_mask_elementwise(
+ &Vector::<LANES>::is_sign_positive,
+ &Scalar::is_sign_positive,
+ &|_| true,
+ );
+ }
+
+ fn is_sign_negative<const LANES: usize>() {
+ test_helpers::test_unary_mask_elementwise(
+ &Vector::<LANES>::is_sign_negative,
+ &Scalar::is_sign_negative,
+ &|_| true,
+ );
+ }
+
+ fn is_finite<const LANES: usize>() {
+ test_helpers::test_unary_mask_elementwise(
+ &Vector::<LANES>::is_finite,
+ &Scalar::is_finite,
+ &|_| true,
+ );
+ }
+
+ fn is_infinite<const LANES: usize>() {
+ test_helpers::test_unary_mask_elementwise(
+ &Vector::<LANES>::is_infinite,
+ &Scalar::is_infinite,
+ &|_| true,
+ );
+ }
+
+ fn is_nan<const LANES: usize>() {
+ test_helpers::test_unary_mask_elementwise(
+ &Vector::<LANES>::is_nan,
+ &Scalar::is_nan,
+ &|_| true,
+ );
+ }
+
+ fn is_normal<const LANES: usize>() {
+ test_helpers::test_unary_mask_elementwise(
+ &Vector::<LANES>::is_normal,
+ &Scalar::is_normal,
+ &|_| true,
+ );
+ }
+
+ fn is_subnormal<const LANES: usize>() {
+ test_helpers::test_unary_mask_elementwise(
+ &Vector::<LANES>::is_subnormal,
+ &Scalar::is_subnormal,
+ &|_| true,
+ );
+ }
+
+ fn abs<const LANES: usize>() {
+ test_helpers::test_unary_elementwise(
+ &Vector::<LANES>::abs,
+ &Scalar::abs,
+ &|_| true,
+ )
+ }
+
+ fn recip<const LANES: usize>() {
+ test_helpers::test_unary_elementwise(
+ &Vector::<LANES>::recip,
+ &Scalar::recip,
+ &|_| true,
+ )
+ }
+
+ fn to_degrees<const LANES: usize>() {
+ test_helpers::test_unary_elementwise(
+ &Vector::<LANES>::to_degrees,
+ &Scalar::to_degrees,
+ &|_| true,
+ )
+ }
+
+ fn to_radians<const LANES: usize>() {
+ test_helpers::test_unary_elementwise(
+ &Vector::<LANES>::to_radians,
+ &Scalar::to_radians,
+ &|_| true,
+ )
+ }
+
+ fn signum<const LANES: usize>() {
+ test_helpers::test_unary_elementwise(
+ &Vector::<LANES>::signum,
+ &Scalar::signum,
+ &|_| true,
+ )
+ }
+
+ fn copysign<const LANES: usize>() {
+ test_helpers::test_binary_elementwise(
+ &Vector::<LANES>::copysign,
+ &Scalar::copysign,
+ &|_, _| true,
+ )
+ }
+
+ fn min<const LANES: usize>() {
+ // Regular conditions (both values aren't zero)
+ test_helpers::test_binary_elementwise(
+ &Vector::<LANES>::min,
+ &Scalar::min,
+ // Reject the case where both values are zero with different signs
+ &|a, b| {
+ for (a, b) in a.iter().zip(b.iter()) {
+ if *a == 0. && *b == 0. && a.signum() != b.signum() {
+ return false;
+ }
+ }
+ true
+ }
+ );
+
+ // Special case where both values are zero
+ let p_zero = Vector::<LANES>::splat(0.);
+ let n_zero = Vector::<LANES>::splat(-0.);
+ assert!(p_zero.min(n_zero).to_array().iter().all(|x| *x == 0.));
+ assert!(n_zero.min(p_zero).to_array().iter().all(|x| *x == 0.));
+ }
+
+ fn max<const LANES: usize>() {
+ // Regular conditions (both values aren't zero)
+ test_helpers::test_binary_elementwise(
+ &Vector::<LANES>::max,
+ &Scalar::max,
+ // Reject the case where both values are zero with different signs
+ &|a, b| {
+ for (a, b) in a.iter().zip(b.iter()) {
+ if *a == 0. && *b == 0. && a.signum() != b.signum() {
+ return false;
+ }
+ }
+ true
+ }
+ );
+
+ // Special case where both values are zero
+ let p_zero = Vector::<LANES>::splat(0.);
+ let n_zero = Vector::<LANES>::splat(-0.);
+ assert!(p_zero.max(n_zero).to_array().iter().all(|x| *x == 0.));
+ assert!(n_zero.max(p_zero).to_array().iter().all(|x| *x == 0.));
+ }
+
+ fn clamp<const LANES: usize>() {
+ test_helpers::test_3(&|value: [Scalar; LANES], mut min: [Scalar; LANES], mut max: [Scalar; LANES]| {
+ for (min, max) in min.iter_mut().zip(max.iter_mut()) {
+ if max < min {
+ core::mem::swap(min, max);
+ }
+ if min.is_nan() {
+ *min = Scalar::NEG_INFINITY;
+ }
+ if max.is_nan() {
+ *max = Scalar::INFINITY;
+ }
+ }
+
+ let mut result_scalar = [Scalar::default(); LANES];
+ for i in 0..LANES {
+ result_scalar[i] = value[i].clamp(min[i], max[i]);
+ }
+ let result_vector = Vector::from_array(value).clamp(min.into(), max.into()).to_array();
+ test_helpers::prop_assert_biteq!(result_scalar, result_vector);
+ Ok(())
+ })
+ }
+
+ fn horizontal_sum<const LANES: usize>() {
+ test_helpers::test_1(&|x| {
+ test_helpers::prop_assert_biteq! (
+ Vector::<LANES>::from_array(x).horizontal_sum(),
+ x.iter().sum(),
+ );
+ Ok(())
+ });
+ }
+
+ fn horizontal_product<const LANES: usize>() {
+ test_helpers::test_1(&|x| {
+ test_helpers::prop_assert_biteq! (
+ Vector::<LANES>::from_array(x).horizontal_product(),
+ x.iter().product(),
+ );
+ Ok(())
+ });
+ }
+
+ fn horizontal_max<const LANES: usize>() {
+ test_helpers::test_1(&|x| {
+ let vmax = Vector::<LANES>::from_array(x).horizontal_max();
+ let smax = x.iter().copied().fold(Scalar::NAN, Scalar::max);
+ // 0 and -0 are treated the same
+ if !(x.contains(&0.) && x.contains(&-0.) && vmax.abs() == 0. && smax.abs() == 0.) {
+ test_helpers::prop_assert_biteq!(vmax, smax);
+ }
+ Ok(())
+ });
+ }
+
+ fn horizontal_min<const LANES: usize>() {
+ test_helpers::test_1(&|x| {
+ let vmax = Vector::<LANES>::from_array(x).horizontal_min();
+ let smax = x.iter().copied().fold(Scalar::NAN, Scalar::min);
+ // 0 and -0 are treated the same
+ if !(x.contains(&0.) && x.contains(&-0.) && vmax.abs() == 0. && smax.abs() == 0.) {
+ test_helpers::prop_assert_biteq!(vmax, smax);
+ }
+ Ok(())
+ });
+ }
+ }
+
+ #[cfg(feature = "std")]
+ mod std {
+ use super::*;
+ test_helpers::test_lanes! {
+ fn sqrt<const LANES: usize>() {
+ test_helpers::test_unary_elementwise(
+ &Vector::<LANES>::sqrt,
+ &Scalar::sqrt,
+ &|_| true,
+ )
+ }
+
+ fn mul_add<const LANES: usize>() {
+ test_helpers::test_ternary_elementwise(
+ &Vector::<LANES>::mul_add,
+ &Scalar::mul_add,
+ &|_, _, _| true,
+ )
+ }
+ }
+ }
+ }
+ }
+}
--- /dev/null
+#![feature(portable_simd)]
+
+macro_rules! float_rounding_test {
+ { $scalar:tt, $int_scalar:tt } => {
+ mod $scalar {
+ type Vector<const LANES: usize> = core_simd::Simd<$scalar, LANES>;
+ type Scalar = $scalar;
+ type IntScalar = $int_scalar;
+
+ #[cfg(feature = "std")]
+ test_helpers::test_lanes! {
+ fn ceil<const LANES: usize>() {
+ test_helpers::test_unary_elementwise(
+ &Vector::<LANES>::ceil,
+ &Scalar::ceil,
+ &|_| true,
+ )
+ }
+
+ fn floor<const LANES: usize>() {
+ test_helpers::test_unary_elementwise(
+ &Vector::<LANES>::floor,
+ &Scalar::floor,
+ &|_| true,
+ )
+ }
+
+ fn round<const LANES: usize>() {
+ test_helpers::test_unary_elementwise(
+ &Vector::<LANES>::round,
+ &Scalar::round,
+ &|_| true,
+ )
+ }
+
+ fn trunc<const LANES: usize>() {
+ test_helpers::test_unary_elementwise(
+ &Vector::<LANES>::trunc,
+ &Scalar::trunc,
+ &|_| true,
+ )
+ }
+
+ fn fract<const LANES: usize>() {
+ test_helpers::test_unary_elementwise(
+ &Vector::<LANES>::fract,
+ &Scalar::fract,
+ &|_| true,
+ )
+ }
+ }
+
+ test_helpers::test_lanes! {
+ fn from_int<const LANES: usize>() {
+ test_helpers::test_unary_elementwise(
+ &Vector::<LANES>::round_from_int,
+ &|x| x as Scalar,
+ &|_| true,
+ )
+ }
+
+ fn to_int_unchecked<const LANES: usize>() {
+ // The maximum integer that can be represented by the equivalently sized float has
+ // all of the mantissa digits set to 1, pushed up to the MSB.
+ const ALL_MANTISSA_BITS: IntScalar = ((1 << <Scalar>::MANTISSA_DIGITS) - 1);
+ const MAX_REPRESENTABLE_VALUE: Scalar =
+ (ALL_MANTISSA_BITS << (core::mem::size_of::<Scalar>() * 8 - <Scalar>::MANTISSA_DIGITS as usize - 1)) as Scalar;
+
+ let mut runner = proptest::test_runner::TestRunner::default();
+ runner.run(
+ &test_helpers::array::UniformArrayStrategy::new(-MAX_REPRESENTABLE_VALUE..MAX_REPRESENTABLE_VALUE),
+ |x| {
+ let result_1 = unsafe { Vector::from_array(x).to_int_unchecked().to_array() };
+ let result_2 = {
+ let mut result = [0; LANES];
+ for (i, o) in x.iter().zip(result.iter_mut()) {
+ *o = unsafe { i.to_int_unchecked() };
+ }
+ result
+ };
+ test_helpers::prop_assert_biteq!(result_1, result_2);
+ Ok(())
+ },
+ ).unwrap();
+ }
+ }
+ }
+ }
+}
+
+float_rounding_test! { f32, i32 }
+float_rounding_test! { f64, i64 }
--- /dev/null
+#![feature(portable_simd)]
+use core_simd::{Simd, Swizzle};
+
+#[cfg(target_arch = "wasm32")]
+use wasm_bindgen_test::*;
+
+#[cfg(target_arch = "wasm32")]
+wasm_bindgen_test_configure!(run_in_browser);
+
+#[test]
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+fn swizzle() {
+ struct Index;
+ impl Swizzle<4, 4> for Index {
+ const INDEX: [usize; 4] = [2, 1, 3, 0];
+ }
+ impl Swizzle<4, 2> for Index {
+ const INDEX: [usize; 2] = [1, 1];
+ }
+
+ let vector = Simd::from_array([2, 4, 1, 9]);
+ assert_eq!(Index::swizzle(vector).to_array(), [1, 4, 9, 2]);
+ assert_eq!(Index::swizzle(vector).to_array(), [4, 4]);
+}
+
+#[test]
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+fn reverse() {
+ let a = Simd::from_array([1, 2, 3, 4]);
+ assert_eq!(a.reverse().to_array(), [4, 3, 2, 1]);
+}
+
+#[test]
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+fn rotate() {
+ let a = Simd::from_array([1, 2, 3, 4]);
+ assert_eq!(a.rotate_lanes_left::<0>().to_array(), [1, 2, 3, 4]);
+ assert_eq!(a.rotate_lanes_left::<1>().to_array(), [2, 3, 4, 1]);
+ assert_eq!(a.rotate_lanes_left::<2>().to_array(), [3, 4, 1, 2]);
+ assert_eq!(a.rotate_lanes_left::<3>().to_array(), [4, 1, 2, 3]);
+ assert_eq!(a.rotate_lanes_left::<4>().to_array(), [1, 2, 3, 4]);
+ assert_eq!(a.rotate_lanes_left::<5>().to_array(), [2, 3, 4, 1]);
+ assert_eq!(a.rotate_lanes_right::<0>().to_array(), [1, 2, 3, 4]);
+ assert_eq!(a.rotate_lanes_right::<1>().to_array(), [4, 1, 2, 3]);
+ assert_eq!(a.rotate_lanes_right::<2>().to_array(), [3, 4, 1, 2]);
+ assert_eq!(a.rotate_lanes_right::<3>().to_array(), [2, 3, 4, 1]);
+ assert_eq!(a.rotate_lanes_right::<4>().to_array(), [1, 2, 3, 4]);
+ assert_eq!(a.rotate_lanes_right::<5>().to_array(), [4, 1, 2, 3]);
+}
+
+#[test]
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+fn interleave() {
+ let a = Simd::from_array([0, 1, 2, 3, 4, 5, 6, 7]);
+ let b = Simd::from_array([8, 9, 10, 11, 12, 13, 14, 15]);
+ let (lo, hi) = a.interleave(b);
+ assert_eq!(lo.to_array(), [0, 8, 1, 9, 2, 10, 3, 11]);
+ assert_eq!(hi.to_array(), [4, 12, 5, 13, 6, 14, 7, 15]);
+ let (even, odd) = lo.deinterleave(hi);
+ assert_eq!(even, a);
+ assert_eq!(odd, b);
+}
--- /dev/null
+#![feature(portable_simd, generic_const_exprs, adt_const_params)]
+#![allow(incomplete_features)]
+#![cfg(feature = "generic_const_exprs")]
+
+use core_simd::Simd;
+
+#[test]
+fn byte_convert() {
+ let int = Simd::<u32, 2>::from_array([0xdeadbeef, 0x8badf00d]);
+ let bytes = int.to_ne_bytes();
+ assert_eq!(int[0].to_ne_bytes(), bytes[..4]);
+ assert_eq!(int[1].to_ne_bytes(), bytes[4..]);
+ assert_eq!(Simd::<u32, 2>::from_ne_bytes(bytes), int);
+}
--- /dev/null
+#![feature(portable_simd)]
+
+#[macro_use]
+mod ops_macros;
+impl_unsigned_tests! { u16 }
--- /dev/null
+#![feature(portable_simd)]
+
+#[macro_use]
+mod ops_macros;
+impl_unsigned_tests! { u32 }
--- /dev/null
+#![feature(portable_simd)]
+
+#[macro_use]
+mod ops_macros;
+impl_unsigned_tests! { u64 }
--- /dev/null
+#![feature(portable_simd)]
+
+#[macro_use]
+mod ops_macros;
+impl_unsigned_tests! { u8 }
--- /dev/null
+#![feature(portable_simd)]
+
+#[macro_use]
+mod ops_macros;
+impl_unsigned_tests! { usize }
--- /dev/null
+{
+ "goog:chromeOptions": {
+ "args": [
+ "--enable-features=WebAssemblySimd"
+ ]
+ }
+}
--- /dev/null
+[package]
+name = "test_helpers"
+version = "0.1.0"
+edition = "2021"
+publish = false
+
+[dependencies.proptest]
+version = "0.10"
+default-features = false
+features = ["alloc"]
--- /dev/null
+//! Generic-length array strategy.
+
+// Adapted from proptest's array code
+// Copyright 2017 Jason Lingle
+
+use core::{marker::PhantomData, mem::MaybeUninit};
+use proptest::{
+ strategy::{NewTree, Strategy, ValueTree},
+ test_runner::TestRunner,
+};
+
+#[must_use = "strategies do nothing unless used"]
+#[derive(Clone, Copy, Debug)]
+pub struct UniformArrayStrategy<S, T> {
+ strategy: S,
+ _marker: PhantomData<T>,
+}
+
+impl<S, T> UniformArrayStrategy<S, T> {
+ pub const fn new(strategy: S) -> Self {
+ Self {
+ strategy,
+ _marker: PhantomData,
+ }
+ }
+}
+
+pub struct ArrayValueTree<T> {
+ tree: T,
+ shrinker: usize,
+ last_shrinker: Option<usize>,
+}
+
+impl<T, S, const LANES: usize> Strategy for UniformArrayStrategy<S, [T; LANES]>
+where
+ T: core::fmt::Debug,
+ S: Strategy<Value = T>,
+{
+ type Tree = ArrayValueTree<[S::Tree; LANES]>;
+ type Value = [T; LANES];
+
+ fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
+ let tree: [S::Tree; LANES] = unsafe {
+ let mut tree: [MaybeUninit<S::Tree>; LANES] = MaybeUninit::uninit().assume_init();
+ for t in tree.iter_mut() {
+ *t = MaybeUninit::new(self.strategy.new_tree(runner)?)
+ }
+ core::mem::transmute_copy(&tree)
+ };
+ Ok(ArrayValueTree {
+ tree,
+ shrinker: 0,
+ last_shrinker: None,
+ })
+ }
+}
+
+impl<T: ValueTree, const LANES: usize> ValueTree for ArrayValueTree<[T; LANES]> {
+ type Value = [T::Value; LANES];
+
+ fn current(&self) -> Self::Value {
+ unsafe {
+ let mut value: [MaybeUninit<T::Value>; LANES] = MaybeUninit::uninit().assume_init();
+ for (tree_elem, value_elem) in self.tree.iter().zip(value.iter_mut()) {
+ *value_elem = MaybeUninit::new(tree_elem.current());
+ }
+ core::mem::transmute_copy(&value)
+ }
+ }
+
+ fn simplify(&mut self) -> bool {
+ while self.shrinker < LANES {
+ if self.tree[self.shrinker].simplify() {
+ self.last_shrinker = Some(self.shrinker);
+ return true;
+ } else {
+ self.shrinker += 1;
+ }
+ }
+
+ false
+ }
+
+ fn complicate(&mut self) -> bool {
+ if let Some(shrinker) = self.last_shrinker {
+ self.shrinker = shrinker;
+ if self.tree[shrinker].complicate() {
+ true
+ } else {
+ self.last_shrinker = None;
+ false
+ }
+ } else {
+ false
+ }
+ }
+}
--- /dev/null
+//! Compare numeric types by exact bit value.
+
+pub trait BitEq {
+ fn biteq(&self, other: &Self) -> bool;
+ fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result;
+}
+
+impl BitEq for bool {
+ fn biteq(&self, other: &Self) -> bool {
+ self == other
+ }
+
+ fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+ write!(f, "{:?}", self)
+ }
+}
+
+macro_rules! impl_integer_biteq {
+ { $($type:ty),* } => {
+ $(
+ impl BitEq for $type {
+ fn biteq(&self, other: &Self) -> bool {
+ self == other
+ }
+
+ fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+ write!(f, "{:?} ({:x})", self, self)
+ }
+ }
+ )*
+ };
+}
+
+impl_integer_biteq! { u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize }
+
+macro_rules! impl_float_biteq {
+ { $($type:ty),* } => {
+ $(
+ impl BitEq for $type {
+ fn biteq(&self, other: &Self) -> bool {
+ if self.is_nan() && other.is_nan() {
+ true // exact nan bits don't matter
+ } else {
+ self.to_bits() == other.to_bits()
+ }
+ }
+
+ fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+ write!(f, "{:?} ({:x})", self, self.to_bits())
+ }
+ }
+ )*
+ };
+}
+
+impl_float_biteq! { f32, f64 }
+
+impl<T: BitEq, const N: usize> BitEq for [T; N] {
+ fn biteq(&self, other: &Self) -> bool {
+ self.iter()
+ .zip(other.iter())
+ .fold(true, |value, (left, right)| value && left.biteq(right))
+ }
+
+ fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+ #[repr(transparent)]
+ struct Wrapper<'a, T: BitEq>(&'a T);
+
+ impl<T: BitEq> core::fmt::Debug for Wrapper<'_, T> {
+ fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+ self.0.fmt(f)
+ }
+ }
+
+ f.debug_list()
+ .entries(self.iter().map(|x| Wrapper(x)))
+ .finish()
+ }
+}
+
+#[doc(hidden)]
+pub struct BitEqWrapper<'a, T>(pub &'a T);
+
+impl<T: BitEq> PartialEq for BitEqWrapper<'_, T> {
+ fn eq(&self, other: &Self) -> bool {
+ self.0.biteq(other.0)
+ }
+}
+
+impl<T: BitEq> core::fmt::Debug for BitEqWrapper<'_, T> {
+ fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+#[macro_export]
+macro_rules! prop_assert_biteq {
+ { $a:expr, $b:expr $(,)? } => {
+ {
+ use $crate::biteq::BitEqWrapper;
+ let a = $a;
+ let b = $b;
+ proptest::prop_assert_eq!(BitEqWrapper(&a), BitEqWrapper(&b));
+ }
+ }
+}
--- /dev/null
+pub mod array;
+
+#[cfg(target_arch = "wasm32")]
+pub mod wasm;
+
+#[macro_use]
+pub mod biteq;
+
+/// Specifies the default strategy for testing a type.
+///
+/// This strategy should be what "makes sense" to test.
+pub trait DefaultStrategy {
+ type Strategy: proptest::strategy::Strategy<Value = Self>;
+ fn default_strategy() -> Self::Strategy;
+}
+
+macro_rules! impl_num {
+ { $type:tt } => {
+ impl DefaultStrategy for $type {
+ type Strategy = proptest::num::$type::Any;
+ fn default_strategy() -> Self::Strategy {
+ proptest::num::$type::ANY
+ }
+ }
+ }
+}
+
+impl_num! { i8 }
+impl_num! { i16 }
+impl_num! { i32 }
+impl_num! { i64 }
+impl_num! { isize }
+impl_num! { u8 }
+impl_num! { u16 }
+impl_num! { u32 }
+impl_num! { u64 }
+impl_num! { usize }
+impl_num! { f32 }
+impl_num! { f64 }
+
+#[cfg(not(target_arch = "wasm32"))]
+impl DefaultStrategy for u128 {
+ type Strategy = proptest::num::u128::Any;
+ fn default_strategy() -> Self::Strategy {
+ proptest::num::u128::ANY
+ }
+}
+
+#[cfg(not(target_arch = "wasm32"))]
+impl DefaultStrategy for i128 {
+ type Strategy = proptest::num::i128::Any;
+ fn default_strategy() -> Self::Strategy {
+ proptest::num::i128::ANY
+ }
+}
+
+#[cfg(target_arch = "wasm32")]
+impl DefaultStrategy for u128 {
+ type Strategy = crate::wasm::u128::Any;
+ fn default_strategy() -> Self::Strategy {
+ crate::wasm::u128::ANY
+ }
+}
+
+#[cfg(target_arch = "wasm32")]
+impl DefaultStrategy for i128 {
+ type Strategy = crate::wasm::i128::Any;
+ fn default_strategy() -> Self::Strategy {
+ crate::wasm::i128::ANY
+ }
+}
+
+impl<T: core::fmt::Debug + DefaultStrategy, const LANES: usize> DefaultStrategy for [T; LANES] {
+ type Strategy = crate::array::UniformArrayStrategy<T::Strategy, Self>;
+ fn default_strategy() -> Self::Strategy {
+ Self::Strategy::new(T::default_strategy())
+ }
+}
+
+/// Test a function that takes a single value.
+pub fn test_1<A: core::fmt::Debug + DefaultStrategy>(
+ f: &dyn Fn(A) -> proptest::test_runner::TestCaseResult,
+) {
+ let mut runner = proptest::test_runner::TestRunner::default();
+ runner.run(&A::default_strategy(), f).unwrap();
+}
+
+/// Test a function that takes two values.
+pub fn test_2<A: core::fmt::Debug + DefaultStrategy, B: core::fmt::Debug + DefaultStrategy>(
+ f: &dyn Fn(A, B) -> proptest::test_runner::TestCaseResult,
+) {
+ let mut runner = proptest::test_runner::TestRunner::default();
+ runner
+ .run(&(A::default_strategy(), B::default_strategy()), |(a, b)| {
+ f(a, b)
+ })
+ .unwrap();
+}
+
+/// Test a function that takes two values.
+pub fn test_3<
+ A: core::fmt::Debug + DefaultStrategy,
+ B: core::fmt::Debug + DefaultStrategy,
+ C: core::fmt::Debug + DefaultStrategy,
+>(
+ f: &dyn Fn(A, B, C) -> proptest::test_runner::TestCaseResult,
+) {
+ let mut runner = proptest::test_runner::TestRunner::default();
+ runner
+ .run(
+ &(
+ A::default_strategy(),
+ B::default_strategy(),
+ C::default_strategy(),
+ ),
+ |(a, b, c)| f(a, b, c),
+ )
+ .unwrap();
+}
+
+/// Test a unary vector function against a unary scalar function, applied elementwise.
+#[inline(never)]
+pub fn test_unary_elementwise<Scalar, ScalarResult, Vector, VectorResult, const LANES: usize>(
+ fv: &dyn Fn(Vector) -> VectorResult,
+ fs: &dyn Fn(Scalar) -> ScalarResult,
+ check: &dyn Fn([Scalar; LANES]) -> bool,
+) where
+ Scalar: Copy + Default + core::fmt::Debug + DefaultStrategy,
+ ScalarResult: Copy + Default + biteq::BitEq + core::fmt::Debug + DefaultStrategy,
+ Vector: Into<[Scalar; LANES]> + From<[Scalar; LANES]> + Copy,
+ VectorResult: Into<[ScalarResult; LANES]> + From<[ScalarResult; LANES]> + Copy,
+{
+ test_1(&|x: [Scalar; LANES]| {
+ proptest::prop_assume!(check(x));
+ let result_1: [ScalarResult; LANES] = fv(x.into()).into();
+ let result_2: [ScalarResult; LANES] = {
+ let mut result = [ScalarResult::default(); LANES];
+ for (i, o) in x.iter().zip(result.iter_mut()) {
+ *o = fs(*i);
+ }
+ result
+ };
+ crate::prop_assert_biteq!(result_1, result_2);
+ Ok(())
+ });
+}
+
+/// Test a unary vector function against a unary scalar function, applied elementwise.
+#[inline(never)]
+pub fn test_unary_mask_elementwise<Scalar, Vector, Mask, const LANES: usize>(
+ fv: &dyn Fn(Vector) -> Mask,
+ fs: &dyn Fn(Scalar) -> bool,
+ check: &dyn Fn([Scalar; LANES]) -> bool,
+) where
+ Scalar: Copy + Default + core::fmt::Debug + DefaultStrategy,
+ Vector: Into<[Scalar; LANES]> + From<[Scalar; LANES]> + Copy,
+ Mask: Into<[bool; LANES]> + From<[bool; LANES]> + Copy,
+{
+ test_1(&|x: [Scalar; LANES]| {
+ proptest::prop_assume!(check(x));
+ let result_1: [bool; LANES] = fv(x.into()).into();
+ let result_2: [bool; LANES] = {
+ let mut result = [false; LANES];
+ for (i, o) in x.iter().zip(result.iter_mut()) {
+ *o = fs(*i);
+ }
+ result
+ };
+ crate::prop_assert_biteq!(result_1, result_2);
+ Ok(())
+ });
+}
+
+/// Test a binary vector function against a binary scalar function, applied elementwise.
+#[inline(never)]
+pub fn test_binary_elementwise<
+ Scalar1,
+ Scalar2,
+ ScalarResult,
+ Vector1,
+ Vector2,
+ VectorResult,
+ const LANES: usize,
+>(
+ fv: &dyn Fn(Vector1, Vector2) -> VectorResult,
+ fs: &dyn Fn(Scalar1, Scalar2) -> ScalarResult,
+ check: &dyn Fn([Scalar1; LANES], [Scalar2; LANES]) -> bool,
+) where
+ Scalar1: Copy + Default + core::fmt::Debug + DefaultStrategy,
+ Scalar2: Copy + Default + core::fmt::Debug + DefaultStrategy,
+ ScalarResult: Copy + Default + biteq::BitEq + core::fmt::Debug + DefaultStrategy,
+ Vector1: Into<[Scalar1; LANES]> + From<[Scalar1; LANES]> + Copy,
+ Vector2: Into<[Scalar2; LANES]> + From<[Scalar2; LANES]> + Copy,
+ VectorResult: Into<[ScalarResult; LANES]> + From<[ScalarResult; LANES]> + Copy,
+{
+ test_2(&|x: [Scalar1; LANES], y: [Scalar2; LANES]| {
+ proptest::prop_assume!(check(x, y));
+ let result_1: [ScalarResult; LANES] = fv(x.into(), y.into()).into();
+ let result_2: [ScalarResult; LANES] = {
+ let mut result = [ScalarResult::default(); LANES];
+ for ((i1, i2), o) in x.iter().zip(y.iter()).zip(result.iter_mut()) {
+ *o = fs(*i1, *i2);
+ }
+ result
+ };
+ crate::prop_assert_biteq!(result_1, result_2);
+ Ok(())
+ });
+}
+
+/// Test a binary vector-scalar function against a binary scalar function, applied elementwise.
+#[inline(never)]
+pub fn test_binary_scalar_rhs_elementwise<
+ Scalar1,
+ Scalar2,
+ ScalarResult,
+ Vector,
+ VectorResult,
+ const LANES: usize,
+>(
+ fv: &dyn Fn(Vector, Scalar2) -> VectorResult,
+ fs: &dyn Fn(Scalar1, Scalar2) -> ScalarResult,
+ check: &dyn Fn([Scalar1; LANES], Scalar2) -> bool,
+) where
+ Scalar1: Copy + Default + core::fmt::Debug + DefaultStrategy,
+ Scalar2: Copy + Default + core::fmt::Debug + DefaultStrategy,
+ ScalarResult: Copy + Default + biteq::BitEq + core::fmt::Debug + DefaultStrategy,
+ Vector: Into<[Scalar1; LANES]> + From<[Scalar1; LANES]> + Copy,
+ VectorResult: Into<[ScalarResult; LANES]> + From<[ScalarResult; LANES]> + Copy,
+{
+ test_2(&|x: [Scalar1; LANES], y: Scalar2| {
+ proptest::prop_assume!(check(x, y));
+ let result_1: [ScalarResult; LANES] = fv(x.into(), y).into();
+ let result_2: [ScalarResult; LANES] = {
+ let mut result = [ScalarResult::default(); LANES];
+ for (i, o) in x.iter().zip(result.iter_mut()) {
+ *o = fs(*i, y);
+ }
+ result
+ };
+ crate::prop_assert_biteq!(result_1, result_2);
+ Ok(())
+ });
+}
+
+/// Test a binary vector-scalar function against a binary scalar function, applied elementwise.
+#[inline(never)]
+pub fn test_binary_scalar_lhs_elementwise<
+ Scalar1,
+ Scalar2,
+ ScalarResult,
+ Vector,
+ VectorResult,
+ const LANES: usize,
+>(
+ fv: &dyn Fn(Scalar1, Vector) -> VectorResult,
+ fs: &dyn Fn(Scalar1, Scalar2) -> ScalarResult,
+ check: &dyn Fn(Scalar1, [Scalar2; LANES]) -> bool,
+) where
+ Scalar1: Copy + Default + core::fmt::Debug + DefaultStrategy,
+ Scalar2: Copy + Default + core::fmt::Debug + DefaultStrategy,
+ ScalarResult: Copy + Default + biteq::BitEq + core::fmt::Debug + DefaultStrategy,
+ Vector: Into<[Scalar2; LANES]> + From<[Scalar2; LANES]> + Copy,
+ VectorResult: Into<[ScalarResult; LANES]> + From<[ScalarResult; LANES]> + Copy,
+{
+ test_2(&|x: Scalar1, y: [Scalar2; LANES]| {
+ proptest::prop_assume!(check(x, y));
+ let result_1: [ScalarResult; LANES] = fv(x, y.into()).into();
+ let result_2: [ScalarResult; LANES] = {
+ let mut result = [ScalarResult::default(); LANES];
+ for (i, o) in y.iter().zip(result.iter_mut()) {
+ *o = fs(x, *i);
+ }
+ result
+ };
+ crate::prop_assert_biteq!(result_1, result_2);
+ Ok(())
+ });
+}
+
+/// Test a ternary vector function against a ternary scalar function, applied elementwise.
+#[inline(never)]
+pub fn test_ternary_elementwise<
+ Scalar1,
+ Scalar2,
+ Scalar3,
+ ScalarResult,
+ Vector1,
+ Vector2,
+ Vector3,
+ VectorResult,
+ const LANES: usize,
+>(
+ fv: &dyn Fn(Vector1, Vector2, Vector3) -> VectorResult,
+ fs: &dyn Fn(Scalar1, Scalar2, Scalar3) -> ScalarResult,
+ check: &dyn Fn([Scalar1; LANES], [Scalar2; LANES], [Scalar3; LANES]) -> bool,
+) where
+ Scalar1: Copy + Default + core::fmt::Debug + DefaultStrategy,
+ Scalar2: Copy + Default + core::fmt::Debug + DefaultStrategy,
+ Scalar3: Copy + Default + core::fmt::Debug + DefaultStrategy,
+ ScalarResult: Copy + Default + biteq::BitEq + core::fmt::Debug + DefaultStrategy,
+ Vector1: Into<[Scalar1; LANES]> + From<[Scalar1; LANES]> + Copy,
+ Vector2: Into<[Scalar2; LANES]> + From<[Scalar2; LANES]> + Copy,
+ Vector3: Into<[Scalar3; LANES]> + From<[Scalar3; LANES]> + Copy,
+ VectorResult: Into<[ScalarResult; LANES]> + From<[ScalarResult; LANES]> + Copy,
+{
+ test_3(
+ &|x: [Scalar1; LANES], y: [Scalar2; LANES], z: [Scalar3; LANES]| {
+ proptest::prop_assume!(check(x, y, z));
+ let result_1: [ScalarResult; LANES] = fv(x.into(), y.into(), z.into()).into();
+ let result_2: [ScalarResult; LANES] = {
+ let mut result = [ScalarResult::default(); LANES];
+ for ((i1, (i2, i3)), o) in
+ x.iter().zip(y.iter().zip(z.iter())).zip(result.iter_mut())
+ {
+ *o = fs(*i1, *i2, *i3);
+ }
+ result
+ };
+ crate::prop_assert_biteq!(result_1, result_2);
+ Ok(())
+ },
+ );
+}
+
+/// Expand a const-generic test into separate tests for each possible lane count.
+#[macro_export]
+macro_rules! test_lanes {
+ {
+ $(fn $test:ident<const $lanes:ident: usize>() $body:tt)*
+ } => {
+ $(
+ mod $test {
+ use super::*;
+
+ fn implementation<const $lanes: usize>()
+ where
+ core_simd::LaneCount<$lanes>: core_simd::SupportedLaneCount,
+ $body
+
+ #[cfg(target_arch = "wasm32")]
+ wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
+
+ #[test]
+ #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+ fn lanes_1() {
+ implementation::<1>();
+ }
+
+ #[test]
+ #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+ fn lanes_2() {
+ implementation::<2>();
+ }
+
+ #[test]
+ #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+ fn lanes_4() {
+ implementation::<4>();
+ }
+
+ #[test]
+ #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+ fn lanes_8() {
+ implementation::<8>();
+ }
+
+ #[test]
+ #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+ fn lanes_16() {
+ implementation::<16>();
+ }
+
+ #[test]
+ #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+ fn lanes_32() {
+ implementation::<32>();
+ }
+ }
+ )*
+ }
+}
+
+/// Expand a const-generic `#[should_panic]` test into separate tests for each possible lane count.
+#[macro_export]
+macro_rules! test_lanes_panic {
+ {
+ $(fn $test:ident<const $lanes:ident: usize>() $body:tt)*
+ } => {
+ $(
+ mod $test {
+ use super::*;
+
+ fn implementation<const $lanes: usize>()
+ where
+ core_simd::LaneCount<$lanes>: core_simd::SupportedLaneCount,
+ $body
+
+ #[test]
+ #[should_panic]
+ fn lanes_1() {
+ implementation::<1>();
+ }
+
+ #[test]
+ #[should_panic]
+ fn lanes_2() {
+ implementation::<2>();
+ }
+
+ #[test]
+ #[should_panic]
+ fn lanes_4() {
+ implementation::<4>();
+ }
+
+ #[test]
+ #[should_panic]
+ fn lanes_8() {
+ implementation::<8>();
+ }
+
+ #[test]
+ #[should_panic]
+ fn lanes_16() {
+ implementation::<16>();
+ }
+
+ #[test]
+ #[should_panic]
+ fn lanes_32() {
+ implementation::<32>();
+ }
+ }
+ )*
+ }
+}
--- /dev/null
+//! Strategies for `u128` and `i128`, since proptest doesn't provide them for the wasm target.
+
+macro_rules! impl_num {
+ { $name:ident } => {
+ pub(crate) mod $name {
+ type InnerStrategy = crate::array::UniformArrayStrategy<proptest::num::u64::Any, [u64; 2]>;
+ use proptest::strategy::{Strategy, ValueTree, NewTree};
+
+
+ #[must_use = "strategies do nothing unless used"]
+ #[derive(Clone, Copy, Debug)]
+ pub struct Any {
+ strategy: InnerStrategy,
+ }
+
+ pub struct BinarySearch {
+ inner: <InnerStrategy as Strategy>::Tree,
+ }
+
+ impl ValueTree for BinarySearch {
+ type Value = $name;
+
+ fn current(&self) -> $name {
+ unsafe { core::mem::transmute(self.inner.current()) }
+ }
+
+ fn simplify(&mut self) -> bool {
+ self.inner.simplify()
+ }
+
+ fn complicate(&mut self) -> bool {
+ self.inner.complicate()
+ }
+ }
+
+ impl Strategy for Any {
+ type Tree = BinarySearch;
+ type Value = $name;
+
+ fn new_tree(&self, runner: &mut proptest::test_runner::TestRunner) -> NewTree<Self> {
+ Ok(BinarySearch { inner: self.strategy.new_tree(runner)? })
+ }
+ }
+
+ pub const ANY: Any = Any { strategy: InnerStrategy::new(proptest::num::u64::ANY) };
+ }
+ }
+}
+
+impl_num! { u128 }
+impl_num! { i128 }
fn clone($self: &$S::TokenStream) -> $S::TokenStream;
fn new() -> $S::TokenStream;
fn is_empty($self: &$S::TokenStream) -> bool;
+ fn expand_expr($self: &$S::TokenStream) -> Result<$S::TokenStream, ()>;
fn from_str(src: &str) -> $S::TokenStream;
fn to_string($self: &$S::TokenStream) -> String;
fn from_token_tree(
#[derive(Debug)]
pub struct LexError;
-impl LexError {
- fn new() -> Self {
- LexError
- }
-}
-
#[stable(feature = "proc_macro_lexerror_impls", since = "1.44.0")]
impl fmt::Display for LexError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
#[stable(feature = "proc_macro_lib", since = "1.15.0")]
impl !Sync for LexError {}
+/// Error returned from `TokenStream::expand_expr`.
+#[unstable(feature = "proc_macro_expand", issue = "90765")]
+#[non_exhaustive]
+#[derive(Debug)]
+pub struct ExpandError;
+
+#[unstable(feature = "proc_macro_expand", issue = "90765")]
+impl fmt::Display for ExpandError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("macro expansion failed")
+ }
+}
+
+#[unstable(feature = "proc_macro_expand", issue = "90765")]
+impl error::Error for ExpandError {}
+
+#[unstable(feature = "proc_macro_expand", issue = "90765")]
+impl !Send for ExpandError {}
+
+#[unstable(feature = "proc_macro_expand", issue = "90765")]
+impl !Sync for ExpandError {}
+
impl TokenStream {
/// Returns an empty `TokenStream` containing no token trees.
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
+
+ /// Parses this `TokenStream` as an expression and attempts to expand any
+ /// macros within it. Returns the expanded `TokenStream`.
+ ///
+ /// Currently only expressions expanding to literals will succeed, although
+ /// this may be relaxed in the future.
+ ///
+ /// NOTE: In error conditions, `expand_expr` may leave macros unexpanded,
+ /// report an error, failing compilation, and/or return an `Err(..)`. The
+ /// specific behavior for any error condition, and what conditions are
+ /// considered errors, is unspecified and may change in the future.
+ #[unstable(feature = "proc_macro_expand", issue = "90765")]
+ pub fn expand_expr(&self) -> Result<TokenStream, ExpandError> {
+ match bridge::client::TokenStream::expand_expr(&self.0) {
+ Ok(stream) => Ok(TokenStream(stream)),
+ Err(_) => Err(ExpandError),
+ }
+ }
}
/// Attempts to break the string into tokens and parse those tokens into a token stream.
fn from_str(src: &str) -> Result<Self, LexError> {
match bridge::client::Literal::from_str(src) {
Ok(literal) => Ok(Literal(literal)),
- Err(()) => Err(LexError::new()),
+ Err(()) => Err(LexError),
}
}
}
//! not. Normally, this would require a `find` followed by an `insert`,
//! effectively duplicating the search effort on each insertion.
//!
-//! When a user calls `map.entry(&key)`, the map will search for the key and
+//! When a user calls `map.entry(key)`, the map will search for the key and
//! then yield a variant of the `Entry` enum.
//!
//! If a `Vacant(entry)` is yielded, then the key *was not* found. In this case
/// T` and `*mut T`. More about `const` as used in raw pointers can be read at the Rust docs for the [pointer primitive].
///
/// [pointer primitive]: pointer
-/// [Rust Book]: ../book/ch03-01-variables-and-mutability.html#differences-between-variables-and-constants
+/// [Rust Book]: ../book/ch03-01-variables-and-mutability.html#constants
/// [Reference]: ../reference/items/constant-items.html
/// [const-eval]: ../reference/const_eval.html
mod const_keyword {}
#![feature(panic_internals)]
#![feature(panic_unwind)]
#![feature(pin_static_ref)]
+#![cfg_attr(not(bootstrap), feature(portable_simd))]
#![feature(prelude_import)]
#![feature(ptr_internals)]
#![feature(rustc_attrs)]
pub use core::ptr;
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::result;
+#[unstable(feature = "portable_simd", issue = "86656")]
+#[cfg(not(bootstrap))]
+pub use core::simd;
#[unstable(feature = "async_stream", issue = "79024")]
pub use core::stream;
#[stable(feature = "i128", since = "1.26.0")]
#[must_use]
#[inline]
pub const fn is_documentation(&self) -> bool {
- match self.octets() {
- [192, 0, 2, _] => true,
- [198, 51, 100, _] => true,
- [203, 0, 113, _] => true,
- _ => false,
- }
+ matches!(self.octets(), [192, 0, 2, _] | [198, 51, 100, _] | [203, 0, 113, _])
}
/// Converts this address to an [IPv4-compatible] [`IPv6` address].
#[must_use]
#[stable(feature = "unix_socket", since = "1.10.0")]
pub fn is_unnamed(&self) -> bool {
- if let AddressKind::Unnamed = self.address() { true } else { false }
+ matches!(self.address(), AddressKind::Unnamed)
}
/// Returns the contents of this address if it is a `pathname` address.
/// Sets the supplementary group IDs for the calling process. Translates to
/// a `setgroups` call in the child process.
- #[unstable(feature = "setgroups", issue = "38527", reason = "")]
+ #[unstable(feature = "setgroups", issue = "90747")]
fn groups(
&mut self,
#[cfg(not(target_os = "vxworks"))] groups: &[u32],
/// [`ExitStatusError`](process::ExitStatusError).
///
/// On Unix, `ExitStatus` **does not necessarily represent an exit status**, as
-/// passed to the `exit` system call or returned by
+/// passed to the `_exit` system call or returned by
/// [`ExitStatus::code()`](crate::process::ExitStatus::code). It represents **any wait status**
/// as returned by one of the `wait` family of system
/// calls.
use super::raw::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
use crate::convert::TryFrom;
-use crate::ffi::c_void;
use crate::fmt;
use crate::fs;
use crate::marker::PhantomData;
use crate::mem::forget;
-use crate::ptr::NonNull;
use crate::sys::c;
use crate::sys_common::{AsInner, FromInner, IntoInner};
///
/// This uses `repr(transparent)` and has the representation of a host handle,
/// so it can be used in FFI in places where a handle is passed as an argument,
-/// it is not captured or consumed, and it is never null.
+/// it is not captured or consumed.
///
/// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is
/// sometimes a valid handle value. See [here] for the full story.
///
+/// And, it *may* have the value `NULL` (0), which can occur when consoles are
+/// detached from processes, or when `windows_subsystem` is used.
+///
/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
#[derive(Copy, Clone)]
#[repr(transparent)]
#[unstable(feature = "io_safety", issue = "87074")]
pub struct BorrowedHandle<'handle> {
- handle: NonNull<c_void>,
+ handle: RawHandle,
_phantom: PhantomData<&'handle OwnedHandle>,
}
///
/// This closes the handle on drop.
///
-/// This uses `repr(transparent)` and has the representation of a host handle,
-/// so it can be used in FFI in places where a handle is passed as a consumed
-/// argument or returned as an owned value, and is never null.
-///
/// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is
-/// sometimes a valid handle value. See [here] for the full story. For APIs
-/// like `CreateFileW` which report errors with `INVALID_HANDLE_VALUE` instead
-/// of null, use [`HandleOrInvalid`] instead of `Option<OwnedHandle>`.
+/// sometimes a valid handle value. See [here] for the full story.
+///
+/// And, it *may* have the value `NULL` (0), which can occur when consoles are
+/// detached from processes, or when `windows_subsystem` is used.
///
/// `OwnedHandle` uses [`CloseHandle`] to close its handle on drop. As such,
/// it must not be used with handles to open registry keys which need to be
/// [`RegCloseKey`]: https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regclosekey
///
/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
-#[repr(transparent)]
#[unstable(feature = "io_safety", issue = "87074")]
pub struct OwnedHandle {
- handle: NonNull<c_void>,
+ handle: RawHandle,
}
+/// FFI type for handles in return values or out parameters, where `NULL` is used
+/// as a sentry value to indicate errors, such as in the return value of `CreateThread`. This uses
+/// `repr(transparent)` and has the representation of a host handle, so that it can be used in such
+/// FFI declarations.
+///
+/// The only thing you can usefully do with a `HandleOrNull` is to convert it into an
+/// `OwnedHandle` using its [`TryFrom`] implementation; this conversion takes care of the check for
+/// `NULL`. This ensures that such FFI calls cannot start using the handle without
+/// checking for `NULL` first.
+///
+/// This type concerns any value other than `NULL` to be valid, including `INVALID_HANDLE_VALUE`.
+/// This is because APIs that use `NULL` as their sentry value don't treat `INVALID_HANDLE_VALUE`
+/// as special.
+///
+/// If this holds a valid handle, it will close the handle on drop.
+#[repr(transparent)]
+#[unstable(feature = "io_safety", issue = "87074")]
+#[derive(Debug)]
+pub struct HandleOrNull(OwnedHandle);
+
/// FFI type for handles in return values or out parameters, where `INVALID_HANDLE_VALUE` is used
/// as a sentry value to indicate errors, such as in the return value of `CreateFileW`. This uses
/// `repr(transparent)` and has the representation of a host handle, so that it can be used in such
/// `INVALID_HANDLE_VALUE`. This ensures that such FFI calls cannot start using the handle without
/// checking for `INVALID_HANDLE_VALUE` first.
///
+/// This type concerns any value other than `INVALID_HANDLE_VALUE` to be valid, including `NULL`.
+/// This is because APIs that use `INVALID_HANDLE_VALUE` as their sentry value may return `NULL`
+/// under `windows_subsystem = "windows"` or other situations where I/O devices are detached.
+///
/// If this holds a valid handle, it will close the handle on drop.
#[repr(transparent)]
#[unstable(feature = "io_safety", issue = "87074")]
#[derive(Debug)]
-pub struct HandleOrInvalid(Option<OwnedHandle>);
+pub struct HandleOrInvalid(OwnedHandle);
// The Windows [`HANDLE`] type may be transferred across and shared between
// thread boundaries (despite containing a `*mut void`, which in general isn't
//
// [`HANDLE`]: std::os::windows::raw::HANDLE
unsafe impl Send for OwnedHandle {}
+unsafe impl Send for HandleOrNull {}
unsafe impl Send for HandleOrInvalid {}
unsafe impl Send for BorrowedHandle<'_> {}
unsafe impl Sync for OwnedHandle {}
+unsafe impl Sync for HandleOrNull {}
unsafe impl Sync for HandleOrInvalid {}
unsafe impl Sync for BorrowedHandle<'_> {}
/// # Safety
///
/// The resource pointed to by `handle` must be a valid open handle, it
- /// must remain open for the duration of the returned `BorrowedHandle`, and
- /// it must not be null.
+ /// must remain open for the duration of the returned `BorrowedHandle`.
///
/// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is
/// sometimes a valid handle value. See [here] for the full story.
///
+ /// And, it *may* have the value `NULL` (0), which can occur when consoles are
+ /// detached from processes, or when `windows_subsystem` is used.
+ ///
/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
#[inline]
#[unstable(feature = "io_safety", issue = "87074")]
pub unsafe fn borrow_raw_handle(handle: RawHandle) -> Self {
- assert!(!handle.is_null());
- Self { handle: NonNull::new_unchecked(handle), _phantom: PhantomData }
+ Self { handle, _phantom: PhantomData }
+ }
+}
+
+impl TryFrom<HandleOrNull> for OwnedHandle {
+ type Error = ();
+
+ #[inline]
+ fn try_from(handle_or_null: HandleOrNull) -> Result<Self, ()> {
+ let owned_handle = handle_or_null.0;
+ if owned_handle.handle.is_null() { Err(()) } else { Ok(owned_handle) }
}
}
#[inline]
fn try_from(handle_or_invalid: HandleOrInvalid) -> Result<Self, ()> {
- // In theory, we ought to be able to assume that the pointer here is
- // never null, use `OwnedHandle` rather than `Option<OwnedHandle>`, and
- // obviate the the panic path here. Unfortunately, Win32 documentation
- // doesn't explicitly guarantee this anywhere.
- //
- // APIs like [`CreateFileW`] itself have `HANDLE` arguments where a
- // null handle indicates an absent value, which wouldn't work if null
- // were a valid handle value, so it seems very unlikely that it could
- // ever return null. But who knows?
- //
- // [`CreateFileW`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew
- let owned_handle = handle_or_invalid.0.expect("A `HandleOrInvalid` was null!");
- if owned_handle.handle.as_ptr() == c::INVALID_HANDLE_VALUE {
- Err(())
- } else {
- Ok(owned_handle)
- }
+ let owned_handle = handle_or_invalid.0;
+ if owned_handle.handle == c::INVALID_HANDLE_VALUE { Err(()) } else { Ok(owned_handle) }
}
}
impl AsRawHandle for BorrowedHandle<'_> {
#[inline]
fn as_raw_handle(&self) -> RawHandle {
- self.handle.as_ptr()
+ self.handle
}
}
impl AsRawHandle for OwnedHandle {
#[inline]
fn as_raw_handle(&self) -> RawHandle {
- self.handle.as_ptr()
+ self.handle
}
}
impl IntoRawHandle for OwnedHandle {
#[inline]
fn into_raw_handle(self) -> RawHandle {
- let handle = self.handle.as_ptr();
+ let handle = self.handle;
forget(self);
handle
}
impl FromRawHandle for OwnedHandle {
/// Constructs a new instance of `Self` from the given raw handle.
///
- /// Use `HandleOrInvalid` instead of `Option<OwnedHandle>` for APIs that
- /// use `INVALID_HANDLE_VALUE` to indicate failure.
- ///
/// # Safety
///
/// The resource pointed to by `handle` must be open and suitable for
/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
#[inline]
unsafe fn from_raw_handle(handle: RawHandle) -> Self {
- assert!(!handle.is_null());
- Self { handle: NonNull::new_unchecked(handle) }
+ Self { handle }
+ }
+}
+
+impl FromRawHandle for HandleOrNull {
+ /// Constructs a new instance of `Self` from the given `RawHandle` returned
+ /// from a Windows API that uses null to indicate failure, such as
+ /// `CreateThread`.
+ ///
+ /// Use `HandleOrInvalid` instead of `HandleOrNull` for APIs that
+ /// use `INVALID_HANDLE_VALUE` to indicate failure.
+ ///
+ /// # Safety
+ ///
+ /// The resource pointed to by `handle` must be either open and otherwise
+ /// unowned, or null. Note that not all Windows APIs use null for errors;
+ /// see [here] for the full story.
+ ///
+ /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
+ #[inline]
+ unsafe fn from_raw_handle(handle: RawHandle) -> Self {
+ Self(OwnedHandle::from_raw_handle(handle))
}
}
/// from a Windows API that uses `INVALID_HANDLE_VALUE` to indicate
/// failure, such as `CreateFileW`.
///
- /// Use `Option<OwnedHandle>` instead of `HandleOrInvalid` for APIs that
+ /// Use `HandleOrNull` instead of `HandleOrInvalid` for APIs that
/// use null to indicate failure.
///
/// # Safety
///
/// The resource pointed to by `handle` must be either open and otherwise
- /// unowned, or equal to `INVALID_HANDLE_VALUE` (-1). It must not be null.
- /// Note that not all Windows APIs use `INVALID_HANDLE_VALUE` for errors;
- /// see [here] for the full story.
+ /// unowned, null, or equal to `INVALID_HANDLE_VALUE` (-1). Note that not
+ /// all Windows APIs use `INVALID_HANDLE_VALUE` for errors; see [here] for
+ /// the full story.
///
/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
#[inline]
unsafe fn from_raw_handle(handle: RawHandle) -> Self {
- // We require non-null here to catch errors earlier.
- Self(Some(OwnedHandle::from_raw_handle(handle)))
+ Self(OwnedHandle::from_raw_handle(handle))
}
}
#[inline]
fn drop(&mut self) {
unsafe {
- let _ = c::CloseHandle(self.handle.as_ptr());
+ let _ = c::CloseHandle(self.handle);
}
}
}
///
/// [`status`]: Command::status
/// [`wait`]: Child::wait
+//
+// We speak slightly loosely (here and in various other places in the stdlib docs) about `exit`
+// vs `_exit`. Naming of Unix system calls is not standardised across Unices, so terminology is a
+// matter of convention and tradition. For clarity we usually speak of `exit`, even when we might
+// mean an underlying system call such as `_exit`.
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
#[stable(feature = "process", since = "1.0.0")]
pub struct ExitStatus(imp::ExitStatus);
pub mod sockets;
pub use self::fs::*;
-pub const SOLID_BP_PROGRAM_EXITED: usize = 15;
-pub const SOLID_BP_CSABORT: usize = 16;
-
#[inline(always)]
pub fn breakpoint_program_exited(tid: usize) {
unsafe {
match () {
+ // SOLID_BP_PROGRAM_EXITED = 15
#[cfg(target_arch = "arm")]
- () => asm!("bkpt #{}", const SOLID_BP_PROGRAM_EXITED, in("r0") tid),
+ () => asm!("bkpt #15", in("r0") tid),
#[cfg(target_arch = "aarch64")]
- () => asm!("hlt #{}", const SOLID_BP_PROGRAM_EXITED, in("x0") tid),
+ () => asm!("hlt #15", in("x0") tid),
}
}
}
pub fn breakpoint_abort() {
unsafe {
match () {
+ // SOLID_BP_CSABORT = 16
#[cfg(target_arch = "arm")]
- () => asm!("bkpt #{}", const SOLID_BP_CSABORT),
+ () => asm!("bkpt #16"),
#[cfg(target_arch = "aarch64")]
- () => asm!("hlt #{}", const SOLID_BP_CSABORT),
+ () => asm!("hlt #16"),
}
}
}
fn clone3(cl_args: *mut clone_args, len: libc::size_t) -> libc::c_long
}
+ // Bypassing libc for `clone3` can make further libc calls unsafe,
+ // so we use it sparingly for now. See #89522 for details.
+ // Some tools (e.g. sandboxing tools) may also expect `fork`
+ // rather than `clone3`.
+ let want_clone3_pidfd = self.get_create_pidfd();
+
// If we fail to create a pidfd for any reason, this will
// stay as -1, which indicates an error.
let mut pidfd: pid_t = -1;
// Attempt to use the `clone3` syscall, which supports more arguments
// (in particular, the ability to create a pidfd). If this fails,
// we will fall through this block to a call to `fork()`
- if HAS_CLONE3.load(Ordering::Relaxed) {
- let mut flags = 0;
- if self.get_create_pidfd() {
- flags |= CLONE_PIDFD;
- }
-
+ if want_clone3_pidfd && HAS_CLONE3.load(Ordering::Relaxed) {
let mut args = clone_args {
- flags,
+ flags: CLONE_PIDFD,
pidfd: &mut pidfd as *mut pid_t as u64,
child_tid: 0,
parent_tid: 0,
}
}
- // If we get here, the 'clone3' syscall does not exist
- // or we do not have permission to call it
+ // Generally, we just call `fork`. If we get here after wanting `clone3`,
+ // then the syscall does not exist or we do not have permission to call it.
cvt(libc::fork()).map(|res| (res, pidfd))
}
}
/// Unix exit statuses
+//
+// This is not actually an "exit status" in Unix terminology. Rather, it is a "wait status".
+// See the discussion in comments and doc comments for `std::process::ExitStatus`.
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct ExitStatus(c_int);
target_os = "solaris",
target_os = "illumos",
))] {
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ {
+ let mut set: libc::cpu_set_t = unsafe { mem::zeroed() };
+ if unsafe { libc::sched_getaffinity(0, mem::size_of::<libc::cpu_set_t>(), &mut set) } == 0 {
+ let count = unsafe { libc::CPU_COUNT(&set) };
+ return Ok(unsafe { NonZeroUsize::new_unchecked(count as usize) });
+ }
+ }
match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } {
-1 => Err(io::Error::last_os_error()),
0 => Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform")),
# do not format submodules
"library/backtrace",
+ "library/portable-simd",
"library/stdarch",
"compiler/rustc_codegen_cranelift",
"compiler/rustc_codegen_gcc",
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("src/librustc")
+ let builder = run.builder;
+ run.path("rustc-docs").default_condition(builder.config.compiler_docs)
}
fn make_run(run: RunConfig<'_>) {
/// Builds the `rustc-docs` installer component.
fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
let host = self.host;
- if !builder.config.compiler_docs {
- return None;
- }
builder.default_doc(&[]);
let mut tarball = Tarball::new(builder, "rustc-docs", &host.triple);
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let builder = run.builder;
- run.krate("rustc-main").path("compiler").default_condition(builder.config.docs)
+ run.krate("rustc-main").path("compiler").default_condition(builder.config.compiler_docs)
}
fn make_run(run: RunConfig<'_>) {
})
.collect::<Vec<_>>();
- if !builder.config.compiler_docs && !builder.was_invoked_explicitly::<Self>() {
- builder.info("\tskipping - compiler/librustdoc docs disabled");
- return;
- }
-
// This is the intended out directory for compiler documentation.
let out = builder.compiler_doc_out(target);
t!(fs::create_dir_all(&out));
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.krate($should_run)
+ let builder = run.builder;
+ run.krate($should_run).default_condition(builder.config.compiler_docs)
}
fn make_run(run: RunConfig<'_>) {
let compiler = builder.compiler(stage, builder.config.build);
- if !builder.config.compiler_docs && !builder.was_invoked_explicitly::<Self>() {
- builder.info("\tskipping - compiler/tool docs disabled");
- return;
- }
-
// Build rustc docs so that we generate relative links.
builder.ensure(Rustc { stage, target });
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("src/test/rustdoc-js-std")
+ run.suite_path("src/test/rustdoc-js-std")
}
fn make_run(run: RunConfig<'_>) {
.arg(builder.doc_out(self.target))
.arg("--test-folder")
.arg(builder.src.join("src/test/rustdoc-js-std"));
+ for path in &builder.paths {
+ if let Some(p) =
+ util::is_valid_test_suite_arg(path, "src/test/rustdoc-js-std", builder)
+ {
+ if !p.ends_with(".js") {
+ eprintln!("A non-js file was given: `{}`", path.display());
+ panic!("Cannot run rustdoc-js-std tests");
+ }
+ command.arg("--test-file").arg(path);
+ }
+ }
builder.ensure(crate::doc::Std { target: self.target, stage: builder.top_stage });
builder.run(&mut command);
} else {
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("src/test/rustdoc-js")
+ run.suite_path("src/test/rustdoc-js")
}
fn make_run(run: RunConfig<'_>) {
.arg("--tests-folder")
.arg(builder.build.src.join("src/test/rustdoc-gui"));
for path in &builder.paths {
- if let Some(name) = path.file_name().and_then(|f| f.to_str()) {
- if name.ends_with(".goml") {
+ if let Some(p) = util::is_valid_test_suite_arg(path, "src/test/rustdoc-gui", builder) {
+ if !p.ends_with(".goml") {
+ eprintln!("A non-goml file was given: `{}`", path.display());
+ panic!("Cannot run rustdoc-gui tests");
+ }
+ if let Some(name) = path.file_name().and_then(|f| f.to_str()) {
command.arg("--file").arg(name);
}
}
// Get test-args by striping suite path
let mut test_args: Vec<&str> = paths
.iter()
- .map(|p| match p.strip_prefix(".") {
- Ok(path) => path,
- Err(_) => p,
- })
- .filter(|p| p.starts_with(suite_path))
- .filter(|p| {
- let exists = p.is_dir() || p.is_file();
- if !exists {
- if let Some(p) = p.to_str() {
- builder.info(&format!(
- "Warning: Skipping \"{}\": not a regular file or directory",
- p
- ));
- }
- }
- exists
- })
- .filter_map(|p| {
- // Since test suite paths are themselves directories, if we don't
- // specify a directory or file, we'll get an empty string here
- // (the result of the test suite directory without its suite prefix).
- // Therefore, we need to filter these out, as only the first --test-args
- // flag is respected, so providing an empty --test-args conflicts with
- // any following it.
- match p.strip_prefix(suite_path).ok().and_then(|p| p.to_str()) {
- Some(s) if !s.is_empty() => Some(s),
- _ => None,
- }
- })
+ .filter_map(|p| util::is_valid_test_suite_arg(p, suite_path, builder))
.collect();
test_args.append(&mut builder.config.cmd.test_args());
$name:ident, $path:expr, $tool_name:expr
$(,is_external_tool = $external:expr)*
$(,is_unstable_tool = $unstable:expr)*
- $(,features = $features:expr)*
;
)+) => {
#[derive(Copy, PartialEq, Eq, Clone)]
} else {
SourceType::InTree
},
- extra_features: {
- // FIXME(#60643): avoid this lint by using `_`
- let mut _tmp = Vec::new();
- $(_tmp.extend($features);)*
- _tmp
- },
+ extra_features: vec![],
}).expect("expected to build -- essential tool")
}
}
|| target.contains("fuchsia")
|| target.contains("bpf"))
}
+
+pub fn is_valid_test_suite_arg<'a, P: AsRef<Path>>(
+ path: &'a Path,
+ suite_path: P,
+ builder: &Builder<'_>,
+) -> Option<&'a str> {
+ let suite_path = suite_path.as_ref();
+ let path = match path.strip_prefix(".") {
+ Ok(p) => p,
+ Err(_) => path,
+ };
+ if !path.starts_with(suite_path) {
+ return None;
+ }
+ let exists = path.is_dir() || path.is_file();
+ if !exists {
+ if let Some(p) = path.to_str() {
+ builder.info(&format!("Warning: Skipping \"{}\": not a regular file or directory", p));
+ }
+ return None;
+ }
+ // Since test suite paths are themselves directories, if we don't
+ // specify a directory or file, we'll get an empty string here
+ // (the result of the test suite directory without its suite prefix).
+ // Therefore, we need to filter these out, as only the first --test-args
+ // flag is respected, so providing an empty --test-args conflicts with
+ // any following it.
+ match path.strip_prefix(suite_path).ok().and_then(|p| p.to_str()) {
+ Some(s) if !s.is_empty() => Some(s),
+ _ => None,
+ }
+}
-Subproject commit fd9299792852c9a368cb236748781852f75cdac6
+Subproject commit 5c5dbc5b196c9564422b3193264f3288d2a051ce
-Subproject commit 7c0088ca744d293a5f4b1e2ac378e7c23d30fe55
+Subproject commit 27f4a84d3852e9416cae5861254fa53a825c56bd
-Subproject commit 358e6a61d5f4f0496d0a81e70cdcd25d05307342
+Subproject commit c6b4bf831e9a40aec34f53067d20634839a6778b
-Subproject commit 27f1ff5e440ef78828b68ab882b98e1b10d9af32
+Subproject commit e9d45342d7a6c1def4731f1782d87ea317ba30c3
-Subproject commit b06008731af0f7d07cd0614e820c8276dfed1c18
+Subproject commit 196ef69aa68f2cef44f37566ee7db37daf00301b
# The Rustdoc Book
- [What is rustdoc?](what-is-rustdoc.md)
+- [How to read rustdoc output](how-to-read-rustdoc.md)
- [How to write documentation](how-to-write-documentation.md)
- [What to include (and exclude)](what-to-include.md)
- [Command-line arguments](command-line-arguments.md)
--- /dev/null
+# How to read rustdoc output
+
+Rustdoc's HTML output includes a friendly and useful navigation interface which
+makes it easier for users to navigate and understand your code.
+This chapter covers the major features of that interface,
+and is a great starting point for documentation authors and users alike.
+
+## Structure
+
+The `rustdoc` output is divided into three sections.
+Along the left side of each page is a quick navigation bar,
+which shows contextual information about the current entry.
+The rest of the page is taken up by the search interface at the top
+and the documentation for the current item below that.
+
+## The Item Documentation
+
+The majority of the screen is taken up with the documentation text for the item
+currently being viewed.
+At the top is some at-a-glance info and controls:
+
+- the type and name of the item,
+ such as "Struct `std::time::Duration`",
+- a button to copy the item's path to the clipboard,
+ which is a clipboard item
+- a button to collapse or expand the top-level documentation for that item
+ (`[+]` or `[-]`),
+- a link to the source code (`[src]`),
+ if [configured](the-doc-attribute.html#html_no_source),
+ and present (the source may not be available if
+ the documentation was created with `cargo doc --no-deps`),
+- and the version in which the item became stable,
+ if it's a stable item in the standard library.
+
+Below this is the main documentation for the item,
+including a definition or function signature if appropriate,
+followed by a list of fields or variants for Rust types.
+Finally, the page lists associated functions and trait implementations,
+including automatic and blanket implementations that `rustdoc` knows about.
+
+### Navigation
+
+Subheadings, variants, fields, and many other things in this documentation
+are anchors and can be clicked on and deep-linked to,
+which is a great way to communicate exactly what you're talking about.
+The typograpical character "§" appears next to lines with anchors on them
+when hovered or given keyboard focus.
+
+## The Navigation Bar
+
+For example, when looking at documentation for the crate root,
+it shows all the crates documented in the documentation bundle,
+and quick links to the modules, structs, traits, functions, and macros available
+from the current crate.
+At the top, it displays a [configurable logo](the-doc-attribute.html#html_logo_url)
+alongside the current crate's name and version,
+or the current item whose documentation is being displayed.
+
+## The Theme Picker and Search Interface
+
+When viewing `rustdoc`'s output in a browser with JavaScript enabled,
+a dynamic interface appears at the top of the page.
+To the left is the theme picker, denoted with a paint-brush icon,
+and the search interface, help screen, and options appear to the right of that.
+
+### The Theme Picker
+
+Clicking on the theme picker provides a list of themes -
+by default `ayu`, `light`, and `dark` -
+which are available for viewing.
+
+### The Search Interface
+
+Typing in the search bar instantly searches the available documentation for
+the string entered with a fuzzy matching algorithm that is tolerant of minor
+typos.
+
+By default, the search results give are "In Names",
+meaning that the fuzzy match is made against the names of items.
+Matching names are shown on the left, and the first few words of their
+descriptions are given on the right.
+By clicking an item, you will navigate to its particular documentation.
+
+There are two other sets of results, shown as tabs in the search results pane.
+"In Parameters" shows matches for the string in the types of parameters to
+functions, and "In Return Types" shows matches in the return types of functions.
+Both are very useful when looking for a function whose name you can't quite
+bring to mind when you know the type you have or want.
+
+When typing in the search bar, you can prefix your search term with a type
+followed by a colon (such as `mod:`) to restrict the results to just that
+kind of item. (The available items are listed in the help popup.)
+
+### Shortcuts
+
+Pressing `S` while focused elsewhere on the page will move focus to the
+search bar, and pressing `?` shows the help screen,
+which includes all these shortcuts and more.
+Pressing `T` focuses the theme picker.
+
+When the search results are focused,
+the left and right arrows move between tabs and the up and down arrows move
+among the results.
+Pressing the enter or return key opens the highlighted result.
+
+When looking at the documentation for an item, the plus and minus keys expand
+and collapse all sections in the document.
--- /dev/null
+# `temps-dir`
+
+--------------------
+
+The `-Ztemps-dir` compiler flag specifies the directory to write the
+intermediate files in. If not set, the output directory is used. This option is
+useful if you are running more than one instance of `rustc` (e.g. with different
+`--crate-type` settings), and you need to make sure they are not overwriting
+each other's intermediate files. No files are kept unless `-C save-temps=yes` is
+also set.
--- /dev/null
+# `type_changing_struct_update`
+
+The tracking issue for this feature is: [#86555]
+
+[#86555]: https://github.com/rust-lang/rust/issues/86555
+
+------------------------
+
+This implements [RFC2528]. When turned on, you can create instances of the same struct
+that have different generic type or lifetime parameters.
+
+[RFC2528]: https://github.com/rust-lang/rfcs/blob/master/text/2528-type-changing-struct-update-syntax.md
+
+```rust
+#![allow(unused_variables, dead_code)]
+#![feature(type_changing_struct_update)]
+
+fn main () {
+ struct Foo<T, U> {
+ field1: T,
+ field2: U,
+ }
+
+ let base: Foo<String, i32> = Foo {
+ field1: String::from("hello"),
+ field2: 1234,
+ };
+ let updated: Foo<f64, i32> = Foo {
+ field1: 3.14,
+ ..base
+ };
+}
+```
Note that the `fn` or `static` item does not need to be public or `#[no_mangle]`: the compiler will automatically insert the appropriate mangled symbol name into the assembly code.
-By default, `asm!` assumes that any register not specified as an output will have its contents preserved by the assembly code. The [`clobber_abi`](#abi-clobbers) argument to `asm!` tells the compiler to automatically insert the necessary clobber operands according to the given calling convention ABI: any register which is not fully preserved in that ABI will be treated as clobbered.
+By default, `asm!` assumes that any register not specified as an output will have its contents preserved by the assembly code. The [`clobber_abi`](#abi-clobbers) argument to `asm!` tells the compiler to automatically insert the necessary clobber operands according to the given calling convention ABI: any register which is not fully preserved in that ABI will be treated as clobbered. Multiple `clobber_abi` arguments may be provided and all clobbers from all specified ABIs will be inserted.
## Register template modifiers
operand_expr := expr / "_" / expr "=>" expr / expr "=>" "_"
reg_operand := dir_spec "(" reg_spec ")" operand_expr
operand := reg_operand / "const" const_expr / "sym" path
-clobber_abi := "clobber_abi(" <abi> ")"
+clobber_abi := "clobber_abi(" <abi> *["," <abi>] [","] ")"
option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "nostack" / "att_syntax" / "raw"
options := "options(" option *["," option] [","] ")"
-asm := "asm!(" format_string *("," format_string) *("," [ident "="] operand) ["," clobber_abi] *("," options) [","] ")"
+asm := "asm!(" format_string *("," format_string) *("," [ident "="] operand) *("," clobber_abi) *("," options) [","] ")"
```
Inline assembly is currently supported on the following architectures:
| AArch64 | `vreg` | `v[0-31]` | `w` |
| AArch64 | `vreg_low16` | `v[0-15]` | `x` |
| AArch64 | `preg` | `p[0-15]`, `ffr` | Only clobbers |
-| ARM | `reg` | `r[0-12]`, `r14` | `r` |
-| ARM (Thumb) | `reg_thumb` | `r[0-r7]` | `l` |
+| ARM (ARM) | `reg` | `r[0-12]`, `r14` | `r` |
+| ARM (Thumb2) | `reg` | `r[0-12]`, `r14` | `r` |
+| ARM (Thumb1) | `reg` | `r[0-7]` | `r` |
| ARM (ARM) | `reg_thumb` | `r[0-r12]`, `r14` | `l` |
+| ARM (Thumb2) | `reg_thumb` | `r[0-7]` | `l` |
+| ARM (Thumb1) | `reg_thumb` | `r[0-7]` | `l` |
| ARM | `sreg` | `s[0-31]` | `t` |
| ARM | `sreg_low16` | `s[0-15]` | `x` |
| ARM | `dreg` | `d[0-31]` | `w` |
The `clobber_abi` keyword can be used to apply a default set of clobbers to an `asm` block. This will automatically insert the necessary clobber constraints as needed for calling a function with a particular calling convention: if the calling convention does not fully preserve the value of a register across a call then a `lateout("reg") _` is implicitly added to the operands list.
+`clobber_abi` may be specified any number of times. It will insert a clobber for all unique registers in the union of all specified calling conventions.
+
Generic register class outputs are disallowed by the compiler when `clobber_abi` is used: all outputs must specify an explicit register. Explicit register outputs have precedence over the implicit clobbers inserted by `clobber_abi`: a clobber will only be inserted for a register if that register is not used as an output.
The following ABIs can be used with `clobber_abi`:
constants defined in Rust to be used in assembly code:
```rust,no_run
-#![feature(global_asm)]
+#![feature(global_asm, asm_const)]
# #[cfg(any(target_arch="x86", target_arch="x86_64"))]
# mod x86 {
const C: i32 = 1234;
arguments list:
```rust,no_run
-#![feature(global_asm)]
+#![feature(global_asm, asm_const)]
# #[cfg(any(target_arch="x86", target_arch="x86_64"))]
# mod x86 {
global_asm!("movl ${}, %ecx", const 5, options(att_syntax));
new_generics
});
- let negative_polarity;
+ let polarity;
let new_generics = match result {
AutoTraitResult::PositiveImpl(new_generics) => {
- negative_polarity = false;
+ polarity = ty::ImplPolarity::Positive;
if discard_positive_impl {
return None;
}
new_generics
}
AutoTraitResult::NegativeImpl => {
- negative_polarity = true;
+ polarity = ty::ImplPolarity::Negative;
// For negative impls, we use the generic params, but *not* the predicates,
// from the original type. Otherwise, the displayed impl appears to be a
visibility: Inherited,
def_id: ItemId::Auto { trait_: trait_def_id, for_: item_def_id },
kind: box ImplItem(Impl {
- span: Span::dummy(),
unsafety: hir::Unsafety::Normal,
generics: new_generics,
trait_: Some(trait_ref.clean(self.cx)),
for_: ty.clean(self.cx),
items: Vec::new(),
- negative_polarity,
- synthetic: true,
- blanket_impl: None,
+ polarity,
+ kind: ImplKind::Auto,
}),
cfg: None,
})
visibility: Inherited,
def_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
kind: box ImplItem(Impl {
- span: Span::new(self.cx.tcx.def_span(impl_def_id)),
unsafety: hir::Unsafety::Normal,
generics: (
self.cx.tcx.generics_of(impl_def_id),
.tcx
.associated_items(impl_def_id)
.in_definition_order()
- .collect::<Vec<_>>()
- .clean(self.cx),
- negative_polarity: false,
- synthetic: false,
- blanket_impl: Some(box trait_ref.self_ty().clean(self.cx)),
+ .map(|x| x.clean(self.cx))
+ .collect::<Vec<_>>(),
+ polarity: ty::ImplPolarity::Positive,
+ kind: ImplKind::Blanket(box trait_ref.self_ty().clean(self.cx)),
}),
cfg: None,
});
use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::{kw, sym, Symbol};
-use crate::clean::{self, utils, Attributes, AttributesExt, ItemId, NestedAttributesExt, Type};
+use crate::clean::{
+ self, utils, Attributes, AttributesExt, ImplKind, ItemId, NestedAttributesExt, Type,
+};
use crate::core::DocContext;
use crate::formats::item_type::ItemType;
clean::Enum {
generics: (cx.tcx.generics_of(did), predicates).clean(cx),
variants_stripped: false,
- variants: cx.tcx.adt_def(did).variants.clean(cx),
+ variants: cx.tcx.adt_def(did).variants.iter().map(|v| v.clean(cx)).collect(),
}
}
clean::Struct {
struct_type: variant.ctor_kind,
generics: (cx.tcx.generics_of(did), predicates).clean(cx),
- fields: variant.fields.clean(cx),
+ fields: variant.fields.iter().map(|x| x.clean(cx)).collect(),
fields_stripped: false,
}
}
let predicates = cx.tcx.explicit_predicates_of(did);
let variant = cx.tcx.adt_def(did).non_enum_variant();
- clean::Union {
- generics: (cx.tcx.generics_of(did), predicates).clean(cx),
- fields: variant.fields.clean(cx),
- fields_stripped: false,
- }
+ let generics = (cx.tcx.generics_of(did), predicates).clean(cx);
+ let fields = variant.fields.iter().map(|x| x.clean(cx)).collect();
+ clean::Union { generics, fields, fields_stripped: false }
}
fn build_type_alias(cx: &mut DocContext<'_>, did: DefId) -> clean::Typedef {
tcx.associated_items(did)
.in_definition_order()
.filter_map(|item| {
- if associated_trait.is_some() || item.vis == ty::Visibility::Public {
+ if associated_trait.is_some() || item.vis.is_public() {
Some(item.clean(cx))
} else {
None
),
};
let polarity = tcx.impl_polarity(did);
- let trait_ = associated_trait.clean(cx);
+ let trait_ = associated_trait.map(|t| t.clean(cx));
if trait_.as_ref().map(|t| t.def_id()) == tcx.lang_items().deref_trait() {
super::build_deref_target_impls(cx, &trait_items, ret);
}
did,
None,
clean::ImplItem(clean::Impl {
- span: clean::types::rustc_span(did, cx.tcx),
unsafety: hir::Unsafety::Normal,
generics,
trait_,
for_,
items: trait_items,
- negative_polarity: polarity.clean(cx),
- synthetic: false,
- blanket_impl: None,
+ polarity,
+ kind: ImplKind::Normal,
}),
box merged_attrs,
cx,
// two namespaces, so the target may be listed twice. Make sure we only
// visit each node at most once.
for &item in cx.tcx.item_children(did).iter() {
- if item.vis == ty::Visibility::Public {
+ if item.vis.is_public() {
let res = item.res.expect_non_local();
if let Some(def_id) = res.mod_def_id() {
if did == def_id || !visited.insert(def_id) {
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
-use rustc_index::vec::{Idx, IndexVec};
use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
use rustc_middle::middle::resolve_lifetime as rl;
use rustc_middle::ty::fold::TypeFolder;
use std::collections::hash_map::Entry;
use std::default::Default;
use std::hash::Hash;
-use std::rc::Rc;
use std::{mem, vec};
use crate::core::{self, DocContext, ImplTraitParam};
fn clean(&self, cx: &mut DocContext<'_>) -> T;
}
-impl<T: Clean<U>, U> Clean<Vec<U>> for [T] {
- fn clean(&self, cx: &mut DocContext<'_>) -> Vec<U> {
- self.iter().map(|x| x.clean(cx)).collect()
- }
-}
-
-impl<T: Clean<U>, U, V: Idx> Clean<IndexVec<V, U>> for IndexVec<V, T> {
- fn clean(&self, cx: &mut DocContext<'_>) -> IndexVec<V, U> {
- self.iter().map(|x| x.clean(cx)).collect()
- }
-}
-
-impl<T: Clean<U>, U> Clean<U> for &T {
- fn clean(&self, cx: &mut DocContext<'_>) -> U {
- (**self).clean(cx)
- }
-}
-
-impl<T: Clean<U>, U> Clean<U> for Rc<T> {
- fn clean(&self, cx: &mut DocContext<'_>) -> U {
- (**self).clean(cx)
- }
-}
-
-impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> {
- fn clean(&self, cx: &mut DocContext<'_>) -> Option<U> {
- self.as_ref().map(|v| v.clean(cx))
- }
-}
-
impl Clean<Item> for doctree::Module<'_> {
fn clean(&self, cx: &mut DocContext<'_>) -> Item {
let mut items: Vec<Item> = vec![];
| rl::Region::Free(_, node_id),
) = def
{
- if let Some(lt) = cx.lt_substs.get(&node_id).cloned() {
+ if let Some(lt) = cx.substs.get(&node_id).and_then(|p| p.as_lt()).cloned() {
return lt;
}
}
.collect();
WherePredicate::BoundPredicate {
ty: wbp.bounded_ty.clean(cx),
- bounds: wbp.bounds.clean(cx),
+ bounds: wbp.bounds.iter().map(|x| x.clean(cx)).collect(),
bound_params,
}
}
hir::WherePredicate::RegionPredicate(ref wrp) => WherePredicate::RegionPredicate {
lifetime: wrp.lifetime.clean(cx),
- bounds: wrp.bounds.clean(cx),
+ bounds: wrp.bounds.iter().map(|x| x.clean(cx)).collect(),
},
hir::WherePredicate::EqPredicate(ref wrp) => {
self.name.ident().name,
GenericParamDefKind::Type {
did: cx.tcx.hir().local_def_id(self.hir_id).to_def_id(),
- bounds: self.bounds.clean(cx),
- default: default.clean(cx).map(Box::new),
+ bounds: self.bounds.iter().map(|x| x.clean(cx)).collect(),
+ default: default.map(|t| t.clean(cx)).map(Box::new),
synthetic,
},
),
}
params.extend(impl_trait_params);
- let mut generics =
- Generics { params, where_predicates: self.where_clause.predicates.clean(cx) };
+ let mut generics = Generics {
+ params,
+ where_predicates: self.where_clause.predicates.iter().map(|x| x.clean(cx)).collect(),
+ };
// Some duplicates are generated for ?Sized bounds between type params and where
// predicates. The point in here is to move the bounds definitions from type params
fn clean(&self, cx: &mut DocContext<'_>) -> PolyTrait {
PolyTrait {
trait_: self.trait_ref.clean(cx),
- generic_params: self.bound_generic_params.clean(cx),
+ generic_params: self.bound_generic_params.iter().map(|x| x.clean(cx)).collect(),
}
}
}
}
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(names)) => {
let (generics, decl) = enter_impl_trait(cx, |cx| {
- (self.generics.clean(cx), (&*sig.decl, &names[..]).clean(cx))
+ (self.generics.clean(cx), (sig.decl, names).clean(cx))
});
let mut t = Function { header: sig.header, decl, generics };
if t.header.constness == hir::Constness::Const
TyMethodItem(t)
}
hir::TraitItemKind::Type(bounds, ref default) => {
- AssocTypeItem(bounds.clean(cx), default.clean(cx))
+ let bounds = bounds.iter().map(|x| x.clean(cx)).collect();
+ let default = default.map(|t| t.clean(cx));
+ AssocTypeItem(bounds, default)
}
};
let what_rustc_thinks =
None
};
- AssocTypeItem(bounds, ty.clean(cx))
+ AssocTypeItem(bounds, ty.map(|t| t.clean(cx)))
} else {
// FIXME: when could this happen? Associated items in inherent impls?
let type_ = tcx.type_of(self.def_id).clean(cx);
}
fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
- use rustc_hir::GenericParamCount;
let hir::Ty { hir_id: _, span, ref kind } = *hir_ty;
let qpath = match kind {
hir::TyKind::Path(qpath) => qpath,
match qpath {
hir::QPath::Resolved(None, ref path) => {
if let Res::Def(DefKind::TyParam, did) = path.res {
- if let Some(new_ty) = cx.ty_substs.get(&did).cloned() {
+ if let Some(new_ty) = cx.substs.get(&did).and_then(|p| p.as_ty()).cloned() {
return new_ty;
}
if let Some(bounds) = cx.impl_trait_bounds.remove(&did.into()) {
}
}
- let mut alias = None;
- if let Res::Def(DefKind::TyAlias, def_id) = path.res {
- // Substitute private type aliases
- if let Some(def_id) = def_id.as_local() {
- let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
- if !cx.cache.access_levels.is_exported(def_id.to_def_id()) {
- alias = Some(&cx.tcx.hir().expect_item(hir_id).kind);
- }
- }
- };
-
- if let Some(&hir::ItemKind::TyAlias(ref ty, ref generics)) = alias {
- let provided_params = &path.segments.last().expect("segments were empty");
- let mut ty_substs = FxHashMap::default();
- let mut lt_substs = FxHashMap::default();
- let mut ct_substs = FxHashMap::default();
- let generic_args = provided_params.args();
- {
- let mut indices: GenericParamCount = Default::default();
- for param in generics.params.iter() {
- match param.kind {
- hir::GenericParamKind::Lifetime { .. } => {
- let mut j = 0;
- let lifetime = generic_args.args.iter().find_map(|arg| match arg {
- hir::GenericArg::Lifetime(lt) => {
- if indices.lifetimes == j {
- return Some(lt);
- }
- j += 1;
- None
- }
- _ => None,
- });
- if let Some(lt) = lifetime.cloned() {
- let lt_def_id = cx.tcx.hir().local_def_id(param.hir_id);
- let cleaned = if !lt.is_elided() {
- lt.clean(cx)
- } else {
- self::types::Lifetime::elided()
- };
- lt_substs.insert(lt_def_id.to_def_id(), cleaned);
- }
- indices.lifetimes += 1;
- }
- hir::GenericParamKind::Type { ref default, .. } => {
- let ty_param_def_id = cx.tcx.hir().local_def_id(param.hir_id);
- let mut j = 0;
- let type_ = generic_args.args.iter().find_map(|arg| match arg {
- hir::GenericArg::Type(ty) => {
- if indices.types == j {
- return Some(ty);
- }
- j += 1;
- None
- }
- _ => None,
- });
- if let Some(ty) = type_ {
- ty_substs.insert(ty_param_def_id.to_def_id(), ty.clean(cx));
- } else if let Some(default) = *default {
- ty_substs
- .insert(ty_param_def_id.to_def_id(), default.clean(cx));
- }
- indices.types += 1;
- }
- hir::GenericParamKind::Const { .. } => {
- let const_param_def_id = cx.tcx.hir().local_def_id(param.hir_id);
- let mut j = 0;
- let const_ = generic_args.args.iter().find_map(|arg| match arg {
- hir::GenericArg::Const(ct) => {
- if indices.consts == j {
- return Some(ct);
- }
- j += 1;
- None
- }
- _ => None,
- });
- if let Some(ct) = const_ {
- ct_substs.insert(const_param_def_id.to_def_id(), ct.clean(cx));
- }
- // FIXME(const_generics_defaults)
- indices.consts += 1;
- }
- }
- }
- }
- return cx.enter_alias(ty_substs, lt_substs, ct_substs, |cx| ty.clean(cx));
+ if let Some(expanded) = maybe_expand_private_type_alias(cx, path) {
+ expanded
+ } else {
+ let path = path.clean(cx);
+ resolve_type(cx, path)
}
- let path = path.clean(cx);
- resolve_type(cx, path)
}
hir::QPath::Resolved(Some(ref qself), p) => {
// Try to normalize `<X as Y>::T` to a type
let trait_def = cx.tcx.associated_item(p.res.def_id()).container.id();
let trait_ = self::Path {
res: Res::Def(DefKind::Trait, trait_def),
- segments: trait_segments.clean(cx),
+ segments: trait_segments.iter().map(|x| x.clean(cx)).collect(),
};
register_res(cx, trait_.res);
Type::QPath {
}
}
+fn maybe_expand_private_type_alias(cx: &mut DocContext<'_>, path: &hir::Path<'_>) -> Option<Type> {
+ let Res::Def(DefKind::TyAlias, def_id) = path.res else { return None };
+ // Substitute private type aliases
+ let Some(def_id) = def_id.as_local() else { return None };
+ let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
+ let alias = if !cx.cache.access_levels.is_exported(def_id.to_def_id()) {
+ &cx.tcx.hir().expect_item(hir_id).kind
+ } else {
+ return None;
+ };
+ let hir::ItemKind::TyAlias(ty, generics) = alias else { return None };
+
+ let provided_params = &path.segments.last().expect("segments were empty");
+ let mut substs = FxHashMap::default();
+ let generic_args = provided_params.args();
+
+ let mut indices: hir::GenericParamCount = Default::default();
+ for param in generics.params.iter() {
+ match param.kind {
+ hir::GenericParamKind::Lifetime { .. } => {
+ let mut j = 0;
+ let lifetime = generic_args.args.iter().find_map(|arg| match arg {
+ hir::GenericArg::Lifetime(lt) => {
+ if indices.lifetimes == j {
+ return Some(lt);
+ }
+ j += 1;
+ None
+ }
+ _ => None,
+ });
+ if let Some(lt) = lifetime.cloned() {
+ let lt_def_id = cx.tcx.hir().local_def_id(param.hir_id);
+ let cleaned = if !lt.is_elided() {
+ lt.clean(cx)
+ } else {
+ self::types::Lifetime::elided()
+ };
+ substs.insert(lt_def_id.to_def_id(), SubstParam::Lifetime(cleaned));
+ }
+ indices.lifetimes += 1;
+ }
+ hir::GenericParamKind::Type { ref default, .. } => {
+ let ty_param_def_id = cx.tcx.hir().local_def_id(param.hir_id);
+ let mut j = 0;
+ let type_ = generic_args.args.iter().find_map(|arg| match arg {
+ hir::GenericArg::Type(ty) => {
+ if indices.types == j {
+ return Some(ty);
+ }
+ j += 1;
+ None
+ }
+ _ => None,
+ });
+ if let Some(ty) = type_ {
+ substs.insert(ty_param_def_id.to_def_id(), SubstParam::Type(ty.clean(cx)));
+ } else if let Some(default) = *default {
+ substs.insert(ty_param_def_id.to_def_id(), SubstParam::Type(default.clean(cx)));
+ }
+ indices.types += 1;
+ }
+ hir::GenericParamKind::Const { .. } => {
+ let const_param_def_id = cx.tcx.hir().local_def_id(param.hir_id);
+ let mut j = 0;
+ let const_ = generic_args.args.iter().find_map(|arg| match arg {
+ hir::GenericArg::Const(ct) => {
+ if indices.consts == j {
+ return Some(ct);
+ }
+ j += 1;
+ None
+ }
+ _ => None,
+ });
+ if let Some(ct) = const_ {
+ substs
+ .insert(const_param_def_id.to_def_id(), SubstParam::Constant(ct.clean(cx)));
+ }
+ // FIXME(const_generics_defaults)
+ indices.consts += 1;
+ }
+ }
+ }
+
+ Some(cx.enter_alias(substs, |cx| ty.clean(cx)))
+}
+
impl Clean<Type> for hir::Ty<'_> {
fn clean(&self, cx: &mut DocContext<'_>) -> Type {
use rustc_hir::*;
let length = print_const(cx, ct.eval(cx.tcx, param_env));
Array(box ty.clean(cx), length)
}
- TyKind::Tup(tys) => Tuple(tys.clean(cx)),
+ TyKind::Tup(tys) => Tuple(tys.iter().map(|x| x.clean(cx)).collect()),
TyKind::OpaqueDef(item_id, _) => {
let item = cx.tcx.hir().item(item_id);
if let hir::ItemKind::OpaqueTy(ref ty) = item.kind {
- ImplTrait(ty.bounds.clean(cx))
+ ImplTrait(ty.bounds.iter().map(|x| x.clean(cx)).collect())
} else {
unreachable!()
}
DynTrait(bounds, lifetime)
}
- ty::Tuple(t) => Tuple(t.iter().map(|t| t.expect_ty()).collect::<Vec<_>>().clean(cx)),
+ ty::Tuple(t) => Tuple(t.iter().map(|t| t.expect_ty().clean(cx)).collect()),
ty::Projection(ref data) => data.clean(cx),
impl Clean<Path> for hir::Path<'_> {
fn clean(&self, cx: &mut DocContext<'_>) -> Path {
- Path { res: self.res, segments: self.segments.clean(cx) }
+ Path { res: self.res, segments: self.segments.iter().map(|x| x.clean(cx)).collect() }
}
}
let output = self.bindings[0].ty().clean(cx);
let output =
if output != Type::Tuple(Vec::new()) { Some(Box::new(output)) } else { None };
- GenericArgs::Parenthesized { inputs: self.inputs().clean(cx), output }
+ let inputs = self.inputs().iter().map(|x| x.clean(cx)).collect();
+ GenericArgs::Parenthesized { inputs, output }
} else {
- GenericArgs::AngleBracketed {
- args: self
- .args
- .iter()
- .map(|arg| match arg {
- hir::GenericArg::Lifetime(lt) if !lt.is_elided() => {
- GenericArg::Lifetime(lt.clean(cx))
- }
- hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()),
- hir::GenericArg::Type(ty) => GenericArg::Type(ty.clean(cx)),
- hir::GenericArg::Const(ct) => GenericArg::Const(Box::new(ct.clean(cx))),
- hir::GenericArg::Infer(_inf) => GenericArg::Infer,
- })
- .collect(),
- bindings: self.bindings.clean(cx),
- }
+ let args = self
+ .args
+ .iter()
+ .map(|arg| match arg {
+ hir::GenericArg::Lifetime(lt) if !lt.is_elided() => {
+ GenericArg::Lifetime(lt.clean(cx))
+ }
+ hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()),
+ hir::GenericArg::Type(ty) => GenericArg::Type(ty.clean(cx)),
+ hir::GenericArg::Const(ct) => GenericArg::Const(Box::new(ct.clean(cx))),
+ hir::GenericArg::Infer(_inf) => GenericArg::Infer,
+ })
+ .collect();
+ let bindings = self.bindings.iter().map(|x| x.clean(cx)).collect();
+ GenericArgs::AngleBracketed { args, bindings }
}
}
}
impl Clean<BareFunctionDecl> for hir::BareFnTy<'_> {
fn clean(&self, cx: &mut DocContext<'_>) -> BareFunctionDecl {
let (generic_params, decl) = enter_impl_trait(cx, |cx| {
- (self.generic_params.clean(cx), (&*self.decl, self.param_names).clean(cx))
+ let generic_params = self.generic_params.iter().map(|x| x.clean(cx)).collect();
+ let decl = (self.decl, self.param_names).clean(cx);
+ (generic_params, decl)
});
BareFunctionDecl { unsafety: self.unsafety, abi: self.abi, decl, generic_params }
}
kind: ConstantKind::Local { body: body_id, def_id },
}),
ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy {
- bounds: ty.bounds.clean(cx),
+ bounds: ty.bounds.iter().map(|x| x.clean(cx)).collect(),
generics: ty.generics.clean(cx),
}),
ItemKind::TyAlias(hir_ty, ref generics) => {
}),
ItemKind::TraitAlias(ref generics, bounds) => TraitAliasItem(TraitAlias {
generics: generics.clean(cx),
- bounds: bounds.clean(cx),
+ bounds: bounds.iter().map(|x| x.clean(cx)).collect(),
}),
ItemKind::Union(ref variant_data, ref generics) => UnionItem(Union {
generics: generics.clean(cx),
- fields: variant_data.fields().clean(cx),
+ fields: variant_data.fields().iter().map(|x| x.clean(cx)).collect(),
fields_stripped: false,
}),
ItemKind::Struct(ref variant_data, ref generics) => StructItem(Struct {
struct_type: CtorKind::from_hir(variant_data),
generics: generics.clean(cx),
- fields: variant_data.fields().clean(cx),
+ fields: variant_data.fields().iter().map(|x| x.clean(cx)).collect(),
fields_stripped: false,
}),
ItemKind::Impl(ref impl_) => return clean_impl(impl_, item.hir_id(), cx),
clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx)
}
ItemKind::Macro(ref macro_def) => MacroItem(Macro {
- source: display_macro_source(cx, name, macro_def, def_id, &item.vis),
+ source: display_macro_source(cx, name, macro_def, def_id, item.vis),
}),
ItemKind::Trait(is_auto, unsafety, ref generics, bounds, item_ids) => {
let items = item_ids
unsafety,
items,
generics: generics.clean(cx),
- bounds: bounds.clean(cx),
+ bounds: bounds.iter().map(|x| x.clean(cx)).collect(),
is_auto: is_auto.clean(cx),
})
}
}
}
-impl Clean<bool> for ty::ImplPolarity {
- /// Returns whether the impl has negative polarity.
- fn clean(&self, _: &mut DocContext<'_>) -> bool {
- match self {
- &ty::ImplPolarity::Positive |
- // FIXME: do we want to do something else here?
- &ty::ImplPolarity::Reservation => false,
- &ty::ImplPolarity::Negative => true,
- }
- }
-}
-
fn clean_impl(impl_: &hir::Impl<'_>, hir_id: hir::HirId, cx: &mut DocContext<'_>) -> Vec<Item> {
let tcx = cx.tcx;
let mut ret = Vec::new();
- let trait_ = impl_.of_trait.clean(cx);
+ let trait_ = impl_.of_trait.as_ref().map(|t| t.clean(cx));
let items =
impl_.items.iter().map(|ii| tcx.hir().impl_item(ii.id).clean(cx)).collect::<Vec<_>>();
let def_id = tcx.hir().local_def_id(hir_id);
});
let mut make_item = |trait_: Option<Path>, for_: Type, items: Vec<Item>| {
let kind = ImplItem(Impl {
- span: types::rustc_span(tcx.hir().local_def_id(hir_id).to_def_id(), tcx),
unsafety: impl_.unsafety,
generics: impl_.generics.clean(cx),
trait_,
for_,
items,
- negative_polarity: tcx.impl_polarity(def_id).clean(cx),
- synthetic: false,
- blanket_impl: None,
+ polarity: tcx.impl_polarity(def_id),
+ kind: ImplKind::Normal,
});
Item::from_hir_id_and_parts(hir_id, None, kind, cx)
};
// this is the ID of the crate itself
let crate_def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
let attrs = cx.tcx.hir().attrs(krate.hir_id());
- let please_inline = krate.vis.node.is_pub()
+ let please_inline = cx.tcx.visibility(krate.def_id).is_public()
&& attrs.iter().any(|a| {
a.has_name(sym::doc)
&& match a.meta_item_list() {
return Vec::new();
}
+ let visibility = cx.tcx.visibility(import.def_id);
let attrs = cx.tcx.hir().attrs(import.hir_id());
let inline_attr = attrs.lists(sym::doc).get_word_attr(sym::inline);
- let pub_underscore = import.vis.node.is_pub() && name == kw::Underscore;
+ let pub_underscore = visibility.is_public() && name == kw::Underscore;
+ let current_mod = cx.tcx.parent_module_from_def_id(import.def_id);
+ let parent_mod = cx.tcx.parent_module_from_def_id(current_mod);
if pub_underscore {
if let Some(ref inline) = inline_attr {
// forcefully don't inline if this is not public or if the
// #[doc(no_inline)] attribute is present.
// Don't inline doc(hidden) imports so they can be stripped at a later stage.
- let mut denied = !(import.vis.node.is_pub()
- || (cx.render_options.document_private && import.vis.node.is_pub_restricted()))
+ let mut denied = !(visibility.is_public()
+ || (cx.render_options.document_private
+ && visibility.is_accessible_from(parent_mod.to_def_id(), cx.tcx)))
|| pub_underscore
|| attrs.iter().any(|a| {
a.has_name(sym::doc)
let kind = match item.kind {
hir::ForeignItemKind::Fn(decl, names, ref generics) => {
let abi = cx.tcx.hir().get_foreign_abi(item.hir_id());
- let (generics, decl) = enter_impl_trait(cx, |cx| {
- (generics.clean(cx), (&*decl, &names[..]).clean(cx))
- });
+ let (generics, decl) =
+ enter_impl_trait(cx, |cx| (generics.clean(cx), (decl, names).clean(cx)));
ForeignFunctionItem(Function {
decl,
generics,
as_keyword(Res::Def(DefKind::Mod, id.def_id.to_def_id()))
}
hir::ItemKind::Use(path, hir::UseKind::Single)
- if item.vis.node.is_pub() =>
+ if tcx.visibility(id.def_id).is_public() =>
{
as_keyword(path.res.expect_non_local())
.map(|(_, prim)| (id.def_id.to_def_id(), prim))
as_primitive(Res::Def(DefKind::Mod, id.def_id.to_def_id()))
}
hir::ItemKind::Use(path, hir::UseKind::Single)
- if item.vis.node.is_pub() =>
+ if tcx.visibility(id.def_id).is_public() =>
{
as_primitive(path.res.expect_non_local()).map(|(_, prim)| {
// Pretend the primitive is local.
ItemKind::StrippedItem(k) => k,
_ => &*self.kind,
};
- if let ItemKind::ModuleItem(Module { span, .. }) | ItemKind::ImplItem(Impl { span, .. }) =
- kind
- {
- *span
- } else {
- self.def_id.as_def_id().map(|did| rustc_span(did, tcx)).unwrap_or_else(Span::dummy)
+ match kind {
+ ItemKind::ModuleItem(Module { span, .. }) => *span,
+ ItemKind::ImplItem(Impl { kind: ImplKind::Auto, .. }) => Span::dummy(),
+ ItemKind::ImplItem(Impl { kind: ImplKind::Blanket(_), .. }) => {
+ if let ItemId::Blanket { impl_id, .. } = self.def_id {
+ rustc_span(impl_id, tcx)
+ } else {
+ panic!("blanket impl item has non-blanket ID")
+ }
+ }
+ _ => {
+ self.def_id.as_def_id().map(|did| rustc_span(did, tcx)).unwrap_or_else(Span::dummy)
+ }
}
}
#[derive(Clone, Debug)]
crate struct Impl {
- crate span: Span,
crate unsafety: hir::Unsafety,
crate generics: Generics,
crate trait_: Option<Path>,
crate for_: Type,
crate items: Vec<Item>,
- crate negative_polarity: bool,
- crate synthetic: bool,
- crate blanket_impl: Option<Box<Type>>,
+ crate polarity: ty::ImplPolarity,
+ crate kind: ImplKind,
}
impl Impl {
}
}
+#[derive(Clone, Debug)]
+crate enum ImplKind {
+ Normal,
+ Auto,
+ Blanket(Box<Type>),
+}
+
+impl ImplKind {
+ crate fn is_auto(&self) -> bool {
+ matches!(self, ImplKind::Auto)
+ }
+
+ crate fn is_blanket(&self) -> bool {
+ matches!(self, ImplKind::Blanket(_))
+ }
+
+ crate fn as_blanket_ty(&self) -> Option<&Type> {
+ match self {
+ ImplKind::Blanket(ty) => Some(ty),
+ _ => None,
+ }
+ }
+}
+
#[derive(Clone, Debug)]
crate struct Import {
crate kind: ImportKind,
}
}
}
+
+/// The type, lifetime, or constant that a private type alias's parameter should be
+/// replaced with when expanding a use of that type alias.
+///
+/// For example:
+///
+/// ```
+/// type PrivAlias<T> = Vec<T>;
+///
+/// pub fn public_fn() -> PrivAlias<i32> { vec![] }
+/// ```
+///
+/// `public_fn`'s docs will show it as returning `Vec<i32>`, since `PrivAlias` is private.
+/// [`SubstParam`] is used to record that `T` should be mapped to `i32`.
+crate enum SubstParam {
+ Type(Type),
+ Lifetime(Lifetime),
+ Constant(Constant),
+}
+
+impl SubstParam {
+ crate fn as_ty(&self) -> Option<&Type> {
+ if let Self::Type(ty) = self { Some(ty) } else { None }
+ }
+
+ crate fn as_lt(&self) -> Option<&Lifetime> {
+ if let Self::Lifetime(lt) = self { Some(lt) } else { None }
+ }
+}
| Res::NonMacroAttr(_)
| Res::Err => return res.def_id(),
Res::Def(
- TyParam | ConstParam | Ctor(..) | ExternCrate | Use | ForeignMod | AnonConst | OpaqueTy
- | Field | LifetimeParam | GlobalAsm | Impl | Closure | Generator,
+ TyParam | ConstParam | Ctor(..) | ExternCrate | Use | ForeignMod | AnonConst
+ | InlineConst | OpaqueTy | Field | LifetimeParam | GlobalAsm | Impl | Closure
+ | Generator,
id,
) => return id,
};
use rustc_middle::middle::privacy::AccessLevels;
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
use rustc_resolve as resolve;
+use rustc_resolve::Namespace::TypeNS;
use rustc_session::config::{self, CrateType, ErrorOutputType};
use rustc_session::lint;
use rustc_session::DiagnosticOutput;
use rustc_session::Session;
+use rustc_span::def_id::CRATE_DEF_INDEX;
use rustc_span::source_map;
use rustc_span::symbol::sym;
-use rustc_span::Span;
+use rustc_span::{Span, DUMMY_SP};
use std::cell::RefCell;
use std::lazy::SyncLazy;
/// Used while populating `external_traits` to ensure we don't process the same trait twice at
/// the same time.
crate active_extern_traits: FxHashSet<DefId>,
- // The current set of type and lifetime substitutions,
+ // The current set of parameter substitutions,
// for expanding type aliases at the HIR level:
- /// Table `DefId` of type parameter -> substituted type
- crate ty_substs: FxHashMap<DefId, clean::Type>,
- /// Table `DefId` of lifetime parameter -> substituted lifetime
- crate lt_substs: FxHashMap<DefId, clean::Lifetime>,
- /// Table `DefId` of const parameter -> substituted const
- crate ct_substs: FxHashMap<DefId, clean::Constant>,
+ /// Table `DefId` of type, lifetime, or const parameter -> substituted type, lifetime, or const
+ crate substs: FxHashMap<DefId, clean::SubstParam>,
/// Table synthetic type parameter for `impl Trait` in argument position -> bounds
crate impl_trait_bounds: FxHashMap<ImplTraitParam, Vec<clean::GenericBound>>,
/// Auto-trait or blanket impls processed so far, as `(self_ty, trait_def_id)`.
/// Call the closure with the given parameters set as
/// the substitutions for a type alias' RHS.
- crate fn enter_alias<F, R>(
- &mut self,
- ty_substs: FxHashMap<DefId, clean::Type>,
- lt_substs: FxHashMap<DefId, clean::Lifetime>,
- ct_substs: FxHashMap<DefId, clean::Constant>,
- f: F,
- ) -> R
+ crate fn enter_alias<F, R>(&mut self, substs: FxHashMap<DefId, clean::SubstParam>, f: F) -> R
where
F: FnOnce(&mut Self) -> R,
{
- let (old_tys, old_lts, old_cts) = (
- mem::replace(&mut self.ty_substs, ty_substs),
- mem::replace(&mut self.lt_substs, lt_substs),
- mem::replace(&mut self.ct_substs, ct_substs),
- );
+ let old_substs = mem::replace(&mut self.substs, substs);
let r = f(self);
- self.ty_substs = old_tys;
- self.lt_substs = old_lts;
- self.ct_substs = old_cts;
+ self.substs = old_substs;
r
}
// Closures' tables come from their outermost function,
// as they are part of the same "inference environment".
// This avoids emitting errors for the parent twice (see similar code in `typeck_with_fallback`)
- let outer_def_id = tcx.closure_base_def_id(def_id.to_def_id()).expect_local();
- if outer_def_id != def_id {
- return tcx.typeck(outer_def_id);
+ let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
+ if typeck_root_def_id != def_id {
+ return tcx.typeck(typeck_root_def_id);
}
let hir = tcx.hir();
}
crate fn create_resolver<'a>(
+ externs: config::Externs,
queries: &Queries<'a>,
sess: &Session,
) -> Rc<RefCell<interface::BoxedResolver>> {
let (krate, resolver, _) = &*abort_on_err(queries.expansion(), sess).peek();
let resolver = resolver.clone();
- crate::passes::collect_intra_doc_links::load_intra_link_crates(resolver, krate)
+ let resolver = crate::passes::collect_intra_doc_links::load_intra_link_crates(resolver, krate);
+
+ // FIXME: somehow rustdoc is still missing crates even though we loaded all
+ // the known necessary crates. Load them all unconditionally until we find a way to fix this.
+ // DO NOT REMOVE THIS without first testing on the reproducer in
+ // https://github.com/jyn514/objr/commit/edcee7b8124abf0e4c63873e8422ff81beb11ebb
+ let extern_names: Vec<String> = externs
+ .iter()
+ .filter(|(_, entry)| entry.add_prelude)
+ .map(|(name, _)| name)
+ .cloned()
+ .collect();
+ resolver.borrow_mut().access(|resolver| {
+ sess.time("load_extern_crates", || {
+ for extern_name in &extern_names {
+ debug!("loading extern crate {}", extern_name);
+ if let Err(()) = resolver
+ .resolve_str_path_error(
+ DUMMY_SP,
+ extern_name,
+ TypeNS,
+ LocalDefId { local_def_index: CRATE_DEF_INDEX }.to_def_id(),
+ ) {
+ warn!("unable to resolve external crate {} (do you have an unused `--extern` crate?)", extern_name)
+ }
+ }
+ });
+ });
+
+ resolver
}
crate fn run_global_ctxt(
param_env: ParamEnv::empty(),
external_traits: Default::default(),
active_extern_traits: Default::default(),
- ty_substs: Default::default(),
- lt_substs: Default::default(),
- ct_substs: Default::default(),
+ substs: Default::default(),
impl_trait_bounds: Default::default(),
generated_synthetics: Default::default(),
auto_traits: tcx
};
if run {
debug!("running pass {}", p.pass.name);
- krate = ctxt.tcx.sess.time(p.pass.name, || (p.pass.run)(krate, &mut ctxt));
+ krate = tcx.sess.time(p.pass.name, || (p.pass.run)(krate, &mut ctxt));
}
}
- ctxt.sess().abort_if_errors();
+ if tcx.sess.diagnostic().has_errors_or_lint_errors() {
+ rustc_errors::FatalError.raise();
+ }
let render_options = ctxt.render_options;
let mut cache = ctxt.cache;
use rustc_ast as ast;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::Lrc;
-use rustc_errors::{ColorConfig, ErrorReported};
+use rustc_errors::{ColorConfig, ErrorReported, FatalError};
use rustc_hir as hir;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_hir::intravisit;
collector
});
- compiler.session().abort_if_errors();
+ if compiler.session().diagnostic().has_errors_or_lint_errors() {
+ FatalError.raise();
+ }
let unused_extern_reports = collector.unused_extern_reports.clone();
let compiling_test_count = collector.compiling_test_count.load(Ordering::SeqCst);
// Collect all the implementors of traits.
if let clean::ImplItem(ref i) = *item.kind {
if let Some(trait_) = &i.trait_ {
- if i.blanket_impl.is_none() {
+ if !i.kind.is_blanket() {
self.cache
.implementors
.entry(trait_.def_id())
| DefKind::Use
| DefKind::ForeignMod
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::OpaqueTy
| DefKind::Field
| DefKind::LifetimeParam
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
+use rustc_middle::ty;
use rustc_middle::ty::TyCtxt;
use rustc_span::def_id::CRATE_DEF_INDEX;
use rustc_target::spec::abi::Abi;
}
if let Some(ref ty) = self.trait_ {
- if self.negative_polarity {
- write!(f, "!")?;
+ match self.polarity {
+ ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => {}
+ ty::ImplPolarity::Negative => write!(f, "!")?,
}
fmt::Display::fmt(&ty.print(cx), f)?;
write!(f, " for ")?;
}
- if let Some(ref ty) = self.blanket_impl {
+ if let Some(ref ty) = self.kind.as_blanket_ty() {
fmt_type(ty, f, use_absolute, cx)?;
} else {
fmt_type(&self.for_, f, use_absolute, cx)?;
/// Builds the search index from the collected metadata
crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt<'tcx>) -> String {
let mut defid_to_pathid = FxHashMap::default();
- let mut crate_items = Vec::with_capacity(cache.search_index.len());
let mut crate_paths = vec![];
// Attach all orphan items to the type's definition if the type
// Reduce `DefId` in paths into smaller sequential numbers,
// and prune the paths that do not appear in the index.
- let mut lastpath = String::new();
+ let mut lastpath = "";
let mut lastpathid = 0usize;
- for item in search_index {
- item.parent_idx = item.parent.and_then(|defid| match defid_to_pathid.entry(defid) {
- Entry::Occupied(entry) => Some(*entry.get()),
- Entry::Vacant(entry) => {
- let pathid = lastpathid;
- entry.insert(pathid);
- lastpathid += 1;
+ let crate_items: Vec<&IndexItem> = search_index
+ .iter_mut()
+ .map(|item| {
+ item.parent_idx = item.parent.and_then(|defid| match defid_to_pathid.entry(defid) {
+ Entry::Occupied(entry) => Some(*entry.get()),
+ Entry::Vacant(entry) => {
+ let pathid = lastpathid;
+ entry.insert(pathid);
+ lastpathid += 1;
- if let Some(&(ref fqp, short)) = paths.get(&defid) {
- crate_paths.push((short, fqp.last().unwrap().clone()));
- Some(pathid)
- } else {
- None
+ if let Some(&(ref fqp, short)) = paths.get(&defid) {
+ crate_paths.push((short, fqp.last().unwrap().clone()));
+ Some(pathid)
+ } else {
+ None
+ }
}
+ });
+
+ // Omit the parent path if it is same to that of the prior item.
+ if lastpath == &item.path {
+ item.path.clear();
+ } else {
+ lastpath = &item.path;
}
- });
- // Omit the parent path if it is same to that of the prior item.
- if lastpath == item.path {
- item.path.clear();
- } else {
- lastpath = item.path.clone();
- }
- crate_items.push(&*item);
- }
+ &*item
+ })
+ .collect();
struct CrateData<'a> {
doc: String,
/// The point of this function is to replace bounds with types.
///
/// i.e. `[T, U]` when you have the following bounds: `T: Display, U: Option<T>` will return
-/// `[Display, Option]` (we just returns the list of the types, we don't care about the
-/// wrapped types in here).
+/// `[Display, Option]`. If a type parameter has no trait bound, it is discarded.
+///
+/// Important note: It goes through generics recursively. So if you have
+/// `T: Option<Result<(), ()>>`, it'll go into `Option` and then into `Result`.
crate fn get_real_types<'tcx>(
generics: &Generics,
arg: &Type,
) {
let is_full_generic = ty.is_full_generic();
- if is_full_generic && generics.len() == 1 {
- // In this case, no need to go through an intermediate state if the generics
- // contains only one element.
- //
- // For example:
- //
- // fn foo<T: Display>(r: Option<T>) {}
- //
- // In this case, it would contain:
- //
- // ```
- // [{
- // name: "option",
- // generics: [{
- // name: "",
- // generics: [
- // name: "Display",
- // generics: []
- // }]
- // }]
- // }]
- // ```
- //
- // After removing the intermediate (unnecessary) full generic, it'll become:
- //
- // ```
- // [{
- // name: "option",
- // generics: [{
- // name: "Display",
- // generics: []
- // }]
- // }]
- // ```
- //
- // To be noted that it can work if there is ONLY ONE generic, otherwise we still
- // need to keep it as is!
- res.push(generics.pop().unwrap());
- return;
+ if is_full_generic {
+ if generics.is_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
+ // with an empty type with an empty name. Let's just discard it.
+ return;
+ } else if generics.len() == 1 {
+ // In this case, no need to go through an intermediate state if the type parameter
+ // contains only one trait bound.
+ //
+ // For example:
+ //
+ // `fn foo<T: Display>(r: Option<T>) {}`
+ //
+ // In this case, it would contain:
+ //
+ // ```
+ // [{
+ // name: "option",
+ // generics: [{
+ // name: "",
+ // generics: [
+ // name: "Display",
+ // generics: []
+ // }]
+ // }]
+ // }]
+ // ```
+ //
+ // After removing the intermediate (unnecessary) type parameter, it'll become:
+ //
+ // ```
+ // [{
+ // name: "option",
+ // generics: [{
+ // name: "Display",
+ // generics: []
+ // }]
+ // }]
+ // ```
+ //
+ // To be noted that it can work if there is ONLY ONE trait bound, otherwise we still
+ // need to keep it as is!
+ res.push(generics.pop().unwrap());
+ return;
+ }
}
let mut index_ty = get_index_type(&ty, generics);
if index_ty.name.as_ref().map(|s| s.is_empty()).unwrap_or(true) {
return;
}
+ // If this argument is a type parameter and not a trait bound or a type, we need to look
+ // for its bounds.
if let Type::Generic(arg_s) = *arg {
+ // First we check if the bounds are in a `where` predicate...
if let Some(where_pred) = generics.where_predicates.iter().find(|g| match g {
WherePredicate::BoundPredicate { ty, .. } => {
ty.def_id_no_primitives() == arg.def_id_no_primitives()
}
insert_ty(res, tcx, arg.clone(), ty_generics);
}
+ // Otherwise we check if the trait bounds are "inlined" like `T: Option<u32>`...
if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) {
let mut ty_generics = Vec::new();
for bound in bound.get_bounds().unwrap_or(&[]) {
insert_ty(res, tcx, arg.clone(), ty_generics);
}
} 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.
+ //
+ // So in here, we can add it directly and look for its own type parameters (so for `Option`,
+ // we will look for them but not for `T`).
let mut ty_generics = Vec::new();
if let Some(arg_generics) = arg.generics() {
for gen in arg_generics.iter() {
mod templates;
mod write_shared;
-crate use context::*;
-crate use span_map::{collect_spans_and_sources, LinkFromSrc};
+crate use self::context::*;
+crate use self::span_map::{collect_spans_and_sources, LinkFromSrc};
use std::collections::VecDeque;
use std::default::Default;
use rustc_hir::def_id::DefId;
use rustc_hir::Mutability;
use rustc_middle::middle::stability;
+use rustc_middle::ty;
use rustc_middle::ty::TyCtxt;
use rustc_span::{
symbol::{kw, sym, Symbol},
}
let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) =
- traits.iter().partition(|t| t.inner_impl().synthetic);
+ traits.iter().partition(|t| t.inner_impl().kind.is_auto());
let (blanket_impl, concrete): (Vec<&&Impl>, _) =
- concrete.into_iter().partition(|t| t.inner_impl().blanket_impl.is_some());
+ concrete.into_iter().partition(|t| t.inner_impl().kind.is_blanket());
let mut impls = Buffer::empty_from(w);
render_impls(cx, &mut impls, &concrete, containing_item);
let i_display = format!("{:#}", i.print(cx));
let out = Escape(&i_display);
let encoded = small_url_encode(format!("{:#}", i.print(cx)));
- let generated = format!(
- "<a href=\"#impl-{}\">{}{}</a>",
- encoded,
- if it.inner_impl().negative_polarity { "!" } else { "" },
- out
- );
+ let prefix = match it.inner_impl().polarity {
+ ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => "",
+ ty::ImplPolarity::Negative => "!",
+ };
+ let generated =
+ format!("<a href=\"#impl-{}\">{}{}</a>", encoded, prefix, out);
if links.insert(generated.clone()) { Some(generated) } else { None }
} else {
None
};
let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) =
- v.iter().partition::<Vec<_>, _>(|i| i.inner_impl().synthetic);
- let (blanket_impl, concrete): (Vec<&Impl>, Vec<&Impl>) = concrete
- .into_iter()
- .partition::<Vec<_>, _>(|i| i.inner_impl().blanket_impl.is_some());
+ v.iter().partition::<Vec<_>, _>(|i| i.inner_impl().kind.is_auto());
+ let (blanket_impl, concrete): (Vec<&Impl>, Vec<&Impl>) =
+ concrete.into_iter().partition::<Vec<_>, _>(|i| i.inner_impl().kind.is_blanket());
let concrete_format = format_impls(concrete);
let synthetic_format = format_impls(synthetic);
});
let (mut synthetic, mut concrete): (Vec<&&Impl>, Vec<&&Impl>) =
- local.iter().partition(|i| i.inner_impl().synthetic);
+ local.iter().partition(|i| i.inner_impl().kind.is_auto());
synthetic.sort_by(|a, b| compare_impl(a, b, cx));
concrete.sort_by(|a, b| compare_impl(a, b, cx));
} else {
Some(Implementor {
text: imp.inner_impl().print(false, cx).to_string(),
- synthetic: imp.inner_impl().synthetic,
+ synthetic: imp.inner_impl().kind.is_auto(),
types: collect_paths_for_type(imp.inner_impl().for_.clone(), cache),
})
}
use rustc_ast::ast;
use rustc_hir::{def::CtorKind, def_id::DefId};
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{self, TyCtxt};
use rustc_span::def_id::CRATE_DEF_INDEX;
use rustc_span::Pos;
impl FromWithTcx<clean::Impl> for Impl {
fn from_tcx(impl_: clean::Impl, tcx: TyCtxt<'_>) -> Self {
let provided_trait_methods = impl_.provided_trait_methods(tcx);
- let clean::Impl {
- unsafety,
- generics,
- trait_,
- for_,
- items,
- negative_polarity,
- synthetic,
- blanket_impl,
- span: _span,
- } = impl_;
+ let clean::Impl { unsafety, generics, trait_, for_, items, polarity, kind } = impl_;
// FIXME: should `trait_` be a clean::Path equivalent in JSON?
let trait_ = trait_.map(|path| {
let did = path.def_id();
clean::ResolvedPath { path, did }.into_tcx(tcx)
});
+ // FIXME: use something like ImplKind in JSON?
+ let (synthetic, blanket_impl) = match kind {
+ clean::ImplKind::Normal => (false, None),
+ clean::ImplKind::Auto => (true, None),
+ clean::ImplKind::Blanket(ty) => (false, Some(*ty)),
+ };
+ let negative_polarity = match polarity {
+ ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => false,
+ ty::ImplPolarity::Negative => true,
+ };
Impl {
is_unsafe: unsafety == rustc_hir::Unsafety::Unsafe,
generics: generics.into_tcx(tcx),
items: ids(items),
negative: negative_polarity,
synthetic,
- blanket_impl: blanket_impl.map(|x| (*x).into_tcx(tcx)),
+ blanket_impl: blanket_impl.map(|x| x.into_tcx(tcx)),
}
}
}
#![feature(control_flow_enum)]
#![feature(box_syntax)]
#![feature(in_band_lifetimes)]
+#![feature(let_else)]
#![feature(nll)]
#![feature(test)]
#![feature(crate_visibility_modifier)]
let default_passes = options.default_passes;
let output_format = options.output_format;
// FIXME: fix this clone (especially render_options)
+ let externs = options.externs.clone();
let manual_passes = options.manual_passes.clone();
let render_options = options.render_options.clone();
let scrape_examples_options = options.scrape_examples_options.clone();
// We need to hold on to the complete resolver, so we cause everything to be
// cloned for the analysis passes to use. Suboptimal, but necessary in the
// current architecture.
- let resolver = core::create_resolver(queries, sess);
+ let resolver = core::create_resolver(externs, queries, sess);
- if sess.has_errors() {
+ if sess.diagnostic().has_errors_or_lint_errors() {
sess.fatal("Compilation failed, aborting rustdoc");
}
| Use
| LifetimeParam
| Ctor(_, _)
- | AnonConst => {
+ | AnonConst
+ | InlineConst => {
let note = assoc_item_not_allowed(res);
if let Some(span) = sp {
diag.span_label(span, ¬e);
+use ast::visit;
use rustc_ast as ast;
use rustc_hir::def::Namespace::TypeNS;
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
let mut loader = IntraLinkCrateLoader { current_mod: CRATE_DEF_ID, resolver };
// `walk_crate` doesn't visit the crate itself for some reason.
loader.load_links_in_attrs(&krate.attrs, krate.span);
- ast::visit::walk_crate(&mut loader, krate);
+ visit::walk_crate(&mut loader, krate);
loader.resolver
}
}
}
-impl ast::visit::Visitor<'_> for IntraLinkCrateLoader {
+impl visit::Visitor<'_> for IntraLinkCrateLoader {
+ fn visit_foreign_item(&mut self, item: &ast::ForeignItem) {
+ self.load_links_in_attrs(&item.attrs, item.span);
+ visit::walk_foreign_item(self, item)
+ }
+
fn visit_item(&mut self, item: &ast::Item) {
use rustc_ast_lowering::ResolverAstLowering;
let old_mod = mem::replace(&mut self.current_mod, new_mod);
self.load_links_in_attrs(&item.attrs, item.span);
- ast::visit::walk_item(self, item);
+ visit::walk_item(self, item);
self.current_mod = old_mod;
} else {
self.load_links_in_attrs(&item.attrs, item.span);
- ast::visit::walk_item(self, item);
+ visit::walk_item(self, item);
}
}
+
+ // NOTE: if doc-comments are ever allowed on function parameters, this will have to implement `visit_param` too.
+
+ fn visit_assoc_item(&mut self, item: &ast::AssocItem, ctxt: visit::AssocCtxt) {
+ self.load_links_in_attrs(&item.attrs, item.span);
+ visit::walk_assoc_item(self, item, ctxt)
+ }
+
+ fn visit_field_def(&mut self, field: &ast::FieldDef) {
+ self.load_links_in_attrs(&field.attrs, field.span);
+ visit::walk_field_def(self, field)
+ }
+
+ fn visit_variant(&mut self, v: &ast::Variant) {
+ self.load_links_in_attrs(&v.attrs, v.span);
+ visit::walk_variant(self, v)
+ }
}
}
new_items.retain(|it| {
- if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = *it.kind {
+ if let ImplItem(Impl { ref for_, ref trait_, ref kind, .. }) = *it.kind {
cleaner.keep_impl(
for_,
trait_.as_ref().map(|t| t.def_id()) == cx.tcx.lang_items().deref_trait(),
) || trait_.as_ref().map_or(false, |t| cleaner.keep_impl_with_def_id(t.def_id().into()))
- || blanket_impl.is_some()
+ || kind.is_blanket()
} else {
true
}
target_crates,
})),
(Some(_), false) | (None, true) => {
- diag.err(&format!("must use --scrape-examples-output-path and --scrape-examples-target-crate together"));
+ diag.err("must use --scrape-examples-output-path and --scrape-examples-target-crate together");
Err(1)
}
(None, false) => Ok(None),
use rustc_middle::middle::privacy::AccessLevel;
use rustc_middle::ty::TyCtxt;
use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
-use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Symbol};
use std::mem;
}
crate fn visit(mut self) -> Module<'tcx> {
- let span = self.cx.tcx.def_span(CRATE_DEF_ID);
let mut top_level_module = self.visit_mod_contents(
- &Spanned { span, node: hir::VisibilityKind::Public },
hir::CRATE_HIR_ID,
self.cx.tcx.hir().root_module(),
self.cx.tcx.crate_name(LOCAL_CRATE),
fn visit_mod_contents(
&mut self,
- vis: &hir::Visibility<'_>,
id: hir::HirId,
m: &'tcx hir::Mod<'tcx>,
name: Symbol,
) -> Module<'tcx> {
let mut om = Module::new(name, id, m.inner);
+ let def_id = self.cx.tcx.hir().local_def_id(id).to_def_id();
// Keep track of if there were any private modules in the path.
let orig_inside_public_path = self.inside_public_path;
- self.inside_public_path &= vis.node.is_pub();
+ self.inside_public_path &= self.cx.tcx.visibility(def_id).is_public();
for &i in m.item_ids {
let item = self.cx.tcx.hir().item(i);
self.visit_item(item, None, &mut om);
let name = renamed.unwrap_or(item.ident.name);
let def_id = item.def_id.to_def_id();
- let is_pub = item.vis.node.is_pub() || self.cx.tcx.has_attr(def_id, sym::macro_export);
+ let is_pub = self.cx.tcx.visibility(def_id).is_public();
if is_pub {
self.store_path(item.def_id.to_def_id());
}
}
hir::ItemKind::Mod(ref m) => {
- om.mods.push(self.visit_mod_contents(&item.vis, item.hir_id(), m, name));
+ om.mods.push(self.visit_mod_contents(item.hir_id(), m, name));
}
hir::ItemKind::Fn(..)
| hir::ItemKind::ExternCrate(..)
om: &mut Module<'tcx>,
) {
// If inlining we only want to include public functions.
- if !self.inlining || item.vis.node.is_pub() {
+ if !self.inlining || self.cx.tcx.visibility(item.def_id).is_public() {
om.foreigns.push((item, renamed));
}
}
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
use rustc_middle::middle::privacy::{AccessLevel, AccessLevels};
-use rustc_middle::ty::{TyCtxt, Visibility};
+use rustc_middle::ty::TyCtxt;
use rustc_span::symbol::sym;
use crate::clean::{AttributesExt, NestedAttributesExt};
for item in self.tcx.item_children(def_id).iter() {
if let Some(def_id) = item.res.opt_def_id() {
if self.tcx.def_key(def_id).parent.map_or(false, |d| d == def_id.index)
- || item.vis == Visibility::Public
+ || item.vis.is_public()
{
self.visit_item(item.res);
}
fn visit_item(&mut self, res: Res<!>) {
let def_id = res.def_id();
let vis = self.tcx.visibility(def_id);
- let inherited_item_level = if vis == Visibility::Public { self.prev_level } else { None };
+ let inherited_item_level = if vis.is_public() { self.prev_level } else { None };
let item_level = self.update(def_id, inherited_item_level);
-Subproject commit a7348ae0df3c71581dbe3d355fc0fb6ce6332dd0
+Subproject commit e048e97f5280e8a232a43ae134d395aeab67c2e8
// compile-flags: --target aarch64-unknown-linux-gnu
// needs-llvm-components: aarch64
-#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
+#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_sym)]
#![crate_type = "rlib"]
#![no_core]
#![allow(asm_sub_register, non_camel_case_types)]
// compile-flags: -C target-feature=+neon
// needs-llvm-components: arm
-#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
+#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_sym)]
#![crate_type = "rlib"]
#![no_core]
#![allow(asm_sub_register, non_camel_case_types)]
// compile-flags: --target bpfel-unknown-none -C target_feature=+alu32
// needs-llvm-components: bpf
-#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
+#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_sym, asm_experimental_arch)]
#![crate_type = "rlib"]
#![no_core]
#![allow(asm_sub_register, non_camel_case_types)]
// assembly-output: emit-asm
// compile-flags: -C llvm-args=--x86-asm-syntax=intel
-#![feature(asm, global_asm)]
+#![feature(global_asm, asm_const)]
#![crate_type = "rlib"]
// CHECK: mov eax, eax
// compile-flags: --target hexagon-unknown-linux-musl
// needs-llvm-components: hexagon
-#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
+#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_sym, asm_experimental_arch)]
#![crate_type = "rlib"]
#![no_core]
#![allow(asm_sub_register, non_camel_case_types)]
//[mips64] compile-flags: --target mips64-unknown-linux-gnuabi64
//[mips64] needs-llvm-components: mips
-#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
+#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_sym, asm_experimental_arch)]
#![crate_type = "rlib"]
#![no_core]
#![allow(asm_sub_register, non_camel_case_types)]
// compile-flags: --crate-type cdylib
// needs-llvm-components: nvptx
-#![feature(no_core, lang_items, rustc_attrs)]
+#![feature(no_core, lang_items, rustc_attrs, asm_sym, asm_experimental_arch)]
#![no_core]
#[rustc_builtin_macro]
//[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu
//[powerpc64] needs-llvm-components: powerpc
-#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
+#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_sym, asm_experimental_arch)]
#![crate_type = "rlib"]
#![no_core]
#![allow(asm_sub_register, non_camel_case_types)]
//[riscv32] needs-llvm-components: riscv
// compile-flags: -C target-feature=+d
-#![feature(no_core, lang_items, rustc_attrs)]
+#![feature(no_core, lang_items, rustc_attrs, asm_sym)]
#![crate_type = "rlib"]
#![no_core]
#![allow(asm_sub_register)]
//[s390x] compile-flags: --target s390x-unknown-linux-gnu
//[s390x] needs-llvm-components: systemz
-#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
+#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_sym, asm_experimental_arch)]
#![crate_type = "rlib"]
#![no_core]
#![allow(asm_sub_register, non_camel_case_types)]
// compile-flags: --crate-type cdylib
// needs-llvm-components: webassembly
-#![feature(no_core, lang_items, rustc_attrs)]
+#![feature(no_core, lang_items, rustc_attrs, asm_sym, asm_experimental_arch)]
#![no_core]
#[rustc_builtin_macro]
// compile-flags: -C llvm-args=--x86-asm-syntax=intel
// compile-flags: -C target-feature=+avx512bw
-#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
+#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_sym)]
#![crate_type = "rlib"]
#![no_core]
#![allow(asm_sub_register, non_camel_case_types)]
--- /dev/null
+// compile-flags: -O
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @array_clone
+#[no_mangle]
+pub fn array_clone(a: &[u8; 2]) -> [u8; 2] {
+ // CHECK-NOT: getelementptr
+ // CHECK-NOT: load i8
+ // CHECK-NOT: zext
+ // CHECK-NOT: shl
+ // CHECK: load i16
+ // CHECK-NEXT: ret i16
+ a.clone()
+}
//[powerpc64le] needs-llvm-components: powerpc
#![crate_type = "rlib"]
-#![feature(no_core, rustc_attrs, lang_items)]
+#![feature(no_core, rustc_attrs, lang_items, asm_experimental_arch)]
#![no_core]
#[lang = "sized"]
-// EMIT_MIR issue_78192.f.InstCombine.diff
+// compile-flags: -Zmir-opt-level=1 -Zinline-mir
pub fn f<T>(a: &T) -> *const T {
let b: &*const T = &(a as *const T);
*b
fn main() {
f(&2);
}
+
+// EMIT_MIR issue_78192.f.InstCombine.diff
{
::std::io::_print(::core::fmt::Arguments::new_v1(&["rust\n"],
&match () {
- () => [],
+ _args => [],
}));
};
}
as
())
{
- ()
+ _args
=>
([]
as
all:
touch $(TMPDIR)/lib.rmeta
$(AR) crus $(TMPDIR)/libfoo-ffffffff-1.0.rlib $(TMPDIR)/lib.rmeta
- $(RUSTC) foo.rs 2>&1 | $(CGREP) "can't find crate for"
+ $(RUSTC) foo.rs 2>&1 | $(CGREP) "found invalid metadata"
+# needs-llvm-components: x86 arm
+
-include ../tools.mk
all: default
--- /dev/null
+include ../../run-make-fulldeps/tools.mk
+
+DYLIB_NAME := $(shell echo | $(RUSTC) --crate-name foo --crate-type dylib --print file-names -)
+
+all:
+ echo >> $(TMPDIR)/$(DYLIB_NAME)
+ $(RUSTC) --crate-type lib --extern foo=$(TMPDIR)/$(DYLIB_NAME) bar.rs 2>&1 | $(CGREP) 'invalid metadata files for crate `foo`'
--- /dev/null
+extern crate foo;
--- /dev/null
+-include ../../run-make-fulldeps/tools.mk
+
+# Regression test for issue #10971
+# Running two invocations in parallel would overwrite each other's temp files.
+
+all:
+ touch $(TMPDIR)/lib.rs
+
+ $(RUSTC) --crate-type=lib -Z temps-dir=$(TMPDIR)/temp1 $(TMPDIR)/lib.rs & \
+ $(RUSTC) --crate-type=staticlib -Z temps-dir=$(TMPDIR)/temp2 $(TMPDIR)/lib.rs
--- /dev/null
+// intentionally empty
--- /dev/null
+// intentionally empty
--- /dev/null
+// intentionally empty
--- /dev/null
+// intentionally empty
--- /dev/null
+// check-pass
+// aux-crate:dep1=dep1.rs
+// aux-crate:dep2=dep2.rs
+// aux-crate:dep3=dep3.rs
+// aux-crate:dep4=dep4.rs
+#![deny(rustdoc::broken_intra_doc_links)]
+
+pub trait Trait {
+ /// [dep1]
+ type Item;
+}
+
+pub struct S {
+ /// [dep2]
+ pub x: usize,
+}
+
+extern "C" {
+ /// [dep3]
+ pub fn printf();
+}
+
+pub enum E {
+ /// [dep4]
+ A
+}
--- /dev/null
+#![crate_name = "foo"]
+#![no_std]
+
+// @has 'foo/fn.foo.html'
+// @has - '//*[@class="docblock"]' 'inc2 x'
+#[doc = include_str!("short-line.md")]
+pub fn foo() {}
//~^ WARNING lint name `test_lint` is deprecated and may not have an effect in the future
//~| WARNING lint name `test_lint` is deprecated and may not have an effect in the future
//~| WARNING lint name `test_lint` is deprecated and may not have an effect in the future
+//~| WARNING lint name `test_lint` is deprecated and may not have an effect in the future
#![deny(clippy_group)]
//~^ WARNING lint name `clippy_group` is deprecated and may not have an effect in the future
//~| WARNING lint name `clippy_group` is deprecated and may not have an effect in the future
//~| WARNING lint name `clippy_group` is deprecated and may not have an effect in the future
+//~| WARNING lint name `clippy_group` is deprecated and may not have an effect in the future
fn lintme() { } //~ ERROR item is named 'lintme'
//~^ WARNING lint name `test_group` is deprecated and may not have an effect in the future
//~| WARNING lint name `test_group` is deprecated and may not have an effect in the future
//~| WARNING lint name `test_group` is deprecated and may not have an effect in the future
+//~| WARNING lint name `test_group` is deprecated and may not have an effect in the future
#[deny(this_lint_does_not_exist)] //~ WARNING unknown lint: `this_lint_does_not_exist`
fn hello() {
fn lintmetoo() { }
= note: `#[warn(renamed_and_removed_lints)]` on by default
warning: lint name `clippy_group` is deprecated and may not have an effect in the future.
- --> $DIR/lint-tool-test.rs:13:9
+ --> $DIR/lint-tool-test.rs:14:9
|
LL | #![deny(clippy_group)]
| ^^^^^^^^^^^^ help: change it to: `clippy::group`
warning: lint name `test_group` is deprecated and may not have an effect in the future.
- --> $DIR/lint-tool-test.rs:29:9
+ --> $DIR/lint-tool-test.rs:31:9
|
LL | #[allow(test_group)]
| ^^^^^^^^^^ help: change it to: `clippy::test_group`
warning: unknown lint: `this_lint_does_not_exist`
- --> $DIR/lint-tool-test.rs:33:8
+ --> $DIR/lint-tool-test.rs:36:8
|
LL | #[deny(this_lint_does_not_exist)]
| ^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^ help: change it to: `clippy::test_lint`
warning: lint name `clippy_group` is deprecated and may not have an effect in the future.
- --> $DIR/lint-tool-test.rs:13:9
+ --> $DIR/lint-tool-test.rs:14:9
|
LL | #![deny(clippy_group)]
| ^^^^^^^^^^^^ help: change it to: `clippy::group`
warning: lint name `test_group` is deprecated and may not have an effect in the future.
- --> $DIR/lint-tool-test.rs:29:9
+ --> $DIR/lint-tool-test.rs:31:9
|
LL | #[allow(test_group)]
| ^^^^^^^^^^ help: change it to: `clippy::test_group`
| ^^^^^^^^^ help: change it to: `clippy::test_lint`
warning: lint name `clippy_group` is deprecated and may not have an effect in the future.
- --> $DIR/lint-tool-test.rs:13:9
+ --> $DIR/lint-tool-test.rs:14:9
|
LL | #![deny(clippy_group)]
| ^^^^^^^^^^^^ help: change it to: `clippy::group`
error: item is named 'lintme'
- --> $DIR/lint-tool-test.rs:18:1
+ --> $DIR/lint-tool-test.rs:20:1
|
LL | fn lintme() { }
| ^^^^^^^^^^^^^^^
|
note: the lint level is defined here
- --> $DIR/lint-tool-test.rs:13:9
+ --> $DIR/lint-tool-test.rs:14:9
|
LL | #![deny(clippy_group)]
| ^^^^^^^^^^^^
= note: `#[deny(clippy::test_lint)]` implied by `#[deny(clippy::group)]`
error: item is named 'lintmetoo'
- --> $DIR/lint-tool-test.rs:26:5
+ --> $DIR/lint-tool-test.rs:28:5
|
LL | fn lintmetoo() { }
| ^^^^^^^^^^^^^^^^^^
|
note: the lint level is defined here
- --> $DIR/lint-tool-test.rs:13:9
+ --> $DIR/lint-tool-test.rs:14:9
|
LL | #![deny(clippy_group)]
| ^^^^^^^^^^^^
= note: `#[deny(clippy::test_group)]` implied by `#[deny(clippy::group)]`
warning: lint name `test_group` is deprecated and may not have an effect in the future.
- --> $DIR/lint-tool-test.rs:29:9
+ --> $DIR/lint-tool-test.rs:31:9
|
LL | #[allow(test_group)]
| ^^^^^^^^^^ help: change it to: `clippy::test_group`
-error: aborting due to 2 previous errors; 11 warnings emitted
+warning: lint name `test_lint` is deprecated and may not have an effect in the future.
+ --> $DIR/lint-tool-test.rs:9:23
+ |
+LL | #![cfg_attr(foo, warn(test_lint))]
+ | ^^^^^^^^^ help: change it to: `clippy::test_lint`
+
+warning: lint name `clippy_group` is deprecated and may not have an effect in the future.
+ --> $DIR/lint-tool-test.rs:14:9
+ |
+LL | #![deny(clippy_group)]
+ | ^^^^^^^^^^^^ help: change it to: `clippy::group`
+
+warning: lint name `test_group` is deprecated and may not have an effect in the future.
+ --> $DIR/lint-tool-test.rs:31:9
+ |
+LL | #[allow(test_group)]
+ | ^^^^^^^^^^ help: change it to: `clippy::test_group`
+
+error: aborting due to 2 previous errors; 14 warnings emitted
+++ /dev/null
-// run-pass
-
-struct X {
- x: isize
-}
-
-fn f1(a: &mut X, b: &mut isize, c: isize) -> isize {
- let r = a.x + *b + c;
- a.x = 0;
- *b = 10;
- return r;
-}
-
-fn f2<F>(a: isize, f: F) -> isize where F: FnOnce(isize) { f(1); return a; }
-
-pub fn main() {
- let mut a = X {x: 1};
- let mut b = 2;
- let c = 3;
- assert_eq!(f1(&mut a, &mut b, c), 6);
- assert_eq!(a.x, 0);
- assert_eq!(b, 10);
- assert_eq!(f2(a.x, |_| a.x = 50), 0);
- assert_eq!(a.x, 50);
-}
--- /dev/null
+// run-pass
+// pretty-expanded FIXME #23616
+
+pub fn main() {
+ let _x: &mut [isize] = &mut [ 1, 2, 3 ];
+}
// only-aarch64
// compile-flags: -C target-feature=+fp
-#![feature(asm)]
+#![feature(asm, asm_const, asm_sym)]
fn main() {
let mut foo = 0;
// revisions: mirunsafeck thirunsafeck
// [thirunsafeck]compile-flags: -Z thir-unsafeck
-#![feature(asm, global_asm)]
+#![feature(asm, global_asm, asm_const)]
fn const_generic<const X: usize>() -> usize {
unsafe {
// only-aarch64
-#![feature(asm, global_asm)]
+#![feature(asm, global_asm, asm_const)]
fn main() {
let mut foo = 0;
asm!("", clobber_abi(foo));
//~^ ERROR expected string literal
asm!("", clobber_abi("C" foo));
- //~^ ERROR expected `)`, found `foo`
+ //~^ ERROR expected one of `)` or `,`, found `foo`
asm!("", clobber_abi("C", foo));
- //~^ ERROR expected `)`, found `,`
+ //~^ ERROR expected string literal
asm!("{}", clobber_abi("C"), const foo);
//~^ ERROR arguments are not allowed after clobber_abi
//~^^ ERROR attempt to use a non-constant value in a constant
//~^ ERROR clobber_abi is not allowed after options
asm!("{}", options(), clobber_abi("C"), const foo);
//~^ ERROR clobber_abi is not allowed after options
- asm!("", clobber_abi("C"), clobber_abi("C"));
- //~^ ERROR clobber_abi specified multiple times
asm!("{a}", a = const foo, a = const bar);
//~^ ERROR duplicate argument named `a`
//~^^ ERROR argument never used
global_asm!("", clobber_abi(FOO));
//~^ ERROR expected string literal
global_asm!("", clobber_abi("C" FOO));
-//~^ ERROR expected `)`, found `FOO`
+//~^ ERROR expected one of `)` or `,`, found `FOO`
global_asm!("", clobber_abi("C", FOO));
-//~^ ERROR expected `)`, found `,`
+//~^ ERROR expected string literal
global_asm!("{}", clobber_abi("C"), const FOO);
//~^ ERROR arguments are not allowed after clobber_abi
//~^^ ERROR `clobber_abi` cannot be used with `global_asm!`
//~^ ERROR clobber_abi is not allowed after options
global_asm!("{}", options(), clobber_abi("C"), const FOO);
//~^ ERROR clobber_abi is not allowed after options
-global_asm!("", clobber_abi("C"), clobber_abi("C"));
-//~^ ERROR clobber_abi specified multiple times
global_asm!("{a}", a = const FOO, a = const BAR);
//~^ ERROR duplicate argument named `a`
//~^^ ERROR argument never used
LL | asm!("", clobber_abi(foo));
| ^^^ not a string literal
-error: expected `)`, found `foo`
+error: expected one of `)` or `,`, found `foo`
--> $DIR/parse-error.rs:42:34
|
LL | asm!("", clobber_abi("C" foo));
- | ^^^ expected `)`
+ | ^^^ expected one of `)` or `,`
-error: expected `)`, found `,`
- --> $DIR/parse-error.rs:44:33
+error: expected string literal
+ --> $DIR/parse-error.rs:44:35
|
LL | asm!("", clobber_abi("C", foo));
- | ^ expected `)`
+ | ^^^ not a string literal
error: arguments are not allowed after clobber_abi
--> $DIR/parse-error.rs:46:38
| |
| options
-error: clobber_abi specified multiple times
- --> $DIR/parse-error.rs:53:36
- |
-LL | asm!("", clobber_abi("C"), clobber_abi("C"));
- | ---------------- ^^^^^^^^^^^^^^^^
- | |
- | clobber_abi previously specified here
-
error: duplicate argument named `a`
- --> $DIR/parse-error.rs:55:36
+ --> $DIR/parse-error.rs:53:36
|
LL | asm!("{a}", a = const foo, a = const bar);
| ------------- ^^^^^^^^^^^^^ duplicate argument
| previously here
error: argument never used
- --> $DIR/parse-error.rs:55:36
+ --> $DIR/parse-error.rs:53:36
|
LL | asm!("{a}", a = const foo, a = const bar);
| ^^^^^^^^^^^^^ argument never used
= help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
error: explicit register arguments cannot have names
- --> $DIR/parse-error.rs:60:18
+ --> $DIR/parse-error.rs:58:18
|
LL | asm!("", a = in("x0") foo);
| ^^^^^^^^^^^^^^^^
error: named arguments cannot follow explicit register arguments
- --> $DIR/parse-error.rs:62:35
+ --> $DIR/parse-error.rs:60:35
|
LL | asm!("{a}", in("x0") foo, a = const bar);
| ------------ ^^^^^^^^^^^^^ named argument
| explicit register argument
error: named arguments cannot follow explicit register arguments
- --> $DIR/parse-error.rs:65:35
+ --> $DIR/parse-error.rs:63:35
|
LL | asm!("{a}", in("x0") foo, a = const bar);
| ------------ ^^^^^^^^^^^^^ named argument
| explicit register argument
error: positional arguments cannot follow named arguments or explicit register arguments
- --> $DIR/parse-error.rs:68:35
+ --> $DIR/parse-error.rs:66:35
|
LL | asm!("{1}", in("x0") foo, const bar);
| ------------ ^^^^^^^^^ positional argument
| explicit register argument
error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `""`
- --> $DIR/parse-error.rs:71:29
+ --> $DIR/parse-error.rs:69:29
|
LL | asm!("", options(), "");
| ^^ expected one of 9 possible tokens
error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `"{}"`
- --> $DIR/parse-error.rs:73:33
+ --> $DIR/parse-error.rs:71:33
|
LL | asm!("{}", in(reg) foo, "{}", out(reg) foo);
| ^^^^ expected one of 9 possible tokens
error: asm template must be a string literal
- --> $DIR/parse-error.rs:75:14
+ --> $DIR/parse-error.rs:73:14
|
LL | asm!(format!("{{{}}}", 0), in(reg) foo);
| ^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
error: asm template must be a string literal
- --> $DIR/parse-error.rs:77:21
+ --> $DIR/parse-error.rs:75:21
|
LL | asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
| ^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
error: _ cannot be used for input operands
- --> $DIR/parse-error.rs:79:28
+ --> $DIR/parse-error.rs:77:28
|
LL | asm!("{}", in(reg) _);
| ^
error: _ cannot be used for input operands
- --> $DIR/parse-error.rs:81:31
+ --> $DIR/parse-error.rs:79:31
|
LL | asm!("{}", inout(reg) _);
| ^
error: _ cannot be used for input operands
- --> $DIR/parse-error.rs:83:35
+ --> $DIR/parse-error.rs:81:35
|
LL | asm!("{}", inlateout(reg) _);
| ^
error: requires at least a template string argument
- --> $DIR/parse-error.rs:90:1
+ --> $DIR/parse-error.rs:88:1
|
LL | global_asm!();
| ^^^^^^^^^^^^^
error: asm template must be a string literal
- --> $DIR/parse-error.rs:92:13
+ --> $DIR/parse-error.rs:90:13
|
LL | global_asm!(FOO);
| ^^^
error: expected token: `,`
- --> $DIR/parse-error.rs:94:18
+ --> $DIR/parse-error.rs:92:18
|
LL | global_asm!("{}" FOO);
| ^^^ expected `,`
error: expected operand, options, or additional template string
- --> $DIR/parse-error.rs:96:19
+ --> $DIR/parse-error.rs:94:19
|
LL | global_asm!("{}", FOO);
| ^^^ expected operand, options, or additional template string
error: expected expression, found end of macro arguments
- --> $DIR/parse-error.rs:98:24
+ --> $DIR/parse-error.rs:96:24
|
LL | global_asm!("{}", const);
| ^ expected expression
error: expected one of `,`, `.`, `?`, or an operator, found `FOO`
- --> $DIR/parse-error.rs:100:30
+ --> $DIR/parse-error.rs:98:30
|
LL | global_asm!("{}", const(reg) FOO);
| ^^^ expected one of `,`, `.`, `?`, or an operator
error: expected one of `)`, `att_syntax`, or `raw`, found `FOO`
- --> $DIR/parse-error.rs:102:25
+ --> $DIR/parse-error.rs:100:25
|
LL | global_asm!("", options(FOO));
| ^^^ expected one of `)`, `att_syntax`, or `raw`
error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
- --> $DIR/parse-error.rs:104:25
+ --> $DIR/parse-error.rs:102:25
|
LL | global_asm!("", options(nomem FOO));
| ^^^^^ expected one of `)`, `att_syntax`, or `raw`
error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
- --> $DIR/parse-error.rs:106:25
+ --> $DIR/parse-error.rs:104:25
|
LL | global_asm!("", options(nomem, FOO));
| ^^^^^ expected one of `)`, `att_syntax`, or `raw`
error: arguments are not allowed after options
- --> $DIR/parse-error.rs:108:30
+ --> $DIR/parse-error.rs:106:30
|
LL | global_asm!("{}", options(), const FOO);
| --------- ^^^^^^^^^ argument
| previous options
error: expected string literal
- --> $DIR/parse-error.rs:110:29
+ --> $DIR/parse-error.rs:108:29
|
LL | global_asm!("", clobber_abi(FOO));
| ^^^ not a string literal
-error: expected `)`, found `FOO`
- --> $DIR/parse-error.rs:112:33
+error: expected one of `)` or `,`, found `FOO`
+ --> $DIR/parse-error.rs:110:33
|
LL | global_asm!("", clobber_abi("C" FOO));
- | ^^^ expected `)`
+ | ^^^ expected one of `)` or `,`
-error: expected `)`, found `,`
- --> $DIR/parse-error.rs:114:32
+error: expected string literal
+ --> $DIR/parse-error.rs:112:34
|
LL | global_asm!("", clobber_abi("C", FOO));
- | ^ expected `)`
+ | ^^^ not a string literal
error: arguments are not allowed after clobber_abi
- --> $DIR/parse-error.rs:116:37
+ --> $DIR/parse-error.rs:114:37
|
LL | global_asm!("{}", clobber_abi("C"), const FOO);
| ---------------- ^^^^^^^^^ argument
| clobber_abi
error: `clobber_abi` cannot be used with `global_asm!`
- --> $DIR/parse-error.rs:116:19
+ --> $DIR/parse-error.rs:114:19
|
LL | global_asm!("{}", clobber_abi("C"), const FOO);
| ^^^^^^^^^^^^^^^^
error: clobber_abi is not allowed after options
- --> $DIR/parse-error.rs:119:28
+ --> $DIR/parse-error.rs:117:28
|
LL | global_asm!("", options(), clobber_abi("C"));
| --------- ^^^^^^^^^^^^^^^^
| options
error: clobber_abi is not allowed after options
- --> $DIR/parse-error.rs:121:30
+ --> $DIR/parse-error.rs:119:30
|
LL | global_asm!("{}", options(), clobber_abi("C"), const FOO);
| --------- ^^^^^^^^^^^^^^^^
| |
| options
-error: clobber_abi specified multiple times
- --> $DIR/parse-error.rs:123:35
- |
-LL | global_asm!("", clobber_abi("C"), clobber_abi("C"));
- | ---------------- ^^^^^^^^^^^^^^^^
- | |
- | clobber_abi previously specified here
-
error: duplicate argument named `a`
- --> $DIR/parse-error.rs:125:35
+ --> $DIR/parse-error.rs:121:35
|
LL | global_asm!("{a}", a = const FOO, a = const BAR);
| ------------- ^^^^^^^^^^^^^ duplicate argument
| previously here
error: argument never used
- --> $DIR/parse-error.rs:125:35
+ --> $DIR/parse-error.rs:121:35
|
LL | global_asm!("{a}", a = const FOO, a = const BAR);
| ^^^^^^^^^^^^^ argument never used
= help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
error: expected one of `clobber_abi`, `const`, or `options`, found `""`
- --> $DIR/parse-error.rs:128:28
+ --> $DIR/parse-error.rs:124:28
|
LL | global_asm!("", options(), "");
| ^^ expected one of `clobber_abi`, `const`, or `options`
error: expected one of `clobber_abi`, `const`, or `options`, found `"{}"`
- --> $DIR/parse-error.rs:130:30
+ --> $DIR/parse-error.rs:126:30
|
LL | global_asm!("{}", const FOO, "{}", const FOO);
| ^^^^ expected one of `clobber_abi`, `const`, or `options`
error: asm template must be a string literal
- --> $DIR/parse-error.rs:132:13
+ --> $DIR/parse-error.rs:128:13
|
LL | global_asm!(format!("{{{}}}", 0), const FOO);
| ^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
error: asm template must be a string literal
- --> $DIR/parse-error.rs:134:20
+ --> $DIR/parse-error.rs:130:20
|
LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
| ^^^^^^^^^^^^^^^^^^^^
| ^^^ non-constant value
error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/parse-error.rs:55:31
+ --> $DIR/parse-error.rs:53:31
|
LL | let mut foo = 0;
| ---------- help: consider using `const` instead of `let`: `const foo`
| ^^^ non-constant value
error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/parse-error.rs:55:46
+ --> $DIR/parse-error.rs:53:46
|
LL | let mut bar = 0;
| ---------- help: consider using `const` instead of `let`: `const bar`
| ^^^ non-constant value
error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/parse-error.rs:62:45
+ --> $DIR/parse-error.rs:60:45
|
LL | let mut bar = 0;
| ---------- help: consider using `const` instead of `let`: `const bar`
| ^^^ non-constant value
error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/parse-error.rs:65:45
+ --> $DIR/parse-error.rs:63:45
|
LL | let mut bar = 0;
| ---------- help: consider using `const` instead of `let`: `const bar`
| ^^^ non-constant value
error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/parse-error.rs:68:41
+ --> $DIR/parse-error.rs:66:41
|
LL | let mut bar = 0;
| ---------- help: consider using `const` instead of `let`: `const bar`
LL | asm!("{1}", in("x0") foo, const bar);
| ^^^ non-constant value
-error: aborting due to 66 previous errors
+error: aborting due to 64 previous errors
For more information about this error, try `rustc --explain E0435`.
// only-linux
// run-pass
-#![feature(asm, thread_local)]
+#![feature(asm, thread_local, asm_sym)]
extern "C" fn f1() -> i32 {
111
std::thread::spawn(|| {
assert_eq!(static_addr!(S1), &S1 as *const u32);
assert_eq!(static_tls_addr!(S2), &S2 as *const u32);
- }).join().unwrap();
+ })
+ .join()
+ .unwrap();
}
// only-aarch64
-#![feature(asm, repr_simd, never_type)]
+#![feature(asm, repr_simd, never_type, asm_sym)]
#[repr(simd)]
#[derive(Clone, Copy)]
// only-aarch64
// compile-flags: -C target-feature=+neon
-#![feature(asm, global_asm, repr_simd, stdsimd)]
+#![feature(asm, global_asm, repr_simd, stdsimd, asm_const)]
use std::arch::aarch64::float64x2_t;
#[repr(simd)]
#[derive(Copy, Clone)]
-struct Simd256bit(f64, f64,f64, f64);
+struct Simd256bit(f64, f64, f64, f64);
fn main() {
let f64x2: float64x2_t = unsafe { std::mem::transmute(0i128) };
asm!("{:b}", in(vreg) 0u64);
asm!("{:d}", in(vreg_low16) f64x2);
-
// Template modifier suggestions for sub-registers
asm!("{}", in(reg) 0u8);
warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:48:15
+ --> $DIR/type-check-3.rs:47:15
|
LL | asm!("{}", in(reg) 0u8);
| ^^ --- for this argument
= help: or use the `x` modifier to keep the default formatting of `x0`
warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:50:15
+ --> $DIR/type-check-3.rs:49:15
|
LL | asm!("{}", in(reg) 0u16);
| ^^ ---- for this argument
= help: or use the `x` modifier to keep the default formatting of `x0`
warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:52:15
+ --> $DIR/type-check-3.rs:51:15
|
LL | asm!("{}", in(reg) 0i32);
| ^^ ---- for this argument
= help: or use the `x` modifier to keep the default formatting of `x0`
warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:54:15
+ --> $DIR/type-check-3.rs:53:15
|
LL | asm!("{}", in(reg) 0f32);
| ^^ ---- for this argument
= help: or use the `x` modifier to keep the default formatting of `x0`
warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:57:15
+ --> $DIR/type-check-3.rs:56:15
|
LL | asm!("{}", in(vreg) 0i16);
| ^^ ---- for this argument
= help: or use the `v` modifier to keep the default formatting of `v0`
warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:59:15
+ --> $DIR/type-check-3.rs:58:15
|
LL | asm!("{}", in(vreg) 0f32);
| ^^ ---- for this argument
= help: or use the `v` modifier to keep the default formatting of `v0`
warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:61:15
+ --> $DIR/type-check-3.rs:60:15
|
LL | asm!("{}", in(vreg) 0f64);
| ^^ ---- for this argument
= help: or use the `v` modifier to keep the default formatting of `v0`
warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:63:15
+ --> $DIR/type-check-3.rs:62:15
|
LL | asm!("{}", in(vreg_low16) 0f64);
| ^^ ---- for this argument
= help: or use the `v` modifier to keep the default formatting of `v0`
warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:66:15
+ --> $DIR/type-check-3.rs:65:15
|
LL | asm!("{0} {0}", in(reg) 0i16);
| ^^^ ^^^ ---- for this argument
= help: or use the `x` modifier to keep the default formatting of `x0`
warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:68:15
+ --> $DIR/type-check-3.rs:67:15
|
LL | asm!("{0} {0:x}", in(reg) 0i16);
| ^^^ ---- for this argument
= help: or use the `x` modifier to keep the default formatting of `x0`
error: type `i128` cannot be used with this register class
- --> $DIR/type-check-3.rs:73:28
+ --> $DIR/type-check-3.rs:72:28
|
LL | asm!("{}", in(reg) 0i128);
| ^^^^^
= note: register class `reg` supports these types: i8, i16, i32, i64, f32, f64
error: type `float64x2_t` cannot be used with this register class
- --> $DIR/type-check-3.rs:75:28
+ --> $DIR/type-check-3.rs:74:28
|
LL | asm!("{}", in(reg) f64x2);
| ^^^^^
= note: register class `reg` supports these types: i8, i16, i32, i64, f32, f64
error: type `Simd256bit` cannot be used with this register class
- --> $DIR/type-check-3.rs:77:29
+ --> $DIR/type-check-3.rs:76:29
|
LL | asm!("{}", in(vreg) f64x4);
| ^^^^^
= note: register class `vreg` supports these types: i8, i16, i32, i64, f32, f64, i8x8, i16x4, i32x2, i64x1, f32x2, f64x1, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2
error: incompatible types for asm inout argument
- --> $DIR/type-check-3.rs:88:33
+ --> $DIR/type-check-3.rs:87:33
|
LL | asm!("{:x}", inout(reg) 0u32 => val_f32);
| ^^^^ ^^^^^^^ type `f32`
= note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size
error: incompatible types for asm inout argument
- --> $DIR/type-check-3.rs:90:33
+ --> $DIR/type-check-3.rs:89:33
|
LL | asm!("{:x}", inout(reg) 0u32 => val_ptr);
| ^^^^ ^^^^^^^ type `*mut u8`
= note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size
error: incompatible types for asm inout argument
- --> $DIR/type-check-3.rs:92:33
+ --> $DIR/type-check-3.rs:91:33
|
LL | asm!("{:x}", inout(reg) main => val_u32);
| ^^^^ ^^^^^^^ type `u32`
= note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size
error[E0013]: constants cannot refer to statics
- --> $DIR/type-check-3.rs:108:25
+ --> $DIR/type-check-3.rs:107:25
|
LL | global_asm!("{}", const S);
| ^
= help: consider extracting the value of the `static` to a `const`, and referring to that
error[E0013]: constants cannot refer to statics
- --> $DIR/type-check-3.rs:111:35
+ --> $DIR/type-check-3.rs:110:35
|
LL | global_asm!("{}", const const_foo(S));
| ^
= help: consider extracting the value of the `static` to a `const`, and referring to that
error[E0013]: constants cannot refer to statics
- --> $DIR/type-check-3.rs:114:35
+ --> $DIR/type-check-3.rs:113:35
|
LL | global_asm!("{}", const const_bar(S));
| ^
// [aarch64_thirunsafeck] needs-llvm-components: aarch64
// [aarch64_mirunsafeck] needs-llvm-components: aarch64
-#![feature(no_core, lang_items, rustc_attrs)]
+#![feature(no_core, lang_items, rustc_attrs, asm_const)]
#![no_core]
#[rustc_builtin_macro]
// as both unused and possibly-uninitialized.
// check-pass
+// needs-asm-support
#![feature(asm)]
#![warn(unused)]
warning: unused variable: `x`
- --> $DIR/issue-89305.rs:11:13
+ --> $DIR/issue-89305.rs:12:13
|
LL | let x: () = asm!("nop");
| ^ help: if this is intentional, prefix it with an underscore: `_x`
|
note: the lint level is defined here
- --> $DIR/issue-89305.rs:7:9
+ --> $DIR/issue-89305.rs:8:9
|
LL | #![warn(unused)]
| ^^^^^^
#![feature(llvm_asm)]
#![feature(naked_functions)]
#![feature(or_patterns)]
+#![feature(asm_const, asm_sym)]
#![crate_type = "lib"]
#![allow(deprecated)] // llvm_asm!
#[repr(C)]
-pub struct P { x: u8, y: u16 }
+pub struct P {
+ x: u8,
+ y: u16,
+}
#[naked]
pub unsafe extern "C" fn patterns(
}
#[naked]
-pub unsafe extern "Rust" fn rust_abi() {
+pub unsafe fn rust_abi() {
//~^ WARN Rust ABI is unsupported in naked functions
asm!("", options(noreturn));
}
#[naked]
pub extern "C" fn valid_a<T>() -> T {
- unsafe { asm!("", options(noreturn)); }
+ unsafe {
+ asm!("", options(noreturn));
+ }
}
#[naked]
pub extern "C" fn valid_b() {
- unsafe { { {
- asm!("", options(noreturn)); ; ; ;
- } ; } ; }
+ unsafe {
+ {
+ {
+ asm!("", options(noreturn));
+ };
+ };
+ }
}
#[naked]
error: asm with the `pure` option must have at least one output
- --> $DIR/naked-functions.rs:131:14
+ --> $DIR/naked-functions.rs:135:14
|
LL | asm!("", options(readonly, nostack), options(pure));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^
error: patterns not allowed in naked function parameters
- --> $DIR/naked-functions.rs:18:5
+ --> $DIR/naked-functions.rs:22:5
|
LL | mut a: u32,
| ^^^^^
error: patterns not allowed in naked function parameters
- --> $DIR/naked-functions.rs:20:5
+ --> $DIR/naked-functions.rs:24:5
|
LL | &b: &i32,
| ^^
error: patterns not allowed in naked function parameters
- --> $DIR/naked-functions.rs:22:6
+ --> $DIR/naked-functions.rs:26:6
|
LL | (None | Some(_)): Option<std::ptr::NonNull<u8>>,
| ^^^^^^^^^^^^^^
error: patterns not allowed in naked function parameters
- --> $DIR/naked-functions.rs:24:5
+ --> $DIR/naked-functions.rs:28:5
|
LL | P { x, y }: P,
| ^^^^^^^^^^
error: referencing function parameters is not allowed in naked functions
- --> $DIR/naked-functions.rs:34:5
+ --> $DIR/naked-functions.rs:38:5
|
LL | a + 1
| ^
= help: follow the calling convention in asm block to use parameters
warning: naked functions must contain a single asm block
- --> $DIR/naked-functions.rs:31:1
+ --> $DIR/naked-functions.rs:35:1
|
LL | / pub unsafe extern "C" fn inc(a: u32) -> u32 {
LL | |
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
error: referencing function parameters is not allowed in naked functions
- --> $DIR/naked-functions.rs:40:31
+ --> $DIR/naked-functions.rs:44:31
|
LL | asm!("/* {0} */", in(reg) a, options(noreturn));
| ^
= help: follow the calling convention in asm block to use parameters
warning: only `const` and `sym` operands are supported in naked functions
- --> $DIR/naked-functions.rs:40:23
+ --> $DIR/naked-functions.rs:44:23
|
LL | asm!("/* {0} */", in(reg) a, options(noreturn));
| ^^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions must contain a single asm block
- --> $DIR/naked-functions.rs:47:1
+ --> $DIR/naked-functions.rs:51:1
|
LL | / pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
LL | |
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: only `const` and `sym` operands are supported in naked functions
- --> $DIR/naked-functions.rs:67:10
+ --> $DIR/naked-functions.rs:71:10
|
LL | in(reg) a,
| ^^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm in naked functions must use `noreturn` option
- --> $DIR/naked-functions.rs:64:5
+ --> $DIR/naked-functions.rs:68:5
|
LL | / asm!("/* {0} {1} {2} {3} {4} {5} {6} */",
LL | |
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions must contain a single asm block
- --> $DIR/naked-functions.rs:54:1
+ --> $DIR/naked-functions.rs:58:1
|
LL | / pub unsafe extern "C" fn unsupported_operands() {
LL | |
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions must contain a single asm block
- --> $DIR/naked-functions.rs:80:1
+ --> $DIR/naked-functions.rs:84:1
|
LL | / pub extern "C" fn missing_assembly() {
LL | |
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm in naked functions must use `noreturn` option
- --> $DIR/naked-functions.rs:89:5
+ --> $DIR/naked-functions.rs:93:5
|
LL | asm!("");
| ^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm in naked functions must use `noreturn` option
- --> $DIR/naked-functions.rs:92:5
+ --> $DIR/naked-functions.rs:96:5
|
LL | asm!("");
| ^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm in naked functions must use `noreturn` option
- --> $DIR/naked-functions.rs:95:5
+ --> $DIR/naked-functions.rs:99:5
|
LL | asm!("");
| ^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions must contain a single asm block
- --> $DIR/naked-functions.rs:86:1
+ --> $DIR/naked-functions.rs:90:1
|
LL | / pub extern "C" fn too_many_asm_blocks() {
LL | |
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
error: referencing function parameters is not allowed in naked functions
- --> $DIR/naked-functions.rs:106:11
+ --> $DIR/naked-functions.rs:110:11
|
LL | *&y
| ^
= help: follow the calling convention in asm block to use parameters
warning: naked functions must contain a single asm block
- --> $DIR/naked-functions.rs:103:5
+ --> $DIR/naked-functions.rs:107:5
|
LL | / pub extern "C" fn inner(y: usize) -> usize {
LL | |
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: the LLVM-style inline assembly is unsupported in naked functions
- --> $DIR/naked-functions.rs:116:5
+ --> $DIR/naked-functions.rs:120:5
|
LL | llvm_asm!("");
| ^^^^^^^^^^^^^
= note: this warning originates in the macro `llvm_asm` (in Nightly builds, run with -Z macro-backtrace for more info)
warning: naked functions must contain a single asm block
- --> $DIR/naked-functions.rs:113:1
+ --> $DIR/naked-functions.rs:117:1
|
LL | / unsafe extern "C" fn llvm() -> ! {
LL | |
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm options unsupported in naked functions: `nomem`, `preserves_flags`
- --> $DIR/naked-functions.rs:124:5
+ --> $DIR/naked-functions.rs:128:5
|
LL | asm!("", options(nomem, preserves_flags, noreturn));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm options unsupported in naked functions: `nostack`, `pure`, `readonly`
- --> $DIR/naked-functions.rs:131:5
+ --> $DIR/naked-functions.rs:135:5
|
LL | asm!("", options(readonly, nostack), options(pure));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm in naked functions must use `noreturn` option
- --> $DIR/naked-functions.rs:131:5
+ --> $DIR/naked-functions.rs:135:5
|
LL | asm!("", options(readonly, nostack), options(pure));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: Rust ABI is unsupported in naked functions
- --> $DIR/naked-functions.rs:140:15
+ --> $DIR/naked-functions.rs:144:15
|
LL | pub unsafe fn default_abi() {
| ^^^^^^^^^^^
= note: `#[warn(undefined_naked_function_abi)]` on by default
warning: Rust ABI is unsupported in naked functions
- --> $DIR/naked-functions.rs:146:29
+ --> $DIR/naked-functions.rs:150:15
|
-LL | pub unsafe extern "Rust" fn rust_abi() {
- | ^^^^^^^^
+LL | pub unsafe fn rust_abi() {
+ | ^^^^^^^^
warning: naked functions cannot be inlined
- --> $DIR/naked-functions.rs:180:1
+ --> $DIR/naked-functions.rs:190:1
|
LL | #[inline]
| ^^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions cannot be inlined
- --> $DIR/naked-functions.rs:188:1
+ --> $DIR/naked-functions.rs:198:1
|
LL | #[inline(always)]
| ^^^^^^^^^^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions cannot be inlined
- --> $DIR/naked-functions.rs:196:1
+ --> $DIR/naked-functions.rs:206:1
|
LL | #[inline(never)]
| ^^^^^^^^^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions cannot be inlined
- --> $DIR/naked-functions.rs:204:1
+ --> $DIR/naked-functions.rs:214:1
|
LL | #[inline]
| ^^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions cannot be inlined
- --> $DIR/naked-functions.rs:207:1
+ --> $DIR/naked-functions.rs:217:1
|
LL | #[inline(always)]
| ^^^^^^^^^^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions cannot be inlined
- --> $DIR/naked-functions.rs:210:1
+ --> $DIR/naked-functions.rs:220:1
|
LL | #[inline(never)]
| ^^^^^^^^^^^^^^^^
// which causes less readable LLVM errors and in the worst cases causes ICEs
// or segfaults based on system dependent behavior and codegen flags.
-#![feature(asm, global_asm, naked_functions)]
+#![feature(asm, global_asm, naked_functions, asm_const)]
#[no_mangle]
pub static FOO: usize = 42;
// ignore-spirv
// ignore-wasm32
-#![feature(asm, global_asm)]
+#![feature(asm, global_asm, asm_const)]
fn main() {
unsafe {
--- /dev/null
+// needs-asm-support
+// only-x86_64
+
+// checks various modes of failure for the `clobber_abi` argument (after parsing)
+
+#![feature(asm)]
+
+fn main() {
+ unsafe {
+ asm!("", clobber_abi("C"));
+ asm!("", clobber_abi("foo"));
+ //~^ ERROR invalid ABI for `clobber_abi`
+ asm!("", clobber_abi("C", "foo"));
+ //~^ ERROR invalid ABI for `clobber_abi`
+ asm!("", clobber_abi("C", "C"));
+ //~^ ERROR `C` ABI specified multiple times
+ asm!("", clobber_abi("win64", "sysv64"));
+ asm!("", clobber_abi("win64", "efiapi"));
+ //~^ ERROR `win64` ABI specified multiple times
+ asm!("", clobber_abi("C", "foo", "C"));
+ //~^ ERROR invalid ABI for `clobber_abi`
+ //~| ERROR `C` ABI specified multiple times
+ asm!("", clobber_abi("win64", "foo", "efiapi"));
+ //~^ ERROR invalid ABI for `clobber_abi`
+ //~| ERROR `win64` ABI specified multiple times
+ asm!("", clobber_abi("C"), clobber_abi("C"));
+ //~^ ERROR `C` ABI specified multiple times
+ asm!("", clobber_abi("win64"), clobber_abi("sysv64"));
+ asm!("", clobber_abi("win64"), clobber_abi("efiapi"));
+ //~^ ERROR `win64` ABI specified multiple times
+ }
+}
--- /dev/null
+error: invalid ABI for `clobber_abi`
+ --> $DIR/bad-clobber-abi.rs:11:18
+ |
+LL | asm!("", clobber_abi("foo"));
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64`
+
+error: invalid ABI for `clobber_abi`
+ --> $DIR/bad-clobber-abi.rs:13:35
+ |
+LL | asm!("", clobber_abi("C", "foo"));
+ | ^^^^^
+ |
+ = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64`
+
+error: `C` ABI specified multiple times
+ --> $DIR/bad-clobber-abi.rs:15:35
+ |
+LL | asm!("", clobber_abi("C", "C"));
+ | --- ^^^
+ | |
+ | previously specified here
+
+error: `win64` ABI specified multiple times
+ --> $DIR/bad-clobber-abi.rs:18:39
+ |
+LL | asm!("", clobber_abi("win64", "efiapi"));
+ | ------- ^^^^^^^^
+ | |
+ | previously specified here
+ |
+ = note: these ABIs are equivalent on the current target
+
+error: invalid ABI for `clobber_abi`
+ --> $DIR/bad-clobber-abi.rs:20:35
+ |
+LL | asm!("", clobber_abi("C", "foo", "C"));
+ | ^^^^^
+ |
+ = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64`
+
+error: `C` ABI specified multiple times
+ --> $DIR/bad-clobber-abi.rs:20:42
+ |
+LL | asm!("", clobber_abi("C", "foo", "C"));
+ | --- ^^^
+ | |
+ | previously specified here
+
+error: invalid ABI for `clobber_abi`
+ --> $DIR/bad-clobber-abi.rs:23:39
+ |
+LL | asm!("", clobber_abi("win64", "foo", "efiapi"));
+ | ^^^^^
+ |
+ = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64`
+
+error: `win64` ABI specified multiple times
+ --> $DIR/bad-clobber-abi.rs:23:46
+ |
+LL | asm!("", clobber_abi("win64", "foo", "efiapi"));
+ | ------- ^^^^^^^^
+ | |
+ | previously specified here
+ |
+ = note: these ABIs are equivalent on the current target
+
+error: `C` ABI specified multiple times
+ --> $DIR/bad-clobber-abi.rs:26:36
+ |
+LL | asm!("", clobber_abi("C"), clobber_abi("C"));
+ | ---------------- ^^^^^^^^^^^^^^^^
+ | |
+ | previously specified here
+
+error: `win64` ABI specified multiple times
+ --> $DIR/bad-clobber-abi.rs:29:40
+ |
+LL | asm!("", clobber_abi("win64"), clobber_abi("efiapi"));
+ | -------------------- ^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | previously specified here
+ |
+ = note: these ABIs are equivalent on the current target
+
+error: aborting due to 10 previous errors
+
//~^ ERROR invalid ABI for `clobber_abi`
asm!("{}", out(reg) foo, clobber_abi("C"));
//~^ ERROR asm with `clobber_abi` must specify explicit registers for outputs
+ asm!("{}", out(reg) foo, clobber_abi("C"), clobber_abi("C"));
+ //~^ ERROR asm with `clobber_abi` must specify explicit registers for outputs
+ //~| ERROR `C` ABI specified multiple times
asm!("", out("eax") foo, clobber_abi("C"));
}
}
| |
| generic outputs
+error: asm with `clobber_abi` must specify explicit registers for outputs
+ --> $DIR/bad-options.rs:24:20
+ |
+LL | asm!("{}", out(reg) foo, clobber_abi("C"), clobber_abi("C"));
+ | ^^^^^^^^^^^^ ---------------- ---------------- clobber_abi
+ | | |
+ | | clobber_abi
+ | generic outputs
+
error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
- --> $DIR/bad-options.rs:28:25
+ --> $DIR/bad-options.rs:31:25
|
LL | global_asm!("", options(nomem));
| ^^^^^ expected one of `)`, `att_syntax`, or `raw`
error: expected one of `)`, `att_syntax`, or `raw`, found `readonly`
- --> $DIR/bad-options.rs:30:25
+ --> $DIR/bad-options.rs:33:25
|
LL | global_asm!("", options(readonly));
| ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn`
- --> $DIR/bad-options.rs:32:25
+ --> $DIR/bad-options.rs:35:25
|
LL | global_asm!("", options(noreturn));
| ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
error: expected one of `)`, `att_syntax`, or `raw`, found `pure`
- --> $DIR/bad-options.rs:34:25
+ --> $DIR/bad-options.rs:37:25
|
LL | global_asm!("", options(pure));
| ^^^^ expected one of `)`, `att_syntax`, or `raw`
error: expected one of `)`, `att_syntax`, or `raw`, found `nostack`
- --> $DIR/bad-options.rs:36:25
+ --> $DIR/bad-options.rs:39:25
|
LL | global_asm!("", options(nostack));
| ^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags`
- --> $DIR/bad-options.rs:38:25
+ --> $DIR/bad-options.rs:41:25
|
LL | global_asm!("", options(preserves_flags));
| ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
|
= note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64`
-error: aborting due to 13 previous errors
+error: `C` ABI specified multiple times
+ --> $DIR/bad-options.rs:24:52
+ |
+LL | asm!("{}", out(reg) foo, clobber_abi("C"), clobber_abi("C"));
+ | ---------------- ^^^^^^^^^^^^^^^^
+ | |
+ | previously specified here
+
+error: aborting due to 15 previous errors
// only-x86_64
// compile-flags: -C target-feature=+avx2
-#![feature(asm)]
+#![feature(asm, asm_const, asm_sym)]
fn main() {
let mut foo = 0;
// revisions: mirunsafeck thirunsafeck
// [thirunsafeck]compile-flags: -Z thir-unsafeck
-#![feature(asm, global_asm)]
+#![feature(asm, global_asm, asm_const)]
fn const_generic<const X: usize>() -> usize {
unsafe {
--- /dev/null
+// run-pass
+// needs-asm-support
+// only-x86_64
+
+// Checks that multiple clobber_abi options can be used
+
+#![feature(asm, asm_sym)]
+
+extern "sysv64" fn foo(x: i32) -> i32 {
+ x + 16
+}
+
+extern "win64" fn bar(x: i32) -> i32 {
+ x / 2
+}
+
+fn main() {
+ let x = 8;
+ let y: i32;
+ // call `foo` with `x` as the input, and then `bar` with the output of `foo`
+ // and output that to `y`
+ unsafe {
+ asm!(
+ "call {}; mov rcx, rax; call {}",
+ sym foo,
+ sym bar,
+ in("rdi") x,
+ out("rax") y,
+ clobber_abi("sysv64", "win64"),
+ );
+ }
+ assert_eq!((x, y), (8, 12));
+}
// only-x86_64
-#![feature(asm, global_asm)]
+#![feature(asm, global_asm, asm_const)]
fn main() {
let mut foo = 0;
asm!("{}", options(), const foo);
//~^ ERROR arguments are not allowed after options
//~^^ ERROR attempt to use a non-constant value in a constant
+ asm!("", clobber_abi());
+ //~^ ERROR at least one abi must be provided
asm!("", clobber_abi(foo));
//~^ ERROR expected string literal
asm!("", clobber_abi("C" foo));
- //~^ ERROR expected `)`, found `foo`
+ //~^ ERROR expected one of `)` or `,`, found `foo`
asm!("", clobber_abi("C", foo));
- //~^ ERROR expected `)`, found `,`
+ //~^ ERROR expected string literal
asm!("{}", clobber_abi("C"), const foo);
//~^ ERROR arguments are not allowed after clobber_abi
//~^^ ERROR attempt to use a non-constant value in a constant
//~^ ERROR clobber_abi is not allowed after options
asm!("{}", options(), clobber_abi("C"), const foo);
//~^ ERROR clobber_abi is not allowed after options
- asm!("", clobber_abi("C"), clobber_abi("C"));
- //~^ ERROR clobber_abi specified multiple times
asm!("{a}", a = const foo, a = const bar);
//~^ ERROR duplicate argument named `a`
//~^^ ERROR argument never used
global_asm!("", clobber_abi(FOO));
//~^ ERROR expected string literal
global_asm!("", clobber_abi("C" FOO));
-//~^ ERROR expected `)`, found `FOO`
+//~^ ERROR expected one of `)` or `,`, found `FOO`
global_asm!("", clobber_abi("C", FOO));
-//~^ ERROR expected `)`, found `,`
+//~^ ERROR expected string literal
global_asm!("{}", clobber_abi("C"), const FOO);
//~^ ERROR arguments are not allowed after clobber_abi
//~^^ ERROR `clobber_abi` cannot be used with `global_asm!`
global_asm!("{}", options(), clobber_abi("C"), const FOO);
//~^ ERROR clobber_abi is not allowed after options
global_asm!("", clobber_abi("C"), clobber_abi("C"));
-//~^ ERROR clobber_abi specified multiple times
+//~^ ERROR `clobber_abi` cannot be used with `global_asm!`
global_asm!("{a}", a = const FOO, a = const BAR);
//~^ ERROR duplicate argument named `a`
//~^^ ERROR argument never used
| |
| previous options
-error: expected string literal
+error: at least one abi must be provided as an argument to `clobber_abi`
--> $DIR/parse-error.rs:40:30
|
+LL | asm!("", clobber_abi());
+ | ^
+
+error: expected string literal
+ --> $DIR/parse-error.rs:42:30
+ |
LL | asm!("", clobber_abi(foo));
| ^^^ not a string literal
-error: expected `)`, found `foo`
- --> $DIR/parse-error.rs:42:34
+error: expected one of `)` or `,`, found `foo`
+ --> $DIR/parse-error.rs:44:34
|
LL | asm!("", clobber_abi("C" foo));
- | ^^^ expected `)`
+ | ^^^ expected one of `)` or `,`
-error: expected `)`, found `,`
- --> $DIR/parse-error.rs:44:33
+error: expected string literal
+ --> $DIR/parse-error.rs:46:35
|
LL | asm!("", clobber_abi("C", foo));
- | ^ expected `)`
+ | ^^^ not a string literal
error: arguments are not allowed after clobber_abi
- --> $DIR/parse-error.rs:46:38
+ --> $DIR/parse-error.rs:48:38
|
LL | asm!("{}", clobber_abi("C"), const foo);
| ---------------- ^^^^^^^^^ argument
| clobber_abi
error: clobber_abi is not allowed after options
- --> $DIR/parse-error.rs:49:29
+ --> $DIR/parse-error.rs:51:29
|
LL | asm!("", options(), clobber_abi("C"));
| --------- ^^^^^^^^^^^^^^^^
| options
error: clobber_abi is not allowed after options
- --> $DIR/parse-error.rs:51:31
+ --> $DIR/parse-error.rs:53:31
|
LL | asm!("{}", options(), clobber_abi("C"), const foo);
| --------- ^^^^^^^^^^^^^^^^
| |
| options
-error: clobber_abi specified multiple times
- --> $DIR/parse-error.rs:53:36
- |
-LL | asm!("", clobber_abi("C"), clobber_abi("C"));
- | ---------------- ^^^^^^^^^^^^^^^^
- | |
- | clobber_abi previously specified here
-
error: duplicate argument named `a`
--> $DIR/parse-error.rs:55:36
|
LL | global_asm!("", clobber_abi(FOO));
| ^^^ not a string literal
-error: expected `)`, found `FOO`
+error: expected one of `)` or `,`, found `FOO`
--> $DIR/parse-error.rs:112:33
|
LL | global_asm!("", clobber_abi("C" FOO));
- | ^^^ expected `)`
+ | ^^^ expected one of `)` or `,`
-error: expected `)`, found `,`
- --> $DIR/parse-error.rs:114:32
+error: expected string literal
+ --> $DIR/parse-error.rs:114:34
|
LL | global_asm!("", clobber_abi("C", FOO));
- | ^ expected `)`
+ | ^^^ not a string literal
error: arguments are not allowed after clobber_abi
--> $DIR/parse-error.rs:116:37
| |
| options
-error: clobber_abi specified multiple times
- --> $DIR/parse-error.rs:123:35
+error: `clobber_abi` cannot be used with `global_asm!`
+ --> $DIR/parse-error.rs:123:17
|
LL | global_asm!("", clobber_abi("C"), clobber_abi("C"));
- | ---------------- ^^^^^^^^^^^^^^^^
- | |
- | clobber_abi previously specified here
+ | ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^
error: duplicate argument named `a`
--> $DIR/parse-error.rs:125:35
| ^^^ non-constant value
error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/parse-error.rs:46:44
+ --> $DIR/parse-error.rs:48:44
|
LL | let mut foo = 0;
| ---------- help: consider using `const` instead of `let`: `const foo`
// only-linux
// run-pass
-#![feature(asm, thread_local)]
+#![feature(asm, thread_local, asm_sym)]
extern "C" fn f1() -> i32 {
111
std::thread::spawn(|| {
assert_eq!(static_addr!(S1), &S1 as *const u32);
assert_eq!(static_tls_addr!(S2), &S2 as *const u32);
- }).join().unwrap();
+ })
+ .join()
+ .unwrap();
}
// only-x86_64
-#![feature(asm, repr_simd, never_type)]
+#![feature(asm, repr_simd, never_type, asm_sym)]
#[repr(simd)]
struct SimdNonCopy(f32, f32, f32, f32);
// only-x86_64
// compile-flags: -C target-feature=+avx512f
-#![feature(asm, global_asm)]
+#![feature(asm, global_asm, asm_const)]
use std::arch::x86_64::{_mm256_setzero_ps, _mm_setzero_ps};
--- /dev/null
+// check-pass
+pub trait LineFormatter<'a> {
+ type Iter: Iterator<Item=&'a str> + 'a;
+ fn iter(&'a self, line: &'a str) -> Self::Iter;
+
+ fn dimensions(&'a self, line: &'a str) {
+ let iter: Self::Iter = self.iter(line);
+ <_ as IntoIterator>::into_iter(iter);
+ }
+}
+
+fn main() {}
--- /dev/null
+// run-pass
+#![allow(dead_code)]
+// Test transitive analysis for associated types. Collected types
+// should be normalized and new obligations generated.
+
+// pretty-expanded FIXME #23616
+
+trait Foo {
+ type A;
+ fn foo(&self) {}
+}
+
+impl Foo for usize {
+ type A = usize;
+}
+
+struct Bar<T: Foo> { inner: T::A }
+
+fn is_send<T: Send>() {}
+
+fn main() {
+ is_send::<Bar<usize>>();
+}
--- /dev/null
+// check-pass
+// Regression test for #28871. The problem is that rustc encountered
+// two ways to project, one from a where clause and one from the where
+// clauses on the trait definition. (In fact, in this case, the where
+// clauses originated from the trait definition as well.) The true
+// cause of the error is that the trait definition where clauses are
+// not being normalized, and hence the two sources are considered in
+// conflict, and not a duplicate. Hacky solution is to prefer where
+// clauses over the data found in the trait definition.
+
+trait T {
+ type T;
+}
+
+struct S;
+impl T for S {
+ type T = S;
+}
+
+trait T2 {
+ type T: Iterator<Item=<S as T>::T>;
+}
+
+fn main() { }
--- /dev/null
+// run-pass
+// Regression test for issue #47139:
+//
+// Coherence was encountering an (unnecessary) overflow trying to
+// decide if the two impls of dummy overlap.
+//
+// The overflow went something like:
+//
+// - `&'a ?T: Insertable` ?
+// - let ?T = Option<?U> ?
+// - `Option<?U>: Insertable` ?
+// - `Option<&'a ?U>: Insertable` ?
+// - `&'a ?U: Insertable` ?
+//
+// While somewhere in the middle, a projection would occur, which
+// broke cycle detection.
+//
+// It turned out that this cycle was being kicked off due to some
+// extended diagnostic attempts in coherence, so removing those
+// sidestepped the issue for now.
+
+#![allow(dead_code)]
+
+pub trait Insertable {
+ type Values;
+
+ fn values(self) -> Self::Values;
+}
+
+impl<T> Insertable for Option<T>
+ where
+ T: Insertable,
+ T::Values: Default,
+{
+ type Values = T::Values;
+
+ fn values(self) -> Self::Values {
+ self.map(Insertable::values).unwrap_or_default()
+ }
+}
+
+impl<'a, T> Insertable for &'a Option<T>
+ where
+ Option<&'a T>: Insertable,
+{
+ type Values = <Option<&'a T> as Insertable>::Values;
+
+ fn values(self) -> Self::Values {
+ self.as_ref().values()
+ }
+}
+
+impl<'a, T> Insertable for &'a [T]
+{
+ type Values = Self;
+
+ fn values(self) -> Self::Values {
+ self
+ }
+}
+
+trait Unimplemented { }
+
+trait Dummy { }
+
+struct Foo<T> { t: T }
+
+impl<'a, U> Dummy for Foo<&'a U>
+ where &'a U: Insertable
+{
+}
+
+impl<T> Dummy for T
+ where T: Unimplemented
+{ }
+
+fn main() {
+}
--- /dev/null
+// run-pass
+
+pub trait Stream {
+ type Item;
+ type Error;
+}
+
+pub trait ParseError<I> {
+ type Output;
+}
+
+impl ParseError<char> for u32 {
+ type Output = ();
+}
+
+impl Stream for () {
+ type Item = char;
+ type Error = u32;
+}
+
+pub struct Lex<'a, I>
+ where I: Stream,
+ I::Error: ParseError<char>,
+ <<I as Stream>::Error as ParseError<char>>::Output: 'a
+{
+ x: &'a <I::Error as ParseError<char>>::Output
+}
+
+pub struct Reserved<'a, I> where
+ I: Stream<Item=char> + 'a,
+ I::Error: ParseError<I::Item>,
+ <<I as Stream>::Error as ParseError<char>>::Output: 'a
+
+{
+ x: Lex<'a, I>
+}
+
+fn main() {
+ let r: Reserved<()> = Reserved {
+ x: Lex {
+ x: &()
+ }
+ };
+
+ let _v = r.x.x;
+}
--- /dev/null
+// edition:2018
+
+fn main() {
+ 'a: loop {
+ async {
+ loop {
+ continue 'a
+ //~^ ERROR use of unreachable label `'a`
+ }
+ };
+ }
+}
--- /dev/null
+error[E0767]: use of unreachable label `'a`
+ --> $DIR/issue-73541-1.rs:7:26
+ |
+LL | 'a: loop {
+ | -- unreachable label defined here
+...
+LL | continue 'a
+ | ^^ unreachable label `'a`
+ |
+ = note: labels are unreachable through functions, closures, async blocks and modules
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0767`.
--- /dev/null
+// check-pass
+macro_rules! m {
+ ($i:meta) => {
+ #[derive($i)]
+ struct S;
+ }
+}
+
+m!(Clone);
+
+fn main() {}
let res =
::alloc::fmt::format(::core::fmt::Arguments::new_v1(&[""],
&match (&"u8",) {
- (arg0,) =>
- [::core::fmt::ArgumentV1::new(arg0,
+ _args =>
+ [::core::fmt::ArgumentV1::new(_args.0,
::core::fmt::Display::fmt)],
}));
res
--- /dev/null
+// build-pass (FIXME(62277): could be check-pass?)
+
+#![feature(rustc_attrs)]
+
+#[rustc_dummy(a b c d)]
+#[rustc_dummy[a b c d]]
+#[rustc_dummy{a b c d}]
+fn main() {}
+++ /dev/null
-#![crate_name = "a"]
-
-pub fn foo<T>() {}
+++ /dev/null
-#![crate_name = "a"]
-
-pub fn foo<T>() { println!("hello!"); }
+++ /dev/null
-#![crate_name = "b"]
-
-extern crate a;
-
-pub fn foo() { a::foo::<isize>(); }
+++ /dev/null
-#![feature(rustc_attrs)]
-
-#[rustc_legacy_const_generics(1)]
-pub fn foo<const Y: usize>(x: usize, z: usize) -> [usize; 3] {
- [x, Y, z]
-}
+++ /dev/null
-// no-prefer-dynamic
-
-#![crate_type = "rlib"]
-
-#[no_mangle]
-pub extern "C" fn foo() {}
+++ /dev/null
-// no-prefer-dynamic
-
-#![crate_type = "rlib"]
-
-#[no_mangle]
-pub extern "C" fn foo() {}
+++ /dev/null
-// compile-flags: -Clinker-plugin-lto
-// no-prefer-dynamic
-
-#![crate_type = "rlib"]
-
-pub fn foo() {}
+++ /dev/null
-// original problem
-pub fn foo<T>() -> isize {
- {
- static foo: isize = 2;
- foo
- }
-}
-
-// issue 8134
-struct Foo;
-impl Foo {
- pub fn foo<T>(&self) {
- static X: usize = 1;
- }
-}
-
-// issue 8134
-pub struct Parser<T>(T);
-impl<T: std::iter::Iterator<Item=char>> Parser<T> {
- fn in_doctype(&mut self) {
- static DOCTYPEPattern: [char; 6] = ['O', 'C', 'T', 'Y', 'P', 'E'];
- }
-}
-
-struct Bar;
-impl Foo {
- pub fn bar<T>(&self) {
- static X: usize = 1;
- }
-}
+++ /dev/null
-// check-pass
-
-// Bastion of the Turbofish
-// ------------------------
-// Beware travellers, lest you venture into waters callous and unforgiving,
-// where hope must be abandoned, ere it is cruelly torn from you. For here
-// stands the bastion of the Turbofish: an impenetrable fortress holding
-// unshaking against those who would dare suggest the supererogation of the
-// Turbofish.
-//
-// Once I was young and foolish and had the impudence to imagine that I could
-// shake free from the coils by which that creature had us tightly bound. I
-// dared to suggest that there was a better way: a brighter future, in which
-// Rustaceans both new and old could be rid of that vile beast. But alas! In
-// my foolhardiness my ignorance was unveiled and my dreams were dashed
-// unforgivingly against the rock of syntactic ambiguity.
-//
-// This humble program, small and insignificant though it might seem,
-// demonstrates that to which we had previously cast a blind eye: an ambiguity
-// in permitting generic arguments to be provided without the consent of the
-// Great Turbofish. Should you be so naïve as to try to revolt against its
-// mighty clutches, here shall its wrath be indomitably displayed. This
-// program must pass for all eternity: forever watched by the guardian angel
-// which gave this beast its name, and stands fundamentally at odds with the
-// impetuous rebellion against the Turbofish.
-//
-// My heart aches in sorrow, for I know I am defeated. Let this be a warning
-// to all those who come after: for they too must overcome the impassible
-// hurdle of defeating the great beast, championed by a resolute winged
-// guardian.
-//
-// Here stands the Bastion of the Turbofish, a memorial to Anna Harren,
-// Guardian Angel of these Hallowed Grounds. <3
-
-// See https://github.com/rust-lang/rust/pull/53562
-// and https://github.com/rust-lang/rfcs/pull/2527
-// and https://twitter.com/garblefart/status/1393236602856611843
-// for context.
-
-fn main() {
- let (the, guardian, stands, resolute) = ("the", "Turbofish", "remains", "undefeated");
- let _: (bool, bool) = (the<guardian, stands>(resolute));
-}
--- /dev/null
+// run-pass
+
+#![allow(non_camel_case_types)]
+
+
+#[derive(Copy, Clone, Debug)]
+enum foo { large, small, }
+
+impl PartialEq for foo {
+ fn eq(&self, other: &foo) -> bool {
+ ((*self) as usize) == ((*other) as usize)
+ }
+ fn ne(&self, other: &foo) -> bool { !(*self).eq(other) }
+}
+
+pub fn main() {
+ let a = (1, 2, 3);
+ let b = (1, 2, 3);
+ assert_eq!(a, b);
+ assert!((a != (1, 2, 4)));
+ assert!((a < (1, 2, 4)));
+ assert!((a <= (1, 2, 4)));
+ assert!(((1, 2, 4) > a));
+ assert!(((1, 2, 4) >= a));
+ let x = foo::large;
+ let y = foo::small;
+ assert!((x != y));
+ assert_eq!(x, foo::large);
+ assert!((x != foo::small));
+}
--- /dev/null
+// run-pass
+struct A;
+
+impl A {
+ fn take_mutably(&mut self) {}
+}
+
+fn identity<T>(t: T) -> T {
+ t
+}
+
+// Issue 46095
+// Built-in indexing should be used even when the index is not
+// trivially an integer
+// Overloaded indexing would cause wrapped to be borrowed mutably
+
+fn main() {
+ let mut a1 = A;
+ let mut a2 = A;
+
+ let wrapped = [&mut a1, &mut a2];
+
+ {
+ wrapped[0 + 1 - 1].take_mutably();
+ }
+
+ {
+ wrapped[identity(0)].take_mutably();
+ }
+}
--- /dev/null
+// run-pass
+
+fn f(x: Box<isize>) {
+ let y: &isize = &*x;
+ println!("{}", *x);
+ println!("{}", *y);
+}
+
+trait Trait {
+ fn printme(&self);
+}
+
+struct Struct;
+
+impl Trait for Struct {
+ fn printme(&self) {
+ println!("hello world!");
+ }
+}
+
+fn g(x: Box<dyn Trait>) {
+ x.printme();
+ let y: &dyn Trait = &*x;
+ y.printme();
+}
+
+fn main() {
+ f(Box::new(1234));
+ g(Box::new(Struct) as Box<dyn Trait>);
+}
].clone();
});
- assert!(result.is_err());
+ assert!(child.is_err());
assert_eq!(
1,
Rc::strong_count(&counter)
--- /dev/null
+extern "C" {
+ fn foo(a: i32, ...);
+}
+
+fn bar(_: *const u8) {}
+
+fn main() {
+ unsafe {
+ foo(0, bar);
+ //~^ ERROR can't pass `fn(*const u8) {bar}` to variadic function
+ //~| HELP cast the value to `fn(*const u8)`
+ }
+}
--- /dev/null
+error[E0617]: can't pass `fn(*const u8) {bar}` to variadic function
+ --> $DIR/issue-32201.rs:9:16
+ |
+LL | foo(0, bar);
+ | ^^^ help: cast the value to `fn(*const u8)`: `bar as fn(*const u8)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0617`.
--- /dev/null
+// run-pass
+
+pub fn main() {
+ let f = 1_usize as *const String;
+ println!("{:?}", f as isize);
+ println!("{:?}", f as usize);
+ println!("{:?}", f as i8);
+ println!("{:?}", f as i16);
+ println!("{:?}", f as i32);
+ println!("{:?}", f as i64);
+ println!("{:?}", f as u8);
+ println!("{:?}", f as u16);
+ println!("{:?}", f as u32);
+ println!("{:?}", f as u64);
+
+ println!("{:?}", 1 as isize);
+ println!("{:?}", 1 as usize);
+ println!("{:?}", 1 as *const String);
+ println!("{:?}", 1 as i8);
+ println!("{:?}", 1 as i16);
+ println!("{:?}", 1 as i32);
+ println!("{:?}", 1 as i64);
+ println!("{:?}", 1 as u8);
+ println!("{:?}", 1 as u16);
+ println!("{:?}", 1 as u32);
+ println!("{:?}", 1 as u64);
+ println!("{:?}", 1 as f32);
+ println!("{:?}", 1 as f64);
+
+ println!("{:?}", 1_usize as isize);
+ println!("{:?}", 1_usize as usize);
+ println!("{:?}", 1_usize as *const String);
+ println!("{:?}", 1_usize as i8);
+ println!("{:?}", 1_usize as i16);
+ println!("{:?}", 1_usize as i32);
+ println!("{:?}", 1_usize as i64);
+ println!("{:?}", 1_usize as u8);
+ println!("{:?}", 1_usize as u16);
+ println!("{:?}", 1_usize as u32);
+ println!("{:?}", 1_usize as u64);
+ println!("{:?}", 1_usize as f32);
+ println!("{:?}", 1_usize as f64);
+
+ println!("{:?}", 1i8 as isize);
+ println!("{:?}", 1i8 as usize);
+ println!("{:?}", 1i8 as *const String);
+ println!("{:?}", 1i8 as i8);
+ println!("{:?}", 1i8 as i16);
+ println!("{:?}", 1i8 as i32);
+ println!("{:?}", 1i8 as i64);
+ println!("{:?}", 1i8 as u8);
+ println!("{:?}", 1i8 as u16);
+ println!("{:?}", 1i8 as u32);
+ println!("{:?}", 1i8 as u64);
+ println!("{:?}", 1i8 as f32);
+ println!("{:?}", 1i8 as f64);
+
+ println!("{:?}", 1u8 as isize);
+ println!("{:?}", 1u8 as usize);
+ println!("{:?}", 1u8 as *const String);
+ println!("{:?}", 1u8 as i8);
+ println!("{:?}", 1u8 as i16);
+ println!("{:?}", 1u8 as i32);
+ println!("{:?}", 1u8 as i64);
+ println!("{:?}", 1u8 as u8);
+ println!("{:?}", 1u8 as u16);
+ println!("{:?}", 1u8 as u32);
+ println!("{:?}", 1u8 as u64);
+ println!("{:?}", 1u8 as f32);
+ println!("{:?}", 1u8 as f64);
+
+ println!("{:?}", 1i16 as isize);
+ println!("{:?}", 1i16 as usize);
+ println!("{:?}", 1i16 as *const String);
+ println!("{:?}", 1i16 as i8);
+ println!("{:?}", 1i16 as i16);
+ println!("{:?}", 1i16 as i32);
+ println!("{:?}", 1i16 as i64);
+ println!("{:?}", 1i16 as u8);
+ println!("{:?}", 1i16 as u16);
+ println!("{:?}", 1i16 as u32);
+ println!("{:?}", 1i16 as u64);
+ println!("{:?}", 1i16 as f32);
+ println!("{:?}", 1i16 as f64);
+
+ println!("{:?}", 1u16 as isize);
+ println!("{:?}", 1u16 as usize);
+ println!("{:?}", 1u16 as *const String);
+ println!("{:?}", 1u16 as i8);
+ println!("{:?}", 1u16 as i16);
+ println!("{:?}", 1u16 as i32);
+ println!("{:?}", 1u16 as i64);
+ println!("{:?}", 1u16 as u8);
+ println!("{:?}", 1u16 as u16);
+ println!("{:?}", 1u16 as u32);
+ println!("{:?}", 1u16 as u64);
+ println!("{:?}", 1u16 as f32);
+ println!("{:?}", 1u16 as f64);
+
+ println!("{:?}", 1i32 as isize);
+ println!("{:?}", 1i32 as usize);
+ println!("{:?}", 1i32 as *const String);
+ println!("{:?}", 1i32 as i8);
+ println!("{:?}", 1i32 as i16);
+ println!("{:?}", 1i32 as i32);
+ println!("{:?}", 1i32 as i64);
+ println!("{:?}", 1i32 as u8);
+ println!("{:?}", 1i32 as u16);
+ println!("{:?}", 1i32 as u32);
+ println!("{:?}", 1i32 as u64);
+ println!("{:?}", 1i32 as f32);
+ println!("{:?}", 1i32 as f64);
+
+ println!("{:?}", 1u32 as isize);
+ println!("{:?}", 1u32 as usize);
+ println!("{:?}", 1u32 as *const String);
+ println!("{:?}", 1u32 as i8);
+ println!("{:?}", 1u32 as i16);
+ println!("{:?}", 1u32 as i32);
+ println!("{:?}", 1u32 as i64);
+ println!("{:?}", 1u32 as u8);
+ println!("{:?}", 1u32 as u16);
+ println!("{:?}", 1u32 as u32);
+ println!("{:?}", 1u32 as u64);
+ println!("{:?}", 1u32 as f32);
+ println!("{:?}", 1u32 as f64);
+
+ println!("{:?}", 1i64 as isize);
+ println!("{:?}", 1i64 as usize);
+ println!("{:?}", 1i64 as *const String);
+ println!("{:?}", 1i64 as i8);
+ println!("{:?}", 1i64 as i16);
+ println!("{:?}", 1i64 as i32);
+ println!("{:?}", 1i64 as i64);
+ println!("{:?}", 1i64 as u8);
+ println!("{:?}", 1i64 as u16);
+ println!("{:?}", 1i64 as u32);
+ println!("{:?}", 1i64 as u64);
+ println!("{:?}", 1i64 as f32);
+ println!("{:?}", 1i64 as f64);
+
+ println!("{:?}", 1u64 as isize);
+ println!("{:?}", 1u64 as usize);
+ println!("{:?}", 1u64 as *const String);
+ println!("{:?}", 1u64 as i8);
+ println!("{:?}", 1u64 as i16);
+ println!("{:?}", 1u64 as i32);
+ println!("{:?}", 1u64 as i64);
+ println!("{:?}", 1u64 as u8);
+ println!("{:?}", 1u64 as u16);
+ println!("{:?}", 1u64 as u32);
+ println!("{:?}", 1u64 as u64);
+ println!("{:?}", 1u64 as f32);
+ println!("{:?}", 1u64 as f64);
+
+ println!("{:?}", 1u64 as isize);
+ println!("{:?}", 1u64 as usize);
+ println!("{:?}", 1u64 as *const String);
+ println!("{:?}", 1u64 as i8);
+ println!("{:?}", 1u64 as i16);
+ println!("{:?}", 1u64 as i32);
+ println!("{:?}", 1u64 as i64);
+ println!("{:?}", 1u64 as u8);
+ println!("{:?}", 1u64 as u16);
+ println!("{:?}", 1u64 as u32);
+ println!("{:?}", 1u64 as u64);
+ println!("{:?}", 1u64 as f32);
+ println!("{:?}", 1u64 as f64);
+
+ println!("{:?}", true as isize);
+ println!("{:?}", true as usize);
+ println!("{:?}", true as i8);
+ println!("{:?}", true as i16);
+ println!("{:?}", true as i32);
+ println!("{:?}", true as i64);
+ println!("{:?}", true as u8);
+ println!("{:?}", true as u16);
+ println!("{:?}", true as u32);
+ println!("{:?}", true as u64);
+
+ println!("{:?}", 1f32 as isize);
+ println!("{:?}", 1f32 as usize);
+ println!("{:?}", 1f32 as i8);
+ println!("{:?}", 1f32 as i16);
+ println!("{:?}", 1f32 as i32);
+ println!("{:?}", 1f32 as i64);
+ println!("{:?}", 1f32 as u8);
+ println!("{:?}", 1f32 as u16);
+ println!("{:?}", 1f32 as u32);
+ println!("{:?}", 1f32 as u64);
+ println!("{:?}", 1f32 as f32);
+ println!("{:?}", 1f32 as f64);
+
+ println!("{:?}", 1f64 as isize);
+ println!("{:?}", 1f64 as usize);
+ println!("{:?}", 1f64 as i8);
+ println!("{:?}", 1f64 as i16);
+ println!("{:?}", 1f64 as i32);
+ println!("{:?}", 1f64 as i64);
+ println!("{:?}", 1f64 as u8);
+ println!("{:?}", 1f64 as u16);
+ println!("{:?}", 1f64 as u32);
+ println!("{:?}", 1f64 as u64);
+ println!("{:?}", 1f64 as f32);
+ println!("{:?}", 1f64 as f64);
+}
fn foo() { }
fn main() {
+ // FIXME: add closures when they're considered WF
test_copy_clone(foo);
let f: fn() = foo;
test_copy_clone(f);
- // FIXME: add closures when they're considered WF
- test_copy_clone([1; 56]);
+ // FIXME(#86252): reinstate array test after chalk upgrade
+ //test_copy_clone([1; 56]);
test_copy_clone((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1));
test_copy_clone((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, true, 'a', 1.1));
test_copy_clone(());
+++ /dev/null
-// ignore-msvc FIXME #31306
-
-// note that these aux-build directives must be in this order
-// aux-build:changing-crates-a1.rs
-// aux-build:changing-crates-b.rs
-// aux-build:changing-crates-a2.rs
-// normalize-stderr-test: "(crate `(\w+)`:) .*" -> "$1 $$PATH_$2"
-
-extern crate a;
-extern crate b; //~ ERROR: found possibly newer version of crate `a` which `b` depends on
-
-fn main() {}
+++ /dev/null
-error[E0460]: found possibly newer version of crate `a` which `b` depends on
- --> $DIR/changing-crates.rs:10:1
- |
-LL | extern crate b;
- | ^^^^^^^^^^^^^^^
- |
- = note: perhaps that crate needs to be recompiled?
- = note: the following crate versions were found:
- crate `a`: $PATH_a
- crate `b`: $PATH_b
-
-error: aborting due to previous error
-
--- /dev/null
+#![feature(box_syntax)]
+
+fn main() {
+ let x: Box<_> = box 1;
+ let f = move|| {
+ let _a = x;
+ drop(x);
+ //~^ ERROR: use of moved value: `x`
+ };
+ f();
+}
--- /dev/null
+error[E0382]: use of moved value: `x`
+ --> $DIR/issue-10398.rs:7:14
+ |
+LL | let _a = x;
+ | - value moved here
+LL | drop(x);
+ | ^ value used here after move
+ |
+ = note: move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
--- /dev/null
+// run-pass
+use std::ops::{Deref, DerefMut};
+
+struct CheckedDeref<T, F> {
+ value: T,
+ check: F
+}
+
+impl<F: Fn(&T) -> bool, T> Deref for CheckedDeref<T, F> {
+ type Target = T;
+ fn deref(&self) -> &T {
+ assert!((self.check)(&self.value));
+ &self.value
+ }
+}
+
+impl<F: Fn(&T) -> bool, T> DerefMut for CheckedDeref<T, F> {
+ fn deref_mut(&mut self) -> &mut T {
+ assert!((self.check)(&self.value));
+ &mut self.value
+ }
+}
+
+
+fn main() {
+ let mut v = CheckedDeref {
+ value: vec![0],
+ check: |v: &Vec<_>| !v.is_empty()
+ };
+ v.push(1);
+ assert_eq!(*v, vec![0, 1]);
+}
| expected due to this
|
= note: expected unit type `()`
- found closure `[mod1::f<T>::{closure#0} closure_substs=(unavailable) substs=[T, _#25t, extern "rust-call" fn(()), _#26t]]`
+ found closure `[mod1::f<T>::{closure#0} closure_substs=(unavailable) substs=[T, _#22t, extern "rust-call" fn(()), _#23t]]`
help: use parentheses to call this closure
|
LL | let c1 : () = c();
| expected due to this
|
= note: expected unit type `()`
- found closure `[f<T>::{closure#0} closure_substs=(unavailable) substs=[T, _#25t, extern "rust-call" fn(()), _#26t]]`
+ found closure `[f<T>::{closure#0} closure_substs=(unavailable) substs=[T, _#22t, extern "rust-call" fn(()), _#23t]]`
help: use parentheses to call this closure
|
LL | let c1 : () = c();
--- /dev/null
+#![crate_type="rlib"]
+
+#[derive(Debug, PartialEq)]
+pub struct RemoteC(pub u32);
+
+#[derive(Debug, PartialEq)]
+pub struct RemoteG<T>(pub T);
--- /dev/null
+// run-pass
+// All 3 expressions should work in that the argument gets
+// coerced to a trait object
+
+// pretty-expanded FIXME #23616
+
+fn main() {
+ send::<Box<dyn Foo>>(Box::new(Output(0)));
+ Test::<Box<dyn Foo>>::foo(Box::new(Output(0)));
+ Test::<Box<dyn Foo>>::new().send(Box::new(Output(0)));
+}
+
+fn send<T>(_: T) {}
+
+struct Test<T> { marker: std::marker::PhantomData<T> }
+impl<T> Test<T> {
+ fn new() -> Test<T> { Test { marker: ::std::marker::PhantomData } }
+ fn foo(_: T) {}
+ fn send(&self, _: T) {}
+}
+
+trait Foo { fn dummy(&self) { }}
+struct Output(isize);
+impl Foo for Output {}
--- /dev/null
+// run-pass
+// aux-build:issue-39823.rs
+
+extern crate issue_39823;
+use issue_39823::{RemoteC, RemoteG};
+
+#[derive(Debug, PartialEq)]
+struct LocalC(u32);
+
+#[derive(Debug, PartialEq)]
+struct LocalG<T>(T);
+
+fn main() {
+ let virtual_localc : &dyn Fn(_) -> LocalC = &LocalC;
+ assert_eq!(virtual_localc(1), LocalC(1));
+
+ let virtual_localg : &dyn Fn(_) -> LocalG<u32> = &LocalG;
+ assert_eq!(virtual_localg(1), LocalG(1));
+
+ let virtual_remotec : &dyn Fn(_) -> RemoteC = &RemoteC;
+ assert_eq!(virtual_remotec(1), RemoteC(1));
+
+ let virtual_remoteg : &dyn Fn(_) -> RemoteG<u32> = &RemoteG;
+ assert_eq!(virtual_remoteg(1), RemoteG(1));
+}
--- /dev/null
+fn main() {
+ let _ = &&[0] as &[_];
+ //~^ ERROR non-primitive cast: `&&[i32; 1]` as `&[_]`
+ let _ = 7u32 as Option<_>;
+ //~^ ERROR non-primitive cast: `u32` as `Option<_>`
+}
--- /dev/null
+error[E0605]: non-primitive cast: `&&[i32; 1]` as `&[_]`
+ --> $DIR/issue-73886.rs:2:13
+ |
+LL | let _ = &&[0] as &[_];
+ | ^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+
+error[E0605]: non-primitive cast: `u32` as `Option<_>`
+ --> $DIR/issue-73886.rs:4:13
+ |
+LL | let _ = 7u32 as Option<_>;
+ | ^^^^^^^^^^^^^^^^^ help: consider using the `From` trait instead: `Option<_>::from(7u32)`
+ |
+ = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0605`.
extern crate trait_impl_conflict;
use trait_impl_conflict::Foo;
-impl<A> Foo for A {
- //~^ ERROR E0119
- //~| ERROR E0210
+impl<A> Foo for A { //~ ERROR E0210
}
fn main() {
-error[E0119]: conflicting implementations of trait `trait_impl_conflict::Foo` for type `isize`
- --> $DIR/coherence-cross-crate-conflict.rs:9:1
- |
-LL | impl<A> Foo for A {
- | ^^^^^^^^^^^^^^^^^
- |
- = note: conflicting implementation in crate `trait_impl_conflict`:
- - impl Foo for isize;
-
error[E0210]: type parameter `A` must be used as the type parameter for some local type (e.g., `MyStruct<A>`)
--> $DIR/coherence-cross-crate-conflict.rs:9:6
|
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
= note: only traits defined in the current crate can be implemented for a type parameter
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors have detailed explanations: E0119, E0210.
-For more information about an error, try `rustc --explain E0119`.
+For more information about this error, try `rustc --explain E0210`.
-error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker1`
- --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:15:1
- |
-LL | impl !Marker1 for dyn Object + Marker2 { }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1`
-
-error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker2`
- --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:17:1
- |
-LL | impl !Marker2 for dyn Object + Marker2 { }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker2`
-
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:23:1
|
LL | impl !Send for dyn Object + Marker2 {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type
+error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker1`
+ --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:15:1
+ |
+LL | impl !Marker1 for dyn Object + Marker2 { }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1`
+
+error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker2`
+ --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:17:1
+ |
+LL | impl !Marker2 for dyn Object + Marker2 { }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker2`
+
error: aborting due to 5 previous errors
Some errors have detailed explanations: E0117, E0321, E0371.
-error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker1`
- --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:15:1
- |
-LL | impl Marker1 for dyn Object + Marker2 { }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1`
-
-error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker2`
- --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:17:1
- |
-LL | impl Marker2 for dyn Object + Marker2 { }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker2`
-
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:23:1
|
LL | unsafe impl Send for dyn Object + Marker2 {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type
+error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker1`
+ --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:15:1
+ |
+LL | impl Marker1 for dyn Object + Marker2 { }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1`
+
+error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker2`
+ --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:17:1
+ |
+LL | impl Marker2 for dyn Object + Marker2 { }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker2`
+
error: aborting due to 5 previous errors
Some errors have detailed explanations: E0117, E0321, E0371.
use std::marker::Copy;
impl Copy for i32 {}
-//~^ ERROR E0119
-//~| ERROR E0117
+//~^ ERROR E0117
enum TestE {
A
}
//~^ ERROR E0206
//~| ERROR E0117
impl Copy for &'static [NotSync] {}
-//~^ ERROR E0119
-//~| ERROR E0117
+//~^ ERROR E0117
fn main() {
}
-error[E0119]: conflicting implementations of trait `std::marker::Copy` for type `i32`
- --> $DIR/coherence-impls-copy.rs:5:1
- |
-LL | impl Copy for i32 {}
- | ^^^^^^^^^^^^^^^^^
- |
- = note: conflicting implementation in crate `core`:
- - impl Copy for i32;
-
-error[E0119]: conflicting implementations of trait `std::marker::Copy` for type `&NotSync`
- --> $DIR/coherence-impls-copy.rs:29:1
- |
-LL | impl Copy for &'static NotSync {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: conflicting implementation in crate `core`:
- - impl<T> Copy for &T
- where T: ?Sized;
-
-error[E0119]: conflicting implementations of trait `std::marker::Copy` for type `&[NotSync]`
- --> $DIR/coherence-impls-copy.rs:34:1
- |
-LL | impl Copy for &'static [NotSync] {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: conflicting implementation in crate `core`:
- - impl<T> Copy for &T
- where T: ?Sized;
-
-error[E0206]: the trait `Copy` may not be implemented for this type
- --> $DIR/coherence-impls-copy.rs:22:15
- |
-LL | impl Copy for &'static mut MyType {}
- | ^^^^^^^^^^^^^^^^^^^ type is not a structure or enumeration
-
-error[E0206]: the trait `Copy` may not be implemented for this type
- --> $DIR/coherence-impls-copy.rs:26:15
- |
-LL | impl Copy for (MyType, MyType) {}
- | ^^^^^^^^^^^^^^^^ type is not a structure or enumeration
-
-error[E0206]: the trait `Copy` may not be implemented for this type
- --> $DIR/coherence-impls-copy.rs:31:15
- |
-LL | impl Copy for [MyType] {}
- | ^^^^^^^^ type is not a structure or enumeration
-
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> $DIR/coherence-impls-copy.rs:5:1
|
= note: define and implement a trait or new type instead
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
- --> $DIR/coherence-impls-copy.rs:26:1
+ --> $DIR/coherence-impls-copy.rs:25:1
|
LL | impl Copy for (MyType, MyType) {}
| ^^^^^^^^^^^^^^----------------
= note: define and implement a trait or new type instead
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
- --> $DIR/coherence-impls-copy.rs:31:1
+ --> $DIR/coherence-impls-copy.rs:30:1
|
LL | impl Copy for [MyType] {}
| ^^^^^^^^^^^^^^--------
= note: define and implement a trait or new type instead
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
- --> $DIR/coherence-impls-copy.rs:34:1
+ --> $DIR/coherence-impls-copy.rs:33:1
|
LL | impl Copy for &'static [NotSync] {}
| ^^^^^^^^^^^^^^------------------
|
= note: define and implement a trait or new type instead
-error: aborting due to 10 previous errors
+error[E0119]: conflicting implementations of trait `std::marker::Copy` for type `&NotSync`
+ --> $DIR/coherence-impls-copy.rs:28:1
+ |
+LL | impl Copy for &'static NotSync {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: conflicting implementation in crate `core`:
+ - impl<T> Copy for &T
+ where T: ?Sized;
+
+error[E0206]: the trait `Copy` may not be implemented for this type
+ --> $DIR/coherence-impls-copy.rs:21:15
+ |
+LL | impl Copy for &'static mut MyType {}
+ | ^^^^^^^^^^^^^^^^^^^ type is not a structure or enumeration
+
+error[E0206]: the trait `Copy` may not be implemented for this type
+ --> $DIR/coherence-impls-copy.rs:25:15
+ |
+LL | impl Copy for (MyType, MyType) {}
+ | ^^^^^^^^^^^^^^^^ type is not a structure or enumeration
+
+error[E0206]: the trait `Copy` may not be implemented for this type
+ --> $DIR/coherence-impls-copy.rs:30:15
+ |
+LL | impl Copy for [MyType] {}
+ | ^^^^^^^^ type is not a structure or enumeration
+
+error: aborting due to 8 previous errors
Some errors have detailed explanations: E0117, E0119, E0206.
For more information about an error, try `rustc --explain E0117`.
//~^ ERROR E0117
unsafe impl Send for &'static [NotSync] {}
-//~^ ERROR conflicting implementations of trait
-//~| ERROR only traits defined in the current crate
+//~^ ERROR only traits defined in the current crate
fn main() {}
-error[E0119]: conflicting implementations of trait `std::marker::Send` for type `&[NotSync]`
- --> $DIR/coherence-impls-send.rs:25:1
- |
-LL | unsafe impl Send for &'static [NotSync] {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: conflicting implementation in crate `core`:
- - impl<T> Send for &T
- where T: Sync, T: ?Sized;
- = note: upstream crates may add a new impl of trait `std::marker::Sync` for type `[NotSync]` in future versions
-
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> $DIR/coherence-impls-send.rs:16:1
|
|
= note: define and implement a trait or new type instead
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
-Some errors have detailed explanations: E0117, E0119, E0321.
+Some errors have detailed explanations: E0117, E0321.
For more information about an error, try `rustc --explain E0117`.
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+ --> $DIR/coherence-impls-sized.rs:20:1
+ |
+LL | impl Sized for (MyType, MyType) {}
+ | ^^^^^^^^^^^^^^^----------------
+ | | |
+ | | this is not defined in the current crate because tuples are always foreign
+ | impl doesn't use only types from inside the current crate
+ |
+ = note: define and implement a trait or new type instead
+
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+ --> $DIR/coherence-impls-sized.rs:27:1
+ |
+LL | impl Sized for [MyType] {}
+ | ^^^^^^^^^^^^^^^--------
+ | | |
+ | | this is not defined in the current crate because slices are always foreign
+ | impl doesn't use only types from inside the current crate
+ |
+ = note: define and implement a trait or new type instead
+
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+ --> $DIR/coherence-impls-sized.rs:31:1
+ |
+LL | impl Sized for &'static [NotSync] {}
+ | ^^^^^^^^^^^^^^^------------------
+ | | |
+ | | this is not defined in the current crate because slices are always foreign
+ | impl doesn't use only types from inside the current crate
+ |
+ = note: define and implement a trait or new type instead
+
error[E0322]: explicit impls for the `Sized` trait are not permitted
--> $DIR/coherence-impls-sized.rs:14:1
|
LL | impl Sized for &'static [NotSync] {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of 'Sized' not allowed
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
- --> $DIR/coherence-impls-sized.rs:20:1
- |
-LL | impl Sized for (MyType, MyType) {}
- | ^^^^^^^^^^^^^^^----------------
- | | |
- | | this is not defined in the current crate because tuples are always foreign
- | impl doesn't use only types from inside the current crate
- |
- = note: define and implement a trait or new type instead
-
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
- --> $DIR/coherence-impls-sized.rs:27:1
- |
-LL | impl Sized for [MyType] {}
- | ^^^^^^^^^^^^^^^--------
- | | |
- | | this is not defined in the current crate because slices are always foreign
- | impl doesn't use only types from inside the current crate
- |
- = note: define and implement a trait or new type instead
-
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
- --> $DIR/coherence-impls-sized.rs:31:1
- |
-LL | impl Sized for &'static [NotSync] {}
- | ^^^^^^^^^^^^^^^------------------
- | | |
- | | this is not defined in the current crate because slices are always foreign
- | impl doesn't use only types from inside the current crate
- |
- = note: define and implement a trait or new type instead
-
error: aborting due to 9 previous errors
Some errors have detailed explanations: E0117, E0322.
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
- --> $DIR/coherence-orphan.rs:10:1
+ --> $DIR/coherence-orphan.rs:17:1
|
-LL | impl TheTrait<usize> for isize { }
- | ^^^^^---------------^^^^^-----
- | | | |
- | | | `isize` is not defined in the current crate
- | | `usize` is not defined in the current crate
+LL | impl !Send for Vec<isize> { }
+ | ^^^^^^^^^^^^^^^----------
+ | | |
+ | | `Vec` is not defined in the current crate
| impl doesn't use only types from inside the current crate
|
= note: define and implement a trait or new type instead
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
- --> $DIR/coherence-orphan.rs:17:1
+ --> $DIR/coherence-orphan.rs:10:1
|
-LL | impl !Send for Vec<isize> { }
- | ^^^^^^^^^^^^^^^----------
- | | |
- | | `Vec` is not defined in the current crate
+LL | impl TheTrait<usize> for isize { }
+ | ^^^^^---------------^^^^^-----
+ | | | |
+ | | | `isize` is not defined in the current crate
+ | | `usize` is not defined in the current crate
| impl doesn't use only types from inside the current crate
|
= note: define and implement a trait or new type instead
// ignore-sgx no processes
#![feature(process_exec, rustc_private)]
+extern crate libc;
+
use std::env;
use std::io::Error;
use std::os::unix::process::CommandExt;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
-#[cfg(not(target_os = "linux"))]
-fn getpid() -> u32 {
- use std::process;
- process::id()
-}
-
-/// We need to directly use the getpid syscall instead of using `process::id()`
-/// because the libc wrapper might return incorrect values after a process was
-/// forked.
-#[cfg(target_os = "linux")]
-fn getpid() -> u32 {
- extern crate libc;
- unsafe {
- libc::syscall(libc::SYS_getpid) as _
- }
-}
-
fn main() {
if let Some(arg) = env::args().nth(1) {
match &arg[..] {
};
assert_eq!(output.raw_os_error(), Some(102));
- let pid = getpid();
+ let pid = unsafe { libc::getpid() };
+ assert!(pid >= 0);
let output = unsafe {
Command::new(&me)
.arg("empty")
.pre_exec(move || {
- let child = getpid();
+ let child = libc::getpid();
+ assert!(child >= 0);
assert!(pid != child);
Ok(())
})
--- /dev/null
+pub struct A;
+impl From<fn((), (), &())> for A {
+ fn from(_: fn((), (), &mut ())) -> Self {
+ //~^ error: method `from` has an incompatible type for trait
+ loop {}
+ }
+}
+
+pub struct B;
+impl From<fn((), (), u32)> for B {
+ fn from(_: fn((), (), u64)) -> Self {
+ //~^ error: method `from` has an incompatible type for trait
+ loop {}
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0053]: method `from` has an incompatible type for trait
+ --> $DIR/issue-90444.rs:3:16
+ |
+LL | fn from(_: fn((), (), &mut ())) -> Self {
+ | ^^^^^^^^^^^^^^^^^^^
+ | |
+ | types differ in mutability
+ | help: change the parameter type to match the trait: `for<'r> fn((), (), &'r ())`
+ |
+ = note: expected fn pointer `fn(for<'r> fn((), (), &'r ())) -> A`
+ found fn pointer `fn(for<'r> fn((), (), &'r mut ())) -> A`
+
+error[E0053]: method `from` has an incompatible type for trait
+ --> $DIR/issue-90444.rs:11:16
+ |
+LL | fn from(_: fn((), (), u64)) -> Self {
+ | ^^^^^^^^^^^^^^^
+ | |
+ | expected `u32`, found `u64`
+ | help: change the parameter type to match the trait: `fn((), (), u32)`
+ |
+ = note: expected fn pointer `fn(fn((), (), u32)) -> B`
+ found fn pointer `fn(fn((), (), u64)) -> B`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0053`.
--- /dev/null
+// check-pass
+
+macro_rules! m {
+ () => { #[cfg(any())] fn f() {} }
+}
+
+trait T {}
+impl T for () { m!(); }
+
+fn main() {}
--- /dev/null
+#![feature(rustc_attrs)]
+
+#[rustc_legacy_const_generics(1)]
+pub fn foo<const Y: usize>(x: usize, z: usize) -> [usize; 3] {
+ [x, Y, z]
+}
|
LL | assert_eq!(f::<4usize>(Usizable), 20usize);
| ^^^^^^ explicit generic argument not allowed
+ |
+ = note: see issue #83701 <https://github.com/rust-lang/rust/issues/83701> for more information
+ = help: add `#![feature(explicit_generic_args_with_impl_trait)]` to the crate attributes to enable
error: aborting due to previous error
--- /dev/null
+// aux-build:legacy-const-generics.rs
+
+extern crate legacy_const_generics;
+
+fn foo<const N: usize>() {
+ let a = 1;
+ legacy_const_generics::foo(0, a, 2);
+ //~^ ERROR attempt to use a non-constant value in a constant
+
+ legacy_const_generics::foo(0, N, 2);
+
+ legacy_const_generics::foo(0, N + 1, 2);
+ //~^ ERROR generic parameters may not be used in const operations
+}
+
+fn main() {}
--- /dev/null
+error[E0435]: attempt to use a non-constant value in a constant
+ --> $DIR/legacy-const-generics-bad.rs:7:35
+ |
+LL | let a = 1;
+ | ----- help: consider using `const` instead of `let`: `const a`
+LL | legacy_const_generics::foo(0, a, 2);
+ | ^ non-constant value
+
+error: generic parameters may not be used in const operations
+ --> $DIR/legacy-const-generics-bad.rs:12:35
+ |
+LL | legacy_const_generics::foo(0, N + 1, 2);
+ | ^ cannot perform const operation using `N`
+ |
+ = help: const parameters may only be used as standalone arguments, i.e. `N`
+ = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0435`.
--- /dev/null
+// aux-build:legacy-const-generics.rs
+// run-pass
+
+#![feature(rustc_attrs)]
+
+extern crate legacy_const_generics;
+
+#[rustc_legacy_const_generics(1)]
+pub fn bar<const Y: usize>(x: usize, z: usize) -> [usize; 3] {
+ [x, Y, z]
+}
+
+fn main() {
+ assert_eq!(legacy_const_generics::foo(0 + 0, 1 + 1, 2 + 2), [0, 2, 4]);
+ assert_eq!(legacy_const_generics::foo::<{1 + 1}>(0 + 0, 2 + 2), [0, 2, 4]);
+ // FIXME: Only works cross-crate
+ //assert_eq!(bar(0, 1, 2), [0, 1, 2]);
+}
+// needs-asm-support
+
#![feature(asm)]
const _: () = unsafe { asm!("nop") };
error[E0015]: inline assembly is not allowed in constants
- --> $DIR/inline_asm.rs:3:24
+ --> $DIR/inline_asm.rs:5:24
|
LL | const _: () = unsafe { asm!("nop") };
| ^^^^^^^^^^^
--- /dev/null
+// run-pass
+#![allow(dead_code)]
+#![allow(non_camel_case_types)]
+
+const JSVAL_TAG_CLEAR: u32 = 0xFFFFFF80;
+const JSVAL_TYPE_INT32: u8 = 0x01;
+const JSVAL_TYPE_UNDEFINED: u8 = 0x02;
+#[repr(u32)]
+enum ValueTag {
+ JSVAL_TAG_INT32 = JSVAL_TAG_CLEAR | (JSVAL_TYPE_INT32 as u32),
+ JSVAL_TAG_UNDEFINED = JSVAL_TAG_CLEAR | (JSVAL_TYPE_UNDEFINED as u32),
+}
+
+fn main() {
+ let _ = ValueTag::JSVAL_TAG_INT32;
+}
--- /dev/null
+// run-pass
+#![allow(dead_code)]
+
+static X2: u64 = !0 as u16 as u64;
+static Y2: u64 = !0 as u32 as u64;
+const X: u64 = !0 as u16 as u64;
+const Y: u64 = !0 as u32 as u64;
+
+fn main() {
+ assert_eq!(match 1 {
+ X => unreachable!(),
+ Y => unreachable!(),
+ _ => 1
+ }, 1);
+}
--- /dev/null
+fn main() {
+ const X: u32 = 1;
+ const Y: usize = unsafe { &X as *const u32 as usize }; //~ ERROR pointers cannot be cast to integers
+ println!("{}", Y);
+}
--- /dev/null
+error: pointers cannot be cast to integers during const eval
+ --> $DIR/issue-18294.rs:3:31
+ |
+LL | const Y: usize = unsafe { &X as *const u32 as usize };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: at compile-time, pointers do not have an integer value
+ = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
+
+error: aborting due to previous error
+
--- /dev/null
+// run-pass
+const U8_MAX_HALF: u8 = !0u8 / 2;
+const U16_MAX_HALF: u16 = !0u16 / 2;
+const U32_MAX_HALF: u32 = !0u32 / 2;
+const U64_MAX_HALF: u64 = !0u64 / 2;
+
+fn main() {
+ assert_eq!(U8_MAX_HALF, 0x7f);
+ assert_eq!(U16_MAX_HALF, 0x7fff);
+ assert_eq!(U32_MAX_HALF, 0x7fff_ffff);
+ assert_eq!(U64_MAX_HALF, 0x7fff_ffff_ffff_ffff);
+}
--- /dev/null
+const fn x() {
+ let t = true;
+ let x = || t; //~ ERROR function pointer
+}
+
+fn main() {}
--- /dev/null
+error[E0658]: function pointers cannot appear in constant functions
+ --> $DIR/issue-37550-1.rs:3:9
+ |
+LL | let x = || t;
+ | ^
+ |
+ = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+ = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// run-pass
+
+const fn foo() -> i64 {
+ 3
+}
+
+const fn bar(x: i64) -> i64 {
+ x*2
+}
+
+fn main() {
+ let val = &(foo() % 2);
+ assert_eq!(*val, 1);
+
+ let val2 = &(bar(1+1) % 3);
+ assert_eq!(*val2, 1);
+}
--- /dev/null
+// compile-flags: --crate-type lib --extern foo={{src-base}}/crate-loading/auxiliary/libfoo.rlib
+// normalize-stderr-test: "failed to mmap file '.*auxiliary/libfoo.rlib':.*" -> "failed to mmap file 'auxiliary/libfoo.rlib'"
+// don't emit warn logging, it's basically the same as the errors and it's annoying to normalize
+// rustc-env:RUSTC_LOG=error
+// edition:2018
+#![no_std]
+use ::foo; //~ ERROR invalid metadata files for crate `foo`
+//~| NOTE failed to mmap file
--- /dev/null
+error[E0786]: found invalid metadata files for crate `foo`
+ --> $DIR/invalid-rlib.rs:7:7
+ |
+LL | use ::foo;
+ | ^^^
+ |
+ = note: failed to mmap file 'auxiliary/libfoo.rlib'
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0786`.
let _ = nested::DeprecatedStruct {
//~^ ERROR use of deprecated struct `this_crate::nested::DeprecatedStruct`: text
i: 0 //~ ERROR use of deprecated field `this_crate::nested::DeprecatedStruct::i`: text
+ //~| ERROR field `i` of struct `this_crate::nested::DeprecatedStruct` is private
};
let _ = nested::DeprecatedUnitStruct; //~ ERROR use of deprecated unit struct `this_crate::nested::DeprecatedUnitStruct`: text
| ^^^^^^^^^^^^^^^^
error: use of deprecated unit struct `this_crate::nested::DeprecatedUnitStruct`: text
- --> $DIR/deprecation-lint.rs:283:25
+ --> $DIR/deprecation-lint.rs:284:25
|
LL | let _ = nested::DeprecatedUnitStruct;
| ^^^^^^^^^^^^^^^^^^^^
error: use of deprecated unit variant `this_crate::nested::Enum::DeprecatedVariant`: text
- --> $DIR/deprecation-lint.rs:285:31
+ --> $DIR/deprecation-lint.rs:286:31
|
LL | ... let _ = nested::Enum::DeprecatedVariant;
| ^^^^^^^^^^^^^^^^^
error: use of deprecated tuple struct `this_crate::nested::DeprecatedTupleStruct`: text
- --> $DIR/deprecation-lint.rs:287:25
+ --> $DIR/deprecation-lint.rs:288:25
|
LL | ... let _ = nested::DeprecatedTupleStruct (1);
| ^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text
- --> $DIR/deprecation-lint.rs:292:16
+ --> $DIR/deprecation-lint.rs:293:16
|
LL | Trait::trait_deprecated(&foo);
| ^^^^^^^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text
- --> $DIR/deprecation-lint.rs:294:25
+ --> $DIR/deprecation-lint.rs:295:25
|
LL | <Foo as Trait>::trait_deprecated(&foo);
| ^^^^^^^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
- --> $DIR/deprecation-lint.rs:296:16
+ --> $DIR/deprecation-lint.rs:297:16
|
LL | Trait::trait_deprecated_text(&foo);
| ^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
- --> $DIR/deprecation-lint.rs:298:25
+ --> $DIR/deprecation-lint.rs:299:25
|
LL | ... <Foo as Trait>::trait_deprecated_text(&foo);
| ^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated function `this_crate::test_fn_closure_body::{closure#0}::bar`
- --> $DIR/deprecation-lint.rs:316:13
+ --> $DIR/deprecation-lint.rs:317:13
|
LL | bar();
| ^^^
error: use of deprecated trait `this_crate::DeprecatedTrait`: text
- --> $DIR/deprecation-lint.rs:335:10
+ --> $DIR/deprecation-lint.rs:336:10
|
LL | impl DeprecatedTrait for S { }
| ^^^^^^^^^^^^^^^
error: use of deprecated trait `this_crate::DeprecatedTrait`: text
- --> $DIR/deprecation-lint.rs:337:24
+ --> $DIR/deprecation-lint.rs:338:24
|
LL | trait LocalTrait : DeprecatedTrait { }
| ^^^^^^^^^^^^^^^
error: use of deprecated struct `this_crate2::Deprecated`: text
- --> $DIR/deprecation-lint.rs:389:17
+ --> $DIR/deprecation-lint.rs:390:17
|
LL | let x = Deprecated {
| ^^^^^^^^^^
error: use of deprecated struct `this_crate2::Deprecated`: text
- --> $DIR/deprecation-lint.rs:398:13
+ --> $DIR/deprecation-lint.rs:399:13
|
LL | let Deprecated {
| ^^^^^^^^^^
error: use of deprecated struct `this_crate2::Deprecated`: text
- --> $DIR/deprecation-lint.rs:404:13
+ --> $DIR/deprecation-lint.rs:405:13
|
LL | let Deprecated
| ^^^^^^^^^^
error: use of deprecated tuple struct `this_crate2::Deprecated2`: text
- --> $DIR/deprecation-lint.rs:409:17
+ --> $DIR/deprecation-lint.rs:410:17
|
LL | let x = Deprecated2(1, 2, 3);
| ^^^^^^^^^^^
error: use of deprecated tuple struct `this_crate2::Deprecated2`: text
- --> $DIR/deprecation-lint.rs:419:13
+ --> $DIR/deprecation-lint.rs:420:13
|
LL | let Deprecated2
| ^^^^^^^^^^^
error: use of deprecated tuple struct `this_crate2::Deprecated2`: text
- --> $DIR/deprecation-lint.rs:428:13
+ --> $DIR/deprecation-lint.rs:429:13
|
LL | let Deprecated2
| ^^^^^^^^^^^
| ^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text
- --> $DIR/deprecation-lint.rs:291:13
+ --> $DIR/deprecation-lint.rs:292:13
|
LL | foo.trait_deprecated();
| ^^^^^^^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text
- --> $DIR/deprecation-lint.rs:293:16
+ --> $DIR/deprecation-lint.rs:294:16
|
LL | <Foo>::trait_deprecated(&foo);
| ^^^^^^^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
- --> $DIR/deprecation-lint.rs:295:13
+ --> $DIR/deprecation-lint.rs:296:13
|
LL | foo.trait_deprecated_text();
| ^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
- --> $DIR/deprecation-lint.rs:297:16
+ --> $DIR/deprecation-lint.rs:298:16
|
LL | <Foo>::trait_deprecated_text(&foo);
| ^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text
- --> $DIR/deprecation-lint.rs:302:13
+ --> $DIR/deprecation-lint.rs:303:13
|
LL | foo.trait_deprecated();
| ^^^^^^^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
- --> $DIR/deprecation-lint.rs:303:13
+ --> $DIR/deprecation-lint.rs:304:13
|
LL | foo.trait_deprecated_text();
| ^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated field `this_crate2::Stable::override2`: text
- --> $DIR/deprecation-lint.rs:362:13
+ --> $DIR/deprecation-lint.rs:363:13
|
LL | override2: 3,
| ^^^^^^^^^^^^
error: use of deprecated field `this_crate2::Stable::override2`: text
- --> $DIR/deprecation-lint.rs:366:17
+ --> $DIR/deprecation-lint.rs:367:17
|
LL | let _ = x.override2;
| ^^^^^^^^^^^
error: use of deprecated field `this_crate2::Stable::override2`: text
- --> $DIR/deprecation-lint.rs:370:13
+ --> $DIR/deprecation-lint.rs:371:13
|
LL | override2: _
| ^^^^^^^^^^^^
error: use of deprecated field `this_crate2::Stable2::2`: text
- --> $DIR/deprecation-lint.rs:378:17
+ --> $DIR/deprecation-lint.rs:379:17
|
LL | let _ = x.2;
| ^^^
error: use of deprecated field `this_crate2::Stable2::2`: text
- --> $DIR/deprecation-lint.rs:383:20
+ --> $DIR/deprecation-lint.rs:384:20
|
LL | _)
| ^
error: use of deprecated field `this_crate2::Deprecated::inherit`: text
- --> $DIR/deprecation-lint.rs:391:13
+ --> $DIR/deprecation-lint.rs:392:13
|
LL | inherit: 1,
| ^^^^^^^^^^
error: use of deprecated field `this_crate2::Deprecated::inherit`: text
- --> $DIR/deprecation-lint.rs:395:17
+ --> $DIR/deprecation-lint.rs:396:17
|
LL | let _ = x.inherit;
| ^^^^^^^^^
error: use of deprecated field `this_crate2::Deprecated::inherit`: text
- --> $DIR/deprecation-lint.rs:400:13
+ --> $DIR/deprecation-lint.rs:401:13
|
LL | inherit: _,
| ^^^^^^^^^^
error: use of deprecated field `this_crate2::Deprecated2::0`: text
- --> $DIR/deprecation-lint.rs:412:17
+ --> $DIR/deprecation-lint.rs:413:17
|
LL | let _ = x.0;
| ^^^
error: use of deprecated field `this_crate2::Deprecated2::1`: text
- --> $DIR/deprecation-lint.rs:414:17
+ --> $DIR/deprecation-lint.rs:415:17
|
LL | let _ = x.1;
| ^^^
error: use of deprecated field `this_crate2::Deprecated2::2`: text
- --> $DIR/deprecation-lint.rs:416:17
+ --> $DIR/deprecation-lint.rs:417:17
|
LL | let _ = x.2;
| ^^^
error: use of deprecated field `this_crate2::Deprecated2::0`: text
- --> $DIR/deprecation-lint.rs:421:14
+ --> $DIR/deprecation-lint.rs:422:14
|
LL | (_,
| ^
error: use of deprecated field `this_crate2::Deprecated2::1`: text
- --> $DIR/deprecation-lint.rs:423:14
+ --> $DIR/deprecation-lint.rs:424:14
|
LL | _,
| ^
error: use of deprecated field `this_crate2::Deprecated2::2`: text
- --> $DIR/deprecation-lint.rs:425:14
+ --> $DIR/deprecation-lint.rs:426:14
|
LL | _)
| ^
-error: aborting due to 122 previous errors
+error[E0451]: field `i` of struct `this_crate::nested::DeprecatedStruct` is private
+ --> $DIR/deprecation-lint.rs:280:13
+ |
+LL | i: 0
+ | ^^^^ private field
+
+error: aborting due to 123 previous errors
+For more information about this error, try `rustc --explain E0451`.
--- /dev/null
+// compile-flags: --edition 2018
+fn foo() -> Result<(), ()> {
+ Ok(try!()); //~ ERROR use of deprecated `try` macro
+ Ok(try!(Ok(()))) //~ ERROR use of deprecated `try` macro
+}
+
+fn main() {
+ let _ = foo();
+}
--- /dev/null
+error: use of deprecated `try` macro
+ --> $DIR/try-macro-suggestion.rs:3:8
+ |
+LL | Ok(try!());
+ | ^^^^^^
+ |
+ = note: in the 2018 edition `try` is a reserved keyword, and the `try!()` macro is deprecated
+help: you can still access the deprecated `try!()` macro using the "raw identifier" syntax
+ |
+LL | Ok(r#try!());
+ | ++
+
+error: use of deprecated `try` macro
+ --> $DIR/try-macro-suggestion.rs:4:8
+ |
+LL | Ok(try!(Ok(())))
+ | ^^^^^^^^^^^^
+ |
+ = note: in the 2018 edition `try` is a reserved keyword, and the `try!()` macro is deprecated
+help: you can use the `?` operator instead
+ |
+LL - Ok(try!(Ok(())))
+LL + Ok(Ok(())?)
+ |
+help: alternatively, you can still access the deprecated `try!()` macro using the "raw identifier" syntax
+ |
+LL | Ok(r#try!(Ok(())))
+ | ++
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+// run-pass
+
+#![allow(dead_code)]
+
+trait Trait { fn dummy(&self) { } }
+
+#[derive(Debug)]
+struct Foo<T: Trait> {
+ foo: T,
+}
+
+#[derive(Debug)]
+struct Bar<T> where T: Trait {
+ bar: T,
+}
+
+impl Trait for isize {}
+
+fn main() {
+ let a = Foo { foo: 12 };
+ let b = Bar { bar: 12 };
+ println!("{:?} {:?}", a, b);
+}
--- /dev/null
+// run-pass
+fn main() {}
+#[derive(Clone)]
+pub struct Little;
+#[derive(Clone)]
+pub struct Big(
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+);
+++ /dev/null
-// After #39485, this test used to pass, but that change was reverted
-// due to numerous inference failures like #39808, so it now fails
-// again. #39485 made it so that diverging types never propagate
-// upward; but we now do propagate such types upward in many more
-// cases.
-
-fn g() {
- &panic!() //~ ERROR mismatched types
-}
-
-fn f() -> isize {
- (return 1, return 2) //~ ERROR mismatched types
-}
-
-fn main() {}
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/diverging-tuple-parts-39485.rs:8:5
- |
-LL | &panic!()
- | ^^^^^^^^^ expected `()`, found reference
- |
- = note: expected unit type `()`
- found reference `&_`
-help: try adding a return type
- |
-LL | fn g() -> &_ {
- | +++++
-help: consider removing the borrow
- |
-LL - &panic!()
-LL + panic!()
- |
-
-error[E0308]: mismatched types
- --> $DIR/diverging-tuple-parts-39485.rs:12:5
- |
-LL | fn f() -> isize {
- | ----- expected `isize` because of return type
-LL | (return 1, return 2)
- | ^^^^^^^^^^^^^^^^^^^^ expected `isize`, found tuple
- |
- = note: expected type `isize`
- found tuple `(!, !)`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// build-pass
+#![allow(dead_code)]
+// Regression test for #35546. Check that we are able to codegen
+// this. Before we had problems because of the drop glue signature
+// around dropping a trait object (specifically, when dropping the
+// `value` field of `Node<Send>`).
+
+struct Node<T: ?Sized + Send> {
+ next: Option<Box<Node<dyn Send>>>,
+ value: T,
+}
+
+fn clear(head: &mut Option<Box<Node<dyn Send>>>) {
+ match head.take() {
+ Some(node) => *head = node.next,
+ None => (),
+ }
+}
+
+fn main() {}
--- /dev/null
+// run-pass
+// ignore-emscripten no threads support
+
+// Issue #787
+// Don't try to clean up uninitialized locals
+
+
+use std::thread;
+
+fn test_break() { loop { let _x: Box<isize> = break; } }
+
+fn test_cont() { let mut i = 0; while i < 1 { i += 1; let _x: Box<isize> = continue; } }
+
+fn test_ret() { let _x: Box<isize> = return; }
+
+fn test_panic() {
+ fn f() { let _x: Box<isize> = panic!(); }
+ thread::spawn(move|| f() ).join().unwrap_err();
+}
+
+fn test_panic_indirect() {
+ fn f() -> ! { panic!(); }
+ fn g() { let _x: Box<isize> = f(); }
+ thread::spawn(move|| g() ).join().unwrap_err();
+}
+
+pub fn main() {
+ test_break();
+ test_cont();
+ test_ret();
+ test_panic();
+ test_panic_indirect();
+}
LL | impl Drop for Nonexistent {
| ^^^^^^^^^^^ not found in this scope
-error[E0120]: the `Drop` trait may only be implemented for structs, enums, and unions
- --> $DIR/drop-on-non-struct.rs:1:19
- |
-LL | impl<'a> Drop for &'a mut isize {
- | ^^^^^^^^^^^^^ must be a struct, enum, or union
-
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> $DIR/drop-on-non-struct.rs:1:1
|
|
= note: define and implement a trait or new type instead
+error[E0120]: the `Drop` trait may only be implemented for structs, enums, and unions
+ --> $DIR/drop-on-non-struct.rs:1:19
+ |
+LL | impl<'a> Drop for &'a mut isize {
+ | ^^^^^^^^^^^^^ must be a struct, enum, or union
+
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0117, E0120, E0412.
--- /dev/null
+// run-pass
+
+// Demonstrate the use of the unguarded escape hatch with a type param in negative position
+// to assert that destructor will not access any dead data.
+//
+// Compare with ui/span/issue28498-reject-lifetime-param.rs
+
+// Demonstrate that a type param in negative position causes dropck to reject code
+// that might indirectly access previously dropped value.
+//
+// Compare with run-pass/issue28498-ugeh-with-passed-to-fn.rs
+
+#![feature(dropck_eyepatch)]
+
+#[derive(Debug)]
+struct ScribbleOnDrop(String);
+
+impl Drop for ScribbleOnDrop {
+ fn drop(&mut self) {
+ self.0 = format!("DROPPED");
+ }
+}
+
+struct Foo<T>(u32, T, Box<for <'r> fn(&'r T) -> String>);
+
+unsafe impl<#[may_dangle] T> Drop for Foo<T> {
+ fn drop(&mut self) {
+ // Use of `may_dangle` is sound, because destructor never passes a `self.1`
+ // to the callback (in `self.2`) despite having it available.
+ println!("Dropping Foo({}, _)", self.0);
+ }
+}
+
+fn callback(s: & &ScribbleOnDrop) -> String { format!("{:?}", s) }
+
+fn main() {
+ let (last_dropped, foo0);
+ let (foo1, first_dropped);
+
+ last_dropped = ScribbleOnDrop(format!("last"));
+ first_dropped = ScribbleOnDrop(format!("first"));
+ foo0 = Foo(0, &last_dropped, Box::new(callback));
+ foo1 = Foo(1, &first_dropped, Box::new(callback));
+
+ println!("foo0.1: {:?} foo1.1: {:?}", foo0.1, foo1.1);
+}
+++ /dev/null
-// edition:2015
-
-mod inner {
- fn global_inner(_: ::nonexistant::Foo) {
- //~^ ERROR failed to resolve: maybe a missing crate `nonexistant`?
- }
- fn crate_inner(_: crate::nonexistant::Foo) {
- //~^ ERROR failed to resolve: maybe a missing crate `nonexistant`?
- }
-
- fn bare_global(_: ::nonexistant) {
- //~^ ERROR cannot find type `nonexistant` in the crate root
- }
- fn bare_crate(_: crate::nonexistant) {
- //~^ ERROR cannot find type `nonexistant` in the crate root
- }
-}
-
-fn main() {
-
-}
+++ /dev/null
-error[E0433]: failed to resolve: maybe a missing crate `nonexistant`?
- --> $DIR/editions-crate-root-2015.rs:4:26
- |
-LL | fn global_inner(_: ::nonexistant::Foo) {
- | ^^^^^^^^^^^ maybe a missing crate `nonexistant`?
-
-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`?
-
-error[E0412]: cannot find type `nonexistant` in the crate root
- --> $DIR/editions-crate-root-2015.rs:11:25
- |
-LL | fn bare_global(_: ::nonexistant) {
- | ^^^^^^^^^^^ not found in the crate root
-
-error[E0412]: cannot find type `nonexistant` in the crate root
- --> $DIR/editions-crate-root-2015.rs:14:29
- |
-LL | fn bare_crate(_: crate::nonexistant) {
- | ^^^^^^^^^^^ not found in the crate root
-
-error: aborting due to 4 previous errors
-
-Some errors have detailed explanations: E0412, E0433.
-For more information about an error, try `rustc --explain E0412`.
--- /dev/null
+// run-pass
+
+#![allow(dead_code)]
+#![allow(unused_variables)]
+// Checks if the correct registers are being used to pass arguments
+// when the sysv64 ABI is specified.
+
+#![feature(rust_2018_preview)]
+
+pub trait Foo {}
+
+// should compile without the dyn trait feature flag
+fn foo(x: &dyn Foo) {}
+
+pub fn main() {}
--- /dev/null
+// run-pass
+#![feature(core_intrinsics)]
+
+#[repr(i8)]
+pub enum Enum {
+ VariantA,
+ VariantB,
+}
+
+fn make_b() -> Enum { Enum::VariantB }
+
+fn main() {
+ assert_eq!(1, make_b() as i8);
+ assert_eq!(1, make_b() as u8);
+ assert_eq!(1, make_b() as i32);
+ assert_eq!(1, make_b() as u32);
+ assert_eq!(1, std::intrinsics::discriminant_value(&make_b()));
+}
--- /dev/null
+// run-pass
+macro_rules! fooN {
+ ($cur:ident $prev:ty) => {
+ #[allow(dead_code)]
+ enum $cur {
+ Empty,
+ First($prev),
+ Second($prev),
+ Third($prev),
+ Fourth($prev),
+ }
+ }
+}
+
+fooN!(Foo0 ());
+fooN!(Foo1 Foo0);
+fooN!(Foo2 Foo1);
+fooN!(Foo3 Foo2);
+fooN!(Foo4 Foo3);
+fooN!(Foo5 Foo4);
+fooN!(Foo6 Foo5);
+fooN!(Foo7 Foo6);
+fooN!(Foo8 Foo7);
+fooN!(Foo9 Foo8);
+fooN!(Foo10 Foo9);
+fooN!(Foo11 Foo10);
+fooN!(Foo12 Foo11);
+fooN!(Foo13 Foo12);
+fooN!(Foo14 Foo13);
+fooN!(Foo15 Foo14);
+fooN!(Foo16 Foo15);
+fooN!(Foo17 Foo16);
+fooN!(Foo18 Foo17);
+fooN!(Foo19 Foo18);
+fooN!(Foo20 Foo19);
+fooN!(Foo21 Foo20);
+fooN!(Foo22 Foo21);
+fooN!(Foo23 Foo22);
+fooN!(Foo24 Foo23);
+fooN!(Foo25 Foo24);
+fooN!(Foo26 Foo25);
+fooN!(Foo27 Foo26);
+
+fn main() {
+ let _foo = Foo27::Empty;
+}
+++ /dev/null
-// run-pass
-
-#![allow(dead_code)]
-#![allow(unused_variables)]
-// Checks if the correct registers are being used to pass arguments
-// when the sysv64 ABI is specified.
-
-#![feature(rust_2018_preview)]
-
-pub trait Foo {}
-
-// should compile without the dyn trait feature flag
-fn foo(x: &dyn Foo) {}
-
-pub fn main() {}
-error[E0120]: the `Drop` trait may only be implemented for structs, enums, and unions
- --> $DIR/E0117.rs:1:15
- |
-LL | impl Drop for u32 {}
- | ^^^ must be a struct, enum, or union
-
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> $DIR/E0117.rs:1:1
|
|
= note: define and implement a trait or new type instead
+error[E0120]: the `Drop` trait may only be implemented for structs, enums, and unions
+ --> $DIR/E0117.rs:1:15
+ |
+LL | impl Drop for u32 {}
+ | ^^^ must be a struct, enum, or union
+
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0117, E0120.
-type Foo = [u8; 256];
-
-impl Copy for Foo { }
-//~^ ERROR the trait `Copy` may not be implemented for this type
-//~| ERROR only traits defined in the current crate can be implemented for arbitrary types
-
#[derive(Copy, Clone)]
struct Bar;
error[E0206]: the trait `Copy` may not be implemented for this type
- --> $DIR/E0206.rs:3:15
- |
-LL | impl Copy for Foo { }
- | ^^^ type is not a structure or enumeration
-
-error[E0206]: the trait `Copy` may not be implemented for this type
- --> $DIR/E0206.rs:10:15
+ --> $DIR/E0206.rs:4:15
|
LL | impl Copy for &'static mut Bar { }
| ^^^^^^^^^^^^^^^^ type is not a structure or enumeration
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
- --> $DIR/E0206.rs:3:1
- |
-LL | impl Copy for Foo { }
- | ^^^^^^^^^^^^^^---
- | | |
- | | this is not defined in the current crate because arrays are always foreign
- | impl doesn't use only types from inside the current crate
- |
- = note: define and implement a trait or new type instead
-
-error: aborting due to 3 previous errors
+error: aborting due to previous error
-Some errors have detailed explanations: E0117, E0206.
-For more information about an error, try `rustc --explain E0117`.
+For more information about this error, try `rustc --explain E0206`.
struct Q;
impl<R> External for (Q, R) {} //~ ERROR only traits defined
-//~^ ERROR conflicting implementations of trait
fn main() {}
-error[E0119]: conflicting implementations of trait `complex_impl_support::External` for type `(Q, complex_impl_support::M<'_, '_, '_, std::boxed::Box<_>, _, _>)`
- --> $DIR/complex-impl.rs:9:1
- |
-LL | impl<R> External for (Q, R) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: conflicting implementation in crate `complex_impl_support`:
- - impl<'a, 'b, 'c, T, U, V, W> External for (T, M<'a, 'b, 'c, Box<U>, V, W>)
- where <U as FnOnce<(T,)>>::Output == V, <V as Iterator>::Item == T, 'b: 'a, T: 'a, U: 'static, U: FnOnce<(T,)>, V: Iterator, V: Clone, W: Add, <W as Add>::Output: Copy;
-
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> $DIR/complex-impl.rs:9:1
|
|
= note: define and implement a trait or new type instead
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors have detailed explanations: E0117, E0119.
-For more information about an error, try `rustc --explain E0117`.
+For more information about this error, try `rustc --explain E0117`.
struct Foo;
impl<Foo> Deref for Foo { } //~ ERROR must be used
-//~^ ERROR conflicting implementations
fn main() {}
-error[E0119]: conflicting implementations of trait `std::ops::Deref` for type `&_`
- --> $DIR/issue-28981.rs:5:1
- |
-LL | impl<Foo> Deref for Foo { }
- | ^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: conflicting implementation in crate `core`:
- - impl<T> Deref for &T
- where T: ?Sized;
-
error[E0210]: type parameter `Foo` must be used as the type parameter for some local type (e.g., `MyStruct<Foo>`)
--> $DIR/issue-28981.rs:5:6
|
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
= note: only traits defined in the current crate can be implemented for a type parameter
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors have detailed explanations: E0119, E0210.
-For more information about an error, try `rustc --explain E0119`.
+For more information about this error, try `rustc --explain E0210`.
--- /dev/null
+error[E0133]: use of extern static is unsafe and requires unsafe function or block
+ --> $DIR/issue-28324.rs:8:24
+ |
+LL | pub static BAZ: u32 = *&error_message_count;
+ | ^^^^^^^^^^^^^^^^^^^^ use of extern static
+ |
+ = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
--- /dev/null
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
+extern "C" {
+ static error_message_count: u32;
+}
+
+pub static BAZ: u32 = *&error_message_count;
+//~^ ERROR use of extern static is unsafe and requires
+
+fn main() {}
--- /dev/null
+error[E0133]: use of extern static is unsafe and requires unsafe function or block
+ --> $DIR/issue-28324.rs:8:25
+ |
+LL | pub static BAZ: u32 = *&error_message_count;
+ | ^^^^^^^^^^^^^^^^^^^ use of extern static
+ |
+ = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
--- /dev/null
+// only-x86_64
+
+#![feature(asm)]
+
+fn main() {
+ unsafe {
+ asm!("mov eax, {}", const 123);
+ //~^ ERROR const operands for inline assembly are unstable
+ }
+}
--- /dev/null
+error[E0658]: const operands for inline assembly are unstable
+ --> $DIR/feature-gate-asm_const.rs:7:29
+ |
+LL | asm!("mov eax, {}", const 123);
+ | ^^^^^^^^^
+ |
+ = note: see issue #72016 <https://github.com/rust-lang/rust/issues/72016> for more information
+ = help: add `#![feature(asm_const)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// compile-flags: --target mips-unknown-linux-gnu
+// needs-llvm-components: mips
+
+#![feature(no_core, lang_items, rustc_attrs)]
+#![crate_type = "rlib"]
+#![no_core]
+
+#[rustc_builtin_macro]
+macro_rules! asm {
+ () => {};
+}
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+unsafe fn main() {
+ asm!("");
+ //~^ ERROR inline assembly is not stable yet on this architecture
+}
--- /dev/null
+error[E0658]: inline assembly is not stable yet on this architecture
+ --> $DIR/feature-gate-asm_experimental_arch.rs:19:5
+ |
+LL | asm!("");
+ | ^^^^^^^^
+ |
+ = note: see issue #72016 <https://github.com/rust-lang/rust/issues/72016> for more information
+ = help: add `#![feature(asm_experimental_arch)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// only-x86_64
+
+#![feature(asm)]
+
+fn main() {
+ unsafe {
+ asm!("mov eax, {}", sym main);
+ //~^ ERROR sym operands for inline assembly are unstable
+ }
+}
--- /dev/null
+error[E0658]: sym operands for inline assembly are unstable
+ --> $DIR/feature-gate-asm_sym.rs:7:29
+ |
+LL | asm!("mov eax, {}", sym main);
+ | ^^^^^^^^
+ |
+ = note: see issue #72016 <https://github.com/rust-lang/rust/issues/72016> for more information
+ = help: add `#![feature(asm_sym)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
+++ /dev/null
-#[derive(Debug)]
-struct Machine<S> {
- state: S,
- common_field1: &'static str,
- common_field2: i32,
-}
-#[derive(Debug)]
-struct State1;
-#[derive(Debug, PartialEq)]
-struct State2;
-
-fn update_to_state2() {
- let m1: Machine<State1> = Machine {
- state: State1,
- common_field1: "hello",
- common_field2: 2,
- };
- let m2: Machine<State2> = Machine {
- state: State2,
- ..m1 //~ ERROR mismatched types
- };
- // FIXME: this should trigger feature gate
- assert_eq!(State2, m2.state);
-}
-
-fn main() {}
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/feature-gate-type_changing_struct_update.rs:20:11
- |
-LL | ..m1
- | ^^ expected struct `State2`, found struct `State1`
- |
- = note: expected struct `Machine<State2>`
- found struct `Machine<State1>`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// run-pass
+#![allow(unreachable_code)]
+
+fn main() {
+ let mut v = Vec::new();
+
+ loop { v.push(break) }
+}
--- /dev/null
+// run-pass
+// pretty-expanded FIXME #23616
+
+#![allow(unused_variables)]
+
+pub fn main() {
+ let mut i: isize = 0;
+ while i < 1000000 {
+ i += 1;
+ let x = 3;
+ }
+}
--- /dev/null
+// run-pass
+
+#![allow(improper_ctypes)]
+#![allow(dead_code)]
+// Issue #901
+// pretty-expanded FIXME #23616
+
+mod libc {
+ extern "C" {
+ pub fn printf(x: ());
+ }
+}
+
+pub fn main() {}
--- /dev/null
+#![feature(generic_associated_types)]
+#![feature(type_alias_impl_trait)]
+
+fn main() {}
+
+trait A<'a> {
+ type B<'b>: Clone
+ // FIXME(generic_associated_types): Remove one of the below bounds
+ // https://github.com/rust-lang/rust/pull/90678#discussion_r744976085
+ where
+ 'a: 'b, Self: 'a, Self: 'b;
+
+ fn a(&'a self) -> Self::B<'a>;
+}
+
+struct C;
+
+impl<'a> A<'a> for C {
+ type B<'b> = impl Clone;
+ //~^ ERROR: lifetime bound not satisfied
+ //~| ERROR: could not find defining uses
+
+ fn a(&'a self) -> Self::B<'a> {} //~ ERROR: non-defining opaque type use in defining scope
+}
--- /dev/null
+error[E0478]: lifetime bound not satisfied
+ --> $DIR/issue-88595.rs:19:5
+ |
+LL | type B<'b> = impl Clone;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: lifetime parameter instantiated with the lifetime `'a` as defined here
+ --> $DIR/issue-88595.rs:18:6
+ |
+LL | impl<'a> A<'a> for C {
+ | ^^
+note: but lifetime parameter must outlive the lifetime `'b` as defined here
+ --> $DIR/issue-88595.rs:19:12
+ |
+LL | type B<'b> = impl Clone;
+ | ^^
+
+error: non-defining opaque type use in defining scope
+ --> $DIR/issue-88595.rs:23:23
+ |
+LL | fn a(&'a self) -> Self::B<'a> {}
+ | ^^^^^^^^^^^
+ |
+note: lifetime used multiple times
+ --> $DIR/issue-88595.rs:18:6
+ |
+LL | impl<'a> A<'a> for C {
+ | ^^
+LL | type B<'b> = impl Clone;
+ | ^^
+
+error: could not find defining uses
+ --> $DIR/issue-88595.rs:19:18
+ |
+LL | type B<'b> = impl Clone;
+ | ^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0478`.
--- /dev/null
+// edition:2018
+
+#![feature(generic_associated_types)]
+#![feature(type_alias_impl_trait)]
+
+use std::future::Future;
+
+trait MakeFut {
+ type Fut<'a> where Self: 'a;
+ fn make_fut<'a>(&'a self) -> Self::Fut<'a>;
+}
+
+impl MakeFut for &'_ mut () {
+ type Fut<'a> = impl Future<Output = ()>;
+ //~^ ERROR: the type `&mut ()` does not fulfill the required lifetime
+
+ fn make_fut<'a>(&'a self) -> Self::Fut<'a> {
+ async { () }
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0477]: the type `&mut ()` does not fulfill the required lifetime
+ --> $DIR/issue-90014.rs:14:5
+ |
+LL | type Fut<'a> = impl Future<Output = ()>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: type must outlive the lifetime `'a` as defined here
+ --> $DIR/issue-90014.rs:14:14
+ |
+LL | type Fut<'a> = impl Future<Output = ()>;
+ | ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0477`.
--- /dev/null
+// run-pass
+#![allow(dead_code)]
+// Issue #1112
+// Alignment of interior pointers to dynamic-size types
+
+
+struct X<T> {
+ a: T,
+ b: u8,
+ c: bool,
+ d: u8,
+ e: u16,
+ f: u8,
+ g: u8
+}
+
+pub fn main() {
+ let x: X<isize> = X {
+ a: 12345678,
+ b: 9,
+ c: true,
+ d: 10,
+ e: 11,
+ f: 12,
+ g: 13
+ };
+ bar(x);
+}
+
+fn bar<T>(x: X<T>) {
+ assert_eq!(x.b, 9);
+ assert_eq!(x.c, true);
+ assert_eq!(x.d, 10);
+ assert_eq!(x.e, 11);
+ assert_eq!(x.f, 12);
+ assert_eq!(x.g, 13);
+}
--- /dev/null
+// run-pass
+
+fn quux<T>(x: T) -> T { let f = id::<T>; return f(x); }
+
+fn id<T>(x: T) -> T { return x; }
+
+pub fn main() { assert_eq!(quux(10), 10); }
--- /dev/null
+#![allow(dead_code)]
+#![feature(const_generics_defaults)]
+
+// This test checks that generic parameter re-ordering diagnostic suggestions mention that
+// consts come after types and lifetimes when the `const_generics_defaults` feature is enabled.
+// We cannot run rustfix on this test because of the above const generics warning.
+
+struct A;
+
+impl A {
+ pub fn do_things<T, 'a, 'b: 'a>() {
+ //~^ ERROR lifetime parameters must be declared prior to type parameters
+ println!("panic");
+ }
+}
+
+fn main() {}
--- /dev/null
+error: lifetime parameters must be declared prior to type parameters
+ --> $DIR/issue-59508-1.rs:11:25
+ |
+LL | pub fn do_things<T, 'a, 'b: 'a>() {
+ | ----^^--^^----- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b: 'a, T>`
+
+error: aborting due to previous error
+
--- /dev/null
+// run-rustfix
+
+#![allow(dead_code)]
+
+// This test checks that generic parameter re-ordering diagnostic suggestions contain bounds.
+
+struct A;
+
+impl A {
+ pub fn do_things<'a, 'b: 'a, T>() {
+ //~^ ERROR lifetime parameters must be declared prior to type parameters
+ println!("panic");
+ }
+}
+
+fn main() {}
--- /dev/null
+// run-rustfix
+
+#![allow(dead_code)]
+
+// This test checks that generic parameter re-ordering diagnostic suggestions contain bounds.
+
+struct A;
+
+impl A {
+ pub fn do_things<T, 'a, 'b: 'a>() {
+ //~^ ERROR lifetime parameters must be declared prior to type parameters
+ println!("panic");
+ }
+}
+
+fn main() {}
--- /dev/null
+error: lifetime parameters must be declared prior to type parameters
+ --> $DIR/issue-59508.rs:10:25
+ |
+LL | pub fn do_things<T, 'a, 'b: 'a>() {
+ | ----^^--^^----- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b: 'a, T>`
+
+error: aborting due to previous error
+
--- /dev/null
+pub trait Trait<'a> {
+ type Item;
+}
+
+impl<'a> Trait<'a> for () {
+ type Item = ();
+}
+
+pub fn foo<T, F>(_: T, _: F)
+where
+ T: for<'a> Trait<'a>,
+ F: for<'a> FnMut(<T as Trait<'a>>::Item),
+{
+}
+
+fn main() {
+ foo((), drop)
+ //~^ ERROR type mismatch in function arguments
+ //~| ERROR size for values of type `<() as Trait<'_>>::Item` cannot be known at compilation time
+}
--- /dev/null
+error[E0631]: type mismatch in function arguments
+ --> $DIR/issue-60283.rs:17:13
+ |
+LL | foo((), drop)
+ | --- ^^^^
+ | | |
+ | | expected signature of `for<'a> fn(<() as Trait<'a>>::Item) -> _`
+ | | found signature of `fn(()) -> _`
+ | required by a bound introduced by this call
+ |
+note: required by a bound in `foo`
+ --> $DIR/issue-60283.rs:12:16
+ |
+LL | pub fn foo<T, F>(_: T, _: F)
+ | --- required by a bound in this
+...
+LL | F: for<'a> FnMut(<T as Trait<'a>>::Item),
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `foo`
+
+error[E0277]: the size for values of type `<() as Trait<'_>>::Item` cannot be known at compilation time
+ --> $DIR/issue-60283.rs:17:13
+ |
+LL | foo((), drop)
+ | --- ^^^^ doesn't have a size known at compile-time
+ | |
+ | required by a bound introduced by this call
+ |
+ = help: the trait `Sized` is not implemented for `<() as Trait<'_>>::Item`
+note: required by a bound in `std::mem::drop`
+ --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
+ |
+LL | pub fn drop<T>(_x: T) {}
+ | ^ required by this bound in `std::mem::drop`
+help: consider further restricting the associated type
+ |
+LL | fn main() where <() as Trait<'_>>::Item: Sized {
+ | ++++++++++++++++++++++++++++++++++++
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0277, E0631.
+For more information about an error, try `rustc --explain E0277`.
--- /dev/null
+// run-pass
+// shouldn't affect evaluation of $ex:
+macro_rules! bad_macro {
+ ($ex:expr) => ({(|_x| { $ex }) (9) })
+}
+
+fn takes_x(_x : isize) {
+ assert_eq!(bad_macro!(_x),8);
+}
+fn main() {
+ takes_x(8);
+}
|
LL | foo::<str>("".to_string());
| ^^^ explicit generic argument not allowed
+ |
+ = note: see issue #83701 <https://github.com/rust-lang/rust/issues/83701> for more information
+ = help: add `#![feature(explicit_generic_args_with_impl_trait)]` to the crate attributes to enable
error: aborting due to previous error
--- /dev/null
+// check-pass
+
+fn fibs(n: u32) -> impl Iterator<Item=u128> {
+ (0 .. n)
+ .scan((0, 1), |st, _| {
+ *st = (st.1, st.0 + st.1);
+ Some(*st)
+ })
+ .map(&|(f, _)| f)
+}
+
+fn main() {
+ println!("{:?}", fibs(10).collect::<Vec<_>>());
+}
--- /dev/null
+// run-pass
+// Regression test for #49685: drop elaboration was not revealing the
+// value of `impl Trait` returns, leading to an ICE.
+
+fn main() {
+ let _ = Some(())
+ .into_iter()
+ .flat_map(|_| Some(()).into_iter().flat_map(func));
+}
+
+fn func(_: ()) -> impl Iterator<Item = ()> {
+ Some(()).into_iter().flat_map(|_| vec![])
+}
--- /dev/null
+// run-pass
+fn foo() -> impl Into<for<'a> fn(&'a ())> {
+ (|_| {}) as for<'a> fn(&'a ())
+}
+
+fn main() {
+ foo().into()(&());
+}
|
LL | foo::<String>('a');
| ^^^^^^ explicit generic argument not allowed
+ |
+ = note: see issue #83701 <https://github.com/rust-lang/rust/issues/83701> for more information
+ = help: add `#![feature(explicit_generic_args_with_impl_trait)]` to the crate attributes to enable
error: aborting due to previous error
| ^^^^^^^^^ ^^^^^^^^^^^^^ explicit generic argument not allowed
| |
| explicit generic argument not allowed
+ |
+ = note: see issue #83701 <https://github.com/rust-lang/rust/issues/83701> for more information
+ = help: add `#![feature(explicit_generic_args_with_impl_trait)]` to the crate attributes to enable
error: aborting due to previous error
//~^ ERROR defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
//~| WARNING this was previously accepted by the compiler but is being phased out
//~| ERROR `impl Trait` not allowed outside of function and method return types
+//~| ERROR no nominal type found
// Disallowed
fn in_method_generic_param_default<T = impl Debug>(_: T) {}
| ^^^^^^^^^^
error[E0562]: `impl Trait` not allowed outside of function and method return types
- --> $DIR/where-allowed.rs:240:40
+ --> $DIR/where-allowed.rs:241:40
|
LL | fn in_method_generic_param_default<T = impl Debug>(_: T) {}
| ^^^^^^^^^^
error[E0562]: `impl Trait` not allowed outside of function and method return types
- --> $DIR/where-allowed.rs:246:29
+ --> $DIR/where-allowed.rs:247:29
|
LL | let _in_local_variable: impl Fn() = || {};
| ^^^^^^^^^
error[E0562]: `impl Trait` not allowed outside of function and method return types
- --> $DIR/where-allowed.rs:248:46
+ --> $DIR/where-allowed.rs:249:46
|
LL | let _in_return_in_local_variable = || -> impl Fn() { || {} };
| ^^^^^^^^^
= note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
- --> $DIR/where-allowed.rs:240:36
+ --> $DIR/where-allowed.rs:241:36
|
LL | fn in_method_generic_param_default<T = impl Debug>(_: T) {}
| ^
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
-error: aborting due to 48 previous errors
+error[E0118]: no nominal type found for inherent implementation
+ --> $DIR/where-allowed.rs:234:23
+ |
+LL | impl <T = impl Debug> T {}
+ | ^ impl requires a nominal type
+ |
+ = note: either implement a trait on it or create a newtype to wrap it instead
+
+error: aborting due to 49 previous errors
-Some errors have detailed explanations: E0562, E0658, E0666.
-For more information about an error, try `rustc --explain E0562`.
+Some errors have detailed explanations: E0118, E0562, E0658, E0666.
+For more information about an error, try `rustc --explain E0118`.
+++ /dev/null
-// run-pass
-
-#![allow(warnings)]
-#![feature(in_band_lifetimes)]
-
-fn foo(x: &'x u8) -> &'x u8 { x }
-fn foo2(x: &'a u8, y: &u8) -> &'a u8 { x }
-
-fn check_in_band_can_be_late_bound() {
- let _: for<'x> fn(&'x u8, &u8) -> &'x u8 = foo2;
-}
-
-struct ForInherentNoParams;
-
-impl ForInherentNoParams {
- fn foo(x: &'a u32, y: &u32) -> &'a u32 { x }
-}
-
-struct X<'a>(&'a u8);
-
-impl<'a> X<'a> {
- fn inner(&self) -> &'a u8 {
- self.0
- }
-
- fn same_lifetime_as_parameter(&mut self, x: &'a u8) {
- self.0 = x;
- }
-}
-
-impl X<'b> {
- fn inner_2(&self) -> &'b u8 {
- self.0
- }
-
- fn reference_already_introduced_in_band_from_method_with_explicit_binders<'a>(
- &'b self, x: &'a u32
- ) {}
-}
-
-struct Y<T>(T);
-
-impl Y<&'a u8> {
- fn inner(&self) -> &'a u8 {
- self.0
- }
-}
-
-trait MyTrait<'a> {
- fn my_lifetime(&self) -> &'a u8;
- fn any_lifetime() -> &'b u8;
- fn borrowed_lifetime(&'b self) -> &'b u8;
- fn default_impl(&self, x: &'b u32, y: &u32) -> &'b u32 { x }
- fn in_band_def_explicit_impl(&self, x: &'b u8);
-}
-
-impl MyTrait<'a> for Y<&'a u8> {
- fn my_lifetime(&self) -> &'a u8 { self.0 }
- fn any_lifetime() -> &'b u8 { &0 }
- fn borrowed_lifetime(&'b self) -> &'b u8 { &*self.0 }
- fn in_band_def_explicit_impl<'b>(&self, x: &'b u8) {}
-}
-
-fn test_hrtb_defined_lifetime_where<F>(_: F) where for<'a> F: Fn(&'a u8) {}
-fn test_hrtb_defined_lifetime_polytraitref<F>(_: F) where F: for<'a> Fn(&'a u8) {}
-
-fn reference_in_band_from_locals(x: &'test u32) -> &'test u32 {
- let y: &'test u32 = x;
- y
-}
-
-fn in_generics_in_band<T: MyTrait<'a>>(x: &T) {}
-fn where_clause_in_band<T>(x: &T) where T: MyTrait<'a> {}
-fn impl_trait_in_band(x: &impl MyTrait<'a>) {}
-
-// Tests around using in-band lifetimes within existential traits.
-
-trait FunkyTrait<'a> { }
-impl<'a, T> FunkyTrait<'a> for T { }
-fn ret_pos_impl_trait_in_band_outlives(x: &'a u32) -> impl ::std::fmt::Debug + 'a {
- x
-}
-fn ret_pos_impl_trait_in_band_param(x: &'a u32) -> impl FunkyTrait<'a> {
- x
-}
-fn ret_pos_impl_trait_in_band_param_static(x: &'a u32) -> impl FunkyTrait<'static> + 'a {
- x
-}
-fn ret_pos_impl_trait_in_band_param_outlives(x: &'a u32) -> impl FunkyTrait<'a> + 'a {
- x
-}
-fn ret_pos_impl_trait_in_band_higher_ranked(x: &'a u32) -> impl for<'b> FunkyTrait<'b> + 'a {
- x
-}
-
-fn main() {}
--- /dev/null
+// run-pass
+
+#![allow(warnings)]
+#![feature(in_band_lifetimes)]
+
+fn foo(x: &'x u8) -> &'x u8 { x }
+fn foo2(x: &'a u8, y: &u8) -> &'a u8 { x }
+
+fn check_in_band_can_be_late_bound() {
+ let _: for<'x> fn(&'x u8, &u8) -> &'x u8 = foo2;
+}
+
+struct ForInherentNoParams;
+
+impl ForInherentNoParams {
+ fn foo(x: &'a u32, y: &u32) -> &'a u32 { x }
+}
+
+struct X<'a>(&'a u8);
+
+impl<'a> X<'a> {
+ fn inner(&self) -> &'a u8 {
+ self.0
+ }
+
+ fn same_lifetime_as_parameter(&mut self, x: &'a u8) {
+ self.0 = x;
+ }
+}
+
+impl X<'b> {
+ fn inner_2(&self) -> &'b u8 {
+ self.0
+ }
+
+ fn reference_already_introduced_in_band_from_method_with_explicit_binders<'a>(
+ &'b self, x: &'a u32
+ ) {}
+}
+
+struct Y<T>(T);
+
+impl Y<&'a u8> {
+ fn inner(&self) -> &'a u8 {
+ self.0
+ }
+}
+
+trait MyTrait<'a> {
+ fn my_lifetime(&self) -> &'a u8;
+ fn any_lifetime() -> &'b u8;
+ fn borrowed_lifetime(&'b self) -> &'b u8;
+ fn default_impl(&self, x: &'b u32, y: &u32) -> &'b u32 { x }
+ fn in_band_def_explicit_impl(&self, x: &'b u8);
+}
+
+impl MyTrait<'a> for Y<&'a u8> {
+ fn my_lifetime(&self) -> &'a u8 { self.0 }
+ fn any_lifetime() -> &'b u8 { &0 }
+ fn borrowed_lifetime(&'b self) -> &'b u8 { &*self.0 }
+ fn in_band_def_explicit_impl<'b>(&self, x: &'b u8) {}
+}
+
+fn test_hrtb_defined_lifetime_where<F>(_: F) where for<'a> F: Fn(&'a u8) {}
+fn test_hrtb_defined_lifetime_polytraitref<F>(_: F) where F: for<'a> Fn(&'a u8) {}
+
+fn reference_in_band_from_locals(x: &'test u32) -> &'test u32 {
+ let y: &'test u32 = x;
+ y
+}
+
+fn in_generics_in_band<T: MyTrait<'a>>(x: &T) {}
+fn where_clause_in_band<T>(x: &T) where T: MyTrait<'a> {}
+fn impl_trait_in_band(x: &impl MyTrait<'a>) {}
+
+// Tests around using in-band lifetimes within existential traits.
+
+trait FunkyTrait<'a> { }
+impl<'a, T> FunkyTrait<'a> for T { }
+fn ret_pos_impl_trait_in_band_outlives(x: &'a u32) -> impl ::std::fmt::Debug + 'a {
+ x
+}
+fn ret_pos_impl_trait_in_band_param(x: &'a u32) -> impl FunkyTrait<'a> {
+ x
+}
+fn ret_pos_impl_trait_in_band_param_static(x: &'a u32) -> impl FunkyTrait<'static> + 'a {
+ x
+}
+fn ret_pos_impl_trait_in_band_param_outlives(x: &'a u32) -> impl FunkyTrait<'a> + 'a {
+ x
+}
+fn ret_pos_impl_trait_in_band_higher_ranked(x: &'a u32) -> impl for<'b> FunkyTrait<'b> + 'a {
+ x
+}
+
+fn main() {}
--- /dev/null
+// run-pass
+// Test for a specific corner case: when we compute the LUB of two fn
+// types and their parameters have unbound variables. In that case, we
+// wind up relating those two variables. This was causing an ICE in an
+// in-progress PR.
+
+fn main() {
+ let a_f: fn(_) = |_| ();
+ let b_f: fn(_) = |_| ();
+ let c_f = match 22 {
+ 0 => a_f,
+ _ => b_f,
+ };
+ c_f(4);
+}
--- /dev/null
+// check-pass
+
+#![feature(inline_const)]
+#![allow(incomplete_features)]
+
+pub fn todo<T>() -> T {
+ const { todo!() }
+}
+
+fn main() {
+ let _: usize = const { 0 };
+}
--- /dev/null
+#![allow(incomplete_features)]
+#![feature(const_mut_refs)]
+#![feature(inline_const)]
+
+use std::marker::PhantomData;
+
+#[derive(PartialEq, Eq)]
+pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
+
+impl<'a, T: ?Sized> InvariantRef<'a, T> {
+ pub const fn new(r: &'a T) -> Self {
+ InvariantRef(r, PhantomData)
+ }
+}
+
+impl<'a> InvariantRef<'a, ()> {
+ pub const NEW: Self = InvariantRef::new(&());
+}
+
+fn equate<T>(x: T, y: T){}
+
+fn foo<'a>() {
+ let y = ();
+ equate(InvariantRef::new(&y), const { InvariantRef::<'a>::NEW });
+ //~^ ERROR `y` does not live long enough [E0597]
+}
+
+fn main() {
+ foo();
+}
--- /dev/null
+error[E0597]: `y` does not live long enough
+ --> $DIR/const-expr-lifetime-err.rs:24:30
+ |
+LL | fn foo<'a>() {
+ | -- lifetime `'a` defined here
+LL | let y = ();
+LL | equate(InvariantRef::new(&y), const { InvariantRef::<'a>::NEW });
+ | ------------------^^-
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `y` is borrowed for `'a`
+LL |
+LL | }
+ | - `y` dropped here while still borrowed
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
--- /dev/null
+// run-pass
+
+#![allow(incomplete_features)]
+#![feature(const_mut_refs)]
+#![feature(inline_const)]
+
+use std::marker::PhantomData;
+
+// rust-lang/rust#78174: ICE: "cannot convert ReErased to a region vid"
+fn issue_78174() {
+ let foo = const { "foo" };
+ assert_eq!(foo, "foo");
+}
+
+pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
+
+impl<'a, T: ?Sized> InvariantRef<'a, T> {
+ pub const fn new(r: &'a T) -> Self {
+ InvariantRef(r, PhantomData)
+ }
+}
+
+fn get_invariant_ref<'a>() -> InvariantRef<'a, ()> {
+ const { InvariantRef::<'a, ()>::new(&()) }
+}
+
+fn get_invariant_ref2<'a>() -> InvariantRef<'a, ()> {
+ // Try some type inference
+ const { InvariantRef::new(&()) }
+}
+
+fn main() {
+ issue_78174();
+ get_invariant_ref();
+ get_invariant_ref2();
+}
--- /dev/null
+// check-pass
+
+#![feature(inline_const)]
+#![allow(incomplete_features)]
+
+fn main() {
+ match 1u64 {
+ 0 => (),
+ const { 0 + 1 } => (),
+ const { 2 - 1 } ..= const { u64::MAX } => (),
+ }
+}
--- /dev/null
+// ignore-test
+
+#![allow(incomplete_features)]
+#![feature(const_mut_refs)]
+#![feature(inline_const)]
+
+use std::marker::PhantomData;
+
+#[derive(PartialEq, Eq)]
+pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
+
+impl<'a, T: ?Sized> InvariantRef<'a, T> {
+ pub const fn new(r: &'a T) -> Self {
+ InvariantRef(r, PhantomData)
+ }
+}
+
+impl<'a> InvariantRef<'a, ()> {
+ pub const NEW: Self = InvariantRef::new(&());
+}
+
+fn match_invariant_ref<'a>() {
+ let y = ();
+ match InvariantRef::new(&y) {
+ //~^ ERROR `y` does not live long enough [E0597]
+ // FIXME(nbdd0121): This should give the same error as `InvariantRef::<'a>::NEW` (without
+ // const block)
+ const { InvariantRef::<'a>::NEW } => (),
+ }
+}
+
+fn main() {
+ match_invariant_ref();
+}
--- /dev/null
+// run-pass
+
+#![allow(incomplete_features)]
+#![feature(const_mut_refs)]
+#![feature(inline_const)]
+
+use std::marker::PhantomData;
+
+// rust-lang/rust#78174: ICE: "cannot convert ReErased to a region vid"
+fn issue_78174() {
+ match "foo" {
+ const { concat!("fo", "o") } => (),
+ _ => unreachable!(),
+ }
+}
+
+#[derive(PartialEq, Eq)]
+pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
+
+impl<'a, T: ?Sized> InvariantRef<'a, T> {
+ pub const fn new(r: &'a T) -> Self {
+ InvariantRef(r, PhantomData)
+ }
+}
+
+fn match_invariant_ref<'a>() {
+ match const { InvariantRef::<'a, _>::new(&()) } {
+ const { InvariantRef::<'a, ()>::new(&()) } => {
+ }
+ }
+}
+
+fn main() {
+ issue_78174();
+ match_invariant_ref();
+}
target_os = "emscripten",
target_os = "freebsd",
target_os = "fuchsia",
+ target_os = "illumos",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
+++ /dev/null
-#![crate_type = "lib"]
-
-#[macro_export]
-macro_rules! mywrite {
- ($dst:expr, $($arg:tt)*) => ($dst.write_fmt(format_args!($($arg)*)))
-}
+++ /dev/null
-#![crate_type="rlib"]
-
-#[derive(Debug, PartialEq)]
-pub struct RemoteC(pub u32);
-
-#[derive(Debug, PartialEq)]
-pub struct RemoteG<T>(pub T);
+++ /dev/null
-#![crate_type="lib"]
-
-
-pub trait A {
- fn a(&self) {}
-}
-impl A for () {}
+++ /dev/null
-#![crate_type="lib"]
-
-pub extern crate xcrate_issue_43189_a;
+++ /dev/null
-#![crate_type="lib"]
-
-pub extern crate core;
+++ /dev/null
-// edition:2018
-#![crate_type="lib"]
-#![crate_name="xcrate_issue_61711_b"]
-pub struct Struct;
-pub use crate as alias;
+++ /dev/null
-#![feature(box_syntax)]
-
-fn main() {
- let x: Box<_> = box 1;
- let f = move|| {
- let _a = x;
- drop(x);
- //~^ ERROR: use of moved value: `x`
- };
- f();
-}
+++ /dev/null
-error[E0382]: use of moved value: `x`
- --> $DIR/issue-10398.rs:7:14
- |
-LL | let _a = x;
- | - value moved here
-LL | drop(x);
- | ^ value used here after move
- |
- = note: move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0382`.
+++ /dev/null
-// run-pass
-#![allow(dead_code)]
-// Issue #1112
-// Alignment of interior pointers to dynamic-size types
-
-
-struct X<T> {
- a: T,
- b: u8,
- c: bool,
- d: u8,
- e: u16,
- f: u8,
- g: u8
-}
-
-pub fn main() {
- let x: X<isize> = X {
- a: 12345678,
- b: 9,
- c: true,
- d: 10,
- e: 11,
- f: 12,
- g: 13
- };
- bar(x);
-}
-
-fn bar<T>(x: X<T>) {
- assert_eq!(x.b, 9);
- assert_eq!(x.c, true);
- assert_eq!(x.d, 10);
- assert_eq!(x.e, 11);
- assert_eq!(x.f, 12);
- assert_eq!(x.g, 13);
-}
+++ /dev/null
-// run-pass
-// Destructuring struct variants would ICE where regular structs wouldn't
-
-enum Foo {
- VBar { num: isize }
-}
-
-struct SBar { num: isize }
-
-pub fn main() {
- let vbar = Foo::VBar { num: 1 };
- let Foo::VBar { num } = vbar;
- assert_eq!(num, 1);
-
- let sbar = SBar { num: 2 };
- let SBar { num } = sbar;
- assert_eq!(num, 2);
-}
+++ /dev/null
-// run-pass
-
-const TEST_STR: &'static str = "abcd";
-
-fn main() {
- let s = "abcd";
- match s {
- TEST_STR => (),
- _ => unreachable!()
- }
-}
+++ /dev/null
-trait Trait {
- fn outer(&self) {
- fn inner(_: &Self) {
- //~^ ERROR can't use generic parameters from outer function
- }
- }
-}
-
-fn main() { }
+++ /dev/null
-error[E0401]: can't use generic parameters from outer function
- --> $DIR/issue-12796.rs:3:22
- |
-LL | fn inner(_: &Self) {
- | ^^^^
- | |
- | use of generic parameter from outer function
- | can't use `Self` here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0401`.
+++ /dev/null
-fn main() {
- if true {
- } else if { //~ ERROR missing condition
- //~^ ERROR mismatched types
- } else {
- }
-}
-
-fn foo() {
- if true {
- } else if { //~ ERROR missing condition
- //~^ ERROR mismatched types
- }
- bar();
-}
-
-fn bar() {}
+++ /dev/null
-error: missing condition for `if` expression
- --> $DIR/issue-13483.rs:3:14
- |
-LL | } else if {
- | ^ expected if condition here
-
-error: missing condition for `if` expression
- --> $DIR/issue-13483.rs:11:14
- |
-LL | } else if {
- | ^ expected if condition here
-
-error[E0308]: mismatched types
- --> $DIR/issue-13483.rs:3:15
- |
-LL | } else if {
- | _______________^
-LL | |
-LL | | } else {
- | |_____^ expected `bool`, found `()`
-
-error[E0308]: mismatched types
- --> $DIR/issue-13483.rs:11:15
- |
-LL | } else if {
- | _______________^
-LL | |
-LL | | }
- | |_____^ expected `bool`, found `()`
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
+++ /dev/null
-// run-pass
-#![allow(dead_code)]
-#![allow(non_camel_case_types)]
-
-const JSVAL_TAG_CLEAR: u32 = 0xFFFFFF80;
-const JSVAL_TYPE_INT32: u8 = 0x01;
-const JSVAL_TYPE_UNDEFINED: u8 = 0x02;
-#[repr(u32)]
-enum ValueTag {
- JSVAL_TAG_INT32 = JSVAL_TAG_CLEAR | (JSVAL_TYPE_INT32 as u32),
- JSVAL_TAG_UNDEFINED = JSVAL_TAG_CLEAR | (JSVAL_TYPE_UNDEFINED as u32),
-}
-
-fn main() {
- let _ = ValueTag::JSVAL_TAG_INT32;
-}
+++ /dev/null
-error[E0133]: use of extern static is unsafe and requires unsafe function or block
- --> $DIR/issue-14227.rs:7:21
- |
-LL | static CRASH: u32 = symbol;
- | ^^^^^^ use of extern static
- |
- = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0133`.
+++ /dev/null
-// revisions: mir thir
-// [thir]compile-flags: -Z thir-unsafeck
-
-extern "C" {
- pub static symbol: u32;
-}
-static CRASH: u32 = symbol;
-//~^ ERROR use of extern static is unsafe and requires
-
-fn main() {}
+++ /dev/null
-error[E0133]: use of extern static is unsafe and requires unsafe function or block
- --> $DIR/issue-14227.rs:7:21
- |
-LL | static CRASH: u32 = symbol;
- | ^^^^^^ use of extern static
- |
- = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0133`.
+++ /dev/null
-// run-pass
-#![allow(unused_mut)]
-// ignore-emscripten no processes
-// ignore-sgx no processes
-
-use std::env;
-use std::io::prelude::*;
-use std::io;
-use std::process::{Command, Stdio};
-
-fn main() {
- let args: Vec<String> = env::args().collect();
- if args.len() > 1 && args[1] == "child" {
- return child()
- }
-
- test();
-}
-
-fn child() {
- writeln!(&mut io::stdout(), "foo").unwrap();
- writeln!(&mut io::stderr(), "bar").unwrap();
- let mut stdin = io::stdin();
- let mut s = String::new();
- stdin.lock().read_line(&mut s).unwrap();
- assert_eq!(s.len(), 0);
-}
-
-fn test() {
- let args: Vec<String> = env::args().collect();
- let mut p = Command::new(&args[0]).arg("child")
- .stdin(Stdio::piped())
- .stdout(Stdio::piped())
- .stderr(Stdio::piped())
- .spawn().unwrap();
- assert!(p.wait().unwrap().success());
-}
+++ /dev/null
-// run-pass
-// All 3 expressions should work in that the argument gets
-// coerced to a trait object
-
-// pretty-expanded FIXME #23616
-
-fn main() {
- send::<Box<dyn Foo>>(Box::new(Output(0)));
- Test::<Box<dyn Foo>>::foo(Box::new(Output(0)));
- Test::<Box<dyn Foo>>::new().send(Box::new(Output(0)));
-}
-
-fn send<T>(_: T) {}
-
-struct Test<T> { marker: std::marker::PhantomData<T> }
-impl<T> Test<T> {
- fn new() -> Test<T> { Test { marker: ::std::marker::PhantomData } }
- fn foo(_: T) {}
- fn send(&self, _: T) {}
-}
-
-trait Foo { fn dummy(&self) { }}
-struct Output(isize);
-impl Foo for Output {}
+++ /dev/null
-// check-pass
-// pretty-expanded FIXME #23616
-
-#[deny(dead_code)]
-pub enum Foo {
- Bar {
- baz: isize
- }
-}
-
-fn main() { }
+++ /dev/null
-// run-pass
-
-fn main() {
- let mut x: &[_] = &[1, 2, 3, 4];
-
- let mut result = vec![];
- loop {
- x = match *x {
- [1, n, 3, ref rest @ ..] => {
- result.push(n);
- rest
- }
- [n, ref rest @ ..] => {
- result.push(n);
- rest
- }
- [] =>
- break
- }
- }
- assert_eq!(result, [2, 4]);
-}
+++ /dev/null
-macro_rules! prob1 {
- (0) => {
- 0
- };
- ($n:expr) => {
- if ($n % 3 == 0) || ($n % 5 == 0) {
- $n + prob1!($n - 1); //~ ERROR recursion limit reached while expanding `prob1!`
- } else {
- prob1!($n - 1);
- }
- };
-}
-
-fn main() {
- println!("Problem 1: {}", prob1!(1000));
-}
+++ /dev/null
-error: recursion limit reached while expanding `prob1!`
- --> $DIR/issue-16098.rs:7:18
- |
-LL | $n + prob1!($n - 1);
- | ^^^^^^^^^^^^^^
-...
-LL | println!("Problem 1: {}", prob1!(1000));
- | ------------ in this macro invocation
- |
- = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_16098`)
- = note: this error originates in the macro `prob1` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to previous error
-
+++ /dev/null
-// run-pass
-// ignore-emscripten no processes
-// ignore-sgx no processes
-
-use std::process::Command;
-use std::env;
-
-fn main() {
- let len = env::args().len();
-
- if len == 1 {
- test();
- } else {
- assert_eq!(len, 3);
- }
-}
-
-fn test() {
- let status = Command::new(&env::current_exe().unwrap())
- .arg("foo").arg("")
- .status().unwrap();
- assert!(status.success());
-}
+++ /dev/null
-// run-pass
-#![allow(dead_code)]
-
-static X2: u64 = !0 as u16 as u64;
-static Y2: u64 = !0 as u32 as u64;
-const X: u64 = !0 as u16 as u64;
-const Y: u64 = !0 as u32 as u64;
-
-fn main() {
- assert_eq!(match 1 {
- X => unreachable!(),
- Y => unreachable!(),
- _ => 1
- }, 1);
-}
+++ /dev/null
-// run-pass
-// Regression test for #18060: match arms were matching in the wrong order.
-
-fn main() {
- assert_eq!(2, match (1, 3) { (0, 2..=5) => 1, (1, 3) => 2, (_, 2..=5) => 3, (_, _) => 4 });
- assert_eq!(2, match (1, 3) { (1, 3) => 2, (_, 2..=5) => 3, (_, _) => 4 });
- assert_eq!(2, match (1, 7) { (0, 2..=5) => 1, (1, 7) => 2, (_, 2..=5) => 3, (_, _) => 4 });
-}
+++ /dev/null
-fn main() {
- const X: u32 = 1;
- const Y: usize = unsafe { &X as *const u32 as usize }; //~ ERROR pointers cannot be cast to integers
- println!("{}", Y);
-}
+++ /dev/null
-error: pointers cannot be cast to integers during const eval
- --> $DIR/issue-18294.rs:3:31
- |
-LL | const Y: usize = unsafe { &X as *const u32 as usize };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: at compile-time, pointers do not have an integer value
- = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
-
-error: aborting due to previous error
-
+++ /dev/null
-// run-pass
-// Tests multiple free variables being passed by value into an unboxed
-// once closure as an optimization by codegen. This used to hit an
-// incorrect assert.
-
-fn main() {
- let x = 2u8;
- let y = 3u8;
- assert_eq!((move || x + y)(), 5);
-}
+++ /dev/null
-// aux-build:issue-19163.rs
-
-#[macro_use] extern crate issue_19163;
-
-use std::io::Write;
-
-fn main() {
- let mut v = vec![];
- mywrite!(&v, "Hello world");
- //~^ ERROR cannot borrow data in a `&` reference as mutable
-}
+++ /dev/null
-error[E0596]: cannot borrow data in a `&` reference as mutable
- --> $DIR/issue-19163.rs:9:5
- |
-LL | mywrite!(&v, "Hello world");
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
- |
- = note: this error originates in the macro `mywrite` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0596`.
+++ /dev/null
-// run-pass
-
-#![allow(dead_code)]
-
-trait Trait { fn dummy(&self) { } }
-
-#[derive(Debug)]
-struct Foo<T: Trait> {
- foo: T,
-}
-
-#[derive(Debug)]
-struct Bar<T> where T: Trait {
- bar: T,
-}
-
-impl Trait for isize {}
-
-fn main() {
- let a = Foo { foo: 12 };
- let b = Bar { bar: 12 };
- println!("{:?} {:?}", a, b);
-}
+++ /dev/null
-// error-pattern: requires `copy` lang_item
-
-#![feature(lang_items, start, no_core)]
-#![no_core]
-
-#[lang = "sized"]
-trait Sized { }
-
-struct S;
-
-#[start]
-fn main(_: isize, _: *const *const u8) -> isize {
- let _ = S;
- 0
-}
+++ /dev/null
-error: requires `copy` lang_item
-
-error: aborting due to previous error
-
+++ /dev/null
-// run-pass
-#![allow(stable_features)]
-
-// ignore-emscripten no processes
-// ignore-sgx no processes
-
-#![feature(os)]
-
-#[cfg(unix)]
-fn main() {
- use std::process::Command;
- use std::env;
- use std::os::unix::prelude::*;
- use std::ffi::OsStr;
-
- if env::args().len() == 1 {
- assert!(Command::new(&env::current_exe().unwrap())
- .arg(<OsStr as OsStrExt>::from_bytes(b"\xff"))
- .status().unwrap().success())
- }
-}
-
-#[cfg(windows)]
-fn main() {}
+++ /dev/null
-// We need all these 9 issue-20616-N.rs files
-// because we can only catch one parsing error at a time
-
-type Type_1_<'a, T> = &'a T;
-
-
-//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
-
-
-//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
-
-
-//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
-
-
-type Type_4<T> = Type_1_<'static,, T>;
-//~^ error: expected one of `>`, a const expression, lifetime, or type, found `,`
-
-
-type Type_5_<'a> = Type_1_<'a, ()>;
-
-
-//type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
-
-
-//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
-
-
-//type Type_7 = Box<(),,>; // error: expected type, found `,`
-
-
-//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
-
-
-//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
+++ /dev/null
-error: expected one of `>`, a const expression, lifetime, or type, found `,`
- --> $DIR/issue-20616-4.rs:16:34
- |
-LL | type Type_4<T> = Type_1_<'static,, T>;
- | ^ expected one of `>`, a const expression, lifetime, or type
-
-error: aborting due to previous error
-
+++ /dev/null
-// We need all these 9 issue-20616-N.rs files
-// because we can only catch one parsing error at a time
-
-type Type_1_<'a, T> = &'a T;
-
-
-//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
-
-
-//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
-
-
-//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
-
-
-//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
-
-
-type Type_5_<'a> = Type_1_<'a, ()>;
-
-
-type Type_5<'a> = Type_1_<'a, (),,>;
-//~^ error: expected one of `>`, a const expression, lifetime, or type, found `,`
-
-
-//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
-
-
-//type Type_7 = Box<(),,>; // error: expected type, found `,`
-
-
-//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
-
-
-//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
+++ /dev/null
-error: expected one of `>`, a const expression, lifetime, or type, found `,`
- --> $DIR/issue-20616-5.rs:22:34
- |
-LL | type Type_5<'a> = Type_1_<'a, (),,>;
- | ^ expected one of `>`, a const expression, lifetime, or type
-
-error: aborting due to previous error
-
+++ /dev/null
-// We need all these 9 issue-20616-N.rs files
-// because we can only catch one parsing error at a time
-
-type Type_1_<'a, T> = &'a T;
-
-
-//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
-
-
-//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
-
-
-//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
-
-
-//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
-
-
-type Type_5_<'a> = Type_1_<'a, ()>;
-
-
-//type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
-
-
-type Type_6 = Type_5_<'a,,>;
-//~^ error: expected one of `>`, a const expression, lifetime, or type, found `,`
-
-
-//type Type_7 = Box<(),,>; // error: expected type, found `,`
-
-
-//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
-
-
-//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
+++ /dev/null
-error: expected one of `>`, a const expression, lifetime, or type, found `,`
- --> $DIR/issue-20616-6.rs:25:26
- |
-LL | type Type_6 = Type_5_<'a,,>;
- | ^ expected one of `>`, a const expression, lifetime, or type
-
-error: aborting due to previous error
-
+++ /dev/null
-// We need all these 9 issue-20616-N.rs files
-// because we can only catch one parsing error at a time
-
-type Type_1_<'a, T> = &'a T;
-
-
-//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
-
-
-//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
-
-
-//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
-
-
-//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
-
-
-type Type_5_<'a> = Type_1_<'a, ()>;
-
-
-//type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
-
-
-//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
-
-
-type Type_7 = Box<(),,>;
-//~^ error: expected one of `>`, a const expression, lifetime, or type, found `,`
-
-
-//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
-
-
-//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
+++ /dev/null
-error: expected one of `>`, a const expression, lifetime, or type, found `,`
- --> $DIR/issue-20616-7.rs:28:22
- |
-LL | type Type_7 = Box<(),,>;
- | ^ expected one of `>`, a const expression, lifetime, or type
-
-error: aborting due to previous error
-
+++ /dev/null
-// run-pass
-// compile-flags: --test
-
-#[test]
-pub fn foo() {}
+++ /dev/null
-#![allow(unused_macros)]
-
-macro_rules! test { ($wrong:t_ty ..) => () }
- //~^ ERROR: invalid fragment specifier `t_ty`
-
-fn main() {}
+++ /dev/null
-error: invalid fragment specifier `t_ty`
- --> $DIR/issue-21356.rs:3:22
- |
-LL | macro_rules! test { ($wrong:t_ty ..) => () }
- | ^^^^^^^^^^^
- |
- = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
-
-error: aborting due to previous error
-
+++ /dev/null
-// run-pass
-#![allow(unused_imports, overlapping_range_endpoints)]
-// pretty-expanded FIXME #23616
-
-use m::{START, END};
-
-fn main() {
- match 42 {
- m::START..=m::END => {},
- 0..=m::END => {},
- m::START..=59 => {},
- _ => {},
- }
-}
-
-mod m {
- pub const START: u32 = 4;
- pub const END: u32 = 14;
-}
+++ /dev/null
-// check-pass
-#![allow(dead_code)]
-// Test that the requirement (in `Bar`) that `T::Bar : 'static` does
-// not wind up propagating to `T`.
-
-// pretty-expanded FIXME #23616
-
-pub trait Foo {
- type Bar;
-
- fn foo(&self) -> Self;
-}
-
-pub struct Static<T:'static>(T);
-
-struct Bar<T:Foo>
- where T::Bar : 'static
-{
- x: Static<Option<T::Bar>>
-}
-
-fn main() { }
+++ /dev/null
-// check-pass
-pub trait LineFormatter<'a> {
- type Iter: Iterator<Item=&'a str> + 'a;
- fn iter(&'a self, line: &'a str) -> Self::Iter;
-
- fn dimensions(&'a self, line: &'a str) {
- let iter: Self::Iter = self.iter(line);
- <_ as IntoIterator>::into_iter(iter);
- }
-}
-
-fn main() {}
+++ /dev/null
-// run-pass
-macro_rules! items {
- () => {
- type A = ();
- fn a() {}
- }
-}
-
-trait Foo {
- type A;
- fn a();
-}
-
-impl Foo for () {
- items!();
-}
-
-fn main() {
-
-}
+++ /dev/null
-// run-pass
-#![allow(dead_code)]
-// Test transitive analysis for associated types. Collected types
-// should be normalized and new obligations generated.
-
-// pretty-expanded FIXME #23616
-
-trait Foo {
- type A;
- fn foo(&self) {}
-}
-
-impl Foo for usize {
- type A = usize;
-}
-
-struct Bar<T: Foo> { inner: T::A }
-
-fn is_send<T: Send>() {}
-
-fn main() {
- is_send::<Bar<usize>>();
-}
+++ /dev/null
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-// compile-flags: -Ccodegen-units=1
-// build-fail
-// only-x86_64
-
-fn main() {
- unsafe {
- llvm_asm!("int $3"); //~ ERROR too few operands for instruction
- //~| ERROR invalid operand in inline asm
- }
-}
+++ /dev/null
-error: invalid operand in inline asm: 'int $3'
- --> $DIR/issue-23458.rs:9:9
- |
-LL | llvm_asm!("int $3");
- | ^
-
-error: too few operands for instruction
- --> $DIR/issue-23458.rs:9:9
- |
-LL | llvm_asm!("int $3");
- | ^
- |
-note: instantiated into assembly here
- --> <inline asm>:1:2
- |
-LL | int
- | ^
-
-error: aborting due to 2 previous errors
-
+++ /dev/null
-static foo: i32 = 0;
-
-fn bar(foo: i32) {}
-//~^ ERROR function parameters cannot shadow statics
-//~| cannot be named the same as a static
-
-mod submod {
- pub static answer: i32 = 42;
-}
-
-use self::submod::answer;
-
-fn question(answer: i32) {}
-//~^ ERROR function parameters cannot shadow statics
-//~| cannot be named the same as a static
-fn main() {
-}
+++ /dev/null
-error[E0530]: function parameters cannot shadow statics
- --> $DIR/issue-23716.rs:3:8
- |
-LL | static foo: i32 = 0;
- | -------------------- the static `foo` is defined here
-LL |
-LL | fn bar(foo: i32) {}
- | ^^^ cannot be named the same as a static
-
-error[E0530]: function parameters cannot shadow statics
- --> $DIR/issue-23716.rs:13:13
- |
-LL | use self::submod::answer;
- | -------------------- the static `answer` is imported here
-LL |
-LL | fn question(answer: i32) {}
- | ^^^^^^ cannot be named the same as a static
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0530`.
+++ /dev/null
-// run-pass
-const U8_MAX_HALF: u8 = !0u8 / 2;
-const U16_MAX_HALF: u16 = !0u16 / 2;
-const U32_MAX_HALF: u32 = !0u32 / 2;
-const U64_MAX_HALF: u64 = !0u64 / 2;
-
-fn main() {
- assert_eq!(U8_MAX_HALF, 0x7f);
- assert_eq!(U16_MAX_HALF, 0x7fff);
- assert_eq!(U32_MAX_HALF, 0x7fff_ffff);
- assert_eq!(U64_MAX_HALF, 0x7fff_ffff_ffff_ffff);
-}
+++ /dev/null
-// run-pass
-
-trait Foo: Fn(i32) -> i32 + Send {}
-
-impl<T: ?Sized + Fn(i32) -> i32 + Send> Foo for T {}
-
-fn wants_foo(f: Box<dyn Foo>) -> i32 {
- f(42)
-}
-
-fn main() {
- let f = Box::new(|x| x);
- assert_eq!(wants_foo(f), 42);
-}
+++ /dev/null
-// run-pass
-// ignore-emscripten no threads
-// ignore-sgx no processes
-
-use std::thread;
-use std::env;
-use std::process::Command;
-
-struct Handle(i32);
-
-impl Drop for Handle {
- fn drop(&mut self) { panic!(); }
-}
-
-thread_local!(static HANDLE: Handle = Handle(0));
-
-fn main() {
- let args = env::args().collect::<Vec<_>>();
- if args.len() == 1 {
- let out = Command::new(&args[0]).arg("test").output().unwrap();
- let stderr = std::str::from_utf8(&out.stderr).unwrap();
- assert!(stderr.contains("panicked at 'explicit panic'"),
- "bad failure message:\n{}\n", stderr);
- } else {
- // TLS dtors are not always run on process exit
- thread::spawn(|| {
- HANDLE.with(|h| {
- println!("{}", h.0);
- });
- }).join().unwrap();
- }
-}
+++ /dev/null
-// run-fail
-// error-pattern:explicit panic
-// ignore-emscripten no processes
-
-use std::sync::Arc;
-
-enum Err<T> {
- Errr(Arc<T>),
-}
-
-fn foo() -> Err<isize> {
- panic!();
-}
-
-fn main() {
- let _f = foo();
-}
+++ /dev/null
-// run-pass
-#![allow(overlapping_range_endpoints)]
-
-fn main() {
- let x = 'a';
-
- let y = match x {
- 'a'..='b' if false => "one",
- 'a' => "two",
- 'a'..='b' => "three",
- _ => panic!("what?"),
- };
-
- assert_eq!(y, "two");
-}
+++ /dev/null
-// run-pass
-
-pub trait Foo<T> {
- fn foo(self) -> T;
-}
-
-impl<'a, T> Foo<T> for &'a str where &'a str: Into<T> {
- fn foo(self) -> T {
- panic!();
- }
-}
-
-fn main() {}
+++ /dev/null
-// check-pass
-
-pub struct Bar<T> {
- items: Vec<&'static str>,
- inner: T,
-}
-
-pub trait IntoBar<T> {
- fn into_bar(self) -> Bar<T>;
-}
-
-impl<'a, T> IntoBar<T> for &'a str where &'a str: Into<T> {
- fn into_bar(self) -> Bar<T> {
- Bar {
- items: Vec::new(),
- inner: self.into(),
- }
- }
-}
-
-fn main() {}
+++ /dev/null
-// check-pass
-
-pub struct Item {
- _inner: &'static str,
-}
-
-pub struct Bar<T> {
- items: Vec<Item>,
- inner: T,
-}
-
-pub trait IntoBar<T> {
- fn into_bar(self) -> Bar<T>;
-}
-
-impl<'a, T> IntoBar<T> for &'a str where &'a str: Into<T> {
- fn into_bar(self) -> Bar<T> {
- Bar {
- items: Vec::new(),
- inner: self.into(),
- }
- }
-}
-
-fn main() {}
+++ /dev/null
-fn parse_type(iter: Box<dyn Iterator<Item=&str>+'static>) -> &str { iter.next() }
-//~^ ERROR missing lifetime specifier [E0106]
-
-fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
-//~^ ERROR missing lifetime specifier [E0106]
-
-fn parse_type_3() -> &str { unimplemented!() }
-//~^ ERROR missing lifetime specifier [E0106]
-
-fn main() {}
+++ /dev/null
-error[E0106]: missing lifetime specifier
- --> $DIR/issue-26638.rs:1:62
- |
-LL | fn parse_type(iter: Box<dyn Iterator<Item=&str>+'static>) -> &str { iter.next() }
- | ------------------------------------ ^ expected named lifetime parameter
- |
- = help: this function's return type contains a borrowed value, but the signature does not say which one of `iter`'s 2 lifetimes it is borrowed from
-help: consider introducing a named lifetime parameter
- |
-LL | fn parse_type<'a>(iter: Box<dyn Iterator<Item=&str>+'static>) -> &'a str { iter.next() }
- | ++++ ++
-
-error[E0106]: missing lifetime specifier
- --> $DIR/issue-26638.rs:4:40
- |
-LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
- | ^ expected named lifetime parameter
- |
- = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
-help: consider using the `'static` lifetime
- |
-LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &'static str { iter() }
- | ~~~~~~~~
-
-error[E0106]: missing lifetime specifier
- --> $DIR/issue-26638.rs:7:22
- |
-LL | fn parse_type_3() -> &str { unimplemented!() }
- | ^ expected named lifetime parameter
- |
- = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
- |
-LL | fn parse_type_3() -> &'static str { unimplemented!() }
- | ~~~~~~~~
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0106`.
+++ /dev/null
-// run-pass
-
-// This test is bogus (i.e., should be check-fail) during the period
-// where #54986 is implemented and #54987 is *not* implemented. For
-// now: just ignore it
-//
-// ignore-test
-
-// This test is checking that the write to `c.0` (which has been moved out of)
-// won't overwrite the state in `c2`.
-//
-// That's a fine thing to test when this code is accepted by the
-// compiler, and this code is being transcribed accordingly into
-// the ui test issue-21232-partial-init-and-use.rs
-
-fn main() {
- let mut c = (1, "".to_owned());
- match c {
- c2 => {
- c.0 = 2;
- assert_eq!(c2.0, 1);
- }
- }
-}
+++ /dev/null
-// run-pass
-
-fn thing<'r>(x: &'r [isize]) -> &'r [isize] { x }
-
-pub fn main() {
- let x = &[1,2,3];
- let y = x;
- let z = thing(x);
- assert_eq!(z[2], x[2]);
- assert_eq!(z[1], y[1]);
-}
+++ /dev/null
-error[E0133]: use of extern static is unsafe and requires unsafe function or block
- --> $DIR/issue-28324.rs:8:24
- |
-LL | pub static BAZ: u32 = *&error_message_count;
- | ^^^^^^^^^^^^^^^^^^^^ use of extern static
- |
- = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0133`.
+++ /dev/null
-// revisions: mir thir
-// [thir]compile-flags: -Z thir-unsafeck
-
-extern "C" {
- static error_message_count: u32;
-}
-
-pub static BAZ: u32 = *&error_message_count;
-//~^ ERROR use of extern static is unsafe and requires
-
-fn main() {}
+++ /dev/null
-error[E0133]: use of extern static is unsafe and requires unsafe function or block
- --> $DIR/issue-28324.rs:8:25
- |
-LL | pub static BAZ: u32 = *&error_message_count;
- | ^^^^^^^^^^^^^^^^^^^ use of extern static
- |
- = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0133`.
+++ /dev/null
-// run-pass
-
-// Demonstrate the use of the unguarded escape hatch with a type param in negative position
-// to assert that destructor will not access any dead data.
-//
-// Compare with ui/span/issue28498-reject-lifetime-param.rs
-
-// Demonstrate that a type param in negative position causes dropck to reject code
-// that might indirectly access previously dropped value.
-//
-// Compare with run-pass/issue28498-ugeh-with-passed-to-fn.rs
-
-#![feature(dropck_eyepatch)]
-
-#[derive(Debug)]
-struct ScribbleOnDrop(String);
-
-impl Drop for ScribbleOnDrop {
- fn drop(&mut self) {
- self.0 = format!("DROPPED");
- }
-}
-
-struct Foo<T>(u32, T, Box<for <'r> fn(&'r T) -> String>);
-
-unsafe impl<#[may_dangle] T> Drop for Foo<T> {
- fn drop(&mut self) {
- // Use of `may_dangle` is sound, because destructor never passes a `self.1`
- // to the callback (in `self.2`) despite having it available.
- println!("Dropping Foo({}, _)", self.0);
- }
-}
-
-fn callback(s: & &ScribbleOnDrop) -> String { format!("{:?}", s) }
-
-fn main() {
- let (last_dropped, foo0);
- let (foo1, first_dropped);
-
- last_dropped = ScribbleOnDrop(format!("last"));
- first_dropped = ScribbleOnDrop(format!("first"));
- foo0 = Foo(0, &last_dropped, Box::new(callback));
- foo1 = Foo(1, &first_dropped, Box::new(callback));
-
- println!("foo0.1: {:?} foo1.1: {:?}", foo0.1, foo1.1);
-}
+++ /dev/null
-// check-pass
-// Regression test for #28871. The problem is that rustc encountered
-// two ways to project, one from a where clause and one from the where
-// clauses on the trait definition. (In fact, in this case, the where
-// clauses originated from the trait definition as well.) The true
-// cause of the error is that the trait definition where clauses are
-// not being normalized, and hence the two sources are considered in
-// conflict, and not a duplicate. Hacky solution is to prefer where
-// clauses over the data found in the trait definition.
-
-trait T {
- type T;
-}
-
-struct S;
-impl T for S {
- type T = S;
-}
-
-trait T2 {
- type T: Iterator<Item=<S as T>::T>;
-}
-
-fn main() { }
+++ /dev/null
-macro_rules! foo {
- ($d:expr) => {{
- fn bar(d: u8) { }
- bar(&mut $d);
- //~^ ERROR mismatched types
- //~| expected `u8`, found `&mut u8`
- }}
-}
-
-fn main() {
- foo!(0u8);
- //~^ in this expansion of foo!
-}
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/issue-29084.rs:4:13
- |
-LL | bar(&mut $d);
- | ^^^^^^^ expected `u8`, found `&mut u8`
-...
-LL | foo!(0u8);
- | --------- in this macro invocation
- |
- = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
+++ /dev/null
-fn siphash<T>() {
-
- trait U {
- fn g(&self, x: T) -> T; //~ ERROR can't use generic parameters from outer function
- //~^ ERROR can't use generic parameters from outer function
- }
-}
-
-fn main() {}
+++ /dev/null
-error[E0401]: can't use generic parameters from outer function
- --> $DIR/issue-3021-c.rs:4:24
- |
-LL | fn siphash<T>() {
- | - type parameter from outer function
-...
-LL | fn g(&self, x: T) -> T;
- | - ^ use of generic parameter from outer function
- | |
- | help: try using a local generic parameter instead: `g<T>`
-
-error[E0401]: can't use generic parameters from outer function
- --> $DIR/issue-3021-c.rs:4:30
- |
-LL | fn siphash<T>() {
- | - type parameter from outer function
-...
-LL | fn g(&self, x: T) -> T;
- | - ^ use of generic parameter from outer function
- | |
- | help: try using a local generic parameter instead: `g<T>`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0401`.
+++ /dev/null
-trait SipHash {
- fn reset(&self);
-}
-
-fn siphash(k0 : u64) {
- struct SipState {
- v0: u64,
- }
-
- impl SipHash for SipState {
- fn reset(&self) {
- self.v0 = k0 ^ 0x736f6d6570736575; //~ ERROR can't capture dynamic environment
- }
- }
- panic!();
-}
-
-fn main() {}
+++ /dev/null
-error[E0434]: can't capture dynamic environment in a fn item
- --> $DIR/issue-3021.rs:12:22
- |
-LL | self.v0 = k0 ^ 0x736f6d6570736575;
- | ^^
- |
- = help: use the `|| { ... }` closure form instead
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0434`.
+++ /dev/null
-// Regression test for #30225, which was an ICE that would trigger as
-// a result of a poor interaction between trait result caching and
-// type inference. Specifically, at that time, unification could cause
-// unrelated type variables to become instantiated, if subtyping
-// relationships existed. These relationships are now propagated
-// through obligations and hence everything works out fine.
-
-trait Foo<U,V> : Sized {
- fn foo(self, u: Option<U>, v: Option<V>) {}
-}
-
-struct A;
-struct B;
-
-impl Foo<A, B> for () {} // impl A
-impl Foo<u32, u32> for u32 {} // impl B, creating ambiguity
-
-fn toxic() {
- // cache the resolution <() as Foo<$0,$1>> = impl A
- let u = None;
- let v = None;
- Foo::foo((), u, v);
-}
-
-fn bomb() {
- let mut u = None; // type is Option<$0>
- let mut v = None; // type is Option<$1>
- let mut x = None; // type is Option<$2>
-
- Foo::foo(x.unwrap(),u,v); // register <$2 as Foo<$0, $1>>
- u = v; // mark $0 and $1 in a subtype relationship
- //~^ ERROR mismatched types
- x = Some(()); // set $2 = (), allowing impl selection
- // to proceed for <() as Foo<$0, $1>> = impl A.
- // kaboom, this *used* to trigge an ICE
-}
-
-fn main() {}
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/issue-30225.rs:31:9
- |
-LL | u = v; // mark $0 and $1 in a subtype relationship
- | ^ expected struct `A`, found struct `B`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
+++ /dev/null
-pub struct X([u8]);
-
-pub static Y: &'static X = {
- const Y: &'static [u8] = b"";
- &X(*Y)
- //~^ ERROR E0277
-};
-
-fn main() {}
+++ /dev/null
-error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
- --> $DIR/issue-30355.rs:5:8
- |
-LL | &X(*Y)
- | ^^ doesn't have a size known at compile-time
- |
- = help: the trait `Sized` is not implemented for `[u8]`
- = note: all function arguments must have a statically known size
- = help: unsized fn params are gated as an unstable feature
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0277`.
+++ /dev/null
-#![feature(no_core, lang_items)]
-#![no_core]
-
-#[lang="sized"]
-trait Sized {}
-
-#[lang="add"]
-trait Add<T> {}
-
-impl Add<i32> for i32 {}
-
-fn main() {
- let x = 5 + 6;
- //~^ ERROR cannot add `i32` to `{integer}`
- let y = 5i32 + 6i32;
- //~^ ERROR cannot add `i32` to `i32`
-}
+++ /dev/null
-error[E0369]: cannot add `i32` to `{integer}`
- --> $DIR/issue-31076.rs:13:15
- |
-LL | let x = 5 + 6;
- | - ^ - i32
- | |
- | {integer}
-
-error[E0369]: cannot add `i32` to `i32`
- --> $DIR/issue-31076.rs:15:18
- |
-LL | let y = 5i32 + 6i32;
- | ---- ^ ---- i32
- | |
- | i32
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0369`.
+++ /dev/null
-// Test that error recovery in the parser to an EOF does not give an infinite
-// spew of errors.
-
-fn main() {
- let
-} //~ ERROR expected pattern, found `}`
+++ /dev/null
-error: expected pattern, found `}`
- --> $DIR/issue-31804.rs:6:1
- |
-LL | }
- | ^ expected pattern
-
-error: aborting due to previous error
-
+++ /dev/null
-// Checks lexical scopes cannot see through normal module boundaries
-
-fn f() {
- fn g() {}
- mod foo {
- fn h() {
- g(); //~ ERROR cannot find function `g` in this scope
- }
- }
-}
-
-fn main() {}
+++ /dev/null
-error[E0425]: cannot find function `g` in this scope
- --> $DIR/issue-31845.rs:7:12
- |
-LL | g();
- | ^ not found in this scope
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0425`.
+++ /dev/null
-// run-pass
-pub fn main() {
- let mut x = 0;
- for _ in 0..4096 { x += 1; }
- assert_eq!(x, 4096);
- println!("x = {}", x);
-}
+++ /dev/null
-extern "C" {
- fn foo(a: i32, ...);
-}
-
-fn bar(_: *const u8) {}
-
-fn main() {
- unsafe {
- foo(0, bar);
- //~^ ERROR can't pass `fn(*const u8) {bar}` to variadic function
- //~| HELP cast the value to `fn(*const u8)`
- }
-}
+++ /dev/null
-error[E0617]: can't pass `fn(*const u8) {bar}` to variadic function
- --> $DIR/issue-32201.rs:9:16
- |
-LL | foo(0, bar);
- | ^^^ help: cast the value to `fn(*const u8)`: `bar as fn(*const u8)`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0617`.
+++ /dev/null
-// run-pass
-
-fn quux<T>(x: T) -> T { let f = id::<T>; return f(x); }
-
-fn id<T>(x: T) -> T { return x; }
-
-pub fn main() { assert_eq!(quux(10), 10); }
+++ /dev/null
-// check-pass
-
-macro_rules! m {
- () => { #[cfg(any())] fn f() {} }
-}
-
-trait T {}
-impl T for () { m!(); }
-
-fn main() {}
+++ /dev/null
-// check-pass
-
-macro_rules! null { ($i:tt) => {} }
-macro_rules! apply_null {
- ($i:item) => { null! { $i } }
-}
-
-fn main() {
- apply_null!(#[cfg(all())] fn f() {});
-}
+++ /dev/null
-enum Test {
- Drill {
- field: i32,
- }
-}
-
-fn main() {
- Test::Drill(field: 42);
- //~^ ERROR invalid `struct` delimiters or `fn` call arguments
-}
+++ /dev/null
-error: invalid `struct` delimiters or `fn` call arguments
- --> $DIR/issue-34255-1.rs:8:5
- |
-LL | Test::Drill(field: 42);
- | ^^^^^^^^^^^^^^^^^^^^^^
- |
-help: if `Test::Drill` is a struct, use braces as delimiters
- |
-LL | Test::Drill { field: 42 };
- | ~ ~
-help: if `Test::Drill` is a function, use the arguments directly
- |
-LL - Test::Drill(field: 42);
-LL + Test::Drill(42);
- |
-
-error: aborting due to previous error
-
+++ /dev/null
-// build-pass
-#![allow(dead_code)]
-// Regression test for #35546. Check that we are able to codegen
-// this. Before we had problems because of the drop glue signature
-// around dropping a trait object (specifically, when dropping the
-// `value` field of `Node<Send>`).
-
-struct Node<T: ?Sized + Send> {
- next: Option<Box<Node<dyn Send>>>,
- value: T,
-}
-
-fn clear(head: &mut Option<Box<Node<dyn Send>>>) {
- match head.take() {
- Some(node) => *head = node.next,
- None => (),
- }
-}
-
-fn main() {}
+++ /dev/null
-// run-pass
-macro_rules! m { (<$t:ty>) => { stringify!($t) } }
-fn main() {
- println!("{}", m!(<Vec<i32>>));
-}
+++ /dev/null
-// check-pass
-// ignore-emscripten
-
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-macro_rules! interrupt_handler {
- () => {
- unsafe fn _interrupt_handler() {
- llvm_asm!("pop eax" :::: "intel");
- }
- }
-}
-interrupt_handler!{}
-
-fn main() {}
+++ /dev/null
-const fn x() {
- let t = true;
- let x = || t; //~ ERROR function pointer
-}
-
-fn main() {}
+++ /dev/null
-error[E0658]: function pointers cannot appear in constant functions
- --> $DIR/issue-37550.rs:3:9
- |
-LL | let x = || t;
- | ^
- |
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
- = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
+++ /dev/null
-// run-pass
-
-const fn foo() -> i64 {
- 3
-}
-
-const fn bar(x: i64) -> i64 {
- x*2
-}
-
-fn main() {
- let val = &(foo() % 2);
- assert_eq!(*val, 1);
-
- let val2 = &(bar(1+1) % 3);
- assert_eq!(*val2, 1);
-}
+++ /dev/null
-trait Q<T:?Sized> {}
-trait Foo where u32: Q<Self> {
- fn foo(&self);
-}
-
-impl Q<()> for u32 {}
-impl Foo for () {
- fn foo(&self) {
- println!("foo!");
- }
-}
-
-fn main() {
- let _f: Box<dyn Foo> = //~ ERROR `Foo` cannot be made into an object
- Box::new(()); //~ ERROR `Foo` cannot be made into an object
-}
+++ /dev/null
-error[E0038]: the trait `Foo` cannot be made into an object
- --> $DIR/issue-38604.rs:14:13
- |
-LL | let _f: Box<dyn Foo> =
- | ^^^^^^^^^^^^ `Foo` cannot be made into an object
- |
-note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
- --> $DIR/issue-38604.rs:2:22
- |
-LL | trait Foo where u32: Q<Self> {
- | --- ^^^^^^^ ...because it uses `Self` as a type parameter
- | |
- | this trait cannot be made into an object...
-
-error[E0038]: the trait `Foo` cannot be made into an object
- --> $DIR/issue-38604.rs:15:9
- |
-LL | Box::new(());
- | ^^^^^^^^^^^^ `Foo` cannot be made into an object
- |
-note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
- --> $DIR/issue-38604.rs:2:22
- |
-LL | trait Foo where u32: Q<Self> {
- | --- ^^^^^^^ ...because it uses `Self` as a type parameter
- | |
- | this trait cannot be made into an object...
- = note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn Foo>>` for `Box<()>`
- = note: required by cast to type `Box<dyn Foo>`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0038`.
+++ /dev/null
-#![allow(unused_macros)]
-
-macro_rules! assign {
- (($($a:tt)*) = ($($b:tt))*) => { //~ ERROR expected one of: `*`, `+`, or `?`
- $($a)* = $($b)*
- }
-}
-
-fn main() {}
+++ /dev/null
-error: expected one of: `*`, `+`, or `?`
- --> $DIR/issue-39388.rs:4:22
- |
-LL | (($($a:tt)*) = ($($b:tt))*) => {
- | ^^^^^^^
-
-error: aborting due to previous error
-
+++ /dev/null
-struct Point {
- x: f64,
- y: f64,
-}
-
-trait ToString_ {
- fn to_string(&self) -> String;
-}
-
-impl ToString_ for Point {
- fn new(x: f64, y: f64) -> Point {
- //~^ ERROR method `new` is not a member of trait `ToString_`
- Point { x: x, y: y }
- }
-
- fn to_string(&self) -> String {
- format!("({}, {})", self.x, self.y)
- }
-}
-
-fn main() {
- let p = Point::new(0.0, 0.0);
- //~^ ERROR no function or associated item named `new` found for struct `Point`
- println!("{}", p.to_string());
-}
+++ /dev/null
-error[E0407]: method `new` is not a member of trait `ToString_`
- --> $DIR/issue-3973.rs:11:5
- |
-LL | / fn new(x: f64, y: f64) -> Point {
-LL | |
-LL | | Point { x: x, y: y }
-LL | | }
- | |_____^ not a member of trait `ToString_`
-
-error[E0599]: no function or associated item named `new` found for struct `Point` in the current scope
- --> $DIR/issue-3973.rs:22:20
- |
-LL | struct Point {
- | ------------ function or associated item `new` not found for this
-...
-LL | let p = Point::new(0.0, 0.0);
- | ^^^ function or associated item not found in `Point`
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0407, E0599.
-For more information about an error, try `rustc --explain E0407`.
+++ /dev/null
-// run-pass
-// aux-build:issue-39823.rs
-
-extern crate issue_39823;
-use issue_39823::{RemoteC, RemoteG};
-
-#[derive(Debug, PartialEq)]
-struct LocalC(u32);
-
-#[derive(Debug, PartialEq)]
-struct LocalG<T>(T);
-
-fn main() {
- let virtual_localc : &dyn Fn(_) -> LocalC = &LocalC;
- assert_eq!(virtual_localc(1), LocalC(1));
-
- let virtual_localg : &dyn Fn(_) -> LocalG<u32> = &LocalG;
- assert_eq!(virtual_localg(1), LocalG(1));
-
- let virtual_remotec : &dyn Fn(_) -> RemoteC = &RemoteC;
- assert_eq!(virtual_remotec(1), RemoteC(1));
-
- let virtual_remoteg : &dyn Fn(_) -> RemoteG<u32> = &RemoteG;
- assert_eq!(virtual_remoteg(1), RemoteG(1));
-}
+++ /dev/null
-// run-pass
-#![allow(unused_macros)]
-macro_rules! m {
- ($e:expr) => {
- macro_rules! n { () => { $e } }
- }
-}
-
-fn main() {
- m!(foo!());
-}
+++ /dev/null
-// check-pass
-macro_rules! m {
- ($i:meta) => {
- #[derive($i)]
- struct S;
- }
-}
-
-m!(Clone);
-
-fn main() {}
trait A {
}
-impl<T> Drop for T where T: A { //~ ERROR E0119
- //~^ ERROR E0120
- //~| ERROR E0210
+impl<T> Drop for T where T: A {
+ //~^ ERROR E0120
+ //~| ERROR E0210
fn drop(&mut self) {
}
}
-error[E0119]: conflicting implementations of trait `std::ops::Drop` for type `std::boxed::Box<_, _>`
- --> $DIR/issue-41974.rs:7:1
+error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
+ --> $DIR/issue-41974.rs:7:6
|
LL | impl<T> Drop for T where T: A {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^ type parameter `T` must be used as the type parameter for some local type
|
- = note: conflicting implementation in crate `alloc`:
- - impl<T, A> Drop for Box<T, A>
- where A: Allocator, T: ?Sized;
- = note: downstream crates may implement trait `A` for type `std::boxed::Box<_, _>`
+ = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
+ = note: only traits defined in the current crate can be implemented for a type parameter
error[E0120]: the `Drop` trait may only be implemented for structs, enums, and unions
--> $DIR/issue-41974.rs:7:18
LL | impl<T> Drop for T where T: A {
| ^ must be a struct, enum, or union
-error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
- --> $DIR/issue-41974.rs:7:6
- |
-LL | impl<T> Drop for T where T: A {
- | ^ type parameter `T` must be used as the type parameter for some local type
- |
- = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
- = note: only traits defined in the current crate can be implemented for a type parameter
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
-Some errors have detailed explanations: E0119, E0120, E0210.
-For more information about an error, try `rustc --explain E0119`.
+Some errors have detailed explanations: E0120, E0210.
+For more information about an error, try `rustc --explain E0120`.
+++ /dev/null
-// run-pass
-use std::ops::{Deref, DerefMut};
-
-struct CheckedDeref<T, F> {
- value: T,
- check: F
-}
-
-impl<F: Fn(&T) -> bool, T> Deref for CheckedDeref<T, F> {
- type Target = T;
- fn deref(&self) -> &T {
- assert!((self.check)(&self.value));
- &self.value
- }
-}
-
-impl<F: Fn(&T) -> bool, T> DerefMut for CheckedDeref<T, F> {
- fn deref_mut(&mut self) -> &mut T {
- assert!((self.check)(&self.value));
- &mut self.value
- }
-}
-
-
-fn main() {
- let mut v = CheckedDeref {
- value: vec![0],
- check: |v: &Vec<_>| !v.is_empty()
- };
- v.push(1);
- assert_eq!(*v, vec![0, 1]);
-}
+++ /dev/null
-// run-pass
-#![feature(box_syntax)]
-#![feature(box_patterns)]
-
-#[derive(Debug, PartialEq)]
-enum Test {
- Foo(usize),
- Bar(isize),
-}
-
-fn main() {
- let a = box Test::Foo(10);
- let b = box Test::Bar(-20);
- match (a, b) {
- (_, box Test::Foo(_)) => unreachable!(),
- (box Test::Foo(x), b) => {
- assert_eq!(x, 10);
- assert_eq!(b, box Test::Bar(-20));
- },
- _ => unreachable!(),
- }
-}
+++ /dev/null
-// run-pass
-macro_rules! fooN {
- ($cur:ident $prev:ty) => {
- #[allow(dead_code)]
- enum $cur {
- Empty,
- First($prev),
- Second($prev),
- Third($prev),
- Fourth($prev),
- }
- }
-}
-
-fooN!(Foo0 ());
-fooN!(Foo1 Foo0);
-fooN!(Foo2 Foo1);
-fooN!(Foo3 Foo2);
-fooN!(Foo4 Foo3);
-fooN!(Foo5 Foo4);
-fooN!(Foo6 Foo5);
-fooN!(Foo7 Foo6);
-fooN!(Foo8 Foo7);
-fooN!(Foo9 Foo8);
-fooN!(Foo10 Foo9);
-fooN!(Foo11 Foo10);
-fooN!(Foo12 Foo11);
-fooN!(Foo13 Foo12);
-fooN!(Foo14 Foo13);
-fooN!(Foo15 Foo14);
-fooN!(Foo16 Foo15);
-fooN!(Foo17 Foo16);
-fooN!(Foo18 Foo17);
-fooN!(Foo19 Foo18);
-fooN!(Foo20 Foo19);
-fooN!(Foo21 Foo20);
-fooN!(Foo22 Foo21);
-fooN!(Foo23 Foo22);
-fooN!(Foo24 Foo23);
-fooN!(Foo25 Foo24);
-fooN!(Foo26 Foo25);
-fooN!(Foo27 Foo26);
-
-fn main() {
- let _foo = Foo27::Empty;
-}
+++ /dev/null
-// Issue 46112: An extern crate pub re-exporting libcore was causing
-// paths rooted from `std` to be misrendered in the diagnostic output.
-
-// ignore-windows
-// aux-build:xcrate-issue-43189-a.rs
-// aux-build:xcrate-issue-43189-b.rs
-
-extern crate xcrate_issue_43189_b;
-fn main() {
- ().a();
- //~^ ERROR no method named `a` found
-}
+++ /dev/null
-error[E0599]: no method named `a` found for unit type `()` in the current scope
- --> $DIR/issue-43189.rs:10:8
- |
-LL | ().a();
- | ^ method not found in `()`
- |
- ::: $DIR/auxiliary/xcrate-issue-43189-a.rs:5:8
- |
-LL | fn a(&self) {}
- | - the method is available for `()` here
- |
- = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
- |
-LL | use xcrate_issue_43189_b::xcrate_issue_43189_a::A;
- |
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0599`.
+++ /dev/null
-// run-pass
-pub fn main() {
- let mut count = 0;
- for _ in 0..999_999 { count += 1; }
- assert_eq!(count, 999_999);
- println!("{}", count);
-}
+++ /dev/null
-// run-pass
-// ignore-emscripten no threads support
-
-use std::sync::mpsc::channel;
-use std::thread;
-
-pub fn main() {
- let (tx, rx) = channel::<&'static str>();
-
- let t = thread::spawn(move|| {
- assert_eq!(rx.recv().unwrap(), "hello, world");
- });
-
- tx.send("hello, world").unwrap();
- t.join().ok().unwrap();
-}
+++ /dev/null
-// run-pass
-#![allow(unreachable_code)]
-// compile-flags: --edition 2018
-
-#![feature(try_blocks)]
-
-fn main() {
- let mut a = 0;
- let () = {
- let _: Result<(), ()> = try {
- let _ = Err(())?;
- return
- };
- a += 1;
- };
- a += 2;
- assert_eq!(a, 3);
-}
+++ /dev/null
-// run-pass
-#![allow(dead_code)]
-#![allow(unused_variables)]
-#![feature(unsize, coerce_unsized)]
-
-#[repr(packed)]
-struct UnalignedPtr<'a, T: ?Sized>
- where T: 'a,
-{
- data: &'a T,
-}
-
-fn main() {
-
- impl<'a, T, U> std::ops::CoerceUnsized<UnalignedPtr<'a, U>> for UnalignedPtr<'a, T>
- where
- T: std::marker::Unsize<U> + ?Sized,
- U: ?Sized,
- { }
-
- let arr = [1, 2, 3];
- let arr_unaligned: UnalignedPtr<[i32; 3]> = UnalignedPtr { data: &arr };
- let arr_unaligned: UnalignedPtr<[i32]> = arr_unaligned;
-}
+++ /dev/null
-// run-pass
-struct A;
-
-impl A {
- fn take_mutably(&mut self) {}
-}
-
-fn identity<T>(t: T) -> T {
- t
-}
-
-// Issue 46095
-// Built-in indexing should be used even when the index is not
-// trivially an integer
-// Overloaded indexing would cause wrapped to be borrowed mutably
-
-fn main() {
- let mut a1 = A;
- let mut a2 = A;
-
- let wrapped = [&mut a1, &mut a2];
-
- {
- wrapped[0 + 1 - 1].take_mutably();
- }
-
- {
- wrapped[identity(0)].take_mutably();
- }
-}
+++ /dev/null
-// Issue 46112: An extern crate pub re-exporting libcore was causing
-// paths rooted from `std` to be misrendered in the diagnostic output.
-
-// ignore-windows
-// aux-build:xcrate-issue-46112-rexport-core.rs
-
-extern crate xcrate_issue_46112_rexport_core;
-fn test(r: Result<Option<()>, &'static str>) { }
-fn main() { test(Ok(())); }
-//~^ mismatched types
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/issue-46112.rs:9:21
- |
-LL | fn main() { test(Ok(())); }
- | ^^
- | |
- | expected enum `Option`, found `()`
- | help: try using a variant of the expected enum: `Some(())`
- |
- = note: expected enum `Option<()>`
- found unit type `()`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
+++ /dev/null
-// run-pass
-// Regression test for issue #47139:
-//
-// Coherence was encountering an (unnecessary) overflow trying to
-// decide if the two impls of dummy overlap.
-//
-// The overflow went something like:
-//
-// - `&'a ?T: Insertable` ?
-// - let ?T = Option<?U> ?
-// - `Option<?U>: Insertable` ?
-// - `Option<&'a ?U>: Insertable` ?
-// - `&'a ?U: Insertable` ?
-//
-// While somewhere in the middle, a projection would occur, which
-// broke cycle detection.
-//
-// It turned out that this cycle was being kicked off due to some
-// extended diagnostic attempts in coherence, so removing those
-// sidestepped the issue for now.
-
-#![allow(dead_code)]
-
-pub trait Insertable {
- type Values;
-
- fn values(self) -> Self::Values;
-}
-
-impl<T> Insertable for Option<T>
- where
- T: Insertable,
- T::Values: Default,
-{
- type Values = T::Values;
-
- fn values(self) -> Self::Values {
- self.map(Insertable::values).unwrap_or_default()
- }
-}
-
-impl<'a, T> Insertable for &'a Option<T>
- where
- Option<&'a T>: Insertable,
-{
- type Values = <Option<&'a T> as Insertable>::Values;
-
- fn values(self) -> Self::Values {
- self.as_ref().values()
- }
-}
-
-impl<'a, T> Insertable for &'a [T]
-{
- type Values = Self;
-
- fn values(self) -> Self::Values {
- self
- }
-}
-
-trait Unimplemented { }
-
-trait Dummy { }
-
-struct Foo<T> { t: T }
-
-impl<'a, U> Dummy for Foo<&'a U>
- where &'a U: Insertable
-{
-}
-
-impl<T> Dummy for T
- where T: Unimplemented
-{ }
-
-fn main() {
-}
+++ /dev/null
-#![allow(unused_variables)]; //~ ERROR expected item, found `;`
-//~^ ERROR `main` function
-fn foo() {}
+++ /dev/null
-error: expected item, found `;`
- --> $DIR/issue-49040.rs:1:28
- |
-LL | #![allow(unused_variables)];
- | ^ help: remove this semicolon
-
-error[E0601]: `main` function not found in crate `issue_49040`
- --> $DIR/issue-49040.rs:1:1
- |
-LL | #![allow(unused_variables)];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ consider adding a `main` function to `$DIR/issue-49040.rs`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0601`.
+++ /dev/null
-// check-pass
-
-fn fibs(n: u32) -> impl Iterator<Item=u128> {
- (0 .. n)
- .scan((0, 1), |st, _| {
- *st = (st.1, st.0 + st.1);
- Some(*st)
- })
- .map(&|(f, _)| f)
-}
-
-fn main() {
- println!("{:?}", fibs(10).collect::<Vec<_>>());
-}
+++ /dev/null
-// run-pass
-// Regression test for #49685: drop elaboration was not revealing the
-// value of `impl Trait` returns, leading to an ICE.
-
-fn main() {
- let _ = Some(())
- .into_iter()
- .flat_map(|_| Some(()).into_iter().flat_map(func));
-}
-
-fn func(_: ()) -> impl Iterator<Item = ()> {
- Some(()).into_iter().flat_map(|_| vec![])
-}
+++ /dev/null
-// run-pass
-enum Void {}
-fn foo(_: Result<(Void, u32), (Void, String)>) {}
-fn main() {
- let _: fn(_) = foo;
-}
+++ /dev/null
-trait B <A> {
- fn a() -> A {
- this.a //~ ERROR cannot find value `this` in this scope
- }
- fn b(x: i32) {
- this.b(x); //~ ERROR cannot find value `this` in this scope
- }
- fn c() {
- let _ = || this.a; //~ ERROR cannot find value `this` in this scope
- }
-}
-
-fn main() {}
+++ /dev/null
-error[E0425]: cannot find value `this` in this scope
- --> $DIR/issue-5099.rs:3:9
- |
-LL | this.a
- | ^^^^ not found in this scope
- |
-help: you might have meant to use `self` here instead
- |
-LL | self.a
- | ~~~~
-help: if you meant to use `self`, you are also missing a `self` receiver argument
- |
-LL | fn a(&self) -> A {
- | +++++
-
-error[E0425]: cannot find value `this` in this scope
- --> $DIR/issue-5099.rs:6:9
- |
-LL | this.b(x);
- | ^^^^ not found in this scope
- |
-help: you might have meant to use `self` here instead
- |
-LL | self.b(x);
- | ~~~~
-help: if you meant to use `self`, you are also missing a `self` receiver argument
- |
-LL | fn b(&self, x: i32) {
- | ++++++
-
-error[E0425]: cannot find value `this` in this scope
- --> $DIR/issue-5099.rs:9:20
- |
-LL | let _ = || this.a;
- | ^^^^ not found in this scope
- |
-help: you might have meant to use `self` here instead
- |
-LL | let _ = || self.a;
- | ~~~~
-help: if you meant to use `self`, you are also missing a `self` receiver argument
- |
-LL | fn c(&self) {
- | +++++
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0425`.
+++ /dev/null
-// compile-flags: --crate-type dylib --target thumbv7em-none-eabihf
-// needs-llvm-components: arm
-// build-pass
-// error-pattern: dropping unsupported crate type `dylib` for target `thumbv7em-none-eabihf`
-
-#![feature(no_core)]
-
-#![no_std]
-#![no_core]
+++ /dev/null
-warning: dropping unsupported crate type `dylib` for target `thumbv7em-none-eabihf`
-
-warning: 1 warning emitted
-
+++ /dev/null
-// run-pass
-fn foo() -> impl Into<for<'a> fn(&'a ())> {
- (|_| {}) as for<'a> fn(&'a ())
-}
-
-fn main() {
- foo().into()(&());
-}
+++ /dev/null
-// run-pass
-#![allow(unreachable_code)]
-
-fn main() {
- let mut v = Vec::new();
-
- loop { v.push(break) }
-}
+++ /dev/null
-// run-pass
-#![feature(core_intrinsics)]
-
-#[repr(i8)]
-pub enum Enum {
- VariantA,
- VariantB,
-}
-
-fn make_b() -> Enum { Enum::VariantB }
-
-fn main() {
- assert_eq!(1, make_b() as i8);
- assert_eq!(1, make_b() as u8);
- assert_eq!(1, make_b() as i32);
- assert_eq!(1, make_b() as u32);
- assert_eq!(1, std::intrinsics::discriminant_value(&make_b()));
-}
+++ /dev/null
-// Regression test for Issue #53787: Fix ICE when creating a label in inline assembler with macros.
-
-// build-fail
-// ignore-emscripten
-
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-macro_rules! fake_jump {
- ($id:expr) => {
- unsafe {
- llvm_asm!(
- "
- jmp $0
- lea eax, [ebx]
- xor eax, 0xDEADBEEF
- retn
- $0:
- "::"0"($id)::"volatile", "intel");
- }
- };
-}
-
-fn main() {
- fake_jump!("FirstFunc"); //~ ERROR invalid value for constraint in inline assembly
- println!("Hello, world!");
-}
+++ /dev/null
-error[E0669]: invalid value for constraint in inline assembly
- --> $DIR/issue-53787-inline-assembler-macro.rs:25:16
- |
-LL | fake_jump!("FirstFunc");
- | ^^^^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0669`.
+++ /dev/null
-// run-pass
-
-pub trait Stream {
- type Item;
- type Error;
-}
-
-pub trait ParseError<I> {
- type Output;
-}
-
-impl ParseError<char> for u32 {
- type Output = ();
-}
-
-impl Stream for () {
- type Item = char;
- type Error = u32;
-}
-
-pub struct Lex<'a, I>
- where I: Stream,
- I::Error: ParseError<char>,
- <<I as Stream>::Error as ParseError<char>>::Output: 'a
-{
- x: &'a <I::Error as ParseError<char>>::Output
-}
-
-pub struct Reserved<'a, I> where
- I: Stream<Item=char> + 'a,
- I::Error: ParseError<I::Item>,
- <<I as Stream>::Error as ParseError<char>>::Output: 'a
-
-{
- x: Lex<'a, I>
-}
-
-fn main() {
- let r: Reserved<()> = Reserved {
- x: Lex {
- x: &()
- }
- };
-
- let _v = r.x.x;
-}
+++ /dev/null
-struct T;
-
-impl for T {}
-//~^ ERROR missing trait in a trait impl
-
-fn main() {}
+++ /dev/null
-error: missing trait in a trait impl
- --> $DIR/issue-56031.rs:3:5
- |
-LL | impl for T {}
- | ^
- |
-help: add a trait here
- |
-LL | impl Trait for T {}
- | +++++
-help: for an inherent impl, drop this `for`
- |
-LL - impl for T {}
-LL + impl T {}
- |
-
-error: aborting due to previous error
-
+++ /dev/null
-// check-pass
-
-// Originally from #53925.
-// Tests that the `unreachable_pub` lint doesn't fire for `pub self::bar::Bar`.
-
-#![deny(unreachable_pub)]
-
-mod foo {
- mod bar {
- pub struct Bar;
- }
-
- pub use self::bar::Bar;
-}
-
-pub use foo::Bar;
-
-fn main() {}
+++ /dev/null
-// Regression test for #57597.
-//
-// Make sure that nested matchers work correctly rather than causing an infinite loop or crash.
-
-// edition:2018
-
-macro_rules! foo1 {
- ($($($i:ident)?)+) => {};
- //~^ ERROR repetition matches empty token tree
-}
-
-macro_rules! foo2 {
- ($($($i:ident)?)*) => {};
- //~^ ERROR repetition matches empty token tree
-}
-
-macro_rules! foo3 {
- ($($($i:ident)?)?) => {};
- //~^ ERROR repetition matches empty token tree
-}
-
-macro_rules! foo4 {
- ($($($($i:ident)?)?)?) => {};
- //~^ ERROR repetition matches empty token tree
-}
-
-macro_rules! foo5 {
- ($($($($i:ident)*)?)?) => {};
- //~^ ERROR repetition matches empty token tree
-}
-
-macro_rules! foo6 {
- ($($($($i:ident)?)*)?) => {};
- //~^ ERROR repetition matches empty token tree
-}
-
-macro_rules! foo7 {
- ($($($($i:ident)?)?)*) => {};
- //~^ ERROR repetition matches empty token tree
-}
-
-macro_rules! foo8 {
- ($($($($i:ident)*)*)?) => {};
- //~^ ERROR repetition matches empty token tree
-}
-
-macro_rules! foo9 {
- ($($($($i:ident)?)*)*) => {};
- //~^ ERROR repetition matches empty token tree
-}
-
-macro_rules! foo10 {
- ($($($($i:ident)?)*)+) => {};
- //~^ ERROR repetition matches empty token tree
-}
-
-macro_rules! foo11 {
- ($($($($i:ident)+)?)*) => {};
- //~^ ERROR repetition matches empty token tree
-}
-
-macro_rules! foo12 {
- ($($($($i:ident)+)*)?) => {};
- //~^ ERROR repetition matches empty token tree
-}
-
-fn main() {
- foo1!();
- foo2!();
- foo3!();
- foo4!();
- foo5!();
- foo6!();
- foo7!();
- foo8!();
- foo9!();
- foo10!();
- foo11!();
- foo12!();
-}
+++ /dev/null
-error: repetition matches empty token tree
- --> $DIR/issue-57597.rs:8:7
- |
-LL | ($($($i:ident)?)+) => {};
- | ^^^^^^^^^^^^^^
-
-error: repetition matches empty token tree
- --> $DIR/issue-57597.rs:13:7
- |
-LL | ($($($i:ident)?)*) => {};
- | ^^^^^^^^^^^^^^
-
-error: repetition matches empty token tree
- --> $DIR/issue-57597.rs:18:7
- |
-LL | ($($($i:ident)?)?) => {};
- | ^^^^^^^^^^^^^^
-
-error: repetition matches empty token tree
- --> $DIR/issue-57597.rs:23:7
- |
-LL | ($($($($i:ident)?)?)?) => {};
- | ^^^^^^^^^^^^^^^^^^
-
-error: repetition matches empty token tree
- --> $DIR/issue-57597.rs:28:7
- |
-LL | ($($($($i:ident)*)?)?) => {};
- | ^^^^^^^^^^^^^^^^^^
-
-error: repetition matches empty token tree
- --> $DIR/issue-57597.rs:33:7
- |
-LL | ($($($($i:ident)?)*)?) => {};
- | ^^^^^^^^^^^^^^^^^^
-
-error: repetition matches empty token tree
- --> $DIR/issue-57597.rs:38:7
- |
-LL | ($($($($i:ident)?)?)*) => {};
- | ^^^^^^^^^^^^^^^^^^
-
-error: repetition matches empty token tree
- --> $DIR/issue-57597.rs:43:7
- |
-LL | ($($($($i:ident)*)*)?) => {};
- | ^^^^^^^^^^^^^^^^^^
-
-error: repetition matches empty token tree
- --> $DIR/issue-57597.rs:48:7
- |
-LL | ($($($($i:ident)?)*)*) => {};
- | ^^^^^^^^^^^^^^^^^^
-
-error: repetition matches empty token tree
- --> $DIR/issue-57597.rs:53:7
- |
-LL | ($($($($i:ident)?)*)+) => {};
- | ^^^^^^^^^^^^^^^^^^
-
-error: repetition matches empty token tree
- --> $DIR/issue-57597.rs:58:7
- |
-LL | ($($($($i:ident)+)?)*) => {};
- | ^^^^^^^^^^^^^^^^^^
-
-error: repetition matches empty token tree
- --> $DIR/issue-57597.rs:63:7
- |
-LL | ($($($($i:ident)+)*)?) => {};
- | ^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 12 previous errors
-
+++ /dev/null
-// run-pass
-fn main() {}
-#[derive(Clone)]
-pub struct Little;
-#[derive(Clone)]
-pub struct Big(
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
-);
+++ /dev/null
-#![feature(trait_alias)]
-
-trait Svc<Req> { type Res; }
-
-trait MkSvc<Target, Req> = Svc<Target> where Self::Res: Svc<Req>;
-//~^ ERROR associated type `Res` not found for `Self`
-//~| ERROR associated type `Res` not found for `Self`
-
-fn main() {}
+++ /dev/null
-error[E0220]: associated type `Res` not found for `Self`
- --> $DIR/issue-59029-1.rs:5:52
- |
-LL | trait MkSvc<Target, Req> = Svc<Target> where Self::Res: Svc<Req>;
- | ^^^ associated type `Res` not found
-
-error[E0220]: associated type `Res` not found for `Self`
- --> $DIR/issue-59029-1.rs:5:52
- |
-LL | trait MkSvc<Target, Req> = Svc<Target> where Self::Res: Svc<Req>;
- | ^^^ associated type `Res` not found
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0220`.
+++ /dev/null
-#![allow(dead_code)]
-#![feature(const_generics_defaults)]
-
-// This test checks that generic parameter re-ordering diagnostic suggestions mention that
-// consts come after types and lifetimes when the `const_generics_defaults` feature is enabled.
-// We cannot run rustfix on this test because of the above const generics warning.
-
-struct A;
-
-impl A {
- pub fn do_things<T, 'a, 'b: 'a>() {
- //~^ ERROR lifetime parameters must be declared prior to type parameters
- println!("panic");
- }
-}
-
-fn main() {}
+++ /dev/null
-error: lifetime parameters must be declared prior to type parameters
- --> $DIR/issue-59508-1.rs:11:25
- |
-LL | pub fn do_things<T, 'a, 'b: 'a>() {
- | ----^^--^^----- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b: 'a, T>`
-
-error: aborting due to previous error
-
+++ /dev/null
-// run-rustfix
-
-#![allow(dead_code)]
-
-// This test checks that generic parameter re-ordering diagnostic suggestions contain bounds.
-
-struct A;
-
-impl A {
- pub fn do_things<'a, 'b: 'a, T>() {
- //~^ ERROR lifetime parameters must be declared prior to type parameters
- println!("panic");
- }
-}
-
-fn main() {}
+++ /dev/null
-// run-rustfix
-
-#![allow(dead_code)]
-
-// This test checks that generic parameter re-ordering diagnostic suggestions contain bounds.
-
-struct A;
-
-impl A {
- pub fn do_things<T, 'a, 'b: 'a>() {
- //~^ ERROR lifetime parameters must be declared prior to type parameters
- println!("panic");
- }
-}
-
-fn main() {}
+++ /dev/null
-error: lifetime parameters must be declared prior to type parameters
- --> $DIR/issue-59508.rs:10:25
- |
-LL | pub fn do_things<T, 'a, 'b: 'a>() {
- | ----^^--^^----- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b: 'a, T>`
-
-error: aborting due to previous error
-
+++ /dev/null
-pub trait Trait<'a> {
- type Item;
-}
-
-impl<'a> Trait<'a> for () {
- type Item = ();
-}
-
-pub fn foo<T, F>(_: T, _: F)
-where
- T: for<'a> Trait<'a>,
- F: for<'a> FnMut(<T as Trait<'a>>::Item),
-{
-}
-
-fn main() {
- foo((), drop)
- //~^ ERROR type mismatch in function arguments
- //~| ERROR size for values of type `<() as Trait<'_>>::Item` cannot be known at compilation time
-}
+++ /dev/null
-error[E0631]: type mismatch in function arguments
- --> $DIR/issue-60283.rs:17:13
- |
-LL | foo((), drop)
- | --- ^^^^
- | | |
- | | expected signature of `for<'a> fn(<() as Trait<'a>>::Item) -> _`
- | | found signature of `fn(()) -> _`
- | required by a bound introduced by this call
- |
-note: required by a bound in `foo`
- --> $DIR/issue-60283.rs:12:16
- |
-LL | pub fn foo<T, F>(_: T, _: F)
- | --- required by a bound in this
-...
-LL | F: for<'a> FnMut(<T as Trait<'a>>::Item),
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `foo`
-
-error[E0277]: the size for values of type `<() as Trait<'_>>::Item` cannot be known at compilation time
- --> $DIR/issue-60283.rs:17:13
- |
-LL | foo((), drop)
- | --- ^^^^ doesn't have a size known at compile-time
- | |
- | required by a bound introduced by this call
- |
- = help: the trait `Sized` is not implemented for `<() as Trait<'_>>::Item`
-note: required by a bound in `std::mem::drop`
- --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
- |
-LL | pub fn drop<T>(_x: T) {}
- | ^ required by this bound in `std::mem::drop`
-help: consider further restricting the associated type
- |
-LL | fn main() where <() as Trait<'_>>::Item: Sized {
- | ++++++++++++++++++++++++++++++++++++
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0277, E0631.
-For more information about an error, try `rustc --explain E0277`.
+++ /dev/null
-// check-pass
-// compile-flags: -Z unpretty=hir
-
-#![feature(type_alias_impl_trait)]
-
-trait Animal {}
-
-fn main() {
- pub type ServeFut = impl Animal;
-}
+++ /dev/null
-// check-pass
-// compile-flags: -Z unpretty=hir
-
-#![feature(type_alias_impl_trait)]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
-#[macro_use]
-extern crate std;
-
-trait Animal { }
-
-fn main() {
- pub type ServeFut = /*impl Trait*/;
- }
+++ /dev/null
-// Issue 61711: A crate pub re-exporting `crate` was causing an
-// infinite loop.
-
-// edition:2018
-// aux-build:xcrate-issue-61711-b.rs
-// compile-flags:--extern xcrate_issue_61711_b
-
-// build-pass
-
-fn f<F: Fn(xcrate_issue_61711_b::Struct)>(_: F) { }
-fn main() { }
+++ /dev/null
-struct A<T>(T);
-
-impl A<&'static u8> {
- fn f() {
- let x = 0;
- Self(&x);
- //~^ ERROR `x` does not live long enough
- }
-}
-
-fn main() {}
+++ /dev/null
-error[E0597]: `x` does not live long enough
- --> $DIR/issue-61882-2.rs:6:14
- |
-LL | Self(&x);
- | ^^
- | |
- | borrowed value does not live long enough
- | this usage requires that `x` is borrowed for `'static`
-LL |
-LL | }
- | - `x` dropped here while still borrowed
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0597`.
+++ /dev/null
-struct A<T>(T);
-
-impl A<bool> {
- const B: A<u8> = Self(0);
- //~^ ERROR mismatched types
- //~| ERROR mismatched types
-}
-
-fn main() {}
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/issue-61882.rs:4:27
- |
-LL | const B: A<u8> = Self(0);
- | ^ expected `bool`, found integer
-
-error[E0308]: mismatched types
- --> $DIR/issue-61882.rs:4:22
- |
-LL | const B: A<u8> = Self(0);
- | ^^^^^^^ expected `u8`, found `bool`
- |
- = note: expected struct `A<u8>`
- found struct `A<bool>`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
+++ /dev/null
-fn part(_: u16) -> u32 {
- 1
-}
-
-fn main() {
- for n in 100_000.. {
- //~^ ERROR: literal out of range for `u16`
- let _ = part(n);
- }
-}
+++ /dev/null
-error: literal out of range for `u16`
- --> $DIR/issue-63364.rs:6:14
- |
-LL | for n in 100_000.. {
- | ^^^^^^^
- |
- = note: `#[deny(overflowing_literals)]` on by default
- = note: the literal `100_000` does not fit into the type `u16` whose range is `0..=65535`
-
-error: aborting due to previous error
-
+++ /dev/null
-macro_rules! e {
- ($inp:ident) => (
- $nonexistent
- //~^ ERROR expected expression, found `$`
- );
-}
-
-fn main() {
- e!(foo);
-}
+++ /dev/null
-error: expected expression, found `$`
- --> $DIR/issue-6596-1.rs:3:9
- |
-LL | $nonexistent
- | ^^^^^^^^^^^^ expected expression
-...
-LL | e!(foo);
- | ------- in this macro invocation
- |
- = note: this error originates in the macro `e` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to previous error
-
+++ /dev/null
-// Matching against NaN should result in a warning
-
-#![allow(unused)]
-#![deny(illegal_floating_point_literal_pattern)]
-
-const NAN: f64 = f64::NAN;
-
-fn main() {
- let x = NAN;
- match x {
- NAN => {}, //~ ERROR floating-point types cannot be used
- //~| WARN this was previously accepted by the compiler but is being phased out
- _ => {},
- };
-
- match [x, 1.0] {
- [NAN, _] => {}, //~ ERROR floating-point types cannot be used
- //~| WARN this was previously accepted by the compiler but is being phased out
- _ => {},
- };
-}
+++ /dev/null
-error: floating-point types cannot be used in patterns
- --> $DIR/issue-6804.rs:11:9
- |
-LL | NAN => {},
- | ^^^
- |
-note: the lint level is defined here
- --> $DIR/issue-6804.rs:4:9
- |
-LL | #![deny(illegal_floating_point_literal_pattern)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
-
-error: floating-point types cannot be used in patterns
- --> $DIR/issue-6804.rs:17:10
- |
-LL | [NAN, _] => {},
- | ^^^
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
-
-error: aborting due to 2 previous errors
-
+++ /dev/null
-// check-pass
-
-pub trait ResultExt {
- type Ok;
- fn err_eprint_and_ignore(self) -> Option<Self::Ok>;
-}
-
-impl<O, E> ResultExt for std::result::Result<O, E>
-where
- E: std::error::Error,
-{
- type Ok = O;
- fn err_eprint_and_ignore(self) -> Option<O>
- where
- Self: ,
- {
- match self {
- Err(e) => {
- eprintln!("{}", e);
- None
- }
- Ok(o) => Some(o),
- }
- }
-}
-
-fn main() {}
pub unsafe fn g() {
return;
if *ptr::null() {}; //~ ERROR unreachable
+ //~| WARNING dereferencing a null pointer
}
pub fn main() {}
LL | #![deny(unreachable_code)]
| ^^^^^^^^^^^^^^^^
-error: aborting due to previous error
+warning: dereferencing a null pointer
+ --> $DIR/issue-7246.rs:7:8
+ |
+LL | if *ptr::null() {};
+ | ^^^^^^^^^^^^ this code causes undefined behavior when executed
+ |
+ = note: `#[warn(deref_nullptr)]` on by default
+
+error: aborting due to previous error; 1 warning emitted
+++ /dev/null
-struct Binder(i32, i32, i32);
-
-fn main() {
- let x = Binder(1, 2, 3);
- match x {
- Binder(_a, _x @ ..) => {}
- _ => {}
- }
-}
-//~^^^^ ERROR `_x @` is not allowed in a tuple struct
-//~| ERROR: `..` patterns are not allowed here
-//~| ERROR: this pattern has 2 fields, but the corresponding tuple struct has 3 fields
+++ /dev/null
-error: `_x @` is not allowed in a tuple struct
- --> $DIR/issue-72574-2.rs:6:20
- |
-LL | Binder(_a, _x @ ..) => {}
- | ^^^^^^^ this is only allowed in slice patterns
- |
- = help: remove this and bind each tuple field independently
-help: if you don't need to use the contents of _x, discard the tuple's remaining fields
- |
-LL | Binder(_a, ..) => {}
- | ~~
-
-error: `..` patterns are not allowed here
- --> $DIR/issue-72574-2.rs:6:25
- |
-LL | Binder(_a, _x @ ..) => {}
- | ^^
- |
- = note: only allowed in tuple, tuple struct, and slice patterns
-
-error[E0023]: this pattern has 2 fields, but the corresponding tuple struct has 3 fields
- --> $DIR/issue-72574-2.rs:6:16
- |
-LL | struct Binder(i32, i32, i32);
- | --- --- --- tuple struct has 3 fields
-...
-LL | Binder(_a, _x @ ..) => {}
- | ^^ ^^^^^^^ expected 3 fields, found 2
- |
-help: use `_` to explicitly ignore each field
- |
-LL | Binder(_a, _x @ .., _) => {}
- | +++
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0023`.
+++ /dev/null
-// edition:2018
-
-fn main() {
- 'a: loop {
- async {
- loop {
- continue 'a
- //~^ ERROR use of unreachable label `'a`
- }
- };
- }
-}
+++ /dev/null
-error[E0767]: use of unreachable label `'a`
- --> $DIR/issue-73541-1.rs:7:26
- |
-LL | 'a: loop {
- | -- unreachable label defined here
-...
-LL | continue 'a
- | ^^ unreachable label `'a`
- |
- = note: labels are unreachable through functions, closures, async blocks and modules
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0767`.
+++ /dev/null
-fn main() {
- let _ = &&[0] as &[_];
- //~^ ERROR non-primitive cast: `&&[i32; 1]` as `&[_]`
- let _ = 7u32 as Option<_>;
- //~^ ERROR non-primitive cast: `u32` as `Option<_>`
-}
+++ /dev/null
-error[E0605]: non-primitive cast: `&&[i32; 1]` as `&[_]`
- --> $DIR/issue-73886.rs:2:13
- |
-LL | let _ = &&[0] as &[_];
- | ^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
-
-error[E0605]: non-primitive cast: `u32` as `Option<_>`
- --> $DIR/issue-73886.rs:4:13
- |
-LL | let _ = 7u32 as Option<_>;
- | ^^^^^^^^^^^^^^^^^ help: consider using the `From` trait instead: `Option<_>::from(7u32)`
- |
- = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0605`.
+++ /dev/null
-// compile-flags: -O
-// run-pass
-
-struct Foo {
- x: i32,
-}
-
-pub fn main() {
- let mut foo = Foo { x: 42 };
- let x = &mut foo.x;
- *x = 13;
- let y = foo;
- assert_eq!(y.x, 13); // used to print 42 due to mir-opt bug
-}
+++ /dev/null
-// run-fail
-// error-pattern:quux
-// ignore-emscripten no processes
-
-use std::marker::PhantomData;
-
-fn test00_start(ch: Chan<isize>, message: isize) {
- send(ch, message);
-}
-
-type TaskId = isize;
-type PortId = isize;
-
-struct Chan<T> {
- task: TaskId,
- port: PortId,
- marker: PhantomData<*mut T>,
-}
-
-fn send<T: Send>(_ch: Chan<T>, _data: T) {
- panic!();
-}
-
-fn main() {
- panic!("quux");
-}
+++ /dev/null
-// run-pass
-#![allow(dead_code)]
-
-enum E {
- Foo{f: isize},
- Bar,
-}
-
-pub fn main() {
- let e = E::Foo{f: 0};
- match e {
- E::Foo{f: 1} => panic!(),
- E::Foo{..} => (),
- _ => panic!(),
- }
-}
+++ /dev/null
-// run-pass
-#![allow(dead_code)]
-
-enum E {
- Foo{f: isize, b: bool},
- Bar,
-}
-
-pub fn main() {
- let e = E::Foo{f: 0, b: false};
- match e {
- E::Foo{f: 1, b: true} => panic!(),
- E::Foo{b: false, f: 0} => (),
- _ => panic!(),
- }
-}
+++ /dev/null
-use std::fmt::Write;
-
-fn main() {
- println!(b"foo");
- //~^ ERROR format argument must be a string literal
- //~| HELP consider removing the leading `b`
- let mut s = String::new();
- write!(s, b"foo{}", "bar");
- //~^ ERROR format argument must be a string literal
- //~| HELP consider removing the leading `b`
-}
+++ /dev/null
-error: format argument must be a string literal
- --> $DIR/issue-86865.rs:4:14
- |
-LL | println!(b"foo");
- | -^^^^^
- | |
- | help: consider removing the leading `b`
-
-error: format argument must be a string literal
- --> $DIR/issue-86865.rs:8:15
- |
-LL | write!(s, b"foo{}", "bar");
- | -^^^^^^^
- | |
- | help: consider removing the leading `b`
-
-error: aborting due to 2 previous errors
-
+++ /dev/null
-// run-pass
-// ignore-emscripten no threads support
-
-use std::thread;
-use std::sync::mpsc::{channel, Receiver};
-
-fn periodical(n: isize) -> Receiver<bool> {
- let (chan, port) = channel();
- thread::spawn(move|| {
- loop {
- for _ in 1..n {
- match chan.send(false) {
- Ok(()) => {}
- Err(..) => break,
- }
- }
- match chan.send(true) {
- Ok(()) => {}
- Err(..) => break
- }
- }
- });
- return port;
-}
-
-fn integers() -> Receiver<isize> {
- let (chan, port) = channel();
- thread::spawn(move|| {
- let mut i = 1;
- loop {
- match chan.send(i) {
- Ok(()) => {}
- Err(..) => break,
- }
- i = i + 1;
- }
- });
- return port;
-}
-
-fn main() {
- let ints = integers();
- let threes = periodical(3);
- let fives = periodical(5);
- for _ in 1..100 {
- match (ints.recv().unwrap(), threes.recv().unwrap(), fives.recv().unwrap()) {
- (_, true, true) => println!("FizzBuzz"),
- (_, true, false) => println!("Fizz"),
- (_, false, true) => println!("Buzz"),
- (i, false, false) => println!("{}", i)
- }
- }
-}
+++ /dev/null
-// run-pass
-#![allow(unused_must_use)]
-#![allow(deprecated)]
-// ignore-emscripten no threads support
-
-use std::sync::mpsc::{TryRecvError, channel};
-use std::thread;
-
-pub fn main() {
- let (tx, rx) = channel();
- let t = thread::spawn(move||{
- thread::sleep_ms(10);
- tx.send(()).unwrap();
- });
- loop {
- match rx.try_recv() {
- Ok(()) => break,
- Err(TryRecvError::Empty) => {}
- Err(TryRecvError::Disconnected) => unreachable!()
- }
- }
- t.join();
-}
+++ /dev/null
-// run-pass
-// shouldn't affect evaluation of $ex:
-macro_rules! bad_macro {
- ($ex:expr) => ({(|_x| { $ex }) (9) })
-}
-
-fn takes_x(_x : isize) {
- assert_eq!(bad_macro!(_x),8);
-}
-fn main() {
- takes_x(8);
-}
--- /dev/null
+// error-pattern: requires `copy` lang_item
+
+#![feature(lang_items, start, no_core)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized { }
+
+struct S;
+
+#[start]
+fn main(_: isize, _: *const *const u8) -> isize {
+ let _ = S;
+ 0
+}
--- /dev/null
+error: requires `copy` lang_item
+
+error: aborting due to previous error
+
--- /dev/null
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang="sized"]
+trait Sized {}
+
+#[lang="add"]
+trait Add<T> {}
+
+impl Add<i32> for i32 {}
+
+fn main() {
+ let x = 5 + 6;
+ //~^ ERROR cannot add `i32` to `{integer}`
+ let y = 5i32 + 6i32;
+ //~^ ERROR cannot add `i32` to `i32`
+}
--- /dev/null
+error[E0369]: cannot add `i32` to `{integer}`
+ --> $DIR/issue-31076.rs:13:15
+ |
+LL | let x = 5 + 6;
+ | - ^ - i32
+ | |
+ | {integer}
+
+error[E0369]: cannot add `i32` to `i32`
+ --> $DIR/issue-31076.rs:15:18
+ |
+LL | let y = 5i32 + 6i32;
+ | ---- ^ ---- i32
+ | |
+ | i32
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0369`.
--- /dev/null
+// build-fail
+
+#![feature(lang_items, no_core)]
+#![no_core]
+
+#[lang="copy"] pub trait Copy { }
+#[lang="sized"] pub trait Sized { }
+
+// error-pattern:requires `start` lang_item
+
+fn main() {}
--- /dev/null
+error: requires `start` lang_item
+
+error: aborting due to previous error
+
+++ /dev/null
-// aux-build:legacy-const-generics.rs
-
-extern crate legacy_const_generics;
-
-fn foo<const N: usize>() {
- let a = 1;
- legacy_const_generics::foo(0, a, 2);
- //~^ ERROR attempt to use a non-constant value in a constant
-
- legacy_const_generics::foo(0, N, 2);
-
- legacy_const_generics::foo(0, N + 1, 2);
- //~^ ERROR generic parameters may not be used in const operations
-}
-
-fn main() {}
+++ /dev/null
-error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/legacy-const-generics-bad.rs:7:35
- |
-LL | let a = 1;
- | ----- help: consider using `const` instead of `let`: `const a`
-LL | legacy_const_generics::foo(0, a, 2);
- | ^ non-constant value
-
-error: generic parameters may not be used in const operations
- --> $DIR/legacy-const-generics-bad.rs:12:35
- |
-LL | legacy_const_generics::foo(0, N + 1, 2);
- | ^ cannot perform const operation using `N`
- |
- = help: const parameters may only be used as standalone arguments, i.e. `N`
- = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0435`.
+++ /dev/null
-// aux-build:legacy-const-generics.rs
-// run-pass
-
-#![feature(rustc_attrs)]
-
-extern crate legacy_const_generics;
-
-#[rustc_legacy_const_generics(1)]
-pub fn bar<const Y: usize>(x: usize, z: usize) -> [usize; 3] {
- [x, Y, z]
-}
-
-fn main() {
- assert_eq!(legacy_const_generics::foo(0 + 0, 1 + 1, 2 + 2), [0, 2, 4]);
- assert_eq!(legacy_const_generics::foo::<{1 + 1}>(0 + 0, 2 + 2), [0, 2, 4]);
- // FIXME: Only works cross-crate
- //assert_eq!(bar(0, 1, 2), [0, 1, 2]);
-}
--- /dev/null
+fn parse_type(iter: Box<dyn Iterator<Item=&str>+'static>) -> &str { iter.next() }
+//~^ ERROR missing lifetime specifier [E0106]
+
+fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
+//~^ ERROR missing lifetime specifier [E0106]
+
+fn parse_type_3() -> &str { unimplemented!() }
+//~^ ERROR missing lifetime specifier [E0106]
+
+fn main() {}
--- /dev/null
+error[E0106]: missing lifetime specifier
+ --> $DIR/issue-26638.rs:1:62
+ |
+LL | fn parse_type(iter: Box<dyn Iterator<Item=&str>+'static>) -> &str { iter.next() }
+ | ------------------------------------ ^ expected named lifetime parameter
+ |
+ = help: this function's return type contains a borrowed value, but the signature does not say which one of `iter`'s 2 lifetimes it is borrowed from
+help: consider introducing a named lifetime parameter
+ |
+LL | fn parse_type<'a>(iter: Box<dyn Iterator<Item=&str>+'static>) -> &'a str { iter.next() }
+ | ++++ ++
+
+error[E0106]: missing lifetime specifier
+ --> $DIR/issue-26638.rs:4:40
+ |
+LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
+ | ^ expected named lifetime parameter
+ |
+ = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+help: consider using the `'static` lifetime
+ |
+LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &'static str { iter() }
+ | ~~~~~~~~
+
+error[E0106]: missing lifetime specifier
+ --> $DIR/issue-26638.rs:7:22
+ |
+LL | fn parse_type_3() -> &str { unimplemented!() }
+ | ^ expected named lifetime parameter
+ |
+ = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
+help: consider using the `'static` lifetime
+ |
+LL | fn parse_type_3() -> &'static str { unimplemented!() }
+ | ~~~~~~~~
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0106`.
#![allow(uncommon_codepoints)]
//~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
+//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
#[allow(uncommon_codepoints)]
//~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
+//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
const BAR: f64 = 0.000001;
}
#[allow(uncommon_codepoints)]
//~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
+//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
fn main() {
}
| ^^^^^^^^^^^^^^^^^
error: allow(uncommon_codepoints) is ignored unless specified at crate level
- --> $DIR/crate_level_only_lint.rs:8:9
+ --> $DIR/crate_level_only_lint.rs:9:9
|
LL | #[allow(uncommon_codepoints)]
| ^^^^^^^^^^^^^^^^^^^
error: allow(uncommon_codepoints) is ignored unless specified at crate level
- --> $DIR/crate_level_only_lint.rs:15:9
+ --> $DIR/crate_level_only_lint.rs:17:9
|
LL | #[allow(uncommon_codepoints)]
| ^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^
error: allow(uncommon_codepoints) is ignored unless specified at crate level
- --> $DIR/crate_level_only_lint.rs:8:9
+ --> $DIR/crate_level_only_lint.rs:9:9
|
LL | #[allow(uncommon_codepoints)]
| ^^^^^^^^^^^^^^^^^^^
error: allow(uncommon_codepoints) is ignored unless specified at crate level
- --> $DIR/crate_level_only_lint.rs:15:9
+ --> $DIR/crate_level_only_lint.rs:17:9
|
LL | #[allow(uncommon_codepoints)]
| ^^^^^^^^^^^^^^^^^^^
-error: aborting due to 6 previous errors
+error: allow(uncommon_codepoints) is ignored unless specified at crate level
+ --> $DIR/crate_level_only_lint.rs:4:10
+ |
+LL | #![allow(uncommon_codepoints)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: allow(uncommon_codepoints) is ignored unless specified at crate level
+ --> $DIR/crate_level_only_lint.rs:9:9
+ |
+LL | #[allow(uncommon_codepoints)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: allow(uncommon_codepoints) is ignored unless specified at crate level
+ --> $DIR/crate_level_only_lint.rs:17:9
+ |
+LL | #[allow(uncommon_codepoints)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 9 previous errors
//~| WARNING previously accepted by the compiler
//~| ERROR incompatible with previous
//~| WARNING previously accepted by the compiler
+//~| ERROR incompatible with previous
+//~| WARNING previously accepted by the compiler
+//~| ERROR incompatible with previous
+//~| WARNING previously accepted by the compiler
+//~| ERROR incompatible with previous
+//~| WARNING previously accepted by the compiler
fn main() {}
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
-error: aborting due to 6 previous errors
+error: allow(nonstandard_style) incompatible with previous forbid
+ --> $DIR/forbid-group-group-2.rs:7:9
+ |
+LL | #![forbid(warnings)]
+ | -------- `forbid` level set here
+...
+LL | #[allow(nonstandard_style)]
+ | ^^^^^^^^^^^^^^^^^ overruled by previous forbid
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
+
+error: allow(nonstandard_style) incompatible with previous forbid
+ --> $DIR/forbid-group-group-2.rs:7:9
+ |
+LL | #![forbid(warnings)]
+ | -------- `forbid` level set here
+...
+LL | #[allow(nonstandard_style)]
+ | ^^^^^^^^^^^^^^^^^ overruled by previous forbid
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
+
+error: allow(nonstandard_style) incompatible with previous forbid
+ --> $DIR/forbid-group-group-2.rs:7:9
+ |
+LL | #![forbid(warnings)]
+ | -------- `forbid` level set here
+...
+LL | #[allow(nonstandard_style)]
+ | ^^^^^^^^^^^^^^^^^ overruled by previous forbid
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
+
+error: aborting due to 9 previous errors
--- /dev/null
+// check-pass
+// pretty-expanded FIXME #23616
+
+#[deny(dead_code)]
+pub enum Foo {
+ Bar {
+ baz: isize
+ }
+}
+
+fn main() { }
--- /dev/null
+// check-pass
+
+// Originally from #53925.
+// Tests that the `unreachable_pub` lint doesn't fire for `pub self::bar::Bar`.
+
+#![deny(unreachable_pub)]
+
+mod foo {
+ mod bar {
+ pub struct Bar;
+ }
+
+ pub use self::bar::Bar;
+}
+
+pub use foo::Bar;
+
+fn main() {}
--- /dev/null
+fn part(_: u16) -> u32 {
+ 1
+}
+
+fn main() {
+ for n in 100_000.. {
+ //~^ ERROR: literal out of range for `u16`
+ let _ = part(n);
+ }
+}
--- /dev/null
+error: literal out of range for `u16`
+ --> $DIR/issue-63364.rs:6:14
+ |
+LL | for n in 100_000.. {
+ | ^^^^^^^
+ |
+ = note: `#[deny(overflowing_literals)]` on by default
+ = note: the literal `100_000` does not fit into the type `u16` whose range is `0..=65535`
+
+error: aborting due to previous error
+
fn main() {
println!("{}", evil!(*(0 as *const u8)));
+ //~^ WARNING dereferencing a null pointer
}
LL | #![forbid(unsafe_code)]
| ^^^^^^^^^^^
-error: aborting due to previous error
+warning: dereferencing a null pointer
+ --> $DIR/lint-forbid-internal-unsafe.rs:15:26
+ |
+LL | println!("{}", evil!(*(0 as *const u8)));
+ | ^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
+ |
+ = note: `#[warn(deref_nullptr)]` on by default
+
+error: aborting due to previous error; 1 warning emitted
#![deny(uncommon_codepoints)]
const µ: f64 = 0.000001; //~ ERROR identifier contains uncommon Unicode codepoints
+//~| WARNING should have an upper case name
fn dijkstra() {} //~ ERROR identifier contains uncommon Unicode codepoints
| ^^^^^^^^^^^^^^^^^^^
error: identifier contains uncommon Unicode codepoints
- --> $DIR/lint-uncommon-codepoints.rs:5:4
+ --> $DIR/lint-uncommon-codepoints.rs:6:4
|
LL | fn dijkstra() {}
| ^^^^^^^
error: identifier contains uncommon Unicode codepoints
- --> $DIR/lint-uncommon-codepoints.rs:8:9
+ --> $DIR/lint-uncommon-codepoints.rs:9:9
|
LL | let ㇻㇲㇳ = "rust";
| ^^^^^^
-error: aborting due to 3 previous errors
+warning: constant `µ` should have an upper case name
+ --> $DIR/lint-uncommon-codepoints.rs:3:7
+ |
+LL | const µ: f64 = 0.000001;
+ | ^ help: convert the identifier to upper case: `Μ`
+ |
+ = note: `#[warn(non_upper_case_globals)]` on by default
+
+error: aborting due to 3 previous errors; 1 warning emitted
--- /dev/null
+// edition:2018
+
+#![deny(unused_extern_crates)]
+#![feature(test, rustc_private, crate_visibility_modifier)]
+
+extern crate libc;
+//~^ ERROR unused extern crate
+//~| HELP remove
+extern crate libc as x;
+//~^ ERROR unused extern crate
+//~| HELP remove
+
+extern crate proc_macro;
+
+#[macro_use]
+extern crate test;
+
+pub extern crate test as y;
+
+pub extern crate alloc;
+
+pub(crate) extern crate alloc as a;
+
+crate extern crate alloc as b;
+
+mod foo {
+ pub(in crate::foo) extern crate alloc as c;
+
+ pub(super) extern crate alloc as d;
+
+ extern crate libc;
+ //~^ ERROR unused extern crate
+ //~| HELP remove
+
+ extern crate libc as x;
+ //~^ ERROR unused extern crate
+ //~| HELP remove
+
+ pub extern crate test;
+
+ pub extern crate test as y;
+
+ mod bar {
+ extern crate libc;
+ //~^ ERROR unused extern crate
+ //~| HELP remove
+
+ extern crate libc as x;
+ //~^ ERROR unused extern crate
+ //~| HELP remove
+
+ pub(in crate::foo::bar) extern crate alloc as e;
+
+ fn dummy() {
+ e::string::String::new();
+ }
+ }
+
+ fn dummy() {
+ c::string::String::new();
+ d::string::String::new();
+ }
+}
+
+
+fn main() {
+ a::string::String::new();
+ b::string::String::new();
+
+ proc_macro::TokenStream::new();
+}
--- /dev/null
+error: unused extern crate
+ --> $DIR/unnecessary-extern-crate.rs:6:1
+ |
+LL | extern crate libc;
+ | ^^^^^^^^^^^^^^^^^^ help: remove it
+ |
+note: the lint level is defined here
+ --> $DIR/unnecessary-extern-crate.rs:3:9
+ |
+LL | #![deny(unused_extern_crates)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: unused extern crate
+ --> $DIR/unnecessary-extern-crate.rs:9:1
+ |
+LL | extern crate libc as x;
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove it
+
+error: unused extern crate
+ --> $DIR/unnecessary-extern-crate.rs:31:5
+ |
+LL | extern crate libc;
+ | ^^^^^^^^^^^^^^^^^^ help: remove it
+
+error: unused extern crate
+ --> $DIR/unnecessary-extern-crate.rs:35:5
+ |
+LL | extern crate libc as x;
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove it
+
+error: unused extern crate
+ --> $DIR/unnecessary-extern-crate.rs:44:9
+ |
+LL | extern crate libc;
+ | ^^^^^^^^^^^^^^^^^^ help: remove it
+
+error: unused extern crate
+ --> $DIR/unnecessary-extern-crate.rs:48:9
+ |
+LL | extern crate libc as x;
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove it
+
+error: aborting due to 6 previous errors
+
-warning: unused macro definition
- --> $DIR/issue-70041.rs:4:1
+warning: unused macro definition: `regex`
+ --> $DIR/issue-70041.rs:4:14
|
-LL | / macro_rules! regex {
-LL | |
-LL | | () => {};
-LL | | }
- | |_^
+LL | macro_rules! regex {
+ | ^^^^^
|
= note: `#[warn(unused_macros)]` on by default
-error: unused macro definition
- --> $DIR/unused-macro-rules.rs:4:1
+error: unused macro definition: `unused`
+ --> $DIR/unused-macro-rules.rs:4:14
|
-LL | / macro_rules! unused {
-LL | | () => {};
-LL | | }
- | |_^
+LL | macro_rules! unused {
+ | ^^^^^^
|
note: the lint level is defined here
--> $DIR/unused-macro-rules.rs:1:9
LL | #![deny(unused_macros)]
| ^^^^^^^^^^^^^
-error: unused macro definition
- --> $DIR/unused-macro-rules.rs:11:9
+error: unused macro definition: `m`
+ --> $DIR/unused-macro-rules.rs:11:22
|
-LL | / macro_rules! m {
-LL | | () => {};
-LL | | }
- | |_________^
-...
-LL | create_macro!();
- | --------------- in this macro invocation
- |
- = note: this error originates in the macro `create_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
+LL | macro_rules! m {
+ | ^
-error: unused macro definition
- --> $DIR/unused-macro-rules.rs:24:5
+error: unused macro definition: `unused`
+ --> $DIR/unused-macro-rules.rs:24:18
|
-LL | / macro_rules! unused {
-LL | | () => {};
-LL | | }
- | |_____^
+LL | macro_rules! unused {
+ | ^^^^^^
|
note: the lint level is defined here
--> $DIR/unused-macro-rules.rs:23:12
-error: unused macro definition
- --> $DIR/unused-macro.rs:5:1
+error: unused macro definition: `unused`
+ --> $DIR/unused-macro.rs:5:7
|
-LL | / macro unused {
-LL | | () => {}
-LL | | }
- | |_^
+LL | macro unused {
+ | ^^^^^^
|
note: the lint level is defined here
--> $DIR/unused-macro.rs:2:9
LL | #![deny(unused_macros)]
| ^^^^^^^^^^^^^
-error: unused macro definition
- --> $DIR/unused-macro.rs:15:5
+error: unused macro definition: `unused`
+ --> $DIR/unused-macro.rs:15:11
|
-LL | / macro unused {
-LL | | () => {}
-LL | | }
- | |_____^
+LL | macro unused {
+ | ^^^^^^
|
note: the lint level is defined here
--> $DIR/unused-macro.rs:14:12
LL | #[deny(unused_macros)]
| ^^^^^^^^^^^^^
-error: unused macro definition
- --> $DIR/unused-macro.rs:21:5
+error: unused macro definition: `unused`
+ --> $DIR/unused-macro.rs:21:22
|
-LL | / pub(crate) macro unused {
-LL | | () => {}
-LL | | }
- | |_____^
+LL | pub(crate) macro unused {
+ | ^^^^^^
error: aborting due to 3 previous errors
--- /dev/null
+// run-pass
+
+#![allow(dead_code)]
+// compile-flags:-D improper-ctypes
+
+// pretty-expanded FIXME #23616
+#![allow(improper_ctypes)]
+
+mod libc {
+ extern "C" {
+ pub fn malloc(size: isize) -> *const u8;
+ }
+}
+
+pub fn main() {}
--- /dev/null
+#![feature(llvm_asm)]
+#![allow(deprecated)] // llvm_asm!
+// compile-flags: -Ccodegen-units=1
+// build-fail
+// only-x86_64
+
+fn main() {
+ unsafe {
+ llvm_asm!("int $3"); //~ ERROR too few operands for instruction
+ //~| ERROR invalid operand in inline asm
+ }
+}
--- /dev/null
+error: invalid operand in inline asm: 'int $3'
+ --> $DIR/issue-23458.rs:9:9
+ |
+LL | llvm_asm!("int $3");
+ | ^
+
+error: too few operands for instruction
+ --> $DIR/issue-23458.rs:9:9
+ |
+LL | llvm_asm!("int $3");
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:1:2
+ |
+LL | int
+ | ^
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+// check-pass
+// ignore-emscripten
+
+#![feature(llvm_asm)]
+#![allow(deprecated)] // llvm_asm!
+
+macro_rules! interrupt_handler {
+ () => {
+ unsafe fn _interrupt_handler() {
+ llvm_asm!("pop eax" :::: "intel");
+ }
+ }
+}
+interrupt_handler!{}
+
+fn main() {}
--- /dev/null
+// Regression test for Issue #53787: Fix ICE when creating a label in inline assembler with macros.
+
+// build-fail
+// ignore-emscripten
+
+#![feature(llvm_asm)]
+#![allow(deprecated)] // llvm_asm!
+
+macro_rules! fake_jump {
+ ($id:expr) => {
+ unsafe {
+ llvm_asm!(
+ "
+ jmp $0
+ lea eax, [ebx]
+ xor eax, 0xDEADBEEF
+ retn
+ $0:
+ "::"0"($id)::"volatile", "intel");
+ }
+ };
+}
+
+fn main() {
+ fake_jump!("FirstFunc"); //~ ERROR invalid value for constraint in inline assembly
+ println!("Hello, world!");
+}
--- /dev/null
+error[E0669]: invalid value for constraint in inline assembly
+ --> $DIR/issue-53787-inline-assembler-macro.rs:25:16
+ |
+LL | fake_jump!("FirstFunc");
+ | ^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0669`.
+++ /dev/null
-// run-pass
-// pretty-expanded FIXME #23616
-
-#![allow(unused_variables)]
-
-pub fn main() {
- let mut i: isize = 0;
- while i < 1000000 {
- i += 1;
- let x = 3;
- }
-}
+++ /dev/null
-// compile-flags: -C lto -C embed-bitcode=no
-
-fn main() {}
+++ /dev/null
-error: options `-C embed-bitcode=no` and `-C lto` are incompatible
-
+++ /dev/null
-// build-fail
-// aux-build:lto-duplicate-symbols1.rs
-// aux-build:lto-duplicate-symbols2.rs
-// error-pattern:Linking globals named 'foo': symbol multiply defined!
-// compile-flags: -C lto
-// no-prefer-dynamic
-
-extern crate lto_duplicate_symbols1;
-extern crate lto_duplicate_symbols2;
-
-fn main() {}
+++ /dev/null
-warning: Linking globals named 'foo': symbol multiply defined!
-
-error: failed to load bc of "lto-duplicate-symbols2.lto_duplicate_symbols2.693a75b4-cgu.0.rcgu.o":
-
-error: aborting due to previous error; 1 warning emitted
-
+++ /dev/null
-// run-pass
-// compile-flags: -C lto -C codegen-units=8
-// no-prefer-dynamic
-
-fn main() {
-}
+++ /dev/null
-// compile-flags: -Clinker-plugin-lto -Copt-level=s
-// build-pass
-// no-prefer-dynamic
-
-#![crate_type = "rlib"]
-
-pub fn foo() {}
+++ /dev/null
-// compile-flags: -Clinker-plugin-lto -Copt-level=z
-// build-pass
-// no-prefer-dynamic
-
-#![crate_type = "rlib"]
-
-pub fn foo() {}
+++ /dev/null
-// compile-flags: -C lto
-// aux-build:lto-rustc-loads-linker-plugin.rs
-// run-pass
-// no-prefer-dynamic
-
-// This test ensures that if a dependency was compiled with
-// `-Clinker-plugin-lto` then we can compile with `-Clto` and still link against
-// that upstream rlib. This should work because LTO implies we're not actually
-// linking against upstream rlibs since we're generating the object code
-// locally. This test will fail if rustc can't find bytecode in rlibs compiled
-// with `-Clinker-plugin-lto`.
-
-extern crate lto_rustc_loads_linker_plugin;
-
-fn main() {
- lto_rustc_loads_linker_plugin::foo();
-}
+++ /dev/null
-// run-pass
-// compile-flags: -C lto
-// no-prefer-dynamic
-// ignore-emscripten no threads support
-// revisions: mir thir
-// [thir]compile-flags: -Zthir-unsafeck
-
-use std::thread;
-
-static mut HIT: usize = 0;
-
-thread_local!(static A: Foo = Foo);
-
-struct Foo;
-
-impl Drop for Foo {
- fn drop(&mut self) {
- unsafe {
- HIT += 1;
- }
- }
-}
-
-fn main() {
- unsafe {
- assert_eq!(HIT, 0);
- thread::spawn(|| {
- assert_eq!(HIT, 0);
- A.with(|_| ());
- assert_eq!(HIT, 0);
- }).join().unwrap();
- assert_eq!(HIT, 1);
- }
-}
+++ /dev/null
-// compile-flags: -C lto=thin
-// aux-build:lto-rustc-loads-linker-plugin.rs
-// run-pass
-// no-prefer-dynamic
-
-// Same as the adjacent `lto-thin-rustc-loads-linker-plugin.rs` test, only with
-// ThinLTO.
-
-extern crate lto_rustc_loads_linker_plugin;
-
-fn main() {
- lto_rustc_loads_linker_plugin::foo();
-}
--- /dev/null
+// run-pass
+
+// compile-flags: -Clto=thin
+// no-prefer-dynamic
+
+fn main() {
+ println!("hello!");
+}
--- /dev/null
+// compile-flags: -Z thinlto -C codegen-units=8
+
+#[inline]
+pub fn foo(b: u8) {
+ b.to_string();
+}
--- /dev/null
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+
+#[no_mangle]
+pub extern "C" fn foo() {}
--- /dev/null
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+
+#[no_mangle]
+pub extern "C" fn foo() {}
--- /dev/null
+// compile-flags: -Clinker-plugin-lto
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+
+pub fn foo() {}
--- /dev/null
+// no-prefer-dynamic
+// compile-flags: -Z thinlto -C codegen-units=8 -C prefer-dynamic
+
+#![crate_type = "rlib"]
+#![crate_type = "dylib"]
+
+pub static A: u32 = 43;
+
+pub mod a {
+ pub static A: u32 = 43;
+}
--- /dev/null
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+
+pub fn bar() -> u32 {
+ 3
+}
--- /dev/null
+// run-pass
+
+// aux-build:dylib.rs
+
+extern crate dylib;
+
+fn main() {
+ dylib::foo(1);
+}
--- /dev/null
+// compile-flags: -C lto -C embed-bitcode=no
+
+fn main() {}
--- /dev/null
+error: options `-C embed-bitcode=no` and `-C lto` are incompatible
+
--- /dev/null
+// build-fail
+// aux-build:lto-duplicate-symbols1.rs
+// aux-build:lto-duplicate-symbols2.rs
+// error-pattern:Linking globals named 'foo': symbol multiply defined!
+// compile-flags: -C lto
+// no-prefer-dynamic
+
+extern crate lto_duplicate_symbols1;
+extern crate lto_duplicate_symbols2;
+
+fn main() {}
--- /dev/null
+warning: Linking globals named 'foo': symbol multiply defined!
+
+error: failed to load bc of "lto-duplicate-symbols2.lto_duplicate_symbols2.693a75b4-cgu.0.rcgu.o":
+
+error: aborting due to previous error; 1 warning emitted
+
--- /dev/null
+// run-pass
+// compile-flags: -C lto -C codegen-units=8
+// no-prefer-dynamic
+
+fn main() {
+}
--- /dev/null
+// compile-flags: -Clinker-plugin-lto -Copt-level=s
+// build-pass
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+
+pub fn foo() {}
--- /dev/null
+// compile-flags: -Clinker-plugin-lto -Copt-level=z
+// build-pass
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+
+pub fn foo() {}
--- /dev/null
+// compile-flags: -C lto
+// aux-build:lto-rustc-loads-linker-plugin.rs
+// run-pass
+// no-prefer-dynamic
+
+// This test ensures that if a dependency was compiled with
+// `-Clinker-plugin-lto` then we can compile with `-Clto` and still link against
+// that upstream rlib. This should work because LTO implies we're not actually
+// linking against upstream rlibs since we're generating the object code
+// locally. This test will fail if rustc can't find bytecode in rlibs compiled
+// with `-Clinker-plugin-lto`.
+
+extern crate lto_rustc_loads_linker_plugin;
+
+fn main() {
+ lto_rustc_loads_linker_plugin::foo();
+}
--- /dev/null
+// run-pass
+// compile-flags: -C lto
+// no-prefer-dynamic
+// ignore-emscripten no threads support
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
+
+use std::thread;
+
+static mut HIT: usize = 0;
+
+thread_local!(static A: Foo = Foo);
+
+struct Foo;
+
+impl Drop for Foo {
+ fn drop(&mut self) {
+ unsafe {
+ HIT += 1;
+ }
+ }
+}
+
+fn main() {
+ unsafe {
+ assert_eq!(HIT, 0);
+ thread::spawn(|| {
+ assert_eq!(HIT, 0);
+ A.with(|_| ());
+ assert_eq!(HIT, 0);
+ }).join().unwrap();
+ assert_eq!(HIT, 1);
+ }
+}
--- /dev/null
+// compile-flags: -C lto=thin
+// aux-build:lto-rustc-loads-linker-plugin.rs
+// run-pass
+// no-prefer-dynamic
+
+// Same as the adjacent `lto-thin-rustc-loads-linker-plugin.rs` test, only with
+// ThinLTO.
+
+extern crate lto_rustc_loads_linker_plugin;
+
+fn main() {
+ lto_rustc_loads_linker_plugin::foo();
+}
--- /dev/null
+// run-pass
+
+// aux-build:msvc-imp-present.rs
+// compile-flags: -Z thinlto -C codegen-units=8
+// no-prefer-dynamic
+
+// On MSVC we have a "hack" where we emit symbols that look like `_imp_$name`
+// for all exported statics. This is done because we apply `dllimport` to all
+// imported constants and this allows everything to actually link correctly.
+//
+// The ThinLTO passes aggressively remove symbols if they can, and this test
+// asserts that the ThinLTO passes don't remove these compiler-generated
+// `_imp_*` symbols. The external library that we link in here is compiled with
+// ThinLTO and multiple codegen units and has a few exported constants. Note
+// that we also namely compile the library as both a dylib and an rlib, but we
+// link the rlib to ensure that we assert those generated symbols exist.
+
+extern crate msvc_imp_present as bar;
+
+fn main() {
+ println!("{}", bar::A);
+}
--- /dev/null
+// run-pass
+// compile-flags: -Z thinlto -C codegen-units=2
+
+#[global_allocator]
+static A: std::alloc::System = std::alloc::System;
+
+fn main() {}
--- /dev/null
+// run-pass
+
+// compile-flags: -Z thinlto -C codegen-units=8 -O
+// ignore-emscripten can't inspect instructions on emscripten
+
+// We want to assert here that ThinLTO will inline across codegen units. There's
+// not really a great way to do that in general so we sort of hack around it by
+// praying two functions go into separate codegen units and then assuming that
+// if inlining *doesn't* happen the first byte of the functions will differ.
+
+pub fn foo() -> u32 {
+ bar::bar()
+}
+
+mod bar {
+ pub fn bar() -> u32 {
+ 3
+ }
+}
+
+fn main() {
+ println!("{} {}", foo(), bar::bar());
+
+ unsafe {
+ let foo = foo as usize as *const u8;
+ let bar = bar::bar as usize as *const u8;
+
+ assert_eq!(*foo, *bar);
+ }
+}
--- /dev/null
+// run-pass
+
+// compile-flags: -C codegen-units=8 -O -C lto=thin
+// aux-build:thin-lto-inlines-aux.rs
+// no-prefer-dynamic
+// ignore-emscripten can't inspect instructions on emscripten
+
+// We want to assert here that ThinLTO will inline across codegen units. There's
+// not really a great way to do that in general so we sort of hack around it by
+// praying two functions go into separate codegen units and then assuming that
+// if inlining *doesn't* happen the first byte of the functions will differ.
+
+extern crate thin_lto_inlines_aux as bar;
+
+pub fn foo() -> u32 {
+ bar::bar()
+}
+
+fn main() {
+ println!("{} {}", foo(), bar::bar());
+
+ unsafe {
+ let foo = foo as usize as *const u8;
+ let bar = bar::bar as usize as *const u8;
+
+ assert_eq!(*foo, *bar);
+ }
+}
--- /dev/null
+// run-pass
+
+// compile-flags: -C codegen-units=8 -Z thinlto
+// ignore-windows
+
+#![feature(linkage)]
+
+pub mod foo {
+ #[linkage = "weak"]
+ #[no_mangle]
+ pub extern "C" fn FOO() -> i32 {
+ 0
+ }
+}
+
+mod bar {
+ extern "C" {
+ fn FOO() -> i32;
+ }
+
+ pub fn bar() -> i32 {
+ unsafe { FOO() }
+ }
+}
+
+fn main() {
+ bar::bar();
+}
+++ /dev/null
-// run-pass
-// Test for a specific corner case: when we compute the LUB of two fn
-// types and their parameters have unbound variables. In that case, we
-// wind up relating those two variables. This was causing an ICE in an
-// in-progress PR.
-
-fn main() {
- let a_f: fn(_) = |_| ();
- let b_f: fn(_) = |_| ();
- let c_f = match 22 {
- 0 => a_f,
- _ => b_f,
- };
- c_f(4);
-}
--- /dev/null
+#![crate_type = "lib"]
+
+#[macro_export]
+macro_rules! mywrite {
+ ($dst:expr, $($arg:tt)*) => ($dst.write_fmt(format_args!($($arg)*)))
+}
--- /dev/null
+macro_rules! prob1 {
+ (0) => {
+ 0
+ };
+ ($n:expr) => {
+ if ($n % 3 == 0) || ($n % 5 == 0) {
+ $n + prob1!($n - 1); //~ ERROR recursion limit reached while expanding `prob1!`
+ } else {
+ prob1!($n - 1);
+ }
+ };
+}
+
+fn main() {
+ println!("Problem 1: {}", prob1!(1000));
+}
--- /dev/null
+error: recursion limit reached while expanding `prob1!`
+ --> $DIR/issue-16098.rs:7:18
+ |
+LL | $n + prob1!($n - 1);
+ | ^^^^^^^^^^^^^^
+...
+LL | println!("Problem 1: {}", prob1!(1000));
+ | ------------ in this macro invocation
+ |
+ = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_16098`)
+ = note: this error originates in the macro `prob1` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
--- /dev/null
+// aux-build:issue-19163.rs
+
+#[macro_use] extern crate issue_19163;
+
+use std::io::Write;
+
+fn main() {
+ let mut v = vec![];
+ mywrite!(&v, "Hello world");
+ //~^ ERROR cannot borrow data in a `&` reference as mutable
+}
--- /dev/null
+error[E0596]: cannot borrow data in a `&` reference as mutable
+ --> $DIR/issue-19163.rs:9:5
+ |
+LL | mywrite!(&v, "Hello world");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
+ |
+ = note: this error originates in the macro `mywrite` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
--- /dev/null
+#![allow(unused_macros)]
+
+macro_rules! test { ($wrong:t_ty ..) => () }
+ //~^ ERROR: invalid fragment specifier `t_ty`
+
+fn main() {}
--- /dev/null
+error: invalid fragment specifier `t_ty`
+ --> $DIR/issue-21356.rs:3:22
+ |
+LL | macro_rules! test { ($wrong:t_ty ..) => () }
+ | ^^^^^^^^^^^
+ |
+ = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
+
+error: aborting due to previous error
+
--- /dev/null
+// run-pass
+macro_rules! items {
+ () => {
+ type A = ();
+ fn a() {}
+ }
+}
+
+trait Foo {
+ type A;
+ fn a();
+}
+
+impl Foo for () {
+ items!();
+}
+
+fn main() {
+
+}
--- /dev/null
+macro_rules! foo {
+ ($d:expr) => {{
+ fn bar(d: u8) { }
+ bar(&mut $d);
+ //~^ ERROR mismatched types
+ //~| expected `u8`, found `&mut u8`
+ }}
+}
+
+fn main() {
+ foo!(0u8);
+ //~^ in this expansion of foo!
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-29084.rs:4:13
+ |
+LL | bar(&mut $d);
+ | ^^^^^^^ expected `u8`, found `&mut u8`
+...
+LL | foo!(0u8);
+ | --------- in this macro invocation
+ |
+ = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// check-pass
+
+macro_rules! null { ($i:tt) => {} }
+macro_rules! apply_null {
+ ($i:item) => { null! { $i } }
+}
+
+fn main() {
+ apply_null!(#[cfg(all())] fn f() {});
+}
--- /dev/null
+// run-pass
+macro_rules! m { (<$t:ty>) => { stringify!($t) } }
+fn main() {
+ println!("{}", m!(<Vec<i32>>));
+}
--- /dev/null
+#![allow(unused_macros)]
+
+macro_rules! assign {
+ (($($a:tt)*) = ($($b:tt))*) => { //~ ERROR expected one of: `*`, `+`, or `?`
+ $($a)* = $($b)*
+ }
+}
+
+fn main() {}
--- /dev/null
+error: expected one of: `*`, `+`, or `?`
+ --> $DIR/issue-39388.rs:4:22
+ |
+LL | (($($a:tt)*) = ($($b:tt))*) => {
+ | ^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// run-pass
+#![allow(unused_macros)]
+macro_rules! m {
+ ($e:expr) => {
+ macro_rules! n { () => { $e } }
+ }
+}
+
+fn main() {
+ m!(foo!());
+}
--- /dev/null
+// Regression test for #57597.
+//
+// Make sure that nested matchers work correctly rather than causing an infinite loop or crash.
+
+// edition:2018
+
+macro_rules! foo1 {
+ ($($($i:ident)?)+) => {};
+ //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo2 {
+ ($($($i:ident)?)*) => {};
+ //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo3 {
+ ($($($i:ident)?)?) => {};
+ //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo4 {
+ ($($($($i:ident)?)?)?) => {};
+ //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo5 {
+ ($($($($i:ident)*)?)?) => {};
+ //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo6 {
+ ($($($($i:ident)?)*)?) => {};
+ //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo7 {
+ ($($($($i:ident)?)?)*) => {};
+ //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo8 {
+ ($($($($i:ident)*)*)?) => {};
+ //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo9 {
+ ($($($($i:ident)?)*)*) => {};
+ //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo10 {
+ ($($($($i:ident)?)*)+) => {};
+ //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo11 {
+ ($($($($i:ident)+)?)*) => {};
+ //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo12 {
+ ($($($($i:ident)+)*)?) => {};
+ //~^ ERROR repetition matches empty token tree
+}
+
+fn main() {
+ foo1!();
+ foo2!();
+ foo3!();
+ foo4!();
+ foo5!();
+ foo6!();
+ foo7!();
+ foo8!();
+ foo9!();
+ foo10!();
+ foo11!();
+ foo12!();
+}
--- /dev/null
+error: repetition matches empty token tree
+ --> $DIR/issue-57597.rs:8:7
+ |
+LL | ($($($i:ident)?)+) => {};
+ | ^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+ --> $DIR/issue-57597.rs:13:7
+ |
+LL | ($($($i:ident)?)*) => {};
+ | ^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+ --> $DIR/issue-57597.rs:18:7
+ |
+LL | ($($($i:ident)?)?) => {};
+ | ^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+ --> $DIR/issue-57597.rs:23:7
+ |
+LL | ($($($($i:ident)?)?)?) => {};
+ | ^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+ --> $DIR/issue-57597.rs:28:7
+ |
+LL | ($($($($i:ident)*)?)?) => {};
+ | ^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+ --> $DIR/issue-57597.rs:33:7
+ |
+LL | ($($($($i:ident)?)*)?) => {};
+ | ^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+ --> $DIR/issue-57597.rs:38:7
+ |
+LL | ($($($($i:ident)?)?)*) => {};
+ | ^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+ --> $DIR/issue-57597.rs:43:7
+ |
+LL | ($($($($i:ident)*)*)?) => {};
+ | ^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+ --> $DIR/issue-57597.rs:48:7
+ |
+LL | ($($($($i:ident)?)*)*) => {};
+ | ^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+ --> $DIR/issue-57597.rs:53:7
+ |
+LL | ($($($($i:ident)?)*)+) => {};
+ | ^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+ --> $DIR/issue-57597.rs:58:7
+ |
+LL | ($($($($i:ident)+)?)*) => {};
+ | ^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+ --> $DIR/issue-57597.rs:63:7
+ |
+LL | ($($($($i:ident)+)*)?) => {};
+ | ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 12 previous errors
+
--- /dev/null
+macro_rules! e {
+ ($inp:ident) => (
+ $nonexistent
+ //~^ ERROR expected expression, found `$`
+ );
+}
+
+fn main() {
+ e!(foo);
+}
--- /dev/null
+error: expected expression, found `$`
+ --> $DIR/issue-6596-1.rs:3:9
+ |
+LL | $nonexistent
+ | ^^^^^^^^^^^^ expected expression
+...
+LL | e!(foo);
+ | ------- in this macro invocation
+ |
+ = note: this error originates in the macro `e` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
--- /dev/null
+use std::fmt::Write;
+
+fn main() {
+ println!(b"foo");
+ //~^ ERROR format argument must be a string literal
+ //~| HELP consider removing the leading `b`
+ let mut s = String::new();
+ write!(s, b"foo{}", "bar");
+ //~^ ERROR format argument must be a string literal
+ //~| HELP consider removing the leading `b`
+}
--- /dev/null
+error: format argument must be a string literal
+ --> $DIR/issue-86865.rs:4:14
+ |
+LL | println!(b"foo");
+ | -^^^^^
+ | |
+ | help: consider removing the leading `b`
+
+error: format argument must be a string literal
+ --> $DIR/issue-86865.rs:8:15
+ |
+LL | write!(s, b"foo{}", "bar");
+ | -^^^^^^^
+ | |
+ | help: consider removing the leading `b`
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+#![feature(trace_macros)]
+
+fn main() {
+ trace_macros!(); //~ ERROR trace_macros! accepts only `true` or `false`
+ trace_macros!(1); //~ ERROR trace_macros! accepts only `true` or `false`
+ trace_macros!(ident); //~ ERROR trace_macros! accepts only `true` or `false`
+ trace_macros!(for); //~ ERROR trace_macros! accepts only `true` or `false`
+ trace_macros!(true,); //~ ERROR trace_macros! accepts only `true` or `false`
+ trace_macros!(false 1); //~ ERROR trace_macros! accepts only `true` or `false`
+
+
+ // should be fine:
+ macro_rules! expando {
+ ($x: ident) => { trace_macros!($x) }
+ }
+
+ expando!(true);
+}
--- /dev/null
+error: trace_macros! accepts only `true` or `false`
+ --> $DIR/trace_macros-format.rs:4:5
+ |
+LL | trace_macros!();
+ | ^^^^^^^^^^^^^^^
+
+error: trace_macros! accepts only `true` or `false`
+ --> $DIR/trace_macros-format.rs:5:5
+ |
+LL | trace_macros!(1);
+ | ^^^^^^^^^^^^^^^^
+
+error: trace_macros! accepts only `true` or `false`
+ --> $DIR/trace_macros-format.rs:6:5
+ |
+LL | trace_macros!(ident);
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: trace_macros! accepts only `true` or `false`
+ --> $DIR/trace_macros-format.rs:7:5
+ |
+LL | trace_macros!(for);
+ | ^^^^^^^^^^^^^^^^^^
+
+error: trace_macros! accepts only `true` or `false`
+ --> $DIR/trace_macros-format.rs:8:5
+ |
+LL | trace_macros!(true,);
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: trace_macros! accepts only `true` or `false`
+ --> $DIR/trace_macros-format.rs:9:5
+ |
+LL | trace_macros!(false 1);
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
+
--- /dev/null
+// run-pass
+
+#![feature(marker_trait_attr)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
+
+#[marker]
+trait MyMarker {}
+
+impl<T> MyMarker for T {}
+impl<T> MyMarker for Vec<T> {}
+
+fn foo<T: MyMarker>(t: T) -> T {
+ t
+}
+
+fn main() {
+ assert_eq!(1, foo(1));
+ assert_eq!(2.0, foo(2.0));
+ assert_eq!(vec![1], foo(vec![1]));
+}
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/overlap-doesnt-conflict-with-specialization.rs:4:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+ = help: consider using `min_specialization` instead, which is more stable and complete
+
+warning: 1 warning emitted
+
--- /dev/null
+// run-pass
+// Tests for RFC 1268: we allow overlapping impls of marker traits,
+// that is, traits with #[marker]. In this case, a type `T` is
+// `MyMarker` if it is either `Debug` or `Display`.
+
+#![feature(marker_trait_attr)]
+
+use std::fmt::{Debug, Display};
+
+#[marker] trait MyMarker {}
+
+impl<T: Debug> MyMarker for T {}
+impl<T: Display> MyMarker for T {}
+
+fn foo<T: MyMarker>(t: T) -> T {
+ t
+}
+
+fn main() {
+ // Debug && Display:
+ assert_eq!(1, foo(1));
+ assert_eq!(2.0, foo(2.0));
+
+ // Debug && !Display:
+ assert_eq!(vec![1], foo(vec![1]));
+}
--- /dev/null
+// run-pass
+
+const TEST_STR: &'static str = "abcd";
+
+fn main() {
+ let s = "abcd";
+ match s {
+ TEST_STR => (),
+ _ => unreachable!()
+ }
+}
--- /dev/null
+// run-pass
+// Regression test for #18060: match arms were matching in the wrong order.
+
+fn main() {
+ assert_eq!(2, match (1, 3) { (0, 2..=5) => 1, (1, 3) => 2, (_, 2..=5) => 3, (_, _) => 4 });
+ assert_eq!(2, match (1, 3) { (1, 3) => 2, (_, 2..=5) => 3, (_, _) => 4 });
+ assert_eq!(2, match (1, 7) { (0, 2..=5) => 1, (1, 7) => 2, (_, 2..=5) => 3, (_, _) => 4 });
+}
--- /dev/null
+// run-pass
+#![allow(overlapping_range_endpoints)]
+
+fn main() {
+ let x = 'a';
+
+ let y = match x {
+ 'a'..='b' if false => "one",
+ 'a' => "two",
+ 'a'..='b' => "three",
+ _ => panic!("what?"),
+ };
+
+ assert_eq!(y, "two");
+}
--- /dev/null
+// run-pass
+
+// This test is bogus (i.e., should be check-fail) during the period
+// where #54986 is implemented and #54987 is *not* implemented. For
+// now: just ignore it
+//
+// ignore-test
+
+// This test is checking that the write to `c.0` (which has been moved out of)
+// won't overwrite the state in `c2`.
+//
+// That's a fine thing to test when this code is accepted by the
+// compiler, and this code is being transcribed accordingly into
+// the ui test issue-21232-partial-init-and-use.rs
+
+fn main() {
+ let mut c = (1, "".to_owned());
+ match c {
+ c2 => {
+ c.0 = 2;
+ assert_eq!(c2.0, 1);
+ }
+ }
+}
--- /dev/null
+// run-pass
+#![feature(box_syntax)]
+#![feature(box_patterns)]
+
+#[derive(Debug, PartialEq)]
+enum Test {
+ Foo(usize),
+ Bar(isize),
+}
+
+fn main() {
+ let a = box Test::Foo(10);
+ let b = box Test::Bar(-20);
+ match (a, b) {
+ (_, box Test::Foo(_)) => unreachable!(),
+ (box Test::Foo(x), b) => {
+ assert_eq!(x, 10);
+ assert_eq!(b, box Test::Bar(-20));
+ },
+ _ => unreachable!(),
+ }
+}
--- /dev/null
+// compile-flags: -O
+// run-pass
+
+struct Foo {
+ x: i32,
+}
+
+pub fn main() {
+ let mut foo = Foo { x: 42 };
+ let x = &mut foo.x;
+ *x = 13;
+ let y = foo;
+ assert_eq!(y.x, 13); // used to print 42 due to mir-opt bug
+}
+++ /dev/null
-// run-pass
-// pretty-expanded FIXME #23616
-
-pub fn main() {
- let _x: &mut [isize] = &mut [ 1, 2, 3 ];
-}
+++ /dev/null
-// run-pass
-
-pub fn main() {
- match -5 {
- -5 => {}
- _ => { panic!() }
- }
-}
+++ /dev/null
-// run-pass
-// aux-build:nested_item.rs
-
-
-extern crate nested_item;
-
-pub fn main() {
- assert_eq!(2, nested_item::foo::<()>());
- assert_eq!(2, nested_item::foo::<isize>());
-}
--- /dev/null
+// After #39485, this test used to pass, but that change was reverted
+// due to numerous inference failures like #39808, so it now fails
+// again. #39485 made it so that diverging types never propagate
+// upward; but we now do propagate such types upward in many more
+// cases.
+
+fn g() {
+ &panic!() //~ ERROR mismatched types
+}
+
+fn f() -> isize {
+ (return 1, return 2) //~ ERROR mismatched types
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/diverging-tuple-parts-39485.rs:8:5
+ |
+LL | &panic!()
+ | ^^^^^^^^^ expected `()`, found reference
+ |
+ = note: expected unit type `()`
+ found reference `&_`
+help: try adding a return type
+ |
+LL | fn g() -> &_ {
+ | +++++
+help: consider removing the borrow
+ |
+LL - &panic!()
+LL + panic!()
+ |
+
+error[E0308]: mismatched types
+ --> $DIR/diverging-tuple-parts-39485.rs:12:5
+ |
+LL | fn f() -> isize {
+ | ----- expected `isize` because of return type
+LL | (return 1, return 2)
+ | ^^^^^^^^^^^^^^^^^^^^ expected `isize`, found tuple
+ |
+ = note: expected type `isize`
+ found tuple `(!, !)`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
+++ /dev/null
-// run-pass
-
-fn f(x: Box<isize>) {
- let y: &isize = &*x;
- println!("{}", *x);
- println!("{}", *y);
-}
-
-trait Trait {
- fn printme(&self);
-}
-
-struct Struct;
-
-impl Trait for Struct {
- fn printme(&self) {
- println!("hello world!");
- }
-}
-
-fn g(x: Box<dyn Trait>) {
- x.printme();
- let y: &dyn Trait = &*x;
- y.printme();
-}
-
-fn main() {
- f(Box::new(1234));
- g(Box::new(Struct) as Box<dyn Trait>);
-}
+++ /dev/null
-// run-pass
-
-#![allow(improper_ctypes)]
-#![allow(dead_code)]
-// Issue #901
-// pretty-expanded FIXME #23616
-
-mod libc {
- extern "C" {
- pub fn printf(x: ());
- }
-}
-
-pub fn main() {}
--- /dev/null
+// run-pass
+
+pub fn main() {
+ let a = 1;
+ let a_neg: i8 = -a;
+ println!("{}", a_neg);
+
+ let b = 1;
+ let b_neg: i16 = -b;
+ println!("{}", b_neg);
+
+ let c = 1;
+ let c_neg: i32 = -c;
+ println!("{}", c_neg);
+
+ let d = 1;
+ let d_neg: i64 = -d;
+ println!("{}", d_neg);
+
+ let e = 1;
+ let e_neg: isize = -e;
+ println!("{}", e_neg);
+}
+++ /dev/null
-// Test that an object type `Box<Foo>` is not considered to implement the
-// trait `Foo`. Issue #5087.
-
-trait Foo {}
-fn take_foo<F:Foo>(f: F) {}
-fn take_object(f: Box<dyn Foo>) { take_foo(f); }
-//~^ ERROR `Box<dyn Foo>: Foo` is not satisfied
-fn main() {}
+++ /dev/null
-error[E0277]: the trait bound `Box<dyn Foo>: Foo` is not satisfied
- --> $DIR/object-does-not-impl-trait.rs:6:44
- |
-LL | fn take_object(f: Box<dyn Foo>) { take_foo(f); }
- | -------- ^ the trait `Foo` is not implemented for `Box<dyn Foo>`
- | |
- | required by a bound introduced by this call
- |
-note: required by a bound in `take_foo`
- --> $DIR/object-does-not-impl-trait.rs:5:15
- |
-LL | fn take_foo<F:Foo>(f: F) {}
- | ^^^ required by this bound in `take_foo`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0277`.
+++ /dev/null
-// run-pass
-
-#![feature(marker_trait_attr)]
-#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
-
-#[marker]
-trait MyMarker {}
-
-impl<T> MyMarker for T {}
-impl<T> MyMarker for Vec<T> {}
-
-fn foo<T: MyMarker>(t: T) -> T {
- t
-}
-
-fn main() {
- assert_eq!(1, foo(1));
- assert_eq!(2.0, foo(2.0));
- assert_eq!(vec![1], foo(vec![1]));
-}
+++ /dev/null
-warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
- --> $DIR/overlap-doesnt-conflict-with-specialization.rs:4:12
- |
-LL | #![feature(specialization)]
- | ^^^^^^^^^^^^^^
- |
- = note: `#[warn(incomplete_features)]` on by default
- = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
- = help: consider using `min_specialization` instead, which is more stable and complete
-
-warning: 1 warning emitted
-
+++ /dev/null
-// run-pass
-// Tests for RFC 1268: we allow overlapping impls of marker traits,
-// that is, traits with #[marker]. In this case, a type `T` is
-// `MyMarker` if it is either `Debug` or `Display`.
-
-#![feature(marker_trait_attr)]
-
-use std::fmt::{Debug, Display};
-
-#[marker] trait MyMarker {}
-
-impl<T: Debug> MyMarker for T {}
-impl<T: Display> MyMarker for T {}
-
-fn foo<T: MyMarker>(t: T) -> T {
- t
-}
-
-fn main() {
- // Debug && Display:
- assert_eq!(1, foo(1));
- assert_eq!(2.0, foo(2.0));
-
- // Debug && !Display:
- assert_eq!(vec![1], foo(vec![1]));
-}
--- /dev/null
+// run-pass
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![feature(unsize, coerce_unsized)]
+
+#[repr(packed)]
+struct UnalignedPtr<'a, T: ?Sized>
+ where T: 'a,
+{
+ data: &'a T,
+}
+
+fn main() {
+
+ impl<'a, T, U> std::ops::CoerceUnsized<UnalignedPtr<'a, U>> for UnalignedPtr<'a, T>
+ where
+ T: std::marker::Unsize<U> + ?Sized,
+ U: ?Sized,
+ { }
+
+ let arr = [1, 2, 3];
+ let arr_unaligned: UnalignedPtr<[i32; 3]> = UnalignedPtr { data: &arr };
+ let arr_unaligned: UnalignedPtr<[i32]> = arr_unaligned;
+}
--- /dev/null
+// check-pass
+
+// Bastion of the Turbofish
+// ------------------------
+// Beware travellers, lest you venture into waters callous and unforgiving,
+// where hope must be abandoned, ere it is cruelly torn from you. For here
+// stands the bastion of the Turbofish: an impenetrable fortress holding
+// unshaking against those who would dare suggest the supererogation of the
+// Turbofish.
+//
+// Once I was young and foolish and had the impudence to imagine that I could
+// shake free from the coils by which that creature had us tightly bound. I
+// dared to suggest that there was a better way: a brighter future, in which
+// Rustaceans both new and old could be rid of that vile beast. But alas! In
+// my foolhardiness my ignorance was unveiled and my dreams were dashed
+// unforgivingly against the rock of syntactic ambiguity.
+//
+// This humble program, small and insignificant though it might seem,
+// demonstrates that to which we had previously cast a blind eye: an ambiguity
+// in permitting generic arguments to be provided without the consent of the
+// Great Turbofish. Should you be so naïve as to try to revolt against its
+// mighty clutches, here shall its wrath be indomitably displayed. This
+// program must pass for all eternity: forever watched by the guardian angel
+// which gave this beast its name, and stands fundamentally at odds with the
+// impetuous rebellion against the Turbofish.
+//
+// My heart aches in sorrow, for I know I am defeated. Let this be a warning
+// to all those who come after: for they too must overcome the impassible
+// hurdle of defeating the great beast, championed by a resolute winged
+// guardian.
+//
+// Here stands the Bastion of the Turbofish, a memorial to Anna Harren,
+// Guardian Angel of these Hallowed Grounds. <3
+
+// See https://github.com/rust-lang/rust/pull/53562
+// and https://github.com/rust-lang/rfcs/pull/2527
+// and https://twitter.com/garblefart/status/1393236602856611843
+// for context.
+
+fn main() {
+ let (the, guardian, stands, resolute) = ("the", "Turbofish", "remains", "undefeated");
+ let _: (bool, bool) = (the<guardian, stands>(resolute));
+}
--- /dev/null
+fn main() {
+ if true {
+ } else if { //~ ERROR missing condition
+ //~^ ERROR mismatched types
+ } else {
+ }
+}
+
+fn foo() {
+ if true {
+ } else if { //~ ERROR missing condition
+ //~^ ERROR mismatched types
+ }
+ bar();
+}
+
+fn bar() {}
--- /dev/null
+error: missing condition for `if` expression
+ --> $DIR/issue-13483.rs:3:14
+ |
+LL | } else if {
+ | ^ expected if condition here
+
+error: missing condition for `if` expression
+ --> $DIR/issue-13483.rs:11:14
+ |
+LL | } else if {
+ | ^ expected if condition here
+
+error[E0308]: mismatched types
+ --> $DIR/issue-13483.rs:3:15
+ |
+LL | } else if {
+ | _______________^
+LL | |
+LL | | } else {
+ | |_____^ expected `bool`, found `()`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-13483.rs:11:15
+ |
+LL | } else if {
+ | _______________^
+LL | |
+LL | | }
+ | |_____^ expected `bool`, found `()`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// We need all these 9 issue-20616-N.rs files
+// because we can only catch one parsing error at a time
+
+type Type_1_<'a, T> = &'a T;
+
+
+//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
+
+
+//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
+
+
+//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
+
+
+type Type_4<T> = Type_1_<'static,, T>;
+//~^ error: expected one of `>`, a const expression, lifetime, or type, found `,`
+
+
+type Type_5_<'a> = Type_1_<'a, ()>;
+
+
+//type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
+
+
+//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
+
+
+//type Type_7 = Box<(),,>; // error: expected type, found `,`
+
+
+//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
+
+
+//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
--- /dev/null
+error: expected one of `>`, a const expression, lifetime, or type, found `,`
+ --> $DIR/issue-20616-4.rs:16:34
+ |
+LL | type Type_4<T> = Type_1_<'static,, T>;
+ | ^ expected one of `>`, a const expression, lifetime, or type
+
+error: aborting due to previous error
+
--- /dev/null
+// We need all these 9 issue-20616-N.rs files
+// because we can only catch one parsing error at a time
+
+type Type_1_<'a, T> = &'a T;
+
+
+//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
+
+
+//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
+
+
+//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
+
+
+//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
+
+
+type Type_5_<'a> = Type_1_<'a, ()>;
+
+
+type Type_5<'a> = Type_1_<'a, (),,>;
+//~^ error: expected one of `>`, a const expression, lifetime, or type, found `,`
+
+
+//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
+
+
+//type Type_7 = Box<(),,>; // error: expected type, found `,`
+
+
+//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
+
+
+//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
--- /dev/null
+error: expected one of `>`, a const expression, lifetime, or type, found `,`
+ --> $DIR/issue-20616-5.rs:22:34
+ |
+LL | type Type_5<'a> = Type_1_<'a, (),,>;
+ | ^ expected one of `>`, a const expression, lifetime, or type
+
+error: aborting due to previous error
+
--- /dev/null
+// We need all these 9 issue-20616-N.rs files
+// because we can only catch one parsing error at a time
+
+type Type_1_<'a, T> = &'a T;
+
+
+//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
+
+
+//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
+
+
+//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
+
+
+//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
+
+
+type Type_5_<'a> = Type_1_<'a, ()>;
+
+
+//type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
+
+
+type Type_6 = Type_5_<'a,,>;
+//~^ error: expected one of `>`, a const expression, lifetime, or type, found `,`
+
+
+//type Type_7 = Box<(),,>; // error: expected type, found `,`
+
+
+//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
+
+
+//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
--- /dev/null
+error: expected one of `>`, a const expression, lifetime, or type, found `,`
+ --> $DIR/issue-20616-6.rs:25:26
+ |
+LL | type Type_6 = Type_5_<'a,,>;
+ | ^ expected one of `>`, a const expression, lifetime, or type
+
+error: aborting due to previous error
+
--- /dev/null
+// We need all these 9 issue-20616-N.rs files
+// because we can only catch one parsing error at a time
+
+type Type_1_<'a, T> = &'a T;
+
+
+//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
+
+
+//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
+
+
+//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
+
+
+//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
+
+
+type Type_5_<'a> = Type_1_<'a, ()>;
+
+
+//type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
+
+
+//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
+
+
+type Type_7 = Box<(),,>;
+//~^ error: expected one of `>`, a const expression, lifetime, or type, found `,`
+
+
+//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
+
+
+//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
--- /dev/null
+error: expected one of `>`, a const expression, lifetime, or type, found `,`
+ --> $DIR/issue-20616-7.rs:28:22
+ |
+LL | type Type_7 = Box<(),,>;
+ | ^ expected one of `>`, a const expression, lifetime, or type
+
+error: aborting due to previous error
+
--- /dev/null
+// run-pass
+#![allow(unused_imports, overlapping_range_endpoints)]
+// pretty-expanded FIXME #23616
+
+use m::{START, END};
+
+fn main() {
+ match 42 {
+ m::START..=m::END => {},
+ 0..=m::END => {},
+ m::START..=59 => {},
+ _ => {},
+ }
+}
+
+mod m {
+ pub const START: u32 = 4;
+ pub const END: u32 = 14;
+}
--- /dev/null
+// Test that error recovery in the parser to an EOF does not give an infinite
+// spew of errors.
+
+fn main() {
+ let
+} //~ ERROR expected pattern, found `}`
--- /dev/null
+error: expected pattern, found `}`
+ --> $DIR/issue-31804.rs:6:1
+ |
+LL | }
+ | ^ expected pattern
+
+error: aborting due to previous error
+
--- /dev/null
+enum Test {
+ Drill {
+ field: i32,
+ }
+}
+
+fn main() {
+ Test::Drill(field: 42);
+ //~^ ERROR invalid `struct` delimiters or `fn` call arguments
+}
--- /dev/null
+error: invalid `struct` delimiters or `fn` call arguments
+ --> $DIR/issue-34255-1.rs:8:5
+ |
+LL | Test::Drill(field: 42);
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: if `Test::Drill` is a struct, use braces as delimiters
+ |
+LL | Test::Drill { field: 42 };
+ | ~ ~
+help: if `Test::Drill` is a function, use the arguments directly
+ |
+LL - Test::Drill(field: 42);
+LL + Test::Drill(42);
+ |
+
+error: aborting due to previous error
+
--- /dev/null
+#![allow(unused_variables)]; //~ ERROR expected item, found `;`
+//~^ ERROR `main` function
+fn foo() {}
--- /dev/null
+error: expected item, found `;`
+ --> $DIR/issue-49040.rs:1:28
+ |
+LL | #![allow(unused_variables)];
+ | ^ help: remove this semicolon
+
+error[E0601]: `main` function not found in crate `issue_49040`
+ --> $DIR/issue-49040.rs:1:1
+ |
+LL | #![allow(unused_variables)];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ consider adding a `main` function to `$DIR/issue-49040.rs`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0601`.
--- /dev/null
+struct T;
+
+impl for T {}
+//~^ ERROR missing trait in a trait impl
+
+fn main() {}
--- /dev/null
+error: missing trait in a trait impl
+ --> $DIR/issue-56031.rs:3:5
+ |
+LL | impl for T {}
+ | ^
+ |
+help: add a trait here
+ |
+LL | impl Trait for T {}
+ | +++++
+help: for an inherent impl, drop this `for`
+ |
+LL - impl for T {}
+LL + impl T {}
+ |
+
+error: aborting due to previous error
+
--- /dev/null
+// run-pass
+// Destructuring struct variants would ICE where regular structs wouldn't
+
+enum Foo {
+ VBar { num: isize }
+}
+
+struct SBar { num: isize }
+
+pub fn main() {
+ let vbar = Foo::VBar { num: 1 };
+ let Foo::VBar { num } = vbar;
+ assert_eq!(num, 1);
+
+ let sbar = SBar { num: 2 };
+ let SBar { num } = sbar;
+ assert_eq!(num, 2);
+}
--- /dev/null
+// run-pass
+
+fn main() {
+ let mut x: &[_] = &[1, 2, 3, 4];
+
+ let mut result = vec![];
+ loop {
+ x = match *x {
+ [1, n, 3, ref rest @ ..] => {
+ result.push(n);
+ rest
+ }
+ [n, ref rest @ ..] => {
+ result.push(n);
+ rest
+ }
+ [] =>
+ break
+ }
+ }
+ assert_eq!(result, [2, 4]);
+}
--- /dev/null
+struct Binder(i32, i32, i32);
+
+fn main() {
+ let x = Binder(1, 2, 3);
+ match x {
+ Binder(_a, _x @ ..) => {}
+ _ => {}
+ }
+}
+//~^^^^ ERROR `_x @` is not allowed in a tuple struct
+//~| ERROR: `..` patterns are not allowed here
+//~| ERROR: this pattern has 2 fields, but the corresponding tuple struct has 3 fields
--- /dev/null
+error: `_x @` is not allowed in a tuple struct
+ --> $DIR/issue-72574-2.rs:6:20
+ |
+LL | Binder(_a, _x @ ..) => {}
+ | ^^^^^^^ this is only allowed in slice patterns
+ |
+ = help: remove this and bind each tuple field independently
+help: if you don't need to use the contents of _x, discard the tuple's remaining fields
+ |
+LL | Binder(_a, ..) => {}
+ | ~~
+
+error: `..` patterns are not allowed here
+ --> $DIR/issue-72574-2.rs:6:25
+ |
+LL | Binder(_a, _x @ ..) => {}
+ | ^^
+ |
+ = note: only allowed in tuple, tuple struct, and slice patterns
+
+error[E0023]: this pattern has 2 fields, but the corresponding tuple struct has 3 fields
+ --> $DIR/issue-72574-2.rs:6:16
+ |
+LL | struct Binder(i32, i32, i32);
+ | --- --- --- tuple struct has 3 fields
+...
+LL | Binder(_a, _x @ ..) => {}
+ | ^^ ^^^^^^^ expected 3 fields, found 2
+ |
+help: use `_` to explicitly ignore each field
+ |
+LL | Binder(_a, _x @ .., _) => {}
+ | +++
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0023`.
--- /dev/null
+// run-pass
+#![allow(dead_code)]
+
+enum E {
+ Foo{f: isize},
+ Bar,
+}
+
+pub fn main() {
+ let e = E::Foo{f: 0};
+ match e {
+ E::Foo{f: 1} => panic!(),
+ E::Foo{..} => (),
+ _ => panic!(),
+ }
+}
--- /dev/null
+// run-pass
+#![allow(dead_code)]
+
+enum E {
+ Foo{f: isize, b: bool},
+ Bar,
+}
+
+pub fn main() {
+ let e = E::Foo{f: 0, b: false};
+ match e {
+ E::Foo{f: 1, b: true} => panic!(),
+ E::Foo{b: false, f: 0} => (),
+ _ => panic!(),
+ }
+}
--- /dev/null
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![deny(warnings)]
+#![feature(proc_macro_expand, proc_macro_span)]
+
+extern crate proc_macro;
+
+use proc_macro::*;
+use std::str::FromStr;
+
+#[proc_macro]
+pub fn expand_expr_is(input: TokenStream) -> TokenStream {
+ let mut iter = input.into_iter();
+ let mut expected_tts = Vec::new();
+ loop {
+ match iter.next() {
+ Some(TokenTree::Punct(ref p)) if p.as_char() == ',' => break,
+ Some(tt) => expected_tts.push(tt),
+ None => panic!("expected comma"),
+ }
+ }
+
+ 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()
+}
+
+#[proc_macro]
+pub fn expand_expr_fail(input: TokenStream) -> TokenStream {
+ match input.expand_expr() {
+ Ok(ts) => panic!("expand_expr unexpectedly succeeded: `{}`", ts),
+ Err(_) => TokenStream::new(),
+ }
+}
+
+#[proc_macro]
+pub fn check_expand_expr_file(ts: TokenStream) -> TokenStream {
+ // Check that the passed in `file!()` invocation and a parsed `file!`
+ // invocation expand to the same literal.
+ let input_t = ts.expand_expr().expect("expand_expr failed on macro input").to_string();
+ let parse_t = TokenStream::from_str("file!{}")
+ .unwrap()
+ .expand_expr()
+ .expect("expand_expr failed on internal macro")
+ .to_string();
+ assert_eq!(input_t, parse_t);
+
+ // Check that the literal matches `Span::call_site().source_file().path()`
+ let expect_t =
+ Literal::string(&Span::call_site().source_file().path().to_string_lossy()).to_string();
+ assert_eq!(input_t, expect_t);
+
+ TokenStream::new()
+}
+
+#[proc_macro]
+pub fn recursive_expand(_: TokenStream) -> TokenStream {
+ // Recursively call until we hit the recursion limit and get an error.
+ //
+ // NOTE: This doesn't panic if expansion fails because that'll cause a very
+ // large number of errors to fill the output.
+ TokenStream::from_str("recursive_expand!{}")
+ .unwrap()
+ .expand_expr()
+ .unwrap_or(std::iter::once(TokenTree::Literal(Literal::u32_suffixed(0))).collect())
+}
+
+#[proc_macro]
+pub fn echo_pm(input: TokenStream) -> TokenStream {
+ input
+}
--- /dev/null
+Included file contents
--- /dev/null
+// aux-build:expand-expr.rs
+
+extern crate expand_expr;
+
+use expand_expr::{
+ check_expand_expr_file, echo_pm, expand_expr_fail, expand_expr_is, recursive_expand,
+};
+
+// Check builtin macros can be expanded.
+
+expand_expr_is!(11u32, line!());
+expand_expr_is!(24u32, column!());
+
+expand_expr_is!("Hello, World!", concat!("Hello, ", "World", "!"));
+expand_expr_is!("int10floats5.3booltrue", concat!("int", 10, "floats", 5.3, "bool", true));
+expand_expr_is!("Hello", concat!(r##"Hello"##));
+
+expand_expr_is!("Included file contents\n", include_str!("auxiliary/included-file.txt"));
+expand_expr_is!(b"Included file contents\n", include_bytes!("auxiliary/included-file.txt"));
+
+expand_expr_is!(
+ "contents: Included file contents\n",
+ concat!("contents: ", include_str!("auxiliary/included-file.txt"))
+);
+
+// Correct value is checked for multiple sources.
+check_expand_expr_file!(file!());
+
+expand_expr_is!("hello", stringify!(hello));
+expand_expr_is!("10 + 20", stringify!(10 + 20));
+
+macro_rules! echo_tts {
+ ($($t:tt)*) => { $($t)* }; //~ ERROR: expected expression, found `$`
+}
+
+macro_rules! echo_lit {
+ ($l:literal) => {
+ $l
+ };
+}
+
+macro_rules! echo_expr {
+ ($e:expr) => {
+ $e
+ };
+}
+
+macro_rules! simple_lit {
+ ($l:literal) => {
+ 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!($l, mac!());
+ expand_expr_is!($l, echo_expr!(mac!()));
+ expand_expr_is!($l, echo_tts!(mac!()));
+ expand_expr_is!($l, echo_pm!(mac!()));
+ };
+ };
+}
+
+simple_lit!("Hello, World");
+simple_lit!('c');
+simple_lit!(b'c');
+simple_lit!(10);
+simple_lit!(10.0);
+simple_lit!(10.0f64);
+simple_lit!(-3.14159);
+simple_lit!(-3.5e10);
+simple_lit!(0xFEED);
+simple_lit!(-0xFEED);
+simple_lit!(0b0100);
+simple_lit!(-0b0100);
+simple_lit!("string");
+simple_lit!(r##"raw string"##);
+simple_lit!(b"byte string");
+simple_lit!(br##"raw byte string"##);
+simple_lit!(true);
+simple_lit!(false);
+
+// Ensure char escapes aren't normalized by expansion
+simple_lit!("\u{0}");
+simple_lit!("\0");
+simple_lit!("\x00");
+simple_lit!('\u{0}');
+simple_lit!('\0');
+simple_lit!('\x00');
+simple_lit!(b"\x00");
+simple_lit!(b"\0");
+simple_lit!(b'\x00');
+simple_lit!(b'\0');
+
+// Extra tokens after the string literal aren't ignored
+expand_expr_fail!("string"; hello); //~ ERROR: expected one of `.`, `?`, or an operator, found `;`
+
+// Invalid expressions produce errors in addition to returning `Err(())`.
+expand_expr_fail!($); //~ ERROR: expected expression, found `$`
+expand_expr_fail!(echo_tts!($));
+expand_expr_fail!(echo_pm!($)); //~ ERROR: expected expression, found `$`
+
+// We get errors reported and recover during macro expansion if the macro
+// doesn't produce a valid expression.
+expand_expr_is!("string", echo_tts!("string"; hello)); //~ ERROR: macro expansion ignores token `hello` and any following
+expand_expr_is!("string", echo_pm!("string"; hello)); //~ ERROR: macro expansion ignores token `;` and any following
+
+// For now, fail if a non-literal expression is expanded.
+expand_expr_fail!(arbitrary_expression() + "etc");
+expand_expr_fail!(echo_tts!(arbitrary_expression() + "etc"));
+expand_expr_fail!(echo_expr!(arbitrary_expression() + "etc"));
+expand_expr_fail!(echo_pm!(arbitrary_expression() + "etc"));
+
+const _: u32 = recursive_expand!(); //~ ERROR: recursion limit reached while expanding `recursive_expand!`
+
+fn main() {}
--- /dev/null
+error: expected one of `.`, `?`, or an operator, found `;`
+ --> $DIR/expand-expr.rs:101:27
+ |
+LL | expand_expr_fail!("string"; hello);
+ | ^ expected one of `.`, `?`, or an operator
+
+error: expected expression, found `$`
+ --> $DIR/expand-expr.rs:104:19
+ |
+LL | expand_expr_fail!($);
+ | ^ expected expression
+
+error: expected expression, found `$`
+ --> $DIR/expand-expr.rs:33:23
+ |
+LL | ($($t:tt)*) => { $($t)* };
+ | ^^^^ expected expression
+
+error: expected expression, found `$`
+ --> $DIR/expand-expr.rs:106:28
+ |
+LL | expand_expr_fail!(echo_pm!($));
+ | ^ expected expression
+
+error: macro expansion ignores token `hello` and any following
+ --> $DIR/expand-expr.rs:110:47
+ |
+LL | expand_expr_is!("string", echo_tts!("string"; hello));
+ | --------------------^^^^^-- help: you might be missing a semicolon here: `;`
+ | |
+ | caused by the macro expansion here
+ |
+ = note: the usage of `echo_tts!` is likely invalid in expression context
+
+error: macro expansion ignores token `;` and any following
+ --> $DIR/expand-expr.rs:111:44
+ |
+LL | expand_expr_is!("string", echo_pm!("string"; hello));
+ | -----------------^-------- help: you might be missing a semicolon here: `;`
+ | |
+ | caused by the macro expansion here
+ |
+ = note: the usage of `echo_pm!` is likely invalid in expression context
+
+error: recursion limit reached while expanding `recursive_expand!`
+ --> $DIR/expand-expr.rs:119:16
+ |
+LL | const _: u32 = recursive_expand!();
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`expand_expr`)
+ = note: this error originates in the macro `recursive_expand` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 7 previous errors
+
// run-pass
-#![allow(dead_code)]
+#![allow(dead_code, unused_macros)]
// aux-build:issue-39889.rs
extern crate issue_39889;
--- /dev/null
+// run-pass
+#![allow(unused_mut)]
+// ignore-emscripten no processes
+// ignore-sgx no processes
+
+use std::env;
+use std::io::prelude::*;
+use std::io;
+use std::process::{Command, Stdio};
+
+fn main() {
+ let args: Vec<String> = env::args().collect();
+ if args.len() > 1 && args[1] == "child" {
+ return child()
+ }
+
+ test();
+}
+
+fn child() {
+ writeln!(&mut io::stdout(), "foo").unwrap();
+ writeln!(&mut io::stderr(), "bar").unwrap();
+ let mut stdin = io::stdin();
+ let mut s = String::new();
+ stdin.lock().read_line(&mut s).unwrap();
+ assert_eq!(s.len(), 0);
+}
+
+fn test() {
+ let args: Vec<String> = env::args().collect();
+ let mut p = Command::new(&args[0]).arg("child")
+ .stdin(Stdio::piped())
+ .stdout(Stdio::piped())
+ .stderr(Stdio::piped())
+ .spawn().unwrap();
+ assert!(p.wait().unwrap().success());
+}
--- /dev/null
+// run-pass
+// ignore-emscripten no processes
+// ignore-sgx no processes
+
+use std::process::Command;
+use std::env;
+
+fn main() {
+ let len = env::args().len();
+
+ if len == 1 {
+ test();
+ } else {
+ assert_eq!(len, 3);
+ }
+}
+
+fn test() {
+ let status = Command::new(&env::current_exe().unwrap())
+ .arg("foo").arg("")
+ .status().unwrap();
+ assert!(status.success());
+}
--- /dev/null
+// run-pass
+#![allow(stable_features)]
+
+// ignore-emscripten no processes
+// ignore-sgx no processes
+
+#![feature(os)]
+
+#[cfg(unix)]
+fn main() {
+ use std::process::Command;
+ use std::env;
+ use std::os::unix::prelude::*;
+ use std::ffi::OsStr;
+
+ if env::args().len() == 1 {
+ assert!(Command::new(&env::current_exe().unwrap())
+ .arg(<OsStr as OsStrExt>::from_bytes(b"\xff"))
+ .status().unwrap().success())
+ }
+}
+
+#[cfg(windows)]
+fn main() {}
use libc::c_int;
-#[cfg(not(target_os = "linux"))]
-fn getpid() -> u32 {
- process::id()
-}
-
-/// We need to directly use the getpid syscall instead of using `process::id()`
-/// because the libc wrapper might return incorrect values after a process was
-/// forked.
-#[cfg(target_os = "linux")]
-fn getpid() -> u32 {
- unsafe {
- libc::syscall(libc::SYS_getpid) as _
- }
-}
-
/// This stunt allocator allows us to spot heap allocations in the child.
struct PidChecking<A> {
parent: A,
fn check(&self) {
let require_pid = self.require_pid.load(Ordering::Acquire);
if require_pid != 0 {
- let actual_pid = getpid();
+ let actual_pid = process::id();
if require_pid != actual_pid {
unsafe {
libc::raise(libc::SIGUSR1);
--- /dev/null
+// run-pass
+// ignore-emscripten no processes
+// ignore-sgx no processes
+// ignore-windows
+
+use std::env;
+use std::process::Command;
+
+pub fn main() {
+ let args: Vec<String> = env::args().collect();
+ if args.len() >= 2 && args[1] == "signal" {
+ // Raise a segfault.
+ unsafe { *(1 as *mut isize) = 0; }
+ } else {
+ let status = Command::new(&args[0]).arg("signal").status().unwrap();
+ assert!(status.code().is_none());
+ }
+}
fn a() {
// the cast is unreachable:
let x = {return} as !; //~ ERROR unreachable
+ //~| ERROR non-primitive cast
}
fn main() { }
LL | #![deny(unreachable_code)]
| ^^^^^^^^^^^^^^^^
-error: aborting due to previous error
+error[E0605]: non-primitive cast: `()` as `!`
+ --> $DIR/expr_cast.rs:9:13
+ |
+LL | let x = {return} as !;
+ | ^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+
+error: aborting due to 2 previous errors
+For more information about this error, try `rustc --explain E0605`.
--- /dev/null
+// check-pass
+#![allow(dead_code)]
+// Test that the requirement (in `Bar`) that `T::Bar : 'static` does
+// not wind up propagating to `T`.
+
+// pretty-expanded FIXME #23616
+
+pub trait Foo {
+ type Bar;
+
+ fn foo(&self) -> Self;
+}
+
+pub struct Static<T:'static>(T);
+
+struct Bar<T:Foo>
+ where T::Bar : 'static
+{
+ x: Static<Option<T::Bar>>
+}
+
+fn main() { }
--- /dev/null
+// run-pass
+
+pub trait Foo<T> {
+ fn foo(self) -> T;
+}
+
+impl<'a, T> Foo<T> for &'a str where &'a str: Into<T> {
+ fn foo(self) -> T {
+ panic!();
+ }
+}
+
+fn main() {}
--- /dev/null
+// check-pass
+
+pub struct Bar<T> {
+ items: Vec<&'static str>,
+ inner: T,
+}
+
+pub trait IntoBar<T> {
+ fn into_bar(self) -> Bar<T>;
+}
+
+impl<'a, T> IntoBar<T> for &'a str where &'a str: Into<T> {
+ fn into_bar(self) -> Bar<T> {
+ Bar {
+ items: Vec::new(),
+ inner: self.into(),
+ }
+ }
+}
+
+fn main() {}
--- /dev/null
+// check-pass
+
+pub struct Item {
+ _inner: &'static str,
+}
+
+pub struct Bar<T> {
+ items: Vec<Item>,
+ inner: T,
+}
+
+pub trait IntoBar<T> {
+ fn into_bar(self) -> Bar<T>;
+}
+
+impl<'a, T> IntoBar<T> for &'a str where &'a str: Into<T> {
+ fn into_bar(self) -> Bar<T> {
+ Bar {
+ items: Vec::new(),
+ inner: self.into(),
+ }
+ }
+}
+
+fn main() {}
+++ /dev/null
-// build-fail
-
-#![feature(lang_items, no_core)]
-#![no_core]
-
-#[lang="copy"] pub trait Copy { }
-#[lang="sized"] pub trait Sized { }
-
-// error-pattern:requires `start` lang_item
-
-fn main() {}
+++ /dev/null
-error: requires `start` lang_item
-
-error: aborting due to previous error
-
--- /dev/null
+// edition:2015
+
+mod inner {
+ fn global_inner(_: ::nonexistant::Foo) {
+ //~^ ERROR failed to resolve: maybe a missing crate `nonexistant`?
+ }
+ fn crate_inner(_: crate::nonexistant::Foo) {
+ //~^ ERROR failed to resolve: maybe a missing crate `nonexistant`?
+ }
+
+ fn bare_global(_: ::nonexistant) {
+ //~^ ERROR cannot find type `nonexistant` in the crate root
+ }
+ fn bare_crate(_: crate::nonexistant) {
+ //~^ ERROR cannot find type `nonexistant` in the crate root
+ }
+}
+
+fn main() {
+
+}
--- /dev/null
+error[E0433]: failed to resolve: maybe a missing crate `nonexistant`?
+ --> $DIR/editions-crate-root-2015.rs:4:26
+ |
+LL | fn global_inner(_: ::nonexistant::Foo) {
+ | ^^^^^^^^^^^ maybe a missing crate `nonexistant`?
+
+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`?
+
+error[E0412]: cannot find type `nonexistant` in the crate root
+ --> $DIR/editions-crate-root-2015.rs:11:25
+ |
+LL | fn bare_global(_: ::nonexistant) {
+ | ^^^^^^^^^^^ not found in the crate root
+
+error[E0412]: cannot find type `nonexistant` in the crate root
+ --> $DIR/editions-crate-root-2015.rs:14:29
+ |
+LL | fn bare_crate(_: crate::nonexistant) {
+ | ^^^^^^^^^^^ not found in the crate root
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0412, E0433.
+For more information about an error, try `rustc --explain E0412`.
--- /dev/null
+trait Trait {
+ fn outer(&self) {
+ fn inner(_: &Self) {
+ //~^ ERROR can't use generic parameters from outer function
+ }
+ }
+}
+
+fn main() { }
--- /dev/null
+error[E0401]: can't use generic parameters from outer function
+ --> $DIR/issue-12796.rs:3:22
+ |
+LL | fn inner(_: &Self) {
+ | ^^^^
+ | |
+ | use of generic parameter from outer function
+ | can't use `Self` here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0401`.
--- /dev/null
+static foo: i32 = 0;
+
+fn bar(foo: i32) {}
+//~^ ERROR function parameters cannot shadow statics
+//~| cannot be named the same as a static
+
+mod submod {
+ pub static answer: i32 = 42;
+}
+
+use self::submod::answer;
+
+fn question(answer: i32) {}
+//~^ ERROR function parameters cannot shadow statics
+//~| cannot be named the same as a static
+fn main() {
+}
--- /dev/null
+error[E0530]: function parameters cannot shadow statics
+ --> $DIR/issue-23716.rs:3:8
+ |
+LL | static foo: i32 = 0;
+ | -------------------- the static `foo` is defined here
+LL |
+LL | fn bar(foo: i32) {}
+ | ^^^ cannot be named the same as a static
+
+error[E0530]: function parameters cannot shadow statics
+ --> $DIR/issue-23716.rs:13:13
+ |
+LL | use self::submod::answer;
+ | -------------------- the static `answer` is imported here
+LL |
+LL | fn question(answer: i32) {}
+ | ^^^^^^ cannot be named the same as a static
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0530`.
--- /dev/null
+fn siphash<T>() {
+
+ trait U {
+ fn g(&self, x: T) -> T; //~ ERROR can't use generic parameters from outer function
+ //~^ ERROR can't use generic parameters from outer function
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0401]: can't use generic parameters from outer function
+ --> $DIR/issue-3021-c.rs:4:24
+ |
+LL | fn siphash<T>() {
+ | - type parameter from outer function
+...
+LL | fn g(&self, x: T) -> T;
+ | - ^ use of generic parameter from outer function
+ | |
+ | help: try using a local generic parameter instead: `g<T>`
+
+error[E0401]: can't use generic parameters from outer function
+ --> $DIR/issue-3021-c.rs:4:30
+ |
+LL | fn siphash<T>() {
+ | - type parameter from outer function
+...
+LL | fn g(&self, x: T) -> T;
+ | - ^ use of generic parameter from outer function
+ | |
+ | help: try using a local generic parameter instead: `g<T>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0401`.
--- /dev/null
+trait SipHash {
+ fn reset(&self);
+}
+
+fn siphash(k0 : u64) {
+ struct SipState {
+ v0: u64,
+ }
+
+ impl SipHash for SipState {
+ fn reset(&self) {
+ self.v0 = k0 ^ 0x736f6d6570736575; //~ ERROR can't capture dynamic environment
+ }
+ }
+ panic!();
+}
+
+fn main() {}
--- /dev/null
+error[E0434]: can't capture dynamic environment in a fn item
+ --> $DIR/issue-3021.rs:12:22
+ |
+LL | self.v0 = k0 ^ 0x736f6d6570736575;
+ | ^^
+ |
+ = help: use the `|| { ... }` closure form instead
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0434`.
--- /dev/null
+// Checks lexical scopes cannot see through normal module boundaries
+
+fn f() {
+ fn g() {}
+ mod foo {
+ fn h() {
+ g(); //~ ERROR cannot find function `g` in this scope
+ }
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0425]: cannot find function `g` in this scope
+ --> $DIR/issue-31845.rs:7:12
+ |
+LL | g();
+ | ^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
--- /dev/null
+trait B <A> {
+ fn a() -> A {
+ this.a //~ ERROR cannot find value `this` in this scope
+ }
+ fn b(x: i32) {
+ this.b(x); //~ ERROR cannot find value `this` in this scope
+ }
+ fn c() {
+ let _ = || this.a; //~ ERROR cannot find value `this` in this scope
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0425]: cannot find value `this` in this scope
+ --> $DIR/issue-5099.rs:3:9
+ |
+LL | this.a
+ | ^^^^ not found in this scope
+ |
+help: you might have meant to use `self` here instead
+ |
+LL | self.a
+ | ~~~~
+help: if you meant to use `self`, you are also missing a `self` receiver argument
+ |
+LL | fn a(&self) -> A {
+ | +++++
+
+error[E0425]: cannot find value `this` in this scope
+ --> $DIR/issue-5099.rs:6:9
+ |
+LL | this.b(x);
+ | ^^^^ not found in this scope
+ |
+help: you might have meant to use `self` here instead
+ |
+LL | self.b(x);
+ | ~~~~
+help: if you meant to use `self`, you are also missing a `self` receiver argument
+ |
+LL | fn b(&self, x: i32) {
+ | ++++++
+
+error[E0425]: cannot find value `this` in this scope
+ --> $DIR/issue-5099.rs:9:20
+ |
+LL | let _ = || this.a;
+ | ^^^^ not found in this scope
+ |
+help: you might have meant to use `self` here instead
+ |
+LL | let _ = || self.a;
+ | ~~~~
+help: if you meant to use `self`, you are also missing a `self` receiver argument
+ |
+LL | fn c(&self) {
+ | +++++
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0425`.
--- /dev/null
+// Matching against NaN should result in a warning
+
+#![allow(unused)]
+#![deny(illegal_floating_point_literal_pattern)]
+
+const NAN: f64 = f64::NAN;
+
+fn main() {
+ let x = NAN;
+ match x {
+ NAN => {}, //~ ERROR floating-point types cannot be used
+ //~| WARN this was previously accepted by the compiler but is being phased out
+ _ => {},
+ };
+
+ match [x, 1.0] {
+ [NAN, _] => {}, //~ ERROR floating-point types cannot be used
+ //~| WARN this was previously accepted by the compiler but is being phased out
+ _ => {},
+ };
+}
--- /dev/null
+error: floating-point types cannot be used in patterns
+ --> $DIR/issue-6804.rs:11:9
+ |
+LL | NAN => {},
+ | ^^^
+ |
+note: the lint level is defined here
+ --> $DIR/issue-6804.rs:4:9
+ |
+LL | #![deny(illegal_floating_point_literal_pattern)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
+
+error: floating-point types cannot be used in patterns
+ --> $DIR/issue-6804.rs:17:10
+ |
+LL | [NAN, _] => {},
+ | ^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
+
+error: aborting due to 2 previous errors
+
pub struct Int(i32);
-impl const std::ops::Add for i32 {
- //~^ ERROR conflicting implementations of trait
- //~| ERROR only traits defined in the current crate can be implemented for arbitrary types
+impl const std::ops::Add for i32 { //~ ERROR type annotations needed
+ //~^ ERROR only traits defined in the current crate can be implemented for arbitrary types
type Output = Self;
fn add(self, rhs: Self) -> Self {
}
}
-impl std::ops::Add for Int {
+impl std::ops::Add for Int { //~ ERROR type annotations needed
type Output = Self;
fn add(self, rhs: Self) -> Self {
}
}
-impl const std::ops::Add for Int {
+impl const std::ops::Add for Int { //~ ERROR type annotations needed
//~^ ERROR conflicting implementations of trait
type Output = Self;
-error[E0119]: conflicting implementations of trait `std::ops::Add` for type `i32`
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> $DIR/const-and-non-const-impl.rs:5:1
|
LL | impl const std::ops::Add for i32 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^-------------^^^^^---
+ | | | |
+ | | | `i32` is not defined in the current crate
+ | | `i32` is not defined in the current crate
+ | impl doesn't use only types from inside the current crate
|
- = note: conflicting implementation in crate `core`:
- - impl Add for i32;
+ = note: define and implement a trait or new type instead
error[E0119]: conflicting implementations of trait `std::ops::Add` for type `Int`
- --> $DIR/const-and-non-const-impl.rs:23:1
+ --> $DIR/const-and-non-const-impl.rs:22:1
|
LL | impl std::ops::Add for Int {
| -------------------------- first implementation here
LL | impl const std::ops::Add for Int {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Int`
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0283]: type annotations needed
+ --> $DIR/const-and-non-const-impl.rs:5:12
+ |
+LL | impl const std::ops::Add for i32 {
+ | ^^^^^^^^^^^^^ cannot infer type for type `i32`
+ |
+note: multiple `impl`s satisfying `i32: Add` found
--> $DIR/const-and-non-const-impl.rs:5:1
|
LL | impl const std::ops::Add for i32 {
- | ^^^^^^^^^^^-------------^^^^^---
- | | | |
- | | | `i32` is not defined in the current crate
- | | `i32` is not defined in the current crate
- | impl doesn't use only types from inside the current crate
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: and another `impl` found in the `core` crate: `impl Add for i32;`
+note: required by a bound in `Add`
+ --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
|
- = note: define and implement a trait or new type instead
+LL | / pub trait Add<Rhs = Self> {
+LL | | /// The resulting type after applying the `+` operator.
+LL | | #[stable(feature = "rust1", since = "1.0.0")]
+LL | | type Output;
+... |
+LL | | fn add(self, rhs: Rhs) -> Self::Output;
+LL | | }
+ | |_^ required by this bound in `Add`
+
+error[E0283]: type annotations needed
+ --> $DIR/const-and-non-const-impl.rs:14:6
+ |
+LL | impl std::ops::Add for Int {
+ | ^^^^^^^^^^^^^ cannot infer type for struct `Int`
+ |
+note: multiple `impl`s satisfying `Int: Add` found
+ --> $DIR/const-and-non-const-impl.rs:14:1
+ |
+LL | impl std::ops::Add for Int {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl const std::ops::Add for Int {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `Add`
+ --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
+ |
+LL | / pub trait Add<Rhs = Self> {
+LL | | /// The resulting type after applying the `+` operator.
+LL | | #[stable(feature = "rust1", since = "1.0.0")]
+LL | | type Output;
+... |
+LL | | fn add(self, rhs: Rhs) -> Self::Output;
+LL | | }
+ | |_^ required by this bound in `Add`
+
+error[E0283]: type annotations needed
+ --> $DIR/const-and-non-const-impl.rs:22:12
+ |
+LL | impl const std::ops::Add for Int {
+ | ^^^^^^^^^^^^^ cannot infer type for struct `Int`
+ |
+note: multiple `impl`s satisfying `Int: Add` found
+ --> $DIR/const-and-non-const-impl.rs:14:1
+ |
+LL | impl std::ops::Add for Int {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl const std::ops::Add for Int {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `Add`
+ --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
+ |
+LL | / pub trait Add<Rhs = Self> {
+LL | | /// The resulting type after applying the `+` operator.
+LL | | #[stable(feature = "rust1", since = "1.0.0")]
+LL | | type Output;
+... |
+LL | | fn add(self, rhs: Rhs) -> Self::Output;
+LL | | }
+ | |_^ required by this bound in `Add`
-error: aborting due to 3 previous errors
+error: aborting due to 5 previous errors
-Some errors have detailed explanations: E0117, E0119.
+Some errors have detailed explanations: E0117, E0119, E0283.
For more information about an error, try `rustc --explain E0117`.
--- /dev/null
+// gate-test-type_changing_struct_update
+
+#[derive(Debug)]
+struct Machine<S> {
+ state: S,
+ common_field1: &'static str,
+ common_field2: i32,
+}
+#[derive(Debug)]
+struct State1;
+#[derive(Debug, PartialEq)]
+struct State2;
+
+fn update_to_state2() {
+ let m1: Machine<State1> = Machine {
+ state: State1,
+ common_field1: "hello",
+ common_field2: 2,
+ };
+ let m2: Machine<State2> = Machine {
+ state: State2,
+ ..m1
+ //~^ ERROR type changing struct updating is experimental [E0658]
+ //~| ERROR mismatched types [E0308]
+ };
+ assert_eq!(State2, m2.state);
+}
+
+fn main() {}
--- /dev/null
+error[E0658]: type changing struct updating is experimental
+ --> $DIR/feature-gate.rs:22:11
+ |
+LL | ..m1
+ | ^^
+ |
+ = note: see issue #86555 <https://github.com/rust-lang/rust/issues/86555> for more information
+ = help: add `#![feature(type_changing_struct_update)]` to the crate attributes to enable
+
+error[E0308]: mismatched types
+ --> $DIR/feature-gate.rs:22:11
+ |
+LL | ..m1
+ | ^^ expected struct `State2`, found struct `State1`
+ |
+ = note: expected struct `Machine<State2>`
+ found struct `Machine<State1>`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0308, E0658.
+For more information about an error, try `rustc --explain E0308`.
--- /dev/null
+#![feature(type_changing_struct_update)]
+#![allow(incomplete_features)]
+
+#[derive(Clone)]
+struct Machine<'a, S> {
+ state: S,
+ lt_str: &'a str,
+ common_field: i32,
+}
+
+#[derive(Clone)]
+struct State1;
+#[derive(Clone)]
+struct State2;
+
+fn update_to_state2() {
+ let s = String::from("hello");
+ let m1: Machine<State1> = Machine {
+ state: State1,
+ lt_str: &s,
+ //~^ ERROR `s` does not live long enough [E0597]
+ // FIXME: The error here actually comes from line 34. The
+ // span of the error message should be corrected to line 34
+ common_field: 2,
+ };
+ // update lifetime
+ let m3: Machine<'static, State1> = Machine {
+ lt_str: "hello, too",
+ ..m1.clone()
+ };
+ // update lifetime and type
+ let m4: Machine<'static, State2> = Machine {
+ state: State2,
+ lt_str: "hello, again",
+ ..m1.clone()
+ };
+ // updating to `static should fail.
+ let m2: Machine<'static, State1> = Machine {
+ ..m1
+ };
+}
+
+fn main() {}
--- /dev/null
+error[E0597]: `s` does not live long enough
+ --> $DIR/lifetime-update.rs:20:17
+ |
+LL | lt_str: &s,
+ | ^^ borrowed value does not live long enough
+...
+LL | let m2: Machine<'static, State1> = Machine {
+ | ------------------------ type annotation requires that `s` is borrowed for `'static`
+...
+LL | }
+ | - `s` dropped here while still borrowed
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
--- /dev/null
+#![feature(type_changing_struct_update)]
+#![allow(incomplete_features)]
+
+struct Machine<'a, S, M> {
+ state: S,
+ message: M,
+ lt_str: &'a str,
+ common_field: i32,
+}
+
+struct State1;
+struct State2;
+
+struct Message1;
+struct Message2;
+
+fn update() {
+ let m1: Machine<State1, Message1> = Machine {
+ state: State1,
+ message: Message1,
+ lt_str: "hello",
+ common_field: 2,
+ };
+ // single type update
+ let m2: Machine<State2, Message1> = Machine {
+ state: State2,
+ ..m1
+ };
+ // multiple type update
+ let m3: Machine<State2, Message2> = Machine {
+ state: State2,
+ message: Message2,
+ ..m1
+ };
+}
+
+fn fail_update() {
+ let m1: Machine<f64, f64> = Machine {
+ state: 3.2,
+ message: 6.4,
+ lt_str: "hello",
+ common_field: 2,
+ };
+ // single type update fail
+ let m2: Machine<i32, f64> = Machine {
+ ..m1
+ //~^ ERROR mismatched types [E0308]
+ };
+ // multiple type update fail
+ let m3 = Machine::<i32, i32> {
+ ..m1
+ //~^ ERROR mismatched types [E0308]
+ //~| ERROR mismatched types [E0308]
+ };
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/type-generic-update.rs:46:11
+ |
+LL | ..m1
+ | ^^ field type mismatch: Machine.state
+ |
+ = note: expected type `i32`
+ found type `f64`
+
+error[E0308]: mismatched types
+ --> $DIR/type-generic-update.rs:51:11
+ |
+LL | ..m1
+ | ^^ field type mismatch: Machine.state
+ |
+ = note: expected type `i32`
+ found type `f64`
+
+error[E0308]: mismatched types
+ --> $DIR/type-generic-update.rs:51:11
+ |
+LL | ..m1
+ | ^^ field type mismatch: Machine.message
+ |
+ = note: expected type `i32`
+ found type `f64`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+struct A<T>(T);
+
+impl A<&'static u8> {
+ fn f() {
+ let x = 0;
+ Self(&x);
+ //~^ ERROR `x` does not live long enough
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0597]: `x` does not live long enough
+ --> $DIR/issue-61882-2.rs:6:14
+ |
+LL | Self(&x);
+ | ^^
+ | |
+ | borrowed value does not live long enough
+ | this usage requires that `x` is borrowed for `'static`
+LL |
+LL | }
+ | - `x` dropped here while still borrowed
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
--- /dev/null
+struct A<T>(T);
+
+impl A<bool> {
+ const B: A<u8> = Self(0);
+ //~^ ERROR mismatched types
+ //~| ERROR mismatched types
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-61882.rs:4:27
+ |
+LL | const B: A<u8> = Self(0);
+ | ^ expected `bool`, found integer
+
+error[E0308]: mismatched types
+ --> $DIR/issue-61882.rs:4:22
+ |
+LL | const B: A<u8> = Self(0);
+ | ^^^^^^^ expected `u8`, found `bool`
+ |
+ = note: expected struct `A<u8>`
+ found struct `A<bool>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
+++ /dev/null
-// run-pass
-// ignore-emscripten no processes
-// ignore-sgx no processes
-// ignore-windows
-
-use std::env;
-use std::process::Command;
-
-pub fn main() {
- let args: Vec<String> = env::args().collect();
- if args.len() >= 2 && args[1] == "signal" {
- // Raise a segfault.
- unsafe { *(1 as *mut isize) = 0; }
- } else {
- let status = Command::new(&args[0]).arg("signal").status().unwrap();
- assert!(status.code().is_none());
- }
-}
let _: u64 = simd_bitmask(m64);
let _: u16 = simd_bitmask(m2);
- //~^ ERROR bitmask `u16`, expected `u8`
+ //~^ ERROR invalid monomorphization of `simd_bitmask` intrinsic
let _: u16 = simd_bitmask(m8);
- //~^ ERROR bitmask `u16`, expected `u8`
+ //~^ ERROR invalid monomorphization of `simd_bitmask` intrinsic
let _: u32 = simd_bitmask(m16);
- //~^ ERROR bitmask `u32`, expected `u16`
+ //~^ ERROR invalid monomorphization of `simd_bitmask` intrinsic
let _: u64 = simd_bitmask(m32);
- //~^ ERROR bitmask `u64`, expected `u32`
+ //~^ ERROR invalid monomorphization of `simd_bitmask` intrinsic
let _: u128 = simd_bitmask(m64);
- //~^ ERROR bitmask `u128`, expected `u64`
+ //~^ ERROR invalid monomorphization of `simd_bitmask` intrinsic
}
}
-error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: bitmask `u16`, expected `u8`
+error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: cannot return `u16`, expected `u8` or `[u8; 1]`
--> $DIR/generic-bitmask.rs:53:22
|
LL | let _: u16 = simd_bitmask(m2);
| ^^^^^^^^^^^^^^^^
-error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: bitmask `u16`, expected `u8`
+error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: cannot return `u16`, expected `u8` or `[u8; 1]`
--> $DIR/generic-bitmask.rs:56:22
|
LL | let _: u16 = simd_bitmask(m8);
| ^^^^^^^^^^^^^^^^
-error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: bitmask `u32`, expected `u16`
+error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: cannot return `u32`, expected `u16` or `[u8; 2]`
--> $DIR/generic-bitmask.rs:59:22
|
LL | let _: u32 = simd_bitmask(m16);
| ^^^^^^^^^^^^^^^^^
-error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: bitmask `u64`, expected `u32`
+error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: cannot return `u64`, expected `u32` or `[u8; 4]`
--> $DIR/generic-bitmask.rs:62:22
|
LL | let _: u64 = simd_bitmask(m32);
| ^^^^^^^^^^^^^^^^^
-error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: bitmask `u128`, expected `u64`
+error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: cannot return `u128`, expected `u64` or `[u8; 8]`
--> $DIR/generic-bitmask.rs:65:23
|
LL | let _: u128 = simd_bitmask(m64);
#[repr(simd)]
#[derive(Copy, Clone, PartialEq)]
-struct b8x8(pub i8, pub i8, pub i8, pub i8,
- pub i8, pub i8, pub i8, pub i8);
+struct b8x8(pub i8, pub i8, pub i8, pub i8, pub i8, pub i8, pub i8, pub i8);
extern "platform-intrinsic" {
fn simd_select<T, U>(x: T, a: U, b: U) -> U;
//~^ ERROR found non-SIMD `u32`
simd_select_bitmask(0u16, x, x);
- //~^ ERROR mask length `16` != other vector length `4`
- //
+ //~^ ERROR invalid bitmask `u16`, expected `u8` or `[u8; 1]`
+
simd_select_bitmask(0u8, 1u32, 2u32);
//~^ ERROR found non-SIMD `u32`
simd_select_bitmask(0.0f32, x, x);
- //~^ ERROR `f32` is not an integral type
+ //~^ ERROR invalid bitmask `f32`, expected `u8` or `[u8; 1]`
simd_select_bitmask("x", x, x);
- //~^ ERROR `&str` is not an integral type
+ //~^ ERROR invalid bitmask `&str`, expected `u8` or `[u8; 1]`
}
}
error[E0511]: invalid monomorphization of `simd_select` intrinsic: mismatched lengths: mask length `8` != other vector length `4`
- --> $DIR/generic-select.rs:40:9
+ --> $DIR/generic-select.rs:39:9
|
LL | simd_select(m8, x, x);
| ^^^^^^^^^^^^^^^^^^^^^
error[E0511]: invalid monomorphization of `simd_select` intrinsic: mask element type is `u32`, expected `i_`
- --> $DIR/generic-select.rs:43:9
+ --> $DIR/generic-select.rs:42:9
|
LL | simd_select(x, x, x);
| ^^^^^^^^^^^^^^^^^^^^
error[E0511]: invalid monomorphization of `simd_select` intrinsic: mask element type is `f32`, expected `i_`
- --> $DIR/generic-select.rs:46:9
+ --> $DIR/generic-select.rs:45:9
|
LL | simd_select(z, z, z);
| ^^^^^^^^^^^^^^^^^^^^
error[E0511]: invalid monomorphization of `simd_select` intrinsic: expected SIMD argument type, found non-SIMD `u32`
- --> $DIR/generic-select.rs:49:9
+ --> $DIR/generic-select.rs:48:9
|
LL | simd_select(m4, 0u32, 1u32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: mismatched lengths: mask length `16` != other vector length `4`
- --> $DIR/generic-select.rs:52:9
+error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: invalid bitmask `u16`, expected `u8` or `[u8; 1]`
+ --> $DIR/generic-select.rs:51:9
|
LL | simd_select_bitmask(0u16, x, x);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: expected SIMD argument type, found non-SIMD `u32`
- --> $DIR/generic-select.rs:55:9
+ --> $DIR/generic-select.rs:54:9
|
LL | simd_select_bitmask(0u8, 1u32, 2u32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: `f32` is not an integral type
- --> $DIR/generic-select.rs:58:9
+error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: invalid bitmask `f32`, expected `u8` or `[u8; 1]`
+ --> $DIR/generic-select.rs:57:9
|
LL | simd_select_bitmask(0.0f32, x, x);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: `&str` is not an integral type
- --> $DIR/generic-select.rs:61:9
+error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: invalid bitmask `&str`, expected `u8` or `[u8; 1]`
+ --> $DIR/generic-select.rs:60:9
|
LL | simd_select_bitmask("x", x, x);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
--- /dev/null
+#![crate_type = "rlib"]
+#![no_std]
+#![feature(portable_simd)]
+use core::simd::f32x4;
+
+// For SIMD float ops, the LLIR version which is used to implement the portable
+// forms of them may become calls to math.h AKA libm. So, we can't guarantee
+// we can compile them for #![no_std] crates.
+// Someday we may solve this.
+// Until then, this test at least guarantees these functions require std.
+fn guarantee_no_std_nolibm_calls() -> f32x4 {
+ let x = f32x4::from_array([0.1, 0.5, 0.6, -1.5]);
+ let x2 = x + x;
+ let _xc = x.ceil(); //~ ERROR E0599
+ let _xf = x.floor(); //~ ERROR E0599
+ let _xr = x.round(); //~ ERROR E0599
+ let _xt = x.trunc(); //~ ERROR E0599
+ let _xfma = x.mul_add(x, x); //~ ERROR E0599
+ let _xsqrt = x.sqrt(); //~ ERROR E0599
+ x2.abs() * x2
+}
--- /dev/null
+error[E0599]: no method named `ceil` found for struct `Simd` in the current scope
+ --> $DIR/libm_no_std_cant_float.rs:14:17
+ |
+LL | let _xc = x.ceil();
+ | ^^^^ method not found in `Simd<f32, 4_usize>`
+
+error[E0599]: no method named `floor` found for struct `Simd` in the current scope
+ --> $DIR/libm_no_std_cant_float.rs:15:17
+ |
+LL | let _xf = x.floor();
+ | ^^^^^ method not found in `Simd<f32, 4_usize>`
+
+error[E0599]: no method named `round` found for struct `Simd` in the current scope
+ --> $DIR/libm_no_std_cant_float.rs:16:17
+ |
+LL | let _xr = x.round();
+ | ^^^^^ method not found in `Simd<f32, 4_usize>`
+
+error[E0599]: no method named `trunc` found for struct `Simd` in the current scope
+ --> $DIR/libm_no_std_cant_float.rs:17:17
+ |
+LL | let _xt = x.trunc();
+ | ^^^^^ method not found in `Simd<f32, 4_usize>`
+
+error[E0599]: no method named `mul_add` found for struct `Simd` in the current scope
+ --> $DIR/libm_no_std_cant_float.rs:18:19
+ |
+LL | let _xfma = x.mul_add(x, x);
+ | ^^^^^^^ method not found in `Simd<f32, 4_usize>`
+
+error[E0599]: no method named `sqrt` found for struct `Simd` in the current scope
+ --> $DIR/libm_no_std_cant_float.rs:19:20
+ |
+LL | let _xsqrt = x.sqrt();
+ | ^^^^ method not found in `Simd<f32, 4_usize>`
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
--- /dev/null
+// May not matter, since people can use them with a nightly feature.
+// However this tests to guarantee they don't leak out via portable_simd,
+// and thus don't accidentally get stabilized.
+use std::simd::intrinsics; //~ERROR E0603
+
+fn main() {
+ ()
+}
--- /dev/null
+error[E0603]: module `intrinsics` is private
+ --> $DIR/portable-intrinsics-arent-exposed.rs:4:16
+ |
+LL | use std::simd::intrinsics;
+ | ^^^^^^^^^^ private module
+ |
+note: the module `intrinsics` is defined here
+ --> $SRC_DIR/core/src/lib.rs:LL:COL
+ |
+LL | pub use crate::core_simd::simd::*;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0603`.
--- /dev/null
+//run-pass
+//ignore-endian-big behavior of simd_select_bitmask is endian-specific
+#![feature(repr_simd, platform_intrinsics)]
+
+extern "platform-intrinsic" {
+ fn simd_bitmask<T, U>(v: T) -> U;
+ fn simd_select_bitmask<T, U>(m: T, a: U, b: U) -> U;
+}
+
+#[derive(Copy, Clone)]
+#[repr(simd)]
+struct Simd<T, const N: usize>([T; N]);
+
+fn main() {
+ unsafe {
+ let v = Simd::<i8, 4>([-1, 0, -1, 0]);
+ let i: u8 = simd_bitmask(v);
+ let a: [u8; 1] = simd_bitmask(v);
+
+ assert_eq!(i, 0b0101);
+ assert_eq!(a, [0b0101]);
+
+ let v = Simd::<i8, 16>([0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0]);
+ let i: u16 = simd_bitmask(v);
+ let a: [u8; 2] = simd_bitmask(v);
+
+ assert_eq!(i, 0b0101000000001100);
+ assert_eq!(a, [0b1100, 0b01010000]);
+ }
+
+ unsafe {
+ let a = Simd::<i32, 8>([0, 1, 2, 3, 4, 5, 6, 7]);
+ let b = Simd::<i32, 8>([8, 9, 10, 11, 12, 13, 14, 15]);
+ let e = [0, 9, 2, 11, 12, 13, 14, 15];
+
+ let r = simd_select_bitmask(0b0101u8, a, b);
+ assert_eq!(r.0, e);
+
+ let r = simd_select_bitmask([0b0101u8], a, b);
+ assert_eq!(r.0, e);
+
+ let a = Simd::<i32, 16>([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
+ let b = Simd::<i32, 16>([16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]);
+ let e = [16, 17, 2, 3, 20, 21, 22, 23, 24, 25, 26, 27, 12, 29, 14, 31];
+
+ let r = simd_select_bitmask(0b0101000000001100u16, a, b);
+ assert_eq!(r.0, e);
+
+ let r = simd_select_bitmask([0b1100u8, 0b01010000u8], a, b);
+ assert_eq!(r.0, e);
+ }
+}
--- /dev/null
+// run-pass
+
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
+
+trait Specializable { type Output; }
+
+impl<T> Specializable for T {
+ default type Output = u16;
+}
+
+fn main() {
+ unsafe {
+ std::mem::transmute::<u16, <() as Specializable>::Output>(0);
+ }
+}
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/transmute-specialization.rs:3:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+ = help: consider using `min_specialization` instead, which is more stable and complete
+
+warning: 1 warning emitted
+
#![feature(staged_api)]
+//~^ ERROR module has missing stability attribute
-#[stable(feature = "x", since = "1")]
+#[stable(feature = "a", since = "1")]
struct StableType;
-#[unstable(feature = "x", issue = "none")]
+#[unstable(feature = "b", issue = "none")]
struct UnstableType;
-#[stable(feature = "x", since = "1")]
+#[stable(feature = "c", since = "1")]
trait StableTrait {}
-#[unstable(feature = "x", issue = "none")]
+#[unstable(feature = "d", issue = "none")]
trait UnstableTrait {}
-#[unstable(feature = "x", issue = "none")]
+#[unstable(feature = "e", issue = "none")]
impl UnstableTrait for UnstableType {}
-#[unstable(feature = "x", issue = "none")]
+#[unstable(feature = "f", issue = "none")]
impl StableTrait for UnstableType {}
-#[unstable(feature = "x", issue = "none")]
+#[unstable(feature = "g", issue = "none")]
impl UnstableTrait for StableType {}
-#[unstable(feature = "x", issue = "none")]
+#[unstable(feature = "h", issue = "none")]
//~^ ERROR an `#[unstable]` annotation here has no effect [ineffective_unstable_trait_impl]
impl StableTrait for StableType {}
error: an `#[unstable]` annotation here has no effect
- --> $DIR/stability-attribute-trait-impl.rs:24:1
+ --> $DIR/stability-attribute-trait-impl.rs:25:1
|
-LL | #[unstable(feature = "x", issue = "none")]
+LL | #[unstable(feature = "h", issue = "none")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[deny(ineffective_unstable_trait_impl)]` on by default
= note: see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information
-error: aborting due to previous error
+error: module has missing stability attribute
+ --> $DIR/stability-attribute-trait-impl.rs:1:1
+ |
+LL | / #![feature(staged_api)]
+LL | |
+LL | |
+LL | | #[stable(feature = "a", since = "1")]
+... |
+LL | |
+LL | | fn main() {}
+ | |____________^
+
+error: aborting due to 2 previous errors
--- /dev/null
+// original problem
+pub fn foo<T>() -> isize {
+ {
+ static foo: isize = 2;
+ foo
+ }
+}
+
+// issue 8134
+struct Foo;
+impl Foo {
+ pub fn foo<T>(&self) {
+ static X: usize = 1;
+ }
+}
+
+// issue 8134
+pub struct Parser<T>(T);
+impl<T: std::iter::Iterator<Item=char>> Parser<T> {
+ fn in_doctype(&mut self) {
+ static DOCTYPEPattern: [char; 6] = ['O', 'C', 'T', 'Y', 'P', 'E'];
+ }
+}
+
+struct Bar;
+impl Foo {
+ pub fn bar<T>(&self) {
+ static X: usize = 1;
+ }
+}
--- /dev/null
+// run-pass
+// aux-build:nested_item.rs
+
+
+extern crate nested_item;
+
+pub fn main() {
+ assert_eq!(2, nested_item::foo::<()>());
+ assert_eq!(2, nested_item::foo::<isize>());
+}
--- /dev/null
+error[E0133]: use of extern static is unsafe and requires unsafe function or block
+ --> $DIR/issue-14227.rs:7:21
+ |
+LL | static CRASH: u32 = symbol;
+ | ^^^^^^ use of extern static
+ |
+ = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
--- /dev/null
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
+extern "C" {
+ pub static symbol: u32;
+}
+static CRASH: u32 = symbol;
+//~^ ERROR use of extern static is unsafe and requires
+
+fn main() {}
--- /dev/null
+error[E0133]: use of extern static is unsafe and requires unsafe function or block
+ --> $DIR/issue-14227.rs:7:21
+ |
+LL | static CRASH: u32 = symbol;
+ | ^^^^^^ use of extern static
+ |
+ = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
static VOID2: Void = unsafe { std::mem::transmute(()) }; //~ ERROR static of uninhabited type
//~| WARN: previously accepted
+//~| ERROR undefined behavior to use this value
+//~| WARN: type `Void` does not permit zero-initialization
static NEVER2: Void = unsafe { std::mem::transmute(()) }; //~ ERROR static of uninhabited type
//~| WARN: previously accepted
+//~| ERROR undefined behavior to use this value
+//~| WARN: type `Void` does not permit zero-initialization
fn main() {}
= note: uninhabited statics cannot be initialized, and any access would be an immediate error
error: static of uninhabited type
- --> $DIR/uninhabited-static.rs:14:1
+ --> $DIR/uninhabited-static.rs:16:1
|
LL | static NEVER2: Void = unsafe { std::mem::transmute(()) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: for more information, see issue #74840 <https://github.com/rust-lang/rust/issues/74840>
= note: uninhabited statics cannot be initialized, and any access would be an immediate error
-error: aborting due to 4 previous errors
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/uninhabited-static.rs:12:1
+ |
+LL | static VOID2: Void = unsafe { std::mem::transmute(()) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Void
+ |
+ = 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: 0, align: 1) {}
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/uninhabited-static.rs:16:1
+ |
+LL | static NEVER2: Void = unsafe { std::mem::transmute(()) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Void
+ |
+ = 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: 0, align: 1) {}
+
+warning: the type `Void` does not permit zero-initialization
+ --> $DIR/uninhabited-static.rs:12:31
+ |
+LL | static VOID2: Void = unsafe { std::mem::transmute(()) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | this code causes undefined behavior when executed
+ | help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+ |
+ = note: `#[warn(invalid_value)]` on by default
+ = note: enums with no variants have no valid value
+
+warning: the type `Void` does not permit zero-initialization
+ --> $DIR/uninhabited-static.rs:16:32
+ |
+LL | static NEVER2: Void = unsafe { std::mem::transmute(()) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | this code causes undefined behavior when executed
+ | help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+ |
+ = note: enums with no variants have no valid value
+
+error: aborting due to 6 previous errors; 2 warnings emitted
+For more information about this error, try `rustc --explain E0080`.
--- /dev/null
+// run-pass
+enum Void {}
+fn foo(_: Result<(Void, u32), (Void, String)>) {}
+fn main() {
+ let _: fn(_) = foo;
+}
target_os = "emscripten",
target_os = "freebsd",
target_os = "fuchsia",
+ target_os = "illumos",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
+++ /dev/null
-// run-pass
-
-#![allow(non_camel_case_types)]
-
-
-#[derive(Copy, Clone, Debug)]
-enum foo { large, small, }
-
-impl PartialEq for foo {
- fn eq(&self, other: &foo) -> bool {
- ((*self) as usize) == ((*other) as usize)
- }
- fn ne(&self, other: &foo) -> bool { !(*self).eq(other) }
-}
-
-pub fn main() {
- let a = (1, 2, 3);
- let b = (1, 2, 3);
- assert_eq!(a, b);
- assert!((a != (1, 2, 4)));
- assert!((a < (1, 2, 4)));
- assert!((a <= (1, 2, 4)));
- assert!(((1, 2, 4) > a));
- assert!(((1, 2, 4) >= a));
- let x = foo::large;
- let y = foo::small;
- assert!((x != y));
- assert_eq!(x, foo::large);
- assert!((x != foo::small));
-}
--- /dev/null
+enum Ty {
+ Unit,
+ List(Box<Ty>),
+}
+
+fn foo(x: Ty) -> Ty {
+ match x {
+ Ty::Unit => Ty::Unit,
+ Ty::List(elem) => foo(elem),
+ //~^ ERROR mismatched types
+ //~| HELP try dereferencing the `Box`
+ //~| HELP try using a variant of the expected enum
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/boxed-variant-field.rs:9:31
+ |
+LL | Ty::List(elem) => foo(elem),
+ | ^^^^ expected enum `Ty`, found struct `Box`
+ |
+ = note: expected enum `Ty`
+ found struct `Box<Ty>`
+help: try dereferencing the `Box`
+ |
+LL | Ty::List(elem) => foo(*elem),
+ | +
+help: try using a variant of the expected enum
+ |
+LL | Ty::List(elem) => foo(Ty::List(elem)),
+ | ~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
LL | let _: &[i8] = data.into();
| ^^^^ the trait `From<&[u8]>` is not implemented for `&[i8]`
|
+ = help: the following implementations were found:
+ <[T; LANES] as From<Simd<T, LANES>>>
+ <[bool; LANES] as From<Mask<T, LANES>>>
= note: required because of the requirements on the impl of `Into<&[i8]>` for `&[u8]`
error: aborting due to previous error
+++ /dev/null
-// run-pass
-
-pub fn main() {
- let f = 1_usize as *const String;
- println!("{:?}", f as isize);
- println!("{:?}", f as usize);
- println!("{:?}", f as i8);
- println!("{:?}", f as i16);
- println!("{:?}", f as i32);
- println!("{:?}", f as i64);
- println!("{:?}", f as u8);
- println!("{:?}", f as u16);
- println!("{:?}", f as u32);
- println!("{:?}", f as u64);
-
- println!("{:?}", 1 as isize);
- println!("{:?}", 1 as usize);
- println!("{:?}", 1 as *const String);
- println!("{:?}", 1 as i8);
- println!("{:?}", 1 as i16);
- println!("{:?}", 1 as i32);
- println!("{:?}", 1 as i64);
- println!("{:?}", 1 as u8);
- println!("{:?}", 1 as u16);
- println!("{:?}", 1 as u32);
- println!("{:?}", 1 as u64);
- println!("{:?}", 1 as f32);
- println!("{:?}", 1 as f64);
-
- println!("{:?}", 1_usize as isize);
- println!("{:?}", 1_usize as usize);
- println!("{:?}", 1_usize as *const String);
- println!("{:?}", 1_usize as i8);
- println!("{:?}", 1_usize as i16);
- println!("{:?}", 1_usize as i32);
- println!("{:?}", 1_usize as i64);
- println!("{:?}", 1_usize as u8);
- println!("{:?}", 1_usize as u16);
- println!("{:?}", 1_usize as u32);
- println!("{:?}", 1_usize as u64);
- println!("{:?}", 1_usize as f32);
- println!("{:?}", 1_usize as f64);
-
- println!("{:?}", 1i8 as isize);
- println!("{:?}", 1i8 as usize);
- println!("{:?}", 1i8 as *const String);
- println!("{:?}", 1i8 as i8);
- println!("{:?}", 1i8 as i16);
- println!("{:?}", 1i8 as i32);
- println!("{:?}", 1i8 as i64);
- println!("{:?}", 1i8 as u8);
- println!("{:?}", 1i8 as u16);
- println!("{:?}", 1i8 as u32);
- println!("{:?}", 1i8 as u64);
- println!("{:?}", 1i8 as f32);
- println!("{:?}", 1i8 as f64);
-
- println!("{:?}", 1u8 as isize);
- println!("{:?}", 1u8 as usize);
- println!("{:?}", 1u8 as *const String);
- println!("{:?}", 1u8 as i8);
- println!("{:?}", 1u8 as i16);
- println!("{:?}", 1u8 as i32);
- println!("{:?}", 1u8 as i64);
- println!("{:?}", 1u8 as u8);
- println!("{:?}", 1u8 as u16);
- println!("{:?}", 1u8 as u32);
- println!("{:?}", 1u8 as u64);
- println!("{:?}", 1u8 as f32);
- println!("{:?}", 1u8 as f64);
-
- println!("{:?}", 1i16 as isize);
- println!("{:?}", 1i16 as usize);
- println!("{:?}", 1i16 as *const String);
- println!("{:?}", 1i16 as i8);
- println!("{:?}", 1i16 as i16);
- println!("{:?}", 1i16 as i32);
- println!("{:?}", 1i16 as i64);
- println!("{:?}", 1i16 as u8);
- println!("{:?}", 1i16 as u16);
- println!("{:?}", 1i16 as u32);
- println!("{:?}", 1i16 as u64);
- println!("{:?}", 1i16 as f32);
- println!("{:?}", 1i16 as f64);
-
- println!("{:?}", 1u16 as isize);
- println!("{:?}", 1u16 as usize);
- println!("{:?}", 1u16 as *const String);
- println!("{:?}", 1u16 as i8);
- println!("{:?}", 1u16 as i16);
- println!("{:?}", 1u16 as i32);
- println!("{:?}", 1u16 as i64);
- println!("{:?}", 1u16 as u8);
- println!("{:?}", 1u16 as u16);
- println!("{:?}", 1u16 as u32);
- println!("{:?}", 1u16 as u64);
- println!("{:?}", 1u16 as f32);
- println!("{:?}", 1u16 as f64);
-
- println!("{:?}", 1i32 as isize);
- println!("{:?}", 1i32 as usize);
- println!("{:?}", 1i32 as *const String);
- println!("{:?}", 1i32 as i8);
- println!("{:?}", 1i32 as i16);
- println!("{:?}", 1i32 as i32);
- println!("{:?}", 1i32 as i64);
- println!("{:?}", 1i32 as u8);
- println!("{:?}", 1i32 as u16);
- println!("{:?}", 1i32 as u32);
- println!("{:?}", 1i32 as u64);
- println!("{:?}", 1i32 as f32);
- println!("{:?}", 1i32 as f64);
-
- println!("{:?}", 1u32 as isize);
- println!("{:?}", 1u32 as usize);
- println!("{:?}", 1u32 as *const String);
- println!("{:?}", 1u32 as i8);
- println!("{:?}", 1u32 as i16);
- println!("{:?}", 1u32 as i32);
- println!("{:?}", 1u32 as i64);
- println!("{:?}", 1u32 as u8);
- println!("{:?}", 1u32 as u16);
- println!("{:?}", 1u32 as u32);
- println!("{:?}", 1u32 as u64);
- println!("{:?}", 1u32 as f32);
- println!("{:?}", 1u32 as f64);
-
- println!("{:?}", 1i64 as isize);
- println!("{:?}", 1i64 as usize);
- println!("{:?}", 1i64 as *const String);
- println!("{:?}", 1i64 as i8);
- println!("{:?}", 1i64 as i16);
- println!("{:?}", 1i64 as i32);
- println!("{:?}", 1i64 as i64);
- println!("{:?}", 1i64 as u8);
- println!("{:?}", 1i64 as u16);
- println!("{:?}", 1i64 as u32);
- println!("{:?}", 1i64 as u64);
- println!("{:?}", 1i64 as f32);
- println!("{:?}", 1i64 as f64);
-
- println!("{:?}", 1u64 as isize);
- println!("{:?}", 1u64 as usize);
- println!("{:?}", 1u64 as *const String);
- println!("{:?}", 1u64 as i8);
- println!("{:?}", 1u64 as i16);
- println!("{:?}", 1u64 as i32);
- println!("{:?}", 1u64 as i64);
- println!("{:?}", 1u64 as u8);
- println!("{:?}", 1u64 as u16);
- println!("{:?}", 1u64 as u32);
- println!("{:?}", 1u64 as u64);
- println!("{:?}", 1u64 as f32);
- println!("{:?}", 1u64 as f64);
-
- println!("{:?}", 1u64 as isize);
- println!("{:?}", 1u64 as usize);
- println!("{:?}", 1u64 as *const String);
- println!("{:?}", 1u64 as i8);
- println!("{:?}", 1u64 as i16);
- println!("{:?}", 1u64 as i32);
- println!("{:?}", 1u64 as i64);
- println!("{:?}", 1u64 as u8);
- println!("{:?}", 1u64 as u16);
- println!("{:?}", 1u64 as u32);
- println!("{:?}", 1u64 as u64);
- println!("{:?}", 1u64 as f32);
- println!("{:?}", 1u64 as f64);
-
- println!("{:?}", true as isize);
- println!("{:?}", true as usize);
- println!("{:?}", true as i8);
- println!("{:?}", true as i16);
- println!("{:?}", true as i32);
- println!("{:?}", true as i64);
- println!("{:?}", true as u8);
- println!("{:?}", true as u16);
- println!("{:?}", true as u32);
- println!("{:?}", true as u64);
-
- println!("{:?}", 1f32 as isize);
- println!("{:?}", 1f32 as usize);
- println!("{:?}", 1f32 as i8);
- println!("{:?}", 1f32 as i16);
- println!("{:?}", 1f32 as i32);
- println!("{:?}", 1f32 as i64);
- println!("{:?}", 1f32 as u8);
- println!("{:?}", 1f32 as u16);
- println!("{:?}", 1f32 as u32);
- println!("{:?}", 1f32 as u64);
- println!("{:?}", 1f32 as f32);
- println!("{:?}", 1f32 as f64);
-
- println!("{:?}", 1f64 as isize);
- println!("{:?}", 1f64 as usize);
- println!("{:?}", 1f64 as i8);
- println!("{:?}", 1f64 as i16);
- println!("{:?}", 1f64 as i32);
- println!("{:?}", 1f64 as i64);
- println!("{:?}", 1f64 as u8);
- println!("{:?}", 1f64 as u16);
- println!("{:?}", 1f64 as u32);
- println!("{:?}", 1f64 as u64);
- println!("{:?}", 1f64 as f32);
- println!("{:?}", 1f64 as f64);
-}
--- /dev/null
+#![crate_name = "a"]
+
+pub fn foo<T>() {}
--- /dev/null
+#![crate_name = "a"]
+
+pub fn foo<T>() { println!("hello!"); }
--- /dev/null
+#![crate_name = "b"]
+
+extern crate a;
+
+pub fn foo() { a::foo::<isize>(); }
--- /dev/null
+// ignore-msvc FIXME #31306
+
+// note that these aux-build directives must be in this order
+// aux-build:changing-crates-a1.rs
+// aux-build:changing-crates-b.rs
+// aux-build:changing-crates-a2.rs
+// normalize-stderr-test: "(crate `(\w+)`:) .*" -> "$1 $$PATH_$2"
+
+extern crate a;
+extern crate b; //~ ERROR: found possibly newer version of crate `a` which `b` depends on
+
+fn main() {}
--- /dev/null
+error[E0460]: found possibly newer version of crate `a` which `b` depends on
+ --> $DIR/changing-crates.rs:10:1
+ |
+LL | extern crate b;
+ | ^^^^^^^^^^^^^^^
+ |
+ = note: perhaps that crate needs to be recompiled?
+ = note: the following crate versions were found:
+ crate `a`: $PATH_a
+ crate `b`: $PATH_b
+
+error: aborting due to previous error
+
+++ /dev/null
-#![feature(negative_impls)]
-
-use std::marker::Send;
-
-struct TestType;
-
-impl !TestType {}
-//~^ ERROR inherent impls cannot be negative
-
-trait TestTrait {}
-
-unsafe impl !Send for TestType {}
-//~^ ERROR negative impls cannot be unsafe
-impl !TestTrait for TestType {}
-
-struct TestType2<T>(T);
-
-impl<T> !TestType2<T> {}
-//~^ ERROR inherent impls cannot be negative
-
-unsafe impl<T> !Send for TestType2<T> {}
-//~^ ERROR negative impls cannot be unsafe
-impl<T> !TestTrait for TestType2<T> {}
-
-fn main() {}
+++ /dev/null
-error: inherent impls cannot be negative
- --> $DIR/syntax-trait-polarity.rs:7:7
- |
-LL | impl !TestType {}
- | -^^^^^^^^ inherent impl for this type
- | |
- | negative because of this
-
-error[E0198]: negative impls cannot be unsafe
- --> $DIR/syntax-trait-polarity.rs:12:13
- |
-LL | unsafe impl !Send for TestType {}
- | ------ -^^^^
- | | |
- | | negative because of this
- | unsafe because of this
-
-error: inherent impls cannot be negative
- --> $DIR/syntax-trait-polarity.rs:18:10
- |
-LL | impl<T> !TestType2<T> {}
- | -^^^^^^^^^^^^ inherent impl for this type
- | |
- | negative because of this
-
-error[E0198]: negative impls cannot be unsafe
- --> $DIR/syntax-trait-polarity.rs:21:16
- |
-LL | unsafe impl<T> !Send for TestType2<T> {}
- | ------ -^^^^
- | | |
- | | negative because of this
- | unsafe because of this
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0198`.
|
LL | func::<u8>(42);
| ^^ explicit generic argument not allowed
+ |
+ = note: see issue #83701 <https://github.com/rust-lang/rust/issues/83701> for more information
+ = help: add `#![feature(explicit_generic_args_with_impl_trait)]` to the crate attributes to enable
error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position
--> $DIR/synthetic-param.rs:23:17
|
LL | Foo::func::<u8>(42);
| ^^ explicit generic argument not allowed
+ |
+ = note: see issue #83701 <https://github.com/rust-lang/rust/issues/83701> for more information
+ = help: add `#![feature(explicit_generic_args_with_impl_trait)]` to the crate attributes to enable
error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position
--> $DIR/synthetic-param.rs:26:23
|
LL | Bar::<i8>::func::<u8>(42);
| ^^ explicit generic argument not allowed
+ |
+ = note: see issue #83701 <https://github.com/rust-lang/rust/issues/83701> for more information
+ = help: add `#![feature(explicit_generic_args_with_impl_trait)]` to the crate attributes to enable
error: aborting due to 3 previous errors
+++ /dev/null
-// run-pass
-// ignore-emscripten no threads support
-
-// Issue #787
-// Don't try to clean up uninitialized locals
-
-
-use std::thread;
-
-fn test_break() { loop { let _x: Box<isize> = break; } }
-
-fn test_cont() { let mut i = 0; while i < 1 { i += 1; let _x: Box<isize> = continue; } }
-
-fn test_ret() { let _x: Box<isize> = return; }
-
-fn test_panic() {
- fn f() { let _x: Box<isize> = panic!(); }
- thread::spawn(move|| f() ).join().unwrap_err();
-}
-
-fn test_panic_indirect() {
- fn f() -> ! { panic!(); }
- fn g() { let _x: Box<isize> = f(); }
- thread::spawn(move|| g() ).join().unwrap_err();
-}
-
-pub fn main() {
- test_break();
- test_cont();
- test_ret();
- test_panic();
- test_panic_indirect();
-}
|
= note: expected struct `Foo`
found struct `Box<Foo>`
+help: try dereferencing the `Box`
+ |
+LL | want_foo(*b);
+ | +
error: aborting due to previous error
--- /dev/null
+// run-pass
+// compile-flags: --test
+
+#[test]
+pub fn foo() {}
+++ /dev/null
-// run-pass
-// compile-flags: -Z thinlto -C codegen-units=2
-
-#[global_allocator]
-static A: std::alloc::System = std::alloc::System;
-
-fn main() {}
+++ /dev/null
-// run-pass
-
-// compile-flags: -Clto=thin
-// no-prefer-dynamic
-
-fn main() {
- println!("hello!");
-}
+++ /dev/null
-// compile-flags: -Z thinlto -C codegen-units=8
-
-#[inline]
-pub fn foo(b: u8) {
- b.to_string();
-}
+++ /dev/null
-// no-prefer-dynamic
-// compile-flags: -Z thinlto -C codegen-units=8 -C prefer-dynamic
-
-#![crate_type = "rlib"]
-#![crate_type = "dylib"]
-
-pub static A: u32 = 43;
-
-pub mod a {
- pub static A: u32 = 43;
-}
+++ /dev/null
-// no-prefer-dynamic
-
-#![crate_type = "rlib"]
-
-pub fn bar() -> u32 {
- 3
-}
+++ /dev/null
-// run-pass
-
-// aux-build:dylib.rs
-
-extern crate dylib;
-
-fn main() {
- dylib::foo(1);
-}
+++ /dev/null
-// run-pass
-
-// aux-build:msvc-imp-present.rs
-// compile-flags: -Z thinlto -C codegen-units=8
-// no-prefer-dynamic
-
-// On MSVC we have a "hack" where we emit symbols that look like `_imp_$name`
-// for all exported statics. This is done because we apply `dllimport` to all
-// imported constants and this allows everything to actually link correctly.
-//
-// The ThinLTO passes aggressively remove symbols if they can, and this test
-// asserts that the ThinLTO passes don't remove these compiler-generated
-// `_imp_*` symbols. The external library that we link in here is compiled with
-// ThinLTO and multiple codegen units and has a few exported constants. Note
-// that we also namely compile the library as both a dylib and an rlib, but we
-// link the rlib to ensure that we assert those generated symbols exist.
-
-extern crate msvc_imp_present as bar;
-
-fn main() {
- println!("{}", bar::A);
-}
+++ /dev/null
-// run-pass
-
-// compile-flags: -Z thinlto -C codegen-units=8 -O
-// ignore-emscripten can't inspect instructions on emscripten
-
-// We want to assert here that ThinLTO will inline across codegen units. There's
-// not really a great way to do that in general so we sort of hack around it by
-// praying two functions go into separate codegen units and then assuming that
-// if inlining *doesn't* happen the first byte of the functions will differ.
-
-pub fn foo() -> u32 {
- bar::bar()
-}
-
-mod bar {
- pub fn bar() -> u32 {
- 3
- }
-}
-
-fn main() {
- println!("{} {}", foo(), bar::bar());
-
- unsafe {
- let foo = foo as usize as *const u8;
- let bar = bar::bar as usize as *const u8;
-
- assert_eq!(*foo, *bar);
- }
-}
+++ /dev/null
-// run-pass
-
-// compile-flags: -C codegen-units=8 -O -C lto=thin
-// aux-build:thin-lto-inlines-aux.rs
-// no-prefer-dynamic
-// ignore-emscripten can't inspect instructions on emscripten
-
-// We want to assert here that ThinLTO will inline across codegen units. There's
-// not really a great way to do that in general so we sort of hack around it by
-// praying two functions go into separate codegen units and then assuming that
-// if inlining *doesn't* happen the first byte of the functions will differ.
-
-extern crate thin_lto_inlines_aux as bar;
-
-pub fn foo() -> u32 {
- bar::bar()
-}
-
-fn main() {
- println!("{} {}", foo(), bar::bar());
-
- unsafe {
- let foo = foo as usize as *const u8;
- let bar = bar::bar as usize as *const u8;
-
- assert_eq!(*foo, *bar);
- }
-}
+++ /dev/null
-// run-pass
-
-// compile-flags: -C codegen-units=8 -Z thinlto
-// ignore-windows
-
-#![feature(linkage)]
-
-pub mod foo {
- #[linkage = "weak"]
- #[no_mangle]
- pub extern "C" fn FOO() -> i32 {
- 0
- }
-}
-
-mod bar {
- extern "C" {
- fn FOO() -> i32;
- }
-
- pub fn bar() -> i32 {
- unsafe { FOO() }
- }
-}
-
-fn main() {
- bar::bar();
-}
--- /dev/null
+// run-pass
+// ignore-emscripten no threads
+// ignore-sgx no processes
+
+use std::thread;
+use std::env;
+use std::process::Command;
+
+struct Handle(i32);
+
+impl Drop for Handle {
+ fn drop(&mut self) { panic!(); }
+}
+
+thread_local!(static HANDLE: Handle = Handle(0));
+
+fn main() {
+ let args = env::args().collect::<Vec<_>>();
+ if args.len() == 1 {
+ let out = Command::new(&args[0]).arg("test").output().unwrap();
+ let stderr = std::str::from_utf8(&out.stderr).unwrap();
+ assert!(stderr.contains("panicked at 'explicit panic'"),
+ "bad failure message:\n{}\n", stderr);
+ } else {
+ // TLS dtors are not always run on process exit
+ thread::spawn(|| {
+ HANDLE.with(|h| {
+ println!("{}", h.0);
+ });
+ }).join().unwrap();
+ }
+}
--- /dev/null
+// run-pass
+// ignore-emscripten no threads support
+
+use std::sync::mpsc::channel;
+use std::thread;
+
+pub fn main() {
+ let (tx, rx) = channel::<&'static str>();
+
+ let t = thread::spawn(move|| {
+ assert_eq!(rx.recv().unwrap(), "hello, world");
+ });
+
+ tx.send("hello, world").unwrap();
+ t.join().ok().unwrap();
+}
--- /dev/null
+// run-pass
+// ignore-emscripten no threads support
+
+use std::thread;
+use std::sync::mpsc::{channel, Receiver};
+
+fn periodical(n: isize) -> Receiver<bool> {
+ let (chan, port) = channel();
+ thread::spawn(move|| {
+ loop {
+ for _ in 1..n {
+ match chan.send(false) {
+ Ok(()) => {}
+ Err(..) => break,
+ }
+ }
+ match chan.send(true) {
+ Ok(()) => {}
+ Err(..) => break
+ }
+ }
+ });
+ return port;
+}
+
+fn integers() -> Receiver<isize> {
+ let (chan, port) = channel();
+ thread::spawn(move|| {
+ let mut i = 1;
+ loop {
+ match chan.send(i) {
+ Ok(()) => {}
+ Err(..) => break,
+ }
+ i = i + 1;
+ }
+ });
+ return port;
+}
+
+fn main() {
+ let ints = integers();
+ let threes = periodical(3);
+ let fives = periodical(5);
+ for _ in 1..100 {
+ match (ints.recv().unwrap(), threes.recv().unwrap(), fives.recv().unwrap()) {
+ (_, true, true) => println!("FizzBuzz"),
+ (_, true, false) => println!("Fizz"),
+ (_, false, true) => println!("Buzz"),
+ (i, false, false) => println!("{}", i)
+ }
+ }
+}
--- /dev/null
+// run-pass
+#![allow(unused_must_use)]
+#![allow(deprecated)]
+// ignore-emscripten no threads support
+
+use std::sync::mpsc::{TryRecvError, channel};
+use std::thread;
+
+pub fn main() {
+ let (tx, rx) = channel();
+ let t = thread::spawn(move||{
+ thread::sleep_ms(10);
+ tx.send(()).unwrap();
+ });
+ loop {
+ match rx.try_recv() {
+ Ok(()) => break,
+ Err(TryRecvError::Empty) => {}
+ Err(TryRecvError::Disconnected) => unreachable!()
+ }
+ }
+ t.join();
+}
--- /dev/null
+// run-pass
+
+#![allow(unused_must_use)]
+/*
+ This is about the simplest program that can successfully send a
+ message.
+ */
+
+use std::sync::mpsc::channel;
+
+pub fn main() {
+ let (tx, rx) = channel();
+ tx.send(42);
+ let r = rx.recv();
+ println!("{:?}", r);
+}
--- /dev/null
+// run-pass
+
+use std::thread;
+
+pub fn main() {
+ let mut i: isize = 0;
+ while i < 100 { i = i + 1; println!("{}", i); thread::yield_now(); }
+}
+++ /dev/null
-#![feature(trace_macros)]
-
-fn main() {
- trace_macros!(); //~ ERROR trace_macros! accepts only `true` or `false`
- trace_macros!(1); //~ ERROR trace_macros! accepts only `true` or `false`
- trace_macros!(ident); //~ ERROR trace_macros! accepts only `true` or `false`
- trace_macros!(for); //~ ERROR trace_macros! accepts only `true` or `false`
- trace_macros!(true,); //~ ERROR trace_macros! accepts only `true` or `false`
- trace_macros!(false 1); //~ ERROR trace_macros! accepts only `true` or `false`
-
-
- // should be fine:
- macro_rules! expando {
- ($x: ident) => { trace_macros!($x) }
- }
-
- expando!(true);
-}
+++ /dev/null
-error: trace_macros! accepts only `true` or `false`
- --> $DIR/trace_macros-format.rs:4:5
- |
-LL | trace_macros!();
- | ^^^^^^^^^^^^^^^
-
-error: trace_macros! accepts only `true` or `false`
- --> $DIR/trace_macros-format.rs:5:5
- |
-LL | trace_macros!(1);
- | ^^^^^^^^^^^^^^^^
-
-error: trace_macros! accepts only `true` or `false`
- --> $DIR/trace_macros-format.rs:6:5
- |
-LL | trace_macros!(ident);
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: trace_macros! accepts only `true` or `false`
- --> $DIR/trace_macros-format.rs:7:5
- |
-LL | trace_macros!(for);
- | ^^^^^^^^^^^^^^^^^^
-
-error: trace_macros! accepts only `true` or `false`
- --> $DIR/trace_macros-format.rs:8:5
- |
-LL | trace_macros!(true,);
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: trace_macros! accepts only `true` or `false`
- --> $DIR/trace_macros-format.rs:9:5
- |
-LL | trace_macros!(false 1);
- | ^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 6 previous errors
-
-error[E0119]: conflicting implementations of trait `AnotherTrait` for type `impl OpaqueTrait`
- --> $DIR/issue-83613.rs:10:1
- |
-LL | impl<T: Send> AnotherTrait for T {}
- | -------------------------------- first implementation here
-LL | impl AnotherTrait for OpaqueType {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `impl OpaqueTrait`
-
error: cannot implement trait on type alias impl trait
--> $DIR/issue-83613.rs:10:1
|
LL | type OpaqueType = impl OpaqueTrait;
| ^^^^^^^^^^^^^^^^
+error[E0119]: conflicting implementations of trait `AnotherTrait` for type `impl OpaqueTrait`
+ --> $DIR/issue-83613.rs:10:1
+ |
+LL | impl<T: Send> AnotherTrait for T {}
+ | -------------------------------- first implementation here
+LL | impl AnotherTrait for OpaqueType {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `impl OpaqueTrait`
+
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0119`.
--- /dev/null
+// run-pass
+
+trait Foo: Fn(i32) -> i32 + Send {}
+
+impl<T: ?Sized + Fn(i32) -> i32 + Send> Foo for T {}
+
+fn wants_foo(f: Box<dyn Foo>) -> i32 {
+ f(42)
+}
+
+fn main() {
+ let f = Box::new(|x| x);
+ assert_eq!(wants_foo(f), 42);
+}
--- /dev/null
+trait Q<T:?Sized> {}
+trait Foo where u32: Q<Self> {
+ fn foo(&self);
+}
+
+impl Q<()> for u32 {}
+impl Foo for () {
+ fn foo(&self) {
+ println!("foo!");
+ }
+}
+
+fn main() {
+ let _f: Box<dyn Foo> = //~ ERROR `Foo` cannot be made into an object
+ Box::new(()); //~ ERROR `Foo` cannot be made into an object
+}
--- /dev/null
+error[E0038]: the trait `Foo` cannot be made into an object
+ --> $DIR/issue-38604.rs:14:13
+ |
+LL | let _f: Box<dyn Foo> =
+ | ^^^^^^^^^^^^ `Foo` cannot be made into an object
+ |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+ --> $DIR/issue-38604.rs:2:22
+ |
+LL | trait Foo where u32: Q<Self> {
+ | --- ^^^^^^^ ...because it uses `Self` as a type parameter
+ | |
+ | this trait cannot be made into an object...
+
+error[E0038]: the trait `Foo` cannot be made into an object
+ --> $DIR/issue-38604.rs:15:9
+ |
+LL | Box::new(());
+ | ^^^^^^^^^^^^ `Foo` cannot be made into an object
+ |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+ --> $DIR/issue-38604.rs:2:22
+ |
+LL | trait Foo where u32: Q<Self> {
+ | --- ^^^^^^^ ...because it uses `Self` as a type parameter
+ | |
+ | this trait cannot be made into an object...
+ = note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn Foo>>` for `Box<()>`
+ = note: required by cast to type `Box<dyn Foo>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0038`.
--- /dev/null
+struct Point {
+ x: f64,
+ y: f64,
+}
+
+trait ToString_ {
+ fn to_string(&self) -> String;
+}
+
+impl ToString_ for Point {
+ fn new(x: f64, y: f64) -> Point {
+ //~^ ERROR method `new` is not a member of trait `ToString_`
+ Point { x: x, y: y }
+ }
+
+ fn to_string(&self) -> String {
+ format!("({}, {})", self.x, self.y)
+ }
+}
+
+fn main() {
+ let p = Point::new(0.0, 0.0);
+ //~^ ERROR no function or associated item named `new` found for struct `Point`
+ println!("{}", p.to_string());
+}
--- /dev/null
+error[E0407]: method `new` is not a member of trait `ToString_`
+ --> $DIR/issue-3973.rs:11:5
+ |
+LL | / fn new(x: f64, y: f64) -> Point {
+LL | |
+LL | | Point { x: x, y: y }
+LL | | }
+ | |_____^ not a member of trait `ToString_`
+
+error[E0599]: no function or associated item named `new` found for struct `Point` in the current scope
+ --> $DIR/issue-3973.rs:22:20
+ |
+LL | struct Point {
+ | ------------ function or associated item `new` not found for this
+...
+LL | let p = Point::new(0.0, 0.0);
+ | ^^^ function or associated item not found in `Point`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0407, E0599.
+For more information about an error, try `rustc --explain E0407`.
--- /dev/null
+#![feature(trait_alias)]
+
+trait Svc<Req> { type Res; }
+
+trait MkSvc<Target, Req> = Svc<Target> where Self::Res: Svc<Req>;
+//~^ ERROR associated type `Res` not found for `Self`
+//~| ERROR associated type `Res` not found for `Self`
+
+fn main() {}
--- /dev/null
+error[E0220]: associated type `Res` not found for `Self`
+ --> $DIR/issue-59029-1.rs:5:52
+ |
+LL | trait MkSvc<Target, Req> = Svc<Target> where Self::Res: Svc<Req>;
+ | ^^^ associated type `Res` not found
+
+error[E0220]: associated type `Res` not found for `Self`
+ --> $DIR/issue-59029-1.rs:5:52
+ |
+LL | trait MkSvc<Target, Req> = Svc<Target> where Self::Res: Svc<Req>;
+ | ^^^ associated type `Res` not found
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0220`.
--- /dev/null
+// check-pass
+
+pub trait ResultExt {
+ type Ok;
+ fn err_eprint_and_ignore(self) -> Option<Self::Ok>;
+}
+
+impl<O, E> ResultExt for std::result::Result<O, E>
+where
+ E: std::error::Error,
+{
+ type Ok = O;
+ fn err_eprint_and_ignore(self) -> Option<O>
+ where
+ Self: ,
+ {
+ match self {
+ Err(e) => {
+ eprintln!("{}", e);
+ None
+ }
+ Ok(o) => Some(o),
+ }
+ }
+}
+
+fn main() {}
|
= help: add `#![feature(dispatch_from_dyn)]` to the crate attributes to enable
-error[E0378]: the trait `DispatchFromDyn` may only be implemented for a coercion between structures
- --> $DIR/issue-78372.rs:3:1
- |
-LL | impl<T> DispatchFromDyn<Smaht<U, MISC>> for T {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Smaht<[type error], [type error]>`)
--> $DIR/issue-78372.rs:3:6
|
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
= note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
+error[E0378]: the trait `DispatchFromDyn` may only be implemented for a coercion between structures
+ --> $DIR/issue-78372.rs:3:1
+ |
+LL | impl<T> DispatchFromDyn<Smaht<U, MISC>> for T {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
error: aborting due to 7 previous errors
Some errors have detailed explanations: E0210, E0378, E0412, E0658.
--- /dev/null
+// Test that an object type `Box<Foo>` is not considered to implement the
+// trait `Foo`. Issue #5087.
+
+trait Foo {}
+fn take_foo<F:Foo>(f: F) {}
+fn take_object(f: Box<dyn Foo>) { take_foo(f); }
+//~^ ERROR `Box<dyn Foo>: Foo` is not satisfied
+fn main() {}
--- /dev/null
+error[E0277]: the trait bound `Box<dyn Foo>: Foo` is not satisfied
+ --> $DIR/object-does-not-impl-trait.rs:6:44
+ |
+LL | fn take_object(f: Box<dyn Foo>) { take_foo(f); }
+ | -------- ^ the trait `Foo` is not implemented for `Box<dyn Foo>`
+ | |
+ | required by a bound introduced by this call
+ |
+note: required by a bound in `take_foo`
+ --> $DIR/object-does-not-impl-trait.rs:5:15
+ |
+LL | fn take_foo<F:Foo>(f: F) {}
+ | ^^^ required by this bound in `take_foo`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+#![feature(negative_impls)]
+
+use std::marker::Send;
+
+struct TestType;
+
+impl !TestType {}
+//~^ ERROR inherent impls cannot be negative
+
+trait TestTrait {}
+
+unsafe impl !Send for TestType {}
+//~^ ERROR negative impls cannot be unsafe
+impl !TestTrait for TestType {}
+
+struct TestType2<T>(T);
+
+impl<T> !TestType2<T> {}
+//~^ ERROR inherent impls cannot be negative
+
+unsafe impl<T> !Send for TestType2<T> {}
+//~^ ERROR negative impls cannot be unsafe
+impl<T> !TestTrait for TestType2<T> {}
+
+fn main() {}
--- /dev/null
+error: inherent impls cannot be negative
+ --> $DIR/syntax-trait-polarity.rs:7:7
+ |
+LL | impl !TestType {}
+ | -^^^^^^^^ inherent impl for this type
+ | |
+ | negative because of this
+
+error[E0198]: negative impls cannot be unsafe
+ --> $DIR/syntax-trait-polarity.rs:12:13
+ |
+LL | unsafe impl !Send for TestType {}
+ | ------ -^^^^
+ | | |
+ | | negative because of this
+ | unsafe because of this
+
+error: inherent impls cannot be negative
+ --> $DIR/syntax-trait-polarity.rs:18:10
+ |
+LL | impl<T> !TestType2<T> {}
+ | -^^^^^^^^^^^^ inherent impl for this type
+ | |
+ | negative because of this
+
+error[E0198]: negative impls cannot be unsafe
+ --> $DIR/syntax-trait-polarity.rs:21:16
+ |
+LL | unsafe impl<T> !Send for TestType2<T> {}
+ | ------ -^^^^
+ | | |
+ | | negative because of this
+ | unsafe because of this
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0198`.
+++ /dev/null
-// run-pass
-
-#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
-
-trait Specializable { type Output; }
-
-impl<T> Specializable for T {
- default type Output = u16;
-}
-
-fn main() {
- unsafe {
- std::mem::transmute::<u16, <() as Specializable>::Output>(0);
- }
-}
+++ /dev/null
-warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
- --> $DIR/transmute-specialization.rs:3:12
- |
-LL | #![feature(specialization)]
- | ^^^^^^^^^^^^^^
- |
- = note: `#[warn(incomplete_features)]` on by default
- = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
- = help: consider using `min_specialization` instead, which is more stable and complete
-
-warning: 1 warning emitted
-
+++ /dev/null
-// run-pass
-
-#![allow(unused_must_use)]
-/*
- This is about the simplest program that can successfully send a
- message.
- */
-
-use std::sync::mpsc::channel;
-
-pub fn main() {
- let (tx, rx) = channel();
- tx.send(42);
- let r = rx.recv();
- println!("{:?}", r);
-}
--- /dev/null
+// run-pass
+#![allow(unreachable_code)]
+// compile-flags: --edition 2018
+
+#![feature(try_blocks)]
+
+fn main() {
+ let mut a = 0;
+ let () = {
+ let _: Result<(), ()> = try {
+ let _ = Err(())?;
+ return
+ };
+ a += 1;
+ };
+ a += 2;
+ assert_eq!(a, 3);
+}
+++ /dev/null
-// compile-flags: --edition 2018
-fn foo() -> Result<(), ()> {
- Ok(try!()); //~ ERROR use of deprecated `try` macro
- Ok(try!(Ok(()))) //~ ERROR use of deprecated `try` macro
-}
-
-fn main() {
- let _ = foo();
-}
+++ /dev/null
-error: use of deprecated `try` macro
- --> $DIR/try-macro-suggestion.rs:3:8
- |
-LL | Ok(try!());
- | ^^^^^^
- |
- = note: in the 2018 edition `try` is a reserved keyword, and the `try!()` macro is deprecated
-help: you can still access the deprecated `try!()` macro using the "raw identifier" syntax
- |
-LL | Ok(r#try!());
- | ++
-
-error: use of deprecated `try` macro
- --> $DIR/try-macro-suggestion.rs:4:8
- |
-LL | Ok(try!(Ok(())))
- | ^^^^^^^^^^^^
- |
- = note: in the 2018 edition `try` is a reserved keyword, and the `try!()` macro is deprecated
-help: you can use the `?` operator instead
- |
-LL - Ok(try!(Ok(())))
-LL + Ok(Ok(())?)
- |
-help: alternatively, you can still access the deprecated `try!()` macro using the "raw identifier" syntax
- |
-LL | Ok(r#try!(Ok(())))
- | ++
-
-error: aborting due to 2 previous errors
-
type V = u8;
fn f() -> Self::V { 0 }
//~^ ERROR ambiguous associated item
+ //~| ERROR ambiguous associated item
//~| WARN this was previously accepted
+ //~| WARN this was previously accepted
+ //~| HELP use fully-qualified syntax
//~| HELP use fully-qualified syntax
}
LL | type V;
| ^^^^^^^
-error: aborting due to previous error
+error: ambiguous associated item
+ --> $DIR/enum-variant-priority-lint-ambiguous_associated_items.rs:32:15
+ |
+LL | fn f() -> Self::V { 0 }
+ | ^^^^^^^ help: use fully-qualified syntax: `<E as Tr>::V`
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #57644 <https://github.com/rust-lang/rust/issues/57644>
+note: `V` could refer to the variant defined here
+ --> $DIR/enum-variant-priority-lint-ambiguous_associated_items.rs:22:5
+ |
+LL | V
+ | ^
+note: `V` could also refer to the associated type defined here
+ --> $DIR/enum-variant-priority-lint-ambiguous_associated_items.rs:26:5
+ |
+LL | type V;
+ | ^^^^^^^
+
+error: aborting due to 2 previous errors
impl MyTrait for () {}
impl<F> FnOnce<()> for &F {
- //~^ ERROR conflicting implementations
- //~| ERROR type parameter `F` must be used
+ //~^ ERROR type parameter `F` must be used
type Output = impl MyTrait;
extern "rust-call" fn call_once(self, _: ()) -> Self::Output {}
}
-error[E0119]: conflicting implementations of trait `std::ops::FnOnce<()>` for type `&_`
- --> $DIR/incoherent-assoc-imp-trait.rs:10:1
- |
-LL | impl<F> FnOnce<()> for &F {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: conflicting implementation in crate `core`:
- - impl<A, F> FnOnce<A> for &F
- where F: Fn<A>, F: ?Sized;
-
error[E0210]: type parameter `F` must be used as the type parameter for some local type (e.g., `MyStruct<F>`)
--> $DIR/incoherent-assoc-imp-trait.rs:10:6
|
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
= note: only traits defined in the current crate can be implemented for a type parameter
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors have detailed explanations: E0119, E0210.
-For more information about an error, try `rustc --explain E0119`.
+For more information about this error, try `rustc --explain E0210`.
--- /dev/null
+// check-pass
+// compile-flags: -Z unpretty=hir
+
+#![feature(type_alias_impl_trait)]
+
+trait Animal {}
+
+fn main() {
+ pub type ServeFut = impl Animal;
+}
--- /dev/null
+// check-pass
+// compile-flags: -Z unpretty=hir
+
+#![feature(type_alias_impl_trait)]
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
+#[macro_use]
+extern crate std;
+
+trait Animal { }
+
+fn main() {
+ pub type ServeFut = /*impl Trait*/;
+ }
--- /dev/null
+// Regression test for #30225, which was an ICE that would trigger as
+// a result of a poor interaction between trait result caching and
+// type inference. Specifically, at that time, unification could cause
+// unrelated type variables to become instantiated, if subtyping
+// relationships existed. These relationships are now propagated
+// through obligations and hence everything works out fine.
+
+trait Foo<U,V> : Sized {
+ fn foo(self, u: Option<U>, v: Option<V>) {}
+}
+
+struct A;
+struct B;
+
+impl Foo<A, B> for () {} // impl A
+impl Foo<u32, u32> for u32 {} // impl B, creating ambiguity
+
+fn toxic() {
+ // cache the resolution <() as Foo<$0,$1>> = impl A
+ let u = None;
+ let v = None;
+ Foo::foo((), u, v);
+}
+
+fn bomb() {
+ let mut u = None; // type is Option<$0>
+ let mut v = None; // type is Option<$1>
+ let mut x = None; // type is Option<$2>
+
+ Foo::foo(x.unwrap(),u,v); // register <$2 as Foo<$0, $1>>
+ u = v; // mark $0 and $1 in a subtype relationship
+ //~^ ERROR mismatched types
+ x = Some(()); // set $2 = (), allowing impl selection
+ // to proceed for <() as Foo<$0, $1>> = impl A.
+ // kaboom, this *used* to trigge an ICE
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-30225.rs:31:9
+ |
+LL | u = v; // mark $0 and $1 in a subtype relationship
+ | ^ expected struct `A`, found struct `B`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+#![crate_type="lib"]
+
+
+pub trait A {
+ fn a(&self) {}
+}
+impl A for () {}
--- /dev/null
+#![crate_type="lib"]
+
+pub extern crate xcrate_issue_43189_a;
--- /dev/null
+#![crate_type="lib"]
+
+pub extern crate core;
--- /dev/null
+// edition:2018
+#![crate_type="lib"]
+#![crate_name="xcrate_issue_61711_b"]
+pub struct Struct;
+pub use crate as alias;
--- /dev/null
+// Issue 46112: An extern crate pub re-exporting libcore was causing
+// paths rooted from `std` to be misrendered in the diagnostic output.
+
+// ignore-windows
+// aux-build:xcrate-issue-43189-a.rs
+// aux-build:xcrate-issue-43189-b.rs
+
+extern crate xcrate_issue_43189_b;
+fn main() {
+ ().a();
+ //~^ ERROR no method named `a` found
+}
--- /dev/null
+error[E0599]: no method named `a` found for unit type `()` in the current scope
+ --> $DIR/issue-43189.rs:10:8
+ |
+LL | ().a();
+ | ^ method not found in `()`
+ |
+ ::: $DIR/auxiliary/xcrate-issue-43189-a.rs:5:8
+ |
+LL | fn a(&self) {}
+ | - the method is available for `()` here
+ |
+ = help: items from traits can only be used if the trait is in scope
+help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+ |
+LL | use xcrate_issue_43189_b::xcrate_issue_43189_a::A;
+ |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
--- /dev/null
+// Issue 46112: An extern crate pub re-exporting libcore was causing
+// paths rooted from `std` to be misrendered in the diagnostic output.
+
+// ignore-windows
+// aux-build:xcrate-issue-46112-rexport-core.rs
+
+extern crate xcrate_issue_46112_rexport_core;
+fn test(r: Result<Option<()>, &'static str>) { }
+fn main() { test(Ok(())); }
+//~^ mismatched types
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-46112.rs:9:21
+ |
+LL | fn main() { test(Ok(())); }
+ | ^^
+ | |
+ | expected enum `Option`, found `()`
+ | help: try using a variant of the expected enum: `Some(())`
+ |
+ = note: expected enum `Option<()>`
+ found unit type `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// Issue 61711: A crate pub re-exporting `crate` was causing an
+// infinite loop.
+
+// edition:2018
+// aux-build:xcrate-issue-61711-b.rs
+// compile-flags:--extern xcrate_issue_61711_b
+
+// build-pass
+
+fn f<F: Fn(xcrate_issue_61711_b::Struct)>(_: F) { }
+fn main() { }
--- /dev/null
+// edition:2021
+
+mod m {
+ pub struct S { foo: i32 }
+ impl S {
+ pub fn foo(&self) -> i32 { 42 }
+ }
+}
+
+fn bar(s: &m::S) {
+ || s.foo() + s.foo; //~ ERROR E0616
+}
+
+fn main() {}
--- /dev/null
+error[E0616]: field `foo` of struct `S` is private
+ --> $DIR/issue-90483-inaccessible-field-adjustment.rs:11:18
+ |
+LL | || s.foo() + s.foo;
+ | ^^^ private field
+ |
+help: a method `foo` also exists, call it with parentheses
+ |
+LL | || s.foo() + s.foo();
+ | ++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0616`.
+++ /dev/null
-// run-pass
-
-pub fn main() {
- let a = 1;
- let a_neg: i8 = -a;
- println!("{}", a_neg);
-
- let b = 1;
- let b_neg: i16 = -b;
- println!("{}", b_neg);
-
- let c = 1;
- let c_neg: i32 = -c;
- println!("{}", c_neg);
-
- let d = 1;
- let d_neg: i64 = -d;
- println!("{}", d_neg);
-
- let e = 1;
- let e_neg: isize = -e;
- println!("{}", e_neg);
-}
--- /dev/null
+// run-pass
+// Tests multiple free variables being passed by value into an unboxed
+// once closure as an optimization by codegen. This used to hit an
+// incorrect assert.
+
+fn main() {
+ let x = 2u8;
+ let y = 3u8;
+ assert_eq!((move || x + y)(), 5);
+}
+++ /dev/null
-// edition:2018
-
-#![deny(unused_extern_crates)]
-#![feature(test, rustc_private, crate_visibility_modifier)]
-
-extern crate libc;
-//~^ ERROR unused extern crate
-//~| HELP remove
-extern crate libc as x;
-//~^ ERROR unused extern crate
-//~| HELP remove
-
-extern crate proc_macro;
-
-#[macro_use]
-extern crate test;
-
-pub extern crate test as y;
-
-pub extern crate alloc;
-
-pub(crate) extern crate alloc as a;
-
-crate extern crate alloc as b;
-
-mod foo {
- pub(in crate::foo) extern crate alloc as c;
-
- pub(super) extern crate alloc as d;
-
- extern crate libc;
- //~^ ERROR unused extern crate
- //~| HELP remove
-
- extern crate libc as x;
- //~^ ERROR unused extern crate
- //~| HELP remove
-
- pub extern crate test;
-
- pub extern crate test as y;
-
- mod bar {
- extern crate libc;
- //~^ ERROR unused extern crate
- //~| HELP remove
-
- extern crate libc as x;
- //~^ ERROR unused extern crate
- //~| HELP remove
-
- pub(in crate::foo::bar) extern crate alloc as e;
-
- fn dummy() {
- e::string::String::new();
- }
- }
-
- fn dummy() {
- c::string::String::new();
- d::string::String::new();
- }
-}
-
-
-fn main() {
- a::string::String::new();
- b::string::String::new();
-
- proc_macro::TokenStream::new();
-}
+++ /dev/null
-error: unused extern crate
- --> $DIR/unnecessary-extern-crate.rs:6:1
- |
-LL | extern crate libc;
- | ^^^^^^^^^^^^^^^^^^ help: remove it
- |
-note: the lint level is defined here
- --> $DIR/unnecessary-extern-crate.rs:3:9
- |
-LL | #![deny(unused_extern_crates)]
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: unused extern crate
- --> $DIR/unnecessary-extern-crate.rs:9:1
- |
-LL | extern crate libc as x;
- | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove it
-
-error: unused extern crate
- --> $DIR/unnecessary-extern-crate.rs:31:5
- |
-LL | extern crate libc;
- | ^^^^^^^^^^^^^^^^^^ help: remove it
-
-error: unused extern crate
- --> $DIR/unnecessary-extern-crate.rs:35:5
- |
-LL | extern crate libc as x;
- | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove it
-
-error: unused extern crate
- --> $DIR/unnecessary-extern-crate.rs:44:9
- |
-LL | extern crate libc;
- | ^^^^^^^^^^^^^^^^^^ help: remove it
-
-error: unused extern crate
- --> $DIR/unnecessary-extern-crate.rs:48:9
- |
-LL | extern crate libc as x;
- | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove it
-
-error: aborting due to 6 previous errors
-
+++ /dev/null
-// build-pass (FIXME(62277): could be check-pass?)
-
-#![feature(rustc_attrs)]
-
-#[rustc_dummy(a b c d)]
-#[rustc_dummy[a b c d]]
-#[rustc_dummy{a b c d}]
-fn main() {}
--- /dev/null
+pub struct X([u8]);
+
+pub static Y: &'static X = {
+ const Y: &'static [u8] = b"";
+ &X(*Y)
+ //~^ ERROR E0277
+};
+
+fn main() {}
--- /dev/null
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+ --> $DIR/issue-30355.rs:5:8
+ |
+LL | &X(*Y)
+ | ^^ doesn't have a size known at compile-time
+ |
+ = help: the trait `Sized` is not implemented for `[u8]`
+ = note: all function arguments must have a statically known size
+ = help: unsized fn params are gated as an unstable feature
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
-#![feature(use_nested_groups)]
#![allow(dead_code)]
#![deny(unused_imports)]
error: unused imports: `*`, `Foo`, `baz::{}`, `foobar::*`
- --> $DIR/use-nested-groups-unused-imports.rs:16:11
+ --> $DIR/use-nested-groups-unused-imports.rs:15:11
|
LL | use foo::{Foo, bar::{baz::{}, foobar::*}, *};
| ^^^ ^^^^^^^ ^^^^^^^^^ ^
|
note: the lint level is defined here
- --> $DIR/use-nested-groups-unused-imports.rs:3:9
+ --> $DIR/use-nested-groups-unused-imports.rs:2:9
|
LL | #![deny(unused_imports)]
| ^^^^^^^^^^^^^^
error: unused import: `*`
- --> $DIR/use-nested-groups-unused-imports.rs:18:24
+ --> $DIR/use-nested-groups-unused-imports.rs:17:24
|
LL | use foo::bar::baz::{*, *};
| ^
error: unused import: `foo::{}`
- --> $DIR/use-nested-groups-unused-imports.rs:20:5
+ --> $DIR/use-nested-groups-unused-imports.rs:19:5
|
LL | use foo::{};
| ^^^^^^^
+++ /dev/null
-// run-pass
-
-#![allow(dead_code)]
-// compile-flags:-D improper-ctypes
-
-// pretty-expanded FIXME #23616
-#![allow(improper_ctypes)]
-
-mod libc {
- extern "C" {
- pub fn malloc(size: isize) -> *const u8;
- }
-}
-
-pub fn main() {}
target_os = "emscripten",
target_os = "freebsd",
target_os = "fuchsia",
+ target_os = "illumos",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
- target_os = "vxworks",
- target_os = "solaris"))]
+ target_os = "solaris",
+ target_os = "vxworks"))]
pub fn main() { }
+++ /dev/null
-// run-pass
-
-use std::thread;
-
-pub fn main() {
- let mut i: isize = 0;
- while i < 100 { i = i + 1; println!("{}", i); thread::yield_now(); }
-}
-Subproject commit 94ca096afbf25f670e76e07dca754fcfe27134be
+Subproject commit 2e2a16e983f597da62bc132eb191bc3276d4b1bb
use clippy_utils::{is_entrypoint_fn, is_expn_of, match_panic_def_id, method_chain_args, return_ty};
use if_chain::if_chain;
use itertools::Itertools;
-use rustc_ast::ast::{Async, AttrKind, Attribute, FnKind, FnRetTy, ItemKind};
+use rustc_ast::ast::{Async, AttrKind, Attribute, Fn, FnRetTy, ItemKind};
use rustc_ast::token::CommentKind;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sync::Lrc;
| ItemKind::ExternCrate(..)
| ItemKind::ForeignMod(..) => return false,
// We found a main function ...
- ItemKind::Fn(box FnKind(_, sig, _, Some(block))) if item.ident.name == sym::main => {
+ ItemKind::Fn(box Fn { sig, body: Some(block), .. }) if item.ident.name == sym::main => {
let is_async = matches!(sig.header.asyncness, Async::Yes { .. });
let returns_nothing = match &sig.decl.output {
FnRetTy::Default(..) => true,
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::in_macro;
-use rustc_ast::ast::{AssocItemKind, Extern, FnKind, FnSig, ImplKind, Item, ItemKind, TraitKind, Ty, TyKind};
+use rustc_ast::ast::{AssocItemKind, Extern, Fn, FnSig, Impl, Item, ItemKind, Trait, Ty, TyKind};
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{sym, Span};
);
}
},
- ItemKind::Impl(box ImplKind {
+ ItemKind::Impl(box Impl {
of_trait: None, items, ..
})
- | ItemKind::Trait(box TraitKind(.., items)) => {
+ | ItemKind::Trait(box Trait { items, .. }) => {
for item in items {
- if let AssocItemKind::Fn(box FnKind(_, fn_sig, _, _)) = &item.kind {
- self.check_fn_sig(cx, fn_sig, item.span);
+ if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
+ self.check_fn_sig(cx, sig, item.span);
}
}
},
- ItemKind::Fn(box FnKind(_, fn_sig, _, _)) => self.check_fn_sig(cx, fn_sig, item.span),
+ ItemKind::Fn(box Fn { sig, .. }) => self.check_fn_sig(cx, sig, item.span),
_ => (),
}
}
if is_future {
let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap();
let span = decl.output.span();
- let send_result = cx.tcx.infer_ctxt().enter(|infcx| {
+ let send_errors = cx.tcx.infer_ctxt().enter(|infcx| {
let cause = traits::ObligationCause::misc(span, hir_id);
let mut fulfillment_cx = traits::FulfillmentContext::new();
fulfillment_cx.register_bound(&infcx, cx.param_env, ret_ty, send_trait, cause);
fulfillment_cx.select_all_or_error(&infcx)
});
- if let Err(send_errors) = send_result {
+ if !send_errors.is_empty() {
span_lint_and_then(
cx,
FUTURE_NOT_SEND,
PatKind::Path(path) => {
#[allow(clippy::match_same_arms)]
let id = match cx.qpath_res(path, pat.hir_id) {
- Res::Def(DefKind::Const | DefKind::ConstParam | DefKind::AnonConst, _) => return,
+ Res::Def(
+ DefKind::Const | DefKind::ConstParam | DefKind::AnonConst | DefKind::InlineConst,
+ _,
+ ) => return,
Res::Def(_, id) => id,
_ => return,
};
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
use rustc_ast::ast::{
- Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, FnKind, Item, ItemKind, Local, Pat, PatKind,
+ self, Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, Item, ItemKind, Local, Pat, PatKind,
};
use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor};
use rustc_lint::{EarlyContext, EarlyLintPass};
return;
}
- if let ItemKind::Fn(box FnKind(_, ref sig, _, Some(ref blk))) = item.kind {
+ if let ItemKind::Fn(box ast::Fn { ref sig, body: Some(ref blk), .. }) = item.kind {
do_check(self, cx, &item.attrs, &sig.decl, blk);
}
}
return;
}
- if let AssocItemKind::Fn(box FnKind(_, ref sig, _, Some(ref blk))) = item.kind {
+ if let AssocItemKind::Fn(box ast::Fn { ref sig, body: Some(ref blk), .. }) = item.kind {
do_check(self, cx, &item.attrs, &sig.decl, blk);
}
}
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::{snippet_opt, snippet_with_applicability};
-use rustc_ast::ast::{Expr, ExprKind, ImplKind, Item, ItemKind, MacCall, Path, StrLit, StrStyle};
+use rustc_ast::ast::{Expr, ExprKind, Impl, Item, ItemKind, MacCall, Path, StrLit, StrStyle};
use rustc_ast::token::{self, LitKind};
use rustc_ast::tokenstream::TokenStream;
use rustc_errors::Applicability;
impl EarlyLintPass for Write {
fn check_item(&mut self, _: &EarlyContext<'_>, item: &Item) {
- if let ItemKind::Impl(box ImplKind {
+ if let ItemKind::Impl(box Impl {
of_trait: Some(trait_ref),
..
}) = &item.kind
(Use(l), Use(r)) => eq_use_tree(l, r),
(Static(lt, lm, le), Static(rt, rm, re)) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re),
(Const(ld, lt, le), Const(rd, rt, re)) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re),
- (Fn(box FnKind(ld, lf, lg, lb)), Fn(box FnKind(rd, rf, rg, rb))) => {
+ (Fn(box ast::Fn { defaultness: ld, sig: lf, generics: lg, body: lb }),
+ Fn(box ast::Fn { defaultness: rd, sig: rf, generics: rg, body: rb })) => {
eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r))
},
(Mod(lu, lmk), Mod(ru, rmk)) => {
(ForeignMod(l), ForeignMod(r)) => {
both(&l.abi, &r.abi, eq_str_lit) && over(&l.items, &r.items, |l, r| eq_item(l, r, eq_foreign_item_kind))
},
- (TyAlias(box TyAliasKind(ld, lg, lb, lt)), TyAlias(box TyAliasKind(rd, rg, rb, rt))) => {
+ (TyAlias(box ast::TyAlias { defaultness: ld, generics: lg, bounds: lb, ty: lt }),
+ TyAlias(box ast::TyAlias { defaultness: rd, generics: rg, bounds: rb, ty: rt })) => {
eq_defaultness(*ld, *rd)
&& eq_generics(lg, rg)
&& over(lb, rb, eq_generic_bound)
(Struct(lv, lg), Struct(rv, rg)) | (Union(lv, lg), Union(rv, rg)) => {
eq_variant_data(lv, rv) && eq_generics(lg, rg)
},
- (Trait(box TraitKind(la, lu, lg, lb, li)), Trait(box TraitKind(ra, ru, rg, rb, ri))) => {
+ (Trait(box ast::Trait { is_auto: la, unsafety: lu, generics: lg, bounds: lb, items: li }),
+ Trait(box ast::Trait { is_auto: ra, unsafety: ru, generics: rg, bounds: rb, items: ri })) => {
la == ra
&& matches!(lu, Unsafe::No) == matches!(ru, Unsafe::No)
&& eq_generics(lg, rg)
},
(TraitAlias(lg, lb), TraitAlias(rg, rb)) => eq_generics(lg, rg) && over(lb, rb, eq_generic_bound),
(
- Impl(box ImplKind {
+ Impl(box ast::Impl {
unsafety: lu,
polarity: lp,
defaultness: ld,
self_ty: lst,
items: li,
}),
- Impl(box ImplKind {
+ Impl(box ast::Impl {
unsafety: ru,
polarity: rp,
defaultness: rd,
use ForeignItemKind::*;
match (l, r) {
(Static(lt, lm, le), Static(rt, rm, re)) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re),
- (Fn(box FnKind(ld, lf, lg, lb)), Fn(box FnKind(rd, rf, rg, rb))) => {
+ (Fn(box ast::Fn { defaultness: ld, sig: lf, generics: lg, body: lb }),
+ Fn(box ast::Fn { defaultness: rd, sig: rf, generics: rg, body: rb })) => {
eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r))
},
- (TyAlias(box TyAliasKind(ld, lg, lb, lt)), TyAlias(box TyAliasKind(rd, rg, rb, rt))) => {
+ (TyAlias(box ast::TyAlias { defaultness: ld, generics: lg, bounds: lb, ty: lt }),
+ TyAlias(box ast::TyAlias { defaultness: rd, generics: rg, bounds: rb, ty: rt })) => {
eq_defaultness(*ld, *rd)
&& eq_generics(lg, rg)
&& over(lb, rb, eq_generic_bound)
use AssocItemKind::*;
match (l, r) {
(Const(ld, lt, le), Const(rd, rt, re)) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re),
- (Fn(box FnKind(ld, lf, lg, lb)), Fn(box FnKind(rd, rf, rg, rb))) => {
+ (Fn(box ast::Fn { defaultness: ld, sig: lf, generics: lg, body: lb }),
+ Fn(box ast::Fn { defaultness: rd, sig: rf, generics: rg, body: rb })) => {
eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r))
},
- (TyAlias(box TyAliasKind(ld, lg, lb, lt)), TyAlias(box TyAliasKind(rd, rg, rb, rt))) => {
+ (TyAlias(box ast::TyAlias { defaultness: ld, generics: lg, bounds: lb, ty: lt }),
+ TyAlias(box ast::TyAlias { defaultness: rd, generics: rg, bounds: rb, ty: rt })) => {
eq_defaultness(*ld, *rd)
&& eq_generics(lg, rg)
&& over(lb, rb, eq_generic_bound)
#![deny(clippy::missing_docs_in_private_items)]
use crate::ty::is_type_diagnostic_item;
-use crate::{is_expn_of, last_path_segment, match_def_path, path_to_local_id, paths};
+use crate::{is_expn_of, last_path_segment, match_def_path, paths};
use if_chain::if_chain;
use rustc_ast::ast::{self, LitKind};
use rustc_hir as hir;
use rustc_hir::{
- Arm, Block, BorrowKind, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, PatKind, QPath, StmtKind, UnOp,
+ Arm, Block, BorrowKind, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, QPath, StmtKind, UnOp,
};
use rustc_lint::LateContext;
use rustc_span::{sym, symbol, ExpnKind, Span, Symbol};
pub format_string_parts: &'tcx [Expr<'tcx>],
/// Symbols corresponding to [`Self::format_string_parts`]
pub format_string_symbols: Vec<Symbol>,
- /// Match arm patterns, the `arg0`, etc. from the next field `args`
- pub arg_names: &'tcx [Pat<'tcx>],
/// Expressions like `ArgumentV1::new(arg0, Debug::fmt)`
pub args: &'tcx [Expr<'tcx>],
/// The final argument passed to `Arguments::new_v1_formatted`, if applicable
_ => None,
})
.collect();
- if let PatKind::Tuple(arg_names, None) = arm.pat.kind;
if let ExprKind::Array(args) = arm.body.kind;
then {
Some(FormatArgsExpn {
value_args,
format_string_parts,
format_string_symbols,
- arg_names,
args,
fmt_expr,
})
if let Ok(i) = usize::try_from(position);
let arg = &self.args[i];
if let ExprKind::Call(_, [arg_name, _]) = arg.kind;
- if let Some(j) = self
- .arg_names
- .iter()
- .position(|pat| path_to_local_id(arg_name, pat.hir_id));
+ if let ExprKind::Field(_, j) = arg_name.kind;
+ if let Ok(j) = j.name.as_str().parse::<usize>();
then {
Some(FormatArgsArg { value: self.value_args[j], arg, fmt: Some(fmt) })
} else {
+#![allow(clippy::excessive_precision)]
#[deny(clippy::unreadable_literal)]
fn allow_inconsistent_digit_grouping() {
error: digits grouped inconsistently by underscores
- --> $DIR/test.rs:18:18
+ --> $DIR/test.rs:19:18
|
LL | let _fail1 = 100_200_300.123456789;
| ^^^^^^^^^^^^^^^^^^^^^ help: consider: `100_200_300.123_456_789`
};
}
+#[derive(Copy, Clone)]
pub struct S;
impl S {
pub fn f(&self) -> &Self {
m!(self)
}
- pub fn f_mut(&self) -> &Self {
+ #[allow(unused_mut)] // mut will be unused, once the macro is fixed
+ pub fn f_mut(mut self) -> Self {
m_mut!(self)
}
}
};
}
+#[derive(Copy, Clone)]
pub struct S;
impl S {
pub fn f(&self) -> &Self {
m!(self)
}
- pub fn f_mut(&self) -> &Self {
+ #[allow(unused_mut)] // mut will be unused, once the macro is fixed
+ pub fn f_mut(mut self) -> Self {
m_mut!(self)
}
}
#[warn(clippy::double_neg)]
+#[allow(clippy::no_effect)]
fn main() {
let x = 1;
-x;
error: `--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op
- --> $DIR/double_neg.rs:6:5
+ --> $DIR/double_neg.rs:7:5
|
LL | --x;
| ^^^
#![warn(clippy::fn_params_excessive_bools)]
+#![allow(clippy::too_many_arguments)]
extern "C" {
fn f(_: bool, _: bool, _: bool, _: bool);
error: more than 3 bools in function parameters
- --> $DIR/fn_params_excessive_bools.rs:17:1
+ --> $DIR/fn_params_excessive_bools.rs:18:1
|
LL | fn g(_: bool, _: bool, _: bool, _: bool) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: consider refactoring bools into two-variant enums
error: more than 3 bools in function parameters
- --> $DIR/fn_params_excessive_bools.rs:20:1
+ --> $DIR/fn_params_excessive_bools.rs:21:1
|
LL | fn t(_: S, _: S, _: Box<S>, _: Vec<u32>, _: bool, _: bool, _: bool, _: bool) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: consider refactoring bools into two-variant enums
error: more than 3 bools in function parameters
- --> $DIR/fn_params_excessive_bools.rs:24:5
+ --> $DIR/fn_params_excessive_bools.rs:25:5
|
LL | fn f(_: bool, _: bool, _: bool, _: bool);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: consider refactoring bools into two-variant enums
error: more than 3 bools in function parameters
- --> $DIR/fn_params_excessive_bools.rs:29:5
+ --> $DIR/fn_params_excessive_bools.rs:30:5
|
LL | fn f(&self, _: bool, _: bool, _: bool, _: bool) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: consider refactoring bools into two-variant enums
error: more than 3 bools in function parameters
- --> $DIR/fn_params_excessive_bools.rs:41:5
+ --> $DIR/fn_params_excessive_bools.rs:42:5
|
LL | / fn n(_: bool, _: u32, _: bool, _: Box<u32>, _: bool, _: bool) {
LL | | fn nn(_: bool, _: bool, _: bool, _: bool) {}
= help: consider refactoring bools into two-variant enums
error: more than 3 bools in function parameters
- --> $DIR/fn_params_excessive_bools.rs:42:9
+ --> $DIR/fn_params_excessive_bools.rs:43:9
|
LL | fn nn(_: bool, _: bool, _: bool, _: bool) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#![allow(unused_assignments)]
#![allow(clippy::if_same_then_else)]
#![allow(clippy::deref_addrof)]
+#![allow(clippy::nonminimal_bool)]
fn foo() -> bool {
true
error: this looks like you are trying to use `.. -= ..`, but you really are doing `.. = (- ..)`
- --> $DIR/formatting.rs:15:6
+ --> $DIR/formatting.rs:16:6
|
LL | a =- 35;
| ^^^^
= note: to remove this lint, use either `-=` or `= -`
error: this looks like you are trying to use `.. *= ..`, but you really are doing `.. = (* ..)`
- --> $DIR/formatting.rs:16:6
+ --> $DIR/formatting.rs:17:6
|
LL | a =* &191;
| ^^^^
= note: to remove this lint, use either `*=` or `= *`
error: this looks like you are trying to use `.. != ..`, but you really are doing `.. = (! ..)`
- --> $DIR/formatting.rs:19:6
+ --> $DIR/formatting.rs:20:6
|
LL | b =! false;
| ^^^^
= note: to remove this lint, use either `!=` or `= !`
error: possibly missing a comma here
- --> $DIR/formatting.rs:28:19
+ --> $DIR/formatting.rs:29:19
|
LL | -1, -2, -3 // <= no comma here
| ^
= note: to remove this lint, add a comma or write the expr in a single line
error: possibly missing a comma here
- --> $DIR/formatting.rs:32:19
+ --> $DIR/formatting.rs:33:19
|
LL | -1, -2, -3 // <= no comma here
| ^
= note: to remove this lint, add a comma or write the expr in a single line
error: possibly missing a comma here
- --> $DIR/formatting.rs:69:11
+ --> $DIR/formatting.rs:70:11
|
LL | -1
| ^
#![warn(clippy::zero_prefixed_literal)]
#![warn(clippy::unseparated_literal_suffix)]
#![warn(clippy::separated_literal_suffix)]
-#![allow(dead_code)]
+#![allow(dead_code, overflowing_literals)]
fn main() {
let ok1 = 0xABCD;
+#![allow(clippy::too_many_arguments, clippy::diverging_sub_expression)]
#![warn(clippy::many_single_char_names)]
fn bla() {
error: 5 bindings with single-character names in scope
- --> $DIR/many_single_char_names.rs:4:9
+ --> $DIR/many_single_char_names.rs:5:9
|
LL | let a: i32;
| ^
= note: `-D clippy::many-single-char-names` implied by `-D warnings`
error: 6 bindings with single-character names in scope
- --> $DIR/many_single_char_names.rs:4:9
+ --> $DIR/many_single_char_names.rs:5:9
|
LL | let a: i32;
| ^
| ^
error: 5 bindings with single-character names in scope
- --> $DIR/many_single_char_names.rs:4:9
+ --> $DIR/many_single_char_names.rs:5:9
|
LL | let a: i32;
| ^
| ^
error: 8 bindings with single-character names in scope
- --> $DIR/many_single_char_names.rs:29:13
+ --> $DIR/many_single_char_names.rs:30:13
|
LL | fn bindings(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32, g: i32, h: i32) {}
| ^ ^ ^ ^ ^ ^ ^ ^
error: 8 bindings with single-character names in scope
- --> $DIR/many_single_char_names.rs:32:10
+ --> $DIR/many_single_char_names.rs:33:10
|
LL | let (a, b, c, d, e, f, g, h): (bool, bool, bool, bool, bool, bool, bool, bool) = unimplemented!();
| ^ ^ ^ ^ ^ ^ ^ ^
#![allow(
dead_code,
unused_variables,
+ overflowing_literals,
clippy::excessive_precision,
clippy::inconsistent_digit_grouping
)]
let fail25 = 1E2_f32;
let fail26 = 43E7_f64;
let fail27 = 243E17_f32;
- #[allow(overflowing_literals)]
let fail28 = 241_251_235E723_f64;
let ok29 = 42279.911_32;
#![allow(
dead_code,
unused_variables,
+ overflowing_literals,
clippy::excessive_precision,
clippy::inconsistent_digit_grouping
)]
let fail25 = 1E2_32;
let fail26 = 43E7_64;
let fail27 = 243E17_32;
- #[allow(overflowing_literals)]
let fail28 = 241251235E723_64;
let ok29 = 42279.911_32;
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:11:18
+ --> $DIR/mistyped_literal_suffix.rs:12:18
|
LL | let fail14 = 2_32;
| ^^^^ help: did you mean to write: `2_i32`
= note: `#[deny(clippy::mistyped_literal_suffixes)]` on by default
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:12:18
+ --> $DIR/mistyped_literal_suffix.rs:13:18
|
LL | let fail15 = 4_64;
| ^^^^ help: did you mean to write: `4_i64`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:13:18
+ --> $DIR/mistyped_literal_suffix.rs:14:18
|
LL | let fail16 = 7_8; //
| ^^^ help: did you mean to write: `7_i8`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:14:18
+ --> $DIR/mistyped_literal_suffix.rs:15:18
|
LL | let fail17 = 23_16; //
| ^^^^^ help: did you mean to write: `23_i16`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:17:18
+ --> $DIR/mistyped_literal_suffix.rs:18:18
|
LL | let fail20 = 2__8; //
| ^^^^ help: did you mean to write: `2_i8`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:18:18
+ --> $DIR/mistyped_literal_suffix.rs:19:18
|
LL | let fail21 = 4___16; //
| ^^^^^^ help: did you mean to write: `4_i16`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:21:18
+ --> $DIR/mistyped_literal_suffix.rs:22:18
|
LL | let fail25 = 1E2_32;
| ^^^^^^ help: did you mean to write: `1E2_f32`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:22:18
+ --> $DIR/mistyped_literal_suffix.rs:23:18
|
LL | let fail26 = 43E7_64;
| ^^^^^^^ help: did you mean to write: `43E7_f64`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:23:18
+ --> $DIR/mistyped_literal_suffix.rs:24:18
|
LL | let fail27 = 243E17_32;
| ^^^^^^^^^ help: did you mean to write: `243E17_f32`
// fn call_with_mut_self<'life0>(self: &'life0 mut Self) {}
#[rename_my_lifetimes]
impl T2 for S2 {
+ #[allow(clippy::needless_lifetimes)]
fn call_with_mut_self(self: &mut Self) {}
}
}
error: the type of the `self` parameter does not need to be arbitrary
- --> $DIR/needless_arbitrary_self_type_unfixable.rs:41:31
+ --> $DIR/needless_arbitrary_self_type_unfixable.rs:42:31
|
LL | fn call_with_mut_self(self: &mut Self) {}
| ^^^^^^^^^^^^^^^ help: consider to change this parameter to: `&'_ mut self`
};
}
+#[allow(clippy::nonminimal_bool)]
fn main() {
let mut i = 1;
while i < 10 {
error: this `else` block is redundant
- --> $DIR/needless_continue.rs:28:16
+ --> $DIR/needless_continue.rs:29:16
|
LL | } else {
| ________________^
}
error: there is no need for an explicit `else` block for this `if` expression
- --> $DIR/needless_continue.rs:43:9
+ --> $DIR/needless_continue.rs:44:9
|
LL | / if (zero!(i % 2) || nonzero!(i % 5)) && i % 3 != 0 {
LL | | continue;
}
error: this `continue` expression is redundant
- --> $DIR/needless_continue.rs:56:9
+ --> $DIR/needless_continue.rs:57:9
|
LL | continue; // should lint here
| ^^^^^^^^^
= help: consider dropping the `continue` expression
error: this `continue` expression is redundant
- --> $DIR/needless_continue.rs:63:9
+ --> $DIR/needless_continue.rs:64:9
|
LL | continue; // should lint here
| ^^^^^^^^^
= help: consider dropping the `continue` expression
error: this `continue` expression is redundant
- --> $DIR/needless_continue.rs:70:9
+ --> $DIR/needless_continue.rs:71:9
|
LL | continue // should lint here
| ^^^^^^^^
= help: consider dropping the `continue` expression
error: this `continue` expression is redundant
- --> $DIR/needless_continue.rs:78:9
+ --> $DIR/needless_continue.rs:79:9
|
LL | continue // should lint here
| ^^^^^^^^
= help: consider dropping the `continue` expression
error: this `else` block is redundant
- --> $DIR/needless_continue.rs:128:24
+ --> $DIR/needless_continue.rs:129:24
|
LL | } else {
| ________________________^
}
error: there is no need for an explicit `else` block for this `if` expression
- --> $DIR/needless_continue.rs:134:17
+ --> $DIR/needless_continue.rs:135:17
|
LL | / if condition() {
LL | | continue; // should lint here
#![warn(clippy::all)]
-#![allow(unused, clippy::println_empty_string)]
+#![allow(unused, clippy::println_empty_string, non_snake_case)]
#[derive(Clone, Debug)]
enum MaybeInst {
impl MaybeInst {
fn fill(&mut self) {
+ #[allow(non_fmt_panics)]
let filled = match *self {
MaybeInst::Split1(goto1) => panic!("1"),
MaybeInst::Split2(goto2) => panic!("2"),
}
fn issue3078() {
+ #[allow(clippy::single_match)]
match "a" {
stringify!(a) => {},
_ => {},
error: consider choosing a more descriptive name
- --> $DIR/non_expressive_names.rs:27:9
+ --> $DIR/non_expressive_names.rs:28:9
|
LL | let _1 = 1; //~ERROR Consider a more descriptive name
| ^^
= note: `-D clippy::just-underscores-and-digits` implied by `-D warnings`
error: consider choosing a more descriptive name
- --> $DIR/non_expressive_names.rs:28:9
+ --> $DIR/non_expressive_names.rs:29:9
|
LL | let ____1 = 1; //~ERROR Consider a more descriptive name
| ^^^^^
error: consider choosing a more descriptive name
- --> $DIR/non_expressive_names.rs:29:9
+ --> $DIR/non_expressive_names.rs:30:9
|
LL | let __1___2 = 12; //~ERROR Consider a more descriptive name
| ^^^^^^^
error: consider choosing a more descriptive name
- --> $DIR/non_expressive_names.rs:49:13
+ --> $DIR/non_expressive_names.rs:51:13
|
LL | let _1 = 1;
| ^^
error: consider choosing a more descriptive name
- --> $DIR/non_expressive_names.rs:50:13
+ --> $DIR/non_expressive_names.rs:52:13
|
LL | let ____1 = 1;
| ^^^^^
error: consider choosing a more descriptive name
- --> $DIR/non_expressive_names.rs:51:13
+ --> $DIR/non_expressive_names.rs:53:13
|
LL | let __1___2 = 12;
| ^^^^^^^
#[allow(clippy::needless_return)]
(|| return 2)();
(|| -> Option<i32> { None? })();
+ #[allow(clippy::try_err)]
(|| -> Result<i32, i32> { Err(2)? })();
}
#![warn(clippy::redundant_else)]
-#![allow(clippy::needless_return)]
+#![allow(clippy::needless_return, clippy::if_same_then_else)]
fn main() {
loop {
1
};
// assign
- let a;
+ let mut a;
a = if foo() {
return;
} else {
#![warn(clippy::similar_names)]
-#![allow(unused, clippy::println_empty_string)]
+#![allow(
+ unused,
+ clippy::println_empty_string,
+ clippy::empty_loop,
+ clippy::diverging_sub_expression
+)]
struct Foo {
apple: i32,
error: binding's name is too similar to existing binding
- --> $DIR/similar_names.rs:15:9
+ --> $DIR/similar_names.rs:20:9
|
LL | let bpple: i32;
| ^^^^^
|
= note: `-D clippy::similar-names` implied by `-D warnings`
note: existing binding defined here
- --> $DIR/similar_names.rs:13:9
+ --> $DIR/similar_names.rs:18:9
|
LL | let apple: i32;
| ^^^^^
error: binding's name is too similar to existing binding
- --> $DIR/similar_names.rs:17:9
+ --> $DIR/similar_names.rs:22:9
|
LL | let cpple: i32;
| ^^^^^
|
note: existing binding defined here
- --> $DIR/similar_names.rs:13:9
+ --> $DIR/similar_names.rs:18:9
|
LL | let apple: i32;
| ^^^^^
error: binding's name is too similar to existing binding
- --> $DIR/similar_names.rs:41:9
+ --> $DIR/similar_names.rs:46:9
|
LL | let bluby: i32;
| ^^^^^
|
note: existing binding defined here
- --> $DIR/similar_names.rs:40:9
+ --> $DIR/similar_names.rs:45:9
|
LL | let blubx: i32;
| ^^^^^
error: binding's name is too similar to existing binding
- --> $DIR/similar_names.rs:45:9
+ --> $DIR/similar_names.rs:50:9
|
LL | let coke: i32;
| ^^^^
|
note: existing binding defined here
- --> $DIR/similar_names.rs:43:9
+ --> $DIR/similar_names.rs:48:9
|
LL | let cake: i32;
| ^^^^
error: binding's name is too similar to existing binding
- --> $DIR/similar_names.rs:63:9
+ --> $DIR/similar_names.rs:68:9
|
LL | let xyzeabc: i32;
| ^^^^^^^
|
note: existing binding defined here
- --> $DIR/similar_names.rs:61:9
+ --> $DIR/similar_names.rs:66:9
|
LL | let xyz1abc: i32;
| ^^^^^^^
error: binding's name is too similar to existing binding
- --> $DIR/similar_names.rs:67:9
+ --> $DIR/similar_names.rs:72:9
|
LL | let parsee: i32;
| ^^^^^^
|
note: existing binding defined here
- --> $DIR/similar_names.rs:65:9
+ --> $DIR/similar_names.rs:70:9
|
LL | let parser: i32;
| ^^^^^^
error: binding's name is too similar to existing binding
- --> $DIR/similar_names.rs:88:16
+ --> $DIR/similar_names.rs:93:16
|
LL | bpple: sprang,
| ^^^^^^
|
note: existing binding defined here
- --> $DIR/similar_names.rs:87:16
+ --> $DIR/similar_names.rs:92:16
|
LL | apple: spring,
| ^^^^^^
// aux-build:proc_macro_suspicious_else_formatting.rs
#![warn(clippy::suspicious_else_formatting)]
+#![allow(clippy::if_same_then_else)]
extern crate proc_macro_suspicious_else_formatting;
use proc_macro_suspicious_else_formatting::DeriveBadSpan;
error: this looks like an `else {..}` but the `else` is missing
- --> $DIR/suspicious_else_formatting.rs:16:6
+ --> $DIR/suspicious_else_formatting.rs:17:6
|
LL | } {
| ^
= note: to remove this lint, add the missing `else` or add a new line before the next block
error: this looks like an `else if` but the `else` is missing
- --> $DIR/suspicious_else_formatting.rs:20:6
+ --> $DIR/suspicious_else_formatting.rs:21:6
|
LL | } if foo() {
| ^
= note: to remove this lint, add the missing `else` or add a new line before the second `if`
error: this looks like an `else if` but the `else` is missing
- --> $DIR/suspicious_else_formatting.rs:27:10
+ --> $DIR/suspicious_else_formatting.rs:28:10
|
LL | } if foo() {
| ^
= note: to remove this lint, add the missing `else` or add a new line before the second `if`
error: this looks like an `else if` but the `else` is missing
- --> $DIR/suspicious_else_formatting.rs:35:10
+ --> $DIR/suspicious_else_formatting.rs:36:10
|
LL | } if foo() {
| ^
= note: to remove this lint, add the missing `else` or add a new line before the second `if`
error: this is an `else {..}` but the formatting might hide it
- --> $DIR/suspicious_else_formatting.rs:44:6
+ --> $DIR/suspicious_else_formatting.rs:45:6
|
LL | } else
| ______^
= note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}`
error: this is an `else if` but the formatting might hide it
- --> $DIR/suspicious_else_formatting.rs:56:6
+ --> $DIR/suspicious_else_formatting.rs:57:6
|
LL | } else
| ______^
= note: to remove this lint, remove the `else` or remove the new line between `else` and `if`
error: this is an `else if` but the formatting might hide it
- --> $DIR/suspicious_else_formatting.rs:61:6
+ --> $DIR/suspicious_else_formatting.rs:62:6
|
LL | }
| ______^
= note: to remove this lint, remove the `else` or remove the new line between `else` and `if`
error: this is an `else {..}` but the formatting might hide it
- --> $DIR/suspicious_else_formatting.rs:88:6
+ --> $DIR/suspicious_else_formatting.rs:89:6
|
LL | }
| ______^
= note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}`
error: this is an `else {..}` but the formatting might hide it
- --> $DIR/suspicious_else_formatting.rs:96:6
+ --> $DIR/suspicious_else_formatting.rs:97:6
|
LL | }
| ______^
#![warn(clippy::suspicious_operation_groupings)]
+#![allow(clippy::eq_op)]
struct Vec3 {
x: f64,
}
}
-fn inside_an_if_statement(s1: &S, s2: &S) {
+fn inside_an_if_statement(s1: &mut S, s2: &S) {
// There's no `s1.b`
if s1.a < s2.a && s1.a < s2.b {
s1.c = s2.c;
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:14:9
+ --> $DIR/suspicious_operation_groupings.rs:15:9
|
LL | self.x == other.y && self.y == other.y && self.z == other.z
| ^^^^^^^^^^^^^^^^^ help: did you mean: `self.x == other.x`
= note: `-D clippy::suspicious-operation-groupings` implied by `-D warnings`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:27:20
+ --> $DIR/suspicious_operation_groupings.rs:28:20
|
LL | s1.a < s2.a && s1.a < s2.b
| ^^^^^^^^^^^ help: did you mean: `s1.b < s2.b`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:75:33
+ --> $DIR/suspicious_operation_groupings.rs:76:33
|
LL | s1.a * s2.a + s1.b * s2.b + s1.c * s2.b + s1.d * s2.d
| ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:80:19
+ --> $DIR/suspicious_operation_groupings.rs:81:19
|
LL | s1.a * s2.a + s1.b * s2.c + s1.c * s2.c
| ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:80:19
+ --> $DIR/suspicious_operation_groupings.rs:81:19
|
LL | s1.a * s2.a + s1.b * s2.c + s1.c * s2.c
| ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:85:19
+ --> $DIR/suspicious_operation_groupings.rs:86:19
|
LL | s1.a * s2.a + s2.b * s2.b + s1.c * s2.c
| ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:90:19
+ --> $DIR/suspicious_operation_groupings.rs:91:19
|
LL | s1.a * s2.a + s1.b * s1.b + s1.c * s2.c
| ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:95:5
+ --> $DIR/suspicious_operation_groupings.rs:96:5
|
LL | s1.a * s1.a + s1.b * s2.b + s1.c * s2.c
| ^^^^^^^^^^^ help: did you mean: `s1.a * s2.a`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:100:33
+ --> $DIR/suspicious_operation_groupings.rs:101:33
|
LL | s1.a * s2.a + s1.b * s2.b + s1.c * s1.c
| ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:113:20
+ --> $DIR/suspicious_operation_groupings.rs:114:20
|
LL | (s1.a * s2.a + s1.b * s1.b)
| ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:118:34
+ --> $DIR/suspicious_operation_groupings.rs:119:34
|
LL | (s1.a * s2.a + s1.b * s2.b + s1.c * s2.b + s1.d * s2.d)
| ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:123:38
+ --> $DIR/suspicious_operation_groupings.rs:124:38
|
LL | (s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d)
| ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:128:39
+ --> $DIR/suspicious_operation_groupings.rs:129:39
|
LL | ((s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d))
| ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:133:42
+ --> $DIR/suspicious_operation_groupings.rs:134:42
|
LL | (((s1.a * s2.a) + (s1.b * s2.b)) + ((s1.c * s2.b) + (s1.d * s2.d)))
| ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:133:42
+ --> $DIR/suspicious_operation_groupings.rs:134:42
|
LL | (((s1.a * s2.a) + (s1.b * s2.b)) + ((s1.c * s2.b) + (s1.d * s2.d)))
| ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:138:40
+ --> $DIR/suspicious_operation_groupings.rs:139:40
|
LL | (((s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b)) + (s1.d * s2.d))
| ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:143:40
+ --> $DIR/suspicious_operation_groupings.rs:144:40
|
LL | ((s1.a * s2.a) + ((s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d)))
| ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:148:20
+ --> $DIR/suspicious_operation_groupings.rs:149:20
|
LL | (s1.a * s2.a + s2.b * s2.b) / 2
| ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:153:35
+ --> $DIR/suspicious_operation_groupings.rs:154:35
|
LL | i32::swap_bytes(s1.a * s2.a + s2.b * s2.b)
| ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:158:29
+ --> $DIR/suspicious_operation_groupings.rs:159:29
|
LL | s1.a > 0 && s1.b > 0 && s1.d == s2.c && s1.d == s2.d
| ^^^^^^^^^^^^ help: did you mean: `s1.c == s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:163:17
+ --> $DIR/suspicious_operation_groupings.rs:164:17
|
LL | s1.a > 0 && s1.d == s2.c && s1.b > 0 && s1.d == s2.d
| ^^^^^^^^^^^^ help: did you mean: `s1.c == s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:172:77
+ --> $DIR/suspicious_operation_groupings.rs:173:77
|
LL | (n1.inner.0).0 == (n2.inner.0).0 && (n1.inner.1).0 == (n2.inner.1).0 && (n1.inner.2).0 == (n2.inner.1).0
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `(n1.inner.2).0 == (n2.inner.2).0`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:186:25
+ --> $DIR/suspicious_operation_groupings.rs:187:25
|
LL | s1.a <= s2.a && s1.a <= s2.b
| ^^^^^^^^^^^^ help: did you mean: `s1.b <= s2.b`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:192:23
+ --> $DIR/suspicious_operation_groupings.rs:193:23
|
LL | if s1.a < s2.a && s1.a < s2.b {
| ^^^^^^^^^^^ help: did you mean: `s1.b < s2.b`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:199:48
+ --> $DIR/suspicious_operation_groupings.rs:200:48
|
LL | -(-(-s1.a * -s2.a) + (-(-s1.b * -s2.b) + -(-s1.c * -s2.b) + -(-s1.d * -s2.d)))
| ^^^^^^^^^^^^^ help: did you mean: `-s1.c * -s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:204:27
+ --> $DIR/suspicious_operation_groupings.rs:205:27
|
LL | -(if -s1.a < -s2.a && -s1.a < -s2.b { s1.c } else { s2.a })
| ^^^^^^^^^^^^^ help: did you mean: `-s1.b < -s2.b`
];
static ASM_SUPPORTED_ARCHS: &[&str] = &[
- "x86", "x86_64", "arm", "aarch64", "riscv32", "riscv64", "nvptx64", "hexagon", "mips",
- "mips64", "spirv", "wasm32",
+ "x86", "x86_64", "arm", "aarch64", "riscv32",
+ "riscv64",
+ // These targets require an additional asm_experimental_arch feature.
+ // "nvptx64", "hexagon", "mips", "mips64", "spirv", "wasm32",
];
pub fn has_asm_support(triple: &str) -> bool {
(files_read, errors)
}
+/// Default `tidy` command for macOS is too old that it does not have `mute-id` and `mute` options.
+/// `tidy` on macOS Monterey was released on 31 October 2006, and the same date can be seen seven
+/// years ago at <https://stackoverflow.com/questions/22283382/overwrite-osx-tidy>. Accordingly,
+/// the macOS environment using pre-installed `tidy` should immediately suspend HTML checker process
+/// and show a hint to install a newer one.
+#[cfg(target_os = "macos")]
+fn check_tidy_version() -> Result<(), String> {
+ let output = Command::new("tidy").arg("-v").output().expect("failed to run tidy command");
+ let version = String::from_utf8(output.stdout).expect("failed to read version of tidy command");
+ if version.contains("HTML Tidy for Mac OS X released on 31 October 2006") {
+ eprintln!("The pre-installed HTML Tidy for macOS is not supported.");
+ eprintln!("Consider installing a newer one and re-running.");
+ eprintln!("If you're using Homebrew, you can install it by the following command:");
+ eprintln!(" brew install tidy-html5");
+ eprintln!();
+ Err("HTML check failed: 1 error".to_string())
+ } else {
+ Ok(())
+ }
+}
+
fn main() -> Result<(), String> {
let args = env::args().collect::<Vec<_>>();
if args.len() != 2 {
return Err(format!("Usage: {} <doc folder>", args[0]));
}
+ #[cfg(target_os = "macos")]
+ check_tidy_version()?;
println!("Running HTML checker...");
-Subproject commit 9c18177cd36fe07a3c251234240a9c77a4e66785
+Subproject commit a8b976eb350acec83280a0cd1ca3ac99faff67bc
-Subproject commit 04f03a360ab8fef3d9c0ff84de2d39b8a196c717
+Subproject commit 2c0f433fd2e838ae181f87019b6f1fefe33c6f54
console.log(" --doc-folder [PATH] : location of the generated doc folder");
console.log(" --help : show this message then quit");
console.log(" --crate-name [STRING] : crate name to be used");
- console.log(" --test-file [PATH] : location of the JS test file");
+ console.log(" --test-file [PATHs] : location of the JS test files (can be called " +
+ "multiple times)");
console.log(" --test-folder [PATH] : location of the JS tests folder");
console.log(" --resource-suffix [STRING] : suffix to refer to the correct files");
}
"resource_suffix": "",
"doc_folder": "",
"test_folder": "",
- "test_file": "",
+ "test_file": [],
};
var correspondences = {
"--resource-suffix": "resource_suffix",
console.log("Missing argument after `" + args[i - 1] + "` option.");
return null;
}
- opts[correspondences[args[i - 1]]] = args[i];
+ if (args[i - 1] !== "--test-file") {
+ opts[correspondences[args[i - 1]]] = args[i];
+ } else {
+ opts[correspondences[args[i - 1]]].push(args[i]);
+ }
} else if (args[i] === "--help") {
showHelp();
process.exit(0);
var errors = 0;
if (opts["test_file"].length !== 0) {
- errors += checkFile(opts["test_file"], opts, loaded, index);
- }
- if (opts["test_folder"].length !== 0) {
+ opts["test_file"].forEach(function(file) {
+ errors += checkFile(file, opts, loaded, index);
+ });
+ } else if (opts["test_folder"].length !== 0) {
fs.readdirSync(opts["test_folder"]).forEach(function(file) {
if (!file.endsWith(".js")) {
return;
--- /dev/null
+name: rustdoc check
+on:
+ push:
+ branches:
+ - master
+ pull_request:
+
+jobs:
+ rustdoc_check:
+ runs-on: ubuntu-latest
+ name: rustdoc check
+ steps:
+ - name: checkout
+ uses: actions/checkout@v2
+
+ - name: install rustup
+ run: |
+ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup-init.sh
+ sh rustup-init.sh -y --default-toolchain none
+ rustup target add x86_64-unknown-linux-gnu
+
+ - name: document rustfmt
+ env:
+ RUSTDOCFLAGS: --document-private-items --enable-index-page --show-type-layout --generate-link-to-definition -Zunstable-options -Dwarnings
+ run: cargo doc -Zskip-rustdoc-fingerprint --no-deps -p rustfmt-nightly -p rustfmt-config_proc_macro
Controls the strategy for how imports are grouped together.
- **Default value**: `Preserve`
-- **Possible values**: `Preserve`, `StdExternalCrate`
+- **Possible values**: `Preserve`, `StdExternalCrate`, `One`
- **Stable**: No
#### `Preserve` (default):
use crate::models::Event;
```
+#### `One`:
+
+Discard existing import groups, and create a single group for everything
+
+```rust
+use super::schema::{Context, Payload};
+use super::update::convert_publish_payload;
+use crate::models::Event;
+use alloc::alloc::Layout;
+use broker::database::PooledConnection;
+use chrono::Utc;
+use core::f32;
+use juniper::{FieldError, FieldResult};
+use std::sync::Arc;
+use uuid::Uuid;
+```
+
## `reorder_modules`
Reorder `mod` declarations alphabetically in group.
## Debugging
Some `rewrite_*` methods use the `debug!` macro for printing useful information.
-These messages can be printed by using the environment variable `RUST_LOG=rustfmt=DEBUG`.
+These messages can be printed by using the environment variable `RUSTFMT_LOG=rustfmt=DEBUG`.
These traces can be helpful in understanding which part of the code was used
and get a better grasp on the execution flow.
## Limitations
-Rustfmt tries to work on as much Rust code as possible, sometimes, the code
+Rustfmt tries to work on as much Rust code as possible. Sometimes, the code
doesn't even need to compile! As we approach a 1.0 release we are also looking
to limit areas of instability; in particular, post-1.0, the formatting of most
code should not change as Rustfmt improves. However, there are some things that
binary and library targets of your crate.
You can run `rustfmt --help` for information about available arguments.
+The easiest way to run rustfmt against a project is with `cargo fmt`. `cargo fmt` works on both
+single-crate projects and [cargo workspaces](https://doc.rust-lang.org/book/ch14-03-cargo-workspaces.html).
+Please see `cargo fmt --help` for usage information.
+
+You can specify the path to your own `rustfmt` binary for cargo to use by setting the`RUSTFMT`
+environment variable. This was added in v1.4.22, so you must have this version or newer to leverage this feature (`cargo fmt --version`)
+
+### Running `rustfmt` directly
+
+To format individual files or arbitrary codes from stdin, the `rustfmt` binary should be used. Some
+examples follow:
+
+- `rustfmt lib.rs main.rs` will format "lib.rs" and "main.rs" in place
+- `rustfmt` will read a code from stdin and write formatting to stdout
+ - `echo "fn main() {}" | rustfmt` would emit "fn main() {}".
+
+For more information, including arguments and emit options, see `rustfmt --help`.
+
+### Verifying code is formatted
When running with `--check`, Rustfmt will exit with `0` if Rustfmt would not
make any formatting changes to the input, and `1` if Rustfmt would make changes.
It will also print any found differences. (Older versions of Rustfmt don't
support `--check`, use `--write-mode diff`).
-A minimal Travis setup could look like this (requires Rust 1.24.0 or greater):
+A minimal Travis setup could look like this (requires Rust 1.31.0 or greater):
```yaml
language: rust
+++ /dev/null
-environment:
- global:
- PROJECT_NAME: rustfmt
-
-build: false
-
-test_script:
- - echo Why does no one have access to delete me?
## Installation
- Install [CLion](https://www.jetbrains.com/clion/), [IntelliJ Ultimate or CE](https://www.jetbrains.com/idea/) through the direct download link or using the [JetBrains Toolbox](https://www.jetbrains.com/toolbox/).
- CLion provides a built-in debugger interface but its not free like IntelliJ CE - which does not provide the debugger interface. (IntelliJ seems to lack the toolchain for that, see this discussion [intellij-rust/issues/535](https://github.com/intellij-rust/intellij-rust/issues/535))
-
-- Install the [Rust Plugin](https://intellij-rust.github.io/) by navigating to File -> Settings -> Plugins and press "Install JetBrains Plugin"
- ![plugins](https://user-images.githubusercontent.com/1133787/47240861-f40af680-d3e9-11e8-9b82-cdd5c8d5f5b8.png)
+ CLion and IntelliJ Ultimate [provide a built-in debugger interface](https://github.com/intellij-rust/intellij-rust#compatible-ides) but they are not free like IntelliJ CE.
+
+- Install the [Rust Plugin](https://intellij-rust.github.io/) by navigating to File → Settings → Plugins and searching the plugin in the Marketplace
+ ![plugins](https://user-images.githubusercontent.com/6505554/83944518-6f1e5c00-a81d-11ea-9c35-e16948811ba8.png)
-- Press "Install" on the rust plugin
- ![install rust](https://user-images.githubusercontent.com/1133787/47240803-c0c86780-d3e9-11e8-9265-22f735e4d7ed.png)
+- Press "Install" on the Rust plugin
+ ![install rust](https://user-images.githubusercontent.com/6505554/83944533-82c9c280-a81d-11ea-86b3-ee2e31bc7d12.png)
- Restart CLion/IntelliJ
## Configuration
-- Open the settings window (File -> Settings) and search for "reformat"
+### Run Rustfmt on save
+
+- Open Rustfmt settings (File → Settings → Languages & Frameworks → Rust → Rustfmt) and enable "Run rustfmt on Save"
+ ![run_rustfmt_on_save](https://user-images.githubusercontent.com/6505554/83944610-3468f380-a81e-11ea-9c34-0cbd18dd4969.png)
+
+- IntellJ uses autosave, so now your files will always be formatted according to rustfmt. Alternatively you can use Ctrl+S to reformat file manually
+
+### Bind shortcut to "Reformat File with Rustfmt" action
+
+- Open the settings window (File → Settings) and search for "reformat"
![keymap](https://user-images.githubusercontent.com/1133787/47240922-2ae10c80-d3ea-11e8-9d8f-c798d9749240.png)
- Right-click on "Reformat File with Rustfmt" and assign a keyboard shortcut
+++ /dev/null
-indent_style = "Visual"
-combine_control_expr = false
[toolchain]
-channel = "nightly-2021-10-20"
+channel = "nightly-2021-11-08"
components = ["rustc-dev"]
if next.is_doc_comment() {
let snippet = context.snippet(missing_span);
let (_, mlb) = has_newlines_before_after_comment(snippet);
- result.push_str(&mlb);
+ result.push_str(mlb);
}
}
result.push('\n');
if next.is_doc_comment() {
let snippet = context.snippet(missing_span);
let (_, mlb) = has_newlines_before_after_comment(snippet);
- result.push_str(&mlb);
+ result.push_str(mlb);
}
}
result.push('\n');
) {
assert_eq!(
expected_comment,
- format!("{}", DocCommentFormatter::new(&literal, style))
+ format!("{}", DocCommentFormatter::new(literal, style))
);
}
}
};
fn main() {
- env_logger::init();
+ env_logger::Builder::from_env("RUSTFMT_LOG").init();
let opts = make_opts();
let exit_code = match execute(&opts) {
fn get_targets_recursive(
manifest_path: Option<&Path>,
- mut targets: &mut BTreeSet<Target>,
+ targets: &mut BTreeSet<Target>,
visited: &mut BTreeSet<String>,
) -> Result<(), io::Error> {
let metadata = get_cargo_metadata(manifest_path)?;
for package in &metadata.packages {
- add_targets(&package.targets, &mut targets);
+ add_targets(&package.targets, targets);
// Look for local dependencies using information available since cargo v1.51
// It's theoretically possible someone could use a newer version of rustfmt with
.any(|p| p.manifest_path.eq(&manifest_path))
{
visited.insert(dependency.name.to_owned());
- get_targets_recursive(Some(&manifest_path), &mut targets, visited)?;
+ get_targets_recursive(Some(&manifest_path), targets, visited)?;
}
}
}
} else {
self.rewrites
.iter()
- .map(|rw| utils::unicode_str_width(&rw))
+ .map(|rw| utils::unicode_str_width(rw))
.sum()
} + last.tries;
let one_line_budget = if self.child_count == 1 {
ChainItemKind::Comment(_, CommentPosition::Top) => result.push_str(&connector),
_ => result.push_str(&connector),
}
- result.push_str(&rewrite);
+ result.push_str(rewrite);
}
Some(result)
/// attributes are valid rust attributes
/// See <https://doc.rust-lang.org/rustdoc/print.html#attributes>
fn new(attributes: &str) -> CodeBlockAttribute {
- for attribute in attributes.split(",") {
+ for attribute in attributes.split(',') {
match attribute.trim() {
"" | "rust" | "should_panic" | "no_run" | "edition2015" | "edition2018"
| "edition2021" => (),
result.push_str(line);
result.push_str(match iter.peek() {
Some(next_line) if next_line.is_empty() => sep.trim_end(),
- Some(..) => &sep,
+ Some(..) => sep,
None => "",
});
}
let is_last = i == count_newlines(orig);
if let Some(ref mut ib) = self.item_block {
- if ib.add_line(&line) {
+ if ib.add_line(line) {
return false;
}
self.is_prev_line_multi_line = false;
self.item_block = None;
if let Some(stripped) = line.strip_prefix("```") {
self.code_block_attr = Some(CodeBlockAttribute::new(stripped))
- } else if self.fmt.config.wrap_comments() && ItemizedBlock::is_itemized_line(&line) {
- let ib = ItemizedBlock::new(&line);
+ } else if self.fmt.config.wrap_comments() && ItemizedBlock::is_itemized_line(line) {
+ let ib = ItemizedBlock::new(line);
self.item_block = Some(ib);
return false;
}
{
(&line[4..], true)
} else if let CommentStyle::Custom(opener) = *style {
- if let Some(ref stripped) = line.strip_prefix(opener) {
+ if let Some(stripped) = line.strip_prefix(opener) {
(stripped, true)
} else {
(&line[opener.trim_end().len()..], false)
None => unreachable!(),
};
- while let Some((kind, c)) = self.base.next() {
+ for (kind, c) in self.base.by_ref() {
// needed to set the kind of the ending character on the last line
self.kind = kind;
if c == '\n' {
context.parse_sess.span_to_filename(span),
vec![FormattingError::from_span(
span,
- &context.parse_sess,
+ context.parse_sess,
ErrorKind::LostComment,
)],
);
fn remove_comment_header(comment: &str) -> &str {
if comment.starts_with("///") || comment.starts_with("//!") {
&comment[3..]
- } else if let Some(ref stripped) = comment.strip_prefix("//") {
+ } else if let Some(stripped) = comment.strip_prefix("//") {
stripped
} else if (comment.starts_with("/**") && !comment.starts_with("/**/"))
|| comment.starts_with("/*!")
Windows,
/// Force CR (`\n).
Unix,
- /// `\r\n` in Windows, `\n`` on other platforms.
+ /// `\r\n` in Windows, `\n` on other platforms.
Native,
}
/// 2. other imports
/// 3. `self` / `crate` / `super` imports
StdExternalCrate,
+ /// Discard existing groups, and create a single group for everything
+ One,
}
#[config_type]
format!(r#"<file name="{}">"#, bin_file),
format!(
r#"<error line="2" severity="warning" message="Should be `{}`" />"#,
- XmlEscaped(&r#" println!("Hello, world!");"#),
+ XmlEscaped(r#" println!("Hello, world!");"#),
),
String::from("</file>"),
];
format!(r#"<file name="{}">"#, lib_file),
format!(
r#"<error line="2" severity="warning" message="Should be `{}`" />"#,
- XmlEscaped(&r#" println!("Greetings!");"#),
+ XmlEscaped(r#" println!("Greetings!");"#),
),
String::from("</file>"),
];
}: FormattedFile<'_>,
) -> Result<EmitterResult, io::Error> {
const CONTEXT_SIZE: usize = 3;
- let mismatch = make_diff(&original_text, formatted_text, CONTEXT_SIZE);
+ let mismatch = make_diff(original_text, formatted_text, CONTEXT_SIZE);
let has_diff = !mismatch.is_empty();
if has_diff {
}
_ => false,
},
- ast::ExprKind::Unary(_, ref expr) => needs_space_before_range(context, &expr),
+ ast::ExprKind::Unary(_, ref expr) => needs_space_before_range(context, expr),
_ => false,
}
}
prefix: &str,
shape: Shape,
) -> Option<String> {
- if block_has_statements(&block) {
+ if block_has_statements(block) {
return None;
}
block: &ast::Block,
attrs: Option<&[ast::Attribute]>,
) -> bool {
- !block_has_statements(&block)
+ !block_has_statements(block)
&& !block_contains_comment(context, block)
&& attrs.map_or(true, |a| inner_attributes(a).is_empty())
}
let span = lit.span;
let symbol = lit.token.symbol.as_str();
- if symbol.starts_with("0x") {
+ if let Some(symbol_stripped) = symbol.strip_prefix("0x") {
let hex_lit = match context.config.hex_literal_case() {
HexLiteralCase::Preserve => None,
- HexLiteralCase::Upper => Some(symbol[2..].to_ascii_uppercase()),
- HexLiteralCase::Lower => Some(symbol[2..].to_ascii_lowercase()),
+ HexLiteralCase::Upper => Some(symbol_stripped.to_ascii_uppercase()),
+ HexLiteralCase::Lower => Some(symbol_stripped.to_ascii_lowercase()),
};
if let Some(hex_lit) = hex_lit {
return wrap_str(
};
let fields_str =
- wrap_struct_field(context, &attrs, &fields_str, shape, v_shape, one_line_width)?;
+ wrap_struct_field(context, attrs, &fields_str, shape, v_shape, one_line_width)?;
Some(format!("{} {{{}}}", path_str, fields_str))
// FIXME if context.config.indent_style() == Visual, but we run out
shape: Shape,
rhs_tactics: RhsTactics,
) -> Option<String> {
- let last_line_width = last_line_width(&lhs).saturating_sub(if lhs.contains('\n') {
+ let last_line_width = last_line_width(lhs).saturating_sub(if lhs.contains('\n') {
shape.indent.width()
} else {
0
if contains_comment {
let rhs = rhs.trim_start();
- combine_strs_with_missing_comments(context, &lhs, &rhs, between_span, shape, allow_extend)
+ combine_strs_with_missing_comments(context, &lhs, rhs, between_span, shape, allow_extend)
} else {
Some(lhs + &rhs)
}
has_rhs_comment: bool,
) -> Option<String> {
match orig_rhs {
+ Some(ref new_str) if new_str.is_empty() => {
+ return Some(String::new());
+ }
Some(ref new_str)
if !new_str.contains('\n') && unicode_str_width(new_str) <= shape.width =>
{
}
fn main() {
- env_logger::init();
+ env_logger::Builder::from_env("RUSTFMT_LOG").init();
let opts = Opts::from_args();
if let Err(e) = run(opts) {
println!("{}", e);
let snippet_provider = self.parse_session.snippet_provider(module.span);
let mut visitor = FmtVisitor::from_parse_sess(
&self.parse_session,
- &self.config,
+ self.config,
&snippet_provider,
self.report.clone(),
);
&mut visitor.buffer,
&path,
&visitor.skipped_range.borrow(),
- &self.config,
+ self.config,
&self.report,
);
}
fn main() {
- env_logger::init();
+ env_logger::Builder::from_env("RUSTFMT_LOG").init();
let opts = make_opts();
let matches = opts
shape: Shape,
) -> Option<String> {
let vis = self.visibility.as_ref().map_or(Cow::from(""), |vis| {
- crate::utils::format_visibility(context, &vis)
+ crate::utils::format_visibility(context, vis)
});
let use_str = self
.rewrite(context, shape.offset_left(vis.len())?)
fn rewrite(&self, context: &RewriteContext<'_>, mut shape: Shape) -> Option<String> {
let mut result = String::with_capacity(256);
let mut iter = self.path.iter().peekable();
- while let Some(ref segment) = iter.next() {
+ while let Some(segment) = iter.next() {
let segment_str = segment.rewrite(context, shape)?;
result.push_str(&segment_str);
if iter.peek().is_some() {
fn to_str(&self, context: &RewriteContext<'_>) -> String {
let mut result = String::with_capacity(128);
// Vis defaultness constness unsafety abi.
- result.push_str(&*format_visibility(context, &self.visibility));
+ result.push_str(&*format_visibility(context, self.visibility));
result.push_str(format_defaultness(self.defaultness));
result.push_str(format_constness(self.constness));
result.push_str(format_async(&self.is_async));
fn need_empty_line(a: &ast::AssocItemKind, b: &ast::AssocItemKind) -> bool {
match (a, b) {
(TyAlias(lty), TyAlias(rty))
- if both_type(<y.3, &rty.3) || both_opaque(<y.3, &rty.3) =>
+ if both_type(<y.ty, &rty.ty) || both_opaque(<y.ty, &rty.ty) =>
{
false
}
buffer.sort_by(|(_, a), (_, b)| match (&a.kind, &b.kind) {
(TyAlias(lty), TyAlias(rty))
- if both_type(<y.3, &rty.3) || both_opaque(<y.3, &rty.3) =>
+ if both_type(<y.ty, &rty.ty) || both_opaque(<y.ty, &rty.ty) =>
{
a.ident.as_str().cmp(&b.ident.as_str())
}
a.ident.as_str().cmp(&b.ident.as_str())
}
(Fn(..), Fn(..)) => a.span.lo().cmp(&b.span.lo()),
- (TyAlias(ty), _) if is_type(&ty.3) => Ordering::Less,
- (_, TyAlias(ty)) if is_type(&ty.3) => Ordering::Greater,
+ (TyAlias(ty), _) if is_type(&ty.ty) => Ordering::Less,
+ (_, TyAlias(ty)) if is_type(&ty.ty) => Ordering::Greater,
(TyAlias(..), _) => Ordering::Less,
(_, TyAlias(..)) => Ordering::Greater,
(Const(..), _) => Ordering::Less,
offset: Indent,
) -> Option<String> {
if let ast::ItemKind::Impl(impl_kind) = &item.kind {
- let ast::ImplKind {
+ let ast::Impl {
ref generics,
ref self_ty,
ref items,
offset: Indent,
) -> Option<String> {
if let ast::ItemKind::Impl(impl_kind) = &item.kind {
- let ast::ImplKind {
+ let ast::Impl {
unsafety,
polarity,
defaultness,
offset: Indent,
) -> Option<String> {
if let ast::ItemKind::Trait(trait_kind) = &item.kind {
- let ast::TraitKind(is_auto, unsafety, ref generics, ref generic_bounds, ref trait_items) =
- **trait_kind;
+ let ast::Trait {
+ is_auto,
+ unsafety,
+ ref generics,
+ ref bounds,
+ ref items,
+ } = **trait_kind;
let mut result = String::with_capacity(128);
let header = format!(
"{}{}{}trait ",
result.push_str(&generics_str);
// FIXME(#2055): rustfmt fails to format when there are comments between trait bounds.
- if !generic_bounds.is_empty() {
+ if !bounds.is_empty() {
let ident_hi = context
.snippet_provider
.span_after(item.span, &item.ident.as_str());
- let bound_hi = generic_bounds.last().unwrap().span().hi();
+ let bound_hi = bounds.last().unwrap().span().hi();
let snippet = context.snippet(mk_sp(ident_hi, bound_hi));
if contains_comment(snippet) {
return None;
result = rewrite_assign_rhs_with(
context,
result + ":",
- generic_bounds,
+ bounds,
shape,
RhsTactics::ForceNextLineWithoutIndent,
)?;
let where_on_new_line = context.config.indent_style() != IndentStyle::Block;
let where_budget = context.budget(last_line_width(&result));
- let pos_before_where = if generic_bounds.is_empty() {
+ let pos_before_where = if bounds.is_empty() {
generics.where_clause.span.lo()
} else {
- generic_bounds[generic_bounds.len() - 1].span().hi()
+ bounds[bounds.len() - 1].span().hi()
};
let option = WhereClauseOption::snuggled(&generics_str);
let where_clause_str = rewrite_where_clause(
}
}
+ let block_span = mk_sp(generics.where_clause.span.hi(), item.span.hi());
+ let snippet = context.snippet(block_span);
+ let open_pos = snippet.find_uncommented("{")? + 1;
+
match context.config.brace_style() {
_ if last_line_contains_single_line_comment(&result)
|| last_line_width(&result) + 2 > context.budget(offset.width()) =>
{
result.push_str(&offset.to_string_with_newline(context.config));
}
+ _ if context.config.empty_item_single_line()
+ && items.is_empty()
+ && !result.contains('\n')
+ && !contains_comment(&snippet[open_pos..]) =>
+ {
+ result.push_str(" {}");
+ return Some(result);
+ }
BraceStyle::AlwaysNextLine => {
result.push_str(&offset.to_string_with_newline(context.config));
}
BraceStyle::PreferSameLine => result.push(' '),
BraceStyle::SameLineWhere => {
if result.contains('\n')
- || (!generics.where_clause.predicates.is_empty() && !trait_items.is_empty())
+ || (!generics.where_clause.predicates.is_empty() && !items.is_empty())
{
result.push_str(&offset.to_string_with_newline(context.config));
} else {
}
result.push('{');
- let block_span = mk_sp(generics.where_clause.span.hi(), item.span.hi());
- let snippet = context.snippet(block_span);
- let open_pos = snippet.find_uncommented("{")? + 1;
let outer_indent_str = offset.block_only().to_string_with_newline(context.config);
- if !trait_items.is_empty() || contains_comment(&snippet[open_pos..]) {
+ if !items.is_empty() || contains_comment(&snippet[open_pos..]) {
let mut visitor = FmtVisitor::from_context(context);
visitor.block_indent = offset.block_only().block_indent(context.config);
visitor.last_pos = block_span.lo() + BytePos(open_pos as u32);
- for item in trait_items {
+ for item in items {
visitor.visit_trait_item(item);
}
}
}
-struct OpaqueTypeBounds<'a> {
- generic_bounds: &'a ast::GenericBounds,
-}
-
-impl<'a> Rewrite for OpaqueTypeBounds<'a> {
- fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
- self.generic_bounds
- .rewrite(context, shape)
- .map(|s| format!("impl {}", s))
- }
-}
-
pub(crate) struct TraitAliasBounds<'a> {
generic_bounds: &'a ast::GenericBounds,
generics: &'a ast::Generics,
} else if fits_single_line {
Cow::from(" ")
} else {
- shape.indent.to_string_with_newline(&context.config)
+ shape.indent.to_string_with_newline(context.config)
};
Some(format!("{}{}{}", generic_bounds_str, space, where_str))
let alias = rewrite_ident(context, ident);
// 6 = "trait ", 2 = " ="
let g_shape = shape.offset_left(6)?.sub_width(2)?;
- let generics_str = rewrite_generics(context, &alias, generics, g_shape)?;
+ let generics_str = rewrite_generics(context, alias, generics, g_shape)?;
let vis_str = format_visibility(context, vis);
let lhs = format!("{}trait {} =", vis_str, generics_str);
// 1 = ";"
closer: &str,
) {
// 3 = " {}" or "();"
- let used_width = last_line_used_width(&result, offset.width()) + 3;
+ let used_width = last_line_used_width(result, offset.width()) + 3;
if used_width > context.config.max_width() {
result.push_str(&offset.to_string_with_newline(context.config))
}
Some(result)
}
-pub(crate) fn rewrite_type<R: Rewrite>(
- context: &RewriteContext<'_>,
+pub(crate) enum ItemVisitorKind<'a> {
+ Item(&'a ast::Item),
+ AssocTraitItem(&'a ast::AssocItem),
+ AssocImplItem(&'a ast::AssocItem),
+ ForeignItem(&'a ast::ForeignItem),
+}
+
+struct TyAliasRewriteInfo<'c, 'g>(
+ &'c RewriteContext<'c>,
+ Indent,
+ &'g ast::Generics,
+ symbol::Ident,
+ Span,
+);
+
+pub(crate) fn rewrite_type_alias<'a, 'b>(
+ ty_alias_kind: &ast::TyAlias,
+ context: &RewriteContext<'a>,
indent: Indent,
- ident: symbol::Ident,
- vis: &ast::Visibility,
- generics: &ast::Generics,
+ visitor_kind: &ItemVisitorKind<'b>,
+ span: Span,
+) -> Option<String> {
+ use ItemVisitorKind::*;
+
+ let ast::TyAlias {
+ defaultness,
+ ref generics,
+ ref bounds,
+ ref ty,
+ } = *ty_alias_kind;
+ let ty_opt = ty.as_ref().map(|t| &**t);
+ let (ident, vis) = match visitor_kind {
+ Item(i) => (i.ident, &i.vis),
+ AssocTraitItem(i) | AssocImplItem(i) => (i.ident, &i.vis),
+ ForeignItem(i) => (i.ident, &i.vis),
+ };
+ let rw_info = &TyAliasRewriteInfo(context, indent, generics, ident, span);
+
+ // Type Aliases are formatted slightly differently depending on the context
+ // in which they appear, whether they are opaque, and whether they are associated.
+ // https://rustc-dev-guide.rust-lang.org/opaque-types-type-alias-impl-trait.html
+ // https://github.com/rust-dev-tools/fmt-rfcs/blob/master/guide/items.md#type-aliases
+ match (visitor_kind, ty_opt) {
+ (Item(_), None) => {
+ let op_ty = OpaqueType { bounds };
+ rewrite_ty(rw_info, Some(bounds), Some(&op_ty), vis)
+ }
+ (Item(_), Some(ty)) => rewrite_ty(rw_info, Some(bounds), Some(&*ty), vis),
+ (AssocImplItem(_), _) => {
+ let result = if let Some(ast::Ty {
+ kind: ast::TyKind::ImplTrait(_, ref bounds),
+ ..
+ }) = ty_opt
+ {
+ let op_ty = OpaqueType { bounds };
+ rewrite_ty(rw_info, None, Some(&op_ty), &DEFAULT_VISIBILITY)
+ } else {
+ rewrite_ty(rw_info, None, ty.as_ref(), vis)
+ }?;
+ match defaultness {
+ ast::Defaultness::Default(..) => Some(format!("default {}", result)),
+ _ => Some(result),
+ }
+ }
+ (AssocTraitItem(_), _) | (ForeignItem(_), _) => {
+ rewrite_ty(rw_info, Some(bounds), ty.as_ref(), vis)
+ }
+ }
+}
+
+fn rewrite_ty<R: Rewrite>(
+ rw_info: &TyAliasRewriteInfo<'_, '_>,
generic_bounds_opt: Option<&ast::GenericBounds>,
rhs: Option<&R>,
- span: Span,
+ vis: &ast::Visibility,
) -> Option<String> {
let mut result = String::with_capacity(128);
+ let TyAliasRewriteInfo(context, indent, generics, ident, span) = *rw_info;
result.push_str(&format!("{}type ", format_visibility(context, vis)));
let ident_str = rewrite_ident(context, ident);
}
}
-pub(crate) fn rewrite_opaque_type(
- context: &RewriteContext<'_>,
- indent: Indent,
- ident: symbol::Ident,
- generic_bounds: &ast::GenericBounds,
- generics: &ast::Generics,
- vis: &ast::Visibility,
- span: Span,
-) -> Option<String> {
- let opaque_type_bounds = OpaqueTypeBounds { generic_bounds };
- rewrite_type(
- context,
- indent,
- ident,
- vis,
- generics,
- Some(generic_bounds),
- Some(&opaque_type_bounds),
- span,
- )
-}
-
fn type_annotation_spacing(config: &Config) -> (&str, &str) {
(
if config.space_before_colon() { " " } else { "" },
}
}
-pub(crate) fn rewrite_impl_type(
- ident: symbol::Ident,
- vis: &ast::Visibility,
- defaultness: ast::Defaultness,
- ty_opt: Option<&ptr::P<ast::Ty>>,
- generics: &ast::Generics,
- context: &RewriteContext<'_>,
- indent: Indent,
- span: Span,
-) -> Option<String> {
- // Opaque type
- let result = if let Some(rustc_ast::ast::Ty {
- kind: ast::TyKind::ImplTrait(_, ref bounds),
- ..
- }) = ty_opt.map(|t| &**t)
- {
- rewrite_type(
- context,
- indent,
- ident,
- &DEFAULT_VISIBILITY,
- generics,
- None,
- Some(&OpaqueType { bounds }),
- span,
- )
- } else {
- rewrite_type(context, indent, ident, vis, generics, None, ty_opt, span)
- }?;
-
- match defaultness {
- ast::Defaultness::Default(..) => Some(format!("default {}", result)),
- _ => Some(result),
- }
-}
-
impl Rewrite for ast::FnRetTy {
fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
match *self {
)?;
Some(combine_strs_with_missing_comments(
context,
- ¶m_attrs,
+ param_attrs,
&format!("&{} {}self", lifetime_str, mut_str),
span,
shape,
}
None => Some(combine_strs_with_missing_comments(
context,
- ¶m_attrs,
+ param_attrs,
&format!("&{}self", mut_str),
span,
shape,
Some(combine_strs_with_missing_comments(
context,
- ¶m_attrs,
+ param_attrs,
&format!("{}self: {}", format_mutability(mutability), type_str),
span,
shape,
}
ast::SelfKind::Value(mutability) => Some(combine_strs_with_missing_comments(
context,
- ¶m_attrs,
+ param_attrs,
&format!("{}self", format_mutability(mutability)),
span,
shape,
}
// Skip `pub(crate)`.
- let lo_after_visibility = get_bytepos_after_visibility(&fn_sig.visibility, span);
+ let lo_after_visibility = get_bytepos_after_visibility(fn_sig.visibility, span);
// A conservative estimation, the goal is to be over all parens in generics
let params_start = fn_sig
.generics
let mut result = String::with_capacity(128);
let shape = Shape::indented(offset, context.config);
- result.push_str(&format_visibility(context, vis).trim());
+ result.push_str(format_visibility(context, vis).trim());
// Check for a missing comment between the visibility and the item name.
let after_vis = vis.span.hi();
}
}
- result.push_str(&rewrite_ident(context, ident));
+ result.push_str(rewrite_ident(context, ident));
result
}
let item_str = match self.kind {
ast::ForeignItemKind::Fn(ref fn_kind) => {
- let ast::FnKind(defaultness, ref fn_sig, ref generics, ref block) = **fn_kind;
- if let Some(ref body) = block {
+ let ast::Fn {
+ defaultness,
+ ref sig,
+ ref generics,
+ ref body,
+ } = **fn_kind;
+ if let Some(ref body) = body {
let mut visitor = FmtVisitor::from_context(context);
visitor.block_indent = shape.indent;
visitor.last_pos = self.span.lo();
let inner_attrs = inner_attributes(&self.attrs);
let fn_ctxt = visit::FnCtxt::Foreign;
visitor.visit_fn(
- visit::FnKind::Fn(fn_ctxt, self.ident, &fn_sig, &self.vis, Some(body)),
+ visit::FnKind::Fn(fn_ctxt, self.ident, &sig, &self.vis, Some(body)),
generics,
- &fn_sig.decl,
+ &sig.decl,
self.span,
defaultness,
Some(&inner_attrs),
context,
shape.indent,
self.ident,
- &FnSig::from_method_sig(&fn_sig, generics, &self.vis),
+ &FnSig::from_method_sig(&sig, generics, &self.vis),
span,
FnBraceStyle::None,
)
// 1 = ;
rewrite_assign_rhs(context, prefix, &**ty, shape.sub_width(1)?).map(|s| s + ";")
}
- ast::ForeignItemKind::TyAlias(ref ty_alias_kind) => {
- let ast::TyAliasKind(_, ref generics, ref generic_bounds, ref type_default) =
- **ty_alias_kind;
- rewrite_type(
- &context,
- shape.indent,
- self.ident,
- &self.vis,
- generics,
- Some(generic_bounds),
- type_default.as_ref(),
- self.span,
- )
+ ast::ForeignItemKind::TyAlias(ref ty_alias) => {
+ let (kind, span) = (&ItemVisitorKind::ForeignItem(&self), self.span);
+ rewrite_type_alias(ty_alias, context, shape.indent, kind, span)
}
ast::ForeignItemKind::MacCall(ref mac) => {
rewrite_macro(mac, None, context, shape, MacroPosition::Item)
combine_strs_with_missing_comments(
context,
&attrs_str,
- &item_str,
+ item_str,
missed_span,
shape,
allow_extend,
writeln!(
t,
"{}",
- FormatReportFormatterBuilder::new(&self)
+ FormatReportFormatterBuilder::new(self)
.enable_colors(true)
.build()
)?;
impl fmt::Display for FormatReport {
// Prints all the formatting errors.
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
- write!(fmt, "{}", FormatReportFormatterBuilder::new(&self).build())?;
+ write!(fmt, "{}", FormatReportFormatterBuilder::new(self).build())?;
Ok(())
}
}
result.push('\n');
result.push_str(indent_str);
// This is the width of the item (without comments).
- line_len = item.item.as_ref().map_or(0, |s| unicode_str_width(&s));
+ line_len = item.item.as_ref().map_or(0, |s| unicode_str_width(s));
}
} else {
result.push(' ')
pub(crate) fn total_item_width(item: &ListItem) -> usize {
comment_len(item.pre_comment.as_ref().map(|x| &(*x)[..]))
+ comment_len(item.post_comment.as_ref().map(|x| &(*x)[..]))
- + item.item.as_ref().map_or(0, |s| unicode_str_width(&s))
+ + item.item.as_ref().map_or(0, |s| unicode_str_width(s))
}
fn comment_len(comment: Option<&str>) -> usize {
})
.unwrap_or(false);
if is_like_block_indent_style {
- return trim_left_preserve_layout(context.snippet(span), indent, &context.config);
+ return trim_left_preserve_layout(context.snippet(span), indent, context.config);
}
context.skipped_range.borrow_mut().push((
// the `macro_name!` and `{ /* macro_body */ }` but skip modifying
// anything in between the braces (for now).
let snippet = context.snippet(mac.span()).trim_start_matches(|c| c != '{');
- match trim_left_preserve_layout(snippet, shape.indent, &context.config) {
+ match trim_left_preserve_layout(snippet, shape.indent, context.config) {
Some(macro_body) => Some(format!("{} {}", macro_name, macro_body)),
None => Some(format!("{} {}", macro_name, snippet)),
}
break;
}
TokenTree::Token(ref t) => {
- buffer.push_str(&pprust::token_to_string(&t));
+ buffer.push_str(&pprust::token_to_string(t));
}
_ => return None,
}
let mut iter = args.iter().peekable();
let indent_str = shape.indent.to_string_with_newline(context.config);
- while let Some(ref arg) = iter.next() {
+ while let Some(arg) = iter.next() {
result.push_str(&arg.rewrite(context, shape, use_multiple_lines)?);
if use_multiple_lines
result.pop();
}
result.push_str(&indent_str);
- } else if let Some(ref next_arg) = iter.peek() {
+ } else if let Some(next_arg) = iter.peek() {
let space_before_dollar =
!arg.kind.ends_with_space() && next_arg.kind.starts_with_dollar();
let space_before_brace = next_arg.kind.starts_with_brace();
{
s += &indent_str;
}
- (s + l + "\n", indent_next_line(kind, &l, &config))
+ (s + l + "\n", indent_next_line(kind, l, &config))
},
)
.0;
MacroArg::Item(item) => item,
_ => return None,
};
- visitor.visit_item(&item);
+ visitor.visit_item(item);
}
let mut result = String::with_capacity(256);
- result.push_str(¯o_name);
+ result.push_str(macro_name);
result.push_str(opener);
result.push_str(&visitor.block_indent.to_string_with_newline(context.config));
result.push_str(visitor.buffer.trim());
.map(|a| {
context
.snippet(a.pat.span)
- .starts_with("|")
+ .starts_with('|')
.then(|| a.pat.span().lo())
})
.collect()
let can_extend =
|expr| !context.config.force_multiline_blocks() && can_flatten_block_around_this(expr);
- if let Some(ref block) = block_can_be_flattened(context, body) {
+ if let Some(block) = block_can_be_flattened(context, body) {
if let ast::StmtKind::Expr(ref expr) = block.stmts[0].kind {
if let ast::ExprKind::Block(..) = expr.kind {
flatten_arm_body(context, expr, None)
if comment_str.is_empty() {
String::new()
} else {
- rewrite_comment(comment_str, false, shape, &context.config)?
+ rewrite_comment(comment_str, false, shape, context.config)?
}
};
result.push_str(&arrow_comment);
}
result.push_str(&nested_indent_str);
- result.push_str(&body_str);
- result.push_str(&comma);
+ result.push_str(body_str);
+ result.push_str(comma);
return Some(result);
}
result.push_str(&arrow_comment);
}
result.push_str(&block_sep);
- result.push_str(&body_str);
+ result.push_str(body_str);
result.push_str(&body_suffix);
Some(result)
};
Directory, DirectoryOwnership, ModError, ModulePathSuccess, Parser, ParserError,
};
use crate::syntux::session::ParseSess;
-use crate::utils::contains_skip;
+use crate::utils::{contains_skip, mk_sp};
mod visitor;
self.visit_mod_from_ast(&krate.items)?;
}
+ let snippet_provider = self.parse_sess.snippet_provider(krate.span);
+
self.file_map.insert(
root_filename,
Module::new(
- krate.span,
+ mk_sp(snippet_provider.start_pos(), snippet_provider.end_pos()),
None,
Cow::Borrowed(&krate.items),
Cow::Borrowed(&krate.attrs),
/// Visit modules from AST.
fn visit_mod_from_ast(
&mut self,
- items: &'ast Vec<rustc_ast::ptr::P<ast::Item>>,
+ items: &'ast [rustc_ast::ptr::P<ast::Item>],
) -> Result<(), ModuleResolutionError> {
for item in items {
if is_cfg_if(item) {
};
self.visit_sub_mod_after_directory_update(sub_mod, Some(directory))
}
- SubModKind::Internal(ref item) => {
+ SubModKind::Internal(item) => {
self.push_inline_mod_directory(item.ident, &item.attrs);
self.visit_sub_mod_after_directory_update(sub_mod, None)
}
}
match (sub_mod.ast_mod_kind, sub_mod.items) {
(Some(Cow::Borrowed(ast::ModKind::Loaded(items, _, _))), _) => {
- self.visit_mod_from_ast(&items)
+ self.visit_mod_from_ast(items)
+ }
+ (Some(Cow::Owned(ast::ModKind::Loaded(items, _, _))), _) | (_, Cow::Owned(items)) => {
+ self.visit_mod_outside_ast(items)
}
- (Some(Cow::Owned(..)), Cow::Owned(items)) => self.visit_mod_outside_ast(items),
(_, _) => Ok(()),
}
}
) -> Option<String> {
let last_item = self.last_item()?;
let rewrite = match last_item {
- OverflowableItem::Expr(ref expr) => {
+ OverflowableItem::Expr(expr) => {
match expr.kind {
// When overflowing the closure which consists of a single control flow
// expression, force to use block if its condition uses multi line.
for ((_, rewrite), s) in list.list.iter().zip(list.separators.iter()) {
if let Some(rewrite) = rewrite {
- if !is_single_line(&rewrite) || result.len() > shape.width {
+ if !is_single_line(rewrite) || result.len() > shape.width {
return None;
}
- result.push_str(&rewrite);
+ result.push_str(rewrite);
result.push(' ');
result.push_str(s);
result.push(' ');
shape: Shape,
context: &RewriteContext<'_>,
) -> Option<String> {
- let rhs_offset = shape.rhs_overhead(&context.config);
+ let rhs_offset = shape.rhs_overhead(context.config);
let nested_shape = (match context.config.indent_style() {
IndentStyle::Visual => shape.visual_indent(0),
IndentStyle::Block => shape.block_indent(context.config.tab_spaces()),
})
- .with_max_width(&context.config)
+ .with_max_width(context.config)
.sub_width(rhs_offset)?;
let indent_str = nested_shape.indent.to_string_with_newline(context.config);
let mut result = String::new();
- result.push_str(&list.list[0].1.as_ref()?);
+ result.push_str(list.list[0].1.as_ref()?);
for ((e, default_rw), s) in list.list[1..].iter().zip(list.separators.iter()) {
// The following test checks if we should keep two subexprs on the same
}
}
- result.push_str(&default_rw.as_ref()?);
+ result.push_str(default_rw.as_ref()?);
}
Some(result)
}
return node.rewrite(context, shape);
}
let nested_overhead = sep + 1;
- let rhs_offset = shape.rhs_overhead(&context.config);
+ let rhs_offset = shape.rhs_overhead(context.config);
let nested_shape = (match context.config.indent_style() {
IndentStyle::Visual => shape.visual_indent(0),
IndentStyle::Block => shape.block_indent(context.config.tab_spaces()),
})
- .with_max_width(&context.config)
+ .with_max_width(context.config)
.sub_width(rhs_offset)?;
let default_shape = match context.config.binop_separator() {
SeparatorPlace::Back => nested_shape.sub_width(nested_overhead)?,
context: &RewriteContext<'_>,
shape: Shape,
) -> Option<String> {
- let mut pat_vec: Vec<_> = pats.iter().map(|x| TuplePatField::Pat(x)).collect();
-
- if pat_vec.is_empty() {
+ if pats.is_empty() {
return Some(format!("{}()", path_str.unwrap_or_default()));
}
+ let mut pat_vec: Vec<_> = pats.iter().map(TuplePatField::Pat).collect();
+
let wildcard_suffix_len = count_wildcard_suffix_len(context, &pat_vec, span, shape);
let (pat_vec, span) = if context.config.condense_wildcard_suffixes() && wildcard_suffix_len >= 2
{
let path_str = path_str.unwrap_or_default();
overflow::rewrite_with_parens(
- &context,
+ context,
&path_str,
pat_vec.iter(),
shape,
};
let mut regrouped_items = match context.config.group_imports() {
- GroupImportsTactic::Preserve => vec![normalized_items],
+ GroupImportsTactic::Preserve | GroupImportsTactic::One => {
+ vec![normalized_items]
+ }
GroupImportsTactic::StdExternalCrate => group_imports(normalized_items),
};
span: Span,
) -> Result<(Vec<ast::Attribute>, Vec<ptr::P<ast::Item>>, Span), ParserError> {
let result = catch_unwind(AssertUnwindSafe(|| {
- let mut parser = new_parser_from_file(sess.inner(), &path, Some(span));
+ let mut parser = new_parser_from_file(sess.inner(), path, Some(span));
match parser.parse_mod(&TokenKind::Eof) {
Ok(result) => Some(result),
Err(mut e) => {
}
}));
match result {
- Ok(Some(m)) => {
- if !sess.has_errors() {
- return Ok(m);
- }
-
- if sess.can_reset_errors() {
- sess.reset_errors();
- return Ok(m);
- }
- Err(ParserError::ParseError)
+ Ok(Some(m)) if !sess.has_errors() => Ok(m),
+ Ok(Some(m)) if sess.can_reset_errors() => {
+ sess.reset_errors();
+ Ok(m)
}
- Ok(None) => Err(ParserError::ParseError),
+ Ok(_) => Err(ParserError::ParseError),
Err(..) if path.exists() => Err(ParserError::ParseError),
Err(_) => Err(ParserError::ParsePanicError),
}
}
pub(crate) fn ignore_file(&self, path: &FileName) -> bool {
- self.ignore_path_set.as_ref().is_match(&path)
+ self.ignore_path_set.as_ref().is_match(path)
}
pub(crate) fn set_silent_emitter(&mut self) {
debug!("Testing '{}'...", file_name.display());
- match idempotent_check(&file_name, &opt_config) {
+ match idempotent_check(&file_name, opt_config) {
Ok(ref report) if report.has_warnings() => {
- print!("{}", FormatReportFormatterBuilder::new(&report).build());
+ print!("{}", FormatReportFormatterBuilder::new(report).build());
fails += 1;
}
Ok(report) => reports.push(report),
use crate::{FileName, Input, Session};
-#[test]
-fn nested_out_of_line_mods_loaded() {
- // See also https://github.com/rust-lang/rustfmt/issues/4874
- let filename = "tests/mod-resolver/issue-4874/main.rs";
- let input_file = PathBuf::from(filename);
+fn verify_mod_resolution(input_file_name: &str, exp_misformatted_files: &[&str]) {
+ let input_file = PathBuf::from(input_file_name);
let config = read_config(&input_file);
let mut session = Session::<io::Stdout>::new(config, None);
let report = session
- .format(Input::File(filename.into()))
+ .format(Input::File(input_file_name.into()))
.expect("Should not have had any execution errors");
let errors_by_file = &report.internal.borrow().0;
- assert!(errors_by_file.contains_key(&FileName::Real(PathBuf::from(
- "tests/mod-resolver/issue-4874/bar/baz.rs",
- ))));
- assert!(errors_by_file.contains_key(&FileName::Real(PathBuf::from(
- "tests/mod-resolver/issue-4874/foo/qux.rs",
- ))));
+ for exp_file in exp_misformatted_files {
+ assert!(errors_by_file.contains_key(&FileName::Real(PathBuf::from(exp_file))));
+ }
+}
+
+#[test]
+fn nested_out_of_line_mods_loaded() {
+ // See also https://github.com/rust-lang/rustfmt/issues/4874
+ verify_mod_resolution(
+ "tests/mod-resolver/issue-4874/main.rs",
+ &[
+ "tests/mod-resolver/issue-4874/bar/baz.rs",
+ "tests/mod-resolver/issue-4874/foo/qux.rs",
+ ],
+ );
+}
+
+#[test]
+fn out_of_line_nested_inline_within_out_of_line() {
+ // See also https://github.com/rust-lang/rustfmt/issues/5063
+ verify_mod_resolution(
+ "tests/mod-resolver/issue-5063/main.rs",
+ &[
+ "tests/mod-resolver/issue-5063/foo/bar/baz.rs",
+ "tests/mod-resolver/issue-5063/foo.rs",
+ ],
+ );
}
result = combine_strs_with_missing_comments(
context,
result.trim_end(),
- &mt.ty.rewrite(&context, shape)?,
+ &mt.ty.rewrite(context, shape)?,
before_ty_span,
shape,
true,
let budget = shape.width.checked_sub(used_width)?;
let ty_str = mt
.ty
- .rewrite(&context, Shape::legacy(budget, shape.indent + used_width))?;
+ .rewrite(context, Shape::legacy(budget, shape.indent + used_width))?;
result.push_str(&ty_str);
}
(
VisibilityKind::Restricted { path: p, .. },
VisibilityKind::Restricted { path: q, .. },
- ) => pprust::path_to_string(&p) == pprust::path_to_string(&q),
+ ) => pprust::path_to_string(p) == pprust::path_to_string(q),
(VisibilityKind::Public, VisibilityKind::Public)
| (VisibilityKind::Inherited, VisibilityKind::Inherited)
| (
#[test]
fn test_remove_trailing_white_spaces() {
let s = " r#\"\n test\n \"#";
- assert_eq!(remove_trailing_white_spaces(&s), s);
+ assert_eq!(remove_trailing_white_spaces(s), s);
}
#[test]
let config = Config::default();
let indent = Indent::new(4, 0);
assert_eq!(
- trim_left_preserve_layout(&s, indent, &config),
+ trim_left_preserve_layout(s, indent, &config),
Some("aaa\n bbb\n ccc".to_string())
);
}
use crate::coverage::transform_missing_snippet;
use crate::items::{
format_impl, format_trait, format_trait_alias, is_mod_decl, is_use_item, rewrite_extern_crate,
- rewrite_impl_type, rewrite_opaque_type, rewrite_type, FnBraceStyle, FnSig, StaticParts,
- StructParts,
+ rewrite_type_alias, FnBraceStyle, FnSig, ItemVisitorKind, StaticParts, StructParts,
};
use crate::macros::{macro_style, rewrite_macro, rewrite_macro_def, MacroPosition};
use crate::modules::Module;
);
} else {
let shape = self.shape();
- let rewrite = self.with_context(|ctx| stmt.rewrite(&ctx, shape));
+ let rewrite = self.with_context(|ctx| stmt.rewrite(ctx, shape));
self.push_rewrite(stmt.span(), rewrite)
}
}
let comment_snippet = self.snippet(span);
- let align_to_right = if unindent_comment && contains_comment(&comment_snippet) {
+ let align_to_right = if unindent_comment && contains_comment(comment_snippet) {
let first_lines = comment_snippet.splitn(2, '/').next().unwrap_or("");
- last_line_width(first_lines) > last_line_width(&comment_snippet)
+ last_line_width(first_lines) > last_line_width(comment_snippet)
} else {
false
};
let filtered_attrs;
let mut attrs = &item.attrs;
let skip_context_saved = self.skip_context.clone();
- self.skip_context.update_with_attrs(&attrs);
+ self.skip_context.update_with_attrs(attrs);
let should_visit_node_again = match item.kind {
// For use/extern crate items, skip rewriting attributes but check for a skip attribute.
ast::ItemKind::Use(ref tree) => self.format_import(item, tree),
ast::ItemKind::Impl { .. } => {
let block_indent = self.block_indent;
- let rw = self.with_context(|ctx| format_impl(&ctx, item, block_indent));
+ let rw = self.with_context(|ctx| format_impl(ctx, item, block_indent));
self.push_rewrite(item.span, rw);
}
ast::ItemKind::Trait(..) => {
let block_indent = self.block_indent;
- let rw = self.with_context(|ctx| format_trait(&ctx, item, block_indent));
+ let rw = self.with_context(|ctx| format_trait(ctx, item, block_indent));
self.push_rewrite(item.span, rw);
}
ast::ItemKind::TraitAlias(ref generics, ref generic_bounds) => {
self.visit_static(&StaticParts::from_item(item));
}
ast::ItemKind::Fn(ref fn_kind) => {
- let ast::FnKind(defaultness, ref fn_signature, ref generics, ref block) =
- **fn_kind;
- if let Some(ref body) = block {
+ let ast::Fn {
+ defaultness,
+ ref sig,
+ ref generics,
+ ref body,
+ } = **fn_kind;
+ if let Some(ref body) = body {
let inner_attrs = inner_attributes(&item.attrs);
- let fn_ctxt = match fn_signature.header.ext {
+ let fn_ctxt = match sig.header.ext {
ast::Extern::None => visit::FnCtxt::Free,
_ => visit::FnCtxt::Foreign,
};
self.visit_fn(
- visit::FnKind::Fn(
- fn_ctxt,
- item.ident,
- &fn_signature,
- &item.vis,
- Some(body),
- ),
+ visit::FnKind::Fn(fn_ctxt, item.ident, &sig, &item.vis, Some(body)),
generics,
- &fn_signature.decl,
+ &sig.decl,
item.span,
defaultness,
Some(&inner_attrs),
} else {
let indent = self.block_indent;
let rewrite = self.rewrite_required_fn(
- indent,
- item.ident,
- &fn_signature,
- &item.vis,
- generics,
- item.span,
+ indent, item.ident, &sig, &item.vis, generics, item.span,
);
self.push_rewrite(item.span, rewrite);
}
}
- ast::ItemKind::TyAlias(ref alias_kind) => {
- let ast::TyAliasKind(_, ref generics, ref generic_bounds, ref ty) =
- **alias_kind;
- match ty {
- Some(ty) => {
- let rewrite = rewrite_type(
- &self.get_context(),
- self.block_indent,
- item.ident,
- &item.vis,
- generics,
- Some(generic_bounds),
- Some(&*ty),
- item.span,
- );
- self.push_rewrite(item.span, rewrite);
- }
- None => {
- let rewrite = rewrite_opaque_type(
- &self.get_context(),
- self.block_indent,
- item.ident,
- generic_bounds,
- generics,
- &item.vis,
- item.span,
- );
- self.push_rewrite(item.span, rewrite);
- }
- }
+ ast::ItemKind::TyAlias(ref ty_alias) => {
+ use ItemVisitorKind::Item;
+ self.visit_ty_alias_kind(ty_alias, &Item(&item), item.span);
}
ast::ItemKind::GlobalAsm(..) => {
let snippet = Some(self.snippet(item.span).to_owned());
self.skip_context = skip_context_saved;
}
- pub(crate) fn visit_trait_item(&mut self, ti: &ast::AssocItem) {
- skip_out_of_file_lines_range_visitor!(self, ti.span);
+ fn visit_ty_alias_kind(
+ &mut self,
+ ty_kind: &ast::TyAlias,
+ visitor_kind: &ItemVisitorKind<'_>,
+ span: Span,
+ ) {
+ let rewrite = rewrite_type_alias(
+ ty_kind,
+ &self.get_context(),
+ self.block_indent,
+ visitor_kind,
+ span,
+ );
+ self.push_rewrite(span, rewrite);
+ }
+
+ fn visit_assoc_item(&mut self, visitor_kind: &ItemVisitorKind<'_>) {
+ use ItemVisitorKind::*;
+ // TODO(calebcartwright): Not sure the skip spans are correct
+ let (ai, skip_span, assoc_ctxt) = match visitor_kind {
+ AssocTraitItem(ai) => (*ai, ai.span(), visit::AssocCtxt::Trait),
+ AssocImplItem(ai) => (*ai, ai.span, visit::AssocCtxt::Impl),
+ _ => unreachable!(),
+ };
+ skip_out_of_file_lines_range_visitor!(self, ai.span);
- if self.visit_attrs(&ti.attrs, ast::AttrStyle::Outer) {
- self.push_skipped_with_span(ti.attrs.as_slice(), ti.span(), ti.span());
+ if self.visit_attrs(&ai.attrs, ast::AttrStyle::Outer) {
+ self.push_skipped_with_span(&ai.attrs.as_slice(), skip_span, skip_span);
return;
}
// TODO(calebcartwright): consider enabling box_patterns feature gate
- match ti.kind {
- ast::AssocItemKind::Const(..) => self.visit_static(&StaticParts::from_trait_item(ti)),
- ast::AssocItemKind::Fn(ref fn_kind) => {
- let ast::FnKind(defaultness, ref sig, ref generics, ref block) = **fn_kind;
- if let Some(ref body) = block {
- let inner_attrs = inner_attributes(&ti.attrs);
- let fn_ctxt = visit::FnCtxt::Assoc(visit::AssocCtxt::Trait);
+ match (&ai.kind, visitor_kind) {
+ (ast::AssocItemKind::Const(..), AssocTraitItem(_)) => {
+ self.visit_static(&StaticParts::from_trait_item(&ai))
+ }
+ (ast::AssocItemKind::Const(..), AssocImplItem(_)) => {
+ self.visit_static(&StaticParts::from_impl_item(&ai))
+ }
+ (ast::AssocItemKind::Fn(ref fn_kind), _) => {
+ let ast::Fn {
+ defaultness,
+ ref sig,
+ ref generics,
+ ref body,
+ } = **fn_kind;
+ if let Some(ref body) = body {
+ let inner_attrs = inner_attributes(&ai.attrs);
+ let fn_ctxt = visit::FnCtxt::Assoc(assoc_ctxt);
self.visit_fn(
- visit::FnKind::Fn(fn_ctxt, ti.ident, sig, &ti.vis, Some(body)),
+ visit::FnKind::Fn(fn_ctxt, ai.ident, sig, &ai.vis, Some(body)),
generics,
&sig.decl,
- ti.span,
+ ai.span,
defaultness,
Some(&inner_attrs),
);
} else {
let indent = self.block_indent;
let rewrite =
- self.rewrite_required_fn(indent, ti.ident, sig, &ti.vis, generics, ti.span);
- self.push_rewrite(ti.span, rewrite);
+ self.rewrite_required_fn(indent, ai.ident, sig, &ai.vis, generics, ai.span);
+ self.push_rewrite(ai.span, rewrite);
}
}
- ast::AssocItemKind::TyAlias(ref ty_alias_kind) => {
- let ast::TyAliasKind(_, ref generics, ref generic_bounds, ref type_default) =
- **ty_alias_kind;
- let rewrite = rewrite_type(
- &self.get_context(),
- self.block_indent,
- ti.ident,
- &ti.vis,
- generics,
- Some(generic_bounds),
- type_default.as_ref(),
- ti.span,
- );
- self.push_rewrite(ti.span, rewrite);
+ (ast::AssocItemKind::TyAlias(ref ty_alias), _) => {
+ self.visit_ty_alias_kind(ty_alias, visitor_kind, ai.span);
}
- ast::AssocItemKind::MacCall(ref mac) => {
- self.visit_mac(mac, Some(ti.ident), MacroPosition::Item);
+ (ast::AssocItemKind::MacCall(ref mac), _) => {
+ self.visit_mac(mac, Some(ai.ident), MacroPosition::Item);
}
+ _ => unreachable!(),
}
}
- pub(crate) fn visit_impl_item(&mut self, ii: &ast::AssocItem) {
- skip_out_of_file_lines_range_visitor!(self, ii.span);
-
- if self.visit_attrs(&ii.attrs, ast::AttrStyle::Outer) {
- self.push_skipped_with_span(ii.attrs.as_slice(), ii.span, ii.span);
- return;
- }
+ pub(crate) fn visit_trait_item(&mut self, ti: &ast::AssocItem) {
+ self.visit_assoc_item(&ItemVisitorKind::AssocTraitItem(ti));
+ }
- match ii.kind {
- ast::AssocItemKind::Fn(ref fn_kind) => {
- let ast::FnKind(defaultness, ref sig, ref generics, ref block) = **fn_kind;
- if let Some(ref body) = block {
- let inner_attrs = inner_attributes(&ii.attrs);
- let fn_ctxt = visit::FnCtxt::Assoc(visit::AssocCtxt::Impl);
- self.visit_fn(
- visit::FnKind::Fn(fn_ctxt, ii.ident, sig, &ii.vis, Some(body)),
- generics,
- &sig.decl,
- ii.span,
- defaultness,
- Some(&inner_attrs),
- );
- } else {
- let indent = self.block_indent;
- let rewrite =
- self.rewrite_required_fn(indent, ii.ident, sig, &ii.vis, generics, ii.span);
- self.push_rewrite(ii.span, rewrite);
- }
- }
- ast::AssocItemKind::Const(..) => self.visit_static(&StaticParts::from_impl_item(ii)),
- ast::AssocItemKind::TyAlias(ref ty_alias_kind) => {
- let ast::TyAliasKind(defaultness, ref generics, _, ref ty) = **ty_alias_kind;
- self.push_rewrite(
- ii.span,
- rewrite_impl_type(
- ii.ident,
- &ii.vis,
- defaultness,
- ty.as_ref(),
- &generics,
- &self.get_context(),
- self.block_indent,
- ii.span,
- ),
- );
- }
- ast::AssocItemKind::MacCall(ref mac) => {
- self.visit_mac(mac, Some(ii.ident), MacroPosition::Item);
- }
- }
+ pub(crate) fn visit_impl_item(&mut self, ii: &ast::AssocItem) {
+ self.visit_assoc_item(&ItemVisitorKind::AssocImplItem(ii));
}
fn visit_mac(&mut self, mac: &ast::MacCall, ident: Option<symbol::Ident>, pos: MacroPosition) {
}
fn walk_mod_items(&mut self, items: &[rustc_ast::ptr::P<ast::Item>]) {
- self.visit_items_with_reordering(&ptr_vec_to_ref_vec(&items));
+ self.visit_items_with_reordering(&ptr_vec_to_ref_vec(items));
}
fn walk_stmts(&mut self, stmts: &[Stmt<'_>], include_current_empty_semi: bool) {
--- /dev/null
+mod bar {
+ mod baz;}
\ No newline at end of file
--- /dev/null
+fn baz() { }
\ No newline at end of file
--- /dev/null
+fn main() {
+ println!("Hello, world!");
+}
+
+mod foo;
\ No newline at end of file
--- /dev/null
+// rustfmt-group_imports: One
+// rustfmt-imports_granularity: Crate
+use chrono::Utc;
+use super::update::convert_publish_payload;
+
+use juniper::{FieldError, FieldResult};
+use uuid::Uuid;
+use alloc::alloc::Layout;
+
+use std::sync::Arc;
+use alloc::vec::Vec;
+
+use broker::database::PooledConnection;
+
+use super::schema::{Context, Payload};
+use core::f32;
+use crate::models::Event;
--- /dev/null
+// rustfmt-group_imports: One
+mod test {
+ use crate::foo::bar;
+
+ use std::path;
+ use crate::foo::bar2;
+}
--- /dev/null
+// rustfmt-group_imports: One
+// rustfmt-reorder_imports: false
+use chrono::Utc;
+use super::update::convert_publish_payload;
+
+use juniper::{FieldError, FieldResult};
+use uuid::Uuid;
+use alloc::alloc::Layout;
+
+use std::sync::Arc;
+
+use broker::database::PooledConnection;
+
+use super::schema::{Context, Payload};
+use core::f32;
+use crate::models::Event;
--- /dev/null
+// rustfmt-group_imports: One
+use chrono::Utc;
+use super::update::convert_publish_payload;
+
+use juniper::{FieldError, FieldResult};
+use uuid::Uuid;
+use alloc::alloc::Layout;
+
+use std::sync::Arc;
+
+use broker::database::PooledConnection;
+
+use super::schema::{Context, Payload};
+use core::f32;
+use crate::models::Event;
--- /dev/null
+// rustfmt-brace_style: AlwaysNextLine
+// rustfmt-empty_item_single_line: false
+
+fn function()
+{
+
+}
+
+struct Struct
+{
+
+}
+
+enum Enum
+{
+
+}
+
+trait Trait
+{
+
+}
+
+impl<T> Trait for T
+{
+
+}
+
+trait Trait2<T>
+where
+ T: Copy + Display + Write + Read + FromStr, {}
+
+trait Trait3<T>
+where
+ T: Something
+ + SomethingElse
+ + Sync
+ + Send
+ + Display
+ + Debug
+ + Copy
+ + Hash
+ + Debug
+ + Display
+ + Write
+ + Read, {}
struct D<T> where T: Copy {}
}
+
+
+fn function()
+{
+
+}
+
+trait Trait
+{
+
+}
+
+impl<T> Trait for T
+{
+
+}
+
+trait Trait2<T>
+where
+ T: Copy + Display + Write + Read + FromStr, {}
+
+trait Trait3<T>
+where
+ T: Something
+ + SomethingElse
+ + Sync
+ + Send
+ + Display
+ + Debug
+ + Copy
+ + Hash
+ + Debug
+ + Display
+ + Write
+ + Read, {}
--- /dev/null
+// rustfmt-group_imports: One
+// rustfmt-imports_granularity: Crate
+use super::{
+ schema::{Context, Payload},
+ update::convert_publish_payload,
+};
+use crate::models::Event;
+use alloc::{alloc::Layout, vec::Vec};
+use broker::database::PooledConnection;
+use chrono::Utc;
+use core::f32;
+use juniper::{FieldError, FieldResult};
+use std::sync::Arc;
+use uuid::Uuid;
--- /dev/null
+// rustfmt-group_imports: One
+mod test {
+ use crate::foo::bar;
+ use crate::foo::bar2;
+ use std::path;
+}
--- /dev/null
+// rustfmt-group_imports: One
+// rustfmt-reorder_imports: false
+use chrono::Utc;
+use super::update::convert_publish_payload;
+use juniper::{FieldError, FieldResult};
+use uuid::Uuid;
+use alloc::alloc::Layout;
+use std::sync::Arc;
+use broker::database::PooledConnection;
+use super::schema::{Context, Payload};
+use core::f32;
+use crate::models::Event;
--- /dev/null
+// rustfmt-group_imports: One
+use super::schema::{Context, Payload};
+use super::update::convert_publish_payload;
+use crate::models::Event;
+use alloc::alloc::Layout;
+use broker::database::PooledConnection;
+use chrono::Utc;
+use core::f32;
+use juniper::{FieldError, FieldResult};
+use std::sync::Arc;
+use uuid::Uuid;
--- /dev/null
+// rustfmt-brace_style: AlwaysNextLine
+// rustfmt-empty_item_single_line: false
+
+fn function()
+{
+}
+
+struct Struct {}
+
+enum Enum {}
+
+trait Trait
+{
+}
+
+impl<T> Trait for T
+{
+}
+
+trait Trait2<T>
+where
+ T: Copy + Display + Write + Read + FromStr,
+{
+}
+
+trait Trait3<T>
+where
+ T: Something
+ + SomethingElse
+ + Sync
+ + Send
+ + Display
+ + Debug
+ + Copy
+ + Hash
+ + Debug
+ + Display
+ + Write
+ + Read,
+{
+}
--- /dev/null
+// rustfmt-trailing_comma: Always
+
+pub struct Matrix<T, const R: usize, const C: usize,>
+where
+ [T; R * C]:,
+{
+ contents: [T; R * C],
+}
--- /dev/null
+// rustfmt-trailing_comma: Never
+
+pub struct Matrix<T, const R: usize, const C: usize>
+where
+ [T; R * C]:
+{
+ contents: [T; R * C]
+}
--- /dev/null
+// leading comment
+
+#![rustfmt::skip]
+fn main() {
+ println!("main"); // commented
+}
+
+// post comment
--- /dev/null
+#![rustfmt::skip]
+
+mod a {
+ mod b {
+
+ }
+
+ // trailing comment b
+}
+
+// trailing comment a
--- /dev/null
+impl ThisIsALongStructNameToPushTheWhereToWrapLolololol where
+ [(); this_is_a_long_const_function_name()]:
+{
+}
where
T: Copy, {}
}
+
+fn function() {}
+
+trait Trait {}
+
+impl<T> Trait for T {}
+
+trait Trait2<T>
+where
+ T: Copy + Display + Write + Read + FromStr,
+{
+}
+
+trait Trait3<T>
+where
+ T: Something
+ + SomethingElse
+ + Sync
+ + Send
+ + Display
+ + Debug
+ + Copy
+ + Hash
+ + Debug
+ + Display
+ + Write
+ + Read,
+{
+}
"compiler/rustc_codegen_gcc",
"src/llvm-project",
"library/backtrace",
+ "library/portable-simd",
"library/stdarch",
"src/tools/cargo",
"src/tools/clippy",
const ENTRY_LIMIT: usize = 1000;
// FIXME: The following limits should be reduced eventually.
-const ROOT_ENTRY_LIMIT: usize = 1331;
-const ISSUES_ENTRY_LIMIT: usize = 2488;
+const ROOT_ENTRY_LIMIT: usize = 1275;
+const ISSUES_ENTRY_LIMIT: usize = 2310;
fn check_entries(path: &Path, bad: &mut bool) {
let dirs = walkdir::WalkDir::new(&path.join("test/ui"))