[[package]]
name = "autocfg"
-version = "1.0.0"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitflags"
name = "bootstrap"
version = "0.0.0"
dependencies = [
- "build_helper",
"cc",
"cmake",
"filetime",
"getopts",
"ignore",
"libc",
- "num_cpus",
"once_cell",
"opener",
"pretty_assertions",
"anyhow",
"flate2",
"hex 0.4.2",
- "num_cpus",
"rayon",
"serde",
"serde_json",
"toml",
]
-[[package]]
-name = "build_helper"
-version = "0.1.0"
-
[[package]]
name = "bump-stage0"
version = "0.1.0"
"humantime 2.0.1",
"ignore",
"im-rc",
- "itertools 0.10.1",
+ "itertools",
"jobserver",
"lazy_static",
"lazycell",
"libgit2-sys",
"log",
"memchr",
- "num_cpus",
"opener",
"openssl",
"os_info",
"flate2",
"git2",
"glob",
- "itertools 0.10.1",
+ "itertools",
"lazy_static",
"remove_dir_all",
"serde_json",
"chalk-ir",
"ena",
"indexmap",
- "itertools 0.10.1",
+ "itertools",
"petgraph",
"rustc-hash",
"tracing",
"filetime",
"futures 0.3.19",
"if_chain",
- "itertools 0.10.1",
+ "itertools",
"num_cpus",
"parking_lot",
"quote",
"cargo_metadata",
"clap 2.34.0",
"indoc",
- "itertools 0.10.1",
+ "itertools",
"opener",
"regex",
"shell-escape",
"cargo_metadata",
"clippy_utils",
"if_chain",
- "itertools 0.10.1",
+ "itertools",
"pulldown-cmark",
"quine-mc_cluskey",
"regex-syntax",
[[package]]
name = "git2"
-version = "0.13.23"
+version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a8057932925d3a9d9e4434ea016570d37420ddb1ceed45a174d577f24ed6700"
+checksum = "6e7d3b96ec1fcaa8431cf04a4f1ef5caafe58d5cf7bcc31f09c1626adddb0ffe"
dependencies = [
"bitflags",
"libc",
[[package]]
name = "git2-curl"
-version = "0.14.1"
+version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "883539cb0ea94bab3f8371a98cd8e937bbe9ee7c044499184aa4c17deb643a50"
+checksum = "1ee51709364c341fbb6fe2a385a290fb9196753bdde2fc45447d27cd31b11b13"
dependencies = [
"curl",
"git2",
"cfg-if 1.0.0",
]
-[[package]]
-name = "itertools"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
-dependencies = [
- "either",
-]
-
[[package]]
name = "itertools"
version = "0.10.1"
[[package]]
name = "libgit2-sys"
-version = "0.12.24+1.3.0"
+version = "0.13.1+1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ddbd6021eef06fb289a8f54b3c2acfdd85ff2a585dfbb24b8576325373d2152c"
+checksum = "43e598aa7a4faedf1ea1b4608f582b06f0f40211eec551b7ef36019ae3f62def"
dependencies = [
"cc",
"libc",
[[package]]
name = "minifier"
-version = "0.0.42"
+version = "0.0.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55a1388517eda8a68875243b650c26997e055a33d82571b5a0349129faef7d99"
+checksum = "d81352bda6f4d04af1720afaa762054f66e16caffd93c1f86461a1c0ac4e695e"
dependencies = [
"macro-utils",
]
"futures 0.3.19",
"heck",
"home",
- "itertools 0.10.1",
+ "itertools",
"jsonrpc-core",
"lazy_static",
"log",
"derive-new",
"env_logger 0.9.0",
"fst",
- "itertools 0.10.1",
+ "itertools",
"json",
"lazy_static",
"log",
name = "rustc_ast_passes"
version = "0.0.0"
dependencies = [
- "itertools 0.10.1",
+ "itertools",
"rustc_ast",
"rustc_ast_pretty",
"rustc_attr",
version = "0.0.0"
dependencies = [
"either",
- "itertools 0.10.1",
+ "itertools",
"polonius-engine",
"rustc_const_eval",
"rustc_data_structures",
dependencies = [
"bitflags",
"cc",
- "itertools 0.10.1",
+ "itertools",
"jobserver",
"libc",
"object 0.28.1",
dependencies = [
"rustc_ast",
"rustc_data_structures",
+ "rustc_hir",
"rustc_macros",
"rustc_serialize",
"rustc_span",
name = "rustc_llvm"
version = "0.0.0"
dependencies = [
- "build_helper",
"cc",
"libc",
]
version = "0.0.0"
dependencies = [
"coverage_test_macros",
- "itertools 0.10.1",
+ "itertools",
"rustc_ast",
"rustc_attr",
"rustc_const_eval",
version = "0.0.0"
dependencies = [
"getopts",
- "num_cpus",
"rustc_ast",
"rustc_data_structures",
"rustc_errors",
"askama",
"atty",
"expect-test",
- "itertools 0.10.1",
+ "itertools",
"minifier",
"pulldown-cmark",
"rayon",
"env_logger 0.8.4",
"getopts",
"ignore",
- "itertools 0.9.0",
+ "itertools",
"lazy_static",
"log",
"regex",
dependencies = [
"combine",
"indexmap",
- "itertools 0.10.1",
+ "itertools",
"kstring",
"serde",
]
This release disables incremental compilation, unless the user has explicitly
opted in via the newly added RUSTC_FORCE_INCREMENTAL=1 environment variable.
-This is due to the widespread, and frequently occuring, breakage encountered by
+This is due to the widespread, and frequently occurring, breakage encountered by
Rust users due to newly enabled incremental verification in 1.52.0. Notably,
Rust users **should** upgrade to 1.52.0 or 1.52.1: the bugs that are detected by
newly added incremental verification are still present in past stable versions,
pub items: Vec<P<AssocItem>>,
}
+/// The location of a where clause on a `TyAlias` (`Span`) and whether there was
+/// a `where` keyword (`bool`). This is split out from `WhereClause`, since there
+/// are two locations for where clause on type aliases, but their predicates
+/// are concatenated together.
+///
+/// Take this example:
+/// ```ignore (only-for-syntax-highlight)
+/// trait Foo {
+/// type Assoc<'a, 'b> where Self: 'a, Self: 'b;
+/// }
+/// impl Foo for () {
+/// type Assoc<'a, 'b> where Self: 'a = () where Self: 'b;
+/// // ^^^^^^^^^^^^^^ first where clause
+/// // ^^^^^^^^^^^^^^ second where clause
+/// }
+/// ```
+///
+/// If there is no where clause, then this is `false` with `DUMMY_SP`.
+#[derive(Copy, Clone, Encodable, Decodable, Debug, Default)]
+pub struct TyAliasWhereClause(pub bool, pub Span);
+
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct TyAlias {
pub defaultness: Defaultness,
pub generics: Generics,
+ /// The span information for the two where clauses (before equals, after equals)
+ pub where_clauses: (TyAliasWhereClause, TyAliasWhereClause),
+ /// The index in `generics.where_clause.predicates` that would split into
+ /// predicates from the where clause before the equals and the predicates
+ /// from the where clause after the equals
+ pub where_predicates_split: usize,
pub bounds: GenericBounds,
pub ty: Option<P<Ty>>,
}
}
ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm),
ItemKind::GlobalAsm(asm) => noop_visit_inline_asm(asm, vis),
- ItemKind::TyAlias(box TyAlias { defaultness, generics, bounds, ty }) => {
+ ItemKind::TyAlias(box TyAlias {
+ defaultness, generics, where_clauses, bounds, ty, ..
+ }) => {
visit_defaultness(defaultness, vis);
vis.visit_generics(generics);
+ vis.visit_span(&mut where_clauses.0.1);
+ vis.visit_span(&mut where_clauses.1.1);
visit_bounds(bounds, vis);
visit_opt(ty, |ty| vis.visit_ty(ty));
}
visit_fn_sig(sig, visitor);
visit_opt(body, |body| visitor.visit_block(body));
}
- AssocItemKind::TyAlias(box TyAlias { defaultness, generics, bounds, ty }) => {
+ AssocItemKind::TyAlias(box TyAlias {
+ defaultness,
+ generics,
+ where_clauses,
+ bounds,
+ ty,
+ ..
+ }) => {
visit_defaultness(defaultness, visitor);
visitor.visit_generics(generics);
+ visitor.visit_span(&mut where_clauses.0.1);
+ visitor.visit_span(&mut where_clauses.1.1);
visit_bounds(bounds, visitor);
visit_opt(ty, |ty| visitor.visit_ty(ty));
}
visit_fn_sig(sig, visitor);
visit_opt(body, |body| visitor.visit_block(body));
}
- ForeignItemKind::TyAlias(box TyAlias { defaultness, generics, bounds, ty }) => {
+ ForeignItemKind::TyAlias(box TyAlias {
+ defaultness,
+ generics,
+ where_clauses,
+ bounds,
+ ty,
+ ..
+ }) => {
visit_defaultness(defaultness, visitor);
visitor.visit_generics(generics);
+ visitor.visit_span(&mut where_clauses.0.1);
+ visitor.visit_span(&mut where_clauses.1.1);
visit_bounds(bounds, visitor);
visit_opt(ty, |ty| visitor.visit_ty(ty));
}
walk_list!(visitor, visit_foreign_item, &foreign_module.items);
}
ItemKind::GlobalAsm(ref asm) => walk_inline_asm(visitor, asm),
- ItemKind::TyAlias(box TyAlias { defaultness: _, ref generics, ref bounds, ref ty }) => {
+ ItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. }) => {
visitor.visit_generics(generics);
walk_list!(visitor, visit_param_bound, bounds);
walk_list!(visitor, visit_ty, ty);
let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, body.as_deref());
visitor.visit_fn(kind, span, id);
}
- ForeignItemKind::TyAlias(box TyAlias { defaultness: _, generics, bounds, ty }) => {
+ ForeignItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => {
visitor.visit_generics(generics);
walk_list!(visitor, visit_param_bound, bounds);
walk_list!(visitor, visit_ty, ty);
let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, body.as_deref());
visitor.visit_fn(kind, span, id);
}
- AssocItemKind::TyAlias(box TyAlias { defaultness: _, generics, bounds, ty }) => {
+ AssocItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => {
visitor.visit_generics(generics);
walk_list!(visitor, visit_param_bound, bounds);
walk_list!(visitor, visit_ty, ty);
pub(super) lctx: &'a mut LoweringContext<'lowering, 'hir>,
}
+/// When we have a ty alias we *may* have two where clauses. To give the best diagnostics, we set the span
+/// to the where clause that is prefered, if it exists. Otherwise, it sets the span to the other where
+/// clause if it exists.
+fn add_ty_alias_where_clause(
+ generics: &mut ast::Generics,
+ mut where_clauses: (TyAliasWhereClause, TyAliasWhereClause),
+ prefer_first: bool,
+) {
+ if !prefer_first {
+ where_clauses = (where_clauses.1, where_clauses.0);
+ }
+ if where_clauses.0.0 || !where_clauses.1.0 {
+ generics.where_clause.has_where_token = where_clauses.0.0;
+ generics.where_clause.span = where_clauses.0.1;
+ } else {
+ generics.where_clause.has_where_token = where_clauses.1.0;
+ generics.where_clause.span = where_clauses.1.1;
+ }
+}
+
impl ItemLowerer<'_, '_, '_> {
fn with_trait_impl_ref<T>(
&mut self,
ItemKind::GlobalAsm(ref asm) => {
hir::ItemKind::GlobalAsm(self.lower_inline_asm(span, asm))
}
- ItemKind::TyAlias(box TyAlias { ref generics, ty: Some(ref ty), .. }) => {
+ ItemKind::TyAlias(box TyAlias {
+ ref generics,
+ where_clauses,
+ ty: Some(ref ty),
+ ..
+ }) => {
// We lower
//
// type Foo = impl Trait
capturable_lifetimes: &mut FxHashSet::default(),
},
);
+ let mut generics = generics.clone();
+ add_ty_alias_where_clause(&mut generics, where_clauses, true);
let generics = self.lower_generics(
- generics,
+ &generics,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
);
hir::ItemKind::TyAlias(ty, generics)
}
- ItemKind::TyAlias(box TyAlias { ref generics, ty: None, .. }) => {
+ ItemKind::TyAlias(box TyAlias {
+ ref generics, ref where_clauses, ty: None, ..
+ }) => {
let ty = self.arena.alloc(self.ty(span, hir::TyKind::Err));
+ let mut generics = generics.clone();
+ add_ty_alias_where_clause(&mut generics, *where_clauses, true);
let generics = self.lower_generics(
- generics,
+ &generics,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
);
hir::ItemKind::TyAlias(ty, generics)
);
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)))
}
- AssocItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. }) => {
+ AssocItemKind::TyAlias(box TyAlias {
+ ref generics,
+ where_clauses,
+ ref bounds,
+ ref ty,
+ ..
+ }) => {
let ty = ty.as_ref().map(|x| {
self.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Type))
});
+ let mut generics = generics.clone();
+ add_ty_alias_where_clause(&mut generics, where_clauses, false);
let generics = self.lower_generics(
- generics,
+ &generics,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
);
let kind = hir::TraitItemKind::Type(
self.lower_param_bounds(
bounds,
- ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+ ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
),
ty,
);
(generics, hir::ImplItemKind::Fn(sig, body_id))
}
- AssocItemKind::TyAlias(box TyAlias { generics, ty, .. }) => {
+ AssocItemKind::TyAlias(box TyAlias { generics, where_clauses, ty, .. }) => {
+ let mut generics = generics.clone();
+ add_ty_alias_where_clause(&mut generics, *where_clauses, false);
let generics = self.lower_generics(
- generics,
+ &generics,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
);
let kind = match ty {
)),
_ => None,
});
- if let ImplTraitContext::TypeAliasesOpaqueTy { ref mut capturable_lifetimes, .. } =
- itctx
- {
+ if let ImplTraitContext::TypeAliasesOpaqueTy { ref mut capturable_lifetimes } = itctx {
capturable_lifetimes.extend(lt_def_names.clone());
}
let res = this.lower_trait_ref(&p.trait_ref, itctx.reborrow());
- if let ImplTraitContext::TypeAliasesOpaqueTy { ref mut capturable_lifetimes, .. } =
- itctx
- {
+ if let ImplTraitContext::TypeAliasesOpaqueTy { ref mut capturable_lifetimes } = itctx {
for param in lt_def_names {
capturable_lifetimes.remove(¶m);
}
edition = "2021"
[dependencies]
-itertools = "0.10"
+itertools = "0.10.1"
tracing = "0.1"
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_attr = { path = "../rustc_attr" }
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
use rustc_ast::walk_list;
use rustc_ast::*;
-use rustc_ast_pretty::pprust;
+use rustc_ast_pretty::pprust::{self, State};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{error_code, pluralize, struct_span_err, Applicability};
use rustc_parse::validate_attr;
-use rustc_session::lint::builtin::{MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY};
+use rustc_session::lint::builtin::{
+ DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY,
+};
use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
use rustc_session::Session;
use rustc_span::source_map::Spanned;
}
}
+ fn check_gat_where(
+ &mut self,
+ id: NodeId,
+ before_predicates: &[WherePredicate],
+ where_clauses: (ast::TyAliasWhereClause, ast::TyAliasWhereClause),
+ ) {
+ if !before_predicates.is_empty() {
+ let mut state = State::new();
+ if !where_clauses.1.0 {
+ state.space();
+ state.word_space("where");
+ } else {
+ state.word_space(",");
+ }
+ let mut first = true;
+ for p in before_predicates.iter() {
+ if !first {
+ state.word_space(",");
+ }
+ first = false;
+ state.print_where_predicate(p);
+ }
+ let suggestion = state.s.eof();
+ self.lint_buffer.buffer_lint_with_diagnostic(
+ DEPRECATED_WHERE_CLAUSE_LOCATION,
+ id,
+ where_clauses.0.1,
+ "where clause not allowed here",
+ BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
+ where_clauses.1.1.shrink_to_hi(),
+ suggestion,
+ ),
+ );
+ }
+ }
+
fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) {
let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true);
f(self);
.emit();
}
- fn check_foreign_ty_genericless(&self, generics: &Generics) {
+ fn check_foreign_ty_genericless(&self, generics: &Generics, where_span: Span) {
let cannot_have = |span, descr, remove_descr| {
self.err_handler()
.struct_span_err(
}
if !generics.where_clause.predicates.is_empty() {
- cannot_have(generics.where_clause.span, "`where` clauses", "`where` clause");
+ cannot_have(where_span, "`where` clauses", "`where` clause");
}
}
let msg = "free static item without body";
self.error_item_without_body(item.span, "static", msg, " = <expr>;");
}
- ItemKind::TyAlias(box TyAlias { defaultness, ref bounds, ref ty, .. }) => {
+ ItemKind::TyAlias(box TyAlias {
+ defaultness,
+ where_clauses,
+ 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>;");
}
self.check_type_no_bounds(bounds, "this context");
+ if where_clauses.1.0 {
+ let mut err = self.err_handler().struct_span_err(
+ where_clauses.1.1,
+ "where clauses are not allowed after the type for type aliases",
+ );
+ err.note(
+ "see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information",
+ );
+ err.emit();
+ }
}
_ => {}
}
self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
self.check_foreign_item_ascii_only(fi.ident);
}
- ForeignItemKind::TyAlias(box TyAlias { defaultness, generics, bounds, ty, .. }) => {
+ ForeignItemKind::TyAlias(box TyAlias {
+ defaultness,
+ generics,
+ where_clauses,
+ 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_ty_genericless(generics, where_clauses.0.1);
self.check_foreign_item_ascii_only(fi.ident);
}
ForeignItemKind::Static(_, _, body) => {
AssocItemKind::Fn(box Fn { body, .. }) => {
self.check_impl_item_provided(item.span, body, "function", " { <body> }");
}
- AssocItemKind::TyAlias(box TyAlias { bounds, ty, .. }) => {
+ AssocItemKind::TyAlias(box TyAlias {
+ generics,
+ where_clauses,
+ where_predicates_split,
+ bounds,
+ ty,
+ ..
+ }) => {
self.check_impl_item_provided(item.span, ty, "type", " = <type>;");
self.check_type_no_bounds(bounds, "`impl`s");
+ if ty.is_some() {
+ self.check_gat_where(
+ item.id,
+ generics.where_clause.predicates.split_at(*where_predicates_split).0,
+ *where_clauses,
+ );
+ }
}
_ => {}
}
}
}
}
+
+ // Emit errors for non-staged-api crates.
+ if !self.features.staged_api {
+ if attr.has_name(sym::rustc_deprecated)
+ || attr.has_name(sym::unstable)
+ || attr.has_name(sym::stable)
+ || attr.has_name(sym::rustc_const_unstable)
+ || attr.has_name(sym::rustc_const_stable)
+ {
+ struct_span_err!(
+ self.sess,
+ attr.span,
+ E0734,
+ "stability attributes may not be used outside of the standard library",
+ )
+ .emit();
+ }
+ } else {
+ if attr.has_name(sym::deprecated) {
+ self.sess
+ .struct_span_err(attr.span, "`#[deprecated]` cannot be used in staged API")
+ .span_label(attr.span, "use `#[rustc_deprecated]` instead")
+ .emit();
+ }
+ }
}
fn visit_item(&mut self, i: &'a ast::Item) {
ast::ForeignItemKind::TyAlias(box ast::TyAlias {
defaultness,
generics,
+ where_clauses,
+ where_predicates_split,
bounds,
ty,
}) => {
self.print_associated_type(
ident,
generics,
+ *where_clauses,
+ *where_predicates_split,
bounds,
ty.as_deref(),
vis,
&mut self,
ident: Ident,
generics: &ast::Generics,
+ where_clauses: (ast::TyAliasWhereClause, ast::TyAliasWhereClause),
+ where_predicates_split: usize,
bounds: &ast::GenericBounds,
ty: Option<&ast::Ty>,
vis: &ast::Visibility,
defaultness: ast::Defaultness,
) {
+ let (before_predicates, after_predicates) =
+ generics.where_clause.predicates.split_at(where_predicates_split);
self.head("");
self.print_visibility(vis);
self.print_defaultness(defaultness);
self.print_ident(ident);
self.print_generic_params(&generics.params);
self.print_type_bounds(":", bounds);
- self.print_where_clause(&generics.where_clause);
+ self.print_where_clause_parts(where_clauses.0.0, before_predicates);
if let Some(ty) = ty {
self.space();
self.word_space("=");
self.print_type(ty);
}
+ self.print_where_clause_parts(where_clauses.1.0, after_predicates);
self.word(";");
self.end(); // end inner head-block
self.end(); // end outer head-block
ast::ItemKind::TyAlias(box ast::TyAlias {
defaultness,
ref generics,
+ where_clauses,
+ where_predicates_split,
ref bounds,
ref ty,
}) => {
self.print_associated_type(
item.ident,
generics,
+ where_clauses,
+ where_predicates_split,
bounds,
ty,
&item.vis,
ast::AssocItemKind::Const(def, ty, body) => {
self.print_item_const(ident, None, ty, body.as_deref(), vis, *def);
}
- ast::AssocItemKind::TyAlias(box ast::TyAlias { defaultness, generics, bounds, ty }) => {
+ ast::AssocItemKind::TyAlias(box ast::TyAlias {
+ defaultness,
+ generics,
+ where_clauses,
+ where_predicates_split,
+ bounds,
+ ty,
+ }) => {
self.print_associated_type(
ident,
generics,
+ *where_clauses,
+ *where_predicates_split,
bounds,
ty.as_deref(),
vis,
}
fn print_where_clause(&mut self, where_clause: &ast::WhereClause) {
- if where_clause.predicates.is_empty() && !where_clause.has_where_token {
+ self.print_where_clause_parts(where_clause.has_where_token, &where_clause.predicates);
+ }
+
+ crate fn print_where_clause_parts(
+ &mut self,
+ has_where_token: bool,
+ predicates: &[ast::WherePredicate],
+ ) {
+ if predicates.is_empty() && !has_where_token {
return;
}
self.space();
self.word_space("where");
- for (i, predicate) in where_clause.predicates.iter().enumerate() {
+ for (i, predicate) in predicates.iter().enumerate() {
if i != 0 {
self.word_space(",");
}
cfg.span,
lint_node_id,
"unexpected `cfg` condition name",
- BuiltinLintDiagnostics::UnexpectedCfg(ident.span, name, None),
+ BuiltinLintDiagnostics::UnexpectedCfg((name, ident.span), None),
);
}
}
lint_node_id,
"unexpected `cfg` condition value",
BuiltinLintDiagnostics::UnexpectedCfg(
- cfg.name_value_literal_span().unwrap(),
- name,
- Some(value),
+ (name, ident.span),
+ Some((value, cfg.name_value_literal_span().unwrap())),
),
);
}
[dependencies]
either = "1.5.0"
-itertools = "0.10"
+itertools = "0.10.1"
tracing = "0.1"
polonius-engine = "0.13.0"
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
self.mir_hir_id(),
rustc_infer::traits::ObligationCauseCode::MiscObligation,
);
- fulfill_cx.register_bound(&infcx, self.param_env, ty, copy_did, cause);
- let errors = fulfill_cx.select_where_possible(&infcx);
+ fulfill_cx.register_bound(
+ &infcx,
+ self.param_env,
+ // Erase any region vids from the type, which may not be resolved
+ infcx.tcx.erase_regions(ty),
+ copy_did,
+ cause,
+ );
+ // Select all, including ambiguous predicates
+ let errors = fulfill_cx.select_all_or_error(&infcx);
// Only emit suggestion if all required predicates are on generic
errors
kind: ast::AssocItemKind::TyAlias(Box::new(ast::TyAlias {
defaultness: ast::Defaultness::Final,
generics: Generics::default(),
+ where_clauses: (
+ ast::TyAliasWhereClause::default(),
+ ast::TyAliasWhereClause::default(),
+ ),
+ where_predicates_split: 0,
bounds: Vec::new(),
ty: Some(type_def.to_ty(cx, self.span, type_ident, generics)),
})),
// Note: non-associated fn items are already handled by `expand_test_or_bench`
if !matches!(item.kind, ast::ItemKind::Fn(_)) {
- cx.sess
- .parse_sess
- .span_diagnostic
- .struct_span_err(
- attr_sp,
- "the `#[test]` attribute may only be used on a non-associated function",
- )
- .note("the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions")
+ let diag = &cx.sess.parse_sess.span_diagnostic;
+ let msg = "the `#[test]` attribute may only be used on a non-associated function";
+ let mut err = match item.kind {
+ // These were a warning before #92959 and need to continue being that to avoid breaking
+ // stable user code (#94508).
+ ast::ItemKind::MacCall(_) => diag.struct_span_warn(attr_sp, msg),
+ // `.forget_guarantee()` needed to get these two arms to match types. Because of how
+ // locally close the `.emit()` call is I'm comfortable with it, but if it can be
+ // reworked in the future to not need it, it'd be nice.
+ _ => diag.struct_span_err(attr_sp, msg).forget_guarantee(),
+ };
+ err.span_label(attr_sp, "the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions")
.span_label(item.span, format!("expected a non-associated function, found {} {}", item.kind.article(), item.kind.descr()))
.span_suggestion(attr_sp, "replace with conditional compilation to make the item only exist when tests are being run", String::from("#[cfg(test)]"), Applicability::MaybeIncorrect)
.emit();
return;
}
let TyAndLayout { ty, layout } = place.layout();
- let rustc_target::abi::Layout { size, align, abi: _, variants: _, fields: _, largest_niche: _ } =
- layout;
+ let rustc_target::abi::LayoutS {
+ size,
+ align,
+ abi: _,
+ variants: _,
+ fields: _,
+ largest_niche: _,
+ } = layout.0.0;
let (kind, extra) = match *place.inner() {
CPlaceInner::Var(place_local, var) => {
use rustc_errors::ErrorGuaranteed;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir::interpret::{
- read_target_uint, AllocId, Allocation, ConstValue, ErrorHandled, GlobalAlloc, Scalar,
+ read_target_uint, AllocId, ConstAllocation, ConstValue, ErrorHandled, GlobalAlloc, Scalar,
};
use rustc_middle::ty::ConstKind;
use rustc_span::DUMMY_SP;
&mut fx.constants_cx,
fx.module,
alloc_id,
- alloc.mutability,
+ alloc.inner().mutability,
);
let local_data_id =
fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
pub(crate) fn pointer_for_allocation<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
- alloc: &'tcx Allocation,
+ alloc: ConstAllocation<'tcx>,
) -> crate::pointer::Pointer {
let alloc_id = fx.tcx.create_memory_alloc(alloc);
- let data_id =
- data_id_for_alloc_id(&mut fx.constants_cx, &mut *fx.module, alloc_id, alloc.mutability);
+ let data_id = data_id_for_alloc_id(
+ &mut fx.constants_cx,
+ &mut *fx.module,
+ alloc_id,
+ alloc.inner().mutability,
+ );
let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
if fx.clif_comments.enabled() {
let data_id = *cx.anon_allocs.entry(alloc_id).or_insert_with(|| {
module
.declare_anonymous_data(
- alloc.mutability == rustc_hir::Mutability::Mut,
+ alloc.inner().mutability == rustc_hir::Mutability::Mut,
false,
)
.unwrap()
}
let mut data_ctx = DataContext::new();
+ let alloc = alloc.inner();
data_ctx.set_align(alloc.align.bytes());
if let Some(section_name) = section_name {
continue;
}
GlobalAlloc::Memory(target_alloc) => {
- data_id_for_alloc_id(cx, module, alloc_id, target_alloc.mutability)
+ data_id_for_alloc_id(cx, module, alloc_id, target_alloc.inner().mutability)
}
GlobalAlloc::Static(def_id) => {
if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL)
};
raw_eq, (v lhs_ref, v rhs_ref) {
- let size = fx.layout_of(substs.type_at(0)).layout.size;
+ let size = fx.layout_of(substs.type_at(0)).layout.size();
// FIXME add and use emit_small_memcmp
let is_eq_value =
if size == Size::ZERO {
let idx_bytes = match idx_const {
ConstValue::ByRef { alloc, offset } => {
let size = Size::from_bytes(4 * ret_lane_count /* size_of([u32; ret_lane_count]) */);
- alloc.get_bytes(fx, alloc_range(offset, size)).unwrap()
+ alloc.inner().get_bytes(fx, alloc_range(offset, size)).unwrap()
}
_ => unreachable!("{:?}", idx_const),
};
let val_type = value.get_type();
match (type_is_pointer(val_type), type_is_pointer(dest_ty)) {
(false, true) => {
- // NOTE: Projecting a field of a pointer type will attemp a cast from a signed char to
+ // NOTE: Projecting a field of a pointer type will attempt a cast from a signed char to
// a pointer, which is not supported by gccjit.
return self.cx.context.new_cast(None, self.inttoptr(value, val_type.make_pointer()), dest_ty);
},
use rustc_middle::mir::Mutability;
use rustc_middle::ty::ScalarInt;
use rustc_middle::ty::layout::{TyAndLayout, LayoutOf};
-use rustc_middle::mir::interpret::{Allocation, GlobalAlloc, Scalar};
+use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
use rustc_span::Symbol;
use rustc_target::abi::{self, HasDataLayout, Pointer, Size};
bytes_in_context(self, bytes)
}
- fn const_cstr(&self, symbol: Symbol, _null_terminated: bool) -> LValue<'gcc> {
- // TODO(antoyo): handle null_terminated.
- if let Some(&value) = self.const_cstr_cache.borrow().get(&symbol) {
- return value;
- }
-
- let global = self.global_string(symbol.as_str());
-
- self.const_cstr_cache.borrow_mut().insert(symbol, global);
- global
- }
-
fn global_string(&self, string: &str) -> LValue<'gcc> {
// TODO(antoyo): handle non-null-terminated strings.
let string = self.context.new_string_literal(&*string);
}
fn const_str(&self, s: Symbol) -> (RValue<'gcc>, RValue<'gcc>) {
- let len = s.as_str().len();
- let cs = self.const_ptrcast(self.const_cstr(s, false).get_address(None),
+ let s_str = s.as_str();
+ let str_global = *self.const_str_cache.borrow_mut().entry(s).or_insert_with(|| {
+ self.global_string(s_str)
+ });
+ let len = s_str.len();
+ let cs = self.const_ptrcast(str_global.get_address(None),
self.type_ptr_to(self.layout_of(self.tcx.types.str_).gcc_type(self, true)),
);
(cs, self.const_usize(len as u64))
match self.tcx.global_alloc(alloc_id) {
GlobalAlloc::Memory(alloc) => {
let init = const_alloc_to_gcc(self, alloc);
+ let alloc = alloc.inner();
let value =
match alloc.mutability {
Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None),
}
}
- fn const_data_from_alloc(&self, alloc: &Allocation) -> Self::Value {
+ fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value {
const_alloc_to_gcc(self, alloc)
}
- fn from_const_alloc(&self, layout: TyAndLayout<'tcx>, alloc: &Allocation, offset: Size) -> PlaceRef<'tcx, RValue<'gcc>> {
- assert_eq!(alloc.align, layout.align.abi);
+ fn from_const_alloc(&self, layout: TyAndLayout<'tcx>, alloc: ConstAllocation<'tcx>, offset: Size) -> PlaceRef<'tcx, RValue<'gcc>> {
+ assert_eq!(alloc.inner().align, layout.align.abi);
let ty = self.type_ptr_to(layout.gcc_type(self, true));
let value =
if layout.size == Size::ZERO {
- let value = self.const_usize(alloc.align.bytes());
+ let value = self.const_usize(alloc.inner().align.bytes());
self.context.new_cast(None, value, ty)
}
else {
let init = const_alloc_to_gcc(self, alloc);
- let base_addr = self.static_addr_of(init, alloc.align, None);
+ let base_addr = self.static_addr_of(init, alloc.inner().align, None);
let array = self.const_bitcast(base_addr, self.type_i8p());
let value = self.context.new_array_access(None, array, self.const_usize(offset.bytes())).get_address(None);
use rustc_middle::mir::mono::MonoItem;
use rustc_middle::ty::{self, Instance, Ty};
use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::mir::interpret::{self, Allocation, ErrorHandled, Scalar as InterpScalar, read_target_uint};
+use rustc_middle::mir::interpret::{self, ConstAllocation, ErrorHandled, Scalar as InterpScalar, read_target_uint};
use rustc_span::Span;
use rustc_span::def_id::DefId;
use rustc_target::abi::{self, Align, HasDataLayout, Primitive, Size, WrappingRange};
}
}
-pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: &Allocation) -> RValue<'gcc> {
+pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAllocation<'tcx>) -> RValue<'gcc> {
+ let alloc = alloc.inner();
let mut llvals = Vec::with_capacity(alloc.relocations().len() + 1);
let dl = cx.data_layout();
let pointer_size = dl.pointer_size.bytes() as usize;
cx.const_struct(&llvals, true)
}
-pub fn codegen_static_initializer<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, def_id: DefId) -> Result<(RValue<'gcc>, &'tcx Allocation), ErrorHandled> {
+pub fn codegen_static_initializer<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, def_id: DefId) -> Result<(RValue<'gcc>, ConstAllocation<'tcx>), ErrorHandled> {
let alloc = cx.tcx.eval_static_initializer(def_id)?;
Ok((const_alloc_to_gcc(cx, alloc), alloc))
}
pub const_globals: RefCell<FxHashMap<RValue<'gcc>, RValue<'gcc>>>,
/// Cache of constant strings,
- pub const_cstr_cache: RefCell<FxHashMap<Symbol, LValue<'gcc>>>,
+ pub const_str_cache: RefCell<FxHashMap<Symbol, LValue<'gcc>>>,
/// Cache of globals.
pub globals: RefCell<FxHashMap<String, RValue<'gcc>>>,
function_instances: Default::default(),
vtables: Default::default(),
const_globals: Default::default(),
- const_cstr_cache: Default::default(),
+ const_str_cache: Default::default(),
globals: Default::default(),
scalar_types: Default::default(),
types: Default::default(),
use rustc_target::abi::Abi::*;
let tp_ty = substs.type_at(0);
let layout = self.layout_of(tp_ty).layout;
- let _use_integer_compare = match layout.abi {
+ let _use_integer_compare = match layout.abi() {
Scalar(_) | ScalarPair(_, _) => true,
Uninhabited | Vector { .. } => false,
Aggregate { .. } => {
// For rusty ABIs, small aggregates are actually passed
// as `RegKind::Integer` (see `FnAbi::adjust_for_abi`),
// so we re-use that same threshold here.
- layout.size <= self.data_layout().pointer_size * 2
+ layout.size() <= self.data_layout().pointer_size * 2
}
};
let a = args[0].immediate();
let b = args[1].immediate();
- if layout.size.bytes() == 0 {
+ if layout.size().bytes() == 0 {
self.const_bool(true)
}
/*else if use_integer_compare {
let void_ptr_type = self.context.new_type::<*const ()>();
let a_ptr = self.bitcast(a, void_ptr_type);
let b_ptr = self.bitcast(b, void_ptr_type);
- let n = self.context.new_cast(None, self.const_usize(layout.size.bytes()), self.sizet_type);
+ let n = self.context.new_cast(None, self.const_usize(layout.size().bytes()), self.sizet_type);
let builtin = self.context.get_builtin_function("memcmp");
let cmp = self.context.new_call(None, builtin, &[a_ptr, b_ptr, n]);
self.icmp(IntPredicate::IntEQ, cmp, self.const_i32(0))
if self.conv == Conv::CCmseNonSecureCall {
// This will probably get ignored on all targets but those supporting the TrustZone-M
// extension (thumbv8m targets).
- let cmse_nonsecure_call =
- llvm::CreateAttrString(bx.cx.llcx, cstr::cstr!("cmse_nonsecure_call"));
+ let cmse_nonsecure_call = llvm::CreateAttrString(bx.cx.llcx, "cmse_nonsecure_call");
attributes::apply_to_callsite(
callsite,
llvm::AttributePlace::Function,
//! Set and unset common attributes on LLVM values.
-use std::ffi::CString;
-
-use cstr::cstr;
use rustc_codegen_ssa::traits::*;
-use rustc_data_structures::small_c_str::SmallCStr;
+use rustc_data_structures::small_str::SmallStr;
use rustc_hir::def_id::DefId;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::ty::{self, TyCtxt};
fp = FramePointer::Always;
}
let attr_value = match fp {
- FramePointer::Always => cstr!("all"),
- FramePointer::NonLeaf => cstr!("non-leaf"),
+ FramePointer::Always => "all",
+ FramePointer::NonLeaf => "non-leaf",
FramePointer::MayOmit => return None,
};
- Some(llvm::CreateAttrStringValue(cx.llcx, cstr!("frame-pointer"), attr_value))
+ Some(llvm::CreateAttrStringValue(cx.llcx, "frame-pointer", attr_value))
}
/// Tell LLVM what instrument function to insert.
// The function name varies on platforms.
// See test/CodeGen/mcount.c in clang.
- let mcount_name = CString::new(cx.sess().target.mcount.as_str().as_bytes()).unwrap();
+ let mcount_name = cx.sess().target.mcount.as_str();
Some(llvm::CreateAttrStringValue(
cx.llcx,
- cstr!("instrument-function-entry-inlined"),
+ "instrument-function-entry-inlined",
&mcount_name,
))
} else {
StackProbeType::None => return None,
// Request LLVM to generate the probes inline. If the given LLVM version does not support
// this, no probe is generated at all (even if the attribute is specified).
- StackProbeType::Inline => cstr!("inline-asm"),
+ StackProbeType::Inline => "inline-asm",
// Flag our internal `__rust_probestack` function as the stack probe symbol.
// This is defined in the `compiler-builtins` crate for each architecture.
- StackProbeType::Call => cstr!("__rust_probestack"),
+ StackProbeType::Call => "__rust_probestack",
// Pick from the two above based on the LLVM version.
StackProbeType::InlineOrCall { min_llvm_version_for_inline } => {
if llvm_util::get_version() < min_llvm_version_for_inline {
- cstr!("__rust_probestack")
+ "__rust_probestack"
} else {
- cstr!("inline-asm")
+ "inline-asm"
}
}
};
- Some(llvm::CreateAttrStringValue(cx.llcx, cstr!("probe-stack"), attr_value))
+ Some(llvm::CreateAttrStringValue(cx.llcx, "probe-stack", attr_value))
}
fn stackprotector_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
}
pub fn target_cpu_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> &'ll Attribute {
- let target_cpu = SmallCStr::new(llvm_util::target_cpu(cx.tcx.sess));
- llvm::CreateAttrStringValue(cx.llcx, cstr!("target-cpu"), target_cpu.as_c_str())
+ let target_cpu = llvm_util::target_cpu(cx.tcx.sess);
+ llvm::CreateAttrStringValue(cx.llcx, "target-cpu", target_cpu)
}
pub fn tune_cpu_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
- llvm_util::tune_cpu(cx.tcx.sess).map(|tune| {
- let tune_cpu = SmallCStr::new(tune);
- llvm::CreateAttrStringValue(cx.llcx, cstr!("tune-cpu"), tune_cpu.as_c_str())
- })
+ llvm_util::tune_cpu(cx.tcx.sess)
+ .map(|tune_cpu| llvm::CreateAttrStringValue(cx.llcx, "tune-cpu", tune_cpu))
}
/// Get the `NonLazyBind` LLVM attribute,
}
if cx.sess().opts.debugging_opts.profile_sample_use.is_some() {
- to_add.push(llvm::CreateAttrString(cx.llcx, cstr!("use-sample-profile")));
+ to_add.push(llvm::CreateAttrString(cx.llcx, "use-sample-profile"));
}
// FIXME: none of these three functions interact with source level attributes.
attributes::apply_to_llfn(llfn, AttributePlace::ReturnValue, &[no_alias]);
}
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY) {
- to_add.push(llvm::CreateAttrString(cx.llcx, cstr!("cmse_nonsecure_entry")));
+ to_add.push(llvm::CreateAttrString(cx.llcx, "cmse_nonsecure_entry"));
}
if let Some(align) = codegen_fn_attrs.alignment {
llvm::set_alignment(llfn, align as usize);
// If this function is an import from the environment but the wasm
// import has a specific module/name, apply them here.
if let Some(module) = wasm_import_module(cx.tcx, instance.def_id()) {
- to_add.push(llvm::CreateAttrStringValue(cx.llcx, cstr!("wasm-import-module"), &module));
+ to_add.push(llvm::CreateAttrStringValue(cx.llcx, "wasm-import-module", &module));
let name =
codegen_fn_attrs.link_name.unwrap_or_else(|| cx.tcx.item_name(instance.def_id()));
- let name = CString::new(name.as_str()).unwrap();
- to_add.push(llvm::CreateAttrStringValue(cx.llcx, cstr!("wasm-import-name"), &name));
+ let name = name.as_str();
+ to_add.push(llvm::CreateAttrStringValue(cx.llcx, "wasm-import-name", name));
}
// The `"wasm"` abi on wasm targets automatically enables the
}
}
- if !function_features.is_empty() {
- let global_features = cx.tcx.global_backend_features(()).iter().map(|s| &s[..]);
- let val = global_features
- .chain(function_features.iter().map(|s| &s[..]))
- .intersperse(",")
- .collect::<SmallCStr>();
- to_add.push(llvm::CreateAttrStringValue(cx.llcx, cstr!("target-features"), &val));
+ let global_features = cx.tcx.global_backend_features(()).iter().map(|s| s.as_str());
+ let function_features = function_features.iter().map(|s| s.as_str());
+ let target_features =
+ global_features.chain(function_features).intersperse(",").collect::<SmallStr<1024>>();
+ if !target_features.is_empty() {
+ to_add.push(llvm::CreateAttrStringValue(cx.llcx, "target-features", &target_features));
}
attributes::apply_to_llfn(llfn, Function, &to_add);
}
-fn wasm_import_module(tcx: TyCtxt<'_>, id: DefId) -> Option<CString> {
- tcx.wasm_import_module_map(id.krate).get(&id).map(|s| CString::new(&s[..]).unwrap())
+fn wasm_import_module(tcx: TyCtxt<'_>, id: DefId) -> Option<&String> {
+ tcx.wasm_import_module_map(id.krate).get(&id)
}
info!("linking {:?}", name);
let data = bc_decoded.data();
linker.add(data).map_err(|()| {
- let msg = format!("failed to load bc of {:?}", name);
+ let msg = format!("failed to load bitcode of module {:?}", name);
write::llvm_err(diag_handler, &msg)
})?;
serialized_bitcode.push(bc_decoded);
bx: &mut Builder<'a, 'll, 'tcx>,
load: &'ll Value,
scalar: abi::Scalar,
+ layout: TyAndLayout<'tcx>,
+ offset: Size,
) {
if !scalar.is_always_valid(bx) {
bx.noundef_metadata(load);
bx.range_metadata(load, scalar.valid_range);
}
}
- abi::Pointer if !scalar.valid_range.contains(0) => {
- bx.nonnull_metadata(load);
+ abi::Pointer => {
+ if !scalar.valid_range.contains(0) {
+ bx.nonnull_metadata(load);
+ }
+
+ if let Some(pointee) = layout.pointee_info_at(bx, offset) {
+ if let Some(_) = pointee.safe {
+ bx.align_metadata(load, pointee.align);
+ }
+ }
}
- _ => {}
+ abi::F32 | abi::F64 => {}
}
}
let llval = const_llval.unwrap_or_else(|| {
let load = self.load(place.layout.llvm_type(self), place.llval, place.align);
if let abi::Abi::Scalar(scalar) = place.layout.abi {
- scalar_load_metadata(self, load, scalar);
+ scalar_load_metadata(self, load, scalar, place.layout, Size::ZERO);
}
load
});
let b_offset = a.value.size(self).align_to(b.value.align(self).abi);
let pair_ty = place.layout.llvm_type(self);
- let mut load = |i, scalar: abi::Scalar, align| {
+ let mut load = |i, scalar: abi::Scalar, layout, align, offset| {
let llptr = self.struct_gep(pair_ty, place.llval, i as u64);
let llty = place.layout.scalar_pair_element_llvm_type(self, i, false);
let load = self.load(llty, llptr, align);
- scalar_load_metadata(self, load, scalar);
+ scalar_load_metadata(self, load, scalar, layout, offset);
self.to_immediate_scalar(load, scalar)
};
OperandValue::Pair(
- load(0, a, place.align),
- load(1, b, place.align.restrict_for_offset(b_offset)),
+ load(0, a, place.layout, place.align, Size::ZERO),
+ load(1, b, place.layout, place.align.restrict_for_offset(b_offset), b_offset),
)
} else {
OperandValue::Ref(place.llval, None, place.align)
}
}
+ fn align_metadata(&mut self, load: &'ll Value, align: Align) {
+ unsafe {
+ let v = [self.cx.const_u64(align.bytes())];
+
+ llvm::LLVMSetMetadata(
+ load,
+ llvm::MD_align as c_uint,
+ llvm::LLVMMDNodeInContext(self.cx.llcx, v.as_ptr(), v.len() as c_uint),
+ );
+ }
+ }
+
fn noundef_metadata(&mut self, load: &'ll Value) {
unsafe {
llvm::LLVMSetMetadata(
use rustc_codegen_ssa::mir::place::PlaceRef;
use rustc_codegen_ssa::traits::*;
use rustc_middle::bug;
-use rustc_middle::mir::interpret::{Allocation, GlobalAlloc, Scalar};
+use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_middle::ty::ScalarInt;
use rustc_span::symbol::Symbol;
bytes_in_context(self.llcx, bytes)
}
- fn const_cstr(&self, s: Symbol, null_terminated: bool) -> &'ll Value {
- unsafe {
- if let Some(&llval) = self.const_cstr_cache.borrow().get(&s) {
- return llval;
- }
-
- let s_str = s.as_str();
- let sc = llvm::LLVMConstStringInContext(
- self.llcx,
- s_str.as_ptr() as *const c_char,
- s_str.len() as c_uint,
- !null_terminated as Bool,
- );
- let sym = self.generate_local_symbol_name("str");
- let g = self.define_global(&sym, self.val_ty(sc)).unwrap_or_else(|| {
- bug!("symbol `{}` is already defined", sym);
- });
- llvm::LLVMSetInitializer(g, sc);
- llvm::LLVMSetGlobalConstant(g, True);
- llvm::LLVMRustSetLinkage(g, llvm::Linkage::InternalLinkage);
-
- self.const_cstr_cache.borrow_mut().insert(s, g);
- g
- }
- }
-
pub fn const_get_elt(&self, v: &'ll Value, idx: u64) -> &'ll Value {
unsafe {
assert_eq!(idx as c_uint as u64, idx);
}
fn const_str(&self, s: Symbol) -> (&'ll Value, &'ll Value) {
- let len = s.as_str().len();
+ let s_str = s.as_str();
+ let str_global = *self.const_str_cache.borrow_mut().entry(s).or_insert_with(|| {
+ let sc = self.const_bytes(s_str.as_bytes());
+ let sym = self.generate_local_symbol_name("str");
+ let g = self.define_global(&sym, self.val_ty(sc)).unwrap_or_else(|| {
+ bug!("symbol `{}` is already defined", sym);
+ });
+ unsafe {
+ llvm::LLVMSetInitializer(g, sc);
+ llvm::LLVMSetGlobalConstant(g, True);
+ llvm::LLVMRustSetLinkage(g, llvm::Linkage::InternalLinkage);
+ }
+ g
+ });
+ let len = s_str.len();
let cs = consts::ptrcast(
- self.const_cstr(s, false),
+ str_global,
self.type_ptr_to(self.layout_of(self.tcx.types.str_).llvm_type(self)),
);
(cs, self.const_usize(len as u64))
let (base_addr, base_addr_space) = match self.tcx.global_alloc(alloc_id) {
GlobalAlloc::Memory(alloc) => {
let init = const_alloc_to_llvm(self, alloc);
+ let alloc = alloc.inner();
let value = match alloc.mutability {
Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None),
_ => self.static_addr_of(init, alloc.align, None),
}
}
- fn const_data_from_alloc(&self, alloc: &Allocation) -> Self::Value {
+ fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value {
const_alloc_to_llvm(self, alloc)
}
fn from_const_alloc(
&self,
layout: TyAndLayout<'tcx>,
- alloc: &Allocation,
+ alloc: ConstAllocation<'tcx>,
offset: Size,
) -> PlaceRef<'tcx, &'ll Value> {
- assert_eq!(alloc.align, layout.align.abi);
+ let alloc_align = alloc.inner().align;
+ assert_eq!(alloc_align, layout.align.abi);
let llty = self.type_ptr_to(layout.llvm_type(self));
let llval = if layout.size == Size::ZERO {
- let llval = self.const_usize(alloc.align.bytes());
+ let llval = self.const_usize(alloc_align.bytes());
unsafe { llvm::LLVMConstIntToPtr(llval, llty) }
} else {
let init = const_alloc_to_llvm(self, alloc);
- let base_addr = self.static_addr_of(init, alloc.align, None);
+ let base_addr = self.static_addr_of(init, alloc_align, None);
let llval = unsafe {
llvm::LLVMRustConstInBoundsGEP2(
use rustc_hir::def_id::DefId;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc_middle::mir::interpret::{
- read_target_uint, Allocation, ErrorHandled, GlobalAlloc, InitChunk, Pointer,
+ read_target_uint, Allocation, ConstAllocation, ErrorHandled, GlobalAlloc, InitChunk, Pointer,
Scalar as InterpScalar,
};
use rustc_middle::mir::mono::MonoItem;
use std::ops::Range;
use tracing::debug;
-pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll Value {
+pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation<'_>) -> &'ll Value {
+ let alloc = alloc.inner();
let mut llvals = Vec::with_capacity(alloc.relocations().len() + 1);
let dl = cx.data_layout();
let pointer_size = dl.pointer_size.bytes() as usize;
pub fn codegen_static_initializer<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
def_id: DefId,
-) -> Result<(&'ll Value, &'tcx Allocation), ErrorHandled> {
+) -> Result<(&'ll Value, ConstAllocation<'tcx>), ErrorHandled> {
let alloc = cx.tcx.eval_static_initializer(def_id)?;
Ok((const_alloc_to_llvm(cx, alloc), alloc))
}
// Error has already been reported
return;
};
+ let alloc = alloc.inner();
let g = self.get_static(def_id);
pub vtables:
RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), &'ll Value>>,
/// Cache of constant strings,
- pub const_cstr_cache: RefCell<FxHashMap<Symbol, &'ll Value>>,
+ pub const_str_cache: RefCell<FxHashMap<Symbol, &'ll Value>>,
/// Reverse-direction for const ptrs cast from globals.
///
codegen_unit,
instances: Default::default(),
vtables: Default::default(),
- const_cstr_cache: Default::default(),
+ const_str_cache: Default::default(),
const_unsized: Default::default(),
const_globals: Default::default(),
statics_to_rauw: RefCell::new(Vec::new()),
use abi::Abi::*;
let tp_ty = substs.type_at(0);
let layout = self.layout_of(tp_ty).layout;
- let use_integer_compare = match layout.abi {
+ let use_integer_compare = match layout.abi() {
Scalar(_) | ScalarPair(_, _) => true,
Uninhabited | Vector { .. } => false,
Aggregate { .. } => {
// For rusty ABIs, small aggregates are actually passed
// as `RegKind::Integer` (see `FnAbi::adjust_for_abi`),
// so we re-use that same threshold here.
- layout.size <= self.data_layout().pointer_size * 2
+ layout.size() <= self.data_layout().pointer_size * 2
}
};
let a = args[0].immediate();
let b = args[1].immediate();
- if layout.size.bytes() == 0 {
+ if layout.size().bytes() == 0 {
self.const_bool(true)
} else if use_integer_compare {
- let integer_ty = self.type_ix(layout.size.bits());
+ let integer_ty = self.type_ix(layout.size().bits());
let ptr_ty = self.type_ptr_to(integer_ty);
let a_ptr = self.bitcast(a, ptr_ty);
- let a_val = self.load(integer_ty, a_ptr, layout.align.abi);
+ let a_val = self.load(integer_ty, a_ptr, layout.align().abi);
let b_ptr = self.bitcast(b, ptr_ty);
- let b_val = self.load(integer_ty, b_ptr, layout.align.abi);
+ let b_val = self.load(integer_ty, b_ptr, layout.align().abi);
self.icmp(IntPredicate::IntEQ, a_val, b_val)
} else {
let i8p_ty = self.type_i8p();
let a_ptr = self.bitcast(a, i8p_ty);
let b_ptr = self.bitcast(b, i8p_ty);
- let n = self.const_usize(layout.size.bytes());
+ let n = self.const_usize(layout.size().bytes());
let cmp = self.call_intrinsic("memcmp", &[a_ptr, b_ptr, n]);
self.icmp(IntPredicate::IntEQ, cmp, self.const_i32(0))
}
MD_nontemporal = 9,
MD_mem_parallel_loop_access = 10,
MD_nonnull = 11,
+ MD_align = 17,
MD_type = 19,
MD_noundef = 29,
}
// Operations on attributes
pub fn LLVMRustCreateAttrNoValue(C: &Context, attr: AttributeKind) -> &Attribute;
- pub fn LLVMRustCreateAttrString(C: &Context, Name: *const c_char) -> &Attribute;
- pub fn LLVMRustCreateAttrStringValue(
+ pub fn LLVMCreateStringAttribute(
C: &Context,
Name: *const c_char,
+ NameLen: c_uint,
Value: *const c_char,
+ ValueLen: c_uint,
) -> &Attribute;
pub fn LLVMRustCreateAlignmentAttr(C: &Context, bytes: u64) -> &Attribute;
pub fn LLVMRustCreateDereferenceableAttr(C: &Context, bytes: u64) -> &Attribute;
}
}
-pub fn CreateAttrStringValue<'ll>(llcx: &'ll Context, attr: &CStr, value: &CStr) -> &'ll Attribute {
- unsafe { LLVMRustCreateAttrStringValue(llcx, attr.as_ptr(), value.as_ptr()) }
+pub fn CreateAttrStringValue<'ll>(llcx: &'ll Context, attr: &str, value: &str) -> &'ll Attribute {
+ unsafe {
+ LLVMCreateStringAttribute(
+ llcx,
+ attr.as_ptr().cast(),
+ attr.len().try_into().unwrap(),
+ value.as_ptr().cast(),
+ value.len().try_into().unwrap(),
+ )
+ }
}
-pub fn CreateAttrString<'ll>(llcx: &'ll Context, attr: &CStr) -> &'ll Attribute {
- unsafe { LLVMRustCreateAttrStringValue(llcx, attr.as_ptr(), std::ptr::null()) }
+pub fn CreateAttrString<'ll>(llcx: &'ll Context, attr: &str) -> &'ll Attribute {
+ unsafe {
+ LLVMCreateStringAttribute(
+ llcx,
+ attr.as_ptr().cast(),
+ attr.len().try_into().unwrap(),
+ std::ptr::null(),
+ 0,
+ )
+ }
}
pub fn CreateAlignmentAttr(llcx: &Context, bytes: u64) -> &Attribute {
/// The list of LLVM features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
/// `--target` and similar).
pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<String> {
- // Features that come earlier are overriden by conflicting features later in the string.
+ // Features that come earlier are overridden by conflicting features later in the string.
// Typically we'll want more explicit settings to override the implicit ones, so:
//
- // * Features from -Ctarget-cpu=*; are overriden by [^1]
- // * Features implied by --target; are overriden by
- // * Features from -Ctarget-feature; are overriden by
+ // * Features from -Ctarget-cpu=*; are overridden by [^1]
+ // * Features implied by --target; are overridden by
+ // * Features from -Ctarget-feature; are overridden by
// * function specific features.
//
// [^1]: target-cpu=native is handled here, other target-cpu values are handled implicitly
// FIXME(nagisa): it isn't clear what's the best interaction between features implied by
// `-Ctarget-cpu` and `--target` are. On one hand, you'd expect CLI arguments to always
// override anything that's implicit, so e.g. when there's no `--target` flag, features implied
- // the host target are overriden by `-Ctarget-cpu=*`. On the other hand, what about when both
+ // the host target are overridden by `-Ctarget-cpu=*`. On the other hand, what about when both
// `--target` and `-Ctarget-cpu=*` are specified? Both then imply some target features and both
// flags are specified by the user on the CLI. It isn't as clear-cut which order of precedence
// should be taken in cases like these.
[dependencies]
bitflags = "1.2.1"
cc = "1.0.69"
-itertools = "0.10"
+itertools = "0.10.1"
tracing = "0.1"
libc = "0.2.50"
jobserver = "0.1.22"
// Type Names for Debug Info.
-// Notes on targetting MSVC:
+// Notes on targeting MSVC:
// In general, MSVC's debugger attempts to parse all arguments as C++ expressions,
// even if the argument is explicitly a symbol name.
// As such, there are many things that cause parsing issues:
// calculate the range of values for the dataful variant
let dataful_discriminant_range =
- dataful_variant_layout.largest_niche.unwrap().scalar.valid_range;
+ dataful_variant_layout.largest_niche().unwrap().scalar.valid_range;
let min = dataful_discriminant_range.start;
let min = tag.value.size(&tcx).truncate(min);
// #[target_feature].
("thumb-mode", Some(sym::arm_target_feature)),
("thumb2", Some(sym::arm_target_feature)),
+ ("d32", Some(sym::arm_target_feature)),
];
const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
use super::BackendTypes;
use crate::mir::place::PlaceRef;
-use rustc_middle::mir::interpret::{Allocation, Scalar};
+use rustc_middle::mir::interpret::{ConstAllocation, Scalar};
use rustc_middle::ty::layout::TyAndLayout;
use rustc_span::Symbol;
use rustc_target::abi::{self, Size};
fn const_to_opt_uint(&self, v: Self::Value) -> Option<u64>;
fn const_to_opt_u128(&self, v: Self::Value, sign_ext: bool) -> Option<u128>;
- fn const_data_from_alloc(&self, alloc: &Allocation) -> Self::Value;
+ fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value;
fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: Self::Type) -> Self::Value;
fn from_const_alloc(
&self,
layout: TyAndLayout<'tcx>,
- alloc: &Allocation,
+ alloc: ConstAllocation<'tcx>,
offset: Size,
) -> PlaceRef<'tcx, Self::Value>;
"the raw bytes of the constant ({}",
display_allocation(
*ecx.tcx,
- ecx.tcx.global_alloc(alloc_id).unwrap_memory()
+ ecx.tcx.global_alloc(alloc_id).unwrap_memory().inner()
)
));
},
use rustc_target::spec::abi::Abi;
use crate::interpret::{
- self, compile_time_machine, AllocId, Allocation, Frame, ImmTy, InterpCx, InterpResult, OpTy,
- PlaceTy, Scalar, StackPopUnwind,
+ self, compile_time_machine, AllocId, ConstAllocation, Frame, ImmTy, InterpCx, InterpResult,
+ OpTy, PlaceTy, Scalar, StackPopUnwind,
};
use super::error::*;
fn before_access_global(
memory_extra: &MemoryExtra,
alloc_id: AllocId,
- allocation: &Allocation,
+ alloc: ConstAllocation<'tcx>,
static_def_id: Option<DefId>,
is_write: bool,
) -> InterpResult<'tcx> {
+ let alloc = alloc.inner();
if is_write {
// Write access. These are never allowed, but we give a targeted error message.
- if allocation.mutability == Mutability::Not {
+ if alloc.mutability == Mutability::Not {
Err(err_ub!(WriteToReadOnly(alloc_id)).into())
} else {
Err(ConstEvalErrKind::ModifiedGlobal.into())
// But make sure we never accept a read from something mutable, that would be
// unsound. The reason is that as the content of this allocation may be different
// now and at run-time, so if we permit reading now we might return the wrong value.
- assert_eq!(allocation.mutability, Mutability::Not);
+ assert_eq!(alloc.mutability, Mutability::Not);
Ok(())
}
}
let mplace = ecx.deref_operand(&op).unwrap();
if let Some(alloc_id) = mplace.ptr.provenance {
assert_eq!(
- tcx.get_global_alloc(alloc_id).unwrap().unwrap_memory().mutability,
+ tcx.get_global_alloc(alloc_id).unwrap().unwrap_memory().inner().mutability,
Mutability::Not,
"deref_const cannot be used with mutable allocations as \
that could allow pattern matching to observe mutable statics",
Ok(())
}
- fn misc_cast(
+ pub fn misc_cast(
&self,
src: &ImmTy<'tcx, M::PointerTag>,
cast_ty: Ty<'tcx>,
if let Some(discr) = src.layout.ty.discriminant_for_variant(*self.tcx, index) {
assert!(src.layout.is_zst());
let discr_layout = self.layout_of(discr.ty)?;
- return Ok(self.cast_from_scalar(discr.val, discr_layout, cast_ty).into());
+ return Ok(self.cast_from_int_like(discr.val, discr_layout, cast_ty).into());
}
}
Variants::Multiple { .. } => {}
}
}
- // # The remaining source values are scalar.
+ // # The remaining source values are scalar and "int-like".
// For all remaining casts, we either
// (a) cast a raw ptr to usize, or
// (b) cast from an integer-like (including bool, char, enums).
// In both cases we want the bits.
let bits = src.to_scalar()?.to_bits(src.layout.size)?;
- Ok(self.cast_from_scalar(bits, src.layout, cast_ty).into())
+ Ok(self.cast_from_int_like(bits, src.layout, cast_ty).into())
}
- pub(super) fn cast_from_scalar(
+ fn cast_from_int_like(
&self,
v: u128, // raw bits (there is no ScalarTy so we separate data+layout)
src_layout: TyAndLayout<'tcx>,
use rustc_ast::Mutability;
-use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy, ValueVisitor};
+use super::{
+ AllocId, Allocation, ConstAllocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy,
+ ValueVisitor,
+};
use crate::const_eval;
pub trait CompileTimeMachine<'mir, 'tcx, T> = Machine<
alloc.mutability = Mutability::Not;
};
// link the alloc id to the actual allocation
- let alloc = tcx.intern_const_alloc(alloc);
leftover_allocations.extend(alloc.relocations().iter().map(|&(_, alloc_id)| alloc_id));
+ let alloc = tcx.intern_const_alloc(alloc);
tcx.set_alloc_id_memory(alloc_id, alloc);
None
}
}
let alloc = tcx.intern_const_alloc(alloc);
tcx.set_alloc_id_memory(alloc_id, alloc);
- for &(_, alloc_id) in alloc.relocations().iter() {
+ for &(_, alloc_id) in alloc.inner().relocations().iter() {
if leftover_allocations.insert(alloc_id) {
todo.push(alloc_id);
}
&mut InterpCx<'mir, 'tcx, M>,
&PlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, ()>,
- ) -> InterpResult<'tcx, &'tcx Allocation> {
+ ) -> InterpResult<'tcx, ConstAllocation<'tcx>> {
let dest = self.allocate(layout, MemoryKind::Stack)?;
f(self, &dest.into())?;
let mut alloc = self.memory.alloc_map.remove(&dest.ptr.provenance.unwrap()).unwrap().1;
sym::type_name => {
ensure_monomorphic_enough(tcx, tp_ty)?;
let alloc = type_name::alloc_type_name(tcx, tp_ty);
- ConstValue::Slice { data: alloc, start: 0, end: alloc.len() }
+ ConstValue::Slice { data: alloc, start: 0, end: alloc.inner().len() }
}
sym::needs_drop => {
ensure_monomorphic_enough(tcx, tp_ty)?;
sym::saturating_add | sym::saturating_sub => {
let l = self.read_immediate(&args[0])?;
let r = self.read_immediate(&args[1])?;
- let is_add = intrinsic_name == sym::saturating_add;
- let (val, overflowed, _ty) = self.overflowing_binary_op(
- if is_add { BinOp::Add } else { BinOp::Sub },
+ let val = self.saturating_arith(
+ if intrinsic_name == sym::saturating_add { BinOp::Add } else { BinOp::Sub },
&l,
&r,
)?;
- let val = if overflowed {
- let size = l.layout.size;
- let num_bits = size.bits();
- if l.layout.abi.is_signed() {
- // For signed ints the saturated value depends on the sign of the first
- // term since the sign of the second term can be inferred from this and
- // the fact that the operation has overflowed (if either is 0 no
- // overflow can occur)
- let first_term: u128 = l.to_scalar()?.to_bits(l.layout.size)?;
- let first_term_positive = first_term & (1 << (num_bits - 1)) == 0;
- if first_term_positive {
- // Negative overflow not possible since the positive first term
- // can only increase an (in range) negative term for addition
- // or corresponding negated positive term for subtraction
- Scalar::from_uint(
- (1u128 << (num_bits - 1)) - 1, // max positive
- Size::from_bits(num_bits),
- )
- } else {
- // Positive overflow not possible for similar reason
- // max negative
- Scalar::from_uint(1u128 << (num_bits - 1), Size::from_bits(num_bits))
- }
- } else {
- // unsigned
- if is_add {
- // max unsigned
- Scalar::from_uint(size.unsigned_int_max(), Size::from_bits(num_bits))
- } else {
- // underflow to 0
- Scalar::from_uint(0u128, Size::from_bits(num_bits))
- }
- }
- } else {
- val
- };
self.write_scalar(val, dest)?;
}
sym::discriminant_value => {
self.binop_ignore_overflow(BinOp::Div, &a, &b, dest)
}
+ pub fn saturating_arith(
+ &self,
+ mir_op: BinOp,
+ l: &ImmTy<'tcx, M::PointerTag>,
+ r: &ImmTy<'tcx, M::PointerTag>,
+ ) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
+ assert!(matches!(mir_op, BinOp::Add | BinOp::Sub));
+ let (val, overflowed, _ty) = self.overflowing_binary_op(mir_op, l, r)?;
+ Ok(if overflowed {
+ let size = l.layout.size;
+ let num_bits = size.bits();
+ if l.layout.abi.is_signed() {
+ // For signed ints the saturated value depends on the sign of the first
+ // term since the sign of the second term can be inferred from this and
+ // the fact that the operation has overflowed (if either is 0 no
+ // overflow can occur)
+ let first_term: u128 = l.to_scalar()?.to_bits(l.layout.size)?;
+ let first_term_positive = first_term & (1 << (num_bits - 1)) == 0;
+ if first_term_positive {
+ // Negative overflow not possible since the positive first term
+ // can only increase an (in range) negative term for addition
+ // or corresponding negated positive term for subtraction
+ Scalar::from_int(size.signed_int_max(), size)
+ } else {
+ // Positive overflow not possible for similar reason
+ // max negative
+ Scalar::from_int(size.signed_int_min(), size)
+ }
+ } else {
+ // unsigned
+ if matches!(mir_op, BinOp::Add) {
+ // max unsigned
+ Scalar::from_uint(size.unsigned_int_max(), size)
+ } else {
+ // underflow to 0
+ Scalar::from_uint(0u128, size)
+ }
+ }
+ } else {
+ val
+ })
+ }
+
/// Offsets a pointer by some multiple of its type, returning an error if the pointer leaves its
/// allocation. For integer pointers, we consider each of them their own tiny allocation of size
/// 0, so offset-by-0 (and only 0) is okay -- except that null cannot be offset by _any_ value.
use rustc_hir::def_id::CrateNum;
use rustc_hir::definitions::DisambiguatedDefPathData;
-use rustc_middle::mir::interpret::Allocation;
+use rustc_middle::mir::interpret::{Allocation, ConstAllocation};
use rustc_middle::ty::{
self,
print::{PrettyPrinter, Print, Printer},
}
/// Directly returns an `Allocation` containing an absolute path representation of the given type.
-crate fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx Allocation {
+crate fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAllocation<'tcx> {
let path = AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path;
let alloc = Allocation::from_bytes_byte_aligned_immutable(path.into_bytes());
tcx.intern_const_alloc(alloc)
use rustc_target::spec::abi::Abi;
use super::{
- AllocId, AllocRange, Allocation, Frame, ImmTy, InterpCx, InterpResult, LocalValue, MemPlace,
- Memory, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar, StackPopUnwind,
+ AllocId, AllocRange, Allocation, ConstAllocation, Frame, ImmTy, InterpCx, InterpResult,
+ LocalValue, MemPlace, Memory, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar,
+ StackPopUnwind,
};
/// Data returned by Machine::stack_pop,
fn before_access_global(
_memory_extra: &Self::MemoryExtra,
_alloc_id: AllocId,
- _allocation: &Allocation,
+ _allocation: ConstAllocation<'tcx>,
_static_def_id: Option<DefId>,
_is_write: bool,
) -> InterpResult<'tcx> {
}
};
M::before_access_global(&self.extra, id, alloc, def_id, is_write)?;
- let alloc = Cow::Borrowed(alloc);
// We got tcx memory. Let the machine initialize its "extra" stuff.
let alloc = M::init_allocation_extra(
self,
id, // always use the ID we got as input, not the "hidden" one.
- alloc,
+ Cow::Borrowed(alloc.inner()),
M::GLOBAL_KIND.map(MemoryKind::Machine),
);
Ok(alloc)
Some(GlobalAlloc::Memory(alloc)) => {
// Need to duplicate the logic here, because the global allocations have
// different associated types than the interpreter-local ones.
+ let alloc = alloc.inner();
Ok((alloc.size(), alloc.align))
}
Some(GlobalAlloc::Function(_)) => bug!("We already checked function pointers above"),
&mut *fmt,
self.mem.tcx,
&mut allocs_to_print,
- alloc,
+ alloc.inner(),
)?;
}
Some(GlobalAlloc::Function(func)) => {
let val =
self.subst_from_current_frame_and_normalize_erasing_regions(constant.literal)?;
// This can still fail:
- // * During ConstProp, with `TooGeneric` or since the `requried_consts` were not all
+ // * During ConstProp, with `TooGeneric` or since the `required_consts` were not all
// checked yet.
// * During CTFE, since promoteds in `const`/`static` initializer bodies can fail.
let tag_val = self.read_immediate(&self.operand_field(op, tag_field)?)?;
assert_eq!(tag_layout.size, tag_val.layout.size);
assert_eq!(tag_layout.abi.is_signed(), tag_val.layout.abi.is_signed());
- let tag_val = tag_val.to_scalar()?;
- trace!("tag value: {:?}", tag_val);
+ trace!("tag value: {}", tag_val);
// Figure out which discriminant and variant this corresponds to.
Ok(match *tag_encoding {
TagEncoding::Direct => {
+ // Generate a specific error if `tag_val` is not an integer.
+ // (`tag_bits` itself is only used for error messages below.)
let tag_bits = tag_val
+ .to_scalar()?
.try_to_int()
.map_err(|dbg_val| err_ub!(InvalidTag(dbg_val)))?
.assert_bits(tag_layout.size);
// Cast bits from tag layout to discriminant layout.
- let discr_val = self.cast_from_scalar(tag_bits, tag_layout, discr_layout.ty);
+ // After the checks we did above, this cannot fail.
+ let discr_val =
+ self.misc_cast(&tag_val, discr_layout.ty).unwrap().to_scalar().unwrap();
let discr_bits = discr_val.assert_bits(discr_layout.size);
// Convert discriminant to variant index, and catch invalid discriminants.
let index = match *op.layout.ty.kind() {
(discr_val, index.0)
}
TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => {
+ let tag_val = tag_val.to_scalar()?;
// Compute the variant this niche value/"tag" corresponds to. With niche layout,
// discriminant (encoded in niche/tag) and variant index are the same.
let variants_start = niche_variants.start().as_u32();
// Shift ops can have an RHS with a different numeric type.
if bin_op == Shl || bin_op == Shr {
- let signed = left_layout.abi.is_signed();
let size = u128::from(left_layout.size.bits());
+ // Even if `r` is signed, we treat it as if it was unsigned (i.e., we use its
+ // zero-extended form). This matches the codegen backend:
+ // <https://github.com/rust-lang/rust/blob/c274e4969f058b1c644243181ece9f829efa7594/compiler/rustc_codegen_ssa/src/base.rs#L315-L317>.
+ // The overflow check is also ignorant to the sign:
+ // <https://github.com/rust-lang/rust/blob/c274e4969f058b1c644243181ece9f829efa7594/compiler/rustc_codegen_ssa/src/mir/rvalue.rs#L728>.
+ // This would behave rather strangely if we had integer types of size 256: a shift by
+ // -1i8 would actually shift by 255, but that would *not* be considered overflowing. A
+ // shift by -1i16 though would be considered overflowing. If we had integers of size
+ // 512, then a shift by -1i8 would even produce a different result than one by -1i16:
+ // the first shifts by 255, the latter by u16::MAX % 512 = 511. Lucky enough, our
+ // integers are maximally 128bits wide, so negative shifts *always* overflow and we have
+ // consistent results for the same value represented at different bit widths.
+ assert!(size <= 128);
let overflow = r >= size;
// The shift offset is implicitly masked to the type size, to make sure this operation
// is always defined. This is the one MIR operator that does *not* directly map to a
// single LLVM operation. See
- // <https://github.com/rust-lang/rust/blob/a3b9405ae7bb6ab4e8103b414e75c44598a10fd2/compiler/rustc_codegen_ssa/src/common.rs#L131-L158>
+ // <https://github.com/rust-lang/rust/blob/c274e4969f058b1c644243181ece9f829efa7594/compiler/rustc_codegen_ssa/src/common.rs#L131-L158>
// for the corresponding truncation in our codegen backends.
let r = r % size;
let r = u32::try_from(r).unwrap(); // we masked so this will always fit
- let result = if signed {
+ let result = if left_layout.abi.is_signed() {
let l = self.sign_extend(l, left_layout) as i128;
let result = match bin_op {
Shl => l.checked_shl(r).unwrap(),
let mut target_block = targets.otherwise();
for (const_int, target) in targets.iter() {
- // Compare using binary_op, to also support pointer values
+ // Compare using MIR BinOp::Eq, to also support pointer values.
+ // (Avoiding `self.binary_op` as that does some redundant layout computation.)
let res = self
.overflowing_binary_op(
mir::BinOp::Eq,
}
}
- self.check_item_predicates();
-
for (idx, local) in body.local_decls.iter_enumerated() {
// Handle the return place below.
if idx == RETURN_PLACE || local.internal {
match *ty.kind() {
ty::Ref(_, _, hir::Mutability::Mut) => self.check_op(ops::ty::MutRef(kind)),
- ty::Opaque(..) => self.check_op(ops::ty::ImplTrait),
- ty::FnPtr(..) => self.check_op(ops::ty::FnPtr(kind)),
-
- ty::Dynamic(preds, _) => {
- for pred in preds.iter() {
- match pred.skip_binder() {
- ty::ExistentialPredicate::AutoTrait(_)
- | ty::ExistentialPredicate::Projection(_) => {
- self.check_op(ops::ty::DynTrait(kind))
- }
- ty::ExistentialPredicate::Trait(trait_ref) => {
- if Some(trait_ref.def_id) != self.tcx.lang_items().sized_trait() {
- self.check_op(ops::ty::DynTrait(kind))
- }
- }
- }
- }
- }
_ => {}
}
}
}
- fn check_item_predicates(&mut self) {
- let ConstCx { tcx, .. } = *self.ccx;
-
- let mut current = self.def_id().to_def_id();
- loop {
- let predicates = tcx.predicates_of(current);
- for (predicate, _) in predicates.predicates {
- match predicate.kind().skip_binder() {
- ty::PredicateKind::RegionOutlives(_)
- | ty::PredicateKind::TypeOutlives(_)
- | ty::PredicateKind::WellFormed(_)
- | ty::PredicateKind::Projection(_)
- | ty::PredicateKind::ConstEvaluatable(..)
- | ty::PredicateKind::ConstEquate(..)
- | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue,
- ty::PredicateKind::ObjectSafe(_) => {
- bug!("object safe predicate on function: {:#?}", predicate)
- }
- ty::PredicateKind::ClosureKind(..) => {
- bug!("closure kind predicate on function: {:#?}", predicate)
- }
- ty::PredicateKind::Subtype(_) | ty::PredicateKind::Coerce(_) => {
- bug!("subtype/coerce predicate on function: {:#?}", predicate)
- }
- ty::PredicateKind::Trait(pred) => {
- if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
- continue;
- }
- match pred.self_ty().kind() {
- ty::Param(p) => {
- let generics = tcx.generics_of(current);
- let def = generics.type_param(p, tcx);
- let span = tcx.def_span(def.def_id);
-
- // These are part of the function signature, so treat them like
- // arguments when determining importance.
- let kind = LocalKind::Arg;
-
- self.check_op_spanned(ops::ty::TraitBound(kind), span);
- }
- // other kinds of bounds are either tautologies
- // or cause errors in other passes
- _ => continue,
- }
- }
- }
- }
- match predicates.parent {
- Some(parent) => current = parent,
- None => break,
- }
- }
- }
-
fn check_mut_borrow(&mut self, local: Local, kind: hir::BorrowKind) {
match self.const_kind() {
// In a const fn all borrows are transient or point to the places given via
),
_,
_,
- ) => self.check_op(ops::FnPtrCast),
+ ) => {
+ // Nothing to do here. Function pointer casts are allowed now.
+ }
Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), _, _) => {
// Nothing to check here (`check_local_or_return_ty` ensures no trait objects occur
}
}
-#[derive(Debug)]
-pub struct FnPtrCast;
-impl<'tcx> NonConstOp<'tcx> for FnPtrCast {
- fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
- if ccx.const_kind() != hir::ConstContext::ConstFn {
- Status::Allowed
- } else {
- Status::Unstable(sym::const_fn_fn_ptr_basics)
- }
- }
-
- fn build_error(
- &self,
- ccx: &ConstCx<'_, 'tcx>,
- span: Span,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- feature_err(
- &ccx.tcx.sess.parse_sess,
- sym::const_fn_fn_ptr_basics,
- span,
- &format!("function pointer casts are not allowed in {}s", ccx.const_kind()),
- )
- }
-}
-
#[derive(Debug)]
pub struct Generator(pub hir::GeneratorKind);
impl<'tcx> NonConstOp<'tcx> for Generator {
)
}
}
-
- #[derive(Debug)]
- pub struct FnPtr(pub mir::LocalKind);
- impl<'tcx> NonConstOp<'tcx> for FnPtr {
- fn importance(&self) -> DiagnosticImportance {
- match self.0 {
- mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
- mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => {
- DiagnosticImportance::Primary
- }
- }
- }
-
- fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
- if ccx.const_kind() != hir::ConstContext::ConstFn {
- Status::Allowed
- } else {
- Status::Unstable(sym::const_fn_fn_ptr_basics)
- }
- }
-
- fn build_error(
- &self,
- ccx: &ConstCx<'_, 'tcx>,
- span: Span,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- feature_err(
- &ccx.tcx.sess.parse_sess,
- sym::const_fn_fn_ptr_basics,
- span,
- &format!("function pointers cannot appear in {}s", ccx.const_kind()),
- )
- }
- }
-
- #[derive(Debug)]
- pub struct ImplTrait;
- impl<'tcx> NonConstOp<'tcx> for ImplTrait {
- fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
- Status::Unstable(sym::const_impl_trait)
- }
-
- fn build_error(
- &self,
- ccx: &ConstCx<'_, 'tcx>,
- span: Span,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- feature_err(
- &ccx.tcx.sess.parse_sess,
- sym::const_impl_trait,
- span,
- &format!("`impl Trait` is not allowed in {}s", ccx.const_kind()),
- )
- }
- }
-
- #[derive(Debug)]
- pub struct TraitBound(pub mir::LocalKind);
- impl<'tcx> NonConstOp<'tcx> for TraitBound {
- fn importance(&self) -> DiagnosticImportance {
- match self.0 {
- mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
- mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => {
- DiagnosticImportance::Primary
- }
- }
- }
-
- fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
- if ccx.const_kind() != hir::ConstContext::ConstFn {
- Status::Allowed
- } else {
- Status::Unstable(sym::const_fn_trait_bound)
- }
- }
-
- fn build_error(
- &self,
- ccx: &ConstCx<'_, 'tcx>,
- span: Span,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- let mut err = feature_err(
- &ccx.tcx.sess.parse_sess,
- sym::const_fn_trait_bound,
- span,
- "trait bounds other than `Sized` on const fn parameters are unstable",
- );
-
- match ccx.fn_sig() {
- Some(fn_sig) if !fn_sig.span.contains(span) => {
- err.span_label(fn_sig.span, "function declared as const here");
- }
- _ => {}
- }
-
- err
- }
- }
-
- #[derive(Debug)]
- pub struct DynTrait(pub mir::LocalKind);
- impl<'tcx> NonConstOp<'tcx> for DynTrait {
- fn importance(&self) -> DiagnosticImportance {
- match self.0 {
- mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
- mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => {
- DiagnosticImportance::Primary
- }
- }
- }
-
- fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
- if ccx.const_kind() != hir::ConstContext::ConstFn {
- Status::Allowed
- } else {
- Status::Unstable(sym::const_fn_trait_bound)
- }
- }
-
- fn build_error(
- &self,
- ccx: &ConstCx<'_, 'tcx>,
- span: Span,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- let mut err = feature_err(
- &ccx.tcx.sess.parse_sess,
- sym::const_fn_trait_bound,
- span,
- "trait objects in const fn are unstable",
- );
-
- match ccx.fn_sig() {
- Some(fn_sig) if !fn_sig.span.contains(span) => {
- err.span_label(fn_sig.span, "function declared as const here");
- }
- _ => {}
- }
-
- err
- }
- }
-
- /// A trait bound with the `?const Trait` opt-out
- #[derive(Debug)]
- pub struct TraitBoundNotConst;
- impl<'tcx> NonConstOp<'tcx> for TraitBoundNotConst {
- fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
- Status::Unstable(sym::const_trait_bound_opt_out)
- }
-
- fn build_error(
- &self,
- ccx: &ConstCx<'_, 'tcx>,
- span: Span,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- feature_err(
- &ccx.tcx.sess.parse_sess,
- sym::const_trait_bound_opt_out,
- span,
- "`?const Trait` syntax is unstable",
- )
- }
- }
}
rayon = { version = "0.3.2", package = "rustc-rayon" }
rayon-core = { version = "0.3.2", package = "rustc-rayon-core" }
rustc-hash = "1.1.0"
-smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
+smallvec = { version = "1.6.1", features = ["const_generics", "union", "may_dangle"] }
rustc_index = { path = "../rustc_index", package = "rustc_index" }
bitflags = "1.2.1"
measureme = "10.0.0"
+use crate::stable_hasher::{HashStable, StableHasher};
use std::cmp::Ordering;
use std::hash::{Hash, Hasher};
use std::ops::Deref;
impl<'a, T> Eq for Interned<'a, T> {}
-// In practice you can't intern any `T` that doesn't implement `Eq`, because
-// that's needed for hashing. Therefore, we won't be interning any `T` that
-// implements `PartialOrd` without also implementing `Ord`. So we can have the
-// bound `T: Ord` here and avoid duplication with the `Ord` impl below.
-impl<'a, T: Ord> PartialOrd for Interned<'a, T> {
+impl<'a, T: PartialOrd> PartialOrd for Interned<'a, T> {
fn partial_cmp(&self, other: &Interned<'a, T>) -> Option<Ordering> {
- Some(self.cmp(other))
+ // Pointer equality implies equality, due to the uniqueness constraint,
+ // but the contents must be compared otherwise.
+ if ptr::eq(self.0, other.0) {
+ Some(Ordering::Equal)
+ } else {
+ let res = self.0.partial_cmp(&other.0);
+ debug_assert_ne!(res, Some(Ordering::Equal));
+ res
+ }
}
}
}
}
+impl<T, CTX> HashStable<CTX> for Interned<'_, T>
+where
+ T: HashStable<CTX>,
+{
+ fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+ self.0.hash_stable(hcx, hasher);
+ }
+}
+
#[cfg(test)]
mod tests;
pub mod owning_ref;
pub mod sip128;
pub mod small_c_str;
+pub mod small_str;
pub mod snapshot_map;
pub mod stable_map;
pub mod svh;
impl Deref for SmallCStr {
type Target = ffi::CStr;
+ #[inline]
fn deref(&self) -> &ffi::CStr {
self.as_c_str()
}
--- /dev/null
+use smallvec::SmallVec;
+
+#[cfg(test)]
+mod tests;
+
+/// Like SmallVec but for strings.
+#[derive(Default)]
+pub struct SmallStr<const N: usize>(SmallVec<[u8; N]>);
+
+impl<const N: usize> SmallStr<N> {
+ #[inline]
+ pub fn new() -> Self {
+ SmallStr(SmallVec::default())
+ }
+
+ #[inline]
+ pub fn push_str(&mut self, s: &str) {
+ self.0.extend_from_slice(s.as_bytes());
+ }
+
+ #[inline]
+ pub fn empty(&self) -> bool {
+ self.0.is_empty()
+ }
+
+ #[inline]
+ pub fn spilled(&self) -> bool {
+ self.0.spilled()
+ }
+
+ #[inline]
+ pub fn as_str(&self) -> &str {
+ unsafe { std::str::from_utf8_unchecked(self.0.as_slice()) }
+ }
+}
+
+impl<const N: usize> std::ops::Deref for SmallStr<N> {
+ type Target = str;
+
+ #[inline]
+ fn deref(&self) -> &str {
+ self.as_str()
+ }
+}
+
+impl<const N: usize, A: AsRef<str>> FromIterator<A> for SmallStr<N> {
+ #[inline]
+ fn from_iter<T>(iter: T) -> Self
+ where
+ T: IntoIterator<Item = A>,
+ {
+ let mut s = SmallStr::default();
+ s.extend(iter);
+ s
+ }
+}
+
+impl<const N: usize, A: AsRef<str>> Extend<A> for SmallStr<N> {
+ #[inline]
+ fn extend<T>(&mut self, iter: T)
+ where
+ T: IntoIterator<Item = A>,
+ {
+ for a in iter.into_iter() {
+ self.push_str(a.as_ref());
+ }
+ }
+}
--- /dev/null
+use super::*;
+
+#[test]
+fn empty() {
+ let s = SmallStr::<1>::new();
+ assert!(s.empty());
+ assert_eq!("", s.as_str());
+ assert!(!s.spilled());
+}
+
+#[test]
+fn from_iter() {
+ let s = ["aa", "bb", "cc"].iter().collect::<SmallStr<6>>();
+ assert_eq!("aabbcc", s.as_str());
+ assert!(!s.spilled());
+
+ let s = ["aa", "bb", "cc", "dd"].iter().collect::<SmallStr<6>>();
+ assert_eq!("aabbccdd", s.as_str());
+ assert!(s.spilled());
+}
&self.items[idx].1
}
}
-
-#[cfg(tests)]
-mod tests;
///
/// A custom rustc driver can skip calling this to set up a custom ICE hook.
pub fn install_ice_hook() {
- // If the user has not explicitly overriden "RUST_BACKTRACE", then produce
+ // If the user has not explicitly overridden "RUST_BACKTRACE", then produce
// full backtraces. When a compiler ICE happens, we want to gather
// as much information as possible to present in the issue opened
// by the user. Compiler developers and other rustc users can
F: FnOnce(&dyn PrinterSupport) -> A,
{
match *ppmode {
- Normal | EveryBodyLoops | Expanded => {
+ Normal | Expanded => {
let annotation = NoAnn { sess, tcx };
f(&annotation)
}
rule also goes for any lifetime any struct made into a trait object may have.
In the implementation for `dyn Person`, the `'2` lifetime representing the
-internal data was ommitted, meaning that the compiler inferred the lifetime
+internal data was omitted, meaning that the compiler inferred the lifetime
`'static`. As a result, the implementation's `is_cool` is inferred by the
compiler to look like this:
// FIXME(#59346): Not sure how to map this level
Level::FailureNote => AnnotationType::Error,
Level::Allow => panic!("Should not call with Allow"),
+ Level::Expect(_) => panic!("Should not call with Expect"),
}
}
use crate::ToolMetadata;
use rustc_lint_defs::Applicability;
use rustc_serialize::json::Json;
+use rustc_span::edition::LATEST_STABLE_EDITION;
use rustc_span::{MultiSpan, Span, DUMMY_SP};
use std::fmt;
use std::hash::{Hash, Hasher};
| Level::Error { .. }
| Level::FailureNote => true,
- Level::Warning | Level::Note | Level::Help | Level::Allow => false,
+ Level::Warning | Level::Note | Level::Help | Level::Allow | Level::Expect(_) => false,
}
}
self
}
+ /// Help the user upgrade to the latest edition.
+ /// This is factored out to make sure it does the right thing with `Cargo.toml`.
+ pub fn help_use_latest_edition(&mut self) -> &mut Self {
+ if std::env::var_os("CARGO").is_some() {
+ self.help(&format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION));
+ } else {
+ self.help(&format!("pass `--edition {}` to `rustc`", LATEST_STABLE_EDITION));
+ }
+ self.note("for more on editions, read https://doc.rust-lang.org/edition-guide");
+ self
+ }
+
/// Disallow attaching suggestions this diagnostic.
/// Any suggestions attached e.g. with the `span_suggestion_*` methods
/// (before and after the call to `disable_suggestions`) will be ignored.
sp: impl Into<MultiSpan>,
msg: &str,
) -> &mut Self);
+ forward!(pub fn help_use_latest_edition(&mut self,) -> &mut Self);
forward!(pub fn set_is_lint(&mut self,) -> &mut Self);
forward!(pub fn disable_suggestions(&mut self,) -> &mut Self);
pub use emitter::ColorConfig;
+use rustc_lint_defs::LintExpectationId;
use Level::*;
use emitter::{is_case_difference, Emitter, EmitterWriter};
use registry::Registry;
-use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
use rustc_data_structures::stable_hasher::StableHasher;
use rustc_data_structures::sync::{self, Lock, Lrc};
use rustc_data_structures::AtomicRef;
deduplicated_warn_count: usize,
future_breakage_diagnostics: Vec<Diagnostic>,
+
+ /// Expected [`Diagnostic`]s store a [`LintExpectationId`] as part of
+ /// the lint level. [`LintExpectationId`]s created early during the compilation
+ /// (before `HirId`s have been defined) are not stable and can therefore not be
+ /// stored on disk. This buffer stores these diagnostics until the ID has been
+ /// replaced by a stable [`LintExpectationId`]. The [`Diagnostic`]s are the
+ /// submitted for storage and added to the list of fulfilled expectations.
+ unstable_expect_diagnostics: Vec<Diagnostic>,
+
+ /// expected diagnostic will have the level `Expect` which additionally
+ /// carries the [`LintExpectationId`] of the expectation that can be
+ /// marked as fulfilled. This is a collection of all [`LintExpectationId`]s
+ /// that have been marked as fulfilled this way.
+ ///
+ /// [RFC-2383]: https://rust-lang.github.io/rfcs/2383-lint-reasons.html
+ fulfilled_expectations: FxHashSet<LintExpectationId>,
}
/// A key denoting where from a diagnostic was stashed.
emitted_diagnostics: Default::default(),
stashed_diagnostics: Default::default(),
future_breakage_diagnostics: Vec::new(),
+ unstable_expect_diagnostics: Vec::new(),
+ fulfilled_expectations: Default::default(),
}),
}
}
DiagnosticBuilder::new(self, Level::Allow, msg)
}
+ /// Construct a builder at the `Expect` level with the `msg`.
+ pub fn struct_expect(&self, msg: &str, id: LintExpectationId) -> DiagnosticBuilder<'_, ()> {
+ DiagnosticBuilder::new(self, Level::Expect(id), msg)
+ }
+
/// Construct a builder at the `Error` level at the given `span` and with the `msg`.
pub fn struct_span_err(
&self,
pub fn emit_unused_externs(&self, lint_level: &str, unused_externs: &[&str]) {
self.inner.borrow_mut().emit_unused_externs(lint_level, unused_externs)
}
+
+ pub fn update_unstable_expectation_id(
+ &self,
+ unstable_to_stable: &FxHashMap<LintExpectationId, LintExpectationId>,
+ ) {
+ let diags = std::mem::take(&mut self.inner.borrow_mut().unstable_expect_diagnostics);
+ if diags.is_empty() {
+ return;
+ }
+
+ let mut inner = self.inner.borrow_mut();
+ for mut diag in diags.into_iter() {
+ let mut unstable_id = diag
+ .level
+ .get_expectation_id()
+ .expect("all diagnostics inside `unstable_expect_diagnostics` must have a `LintExpectationId`");
+
+ // The unstable to stable map only maps the unstable `AttrId` to a stable `HirId` with an attribute index.
+ // The lint index inside the attribute is manually transferred here.
+ let lint_index = unstable_id.get_lint_index();
+ unstable_id.set_lint_index(None);
+ let mut stable_id = *unstable_to_stable
+ .get(&unstable_id)
+ .expect("each unstable `LintExpectationId` must have a matching stable id");
+
+ stable_id.set_lint_index(lint_index);
+ diag.level = Level::Expect(stable_id);
+ inner.fulfilled_expectations.insert(stable_id);
+
+ (*TRACK_DIAGNOSTICS)(&diag);
+ }
+ }
+
+ /// This methods steals all [`LintExpectationId`]s that are stored inside
+ /// [`HandlerInner`] and indicate that the linked expectation has been fulfilled.
+ pub fn steal_fulfilled_expectation_ids(&self) -> FxHashSet<LintExpectationId> {
+ assert!(
+ self.inner.borrow().unstable_expect_diagnostics.is_empty(),
+ "`HandlerInner::unstable_expect_diagnostics` should be empty at this point",
+ );
+ std::mem::take(&mut self.inner.borrow_mut().fulfilled_expectations)
+ }
}
impl HandlerInner {
return;
}
+ // The `LintExpectationId` can be stable or unstable depending on when it was created.
+ // Diagnostics created before the definition of `HirId`s are unstable and can not yet
+ // be stored. Instead, they are buffered until the `LintExpectationId` is replaced by
+ // a stable one by the `LintLevelsBuilder`.
+ if let Level::Expect(LintExpectationId::Unstable { .. }) = diagnostic.level {
+ self.unstable_expect_diagnostics.push(diagnostic.clone());
+ return;
+ }
+
(*TRACK_DIAGNOSTICS)(diagnostic);
- if diagnostic.level == Allow {
+ if let Level::Expect(expectation_id) = diagnostic.level {
+ self.fulfilled_expectations.insert(expectation_id);
+ return;
+ } else if diagnostic.level == Allow {
return;
}
Help,
FailureNote,
Allow,
+ Expect(LintExpectationId),
}
impl fmt::Display for Level {
spec.set_fg(Some(Color::Cyan)).set_intense(true);
}
FailureNote => {}
- Allow => unreachable!(),
+ Allow | Expect(_) => unreachable!(),
}
spec
}
Help => "help",
FailureNote => "failure-note",
Allow => panic!("Shouldn't call on allowed error"),
+ Expect(_) => panic!("Shouldn't call on expected error"),
}
}
pub fn is_failure_note(&self) -> bool {
matches!(*self, FailureNote)
}
+
+ pub fn get_expectation_id(&self) -> Option<LintExpectationId> {
+ match self {
+ Level::Expect(id) => Some(*id),
+ _ => None,
+ }
+ }
}
// FIXME(eddyb) this doesn't belong here AFAICT, should be moved to callsite.
if let Some(Feature { since, .. }) = ACCEPTED_FEATURES.iter().find(|f| name == f.name) {
let since = Some(Symbol::intern(since));
features.declared_lang_features.push((name, mi.span(), since));
+ features.active_features.insert(name);
continue;
}
if let Some(f) = ACTIVE_FEATURES.iter().find(|f| name == f.name) {
f.set(&mut features, mi.span());
features.declared_lang_features.push((name, mi.span(), None));
+ features.active_features.insert(name);
continue;
}
features.declared_lib_features.push((name, mi.span()));
+ features.active_features.insert(name);
}
}
self.flat_map_node(node)
}
- fn flat_map_stmt(&mut self, mut node: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> {
+ fn flat_map_stmt(&mut self, node: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> {
// FIXME: invocations in semicolon-less expressions positions are expanded as expressions,
// changing that requires some compatibility measures.
if node.is_expr() {
self.cx.current_expansion.is_trailing_mac = false;
res
}
- _ => assign_id!(self, &mut node.id, || noop_flat_map_stmt(node, self)),
+ _ => noop_flat_map_stmt(node, self),
};
}
/// lifetime. By separating `'tt` from `'root`, we can show that.
#[derive(Clone)]
struct MatcherPos<'root, 'tt> {
- /// The token or sequence of tokens that make up the matcher
+ /// The token or sequence of tokens that make up the matcher. `elts` is short for "elements".
top_elts: TokenTreeOrTokenTreeSlice<'tt>,
/// The position of the "dot" in this matcher
/// in this matcher.
match_hi: usize,
- // The following fields are used if we are matching a repetition. If we aren't, they should be
- // `None`.
- /// The KleeneOp of this sequence if we are in a repetition.
- seq_op: Option<mbe::KleeneOp>,
-
- /// The separator if we are in a repetition.
- sep: Option<Token>,
-
- /// The "parent" matcher position if we are in a repetition. That is, the matcher position just
- /// before we enter the sequence.
- up: Option<MatcherPosHandle<'root, 'tt>>,
+ /// This field is only used if we are matching a repetition.
+ repetition: Option<MatcherPosRepetition<'root, 'tt>>,
/// Specifically used to "unzip" token trees. By "unzip", we mean to unwrap the delimiters from
/// a delimited token tree (e.g., something wrapped in `(` `)`) or to get the contents of a doc
stack: SmallVec<[MatcherTtFrame<'tt>; 1]>,
}
+// This type is used a lot. Make sure it doesn't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+rustc_data_structures::static_assert_size!(MatcherPos<'_, '_>, 192);
+
impl<'root, 'tt> MatcherPos<'root, 'tt> {
+ /// Generates the top-level matcher position in which the "dot" is before the first token of
+ /// the matcher `ms`.
+ fn new(ms: &'tt [TokenTree]) -> Self {
+ let match_idx_hi = count_names(ms);
+ MatcherPos {
+ // Start with the top level matcher given to us.
+ top_elts: TtSeq(ms),
+
+ // The "dot" is before the first token of the matcher.
+ idx: 0,
+
+ // Initialize `matches` to a bunch of empty `Vec`s -- one for each metavar in
+ // `top_elts`. `match_lo` for `top_elts` is 0 and `match_hi` is `match_idx_hi`.
+ // `match_cur` is 0 since we haven't actually matched anything yet.
+ matches: create_matches(match_idx_hi),
+ match_lo: 0,
+ match_cur: 0,
+ match_hi: match_idx_hi,
+
+ // Haven't descended into any delimiters, so this is empty.
+ stack: smallvec![],
+
+ // Haven't descended into any sequences, so this is `None`.
+ repetition: None,
+ }
+ }
+
/// Adds `m` as a named match for the `idx`-th metavar.
fn push_match(&mut self, idx: usize, m: NamedMatch) {
let matches = Lrc::make_mut(&mut self.matches[idx]);
}
}
+#[derive(Clone)]
+struct MatcherPosRepetition<'root, 'tt> {
+ /// The KleeneOp of this sequence.
+ seq_op: mbe::KleeneOp,
+
+ /// The separator.
+ sep: Option<Token>,
+
+ /// The "parent" matcher position. That is, the matcher position just before we enter the
+ /// sequence.
+ up: MatcherPosHandle<'root, 'tt>,
+}
+
// Lots of MatcherPos instances are created at runtime. Allocating them on the
// heap is slow. Furthermore, using SmallVec<MatcherPos> to allocate them all
// on the stack is also slow, because MatcherPos is quite a large type and
}
}
+enum EofItems<'root, 'tt> {
+ None,
+ One(MatcherPosHandle<'root, 'tt>),
+ Multiple,
+}
+
/// Represents the possible results of an attempted parse.
crate enum ParseResult<T> {
/// Parsed successfully.
.into_boxed_slice()
}
-/// Generates the top-level matcher position in which the "dot" is before the first token of the
-/// matcher `ms`.
-fn initial_matcher_pos<'root, 'tt>(ms: &'tt [TokenTree]) -> MatcherPos<'root, 'tt> {
- let match_idx_hi = count_names(ms);
- let matches = create_matches(match_idx_hi);
- MatcherPos {
- // Start with the top level matcher given to us
- top_elts: TtSeq(ms), // "elts" is an abbr. for "elements"
- // The "dot" is before the first token of the matcher
- idx: 0,
-
- // Initialize `matches` to a bunch of empty `Vec`s -- one for each metavar in `top_elts`.
- // `match_lo` for `top_elts` is 0 and `match_hi` is `matches.len()`. `match_cur` is 0 since
- // we haven't actually matched anything yet.
- matches,
- match_lo: 0,
- match_cur: 0,
- match_hi: match_idx_hi,
-
- // Haven't descended into any delimiters, so empty stack
- stack: smallvec![],
-
- // Haven't descended into any sequences, so both of these are `None`.
- seq_op: None,
- sep: None,
- up: None,
- }
-}
-
/// `NamedMatch` is a pattern-match result for a single `token::MATCH_NONTERMINAL`:
/// so it is associated with a single ident in a parse, and all
/// `MatchedNonterminal`s in the `NamedMatch` have the same non-terminal type
sess: &ParseSess,
cur_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>,
next_items: &mut Vec<MatcherPosHandle<'root, 'tt>>,
- eof_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>,
bb_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>,
+ eof_items: &mut EofItems<'root, 'tt>,
token: &Token,
-) -> ParseResult<()> {
+) -> Result<(), (rustc_span::Span, String)> {
// Pop items from `cur_items` until it is empty.
while let Some(mut item) = cur_items.pop() {
// When unzipped trees end, remove them. This corresponds to backtracking out of a
// We are repeating iff there is a parent. If the matcher is inside of a repetition,
// then we could be at the end of a sequence or at the beginning of the next
// repetition.
- if item.up.is_some() {
+ if let Some(repetition) = &item.repetition {
// At this point, regardless of whether there is a separator, we should add all
// matches from the complete repetition of the sequence to the shared, top-level
// `matches` list (actually, `up.matches`, which could itself not be the top-level,
// NOTE: removing the condition `idx == len` allows trailing separators.
if idx == len {
// Get the `up` matcher
- let mut new_pos = item.up.clone().unwrap();
+ let mut new_pos = repetition.up.clone();
// Add matches from this repetition to the `matches` of `up`
for idx in item.match_lo..item.match_hi {
}
// Check if we need a separator.
- if idx == len && item.sep.is_some() {
+ if idx == len && repetition.sep.is_some() {
// We have a separator, and it is the current token. We can advance past the
// separator token.
- if item.sep.as_ref().map_or(false, |sep| token_name_eq(token, sep)) {
+ if repetition.sep.as_ref().map_or(false, |sep| token_name_eq(token, sep)) {
item.idx += 1;
next_items.push(item);
}
- }
- // We don't need a separator. Move the "dot" back to the beginning of the matcher
- // and try to match again UNLESS we are only allowed to have _one_ repetition.
- else if item.seq_op != Some(mbe::KleeneOp::ZeroOrOne) {
+ } else if repetition.seq_op != mbe::KleeneOp::ZeroOrOne {
+ // We don't need a separator. Move the "dot" back to the beginning of the
+ // matcher and try to match again UNLESS we are only allowed to have _one_
+ // repetition.
item.match_cur = item.match_lo;
item.idx = 0;
cur_items.push(item);
}
+ } else {
+ // If we are not in a repetition, then being at the end of a matcher means that we
+ // have reached the potential end of the input.
+ *eof_items = match eof_items {
+ EofItems::None => EofItems::One(item),
+ EofItems::One(_) | EofItems::Multiple => EofItems::Multiple,
+ }
}
- // If we are not in a repetition, then being at the end of a matcher means that we have
- // reached the potential end of the input.
- else {
- eof_items.push(item);
- }
- }
- // We are in the middle of a matcher.
- else {
- // Look at what token in the matcher we are trying to match the current token (`token`)
- // against. Depending on that, we may generate new items.
+ } else {
+ // We are in the middle of a matcher. Look at what token in the matcher we are trying
+ // to match the current token (`token`) against. Depending on that, we may generate new
+ // items.
match item.top_elts.get_tt(idx) {
// Need to descend into a sequence
TokenTree::Sequence(sp, seq) => {
let matches = create_matches(item.matches.len());
cur_items.push(MatcherPosHandle::Box(Box::new(MatcherPos {
stack: smallvec![],
- sep: seq.separator.clone(),
- seq_op: Some(seq.kleene.op),
idx: 0,
matches,
match_lo: item.match_cur,
match_cur: item.match_cur,
match_hi: item.match_cur + seq.num_captures,
- up: Some(item),
+ repetition: Some(MatcherPosRepetition {
+ up: item,
+ sep: seq.separator.clone(),
+ seq_op: seq.kleene.op,
+ }),
top_elts: Tt(TokenTree::Sequence(sp, seq)),
})));
}
// We need to match a metavar (but the identifier is invalid)... this is an error
TokenTree::MetaVarDecl(span, _, None) => {
if sess.missing_fragment_specifiers.borrow_mut().remove(&span).is_some() {
- return Error(span, "missing fragment specifier".to_string());
+ return Err((span, "missing fragment specifier".to_string()));
}
}
}
// Yay a successful parse (so far)!
- Success(())
+ Ok(())
}
/// Use the given sequence of token trees (`ms`) as a matcher. Match the token
//
// This MatcherPos instance is allocated on the stack. All others -- and
// there are frequently *no* others! -- are allocated on the heap.
- let mut initial = initial_matcher_pos(ms);
+ let mut initial = MatcherPos::new(ms);
let mut cur_items = smallvec![MatcherPosHandle::Ref(&mut initial)];
let mut next_items = Vec::new();
loop {
+ assert!(next_items.is_empty());
+
// Matcher positions black-box parsed by parser.rs (`parser`)
let mut bb_items = SmallVec::new();
// Matcher positions that would be valid if the macro invocation was over now
- let mut eof_items = SmallVec::new();
- assert!(next_items.is_empty());
+ let mut eof_items = EofItems::None;
// Process `cur_items` until either we have finished the input or we need to get some
// parsing from the black-box parser done. The result is that `next_items` will contain a
parser.sess,
&mut cur_items,
&mut next_items,
- &mut eof_items,
&mut bb_items,
+ &mut eof_items,
&parser.token,
) {
- Success(_) => {}
- Failure(token, msg) => return Failure(token, msg),
- Error(sp, msg) => return Error(sp, msg),
- ErrorReported => return ErrorReported,
+ Ok(()) => {}
+ Err((sp, msg)) => return Error(sp, msg),
}
// inner parse loop handled all cur_items, so it's empty
assert!(cur_items.is_empty());
- // We need to do some post processing after the `inner_parser_loop`.
+ // We need to do some post processing after the `inner_parse_loop`.
//
// Error messages here could be improved with links to original rules.
// If we reached the EOF, check that there is EXACTLY ONE possible matcher. Otherwise,
// either the parse is ambiguous (which should never happen) or there is a syntax error.
if parser.token == token::Eof {
- if eof_items.len() == 1 {
- let matches =
- eof_items[0].matches.iter_mut().map(|dv| Lrc::make_mut(dv).pop().unwrap());
- return nameize(parser.sess, ms, matches);
- } else if eof_items.len() > 1 {
- return Error(
- parser.token.span,
- "ambiguity: multiple successful parses".to_string(),
- );
- } else {
- return Failure(
+ return match eof_items {
+ EofItems::One(mut eof_item) => {
+ let matches =
+ eof_item.matches.iter_mut().map(|dv| Lrc::make_mut(dv).pop().unwrap());
+ nameize(parser.sess, ms, matches)
+ }
+ EofItems::Multiple => {
+ Error(parser.token.span, "ambiguity: multiple successful parses".to_string())
+ }
+ EofItems::None => Failure(
Token::new(
token::Eof,
if parser.token.span.is_dummy() {
},
),
"missing tokens in macro arguments",
- );
- }
+ ),
+ };
}
- // Performance hack: eof_items may share matchers via Rc with other things that we want
- // to modify. Dropping eof_items now may drop these refcounts to 1, preventing an
- // unnecessary implicit clone later in Rc::make_mut.
+ // Performance hack: `eof_items` may share matchers via `Rc` with other things that we want
+ // to modify. Dropping `eof_items` now may drop these refcounts to 1, preventing an
+ // unnecessary implicit clone later in `Rc::make_mut`.
drop(eof_items);
// If there are no possible next positions AND we aren't waiting for the black-box parser,
if bb_items.is_empty() && next_items.is_empty() {
return Failure(parser.token.clone(), "no rules expected this token in macro call");
}
- // Another possibility is that we need to call out to parse some rust nonterminal
- // (black-box) parser. However, if there is not EXACTLY ONE of these, something is wrong.
- else if (!bb_items.is_empty() && !next_items.is_empty()) || bb_items.len() > 1 {
+
+ if (!bb_items.is_empty() && !next_items.is_empty()) || bb_items.len() > 1 {
+ // We need to call out to parse some rust nonterminal (black-box) parser. But something
+ // is wrong, because there is not EXACTLY ONE of these.
let nts = bb_items
.iter()
.map(|item| match item.top_elts.get_tt(item.idx) {
),
);
}
- // Dump all possible `next_items` into `cur_items` for the next iteration.
- else if !next_items.is_empty() {
- // Now process the next token
+
+ if !next_items.is_empty() {
+ // Dump all possible `next_items` into `cur_items` for the next iteration. Then process
+ // the next token.
cur_items.extend(next_items.drain(..));
parser.to_mut().bump();
- }
- // Finally, we have the case where we need to call the black-box parser to get some
- // nonterminal.
- else {
+ } else {
+ // Finally, we have the case where we need to call the black-box parser to get some
+ // nonterminal.
assert_eq!(bb_items.len(), 1);
let mut item = bb_items.pop().unwrap();
} else {
// Other variables are emitted into the output stream as groups with
// `Delimiter::None` to maintain parsing priorities.
- // `Interpolated` is currenty used for such groups in rustc parser.
+ // `Interpolated` is currently used for such groups in rustc parser.
marker.visit_span(&mut sp);
TokenTree::token(token::Interpolated(nt.clone()), sp)
};
/// the `quote` proc-macro. This will save the span of
/// "hello" into the metadata of `my_proc_macro`. As a result,
/// the body of `my_proc_macro` (after expansion) will end
- /// up containg a call that looks like this:
+ /// up containing a call that looks like this:
/// `proc_macro::Ident::new("hello", proc_macro::Span::recover_proc_macro_span(0))`
///
/// where `0` is the id returned by this function.
(accepted, conservative_impl_trait, "1.26.0", Some(34511), None),
/// Allows calling constructor functions in `const fn`.
(accepted, const_constructor, "1.40.0", Some(61456), None),
+ /// Allows using and casting function pointers in a `const fn`.
+ (accepted, const_fn_fn_ptr_basics, "1.61.0", Some(57563), None),
+ /// Allows trait bounds in `const fn`.
+ (accepted, const_fn_trait_bound, "1.61.0", Some(93706), None),
/// Allows calling `transmute` in const fn
(accepted, const_fn_transmute, "1.56.0", Some(53605), None),
/// Allows accessing fields of unions inside `const` functions.
(accepted, const_generics_defaults, "1.59.0", Some(44580), None),
/// Allows the use of `if` and `match` in constants.
(accepted, const_if_match, "1.46.0", Some(49146), None),
+ /// Allows argument and return position `impl Trait` in a `const fn`.
+ (accepted, const_impl_trait, "1.61.0", Some(77463), None),
/// Allows indexing into constant arrays.
(accepted, const_indexing, "1.26.0", Some(29947), None),
/// Allows let bindings, assignments and destructuring in `const` functions and constants.
use super::{to_nonzero, Feature, State};
+use rustc_data_structures::fx::FxHashSet;
use rustc_span::edition::Edition;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::Span;
pub declared_lang_features: Vec<(Symbol, Span, Option<Symbol>)>,
/// `#![feature]` attrs for non-language (library) features.
pub declared_lib_features: Vec<(Symbol, Span)>,
+ /// Features enabled for this crate.
+ pub active_features: FxHashSet<Symbol>,
$(
$(#[doc = $doc])*
pub $feature: bool
$(f(stringify!($feature), self.$feature);)+
}
+ /// Is the given feature active?
+ pub fn active(&self, feature: Symbol) -> bool {
+ self.active_features.contains(&feature)
+ }
+
/// Is the given feature enabled?
///
/// Panics if the symbol doesn't correspond to a declared feature.
(active, const_extern_fn, "1.40.0", Some(64926), None),
/// Allows basic arithmetic on floating point types in a `const fn`.
(active, const_fn_floating_point_arithmetic, "1.48.0", Some(57241), None),
- /// Allows using and casting function pointers in a `const fn`.
- (active, const_fn_fn_ptr_basics, "1.48.0", Some(57563), None),
- /// Allows trait bounds in `const fn`.
- (active, const_fn_trait_bound, "1.53.0", Some(93706), None),
/// Allows `for _ in _` loops in const contexts.
(active, const_for, "1.56.0", Some(87575), None),
- /// Allows argument and return position `impl Trait` in a `const fn`.
- (active, const_impl_trait, "1.48.0", Some(77463), None),
/// Allows using `&mut` in constant functions.
(active, const_mut_refs, "1.41.0", Some(57349), None),
/// Be more precise when looking for live drops in a const context.
ungated!(
allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk
),
+ gated!(
+ expect, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk,
+ lint_reasons, experimental!(expect)
+ ),
ungated!(
forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), DuplicatesOk
),
rustc_attr!(
rustc_layout_scalar_valid_range_start, Normal, template!(List: "value"), ErrorFollowing,
"the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable \
- niche optimizations in libcore and will never be stable",
+ niche optimizations in libcore and libstd and will never be stable",
),
rustc_attr!(
rustc_layout_scalar_valid_range_end, Normal, template!(List: "value"), ErrorFollowing,
"the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \
- niche optimizations in libcore and will never be stable",
+ niche optimizations in libcore and libstd and will never be stable",
),
rustc_attr!(
rustc_nonnull_optimization_guaranteed, Normal, template!(Word), WarnFollowing,
"the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable \
- niche optimizations in libcore and will never be stable",
+ niche optimizations in libcore and libstd and will never be stable",
),
// ==========================================================================
},
/// The file either didn't exist or was produced by an incompatible compiler version.
DataOutOfDate,
- /// An error occured.
+ /// An error occurred.
Error {
#[allow(missing_docs)]
message: String,
impl<T: Idx> BitRelations<HybridBitSet<T>> for ChunkedBitSet<T> {
fn union(&mut self, other: &HybridBitSet<T>) -> bool {
- // FIXME: this is slow if `other` is dense, and could easily be
- // improved, but it hasn't been a problem in practice so far.
+ // FIXME: This is slow if `other` is dense, but it hasn't been a problem
+ // in practice so far.
+ // If a a faster implementation of this operation is required, consider
+ // reopening https://github.com/rust-lang/rust/pull/94625
assert_eq!(self.domain_size, other.domain_size());
sequential_update(|elem| self.insert(elem), other.iter())
}
fn subtract(&mut self, other: &HybridBitSet<T>) -> bool {
- // FIXME: this is slow if `other` is dense, and could easily be
- // improved, but it hasn't been a problem in practice so far.
+ // FIXME: This is slow if `other` is dense, but it hasn't been a problem
+ // in practice so far.
+ // If a a faster implementation of this operation is required, consider
+ // reopening https://github.com/rust-lang/rust/pull/94625
assert_eq!(self.domain_size, other.domain_size());
sequential_update(|elem| self.remove(elem), other.iter())
}
/// performing that replacement, we'll turn all remaining infer type params to use their name from
/// their definition, and replace all the `[type error]`s back to being infer so they display in
/// the output as `_`. If we didn't go through `[type error]`, we would either show all type params
-/// by their name *or* `_`, neither of which is desireable: we want to show all types that we could
+/// by their name *or* `_`, neither of which is desirable: we want to show all types that we could
/// infer as `_` to reduce verbosity and avoid telling the user about unnecessary type annotations.
struct ResolvedTypeParamEraser<'tcx> {
tcx: TyCtxt<'tcx>,
bug!("Node not an impl.");
};
- // Next, let's figure out the set of trait objects with implict static bounds
+ // Next, let's figure out the set of trait objects with implicit static bounds
let ty = self.tcx().type_of(*impl_def_id);
let mut v = super::static_impl_trait::TraitObjectVisitor(FxHashSet::default());
v.visit_ty(ty);
+//! Greatest lower bound. See [`lattice`].
+
use super::combine::CombineFields;
use super::lattice::{self, LatticeDir};
use super::InferCtxt;
-//! # Lattice Variables
+//! # Lattice variables
//!
-//! This file contains generic code for operating on inference variables
-//! that are characterized by an upper- and lower-bound. The logic and
-//! reasoning is explained in detail in the large comment in `infer.rs`.
+//! Generic code for operating on [lattices] of inference variables
+//! that are characterized by an upper- and lower-bound.
//!
-//! The code in here is defined quite generically so that it can be
+//! The code is defined quite generically so that it can be
//! applied both to type variables, which represent types being inferred,
//! and fn variables, which represent function types being inferred.
-//! It may eventually be applied to their types as well, who knows.
+//! (It may eventually be applied to their types as well.)
//! In some cases, the functions are also generic with respect to the
//! operation on the lattice (GLB vs LUB).
//!
-//! Although all the functions are generic, we generally write the
-//! comments in a way that is specific to type variables and the LUB
-//! operation. It's just easier that way.
+//! ## Note
//!
-//! In general all of the functions are defined parametrically
-//! over a `LatticeValue`, which is a value defined with respect to
-//! a lattice.
+//! Although all the functions are generic, for simplicity, comments in the source code
+//! generally refer to type variables and the LUB operation.
+//!
+//! [lattices]: https://en.wikipedia.org/wiki/Lattice_(order)
use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use super::InferCtxt;
use rustc_middle::ty::TyVar;
use rustc_middle::ty::{self, Ty};
+/// Trait for returning data about a lattice, and for abstracting
+/// over the "direction" of the lattice operation (LUB/GLB).
+///
+/// GLB moves "down" the lattice (to smaller values); LUB moves
+/// "up" the lattice (to bigger values).
pub trait LatticeDir<'f, 'tcx>: TypeRelation<'tcx> {
fn infcx(&self) -> &'f InferCtxt<'f, 'tcx>;
fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>;
}
+/// Relates two types using a given lattice.
pub fn super_lattice_tys<'a, 'tcx: 'a, L>(
this: &mut L,
a: Ty<'tcx>,
+//! Least upper bound. See [`lattice`].
+
use super::combine::CombineFields;
use super::lattice::{self, LatticeDir};
use super::InferCtxt;
"`values()` first argument must be a simple identifer"
);
}
+ } else if args.is_empty() {
+ cfg.well_known_values = true;
+ continue 'specs;
}
}
}
use crate::util;
use ast::CRATE_NODE_ID;
-use rustc_ast::mut_visit::MutVisitor;
use rustc_ast::{self as ast, visit};
use rustc_borrowck as mir_borrowck;
use rustc_codegen_ssa::back::link::emit_metadata;
use rustc_query_impl::{OnDiskCache, Queries as TcxQueries};
use rustc_resolve::{Resolver, ResolverArenas};
use rustc_serialize::json;
-use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType, PpMode, PpSourceMode};
+use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType};
use rustc_session::cstore::{MetadataLoader, MetadataLoaderDyn};
use rustc_session::lint;
use rustc_session::output::{filename_for_input, filename_for_metadata};
rustc_builtin_macros::test_harness::inject(sess, resolver, &mut krate)
});
- if let Some(PpMode::Source(PpSourceMode::EveryBodyLoops)) = sess.opts.pretty {
- tracing::debug!("replacing bodies with loop {{}}");
- util::ReplaceBodyWithLoop::new(resolver).visit_crate(&mut krate);
- }
-
let has_proc_macro_decls = sess.time("AST_validation", || {
rustc_ast_passes::ast_validation::check_crate(sess, &krate, resolver.lint_buffer())
});
});
// Add all buffered lints from the `ParseSess` to the `Session`.
- // The ReplaceBodyWithLoop pass may have deleted some AST nodes, potentially
- // causing a delay_span_bug later if a buffered lint refers to such a deleted
- // AST node (issue #87308). Since everybody_loops is for pretty-printing only,
- // anyway, we simply skip all buffered lints here.
- if !matches!(sess.opts.pretty, Some(PpMode::Source(PpSourceMode::EveryBodyLoops))) {
- sess.parse_sess.buffered_lints.with_lock(|buffered_lints| {
- info!("{} parse sess buffered_lints", buffered_lints.len());
- for early_lint in buffered_lints.drain(..) {
- resolver.lint_buffer().add_early_lint(early_lint);
- }
- });
- }
+ sess.parse_sess.buffered_lints.with_lock(|buffered_lints| {
+ info!("{} parse sess buffered_lints", buffered_lints.len());
+ for early_lint in buffered_lints.drain(..) {
+ resolver.lint_buffer().add_early_lint(early_lint);
+ }
+ });
// Gate identifiers containing invalid Unicode codepoints that were recovered during lexing.
sess.parse_sess.bad_unicode_identifiers.with_lock(|identifiers| {
tcx.ensure().check_mod_const_bodies(module);
});
},
+ {
+ sess.time("unused_lib_feature_checking", || {
+ rustc_passes::stability::check_unused_or_stable_features(tcx)
+ });
+ },
{
// We force these querie to run,
// since they might not otherwise get called.
// This marks the corresponding crate-level attributes
// as used, and ensures that their values are valid.
tcx.ensure().limits(());
+ tcx.ensure().stability_index(());
}
);
});
tcx.hir()
.par_for_each_module(|module| tcx.ensure().check_mod_deathness(module));
},
- {
- sess.time("unused_lib_feature_checking", || {
- rustc_passes::stability::check_unused_or_stable_features(tcx)
- });
- },
{
sess.time("lint_checking", || {
rustc_lint::check_crate(tcx, || {
use libloading::Library;
-use rustc_ast::mut_visit::{visit_clobber, MutVisitor, *};
-use rustc_ast::ptr::P;
-use rustc_ast::{self as ast, AttrVec, BlockCheckMode, Term};
+use rustc_ast as ast;
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
#[cfg(parallel_compiler)]
use rustc_parse::validate_attr;
#[cfg(parallel_compiler)]
use rustc_query_impl::QueryCtxt;
-use rustc_resolve::{self, Resolver};
use rustc_session as session;
use rustc_session::config::CheckCfg;
use rustc_session::config::{self, CrateType};
use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::source_map::FileLoader;
use rustc_span::symbol::{sym, Symbol};
-use smallvec::SmallVec;
use std::env;
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
use std::lazy::SyncOnceCell;
use std::mem;
-use std::ops::DerefMut;
#[cfg(not(parallel_compiler))]
use std::panic;
use std::path::{Path, PathBuf};
std::fs::rename(src, dst)
}
-/// Replaces function bodies with `loop {}` (an infinite loop). This gets rid of
-/// all semantic errors in the body while still satisfying the return type,
-/// except in certain cases, see below for more.
-///
-/// This pass is known as `everybody_loops`. Very punny.
-///
-/// As of March 2021, `everybody_loops` is only used for the
-/// `-Z unpretty=everybody_loops` debugging option.
-///
-/// FIXME: Currently the `everybody_loops` transformation is not applied to:
-/// * `const fn`; support could be added, but hasn't. Originally `const fn`
-/// was skipped due to issue #43636 that `loop` was not supported for
-/// const evaluation.
-/// * `impl Trait`, due to issue #43869 that functions returning impl Trait cannot be diverging.
-/// Solving this may require `!` to implement every trait, which relies on the an even more
-/// ambitious form of the closed RFC #1637. See also [#34511].
-///
-/// [#34511]: https://github.com/rust-lang/rust/issues/34511#issuecomment-322340401
-pub struct ReplaceBodyWithLoop<'a, 'b> {
- within_static_or_const: bool,
- nested_blocks: Option<Vec<ast::Block>>,
- resolver: &'a mut Resolver<'b>,
-}
-
-impl<'a, 'b> ReplaceBodyWithLoop<'a, 'b> {
- pub fn new(resolver: &'a mut Resolver<'b>) -> ReplaceBodyWithLoop<'a, 'b> {
- ReplaceBodyWithLoop { within_static_or_const: false, nested_blocks: None, resolver }
- }
-
- fn run<R, F: FnOnce(&mut Self) -> R>(&mut self, is_const: bool, action: F) -> R {
- let old_const = mem::replace(&mut self.within_static_or_const, is_const);
- let old_blocks = self.nested_blocks.take();
- let ret = action(self);
- self.within_static_or_const = old_const;
- self.nested_blocks = old_blocks;
- ret
- }
-
- fn should_ignore_fn(ret_ty: &ast::FnRetTy) -> bool {
- let ast::FnRetTy::Ty(ref ty) = ret_ty else {
- return false;
- };
- fn involves_impl_trait(ty: &ast::Ty) -> bool {
- match ty.kind {
- ast::TyKind::ImplTrait(..) => true,
- ast::TyKind::Slice(ref subty)
- | ast::TyKind::Array(ref subty, _)
- | ast::TyKind::Ptr(ast::MutTy { ty: ref subty, .. })
- | ast::TyKind::Rptr(_, ast::MutTy { ty: ref subty, .. })
- | ast::TyKind::Paren(ref subty) => involves_impl_trait(subty),
- ast::TyKind::Tup(ref tys) => any_involves_impl_trait(tys.iter()),
- ast::TyKind::Path(_, ref path) => {
- path.segments.iter().any(|seg| match seg.args.as_deref() {
- None => false,
- Some(&ast::GenericArgs::AngleBracketed(ref data)) => {
- data.args.iter().any(|arg| match arg {
- ast::AngleBracketedArg::Arg(arg) => match arg {
- ast::GenericArg::Type(ty) => involves_impl_trait(ty),
- ast::GenericArg::Lifetime(_) | ast::GenericArg::Const(_) => {
- false
- }
- },
- ast::AngleBracketedArg::Constraint(c) => match c.kind {
- ast::AssocConstraintKind::Bound { .. } => true,
- ast::AssocConstraintKind::Equality { ref term } => {
- match term {
- Term::Ty(ty) => involves_impl_trait(ty),
- // FIXME(...): This should check if the constant
- // involves a trait impl, but for now ignore.
- Term::Const(_) => false,
- }
- }
- },
- })
- }
- Some(&ast::GenericArgs::Parenthesized(ref data)) => {
- any_involves_impl_trait(data.inputs.iter())
- || ReplaceBodyWithLoop::should_ignore_fn(&data.output)
- }
- })
- }
- _ => false,
- }
- }
-
- fn any_involves_impl_trait<'a, I: Iterator<Item = &'a P<ast::Ty>>>(mut it: I) -> bool {
- it.any(|subty| involves_impl_trait(subty))
- }
-
- involves_impl_trait(ty)
- }
-
- fn is_sig_const(sig: &ast::FnSig) -> bool {
- matches!(sig.header.constness, ast::Const::Yes(_))
- || ReplaceBodyWithLoop::should_ignore_fn(&sig.decl.output)
- }
-}
-
-impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> {
- 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::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::Fn { ref sig, .. }) => Self::is_sig_const(sig),
- _ => false,
- };
- self.run(is_const, |s| noop_flat_map_assoc_item(i, s))
- }
-
- fn flat_map_impl_item(&mut self, i: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
- self.flat_map_trait_item(i)
- }
-
- fn visit_anon_const(&mut self, c: &mut ast::AnonConst) {
- self.run(true, |s| noop_visit_anon_const(c, s))
- }
-
- fn visit_block(&mut self, b: &mut P<ast::Block>) {
- fn stmt_to_block(
- rules: ast::BlockCheckMode,
- s: Option<ast::Stmt>,
- resolver: &mut Resolver<'_>,
- ) -> ast::Block {
- ast::Block {
- stmts: s.into_iter().collect(),
- rules,
- id: resolver.next_node_id(),
- span: rustc_span::DUMMY_SP,
- tokens: None,
- could_be_bare_literal: false,
- }
- }
-
- fn block_to_stmt(b: ast::Block, resolver: &mut Resolver<'_>) -> ast::Stmt {
- let expr = P(ast::Expr {
- id: resolver.next_node_id(),
- kind: ast::ExprKind::Block(P(b), None),
- span: rustc_span::DUMMY_SP,
- attrs: AttrVec::new(),
- tokens: None,
- });
-
- ast::Stmt {
- id: resolver.next_node_id(),
- kind: ast::StmtKind::Expr(expr),
- span: rustc_span::DUMMY_SP,
- }
- }
-
- let empty_block = stmt_to_block(BlockCheckMode::Default, None, self.resolver);
- let loop_expr = P(ast::Expr {
- kind: ast::ExprKind::Loop(P(empty_block), None),
- id: self.resolver.next_node_id(),
- span: rustc_span::DUMMY_SP,
- attrs: AttrVec::new(),
- tokens: None,
- });
-
- let loop_stmt = ast::Stmt {
- id: self.resolver.next_node_id(),
- span: rustc_span::DUMMY_SP,
- kind: ast::StmtKind::Expr(loop_expr),
- };
-
- if self.within_static_or_const {
- noop_visit_block(b, self)
- } else {
- visit_clobber(b.deref_mut(), |b| {
- let mut stmts = vec![];
- for s in b.stmts {
- let old_blocks = self.nested_blocks.replace(vec![]);
-
- stmts.extend(self.flat_map_stmt(s).into_iter().filter(|s| s.is_item()));
-
- // we put a Some in there earlier with that replace(), so this is valid
- let new_blocks = self.nested_blocks.take().unwrap();
- self.nested_blocks = old_blocks;
- stmts.extend(new_blocks.into_iter().map(|b| block_to_stmt(b, self.resolver)));
- }
-
- let mut new_block = ast::Block { stmts, ..b };
-
- if let Some(old_blocks) = self.nested_blocks.as_mut() {
- //push our fresh block onto the cache and yield an empty block with `loop {}`
- if !new_block.stmts.is_empty() {
- old_blocks.push(new_block);
- }
-
- stmt_to_block(b.rules, Some(loop_stmt), &mut self.resolver)
- } else {
- //push `loop {}` onto the end of our fresh block and yield that
- new_block.stmts.push(loop_stmt);
-
- new_block
- }
- })
- }
- }
-}
-
/// Returns a version string such as "1.46.0 (04488afe3 2020-08-24)"
pub fn version_str() -> Option<&'static str> {
option_env!("CFG_VERSION")
let compare_layouts = |a, b| -> Result<bool, LayoutError<'tcx>> {
debug!("compare_layouts({:?}, {:?})", a, b);
- let a_layout = &cx.layout_of(a)?.layout.abi;
- let b_layout = &cx.layout_of(b)?.layout.abi;
+ let a_layout = &cx.layout_of(a)?.layout.abi();
+ let b_layout = &cx.layout_of(b)?.layout.abi();
debug!(
"comparing layouts: {:?} == {:?} = {}",
a_layout,
depr: Option<LintAlias>,
}
+#[derive(Debug)]
pub enum CheckLintNameResult<'a> {
Ok(&'a [LintId]),
/// Lint doesn't exist. Potentially contains a suggestion for a correct lint name.
Level::ForceWarn => "--force-warn",
Level::Deny => "-D",
Level::Forbid => "-F",
+ Level::Expect(_) => {
+ unreachable!("lints with the level of `expect` should not run this code");
+ }
},
lint_name
);
db.help(&help);
db.note("see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information");
},
- BuiltinLintDiagnostics::UnexpectedCfg(span, name, value) => {
- let possibilities: Vec<Symbol> = if value.is_some() {
- let Some(values) = &sess.parse_sess.check_config.values_valid.get(&name) else {
- bug!("it shouldn't be possible to have a diagnostic on a value whose name is not in values");
- };
- values.iter().map(|&s| s).collect()
- } else {
- let Some(names_valid) = &sess.parse_sess.check_config.names_valid else {
- bug!("it shouldn't be possible to have a diagnostic on a name if name checking is not enabled");
- };
- names_valid.iter().map(|s| *s).collect()
+ BuiltinLintDiagnostics::UnexpectedCfg((name, name_span), None) => {
+ let Some(names_valid) = &sess.parse_sess.check_config.names_valid else {
+ bug!("it shouldn't be possible to have a diagnostic on a name if name checking is not enabled");
};
+ let possibilities: Vec<Symbol> = names_valid.iter().map(|s| *s).collect();
+
+ // Suggest the most probable if we found one
+ if let Some(best_match) = find_best_match_for_name(&possibilities, name, None) {
+ db.span_suggestion(name_span, "did you mean", format!("{best_match}"), Applicability::MaybeIncorrect);
+ }
+ },
+ BuiltinLintDiagnostics::UnexpectedCfg((name, name_span), Some((value, value_span))) => {
+ let Some(values) = &sess.parse_sess.check_config.values_valid.get(&name) else {
+ bug!("it shouldn't be possible to have a diagnostic on a value whose name is not in values");
+ };
+ let possibilities: Vec<Symbol> = values.iter().map(|&s| s).collect();
// Show the full list if all possible values for a given name, but don't do it
// for names as the possibilities could be very long
- if value.is_some() {
- if !possibilities.is_empty() {
+ if !possibilities.is_empty() {
+ {
let mut possibilities = possibilities.iter().map(Symbol::as_str).collect::<Vec<_>>();
possibilities.sort();
let possibilities = possibilities.join(", ");
db.note(&format!("expected values for `{name}` are: {possibilities}"));
- } else {
- db.note(&format!("no expected value for `{name}`"));
}
- }
- // Suggest the most probable if we found one
- if let Some(best_match) = find_best_match_for_name(&possibilities, value.unwrap_or(name), None) {
- let punctuation = if value.is_some() { "\"" } else { "" };
- db.span_suggestion(span, "did you mean", format!("{punctuation}{best_match}{punctuation}"), Applicability::MaybeIncorrect);
+ // Suggest the most probable if we found one
+ if let Some(best_match) = find_best_match_for_name(&possibilities, value, None) {
+ db.span_suggestion(value_span, "did you mean", format!("\"{best_match}\""), Applicability::MaybeIncorrect);
+ }
+ } else {
+ db.note(&format!("no expected value for `{name}`"));
+ if name != sym::feature {
+ db.span_suggestion(name_span.shrink_to_hi().to(value_span), "remove the value", String::new(), Applicability::MaybeIncorrect);
+ }
}
},
+ BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(new_span, suggestion) => {
+ db.multipart_suggestion(
+ "move it to the end of the type declaration",
+ vec![(db.span.primary_span().unwrap(), "".to_string()), (new_span, suggestion)],
+ Applicability::MachineApplicable,
+ );
+ db.note(
+ "see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information",
+ );
+ },
}
// Rewrap `db`, and pass control to the user.
decorate(LintDiagnosticBuilder::new(db));
F: FnOnce(&mut Self),
{
let is_crate_node = id == ast::CRATE_NODE_ID;
- let push = self.context.builder.push(attrs, is_crate_node);
+ let push = self.context.builder.push(attrs, is_crate_node, None);
+
self.check_id(id);
self.enter_attrs(attrs);
f(self);
--- /dev/null
+use crate::builtin;
+use rustc_hir::HirId;
+use rustc_middle::{lint::LintExpectation, ty::TyCtxt};
+use rustc_session::lint::LintExpectationId;
+use rustc_span::symbol::sym;
+
+pub fn check_expectations(tcx: TyCtxt<'_>) {
+ if !tcx.sess.features_untracked().enabled(sym::lint_reasons) {
+ return;
+ }
+
+ let fulfilled_expectations = tcx.sess.diagnostic().steal_fulfilled_expectation_ids();
+ let lint_expectations = &tcx.lint_levels(()).lint_expectations;
+
+ for (id, expectation) in lint_expectations {
+ if !fulfilled_expectations.contains(id) {
+ // This check will always be true, since `lint_expectations` only
+ // holds stable ids
+ if let LintExpectationId::Stable { hir_id, .. } = id {
+ emit_unfulfilled_expectation_lint(tcx, *hir_id, expectation);
+ } else {
+ unreachable!("at this stage all `LintExpectationId`s are stable");
+ }
+ }
+ }
+}
+
+fn emit_unfulfilled_expectation_lint(
+ tcx: TyCtxt<'_>,
+ hir_id: HirId,
+ expectation: &LintExpectation,
+) {
+ // FIXME: The current implementation doesn't cover cases where the
+ // `unfulfilled_lint_expectations` is actually expected by another lint
+ // expectation. This can be added here by checking the lint level and
+ // retrieving the `LintExpectationId` if it was expected.
+ tcx.struct_span_lint_hir(
+ builtin::UNFULFILLED_LINT_EXPECTATIONS,
+ hir_id,
+ expectation.emission_span,
+ |diag| {
+ let mut diag = diag.build("this lint expectation is unfulfilled");
+ if let Some(rationale) = expectation.reason {
+ diag.note(&rationale.as_str());
+ }
+ diag.emit();
+ },
+ );
+}
});
},
);
+
+ // This check has to be run after all lints are done processing for this crate
+ tcx.sess.time("check_lint_expectations", || crate::expect::check_expectations(tcx));
}
use rustc_hir as hir;
use rustc_hir::{intravisit, HirId};
use rustc_middle::hir::nested_filter;
-use rustc_middle::lint::LevelAndSource;
-use rustc_middle::lint::LintDiagnosticBuilder;
use rustc_middle::lint::{
- struct_lint_level, LintLevelMap, LintLevelSets, LintLevelSource, LintSet, LintStackIndex,
- COMMAND_LINE,
+ struct_lint_level, LevelAndSource, LintDiagnosticBuilder, LintExpectation, LintLevelMap,
+ LintLevelSets, LintLevelSource, LintSet, LintStackIndex, COMMAND_LINE,
};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{RegisteredTools, TyCtxt};
use rustc_session::lint::{
builtin::{self, FORBIDDEN_LINT_GROUPS},
- Level, Lint, LintId,
+ Level, Lint, LintExpectationId, LintId,
};
use rustc_session::parse::feature_err;
use rustc_session::Session;
builder.levels.id_to_set.reserve(krate.owners.len() + 1);
- let push = builder.levels.push(tcx.hir().attrs(hir::CRATE_HIR_ID), true);
+ let push =
+ builder.levels.push(tcx.hir().attrs(hir::CRATE_HIR_ID), true, Some(hir::CRATE_HIR_ID));
+
builder.levels.register_id(hir::CRATE_HIR_ID);
tcx.hir().walk_toplevel_module(&mut builder);
builder.levels.pop(push);
+ builder.levels.update_unstable_expectation_ids();
builder.levels.build_map()
}
pub struct LintLevelsBuilder<'s> {
sess: &'s Session,
+ lint_expectations: Vec<(LintExpectationId, LintExpectation)>,
+ /// Each expectation has a stable and an unstable identifier. This map
+ /// is used to map from unstable to stable [`LintExpectationId`]s.
+ expectation_id_map: FxHashMap<LintExpectationId, LintExpectationId>,
sets: LintLevelSets,
id_to_set: FxHashMap<HirId, LintStackIndex>,
cur: LintStackIndex,
) -> Self {
let mut builder = LintLevelsBuilder {
sess,
+ lint_expectations: Default::default(),
+ expectation_id_map: Default::default(),
sets: LintLevelSets::new(),
cur: COMMAND_LINE,
id_to_set: Default::default(),
/// `#[allow]`
///
/// Don't forget to call `pop`!
- pub(crate) fn push(&mut self, attrs: &[ast::Attribute], is_crate_node: bool) -> BuilderPush {
+ pub(crate) fn push(
+ &mut self,
+ attrs: &[ast::Attribute],
+ is_crate_node: bool,
+ source_hir_id: Option<HirId>,
+ ) -> BuilderPush {
let mut specs = FxHashMap::default();
let sess = self.sess;
let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input");
- for attr in attrs {
- let Some(level) = Level::from_symbol(attr.name_or_empty()) else {
- continue
+ for (attr_index, attr) in attrs.iter().enumerate() {
+ let level = match Level::from_attr(attr) {
+ None => continue,
+ Some(Level::Expect(unstable_id)) if let Some(hir_id) = source_hir_id => {
+ let stable_id = self.create_stable_id(unstable_id, hir_id, attr_index);
+
+ Level::Expect(stable_id)
+ }
+ Some(lvl) => lvl,
};
let Some(mut metas) = attr.meta_item_list() else {
};
if metas.is_empty() {
- // FIXME (#55112): issue unused-attributes lint for `#[level()]`
+ // This emits the unused_attributes lint for `#[level()]`
continue;
}
ast::MetaItemKind::Word => {} // actual lint names handled later
ast::MetaItemKind::NameValue(ref name_value) => {
if item.path == sym::reason {
- // FIXME (#55112): issue unused-attributes lint if we thereby
- // don't have any lint names (`#[level(reason = "foo")]`)
if let ast::LitKind::Str(rationale, _) = name_value.kind {
if !self.sess.features_untracked().lint_reasons {
feature_err(
}
}
- for li in metas {
+ for (lint_index, li) in metas.iter_mut().enumerate() {
+ let level = match level {
+ Level::Expect(mut id) => {
+ id.set_lint_index(Some(lint_index as u16));
+ Level::Expect(id)
+ }
+ level => level,
+ };
+
let sp = li.span();
- let mut meta_item = match li {
+ let meta_item = match li {
ast::NestedMetaItem::MetaItem(meta_item) if meta_item.is_word() => meta_item,
_ => {
let mut err = bad_attr(sp);
self.check_gated_lint(id, attr.span);
self.insert_spec(&mut specs, id, (level, src));
}
+ if let Level::Expect(expect_id) = level {
+ self.lint_expectations
+ .push((expect_id, LintExpectation::new(reason, sp)));
+ }
}
CheckLintNameResult::Tool(result) => {
for id in ids {
self.insert_spec(&mut specs, *id, (level, src));
}
+ if let Level::Expect(expect_id) = level {
+ self.lint_expectations
+ .push((expect_id, LintExpectation::new(reason, sp)));
+ }
}
Err((Some(ids), ref new_lint_name)) => {
let lint = builtin::RENAMED_AND_REMOVED_LINTS;
for id in ids {
self.insert_spec(&mut specs, *id, (level, src));
}
+ if let Level::Expect(expect_id) = level {
+ self.lint_expectations
+ .push((expect_id, LintExpectation::new(reason, sp)));
+ }
}
Err((None, _)) => {
// If Tool(Err(None, _)) is returned, then either the lint does not
self.check_gated_lint(id, attr.span);
self.insert_spec(&mut specs, id, (level, src));
}
+ if let Level::Expect(expect_id) = level {
+ self.lint_expectations
+ .push((expect_id, LintExpectation::new(reason, sp)));
+ }
} else {
panic!("renamed lint does not exist: {}", new_name);
}
BuilderPush { prev, changed: prev != self.cur }
}
+ fn create_stable_id(
+ &mut self,
+ unstable_id: LintExpectationId,
+ hir_id: HirId,
+ attr_index: usize,
+ ) -> LintExpectationId {
+ let stable_id =
+ LintExpectationId::Stable { hir_id, attr_index: attr_index as u16, lint_index: None };
+
+ self.expectation_id_map.insert(unstable_id, stable_id);
+
+ stable_id
+ }
+
/// Checks if the lint is gated on a feature that is not enabled.
fn check_gated_lint(&self, lint_id: LintId, span: Span) {
if let Some(feature) = lint_id.lint.feature_gate {
self.id_to_set.insert(id, self.cur);
}
+ fn update_unstable_expectation_ids(&self) {
+ self.sess.diagnostic().update_unstable_expectation_id(&self.expectation_id_map);
+ }
+
pub fn build_map(self) -> LintLevelMap {
- LintLevelMap { sets: self.sets, id_to_set: self.id_to_set }
+ LintLevelMap {
+ sets: self.sets,
+ id_to_set: self.id_to_set,
+ lint_expectations: self.lint_expectations,
+ }
}
}
{
let is_crate_hir = id == hir::CRATE_HIR_ID;
let attrs = self.tcx.hir().attrs(id);
- let push = self.levels.push(attrs, is_crate_hir);
+ let push = self.levels.push(attrs, is_crate_hir, Some(id));
+
if push.changed {
self.levels.register_id(id);
}
mod context;
mod early;
mod enum_intrinsics_non_enums;
+mod expect;
pub mod hidden_unicode_codepoints;
mod internal;
mod late;
let field_ty_abi = &cx.layout_of(field_ty).unwrap().abi;
if let Abi::Scalar(field_ty_scalar) = field_ty_abi {
match (field_ty_scalar.valid_range.start, field_ty_scalar.valid_range.end) {
- (0, _) => unreachable!("Non-null optimisation extended to a non-zero value."),
+ (0, x) if x == field_ty_scalar.value.size(&cx.tcx).unsigned_int_max() - 1 => {
+ return Some(get_nullable_type(cx, field_ty).unwrap());
+ }
(1, _) => {
return Some(get_nullable_type(cx, field_ty).unwrap());
}
let (largest, slargest, largest_index) = iter::zip(enum_definition.variants, variants)
.map(|(variant, variant_layout)| {
// Subtract the size of the enum tag.
- let bytes = variant_layout.size.bytes().saturating_sub(tag_size);
+ let bytes = variant_layout.size().bytes().saturating_sub(tag_size);
debug!("- variant `{}` is {} bytes large", variant.ident, bytes);
bytes
rustc_serialize = { path = "../rustc_serialize" }
rustc_macros = { path = "../rustc_macros" }
rustc_target = { path = "../rustc_target" }
+rustc_hir = { path = "../rustc_hir" }
"unrecognized lint attribute"
}
+declare_lint! {
+ /// The `unfulfilled_lint_expectations` lint detects lint trigger expectations
+ /// that have not been fulfilled.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// #![feature(lint_reasons)]
+ ///
+ /// #[expect(unused_variables)]
+ /// let x = 10;
+ /// println!("{}", x);
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// It was expected that the marked code would emit a lint. This expectation
+ /// has not been fulfilled.
+ ///
+ /// The `expect` attribute can be removed if this is intended behavior otherwise
+ /// it should be investigated why the expected lint is no longer issued.
+ ///
+ /// Part of RFC 2383. The progress is being tracked in [#54503]
+ ///
+ /// [#54503]: https://github.com/rust-lang/rust/issues/54503
+ pub UNFULFILLED_LINT_EXPECTATIONS,
+ Warn,
+ "unfulfilled lint expectation",
+ @feature_gate = rustc_span::sym::lint_reasons;
+}
+
declare_lint! {
/// The `unused_variables` lint detects variables which are not used in
/// any way.
UNUSED_CRATE_DEPENDENCIES,
UNUSED_QUALIFICATIONS,
UNKNOWN_LINTS,
+ UNFULFILLED_LINT_EXPECTATIONS,
UNUSED_VARIABLES,
UNUSED_ASSIGNMENTS,
DEAD_CODE,
DUPLICATE_MACRO_ATTRIBUTES,
SUSPICIOUS_AUTO_TRAIT_IMPLS,
UNEXPECTED_CFGS,
+ DEPRECATED_WHERE_CLAUSE_LOCATION,
]
}
reference: "issue #93367 <https://github.com/rust-lang/rust/issues/93367>",
};
}
+
+declare_lint! {
+ /// The `deprecated_where_clause_location` lint detects when a where clause in front of the equals
+ /// in an associated type.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// #![feature(generic_associated_types)]
+ ///
+ /// trait Trait {
+ /// type Assoc<'a> where Self: 'a;
+ /// }
+ ///
+ /// impl Trait for () {
+ /// type Assoc<'a> where Self: 'a = ();
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// The preferred location for where clauses on associated types in impls
+ /// is after the type. However, for most of generic associated types development,
+ /// it was only accepted before the equals. To provide a transition period and
+ /// further evaluate this change, both are currently accepted. At some point in
+ /// the future, this may be disallowed at an edition boundary; but, that is
+ /// undecided currently.
+ pub DEPRECATED_WHERE_CLAUSE_LOCATION,
+ Warn,
+ "deprecated where clause location"
+}
+#![feature(min_specialization)]
+
#[macro_use]
extern crate rustc_macros;
pub use self::Level::*;
use rustc_ast::node_id::{NodeId, NodeMap};
+use rustc_ast::{AttrId, Attribute};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
+use rustc_hir::HirId;
use rustc_serialize::json::Json;
use rustc_span::edition::Edition;
use rustc_span::{sym, symbol::Ident, MultiSpan, Span, Symbol};
Unspecified,
}
+/// Each lint expectation has a `LintExpectationId` assigned by the `LintLevelsBuilder`.
+/// Expected `Diagnostic`s get the lint level `Expect` which stores the `LintExpectationId`
+/// to match it with the actual expectation later on.
+///
+/// The `LintExpectationId` has to be has stable between compilations, as diagnostic
+/// instances might be loaded from cache. Lint messages can be emitted during an
+/// `EarlyLintPass` operating on the AST and during a `LateLintPass` traversing the
+/// HIR tree. The AST doesn't have enough information to create a stable id. The
+/// `LintExpectationId` will instead store the [`AttrId`] defining the expectation.
+/// These `LintExpectationId` will be updated to use the stable [`HirId`] once the
+/// AST has been lowered. The transformation is done by the `LintLevelsBuilder`
+///
+/// Each lint inside the `expect` attribute is tracked individually, the `lint_index`
+/// identifies the lint inside the attribute and ensures that the IDs are unique.
+///
+/// The index values have a type of `u16` to reduce the size of the `LintExpectationId`.
+/// It's reasonable to assume that no user will define 2^16 attributes on one node or
+/// have that amount of lints listed. `u16` values should therefore suffice.
+#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash, Encodable, Decodable)]
+pub enum LintExpectationId {
+ /// Used for lints emitted during the `EarlyLintPass`. This id is not
+ /// has stable and should not be cached.
+ Unstable { attr_id: AttrId, lint_index: Option<u16> },
+ /// The [`HirId`] that the lint expectation is attached to. This id is
+ /// stable and can be cached. The additional index ensures that nodes with
+ /// several expectations can correctly match diagnostics to the individual
+ /// expectation.
+ Stable { hir_id: HirId, attr_index: u16, lint_index: Option<u16> },
+}
+
+impl LintExpectationId {
+ pub fn is_stable(&self) -> bool {
+ match self {
+ LintExpectationId::Unstable { .. } => false,
+ LintExpectationId::Stable { .. } => true,
+ }
+ }
+
+ pub fn get_lint_index(&self) -> Option<u16> {
+ let (LintExpectationId::Unstable { lint_index, .. }
+ | LintExpectationId::Stable { lint_index, .. }) = self;
+
+ *lint_index
+ }
+
+ pub fn set_lint_index(&mut self, new_lint_index: Option<u16>) {
+ let (LintExpectationId::Unstable { ref mut lint_index, .. }
+ | LintExpectationId::Stable { ref mut lint_index, .. }) = self;
+
+ *lint_index = new_lint_index
+ }
+}
+
+impl<HCX: rustc_hir::HashStableContext> HashStable<HCX> for LintExpectationId {
+ #[inline]
+ fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
+ match self {
+ LintExpectationId::Stable { hir_id, attr_index, lint_index: Some(lint_index) } => {
+ hir_id.hash_stable(hcx, hasher);
+ attr_index.hash_stable(hcx, hasher);
+ lint_index.hash_stable(hcx, hasher);
+ }
+ _ => {
+ unreachable!("HashStable should only be called for a filled `LintExpectationId`")
+ }
+ }
+ }
+}
+
+impl<HCX: rustc_hir::HashStableContext> ToStableHashKey<HCX> for LintExpectationId {
+ type KeyType = (HirId, u16, u16);
+
+ #[inline]
+ fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType {
+ match self {
+ LintExpectationId::Stable { hir_id, attr_index, lint_index: Some(lint_index) } => {
+ (*hir_id, *attr_index, *lint_index)
+ }
+ _ => {
+ unreachable!("HashStable should only be called for a filled `LintExpectationId`")
+ }
+ }
+ }
+}
+
/// Setting for how to handle a lint.
+///
+/// See: <https://doc.rust-lang.org/rustc/lints/levels.html>
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
pub enum Level {
+ /// The `allow` level will not issue any message.
Allow,
+ /// The `expect` level will suppress the lint message but in turn produce a message
+ /// if the lint wasn't issued in the expected scope. `Expect` should not be used as
+ /// an initial level for a lint.
+ ///
+ /// Note that this still means that the lint is enabled in this position and should
+ /// be emitted, this will in turn fulfill the expectation and suppress the lint.
+ ///
+ /// See RFC 2383.
+ ///
+ /// The `LintExpectationId` is used to later link a lint emission to the actual
+ /// expectation. It can be ignored in most cases.
+ Expect(LintExpectationId),
+ /// The `warn` level will produce a warning if the lint was violated, however the
+ /// compiler will continue with its execution.
Warn,
ForceWarn,
+ /// The `deny` level will produce an error and stop further execution after the lint
+ /// pass is complete.
Deny,
+ /// `Forbid` is equivalent to the `deny` level but can't be overwritten like the previous
+ /// levels.
Forbid,
}
pub fn as_str(self) -> &'static str {
match self {
Level::Allow => "allow",
+ Level::Expect(_) => "expect",
Level::Warn => "warn",
Level::ForceWarn => "force-warn",
Level::Deny => "deny",
}
}
- /// Converts a lower-case string to a level.
+ /// Converts a lower-case string to a level. This will never construct the expect
+ /// level as that would require a [`LintExpectationId`]
pub fn from_str(x: &str) -> Option<Level> {
match x {
"allow" => Some(Level::Allow),
"warn" => Some(Level::Warn),
"deny" => Some(Level::Deny),
"forbid" => Some(Level::Forbid),
- _ => None,
+ "expect" | _ => None,
}
}
/// Converts a symbol to a level.
- pub fn from_symbol(x: Symbol) -> Option<Level> {
- match x {
+ pub fn from_attr(attr: &Attribute) -> Option<Level> {
+ match attr.name_or_empty() {
sym::allow => Some(Level::Allow),
+ sym::expect => Some(Level::Expect(LintExpectationId::Unstable {
+ attr_id: attr.id,
+ lint_index: None,
+ })),
sym::warn => Some(Level::Warn),
sym::deny => Some(Level::Deny),
sym::forbid => Some(Level::Forbid),
BreakWithLabelAndLoop(Span),
NamedAsmLabel(String),
UnicodeTextFlow(Span, String),
- UnexpectedCfg(Span, Symbol, Option<Symbol>),
+ UnexpectedCfg((Symbol, Span), Option<(Symbol, Span)>),
+ DeprecatedWhereclauseLocation(Span, String),
}
/// Lints that are buffered up early on in the `Session` before the
libc = "0.2.73"
[build-dependencies]
-build_helper = { path = "../../src/build_helper" }
cc = "1.0.69"
use std::env;
+use std::ffi::{OsStr, OsString};
+use std::fmt::Display;
use std::path::{Path, PathBuf};
-use std::process::Command;
-
-use build_helper::{output, tracked_env_var_os};
+use std::process::{Command, Stdio};
fn detect_llvm_link() -> (&'static str, &'static str) {
// Force the link mode we want, preferring static by default, but
}
}
+// Because Cargo adds the compiler's dylib path to our library search path, llvm-config may
+// break: the dylib path for the compiler, as of this writing, contains a copy of the LLVM
+// shared library, which means that when our freshly built llvm-config goes to load it's
+// associated LLVM, it actually loads the compiler's LLVM. In particular when building the first
+// compiler (i.e., in stage 0) that's a problem, as the compiler's LLVM is likely different from
+// the one we want to use. As such, we restore the environment to what bootstrap saw. This isn't
+// perfect -- we might actually want to see something from Cargo's added library paths -- but
+// for now it works.
+fn restore_library_path() {
+ let key = tracked_env_var_os("REAL_LIBRARY_PATH_VAR").expect("REAL_LIBRARY_PATH_VAR");
+ if let Some(env) = tracked_env_var_os("REAL_LIBRARY_PATH") {
+ env::set_var(&key, &env);
+ } else {
+ env::remove_var(&key);
+ }
+}
+
+/// Reads an environment variable and adds it to dependencies.
+/// Supposed to be used for all variables except those set for build scripts by cargo
+/// <https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts>
+fn tracked_env_var_os<K: AsRef<OsStr> + Display>(key: K) -> Option<OsString> {
+ println!("cargo:rerun-if-env-changed={}", key);
+ env::var_os(key)
+}
+
+fn rerun_if_changed_anything_in_dir(dir: &Path) {
+ let mut stack = dir
+ .read_dir()
+ .unwrap()
+ .map(|e| e.unwrap())
+ .filter(|e| &*e.file_name() != ".git")
+ .collect::<Vec<_>>();
+ while let Some(entry) = stack.pop() {
+ let path = entry.path();
+ if entry.file_type().unwrap().is_dir() {
+ stack.extend(path.read_dir().unwrap().map(|e| e.unwrap()));
+ } else {
+ println!("cargo:rerun-if-changed={}", path.display());
+ }
+ }
+}
+
+#[track_caller]
+fn output(cmd: &mut Command) -> String {
+ let output = match cmd.stderr(Stdio::inherit()).output() {
+ Ok(status) => status,
+ Err(e) => {
+ println!("\n\nfailed to execute command: {:?}\nerror: {}\n\n", cmd, e);
+ std::process::exit(1);
+ }
+ };
+ if !output.status.success() {
+ panic!(
+ "command did not execute successfully: {:?}\n\
+ expected success, got: {}",
+ cmd, output.status
+ );
+ }
+ String::from_utf8(output.stdout).unwrap()
+}
+
fn main() {
if tracked_env_var_os("RUST_CHECK").is_some() {
// If we're just running `check`, there's no need for LLVM to be built.
return;
}
- build_helper::restore_library_path();
+ restore_library_path();
let target = env::var("TARGET").expect("TARGET was not set");
let llvm_config =
cfg.debug(false);
}
- build_helper::rerun_if_changed_anything_in_dir(Path::new("llvm-wrapper"));
+ rerun_if_changed_anything_in_dir(Path::new("llvm-wrapper"));
cfg.file("llvm-wrapper/PassWrapper.cpp")
.file("llvm-wrapper/RustWrapper.cpp")
.file("llvm-wrapper/ArchiveWrapper.cpp")
return wrap(Attribute::get(*unwrap(C), fromRust(RustAttr)));
}
-extern "C" LLVMAttributeRef LLVMRustCreateAttrStringValue(LLVMContextRef C,
- const char *Name,
- const char *Value) {
- return wrap(Attribute::get(*unwrap(C), StringRef(Name), StringRef(Value)));
-}
-
extern "C" LLVMAttributeRef LLVMRustCreateAlignmentAttr(LLVMContextRef C,
uint64_t Bytes) {
return wrap(Attribute::getWithAlignment(*unwrap(C), llvm::Align(Bytes)));
syn::custom_keyword!(MAX);
syn::custom_keyword!(ENCODABLE);
syn::custom_keyword!(custom);
+ syn::custom_keyword!(ORD_IMPL);
}
#[derive(Debug)]
let mut max = None;
let mut consts = Vec::new();
let mut encodable = true;
+ let mut ord = true;
// Parse an optional trailing comma
let try_comma = || -> Result<()> {
encodable = false;
continue;
}
+ if body.lookahead1().peek(kw::ORD_IMPL) {
+ body.parse::<kw::ORD_IMPL>()?;
+ body.parse::<Token![=]>()?;
+ body.parse::<kw::custom>()?;
+ ord = false;
+ continue;
+ }
// We've parsed everything that the user provided, so we're done
if body.is_empty() {
break;
}
- // Otherwise, we are parsng a user-defined constant
+ // Otherwise, we are parsing a user-defined constant
let const_attrs = body.call(Attribute::parse_outer)?;
body.parse::<Token![const]>()?;
let const_name: Ident = body.parse()?;
quote! {}
};
+ if ord {
+ derive_paths.push(parse_quote!(Ord));
+ derive_paths.push(parse_quote!(PartialOrd));
+ }
+
+ let step = if ord {
+ quote! {
+ impl ::std::iter::Step for #name {
+ #[inline]
+ fn steps_between(start: &Self, end: &Self) -> Option<usize> {
+ <usize as ::std::iter::Step>::steps_between(
+ &Self::index(*start),
+ &Self::index(*end),
+ )
+ }
+
+ #[inline]
+ fn forward_checked(start: Self, u: usize) -> Option<Self> {
+ Self::index(start).checked_add(u).map(Self::from_usize)
+ }
+
+ #[inline]
+ fn backward_checked(start: Self, u: usize) -> Option<Self> {
+ Self::index(start).checked_sub(u).map(Self::from_usize)
+ }
+ }
+
+ // Safety: The implementation of `Step` upholds all invariants.
+ unsafe impl ::std::iter::TrustedStep for #name {}
+ }
+ } else {
+ quote! {}
+ };
+
let debug_impl = match debug_format {
DebugFormat::Custom => quote! {},
DebugFormat::Format(format) => {
Ok(Self(quote! {
#(#attrs)*
- #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, #(#derive_paths),*)]
+ #[derive(Clone, Copy, PartialEq, Eq, Hash, #(#derive_paths),*)]
#[rustc_layout_scalar_valid_range_end(#max)]
#vis struct #name {
private: u32,
}
}
- impl ::std::iter::Step for #name {
- #[inline]
- fn steps_between(start: &Self, end: &Self) -> Option<usize> {
- <usize as ::std::iter::Step>::steps_between(
- &Self::index(*start),
- &Self::index(*end),
- )
- }
-
- #[inline]
- fn forward_checked(start: Self, u: usize) -> Option<Self> {
- Self::index(start).checked_add(u).map(Self::from_usize)
- }
-
- #[inline]
- fn backward_checked(start: Self, u: usize) -> Option<Self> {
- Self::index(start).checked_sub(u).map(Self::from_usize)
- }
- }
-
- // Safety: The implementation of `Step` upholds all invariants.
- unsafe impl ::std::iter::TrustedStep for #name {}
+ #step
impl From<#name> for u32 {
#[inline]
.layout;
// In both stdcall and fastcall, we always round up the argument size to the
// nearest multiple of 4 bytes.
- (layout.size.bytes_usize() + 3) & !3
+ (layout.size().bytes_usize() + 3) & !3
})
.sum()
}
use rustc_middle::thir;
use rustc_middle::traits::specialization_graph;
use rustc_middle::ty::codec::TyEncoder;
-use rustc_middle::ty::fast_reject::{self, SimplifiedType, SimplifyParams};
+use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt};
use rustc_serialize::{opaque, Encodable, Encoder};
let simplified_self_ty = fast_reject::simplify_type(
self.tcx,
trait_ref.self_ty(),
- SimplifyParams::No,
+ TreatParams::AsPlaceholders,
);
self.impls
macro_rules! arena_types {
($macro:path) => (
$macro!([
- [] layout: rustc_target::abi::Layout,
+ [] layout: rustc_target::abi::LayoutS<'tcx>,
[] fn_abi: rustc_target::abi::call::FnAbi<'tcx, rustc_middle::ty::Ty<'tcx>>,
// AdtDef are interned and compared by address
[decode] adt_def: rustc_middle::ty::AdtDef,
use rustc_query_system::ich::StableHashingContext;
use rustc_session::lint::{
builtin::{self, FORBIDDEN_LINT_GROUPS},
- FutureIncompatibilityReason, Level, Lint, LintId,
+ FutureIncompatibilityReason, Level, Lint, LintExpectationId, LintId,
};
use rustc_session::{DiagnosticMessageId, Session};
use rustc_span::hygiene::MacroKind;
#[derive(Debug)]
pub struct LintLevelMap {
+ /// This is a collection of lint expectations as described in RFC 2383, that
+ /// can be fulfilled during this compilation session. This means that at least
+ /// one expected lint is currently registered in the lint store.
+ ///
+ /// The [`LintExpectationId`] is stored as a part of the [`Expect`](Level::Expect)
+ /// lint level.
+ pub lint_expectations: Vec<(LintExpectationId, LintExpectation)>,
pub sets: LintLevelSets,
pub id_to_set: FxHashMap<HirId, LintStackIndex>,
}
impl<'a> HashStable<StableHashingContext<'a>> for LintLevelMap {
#[inline]
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
- let LintLevelMap { ref sets, ref id_to_set } = *self;
+ let LintLevelMap { ref sets, ref id_to_set, ref lint_expectations } = *self;
id_to_set.hash_stable(hcx, hasher);
+ lint_expectations.hash_stable(hcx, hasher);
hcx.while_hashing_spans(true, |hcx| sets.hash_stable(hcx, hasher))
}
}
+/// This struct represents a lint expectation and holds all required information
+/// to emit the `unfulfilled_lint_expectations` lint if it is unfulfilled after
+/// the `LateLintPass` has completed.
+#[derive(Clone, Debug, HashStable)]
+pub struct LintExpectation {
+ /// The reason for this expectation that can optionally be added as part of
+ /// the attribute. It will be displayed as part of the lint message.
+ pub reason: Option<Symbol>,
+ /// The [`Span`] of the attribute that this expectation originated from.
+ pub emission_span: Span,
+}
+
+impl LintExpectation {
+ pub fn new(reason: Option<Symbol>, attr_span: Span) -> Self {
+ Self { reason, emission_span: attr_span }
+ }
+}
+
pub struct LintDiagnosticBuilder<'a>(DiagnosticBuilder<'a, ()>);
impl<'a> LintDiagnosticBuilder<'a> {
Level::Forbid => "-F",
Level::Allow => "-A",
Level::ForceWarn => "--force-warn",
+ Level::Expect(_) => {
+ unreachable!("the expect level does not have a commandline flag")
+ }
};
let hyphen_case_lint_name = name.replace('_', "-");
if lint_flag_val.as_str() == name {
return;
}
}
+ (Level::Expect(expect_id), _) => {
+ // This case is special as we actually allow the lint itself in this context, but
+ // we can't return early like in the case for `Level::Allow` because we still
+ // need the lint diagnostic to be emitted to `rustc_error::HanderInner`.
+ //
+ // We can also not mark the lint expectation as fulfilled here right away, as it
+ // can still be cancelled in the decorate function. All of this means that we simply
+ // create a `DiagnosticBuilder` and continue as we would for warnings.
+ sess.struct_expect("", expect_id)
+ }
(Level::Warn | Level::ForceWarn, Some(span)) => sess.struct_span_warn(span, ""),
(Level::Warn | Level::ForceWarn, None) => sess.struct_warn(""),
(Level::Deny | Level::Forbid, Some(span)) => {
}
}
+ // Lint diagnostics that are covered by the expect level will not be emitted outside
+ // the compiler. It is therefore not necessary to add any information for the user.
+ // This will therefore directly call the decorate function which will in turn emit
+ // the `Diagnostic`.
+ if let Level::Expect(_) = level {
+ let name = lint.name_lower();
+ err.code(DiagnosticId::Lint { name, has_future_breakage, is_force_warn: false });
+ decorate(LintDiagnosticBuilder::new(err));
+ return;
+ }
+
explain_lint_level_source(sess, lint, level, src, &mut err);
let name = lint.name_lower();
use crate::ty::{self, DefIdTree, TyCtxt};
use rustc_ast::NodeId;
use rustc_attr::{self as attr, ConstStability, Deprecation, Stability};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{Applicability, Diagnostic};
use rustc_feature::GateIssue;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
-use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX};
use rustc_hir::{self, HirId};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE, SOFT_UNSTABLE};
pub stab_map: FxHashMap<LocalDefId, Stability>,
pub const_stab_map: FxHashMap<LocalDefId, ConstStability>,
pub depr_map: FxHashMap<LocalDefId, DeprecationEntry>,
-
- /// Maps for each crate whether it is part of the staged API.
- pub staged_api: FxHashMap<CrateNum, bool>,
-
- /// Features enabled for this crate.
- pub active_features: FxHashSet<Symbol>,
}
impl Index {
debug!("stability: skipping span={:?} since it is internal", span);
return EvalResult::Allow;
}
- if self.stability().active_features.contains(&feature) {
+ if self.features().active(feature) {
return EvalResult::Allow;
}
use std::borrow::Cow;
use std::convert::{TryFrom, TryInto};
+use std::fmt;
use std::iter;
use std::ops::{Deref, Range};
use std::ptr;
use rustc_ast::Mutability;
+use rustc_data_structures::intern::Interned;
use rustc_data_structures::sorted_map::SortedMap;
use rustc_span::DUMMY_SP;
use rustc_target::abi::{Align, HasDataLayout, Size};
pub extra: Extra,
}
+/// Interned types generally have an `Outer` type and an `Inner` type, where
+/// `Outer` is a newtype around `Interned<Inner>`, and all the operations are
+/// done on `Outer`, because all occurrences are interned. E.g. `Ty` is an
+/// outer type and `TyS` is its inner type.
+///
+/// Here things are different because only const allocations are interned. This
+/// means that both the inner type (`Allocation`) and the outer type
+/// (`ConstAllocation`) are used quite a bit.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
+#[cfg_attr(not(bootstrap), rustc_pass_by_value)]
+pub struct ConstAllocation<'tcx, Tag = AllocId, Extra = ()>(
+ pub Interned<'tcx, Allocation<Tag, Extra>>,
+);
+
+impl<'tcx> fmt::Debug for ConstAllocation<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // This matches how `Allocation` is printed. We print it like this to
+ // avoid having to update expected output in a lot of tests.
+ write!(f, "{:?}", self.inner())
+ }
+}
+
+impl<'tcx, Tag, Extra> ConstAllocation<'tcx, Tag, Extra> {
+ pub fn inner(self) -> &'tcx Allocation<Tag, Extra> {
+ self.0.0
+ }
+}
+
/// We have our own error type that does not know about the `AllocId`; that information
/// is added when converting to `InterpError`.
#[derive(Debug)]
pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar, ScalarMaybeUninit};
pub use self::allocation::{
- alloc_range, AllocRange, Allocation, InitChunk, InitChunkIter, InitMask, Relocations,
+ alloc_range, AllocRange, Allocation, ConstAllocation, InitChunk, InitChunkIter, InitMask,
+ Relocations,
};
pub use self::pointer::{Pointer, PointerArithmetic, Provenance};
let alloc_id = decoder.with_position(pos, |decoder| {
match alloc_kind {
AllocDiscriminant::Alloc => {
- let alloc = <&'tcx Allocation as Decodable<_>>::decode(decoder);
+ let alloc = <ConstAllocation<'tcx> as Decodable<_>>::decode(decoder);
// We already have a reserved `AllocId`.
let alloc_id = alloc_id.unwrap();
trace!("decoded alloc {:?}: {:#?}", alloc_id, alloc);
/// This is also used to break the cycle in recursive statics.
Static(DefId),
/// The alloc ID points to memory.
- Memory(&'tcx Allocation),
+ Memory(ConstAllocation<'tcx>),
}
impl<'tcx> GlobalAlloc<'tcx> {
/// Panics if the `GlobalAlloc` does not refer to an `GlobalAlloc::Memory`
#[track_caller]
#[inline]
- pub fn unwrap_memory(&self) -> &'tcx Allocation {
+ pub fn unwrap_memory(&self) -> ConstAllocation<'tcx> {
match *self {
GlobalAlloc::Memory(mem) => mem,
_ => bug!("expected memory, got {:?}", self),
/// Statics with identical content will still point to the same `Allocation`, i.e.,
/// their data will be deduplicated through `Allocation` interning -- but they
/// are different places in memory and as such need different IDs.
- pub fn create_memory_alloc(self, mem: &'tcx Allocation) -> AllocId {
+ pub fn create_memory_alloc(self, mem: ConstAllocation<'tcx>) -> AllocId {
let id = self.reserve_alloc_id();
self.set_alloc_id_memory(id, mem);
id
/// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. Trying to
/// call this function twice, even with the same `Allocation` will ICE the compiler.
- pub fn set_alloc_id_memory(self, id: AllocId, mem: &'tcx Allocation) {
+ pub fn set_alloc_id_memory(self, id: AllocId, mem: ConstAllocation<'tcx>) {
if let Some(old) = self.alloc_map.lock().alloc_map.insert(id, GlobalAlloc::Memory(mem)) {
bug!("tried to set allocation ID {}, but it was already existing as {:#?}", id, old);
}
/// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. May be called
/// twice for the same `(AllocId, Allocation)` pair.
- fn set_alloc_id_same_memory(self, id: AllocId, mem: &'tcx Allocation) {
+ fn set_alloc_id_same_memory(self, id: AllocId, mem: ConstAllocation<'tcx>) {
self.alloc_map.lock().alloc_map.insert_same(id, GlobalAlloc::Memory(mem));
}
}
pub fn eval_static_initializer(
self,
def_id: DefId,
- ) -> Result<&'tcx mir::Allocation, ErrorHandled> {
+ ) -> Result<mir::ConstAllocation<'tcx>, ErrorHandled> {
trace!("eval_static_initializer: Need to compute {:?}", def_id);
assert!(self.is_static(def_id));
let instance = ty::Instance::mono(self, def_id);
self,
gid: GlobalId<'tcx>,
param_env: ty::ParamEnv<'tcx>,
- ) -> Result<&'tcx mir::Allocation, ErrorHandled> {
+ ) -> Result<mir::ConstAllocation<'tcx>, ErrorHandled> {
let param_env = param_env.with_const();
trace!("eval_to_allocation: Need to compute {:?}", gid);
let raw_const = self.eval_to_allocation_raw(param_env.and(gid))?;
use crate::ty::{Lift, ParamEnv, ScalarInt, Ty, TyCtxt};
use super::{
- AllocId, AllocRange, Allocation, InterpResult, Pointer, PointerArithmetic, Provenance,
+ AllocId, AllocRange, ConstAllocation, InterpResult, Pointer, PointerArithmetic, Provenance,
};
/// Represents the result of const evaluation via the `eval_to_allocation` query.
Scalar(Scalar),
/// Used only for `&[u8]` and `&str`
- Slice { data: &'tcx Allocation, start: usize, end: usize },
+ Slice { data: ConstAllocation<'tcx>, start: usize, end: usize },
/// A value not represented/representable by `Scalar` or `Slice`
ByRef {
/// The backing memory of the value, may contain more memory than needed for just the value
- /// in order to share `Allocation`s between values
- alloc: &'tcx Allocation,
+ /// in order to share `ConstAllocation`s between values
+ alloc: ConstAllocation<'tcx>,
/// Offset into `alloc`
offset: Size,
},
pub fn get_slice_bytes<'tcx>(cx: &impl HasDataLayout, val: ConstValue<'tcx>) -> &'tcx [u8] {
if let ConstValue::Slice { data, start, end } = val {
let len = end - start;
- data.get_bytes(
- cx,
- AllocRange { start: Size::from_bytes(start), size: Size::from_bytes(len) },
- )
- .unwrap_or_else(|err| bug!("const slice is invalid: {:?}", err))
+ data.inner()
+ .get_bytes(
+ cx,
+ AllocRange { start: Size::from_bytes(start), size: Size::from_bytes(len) },
+ )
+ .unwrap_or_else(|err| bug!("const slice is invalid: {:?}", err))
} else {
bug!("expected const slice, but found another const value");
}
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html
use crate::mir::coverage::{CodeRegion, CoverageKind};
-use crate::mir::interpret::{Allocation, ConstValue, GlobalAlloc, Scalar};
+use crate::mir::interpret::{ConstAllocation, ConstValue, GlobalAlloc, Scalar};
use crate::mir::visit::MirVisitable;
use crate::ty::adjustment::PointerCast;
use crate::ty::codec::{TyDecoder, TyEncoder};
impl<'tcx> Constant<'tcx> {
pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
- match self.literal.const_for_ty()?.val().try_to_scalar() {
+ match self.literal.try_to_scalar() {
Some(Scalar::Ptr(ptr, _size)) => match tcx.global_alloc(ptr.provenance) {
GlobalAlloc::Static(def_id) => {
assert!(!tcx.is_thread_local_static(def_id));
use rustc_hir::def_id::DefId;
use rustc_index::vec::Idx;
use rustc_middle::mir::interpret::{
- read_target_uint, AllocId, Allocation, ConstValue, GlobalAlloc, Pointer, Provenance,
+ read_target_uint, AllocId, Allocation, ConstAllocation, ConstValue, GlobalAlloc, Pointer,
+ Provenance,
};
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::MirSource;
use rustc_middle::mir::*;
-use rustc_middle::ty::{self, TyCtxt, TypeFoldable, TypeVisitor};
+use rustc_middle::ty::{self, TyCtxt};
use rustc_target::abi::Size;
-use std::ops::ControlFlow;
const INDENT: &str = " ";
/// Alignment for lining up comments following MIR statements
body: &Body<'_>,
w: &mut dyn Write,
) -> io::Result<()> {
- fn alloc_ids_from_alloc(alloc: &Allocation) -> impl DoubleEndedIterator<Item = AllocId> + '_ {
- alloc.relocations().values().map(|id| *id)
+ fn alloc_ids_from_alloc(
+ alloc: ConstAllocation<'_>,
+ ) -> impl DoubleEndedIterator<Item = AllocId> + '_ {
+ alloc.inner().relocations().values().map(|id| *id)
}
fn alloc_ids_from_const(val: ConstValue<'_>) -> impl Iterator<Item = AllocId> + '_ {
match val {
- ConstValue::Scalar(interpret::Scalar::Ptr(ptr, _size)) => {
+ ConstValue::Scalar(interpret::Scalar::Ptr(ptr, _)) => {
Either::Left(Either::Left(std::iter::once(ptr.provenance)))
}
ConstValue::Scalar(interpret::Scalar::Int { .. }) => {
}
}
struct CollectAllocIds(BTreeSet<AllocId>);
- impl<'tcx> TypeVisitor<'tcx> for CollectAllocIds {
- fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+
+ impl<'tcx> Visitor<'tcx> for CollectAllocIds {
+ fn visit_const(&mut self, c: ty::Const<'tcx>, _loc: Location) {
if let ty::ConstKind::Value(val) = c.val() {
self.0.extend(alloc_ids_from_const(val));
}
- c.super_visit_with(self)
+ }
+
+ fn visit_constant(&mut self, c: &Constant<'tcx>, loc: Location) {
+ match c.literal {
+ ConstantKind::Ty(c) => self.visit_const(c, loc),
+ ConstantKind::Val(val, _) => {
+ self.0.extend(alloc_ids_from_const(val));
+ }
+ }
}
}
+
let mut visitor = CollectAllocIds(Default::default());
- body.visit_with(&mut visitor);
+ visitor.visit_body(body);
+
// `seen` contains all seen allocations, including the ones we have *not* printed yet.
// The protocol is to first `insert` into `seen`, and only if that returns `true`
// then push to `todo`.
let mut todo: Vec<_> = seen.iter().copied().collect();
while let Some(id) = todo.pop() {
let mut write_allocation_track_relocs =
- |w: &mut dyn Write, alloc: &Allocation| -> io::Result<()> {
+ |w: &mut dyn Write, alloc: ConstAllocation<'tcx>| -> io::Result<()> {
// `.rev()` because we are popping them from the back of the `todo` vector.
for id in alloc_ids_from_alloc(alloc).rev() {
if seen.insert(id) {
todo.push(id);
}
}
- write!(w, "{}", display_allocation(tcx, alloc))
+ write!(w, "{}", display_allocation(tcx, alloc.inner()))
};
write!(w, "\n{}", id)?;
match tcx.get_global_alloc(id) {
use rustc_index::vec::IndexVec;
use rustc_middle::infer::canonical::Canonical;
use rustc_middle::middle::region;
+use rustc_middle::mir::interpret::AllocId;
use rustc_middle::mir::{
BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp, UserTypeProjection,
};
/// This is only distinguished from `Literal` so that we can register some
/// info for diagnostics.
StaticRef {
- literal: Const<'tcx>,
+ alloc_id: AllocId,
+ ty: Ty<'tcx>,
def_id: DefId,
},
/// Inline assembly, i.e. `asm!()`.
}
Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {}
Literal { literal, user_ty: _, const_id: _ } => visitor.visit_const(literal),
- StaticRef { literal, def_id: _ } => visitor.visit_const(literal),
+ StaticRef { alloc_id: _, ty: _, def_id: _ } => {}
InlineAsm { ref operands, template: _, options: _, line_spans: _ } => {
for op in &**operands {
use InlineAsmOperand::*;
use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
use crate::mir::{
self,
- interpret::{AllocId, Allocation},
+ interpret::{AllocId, ConstAllocation},
};
use crate::thir;
use crate::traits;
}
}
+impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ConstAllocation<'tcx> {
+ fn encode(&self, e: &mut E) -> Result<(), E::Error> {
+ self.inner().encode(e)
+ }
+}
+
impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for AllocId {
fn encode(&self, e: &mut E) -> Result<(), E::Error> {
e.encode_alloc_id(self)
}
}
-impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for Allocation {
- fn decode(decoder: &mut D) -> &'tcx Self {
+impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ConstAllocation<'tcx> {
+ fn decode(decoder: &mut D) -> Self {
decoder.tcx().intern_const_alloc(Decodable::decode(decoder))
}
}
&'tcx ty::List<Ty<'tcx>>,
&'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
&'tcx traits::ImplSource<'tcx, ()>,
- &'tcx Allocation,
&'tcx mir::Body<'tcx>,
&'tcx mir::UnsafetyCheckResult,
&'tcx mir::BorrowCheckResult<'tcx>,
use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource};
use crate::middle::resolve_lifetime::{self, LifetimeScopeForPath};
use crate::middle::stability;
-use crate::mir::interpret::{self, Allocation, ConstValue, Scalar};
+use crate::mir::interpret::{self, Allocation, ConstAllocation, ConstValue, Scalar};
use crate::mir::{
Body, BorrowCheckResult, Field, Local, Place, PlaceElem, ProjectionKind, Promoted,
};
use rustc_span::source_map::{MultiSpan, SourceMap};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
-use rustc_target::abi::{Layout, TargetDataLayout, VariantIdx};
+use rustc_target::abi::{Layout, LayoutS, TargetDataLayout, VariantIdx};
use rustc_target::spec::abi;
use rustc_type_ir::TypeFlags;
const_: InternedSet<'tcx, ConstS<'tcx>>,
const_allocation: InternedSet<'tcx, Allocation>,
bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>,
- layout: InternedSet<'tcx, Layout>,
+ layout: InternedSet<'tcx, LayoutS<'tcx>>,
adt_def: InternedSet<'tcx, AdtDef>,
}
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted>;
}
-// Deprecated: we are in the process of converting all uses to `nop_lift`.
-macro_rules! nop_lift_old {
- ($set:ident; $ty:ty => $lifted:ty) => {
- impl<'a, 'tcx> Lift<'tcx> for $ty {
- type Lifted = $lifted;
- fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
- if tcx.interners.$set.contains_pointer_to(&InternedInSet(self)) {
- Some(unsafe { mem::transmute(self) })
- } else {
- None
- }
- }
- }
- };
-}
-
macro_rules! nop_lift {
($set:ident; $ty:ty => $lifted:ty) => {
impl<'a, 'tcx> Lift<'tcx> for $ty {
nop_lift! {type_; Ty<'a> => Ty<'tcx>}
nop_lift! {region; Region<'a> => Region<'tcx>}
nop_lift! {const_; Const<'a> => Const<'tcx>}
-nop_lift_old! {const_allocation; &'a Allocation => &'tcx Allocation}
+nop_lift! {const_allocation; ConstAllocation<'a> => ConstAllocation<'tcx>}
nop_lift! {predicate; Predicate<'a> => Predicate<'tcx>}
nop_list_lift! {poly_existential_predicates; ty::Binder<'a, ExistentialPredicate<'a>> => ty::Binder<'tcx, ExistentialPredicate<'tcx>>}
direct_interners! {
region: mk_region(RegionKind): Region -> Region<'tcx>,
const_: mk_const(ConstS<'tcx>): Const -> Const<'tcx>,
+ const_allocation: intern_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>,
+ layout: intern_layout(LayoutS<'tcx>): Layout -> Layout<'tcx>,
}
macro_rules! direct_interners_old {
// FIXME: eventually these should all be converted to `direct_interners`.
direct_interners_old! {
- const_allocation: intern_const_alloc(Allocation),
- layout: intern_layout(Layout),
adt_def: intern_adt_def(AdtDef),
}
return bound;
}
- if hir.attrs(id).iter().any(|attr| Level::from_symbol(attr.name_or_empty()).is_some()) {
+ if hir.attrs(id).iter().any(|attr| Level::from_attr(attr).is_some()) {
return id;
}
let next = hir.get_parent_node(id);
tcx.arena.alloc(tcx.resolutions(()).glob_map.get(&id).cloned().unwrap_or_default())
};
- providers.lookup_stability = |tcx, id| tcx.stability().local_stability(id.expect_local());
- providers.lookup_const_stability =
- |tcx, id| tcx.stability().local_const_stability(id.expect_local());
- providers.lookup_deprecation_entry =
- |tcx, id| tcx.stability().local_deprecation_entry(id.expect_local());
providers.extern_mod_stmt_cnum =
|tcx, id| tcx.resolutions(()).extern_crate_map.get(&id).cloned();
providers.output_filenames = |tcx, ()| &tcx.output_filenames;
}
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
-pub enum SimplifyParams {
- Yes,
- No,
+pub enum TreatParams {
+ /// Treat parameters as bound types in the given environment.
+ ///
+ /// For this to be correct the input has to be fully normalized
+ /// in its param env as it may otherwise cause us to ignore
+ /// potentially applying impls.
+ AsBoundTypes,
+ AsPlaceholders,
}
/// Tries to simplify a type by only returning the outermost injective¹ layer, if one exists.
/// The idea is to get something simple that we can use to quickly decide if two types could unify,
/// for example during method lookup.
///
-/// A special case here are parameters and projections. Projections can be normalized to
-/// a different type, meaning that `<T as Trait>::Assoc` and `u8` can be unified, even though
-/// their outermost layer is different while parameters like `T` of impls are later replaced
-/// with an inference variable, which then also allows unification with other types.
+/// A special case here are parameters and projections, which are only injective
+/// if they are treated as bound types.
///
-/// When using `SimplifyParams::Yes`, we still return a simplified type for params and projections²,
-/// the reasoning for this can be seen at the places doing this.
+/// For example when storing impls based on their simplified self type, we treat
+/// generic parameters as placeholders. We must not simplify them here,
+/// as they can unify with any other type.
///
+/// With projections we have to be even more careful, as even when treating them as bound types
+/// this is still only correct if they are fully normalized.
///
-/// ¹ meaning that if two outermost layers are different, then the whole types are also different.
-/// ² FIXME(@lcnr): this seems like it can actually end up being unsound with the way it's used during
-/// candidate selection. We do not consider non blanket impls for `<_ as Trait>::Assoc` even
-/// though `_` can be inferred to a concrete type later at which point a concrete impl
-/// could actually apply. After experimenting for about an hour I wasn't able to cause any issues
-/// this way so I am not going to change this until we actually find an issue as I am really
-/// interesting in getting an actual test for this.
-pub fn simplify_type(
- tcx: TyCtxt<'_>,
- ty: Ty<'_>,
- can_simplify_params: SimplifyParams,
+/// ¹ meaning that if the outermost layers are different, then the whole types are also different.
+pub fn simplify_type<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ ty: Ty<'tcx>,
+ treat_params: TreatParams,
) -> Option<SimplifiedType> {
match *ty.kind() {
ty::Bool => Some(BoolSimplifiedType),
ty::Array(..) => Some(ArraySimplifiedType),
ty::Slice(..) => Some(SliceSimplifiedType),
ty::RawPtr(ptr) => Some(PtrSimplifiedType(ptr.mutbl)),
- ty::Dynamic(ref trait_info, ..) => match trait_info.principal_def_id() {
+ ty::Dynamic(trait_info, ..) => match trait_info.principal_def_id() {
Some(principal_def_id) if !tcx.trait_is_auto(principal_def_id) => {
Some(TraitSimplifiedType(principal_def_id))
}
ty::Ref(_, _, mutbl) => Some(RefSimplifiedType(mutbl)),
ty::FnDef(def_id, _) | ty::Closure(def_id, _) => Some(ClosureSimplifiedType(def_id)),
ty::Generator(def_id, _, _) => Some(GeneratorSimplifiedType(def_id)),
- ty::GeneratorWitness(ref tys) => {
- Some(GeneratorWitnessSimplifiedType(tys.skip_binder().len()))
- }
+ ty::GeneratorWitness(tys) => Some(GeneratorWitnessSimplifiedType(tys.skip_binder().len())),
ty::Never => Some(NeverSimplifiedType),
- ty::Tuple(ref tys) => Some(TupleSimplifiedType(tys.len())),
- ty::FnPtr(ref f) => Some(FunctionSimplifiedType(f.skip_binder().inputs().len())),
- ty::Projection(_) | ty::Param(_) => {
- if can_simplify_params == SimplifyParams::Yes {
- // In normalized types, projections don't unify with
- // anything. when lazy normalization happens, this
- // will change. It would still be nice to have a way
- // to deal with known-not-to-unify-with-anything
- // projections (e.g., the likes of <__S as Encoder>::Error).
+ ty::Tuple(tys) => Some(TupleSimplifiedType(tys.len())),
+ ty::FnPtr(f) => Some(FunctionSimplifiedType(f.skip_binder().inputs().len())),
+ ty::Param(_) | ty::Projection(_) => match treat_params {
+ // When treated as bound types, projections don't unify with
+ // anything as long as they are fully normalized.
+ //
+ // We will have to be careful with lazy normalization here.
+ TreatParams::AsBoundTypes => {
+ debug!("treating `{}` as a bound type", ty);
Some(ParameterSimplifiedType)
- } else {
- None
}
- }
+ TreatParams::AsPlaceholders => None,
+ },
ty::Opaque(def_id, _) => Some(OpaqueSimplifiedType(def_id)),
ty::Foreign(def_id) => Some(ForeignSimplifiedType(def_id)),
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(_) | ty::Error(_) => None,
use crate::ty::{self, subst::SubstsRef, ReprOptions, Ty, TyCtxt, TypeFoldable};
use rustc_ast as ast;
use rustc_attr as attr;
+use rustc_data_structures::intern::Interned;
use rustc_hir as hir;
use rustc_hir::lang_items::LangItem;
use rustc_index::bit_set::BitSet;
}
impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
- fn scalar_pair(&self, a: Scalar, b: Scalar) -> Layout {
+ fn scalar_pair(&self, a: Scalar, b: Scalar) -> LayoutS<'tcx> {
let dl = self.data_layout();
let b_align = b.value.align(dl);
let align = a.value.align(dl).max(b_align).max(dl.aggregate_align);
.chain(Niche::from_scalar(dl, Size::ZERO, a))
.max_by_key(|niche| niche.available(dl));
- Layout {
+ LayoutS {
variants: Variants::Single { index: VariantIdx::new(0) },
fields: FieldsShape::Arbitrary {
offsets: vec![Size::ZERO, b_offset],
fields: &[TyAndLayout<'_>],
repr: &ReprOptions,
kind: StructKind,
- ) -> Result<Layout, LayoutError<'tcx>> {
+ ) -> Result<LayoutS<'tcx>, LayoutError<'tcx>> {
let dl = self.data_layout();
let pack = repr.pack;
if pack.is_some() && repr.align.is_some() {
// Two non-ZST fields, and they're both scalars.
(
- Some((i, &TyAndLayout { layout: &Layout { abi: Abi::Scalar(a), .. }, .. })),
- Some((j, &TyAndLayout { layout: &Layout { abi: Abi::Scalar(b), .. }, .. })),
+ Some((
+ i,
+ &TyAndLayout {
+ layout: Layout(Interned(&LayoutS { abi: Abi::Scalar(a), .. }, _)),
+ ..
+ },
+ )),
+ Some((
+ j,
+ &TyAndLayout {
+ layout: Layout(Interned(&LayoutS { abi: Abi::Scalar(b), .. }, _)),
+ ..
+ },
+ )),
None,
) => {
// Order by the memory placement, not source order.
abi = Abi::Uninhabited;
}
- Ok(Layout {
+ Ok(LayoutS {
variants: Variants::Single { index: VariantIdx::new(0) },
fields: FieldsShape::Arbitrary { offsets, memory_index },
abi,
})
}
- fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<'tcx>> {
+ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<Layout<'tcx>, LayoutError<'tcx>> {
let tcx = self.tcx;
let param_env = self.param_env;
let dl = self.data_layout();
assert!(size.bits() <= 128);
Scalar { value, valid_range: WrappingRange { start: 0, end: size.unsigned_int_max() } }
};
- let scalar = |value: Primitive| tcx.intern_layout(Layout::scalar(self, scalar_unit(value)));
+ let scalar =
+ |value: Primitive| tcx.intern_layout(LayoutS::scalar(self, scalar_unit(value)));
let univariant = |fields: &[TyAndLayout<'_>], repr: &ReprOptions, kind| {
Ok(tcx.intern_layout(self.univariant_uninterned(ty, fields, repr, kind)?))
Ok(match *ty.kind() {
// Basic scalars.
- ty::Bool => tcx.intern_layout(Layout::scalar(
+ ty::Bool => tcx.intern_layout(LayoutS::scalar(
self,
Scalar { value: Int(I8, false), valid_range: WrappingRange { start: 0, end: 1 } },
)),
- ty::Char => tcx.intern_layout(Layout::scalar(
+ ty::Char => tcx.intern_layout(LayoutS::scalar(
self,
Scalar {
value: Int(I32, false),
ty::FnPtr(_) => {
let mut ptr = scalar_unit(Pointer);
ptr.valid_range = ptr.valid_range.with_start(1);
- tcx.intern_layout(Layout::scalar(self, ptr))
+ tcx.intern_layout(LayoutS::scalar(self, ptr))
}
// The never type.
- ty::Never => tcx.intern_layout(Layout {
+ ty::Never => tcx.intern_layout(LayoutS {
variants: Variants::Single { index: VariantIdx::new(0) },
fields: FieldsShape::Primitive,
abi: Abi::Uninhabited,
let pointee = tcx.normalize_erasing_regions(param_env, pointee);
if pointee.is_sized(tcx.at(DUMMY_SP), param_env) {
- return Ok(tcx.intern_layout(Layout::scalar(self, data_ptr)));
+ return Ok(tcx.intern_layout(LayoutS::scalar(self, data_ptr)));
}
let unsized_part = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
let metadata = match unsized_part.kind() {
ty::Foreign(..) => {
- return Ok(tcx.intern_layout(Layout::scalar(self, data_ptr)));
+ return Ok(tcx.intern_layout(LayoutS::scalar(self, data_ptr)));
}
ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)),
ty::Dynamic(..) => {
let largest_niche = if count != 0 { element.largest_niche } else { None };
- tcx.intern_layout(Layout {
+ tcx.intern_layout(LayoutS {
variants: Variants::Single { index: VariantIdx::new(0) },
fields: FieldsShape::Array { stride: element.size, count },
abi,
}
ty::Slice(element) => {
let element = self.layout_of(element)?;
- tcx.intern_layout(Layout {
+ tcx.intern_layout(LayoutS {
variants: Variants::Single { index: VariantIdx::new(0) },
fields: FieldsShape::Array { stride: element.size, count: 0 },
abi: Abi::Aggregate { sized: false },
size: Size::ZERO,
})
}
- ty::Str => tcx.intern_layout(Layout {
+ ty::Str => tcx.intern_layout(LayoutS {
variants: Variants::Single { index: VariantIdx::new(0) },
fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 },
abi: Abi::Aggregate { sized: false },
// Extract the number of elements from the layout of the array field:
let Ok(TyAndLayout {
- layout: Layout { fields: FieldsShape::Array { count, .. }, .. },
+ layout: Layout(Interned(LayoutS { fields: FieldsShape::Array { count, .. }, .. }, _)),
..
}) = self.layout_of(f0_ty) else {
return Err(LayoutError::Unknown(ty));
FieldsShape::Array { stride: e_ly.size, count: e_len }
};
- tcx.intern_layout(Layout {
+ tcx.intern_layout(LayoutS {
variants: Variants::Single { index: VariantIdx::new(0) },
fields,
abi: Abi::Vector { element: e_abi, count: e_len },
align = align.min(AbiAndPrefAlign::new(pack));
}
- return Ok(tcx.intern_layout(Layout {
+ return Ok(tcx.intern_layout(LayoutS {
variants: Variants::Single { index },
fields: FieldsShape::Union(
NonZeroUsize::new(variants[index].len())
align = align.max(st.align);
- Ok(st)
+ Ok(tcx.intern_layout(st))
})
.collect::<Result<IndexVec<VariantIdx, _>, _>>()?;
- let offset = st[i].fields.offset(field_index) + niche.offset;
- let size = st[i].size;
+ let offset = st[i].fields().offset(field_index) + niche.offset;
+ let size = st[i].size();
- let abi = if st.iter().all(|v| v.abi.is_uninhabited()) {
+ let abi = if st.iter().all(|v| v.abi().is_uninhabited()) {
Abi::Uninhabited
} else {
- match st[i].abi {
+ match st[i].abi() {
Abi::Scalar(_) => Abi::Scalar(niche_scalar),
Abi::ScalarPair(first, second) => {
// We need to use scalar_unit to reset the
let largest_niche = Niche::from_scalar(dl, offset, niche_scalar);
- niche_filling_layout = Some(Layout {
+ niche_filling_layout = Some(LayoutS {
variants: Variants::Multiple {
tag: niche_scalar,
tag_encoding: TagEncoding::Niche {
let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag);
- let tagged_layout = Layout {
+ let layout_variants =
+ layout_variants.into_iter().map(|v| tcx.intern_layout(v)).collect();
+
+ let tagged_layout = LayoutS {
variants: Variants::Multiple {
tag,
tag_encoding: TagEncoding::Direct,
ty: Ty<'tcx>,
def_id: hir::def_id::DefId,
substs: SubstsRef<'tcx>,
- ) -> Result<&'tcx Layout, LayoutError<'tcx>> {
+ ) -> Result<Layout<'tcx>, LayoutError<'tcx>> {
use SavedLocalEligibility::*;
let tcx = self.tcx;
let subst_field = |ty: Ty<'tcx>| ty.subst(tcx, substs);
value: Primitive::Int(discr_int, false),
valid_range: WrappingRange { start: 0, end: max_discr },
};
- let tag_layout = self.tcx.intern_layout(Layout::scalar(self, tag));
+ let tag_layout = self.tcx.intern_layout(LayoutS::scalar(self, tag));
let tag_layout = TyAndLayout { ty: discr_int_ty, layout: tag_layout };
let promoted_layouts = ineligible_locals
size = size.max(variant.size);
align = align.max(variant.align);
- Ok(variant)
+ Ok(tcx.intern_layout(variant))
})
.collect::<Result<IndexVec<VariantIdx, _>, _>>()?;
size = size.align_to(align.abi);
- let abi = if prefix.abi.is_uninhabited() || variants.iter().all(|v| v.abi.is_uninhabited())
- {
- Abi::Uninhabited
- } else {
- Abi::Aggregate { sized: true }
- };
+ let abi =
+ if prefix.abi.is_uninhabited() || variants.iter().all(|v| v.abi().is_uninhabited()) {
+ Abi::Uninhabited
+ } else {
+ Abi::Aggregate { sized: true }
+ };
- let layout = tcx.intern_layout(Layout {
+ let layout = tcx.intern_layout(LayoutS {
variants: Variants::Multiple {
tag,
tag_encoding: TagEncoding::Direct,
ty::Adt(def, _) => def.variants[variant_index].fields.len(),
_ => bug!(),
};
- tcx.intern_layout(Layout {
+ tcx.intern_layout(LayoutS {
variants: Variants::Single { index: variant_index },
fields: match NonZeroUsize::new(fields) {
Some(fields) => FieldsShape::Union(fields),
})
}
- Variants::Multiple { ref variants, .. } => &variants[variant_index],
+ Variants::Multiple { ref variants, .. } => variants[variant_index],
};
- assert_eq!(layout.variants, Variants::Single { index: variant_index });
+ assert_eq!(*layout.variants(), Variants::Single { index: variant_index });
TyAndLayout { ty: this.ty, layout }
}
) -> TyMaybeWithLayout<'tcx> {
let tcx = cx.tcx();
let tag_layout = |tag: Scalar| -> TyAndLayout<'tcx> {
- let layout = Layout::scalar(cx, tag);
- TyAndLayout { layout: tcx.intern_layout(layout), ty: tag.value.to_ty(tcx) }
+ TyAndLayout {
+ layout: tcx.intern_layout(LayoutS::scalar(cx, tag)),
+ ty: tag.value.to_ty(tcx),
+ }
};
match *this.ty.kind() {
_ => return,
}
- // Pass and return structures up to 2 pointers in size by value, matching `ScalarPair`.
- // LLVM will usually pass these in 2 registers, which is more efficient than by-ref.
- let max_by_val_size = Pointer.size(self) * 2;
let size = arg.layout.size;
-
- if arg.layout.is_unsized() || size > max_by_val_size {
+ if arg.layout.is_unsized() || size > Pointer.size(self) {
arg.make_indirect();
} else {
// We want to pass small aggregates as immediates, but using
Some(GlobalAlloc::Memory(alloc)) => {
let len = int.assert_bits(self.tcx().data_layout.pointer_size);
let range = AllocRange { start: offset, size: Size::from_bytes(len) };
- if let Ok(byte_str) = alloc.get_bytes(&self.tcx(), range) {
+ if let Ok(byte_str) = alloc.inner().get_bytes(&self.tcx(), range) {
p!(pretty_print_byte_str(byte_str))
} else {
p!("<too short allocation>")
// The `inspect` here is okay since we checked the bounds, and there are
// no relocations (we have an active slice reference here). We don't use
// this result to affect interpreter execution.
- let byte_str = data.inspect_with_uninit_and_ptr_outside_interpreter(start..end);
+ let byte_str =
+ data.inner().inspect_with_uninit_and_ptr_outside_interpreter(start..end);
self.pretty_print_byte_str(byte_str)
}
(
// The `inspect` here is okay since we checked the bounds, and there are no
// relocations (we have an active `str` reference here). We don't use this
// result to affect interpreter execution.
- let slice = data.inspect_with_uninit_and_ptr_outside_interpreter(start..end);
+ let slice =
+ data.inner().inspect_with_uninit_and_ptr_outside_interpreter(start..end);
p!(write("{:?}", String::from_utf8_lossy(slice)));
Ok(self)
}
// cast is ok because we already checked for pointer size (32 or 64 bit) above
let range = AllocRange { start: offset, size: Size::from_bytes(n) };
- let byte_str = alloc.get_bytes(&self.tcx(), range).unwrap();
+ let byte_str = alloc.inner().get_bytes(&self.tcx(), range).unwrap();
p!("*");
p!(pretty_print_byte_str(byte_str));
Ok(self)
substs: SubstsRef<'tcx>,
) -> ty::TraitRef<'tcx> {
let defs = tcx.generics_of(trait_id);
-
ty::TraitRef { def_id: trait_id, substs: tcx.intern_substs(&substs[..defs.params.len()]) }
}
}
use crate::traits::specialization_graph;
-use crate::ty::fast_reject::{self, SimplifiedType, SimplifyParams};
+use crate::ty::fast_reject::{self, SimplifiedType, TreatParams};
use crate::ty::fold::TypeFoldable;
use crate::ty::{Ident, Ty, TyCtxt};
use rustc_hir as hir;
self_ty: Ty<'tcx>,
) -> impl Iterator<Item = DefId> + 'tcx {
let impls = self.trait_impls_of(def_id);
- if let Some(simp) = fast_reject::simplify_type(self, self_ty, SimplifyParams::No) {
+ if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsPlaceholders) {
if let Some(impls) = impls.non_blanket_impls.get(&simp) {
return impls.iter().copied();
}
}
}
- // Note that we're using `SimplifyParams::Yes` to query `non_blanket_impls` while using
- // `SimplifyParams::No` while actually adding them.
+ // Note that we're using `TreatParams::AsBoundTypes` to query `non_blanket_impls` while using
+ // `TreatParams::AsPlaceholders` while actually adding them.
//
// This way, when searching for some impl for `T: Trait`, we do not look at any impls
// whose outer level is not a parameter or projection. Especially for things like
// `T: Clone` this is incredibly useful as we would otherwise look at all the impls
// of `Clone` for `Option<T>`, `Vec<T>`, `ConcreteType` and so on.
- if let Some(simp) = fast_reject::simplify_type(self, self_ty, SimplifyParams::Yes) {
+ if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsBoundTypes) {
if let Some(impls) = impls.non_blanket_impls.get(&simp) {
for &impl_def_id in impls {
if let result @ Some(_) = f(impl_def_id) {
}
if let Some(simplified_self_ty) =
- fast_reject::simplify_type(tcx, impl_self_ty, SimplifyParams::No)
+ fast_reject::simplify_type(tcx, impl_self_ty, TreatParams::AsPlaceholders)
{
impls.non_blanket_impls.entry(simplified_self_ty).or_default().push(impl_def_id);
} else {
//! See docs in build/expr/mod.rs
use crate::build::Builder;
+use rustc_middle::mir::interpret::{ConstValue, Scalar};
use rustc_middle::mir::*;
use rustc_middle::thir::*;
use rustc_middle::ty::CanonicalUserTypeAnnotation;
assert_eq!(literal.ty(), ty);
Constant { span, user_ty, literal: literal.into() }
}
- ExprKind::StaticRef { literal, .. } => {
- Constant { span, user_ty: None, literal: literal.into() }
+ ExprKind::StaticRef { alloc_id, ty, .. } => {
+ let const_val =
+ ConstValue::Scalar(Scalar::from_pointer(alloc_id.into(), &this.tcx));
+ let literal = ConstantKind::Val(const_val, ty);
+
+ Constant { span, user_ty: None, literal }
}
ExprKind::ConstBlock { value } => {
Constant { span: span, user_ty: None, literal: value.into() }
use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
use rustc_middle::middle::region;
-use rustc_middle::mir::interpret::Scalar;
use rustc_middle::mir::{BinOp, BorrowKind, Field, UnOp};
use rustc_middle::thir::*;
use rustc_middle::ty::adjustment::{
let kind = if self.tcx.is_thread_local_static(id) {
ExprKind::ThreadLocalRef(id)
} else {
- let ptr = self.tcx.create_static_alloc(id);
- ExprKind::StaticRef {
- literal: ty::Const::from_scalar(
- self.tcx,
- Scalar::from_pointer(ptr.into(), &self.tcx),
- ty,
- ),
- def_id: id,
- }
+ let alloc_id = self.tcx.create_static_alloc(id);
+ ExprKind::StaticRef { alloc_id, ty, def_id: id }
};
ExprKind::Deref {
arg: self.thir.exprs.push(Expr { ty, temp_lifetime, span: expr.span, kind }),
};
use rustc_session::Session;
use rustc_span::source_map::Spanned;
-use rustc_span::{DesugaringKind, ExpnKind, Span};
+use rustc_span::{DesugaringKind, ExpnKind, MultiSpan, Span};
crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) {
let body_id = match def_id.as_local() {
fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
intravisit::walk_expr(self, ex);
match &ex.kind {
- hir::ExprKind::Match(scrut, arms, source) => self.check_match(scrut, arms, *source),
+ hir::ExprKind::Match(scrut, arms, source) => {
+ self.check_match(scrut, arms, *source, ex.span)
+ }
hir::ExprKind::Let(hir::Let { pat, init, span, .. }) => {
self.check_let(pat, init, *span)
}
scrut: &hir::Expr<'_>,
hir_arms: &'tcx [hir::Arm<'tcx>],
source: hir::MatchSource,
+ expr_span: Span,
) {
let mut cx = self.new_cx(scrut.hir_id);
}
// Check if the match is exhaustive.
- let is_empty_match = arms.is_empty();
let witnesses = report.non_exhaustiveness_witnesses;
if !witnesses.is_empty() {
if source == hir::MatchSource::ForLoopDesugar && hir_arms.len() == 2 {
let pat = hir_arms[1].pat.for_loop_some().unwrap();
self.check_irrefutable(pat, "`for` loop binding", None);
} else {
- non_exhaustive_match(&cx, scrut_ty, scrut.span, witnesses, is_empty_match);
+ non_exhaustive_match(&cx, scrut_ty, scrut.span, witnesses, hir_arms, expr_span);
}
}
}
let ty_path = cx.tcx.def_path_str(edef.did);
let mut err = lint.build(&format!(
"pattern binding `{}` is named the same as one \
- of the variants of the type `{}`",
+ of the variants of the type `{}`",
ident, ty_path
));
err.code(error_code!(E0170));
scrut_ty: Ty<'tcx>,
sp: Span,
witnesses: Vec<DeconstructedPat<'p, 'tcx>>,
- is_empty_match: bool,
+ arms: &[hir::Arm<'tcx>],
+ expr_span: Span,
) {
+ let is_empty_match = arms.is_empty();
let non_empty_enum = match scrut_ty.kind() {
ty::Adt(def, _) => def.is_enum() && !def.variants.is_empty(),
_ => false,
// In the case of an empty match, replace the '`_` not covered' diagnostic with something more
// informative.
let mut err;
+ let pattern;
+ let mut patterns_len = 0;
if is_empty_match && !non_empty_enum {
err = create_e0004(
cx.tcx.sess,
sp,
format!("non-exhaustive patterns: type `{}` is non-empty", scrut_ty),
);
+ pattern = "_".to_string();
} else {
let joined_patterns = joined_uncovered_patterns(cx, &witnesses);
err = create_e0004(
format!("non-exhaustive patterns: {} not covered", joined_patterns),
);
err.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns));
+ patterns_len = witnesses.len();
+ pattern = if witnesses.len() < 4 {
+ witnesses
+ .iter()
+ .map(|witness| witness.to_pat(cx).to_string())
+ .collect::<Vec<String>>()
+ .join(" | ")
+ } else {
+ "_".to_string()
+ };
};
let is_variant_list_non_exhaustive = match scrut_ty.kind() {
};
adt_defined_here(cx, &mut err, scrut_ty, &witnesses);
- err.help(
- "ensure that all possible cases are being handled, \
- possibly by adding wildcards or more match arms",
- );
err.note(&format!(
"the matched value is of type `{}`{}",
scrut_ty,
&& matches!(witnesses[0].ctor(), Constructor::NonExhaustive)
{
err.note(&format!(
- "`{}` does not have a fixed maximum value, \
- so a wildcard `_` is necessary to match exhaustively",
+ "`{}` does not have a fixed maximum value, so a wildcard `_` is necessary to match \
+ exhaustively",
scrut_ty,
));
if cx.tcx.sess.is_nightly_build() {
err.help(&format!(
- "add `#![feature(precise_pointer_size_matching)]` \
- to the crate attributes to enable precise `{}` matching",
+ "add `#![feature(precise_pointer_size_matching)]` to the crate attributes to \
+ enable precise `{}` matching",
scrut_ty,
));
}
err.note("references are always considered inhabited");
}
}
+
+ let mut suggestion = None;
+ let sm = cx.tcx.sess.source_map();
+ match arms {
+ [] if sp.ctxt() == expr_span.ctxt() => {
+ // Get the span for the empty match body `{}`.
+ let (indentation, more) = if let Some(snippet) = sm.indentation_before(sp) {
+ (format!("\n{}", snippet), " ")
+ } else {
+ (" ".to_string(), "")
+ };
+ suggestion = Some((
+ sp.shrink_to_hi().with_hi(expr_span.hi()),
+ format!(
+ " {{{indentation}{more}{pattern} => todo!(),{indentation}}}",
+ indentation = indentation,
+ more = more,
+ pattern = pattern,
+ ),
+ ));
+ }
+ [only] => {
+ let pre_indentation = if let (Some(snippet), true) = (
+ sm.indentation_before(only.span),
+ sm.is_multiline(sp.shrink_to_hi().with_hi(only.span.lo())),
+ ) {
+ format!("\n{}", snippet)
+ } else {
+ " ".to_string()
+ };
+ let comma = if matches!(only.body.kind, hir::ExprKind::Block(..)) { "" } else { "," };
+ suggestion = Some((
+ only.span.shrink_to_hi(),
+ format!("{}{}{} => todo!()", comma, pre_indentation, pattern),
+ ));
+ }
+ [.., prev, last] if prev.span.ctxt() == last.span.ctxt() => {
+ if let Ok(snippet) = sm.span_to_snippet(prev.span.between(last.span)) {
+ let comma =
+ if matches!(last.body.kind, hir::ExprKind::Block(..)) { "" } else { "," };
+ suggestion = Some((
+ last.span.shrink_to_hi(),
+ format!(
+ "{}{}{} => todo!()",
+ comma,
+ snippet.strip_prefix(",").unwrap_or(&snippet),
+ pattern
+ ),
+ ));
+ }
+ }
+ _ => {}
+ }
+
+ let msg = format!(
+ "ensure that all possible cases are being handled by adding a match arm with a wildcard \
+ pattern{}{}",
+ if patterns_len > 1 && patterns_len < 4 && suggestion.is_some() {
+ ", a match arm with multiple or-patterns"
+ } else {
+ // we are either not suggesting anything, or suggesting `_`
+ ""
+ },
+ match patterns_len {
+ // non-exhaustive enum case
+ 0 if suggestion.is_some() => " as shown",
+ 0 => "",
+ 1 if suggestion.is_some() => " or an explicit pattern as shown",
+ 1 => " or an explicit pattern",
+ _ if suggestion.is_some() => " as shown, or multiple match arms",
+ _ => " or multiple match arms",
+ },
+ );
+ if let Some((span, sugg)) = suggestion {
+ err.span_suggestion_verbose(span, &msg, sugg, Applicability::HasPlaceholders);
+ } else {
+ err.help(&msg);
+ }
err.emit();
}
) {
let ty = ty.peel_refs();
if let ty::Adt(def, _) = ty.kind() {
- if let Some(sp) = cx.tcx.hir().span_if_local(def.did) {
- err.span_label(sp, format!("`{}` defined here", ty));
- }
-
- if witnesses.len() < 4 {
+ let mut spans = vec![];
+ if witnesses.len() < 5 {
for sp in maybe_point_at_variant(cx, def, witnesses.iter()) {
- err.span_label(sp, "not covered");
+ spans.push(sp);
}
}
+ let def_span = cx
+ .tcx
+ .hir()
+ .get_if_local(def.did)
+ .and_then(|node| node.ident())
+ .map(|ident| ident.span)
+ .unwrap_or_else(|| cx.tcx.def_span(def.did));
+ let mut span: MultiSpan =
+ if spans.is_empty() { def_span.into() } else { spans.clone().into() };
+
+ span.push_span_label(def_span, String::new());
+ for pat in spans {
+ span.push_span_label(pat, "not covered".to_string());
+ }
+ err.span_note(span, &format!("`{}` defined here", ty));
}
}
doctest = false
[dependencies]
-itertools = "0.10"
+itertools = "0.10.1"
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
tracing = "0.1"
rustc_ast = { path = "../rustc_ast" }
use crate::MirPass;
use rustc_const_eval::const_eval::ConstEvalErr;
use rustc_const_eval::interpret::{
- self, compile_time_machine, AllocId, Allocation, ConstValue, CtfeValidationMode, Frame, ImmTy,
- Immediate, InterpCx, InterpResult, LocalState, LocalValue, MemPlace, MemoryKind, OpTy,
+ self, compile_time_machine, AllocId, ConstAllocation, ConstValue, CtfeValidationMode, Frame,
+ ImmTy, Immediate, InterpCx, InterpResult, LocalState, LocalValue, MemPlace, MemoryKind, OpTy,
Operand as InterpOperand, PlaceTy, Scalar, ScalarMaybeUninit, StackPopCleanup, StackPopUnwind,
};
fn before_access_global(
_memory_extra: &(),
_alloc_id: AllocId,
- allocation: &Allocation<Self::PointerTag, Self::AllocExtra>,
+ alloc: ConstAllocation<'tcx, Self::PointerTag, Self::AllocExtra>,
_static_def_id: Option<DefId>,
is_write: bool,
) -> InterpResult<'tcx> {
}
// If the static allocation is mutable, then we can't const prop it as its content
// might be different at runtime.
- if allocation.mutability == Mutability::Mut {
+ if alloc.inner().mutability == Mutability::Mut {
throw_machine_stop_str!("can't access mutable globals in ConstProp");
}
Variants::Multiple { variants, .. } => variants
.iter_enumerated()
.filter_map(|(idx, layout)| {
- (layout.abi != Abi::Uninhabited)
+ (layout.abi() != Abi::Uninhabited)
.then(|| ty.discriminant_for_variant(tcx, idx).unwrap().val)
})
.collect(),
recursion_depth_reset = None;
if let Ok(alloc) = tcx.eval_static_initializer(def_id) {
- for &id in alloc.relocations().values() {
+ for &id in alloc.inner().relocations().values() {
collect_miri(tcx, id, &mut neighbors);
}
}
}
GlobalAlloc::Memory(alloc) => {
trace!("collecting {:?} with {:#?}", alloc_id, alloc);
- for &inner in alloc.relocations().values() {
+ for &inner in alloc.inner().relocations().values() {
rustc_data_structures::stack::ensure_sufficient_stack(|| {
collect_miri(tcx, inner, output);
});
match value {
ConstValue::Scalar(Scalar::Ptr(ptr, _size)) => collect_miri(tcx, ptr.provenance, output),
ConstValue::Slice { data: alloc, start: _, end: _ } | ConstValue::ByRef { alloc, .. } => {
- for &id in alloc.relocations().values() {
+ for &id in alloc.inner().relocations().values() {
collect_miri(tcx, id, output);
}
}
use super::pat::Expected;
-use super::ty::{AllowPlus, IsAsCast};
+use super::ty::{AllowPlus, RecoverQuestionMark};
use super::{
BlockMode, CommaRecoveryMode, Parser, PathStyle, RecoverColon, RecoverComma, Restrictions,
SemiColonMode, SeqSep, TokenExpectType, TokenType,
pub(super) fn maybe_recover_from_question_mark(
&mut self,
ty: P<Ty>,
- is_as_cast: IsAsCast,
+ recover_question_mark: RecoverQuestionMark,
) -> P<Ty> {
- if let IsAsCast::Yes = is_as_cast {
+ if let RecoverQuestionMark::No = recover_question_mark {
return ty;
}
if self.token == token::Question {
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, PResult};
use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP;
use rustc_session::lint::BuiltinLintDiagnostics;
-use rustc_span::edition::LATEST_STABLE_EDITION;
use rustc_span::source_map::{self, Span, Spanned};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{BytePos, Pos};
let mut async_block_err = |e: &mut Diagnostic, span: Span| {
recover_async = true;
e.span_label(span, "`async` blocks are only allowed in Rust 2018 or later");
- e.help(&format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION));
- e.note("for more on editions, read https://doc.rust-lang.org/edition-guide");
+ e.help_use_latest_edition();
};
while self.token != token::CloseDelim(close_delim) {
use rustc_ast::{FnHeader, ForeignItem, Path, PathSegment, Visibility, VisibilityKind};
use rustc_ast::{MacArgs, MacCall, MacDelimiter};
use rustc_ast_pretty::pprust;
-use rustc_errors::{struct_span_err, Applicability, ErrorGuaranteed, PResult, StashKey};
-use rustc_span::edition::{Edition, LATEST_STABLE_EDITION};
+use rustc_errors::{struct_span_err, Applicability, PResult, StashKey};
+use rustc_span::edition::Edition;
use rustc_span::lev_distance::lev_distance;
use rustc_span::source_map::{self, Span};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
+use rustc_span::DUMMY_SP;
use std::convert::TryFrom;
use std::mem;
if end.is_doc_comment() {
err.span_label(end.span, "this doc comment doesn't document anything");
}
+ if end.meta_kind().is_some() {
+ if self.token.kind == TokenKind::Semi {
+ err.span_suggestion_verbose(
+ self.token.span,
+ "consider removing this semicolon",
+ String::new(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
if let [.., penultimate, _] = attrs {
err.span_label(start.span.to(penultimate.span), "other attributes here");
}
))
}
- /// Emits an error that the where clause at the end of a type alias is not
- /// allowed and suggests moving it.
- fn error_ty_alias_where(
- &self,
- before_where_clause_present: bool,
- before_where_clause_span: Span,
- after_predicates: &[WherePredicate],
- after_where_clause_span: Span,
- ) -> ErrorGuaranteed {
- let mut err =
- self.struct_span_err(after_where_clause_span, "where clause not allowed here");
- if !after_predicates.is_empty() {
- let mut state = crate::pprust::State::new();
- if !before_where_clause_present {
- state.space();
- state.word_space("where");
- } else {
- state.word_space(",");
- }
- let mut first = true;
- for p in after_predicates.iter() {
- if !first {
- state.word_space(",");
- }
- first = false;
- state.print_where_predicate(p);
- }
- let suggestion = state.s.eof();
- err.span_suggestion(
- before_where_clause_span.shrink_to_hi(),
- "move it here",
- suggestion,
- Applicability::MachineApplicable,
- );
- }
- err.emit()
- }
-
/// Parses a `type` alias with the following grammar:
/// ```
/// TypeAlias = "type" Ident Generics {":" GenericBounds}? {"=" Ty}? ";" ;
// Parse optional colon and param bounds.
let bounds =
if self.eat(&token::Colon) { self.parse_generic_bounds(None)? } else { Vec::new() };
-
- generics.where_clause = self.parse_where_clause()?;
+ let before_where_clause = self.parse_where_clause()?;
let ty = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None };
- if self.token.is_keyword(kw::Where) {
- let after_where_clause = self.parse_where_clause()?;
+ let after_where_clause = self.parse_where_clause()?;
- self.error_ty_alias_where(
- generics.where_clause.has_where_token,
- generics.where_clause.span,
- &after_where_clause.predicates,
- after_where_clause.span,
- );
-
- generics.where_clause.predicates.extend(after_where_clause.predicates.into_iter());
- }
+ let where_clauses = (
+ TyAliasWhereClause(before_where_clause.has_where_token, before_where_clause.span),
+ TyAliasWhereClause(after_where_clause.has_where_token, after_where_clause.span),
+ );
+ let where_predicates_split = before_where_clause.predicates.len();
+ let mut predicates = before_where_clause.predicates;
+ predicates.extend(after_where_clause.predicates.into_iter());
+ let where_clause = WhereClause {
+ has_where_token: before_where_clause.has_where_token
+ || after_where_clause.has_where_token,
+ predicates,
+ span: DUMMY_SP,
+ };
+ generics.where_clause = where_clause;
self.expect_semi()?;
- Ok((ident, ItemKind::TyAlias(Box::new(TyAlias { defaultness, generics, bounds, ty }))))
+ Ok((
+ ident,
+ ItemKind::TyAlias(Box::new(TyAlias {
+ defaultness,
+ generics,
+ where_clauses,
+ where_predicates_split,
+ bounds,
+ ty,
+ })),
+ ))
}
/// Parses a `UseTree`.
let diag = self.diagnostic();
struct_span_err!(diag, span, E0670, "`async fn` is not permitted in Rust 2015")
.span_label(span, "to use `async fn`, switch to Rust 2018 or later")
- .help(&format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION))
- .note("for more on editions, read https://doc.rust-lang.org/edition-guide")
+ .help_use_latest_edition()
.emit();
}
}
}
NonterminalKind::Ty => {
- token::NtTy(self.collect_tokens_no_attrs(|this| this.parse_ty())?)
+ token::NtTy(self.collect_tokens_no_attrs(|this| this.parse_no_question_mark_recover())?)
}
// this could be handled like a token, since it is one
NonterminalKind::Ident
No,
}
-pub(super) enum IsAsCast {
+pub(super) enum RecoverQuestionMark {
Yes,
No,
}
RecoverQPath::Yes,
RecoverReturnSign::Yes,
None,
- IsAsCast::No,
+ RecoverQuestionMark::Yes,
)
}
RecoverQPath::Yes,
RecoverReturnSign::Yes,
Some(ty_params),
- IsAsCast::No,
+ RecoverQuestionMark::Yes,
)
}
RecoverQPath::Yes,
RecoverReturnSign::Yes,
None,
- IsAsCast::No,
+ RecoverQuestionMark::Yes,
)
}
RecoverQPath::Yes,
RecoverReturnSign::Yes,
None,
- IsAsCast::No,
+ RecoverQuestionMark::Yes,
)
}
RecoverQPath::Yes,
RecoverReturnSign::Yes,
None,
- IsAsCast::Yes,
+ RecoverQuestionMark::No,
)
}
+
+ pub(super) fn parse_no_question_mark_recover(&mut self) -> PResult<'a, P<Ty>> {
+ self.parse_ty_common(
+ AllowPlus::Yes,
+ AllowCVariadic::No,
+ RecoverQPath::Yes,
+ RecoverReturnSign::Yes,
+ None,
+ RecoverQuestionMark::No,
+ )
+ }
+
/// Parse a type without recovering `:` as `->` to avoid breaking code such as `where fn() : for<'a>`
pub(super) fn parse_ty_for_where_clause(&mut self) -> PResult<'a, P<Ty>> {
self.parse_ty_common(
RecoverQPath::Yes,
RecoverReturnSign::OnlyFatArrow,
None,
- IsAsCast::No,
+ RecoverQuestionMark::Yes,
)
}
recover_qpath,
recover_return_sign,
None,
- IsAsCast::No,
+ RecoverQuestionMark::Yes,
)?;
FnRetTy::Ty(ty)
} else if recover_return_sign.can_recover(&self.token.kind) {
recover_qpath,
recover_return_sign,
None,
- IsAsCast::No,
+ RecoverQuestionMark::Yes,
)?;
FnRetTy::Ty(ty)
} else {
recover_qpath: RecoverQPath,
recover_return_sign: RecoverReturnSign,
ty_generics: Option<&Generics>,
- is_as_cast: IsAsCast,
+ recover_question_mark: RecoverQuestionMark,
) -> PResult<'a, P<Ty>> {
let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes;
maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery);
// Try to recover from use of `+` with incorrect priority.
self.maybe_report_ambiguous_plus(allow_plus, impl_dyn_multi, &ty);
self.maybe_recover_from_bad_type_plus(allow_plus, &ty)?;
- let ty = self.maybe_recover_from_question_mark(ty, is_as_cast);
+ let ty = self.maybe_recover_from_question_mark(ty, recover_question_mark);
self.maybe_recover_from_bad_qpath(ty, allow_qpath_recovery)
}
//! conflicts between multiple such attributes attached to the same
//! item.
-use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, NestedMetaItem};
+use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{pluralize, struct_span_err, Applicability};
use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
check_duplicates(self.tcx, attr, hir_id, *duplicates, &mut seen);
}
- // Warn on useless empty attributes.
- if matches!(
- attr.name_or_empty(),
- sym::macro_use
- | sym::allow
- | sym::warn
- | sym::deny
- | sym::forbid
- | sym::feature
- | sym::repr
- | sym::target_feature
- ) && attr.meta_item_list().map_or(false, |list| list.is_empty())
- {
- self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
- lint.build("unused attribute")
- .span_suggestion(
- attr.span,
- "remove this attribute",
- String::new(),
- Applicability::MachineApplicable,
- )
- .note(&format!(
- "attribute `{}` with an empty list has no effect",
- attr.name_or_empty()
- ))
- .emit();
- });
- }
+ self.check_unused_attribute(hir_id, attr)
}
if !is_valid {
target: Target,
item: Option<ItemLike<'_>>,
) -> bool {
- let is_function = matches!(target, Target::Fn | Target::Method(..));
+ let is_function = matches!(target, Target::Fn);
if !is_function {
self.tcx
.sess
});
}
}
+
+ fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute) {
+ // Warn on useless empty attributes.
+ let note = if matches!(
+ attr.name_or_empty(),
+ sym::macro_use
+ | sym::allow
+ | sym::expect
+ | sym::warn
+ | sym::deny
+ | sym::forbid
+ | sym::feature
+ | sym::repr
+ | sym::target_feature
+ ) && attr.meta_item_list().map_or(false, |list| list.is_empty())
+ {
+ format!(
+ "attribute `{}` with an empty list has no effect",
+ attr.name_or_empty()
+ )
+ } else if matches!(
+ attr.name_or_empty(),
+ sym::allow | sym::warn | sym::deny | sym::forbid | sym::expect
+ ) && let Some(meta) = attr.meta_item_list()
+ && meta.len() == 1
+ && let Some(item) = meta[0].meta_item()
+ && let MetaItemKind::NameValue(_) = &item.kind
+ && item.path == sym::reason
+ {
+ format!(
+ "attribute `{}` without any lints has no effect",
+ attr.name_or_empty()
+ )
+ } else {
+ return;
+ };
+
+ self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
+ lint.build("unused attribute")
+ .span_suggestion(
+ attr.span,
+ "remove this attribute",
+ String::new(),
+ Applicability::MachineApplicable,
+ )
+ .note(¬e)
+ .emit();
+ });
+ }
}
impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
// The file may be empty, which leads to the diagnostic machinery not emitting this
// note. This is a relatively simple way to detect that case and emit a span-less
// note instead.
- if tcx.sess.source_map().lookup_line(sp.lo()).is_ok() {
- err.set_span(sp);
- err.span_label(sp, ¬e);
+ if tcx.sess.source_map().lookup_line(sp.hi()).is_ok() {
+ err.set_span(sp.shrink_to_hi());
+ err.span_label(sp.shrink_to_hi(), ¬e);
} else {
err.note(¬e);
}
//! A pass that annotates every item and method with its stability level,
//! propagating default levels lexically from parent to children ast nodes.
-use rustc_ast::Attribute;
use rustc_attr::{self as attr, ConstStability, Stability};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX};
use rustc_hir::hir_id::CRATE_HIR_ID;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{FieldDef, Generics, HirId, Item, TraitRef, Ty, TyKind, Variant};
{
let attrs = self.tcx.get_attrs(def_id.to_def_id());
debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs);
- let mut did_error = false;
- if !self.tcx.features().staged_api {
- did_error = self.forbid_staged_api_attrs(def_id, attrs, inherit_deprecation.clone());
- }
- let depr = if did_error { None } else { attr::find_deprecation(&self.tcx.sess, attrs) };
+ let depr = attr::find_deprecation(&self.tcx.sess, attrs);
let mut is_deprecated = false;
if let Some((depr, span)) = &depr {
is_deprecated = true;
}
}
- if self.tcx.features().staged_api {
- if let Some(a) = attrs.iter().find(|a| a.has_name(sym::deprecated)) {
- self.tcx
- .sess
- .struct_span_err(a.span, "`#[deprecated]` cannot be used in staged API")
- .span_label(a.span, "use `#[rustc_deprecated]` instead")
- .span_label(item_sp, "")
- .emit();
+ if !self.tcx.features().staged_api {
+ // Propagate unstability. This can happen even for non-staged-api crates in case
+ // -Zforce-unstable-if-unmarked is set.
+ if let Some(stab) = self.parent_stab {
+ if inherit_deprecation.yes() && stab.level.is_unstable() {
+ self.index.stab_map.insert(def_id, stab);
+ }
}
- } else {
+
self.recurse_with_stability_attrs(
depr.map(|(d, _)| DeprecationEntry::local(d, def_id)),
None,
self.parent_const_stab = orig_parent_const_stab;
}
}
-
- // returns true if an error occurred, used to suppress some spurious errors
- fn forbid_staged_api_attrs(
- &mut self,
- def_id: LocalDefId,
- attrs: &[Attribute],
- inherit_deprecation: InheritDeprecation,
- ) -> bool {
- // Emit errors for non-staged-api crates.
- let unstable_attrs = [
- sym::unstable,
- sym::stable,
- sym::rustc_deprecated,
- sym::rustc_const_unstable,
- sym::rustc_const_stable,
- ];
- let mut has_error = false;
- for attr in attrs {
- let name = attr.name_or_empty();
- if unstable_attrs.contains(&name) {
- struct_span_err!(
- self.tcx.sess,
- attr.span,
- E0734,
- "stability attributes may not be used outside of the standard library",
- )
- .emit();
- has_error = true;
- }
- }
-
- // Propagate unstability. This can happen even for non-staged-api crates in case
- // -Zforce-unstable-if-unmarked is set.
- if let Some(stab) = self.parent_stab {
- if inherit_deprecation.yes() && stab.level.is_unstable() {
- self.index.stab_map.insert(def_id, stab);
- }
- }
-
- has_error
- }
}
impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
}
fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
- let is_staged_api =
- tcx.sess.opts.debugging_opts.force_unstable_if_unmarked || tcx.features().staged_api;
- let mut staged_api = FxHashMap::default();
- staged_api.insert(LOCAL_CRATE, is_staged_api);
let mut index = Index {
- staged_api,
stab_map: Default::default(),
const_stab_map: Default::default(),
depr_map: Default::default(),
- active_features: Default::default(),
};
- let active_lib_features = &tcx.features().declared_lib_features;
- let active_lang_features = &tcx.features().declared_lang_features;
-
- // Put the active features into a map for quick lookup.
- index.active_features = active_lib_features
- .iter()
- .map(|&(s, ..)| s)
- .chain(active_lang_features.iter().map(|&(s, ..)| s))
- .collect();
-
{
let mut annotator = Annotator {
tcx,
}
pub(crate) fn provide(providers: &mut Providers) {
- *providers = Providers { check_mod_unstable_api_usage, stability_index, ..*providers };
+ *providers = Providers {
+ check_mod_unstable_api_usage,
+ stability_index,
+ lookup_stability: |tcx, id| tcx.stability().local_stability(id.expect_local()),
+ lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id.expect_local()),
+ lookup_deprecation_entry: |tcx, id| {
+ tcx.stability().local_deprecation_entry(id.expect_local())
+ },
+ ..*providers
+ };
}
struct Checker<'tcx> {
/// were expected to be library features), and the list of features used from
/// libraries, identify activated features that don't exist and error about them.
pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
- let access_levels = &tcx.privacy_access_levels(());
-
- if tcx.stability().staged_api[&LOCAL_CRATE] {
+ let is_staged_api =
+ tcx.sess.opts.debugging_opts.force_unstable_if_unmarked || tcx.features().staged_api;
+ if is_staged_api {
+ let access_levels = &tcx.privacy_access_levels(());
let mut missing = MissingStabilityAnnotations { tcx, access_levels };
missing.check_missing_stability(CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID));
tcx.hir().walk_toplevel_module(&mut missing);
}
let declared_lib_features = &tcx.features().declared_lib_features;
- let mut remaining_lib_features = FxHashMap::default();
+ let mut remaining_lib_features = FxIndexMap::default();
for (feature, span) in declared_lib_features {
if !tcx.sess.opts.unstable_features.is_nightly_build() {
struct_span_err!(
remaining_lib_features.remove(&sym::libc);
remaining_lib_features.remove(&sym::test);
- let check_features = |remaining_lib_features: &mut FxHashMap<_, _>, defined_features: &[_]| {
+ let check_features = |remaining_lib_features: &mut FxIndexMap<_, _>, defined_features: &[_]| {
for &(feature, since) in defined_features {
if let Some(since) = since {
if let Some(span) = remaining_lib_features.get(&feature) {
self.visit(self.ev.tcx.type_of(param.def_id));
}
}
- GenericParamDefKind::Const { has_default, .. } => {
+ GenericParamDefKind::Const { has_default } => {
self.visit(self.ev.tcx.type_of(param.def_id));
if has_default {
self.visit(self.ev.tcx.const_param_default(param.def_id));
note: Vec::new(),
suggestion: None,
};
- errors.push((path, err));
+ if path.contains("::") {
+ errors.push((path, err))
+ }
}
}
}
}
}
- ImportKind::ExternCrate { source, target, .. } => {
+ ImportKind::ExternCrate { source, target } => {
suggestion = Some(format!(
"extern crate {} as {};",
source.unwrap_or(target.name),
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_span = { path = "../rustc_span" }
rustc_fs_util = { path = "../rustc_fs_util" }
-num_cpus = "1.0"
rustc_ast = { path = "../rustc_ast" }
rustc_lint_defs = { path = "../rustc_lint_defs" }
use rustc_target::abi::{Align, TargetDataLayout};
use rustc_target::spec::{LinkerFlavor, SplitDebuginfo, Target, TargetTriple, TargetWarnings};
+use rustc_target::spec::{PanicStrategy, SanitizerSet, TARGETS};
use rustc_serialize::json;
pub struct CheckCfg<T = String> {
/// The set of all `names()`, if None no name checking is performed
pub names_valid: Option<FxHashSet<T>>,
+ /// Is well known values activated
+ pub well_known_values: bool,
/// The set of all `values()`
pub values_valid: FxHashMap<T, FxHashSet<T>>,
}
impl<T> Default for CheckCfg<T> {
fn default() -> Self {
- CheckCfg { names_valid: Default::default(), values_valid: Default::default() }
+ CheckCfg {
+ names_valid: Default::default(),
+ values_valid: Default::default(),
+ well_known_values: false,
+ }
}
}
.iter()
.map(|(a, b)| (f(a), b.iter().map(|b| f(b)).collect()))
.collect(),
+ well_known_values: self.well_known_values,
}
}
}
impl CrateCheckConfig {
/// Fills a `CrateCheckConfig` with well-known configuration names.
- pub fn fill_well_known(&mut self) {
- // NOTE: This should be kept in sync with `default_configuration`
+ fn fill_well_known_names(&mut self) {
+ // NOTE: This should be kept in sync with `default_configuration` and
+ // `fill_well_known_values`
const WELL_KNOWN_NAMES: &[Symbol] = &[
sym::unix,
sym::windows,
sym::doctest,
sym::feature,
];
+
+ // We only insert well-known names if `names()` was activated
if let Some(names_valid) = &mut self.names_valid {
- for &name in WELL_KNOWN_NAMES {
- names_valid.insert(name);
- }
+ names_valid.extend(WELL_KNOWN_NAMES);
+ }
+ }
+
+ /// Fills a `CrateCheckConfig` with well-known configuration values.
+ fn fill_well_known_values(&mut self) {
+ if !self.well_known_values {
+ return;
}
+
+ // NOTE: This should be kept in sync with `default_configuration` and
+ // `fill_well_known_names`
+
+ let panic_values = &PanicStrategy::all();
+
+ let atomic_values = &[
+ sym::ptr,
+ sym::integer(8usize),
+ sym::integer(16usize),
+ sym::integer(32usize),
+ sym::integer(64usize),
+ sym::integer(128usize),
+ ];
+
+ let sanitize_values = SanitizerSet::all()
+ .into_iter()
+ .map(|sanitizer| Symbol::intern(sanitizer.as_str().unwrap()));
+
+ // No-values
+ for name in [
+ sym::unix,
+ sym::windows,
+ sym::debug_assertions,
+ sym::proc_macro,
+ sym::test,
+ sym::doc,
+ sym::doctest,
+ sym::target_thread_local,
+ ] {
+ self.values_valid.entry(name).or_default();
+ }
+
+ // Pre-defined values
+ self.values_valid.entry(sym::panic).or_default().extend(panic_values);
+ self.values_valid.entry(sym::sanitize).or_default().extend(sanitize_values);
+ self.values_valid.entry(sym::target_has_atomic).or_default().extend(atomic_values);
+ self.values_valid
+ .entry(sym::target_has_atomic_load_store)
+ .or_default()
+ .extend(atomic_values);
+ self.values_valid
+ .entry(sym::target_has_atomic_equal_alignment)
+ .or_default()
+ .extend(atomic_values);
+
+ // Target specific values
+ for target in
+ TARGETS.iter().map(|target| Target::expect_builtin(&TargetTriple::from_triple(target)))
+ {
+ self.values_valid
+ .entry(sym::target_os)
+ .or_default()
+ .insert(Symbol::intern(&target.options.os));
+ self.values_valid
+ .entry(sym::target_family)
+ .or_default()
+ .extend(target.options.families.iter().map(|family| Symbol::intern(family)));
+ self.values_valid
+ .entry(sym::target_arch)
+ .or_default()
+ .insert(Symbol::intern(&target.arch));
+ self.values_valid
+ .entry(sym::target_endian)
+ .or_default()
+ .insert(Symbol::intern(&target.options.endian.as_str()));
+ self.values_valid
+ .entry(sym::target_env)
+ .or_default()
+ .insert(Symbol::intern(&target.options.env));
+ self.values_valid
+ .entry(sym::target_abi)
+ .or_default()
+ .insert(Symbol::intern(&target.options.abi));
+ self.values_valid
+ .entry(sym::target_vendor)
+ .or_default()
+ .insert(Symbol::intern(&target.options.vendor));
+ self.values_valid
+ .entry(sym::target_pointer_width)
+ .or_default()
+ .insert(sym::integer(target.pointer_width));
+ }
+ }
+
+ pub fn fill_well_known(&mut self) {
+ self.fill_well_known_names();
+ self.fill_well_known_values();
}
/// Fills a `CrateCheckConfig` with configuration names and values that are actually active.
let first = match debugging_opts.unpretty.as_deref()? {
"normal" => Source(PpSourceMode::Normal),
"identified" => Source(PpSourceMode::Identified),
- "everybody_loops" => Source(PpSourceMode::EveryBodyLoops),
"expanded" => Source(PpSourceMode::Expanded),
"expanded,identified" => Source(PpSourceMode::ExpandedIdentified),
"expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene),
name => early_error(
efmt,
&format!(
- "argument to `unpretty` must be one of `normal`, \
- `expanded`, `identified`, `expanded,identified`, \
- `expanded,hygiene`, `everybody_loops`, \
+ "argument to `unpretty` must be one of `normal`, `identified`, \
+ `expanded`, `expanded,identified`, `expanded,hygiene`, \
`ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
- `hir,typed`, `hir-tree`, `mir` or `mir-cfg`; got {}",
+ `hir,typed`, `hir-tree`, `thir-tree`, `mir` or `mir-cfg`; got {}",
name
),
),
pub enum PpSourceMode {
/// `-Zunpretty=normal`
Normal,
- /// `-Zunpretty=everybody_loops`
- EveryBodyLoops,
/// `-Zunpretty=expanded`
Expanded,
/// `-Zunpretty=identified`
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum PpMode {
/// Options that print the source code, i.e.
- /// `-Zunpretty=normal` and `-Zunpretty=everybody_loops`
+ /// `-Zunpretty=normal` and `-Zunpretty=expanded`
Source(PpSourceMode),
AstTree(PpAstTreeMode),
/// Options that print the HIR, i.e. `-Zunpretty=hir`
match *self {
Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false,
- Source(Expanded | EveryBodyLoops | ExpandedIdentified | ExpandedHygiene)
+ Source(Expanded | ExpandedIdentified | ExpandedHygiene)
| AstTree(PpAstTreeMode::Expanded)
| Hir(_)
| HirTree
crate fn parse_threads(slot: &mut usize, v: Option<&str>) -> bool {
match v.and_then(|s| s.parse().ok()) {
Some(0) => {
- *slot = ::num_cpus::get();
+ *slot = std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get);
true
}
Some(i) => {
`normal`, `identified`,
`expanded`, `expanded,identified`,
`expanded,hygiene` (with internal representations),
- `everybody_loops` (all function bodies replaced with `loop {}`),
`ast-tree` (raw AST before expansion),
`ast-tree,expanded` (raw AST after expansion),
`hir` (the HIR), `hir,identified`,
pub fn struct_allow(&self, msg: &str) -> DiagnosticBuilder<'_, ()> {
self.diagnostic().struct_allow(msg)
}
+ pub fn struct_expect(
+ &self,
+ msg: &str,
+ id: lint::LintExpectationId,
+ ) -> DiagnosticBuilder<'_, ()> {
+ self.diagnostic().struct_expect(msg, id)
+ }
pub fn struct_span_err<S: Into<MultiSpan>>(
&self,
sp: S,
/// A unique ID associated with a macro invocation and expansion.
pub struct LocalExpnId {
ENCODABLE = custom
+ ORD_IMPL = custom
DEBUG_FORMAT = "expn{}"
}
}
+// To ensure correctness of incremental compilation,
+// `LocalExpnId` must not implement `Ord` or `PartialOrd`.
+// See https://github.com/rust-lang/rust/issues/90317.
+impl !Ord for LocalExpnId {}
+impl !PartialOrd for LocalExpnId {}
+
/// Assert that the provided `HashStableContext` is configured with the 'default'
/// `HashingControls`. We should always have bailed out before getting to here
/// with a non-default mode. With this check in place, we can avoid the need
custom_inner_attributes,
custom_test_frameworks,
d,
+ d32,
dbg_macro,
dead_code,
dealloc,
proc_macro_path_invoc,
profiler_builtins,
profiler_runtime,
+ ptr,
ptr_guaranteed_eq,
ptr_guaranteed_ne,
ptr_null,
// The `inspect` here is okay since we checked the bounds, and there are no
// relocations (we have an active `str` reference here). We don't use this
// result to affect interpreter execution.
- let slice =
- data.inspect_with_uninit_and_ptr_outside_interpreter(start..end);
+ let slice = data
+ .inner()
+ .inspect_with_uninit_and_ptr_outside_interpreter(start..end);
let s = std::str::from_utf8(slice).expect("non utf8 str from miri");
self.push("e");
use std::ops::{Add, AddAssign, Deref, Mul, RangeInclusive, Sub};
use std::str::FromStr;
+use rustc_data_structures::intern::Interned;
use rustc_index::vec::{Idx, IndexVec};
use rustc_macros::HashStable_Generic;
use rustc_serialize::json::{Json, ToJson};
}
#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
-pub enum Variants {
+pub enum Variants<'a> {
/// Single enum variants, structs/tuples, unions, and all non-ADTs.
Single { index: VariantIdx },
tag: Scalar,
tag_encoding: TagEncoding,
tag_field: usize,
- variants: IndexVec<VariantIdx, Layout>,
+ variants: IndexVec<VariantIdx, Layout<'a>>,
},
}
}
}
-#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
-pub struct Layout {
+#[derive(PartialEq, Eq, Hash, HashStable_Generic)]
+pub struct LayoutS<'a> {
/// Says where the fields are located within the layout.
pub fields: FieldsShape,
///
/// To access all fields of this layout, both `fields` and the fields of the active variant
/// must be taken into account.
- pub variants: Variants,
+ pub variants: Variants<'a>,
/// The `abi` defines how this data is passed between functions, and it defines
/// value restrictions via `valid_range`.
pub size: Size,
}
-impl Layout {
+impl<'a> LayoutS<'a> {
pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self {
let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar);
let size = scalar.value.size(cx);
let align = scalar.value.align(cx);
- Layout {
+ LayoutS {
variants: Variants::Single { index: VariantIdx::new(0) },
fields: FieldsShape::Primitive,
abi: Abi::Scalar(scalar),
}
}
+impl<'a> fmt::Debug for LayoutS<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // This is how `Layout` used to print before it become
+ // `Interned<LayoutS>`. We print it like this to avoid having to update
+ // expected output in a lot of tests.
+ f.debug_struct("Layout")
+ .field("fields", &self.fields)
+ .field("variants", &self.variants)
+ .field("abi", &self.abi)
+ .field("largest_niche", &self.largest_niche)
+ .field("align", &self.align)
+ .field("size", &self.size)
+ .finish()
+ }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)]
+#[cfg_attr(not(bootstrap), rustc_pass_by_value)]
+pub struct Layout<'a>(pub Interned<'a, LayoutS<'a>>);
+
+impl<'a> fmt::Debug for Layout<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // See comment on `<LayoutS as Debug>::fmt` above.
+ self.0.0.fmt(f)
+ }
+}
+
+impl<'a> Layout<'a> {
+ pub fn fields(self) -> &'a FieldsShape {
+ &self.0.0.fields
+ }
+
+ pub fn variants(self) -> &'a Variants<'a> {
+ &self.0.0.variants
+ }
+
+ pub fn abi(self) -> Abi {
+ self.0.0.abi
+ }
+
+ pub fn largest_niche(self) -> Option<Niche> {
+ self.0.0.largest_niche
+ }
+
+ pub fn align(self) -> AbiAndPrefAlign {
+ self.0.0.align
+ }
+
+ pub fn size(self) -> Size {
+ self.0.0.size
+ }
+}
+
/// The layout of a type, alongside the type itself.
/// Provides various type traversal APIs (e.g., recursing into fields).
///
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable_Generic)]
pub struct TyAndLayout<'a, Ty> {
pub ty: Ty,
- pub layout: &'a Layout,
+ pub layout: Layout<'a>,
}
impl<'a, Ty> Deref for TyAndLayout<'a, Ty> {
- type Target = &'a Layout;
- fn deref(&self) -> &&'a Layout {
- &self.layout
+ type Target = &'a LayoutS<'a>;
+ fn deref(&self) -> &&'a LayoutS<'a> {
+ &self.layout.0.0
}
}
match self {
Self::reg => types! { _: I8, I16, I32, F32; },
Self::sreg | Self::sreg_low16 => types! { vfp2: I32, F32; },
- Self::dreg | Self::dreg_low16 | Self::dreg_low8 => types! {
+ Self::dreg_low16 | Self::dreg_low8 => types! {
vfp2: I64, F64, VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF32(2);
},
+ Self::dreg => types! {
+ d32: I64, F64, VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF32(2);
+ },
Self::qreg | Self::qreg_low8 | Self::qreg_low4 => types! {
neon: VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4);
},
//! LLVM.
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(bool_to_option)]
-#![feature(let_else)]
-#![feature(nll)]
-#![feature(never_type)]
#![feature(associated_type_bounds)]
+#![feature(bool_to_option)]
#![feature(exhaustive_patterns)]
+#![feature(let_else)]
#![feature(min_specialization)]
+#![feature(never_type)]
+#![feature(nll)]
+#![feature(rustc_attrs)]
#![feature(step_trait)]
use std::iter::FromIterator;
features: "+neon,+fp-armv8".to_string(),
supported_sanitizers: SanitizerSet::CFI
| SanitizerSet::HWADDRESS
- | SanitizerSet::MEMTAG,
+ | SanitizerSet::MEMTAG
+ | SanitizerSet::ADDRESS,
..super::android_base::opts()
},
}
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{SanitizerSet, Target, TargetOptions};
pub fn target() -> Target {
Target {
abi: "eabi".to_string(),
// https://developer.android.com/ndk/guides/abis.html#armeabi
features: "+strict-align,+v5te".to_string(),
+ supported_sanitizers: SanitizerSet::ADDRESS,
max_atomic_width: Some(32),
..super::android_base::opts()
},
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{LinkerFlavor, SanitizerSet, Target, TargetOptions};
// This target if is for the baseline of the Android v7a ABI
// in thumb mode. It's named armv7-* instead of thumbv7-*
options: TargetOptions {
abi: "eabi".to_string(),
features: "+v7,+thumb-mode,+thumb2,+vfp3,-d32,-neon".to_string(),
+ supported_sanitizers: SanitizerSet::ADDRESS,
max_atomic_width: Some(64),
..base
},
-use crate::spec::{StackProbeType, Target};
+use crate::spec::{SanitizerSet, StackProbeType, Target, TargetOptions};
// See https://developer.android.com/ndk/guides/abis.html#x86
// for target ABI requirements.
f64:32:64-f80:32-n8:16:32-S128"
.to_string(),
arch: "x86".to_string(),
- options: base,
+ options: TargetOptions { supported_sanitizers: SanitizerSet::ADDRESS, ..base },
}
}
}
}
- pub fn desc_symbol(&self) -> Symbol {
+ pub const fn desc_symbol(&self) -> Symbol {
match *self {
PanicStrategy::Unwind => sym::unwind,
PanicStrategy::Abort => sym::abort,
}
}
+
+ pub const fn all() -> [Symbol; 2] {
+ [Self::Abort.desc_symbol(), Self::Unwind.desc_symbol()]
+ }
}
impl ToJson for PanicStrategy {
/// Return sanitizer's name
///
/// Returns none if the flags is a set of sanitizers numbering not exactly one.
- fn as_str(self) -> Option<&'static str> {
+ pub fn as_str(self) -> Option<&'static str> {
Some(match self {
SanitizerSet::ADDRESS => "address",
SanitizerSet::CFI => "cfi",
))
}
+ /// Load a built-in target
+ pub fn expect_builtin(target_triple: &TargetTriple) -> Target {
+ match *target_triple {
+ TargetTriple::TargetTriple(ref target_triple) => {
+ load_builtin(target_triple).expect("built-in target")
+ }
+ TargetTriple::TargetPath(..) => {
+ panic!("built-in targets doens't support target-paths")
+ }
+ }
+ }
+
/// Search for a JSON file specifying the given target triple.
///
/// If none is found in `$RUST_TARGET_PATH`, look for a file called `target.json` inside the
-use crate::spec::{LinkerFlavor, StackProbeType, Target};
+use crate::spec::{LinkerFlavor, SanitizerSet, StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
let mut base = super::android_base::opts();
data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
.to_string(),
arch: "x86_64".to_string(),
- options: base,
+ options: TargetOptions { supported_sanitizers: SanitizerSet::ADDRESS, ..base },
}
}
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::TraitEngine;
use rustc_middle::traits::specialization_graph::OverlapMode;
-use rustc_middle::ty::fast_reject::{self, SimplifyParams};
+use rustc_middle::ty::fast_reject::{self, TreatParams};
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{self, Ty, TyCtxt};
impl2_ref.iter().flat_map(|tref| tref.substs.types()),
)
.any(|(ty1, ty2)| {
- let t1 = fast_reject::simplify_type(tcx, ty1, SimplifyParams::No);
- let t2 = fast_reject::simplify_type(tcx, ty2, SimplifyParams::No);
+ let t1 = fast_reject::simplify_type(tcx, ty1, TreatParams::AsPlaceholders);
+ let t2 = fast_reject::simplify_type(tcx, ty2, TreatParams::AsPlaceholders);
if let (Some(t1), Some(t2)) = (t1, t2) {
// Simplified successfully
use crate::infer::InferCtxt;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
-use rustc_middle::ty::subst::Subst;
+use rustc_middle::ty::subst::{Subst, SubstsRef};
use rustc_middle::ty::{self, GenericParamDefKind};
use rustc_span::symbol::sym;
use std::iter;
&self,
trait_ref: ty::PolyTraitRef<'tcx>,
obligation: &PredicateObligation<'tcx>,
- ) -> Option<DefId>;
+ ) -> Option<(DefId, SubstsRef<'tcx>)>;
/*private*/
fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str>;
&self,
trait_ref: ty::PolyTraitRef<'tcx>,
obligation: &PredicateObligation<'tcx>,
- ) -> Option<DefId> {
+ ) -> Option<(DefId, SubstsRef<'tcx>)> {
let tcx = self.tcx;
let param_env = obligation.param_env;
let trait_ref = tcx.erase_late_bound_regions(trait_ref);
let impl_self_ty = impl_trait_ref.self_ty();
if let Ok(..) = self.can_eq(param_env, trait_self_ty, impl_self_ty) {
- self_match_impls.push(def_id);
+ self_match_impls.push((def_id, impl_substs));
if iter::zip(
trait_ref.substs.types().skip(1),
)
.all(|(u, v)| self.fuzzy_match_tys(u, v, false).is_some())
{
- fuzzy_match_impls.push(def_id);
+ fuzzy_match_impls.push((def_id, impl_substs));
}
}
});
- let impl_def_id = if self_match_impls.len() == 1 {
+ let impl_def_id_and_substs = if self_match_impls.len() == 1 {
self_match_impls[0]
} else if fuzzy_match_impls.len() == 1 {
fuzzy_match_impls[0]
return None;
};
- tcx.has_attr(impl_def_id, sym::rustc_on_unimplemented).then_some(impl_def_id)
+ tcx.has_attr(impl_def_id_and_substs.0, sym::rustc_on_unimplemented)
+ .then_some(impl_def_id_and_substs)
}
/// Used to set on_unimplemented's `ItemContext`
trait_ref: ty::PolyTraitRef<'tcx>,
obligation: &PredicateObligation<'tcx>,
) -> OnUnimplementedNote {
- let def_id =
- self.impl_similar_to(trait_ref, obligation).unwrap_or_else(|| trait_ref.def_id());
+ let (def_id, substs) = self
+ .impl_similar_to(trait_ref, obligation)
+ .unwrap_or_else(|| (trait_ref.def_id(), trait_ref.skip_binder().substs));
let trait_ref = trait_ref.skip_binder();
let mut flags = vec![(
for param in generics.params.iter() {
let value = match param.kind {
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
- trait_ref.substs[param.index as usize].to_string()
+ substs[param.index as usize].to_string()
}
GenericParamDefKind::Lifetime => continue,
};
flags.push((name, Some(value)));
if let GenericParamDefKind::Type { .. } = param.kind {
- let param_ty = trait_ref.substs[param.index as usize].expect_ty();
+ let param_ty = substs[param.index as usize].expect_ty();
if let Some(def) = param_ty.ty_adt_def() {
// We also want to be able to select the parameter's
// original signature with no type arguments resolved
}
});
- if let Ok(Some(command)) =
- OnUnimplementedDirective::of_item(self.tcx, trait_ref.def_id, def_id)
- {
+ if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, def_id) {
command.evaluate(self.tcx, trait_ref, &flags)
} else {
OnUnimplementedNote::default()
}
hir::Node::Item(hir::Item {
kind:
- hir::ItemKind::Trait(_, _, generics, _, _)
+ hir::ItemKind::Trait(_, _, generics, ..)
| hir::ItemKind::Impl(hir::Impl { generics, .. }),
..
}) if projection.is_some() => {
let obligation = &mut pending_obligation.obligation;
+ debug!(?obligation, "process_obligation pre-resolve");
+
if obligation.predicate.has_infer_types_or_consts() {
obligation.predicate =
self.selcx.infcx().resolve_vars_if_possible(obligation.predicate);
let infcx = self.selcx.infcx();
+ if obligation.predicate.has_projections() {
+ let mut obligations = Vec::new();
+ let predicate = crate::traits::project::try_normalize_with_depth_to(
+ self.selcx,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ obligation.predicate,
+ &mut obligations,
+ );
+ if predicate != obligation.predicate {
+ obligations.push(obligation.with(predicate));
+ return ProcessResult::Changed(mk_pending(obligations));
+ }
+ }
let binder = obligation.predicate.kind();
match binder.no_bound_vars() {
None => match binder.skip_binder() {
impl<'tcx> OnUnimplementedDirective {
fn parse(
tcx: TyCtxt<'tcx>,
- trait_def_id: DefId,
+ item_def_id: DefId,
items: &[NestedMetaItem],
span: Span,
is_root: bool,
let mut item_iter = items.iter();
let parse_value = |value_str| {
- OnUnimplementedFormatString::try_parse(tcx, trait_def_id, value_str, span).map(Some)
+ OnUnimplementedFormatString::try_parse(tcx, item_def_id, value_str, span).map(Some)
};
let condition = if is_root {
{
if let Some(items) = item.meta_item_list() {
if let Ok(subcommand) =
- Self::parse(tcx, trait_def_id, &items, item.span(), false)
+ Self::parse(tcx, item_def_id, &items, item.span(), false)
{
subcommands.push(subcommand);
} else {
}
}
- pub fn of_item(
- tcx: TyCtxt<'tcx>,
- trait_def_id: DefId,
- impl_def_id: DefId,
- ) -> Result<Option<Self>, ErrorGuaranteed> {
- let attrs = tcx.get_attrs(impl_def_id);
+ pub fn of_item(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<Option<Self>, ErrorGuaranteed> {
+ let attrs = tcx.get_attrs(item_def_id);
let Some(attr) = tcx.sess.find_by_name(&attrs, sym::rustc_on_unimplemented) else {
return Ok(None);
};
let result = if let Some(items) = attr.meta_item_list() {
- Self::parse(tcx, trait_def_id, &items, attr.span, true).map(Some)
+ Self::parse(tcx, item_def_id, &items, attr.span, true).map(Some)
} else if let Some(value) = attr.value_str() {
Ok(Some(OnUnimplementedDirective {
condition: None,
subcommands: vec![],
label: Some(OnUnimplementedFormatString::try_parse(
tcx,
- trait_def_id,
+ item_def_id,
value,
attr.span,
)?),
} else {
return Err(ErrorGuaranteed);
};
- debug!("of_item({:?}/{:?}) = {:?}", trait_def_id, impl_def_id, result);
+ debug!("of_item({:?}) = {:?}", item_def_id, result);
result
}
impl<'tcx> OnUnimplementedFormatString {
fn try_parse(
tcx: TyCtxt<'tcx>,
- trait_def_id: DefId,
+ item_def_id: DefId,
from: Symbol,
err_sp: Span,
) -> Result<Self, ErrorGuaranteed> {
let result = OnUnimplementedFormatString(from);
- result.verify(tcx, trait_def_id, err_sp)?;
+ result.verify(tcx, item_def_id, err_sp)?;
Ok(result)
}
fn verify(
&self,
tcx: TyCtxt<'tcx>,
- trait_def_id: DefId,
+ item_def_id: DefId,
span: Span,
) -> Result<(), ErrorGuaranteed> {
- let name = tcx.item_name(trait_def_id);
- let generics = tcx.generics_of(trait_def_id);
+ let trait_def_id = if tcx.is_trait(item_def_id) {
+ item_def_id
+ } else {
+ tcx.trait_id_of_impl(item_def_id)
+ .expect("expected `on_unimplemented` to correspond to a trait")
+ };
+ let trait_name = tcx.item_name(trait_def_id);
+ let generics = tcx.generics_of(item_def_id);
let s = self.0.as_str();
let parser = Parser::new(s, None, None, false, ParseMode::Format);
let mut result = Ok(());
// `{Self}` is allowed
Position::ArgumentNamed(s, _) if s == kw::SelfUpper => (),
// `{ThisTraitsName}` is allowed
- Position::ArgumentNamed(s, _) if s == name => (),
+ Position::ArgumentNamed(s, _) if s == trait_name => (),
// `{from_method}` is allowed
Position::ArgumentNamed(s, _) if s == sym::from_method => (),
// `{from_desugaring}` is allowed
tcx.sess,
span,
E0230,
- "there is no parameter `{}` on trait `{}`",
+ "there is no parameter `{}` on {}",
s,
- name
+ if trait_def_id == item_def_id {
+ format!("trait `{}`", trait_name)
+ } else {
+ "impl".to_string()
+ }
)
.emit();
result = Err(ErrorGuaranteed);
result
}
+#[instrument(level = "info", skip(selcx, param_env, cause, obligations))]
+pub fn try_normalize_with_depth_to<'a, 'b, 'tcx, T>(
+ selcx: &'a mut SelectionContext<'b, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ cause: ObligationCause<'tcx>,
+ depth: usize,
+ value: T,
+ obligations: &mut Vec<PredicateObligation<'tcx>>,
+) -> T
+where
+ T: TypeFoldable<'tcx>,
+{
+ debug!(obligations.len = obligations.len());
+ let mut normalizer = AssocTypeNormalizer::new_without_eager_inference_replacement(
+ selcx,
+ param_env,
+ cause,
+ depth,
+ obligations,
+ );
+ let result = ensure_sufficient_stack(|| normalizer.fold(value));
+ debug!(?result, obligations.len = normalizer.obligations.len());
+ debug!(?normalizer.obligations,);
+ result
+}
+
pub(crate) fn needs_normalization<'tcx, T: TypeFoldable<'tcx>>(value: &T, reveal: Reveal) -> bool {
match reveal {
Reveal::UserFacing => value
obligations: &'a mut Vec<PredicateObligation<'tcx>>,
depth: usize,
universes: Vec<Option<ty::UniverseIndex>>,
+ /// If true, when a projection is unable to be completed, an inference
+ /// variable will be created and an obligation registered to project to that
+ /// inference variable. Also, constants will be eagerly evaluated.
+ eager_inference_replacement: bool,
}
impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
depth: usize,
obligations: &'a mut Vec<PredicateObligation<'tcx>>,
) -> AssocTypeNormalizer<'a, 'b, 'tcx> {
- AssocTypeNormalizer { selcx, param_env, cause, obligations, depth, universes: vec![] }
+ AssocTypeNormalizer {
+ selcx,
+ param_env,
+ cause,
+ obligations,
+ depth,
+ universes: vec![],
+ eager_inference_replacement: true,
+ }
+ }
+
+ fn new_without_eager_inference_replacement(
+ selcx: &'a mut SelectionContext<'b, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ cause: ObligationCause<'tcx>,
+ depth: usize,
+ obligations: &'a mut Vec<PredicateObligation<'tcx>>,
+ ) -> AssocTypeNormalizer<'a, 'b, 'tcx> {
+ AssocTypeNormalizer {
+ selcx,
+ param_env,
+ cause,
+ obligations,
+ depth,
+ universes: vec![],
+ eager_inference_replacement: false,
+ }
}
fn fold<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
// there won't be bound vars there.
let data = data.super_fold_with(self);
- let normalized_ty = normalize_projection_type(
- self.selcx,
- self.param_env,
- data,
- self.cause.clone(),
- self.depth,
- &mut self.obligations,
- );
+ let normalized_ty = if self.eager_inference_replacement {
+ normalize_projection_type(
+ self.selcx,
+ self.param_env,
+ data,
+ self.cause.clone(),
+ self.depth,
+ &mut self.obligations,
+ )
+ } else {
+ opt_normalize_projection_type(
+ self.selcx,
+ self.param_env,
+ data,
+ self.cause.clone(),
+ self.depth,
+ &mut self.obligations,
+ )
+ .ok()
+ .flatten()
+ .unwrap_or_else(|| ty::Term::Ty(ty.super_fold_with(self)))
+ };
debug!(
?self.depth,
?ty,
}
fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> {
- if self.selcx.tcx().lazy_normalization() {
+ if self.selcx.tcx().lazy_normalization() || !self.eager_inference_replacement {
constant
} else {
let constant = constant.super_fold_with(self);
use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::thir::abstract_const::NotConstEvaluatable;
-use rustc_middle::ty::fast_reject::{self, SimplifyParams};
+use rustc_middle::ty::fast_reject::{self, TreatParams};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::relate::TypeRelation;
use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef};
fn fast_reject_trait_refs(
&mut self,
- obligation: &TraitObligation<'_>,
- impl_trait_ref: &ty::TraitRef<'_>,
+ obligation: &TraitObligation<'tcx>,
+ impl_trait_ref: &ty::TraitRef<'tcx>,
) -> bool {
// We can avoid creating type variables and doing the full
// substitution if we find that any of the input types, when
let simplified_obligation_ty = fast_reject::simplify_type(
self.tcx(),
obligation_ty,
- SimplifyParams::Yes,
+ TreatParams::AsBoundTypes,
+ );
+ let simplified_impl_ty = fast_reject::simplify_type(
+ self.tcx(),
+ impl_ty,
+ TreatParams::AsPlaceholders,
);
- let simplified_impl_ty =
- fast_reject::simplify_type(self.tcx(), impl_ty, SimplifyParams::No);
simplified_obligation_ty.is_some()
&& simplified_impl_ty.is_some()
use crate::traits;
use rustc_hir::def_id::DefId;
-use rustc_middle::ty::fast_reject::{self, SimplifiedType, SimplifyParams};
+use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
/// Insert an impl into this set of children without comparing to any existing impls.
fn insert_blindly(&mut self, tcx: TyCtxt<'_>, impl_def_id: DefId) {
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
- if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), SimplifyParams::No) {
+ if let Some(st) =
+ fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsPlaceholders)
+ {
debug!("insert_blindly: impl_def_id={:?} st={:?}", impl_def_id, st);
self.non_blanket_impls.entry(st).or_default().push(impl_def_id)
} else {
fn remove_existing(&mut self, tcx: TyCtxt<'_>, impl_def_id: DefId) {
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
let vec: &mut Vec<DefId>;
- if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), SimplifyParams::No) {
+ if let Some(st) =
+ fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsPlaceholders)
+ {
debug!("remove_existing: impl_def_id={:?} st={:?}", impl_def_id, st);
vec = self.non_blanket_impls.get_mut(&st).unwrap();
} else {
let mut parent = trait_def_id;
let mut last_lint = None;
- let simplified = fast_reject::simplify_type(tcx, trait_ref.self_ty(), SimplifyParams::No);
+ let simplified =
+ fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsPlaceholders);
// Descend the specialization tree, where `parent` is the current parent node.
loop {
impl_trait_ref,
&impl_.items,
);
- let trait_def_id = impl_trait_ref.def_id;
- check_on_unimplemented(tcx, trait_def_id, it);
+ check_on_unimplemented(tcx, it);
}
}
hir::ItemKind::Trait(_, _, _, _, ref items) => {
- check_on_unimplemented(tcx, it.def_id.to_def_id(), it);
+ check_on_unimplemented(tcx, it);
for item in items.iter() {
let item = tcx.hir().trait_item(item.id);
}
}
-pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, trait_def_id: DefId, item: &hir::Item<'_>) {
+pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
// an error would be reported if this fails.
- let _ = traits::OnUnimplementedDirective::of_item(tcx, trait_def_id, item.def_id.to_def_id());
+ let _ = traits::OnUnimplementedDirective::of_item(tcx, item.def_id.to_def_id());
}
pub(super) fn check_specialization_validity<'tcx>(
use rustc_middle::ty::subst::SubstsRef;
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;
use rustc_span::source_map::Span;
// We know by construction that `<expr>.await` is either on Rust 2015
// or results in `ExprKind::Await`. Suggest switching the edition to 2018.
err.note("to `.await` a `Future`, switch to Rust 2018 or later");
- err.help(&format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION));
- err.note("for more on editions, read https://doc.rust-lang.org/edition-guide");
+ err.help_use_latest_edition();
}
err.emit();
}
// FIXME: currently we never try to compose autoderefs
// and ReifyFnPointer/UnsafeFnPointer, but we could.
- _ => bug!(
- "while adjusting {:?}, can't compose {:?} and {:?}",
- expr,
- entry.get(),
- adj
+ _ => self.tcx.sess.delay_span_bug(
+ expr.span,
+ &format!(
+ "while adjusting {:?}, can't compose {:?} and {:?}",
+ expr,
+ entry.get(),
+ adj
+ ),
),
};
*entry.get_mut() = adj;
self.fcx.var_for_def(self.span, param)
}
}
- GenericParamDefKind::Const { has_default, .. } => {
+ GenericParamDefKind::Const { has_default } => {
if !infer_args && has_default {
tcx.const_param_default(param.def_id)
.subst_spanned(tcx, substs.unwrap(), Some(self.span))
// This is more complicated than just checking type equality, as arguments could be coerced
// This version writes those types back so further type checking uses the narrowed types
let demand_compatible = |idx, final_arg_types: &mut Vec<Option<(Ty<'tcx>, Ty<'tcx>)>>| {
- // Do not check argument compatibility if the number of args do not match
- if arg_count_error.is_some() {
- return;
- }
-
let formal_input_ty: Ty<'tcx> = formal_input_tys[idx];
let expected_input_ty: Ty<'tcx> = expected_input_tys[idx];
let provided_arg = &provided_args[idx];
self.demand_suptype(provided_arg.span, formal_input_ty, coerced_ty);
};
+ let minimum_input_count = formal_input_tys.len();
+
// Check the arguments.
// We do this in a pretty awful way: first we type-check any arguments
// that are not closures, then we type-check the closures. This is so
})
}
- let minimum_input_count = formal_input_tys.len();
for (idx, arg) in provided_args.iter().enumerate() {
// Warn only for the first loop (the "no closures" one).
// Closure arguments themselves can't be diverging, but
err.emit();
}
- // We also need to make sure we at least write the ty of the other
- // arguments which we skipped above.
- if c_variadic {
- fn variadic_error<'tcx>(sess: &Session, span: Span, ty: Ty<'tcx>, cast_ty: &str) {
- use crate::structured_errors::MissingCastForVariadicArg;
+ for arg in provided_args.iter().skip(minimum_input_count) {
+ let arg_ty = self.check_expr(&arg);
- MissingCastForVariadicArg { sess, span, ty, cast_ty }.diagnostic().emit();
- }
+ if c_variadic {
+ // We also need to make sure we at least write the ty of the other
+ // arguments which we skipped above, either because they were additional
+ // c_variadic args, or because we had an argument count mismatch.
+ fn variadic_error<'tcx>(sess: &Session, span: Span, ty: Ty<'tcx>, cast_ty: &str) {
+ use crate::structured_errors::MissingCastForVariadicArg;
- for arg in provided_args.iter().skip(expected_arg_count) {
- let arg_ty = self.check_expr(&arg);
+ MissingCastForVariadicArg { sess, span, ty, cast_ty }.diagnostic().emit();
+ }
// There are a few types which get autopromoted when passed via varargs
// in C but we just error out instead and require explicit casts.
use hir::{def_id::DefId, Body, HirId, HirIdMap};
use rustc_data_structures::stable_set::FxHashSet;
use rustc_hir as hir;
-use rustc_middle::hir::map::Map;
+use rustc_middle::ty::{ParamEnv, TyCtxt};
pub(super) fn find_consumed_and_borrowed<'a, 'tcx>(
fcx: &'a FnCtxt<'a, 'tcx>,
def_id: DefId,
body: &'tcx Body<'tcx>,
) -> ConsumedAndBorrowedPlaces {
- let mut expr_use_visitor = ExprUseDelegate::new(fcx.tcx.hir());
+ let mut expr_use_visitor = ExprUseDelegate::new(fcx.tcx, fcx.param_env);
expr_use_visitor.consume_body(fcx, def_id, body);
expr_use_visitor.places
}
/// Interesting values are those that are either dropped or borrowed. For dropped values, we also
/// record the parent expression, which is the point where the drop actually takes place.
struct ExprUseDelegate<'tcx> {
- hir: Map<'tcx>,
+ tcx: TyCtxt<'tcx>,
+ param_env: ParamEnv<'tcx>,
places: ConsumedAndBorrowedPlaces,
}
impl<'tcx> ExprUseDelegate<'tcx> {
- fn new(hir: Map<'tcx>) -> Self {
+ fn new(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
Self {
- hir,
+ tcx,
+ param_env,
places: ConsumedAndBorrowedPlaces {
consumed: <_>::default(),
borrowed: <_>::default(),
place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>,
diag_expr_id: HirId,
) {
- let parent = match self.hir.find_parent_node(place_with_id.hir_id) {
+ let parent = match self.tcx.hir().find_parent_node(place_with_id.hir_id) {
Some(parent) => parent,
None => place_with_id.hir_id,
};
assignee_place: &expr_use_visitor::PlaceWithHirId<'tcx>,
diag_expr_id: HirId,
) {
- debug!("mutate {:?}; diag_expr_id={:?}", assignee_place, diag_expr_id);
- // Count mutations as a borrow.
- self.places
- .borrowed
- .insert(TrackedValue::from_place_with_projections_allowed(assignee_place));
+ debug!("mutate {assignee_place:?}; diag_expr_id={diag_expr_id:?}");
+ // If the type being assigned needs dropped, then the mutation counts as a borrow
+ // since it is essentially doing `Drop::drop(&mut x); x = new_value;`.
+ if assignee_place.place.base_ty.needs_drop(self.tcx, self.param_env) {
+ self.places
+ .borrowed
+ .insert(TrackedValue::from_place_with_projections_allowed(assignee_place));
+ }
+ }
+
+ fn bind(
+ &mut self,
+ binding_place: &expr_use_visitor::PlaceWithHirId<'tcx>,
+ diag_expr_id: HirId,
+ ) {
+ debug!("bind {binding_place:?}; diag_expr_id={diag_expr_id:?}");
}
fn fake_read(
use rustc_hir::{ExprKind, Node, QPath};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_middle::traits::util::supertraits;
-use rustc_middle::ty::fast_reject::{simplify_type, SimplifyParams};
+use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
use rustc_middle::ty::print::with_crate_prefix;
use rustc_middle::ty::ToPolyTraitRef;
use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable};
// FIXME: Even though negative bounds are not implemented, we could maybe handle
// cases where a positive bound implies a negative impl.
(candidates, Vec::new())
- } else if let Some(simp_rcvr_ty) = simplify_type(self.tcx, rcvr_ty, SimplifyParams::Yes)
+ } else if let Some(simp_rcvr_ty) =
+ simplify_type(self.tcx, rcvr_ty, TreatParams::AsBoundTypes)
{
let mut potential_candidates = Vec::new();
let mut explicitly_negative = Vec::new();
.any(|imp_did| {
let imp = self.tcx.impl_trait_ref(imp_did).unwrap();
let imp_simp =
- simplify_type(self.tcx, imp.self_ty(), SimplifyParams::Yes);
+ simplify_type(self.tcx, imp.self_ty(), TreatParams::AsBoundTypes);
imp_simp.map_or(false, |s| s == simp_rcvr_ty)
})
{
// the consumer's responsibility to ensure all bytes that have been read
// have defined values.
if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id()) {
- if alloc.relocations().len() != 0 {
+ if alloc.inner().relocations().len() != 0 {
let msg = "statics with a custom `#[link_section]` must be a \
simple list of bytes on the wasm target with no \
extra levels of indirection such as references";
// The `def_id` here actually was calculated during resolution (at least
// at the time of this writing) and is being shipped to us via a side
// channel of the tcx. There may have been extra expansion phases,
- // however, which ended up removing the `def_id` *after* expansion such
- // as the `ReplaceBodyWithLoop` pass (which is a bit of a hack, but hey)
+ // however, which ended up removing the `def_id` *after* expansion.
//
// As a result we need to verify that `def_id` is indeed still valid for
// our AST and actually present in the HIR map. If it's not there then
/// `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId);
+ /// The path at `binding_place` is a binding that is being initialized.
+ ///
+ /// This covers cases such as `let x = 42;`
+ fn bind(&mut self, binding_place: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId) {
+ // Bindings can normally be treated as a regular assignment, so by default we
+ // forward this to the mutate callback.
+ self.mutate(binding_place, diag_expr_id)
+ }
+
/// The `place` should be a fake read because of specified `cause`.
fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause, diag_expr_id: hir::HirId);
}
let pat_ty = return_if_err!(mc.node_ty(pat.hir_id));
debug!("walk_pat: pat_ty={:?}", pat_ty);
- // Each match binding is effectively an assignment to the
- // binding being produced.
let def = Res::Local(canonical_id);
if let Ok(ref binding_place) = mc.cat_res(pat.hir_id, pat.span, pat_ty, def) {
- delegate.mutate(binding_place, binding_place.hir_id);
+ delegate.bind(binding_place, binding_place.hir_id);
}
// It is also a borrow or copy/move of the value being matched.
use core::mem;
use super::super::borrow::DormantMutRef;
-use super::super::node::{marker, Handle, InsertResult::*, NodeRef};
+use super::super::node::{marker, Handle, NodeRef};
use super::BTreeMap;
use Entry::*;
#[stable(feature = "rust1", since = "1.0.0")]
pub fn insert(self, value: V) -> &'a mut V {
let out_ptr = match self.handle.insert_recursing(self.key, value) {
- (Fit(_), val_ptr) => {
+ (None, val_ptr) => {
// SAFETY: We have consumed self.handle and the handle returned.
let map = unsafe { self.dormant_map.awaken() };
map.length += 1;
val_ptr
}
- (Split(ins), val_ptr) => {
+ (Some(ins), val_ptr) => {
drop(ins.left);
// SAFETY: We have consumed self.handle and the reference returned.
let map = unsafe { self.dormant_map.awaken() };
/// this edge. This method splits the node if there isn't enough room.
///
/// The returned pointer points to the inserted value.
- fn insert(mut self, key: K, val: V) -> (InsertResult<'a, K, V, marker::Leaf>, *mut V) {
+ fn insert(mut self, key: K, val: V) -> (Option<SplitResult<'a, K, V, marker::Leaf>>, *mut V) {
if self.node.len() < CAPACITY {
let val_ptr = self.insert_fit(key, val);
- let kv = unsafe { Handle::new_kv(self.node, self.idx) };
- (InsertResult::Fit(kv), val_ptr)
+ (None, val_ptr)
} else {
let (middle_kv_idx, insertion) = splitpoint(self.idx);
let middle = unsafe { Handle::new_kv(self.node, middle_kv_idx) };
},
};
let val_ptr = insertion_edge.insert_fit(key, val);
- (InsertResult::Split(result), val_ptr)
+ (Some(result), val_ptr)
}
}
}
key: K,
val: V,
edge: Root<K, V>,
- ) -> InsertResult<'a, K, V, marker::Internal> {
+ ) -> Option<SplitResult<'a, K, V, marker::Internal>> {
assert!(edge.height == self.node.height - 1);
if self.node.len() < CAPACITY {
self.insert_fit(key, val, edge);
- let kv = unsafe { Handle::new_kv(self.node, self.idx) };
- InsertResult::Fit(kv)
+ None
} else {
let (middle_kv_idx, insertion) = splitpoint(self.idx);
let middle = unsafe { Handle::new_kv(self.node, middle_kv_idx) };
},
};
insertion_edge.insert_fit(key, val, edge);
- InsertResult::Split(result)
+ Some(result)
}
}
}
/// this edge. This method splits the node if there isn't enough room, and tries to
/// insert the split off portion into the parent node recursively, until the root is reached.
///
- /// If the returned result is a `Fit`, its handle's node can be this edge's node or an ancestor.
- /// If the returned result is a `Split`, the `left` field will be the root node.
- /// The returned pointer points to the inserted value.
+ /// If the returned result is some `SplitResult`, the `left` field will be the root node.
+ /// The returned pointer points to the inserted value, which in the case of `SplitResult`
+ /// is in the `left` or `right` tree.
pub fn insert_recursing(
self,
key: K,
value: V,
- ) -> (InsertResult<'a, K, V, marker::LeafOrInternal>, *mut V) {
+ ) -> (Option<SplitResult<'a, K, V, marker::LeafOrInternal>>, *mut V) {
let (mut split, val_ptr) = match self.insert(key, value) {
- (InsertResult::Fit(handle), ptr) => {
- return (InsertResult::Fit(handle.forget_node_type()), ptr);
- }
- (InsertResult::Split(split), val_ptr) => (split.forget_node_type(), val_ptr),
+ (None, val_ptr) => return (None, val_ptr),
+ (Some(split), val_ptr) => (split.forget_node_type(), val_ptr),
};
loop {
split = match split.left.ascend() {
Ok(parent) => match parent.insert(split.kv.0, split.kv.1, split.right) {
- InsertResult::Fit(handle) => {
- return (InsertResult::Fit(handle.forget_node_type()), val_ptr);
- }
- InsertResult::Split(split) => split.forget_node_type(),
+ None => return (None, val_ptr),
+ Some(split) => split.forget_node_type(),
},
- Err(root) => {
- return (InsertResult::Split(SplitResult { left: root, ..split }), val_ptr);
- }
+ Err(root) => return (Some(SplitResult { left: root, ..split }), val_ptr),
};
}
}
}
}
-impl<BorrowType, K, V> Handle<NodeRef<BorrowType, K, V, marker::Internal>, marker::KV> {
- pub fn forget_node_type(
- self,
- ) -> Handle<NodeRef<BorrowType, K, V, marker::LeafOrInternal>, marker::KV> {
- unsafe { Handle::new_kv(self.node.forget_type(), self.idx) }
- }
-}
-
impl<BorrowType, K, V, Type> Handle<NodeRef<BorrowType, K, V, marker::LeafOrInternal>, Type> {
/// Checks whether the underlying node is an `Internal` node or a `Leaf` node.
pub fn force(
pub struct SplitResult<'a, K, V, NodeType> {
// Altered node in existing tree with elements and edges that belong to the left of `kv`.
pub left: NodeRef<marker::Mut<'a>, K, V, NodeType>,
- // Some key and value split off, to be inserted elsewhere.
+ // Some key and value that existed before and were split off, to be inserted elsewhere.
pub kv: (K, V),
// Owned, unattached, new node with elements and edges that belong to the right of `kv`.
pub right: NodeRef<marker::Owned, K, V, NodeType>,
}
}
-pub enum InsertResult<'a, K, V, NodeType> {
- Fit(Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, marker::KV>),
- Split(SplitResult<'a, K, V, NodeType>),
-}
-
pub mod marker {
use core::marker::PhantomData;
#![feature(box_syntax)]
#![feature(cfg_sanitize)]
#![feature(const_deref)]
-#![feature(const_fn_trait_bound)]
+#![cfg_attr(bootstrap, feature(const_fn_trait_bound))]
#![feature(const_mut_refs)]
#![feature(const_ptr_write)]
#![feature(const_precise_live_drops)]
/// The `lt`, `le`, `gt`, and `ge` methods of this trait can be called using
/// the `<`, `<=`, `>`, and `>=` operators, respectively.
///
-/// The methods of this trait must be consistent with each other and with those of `PartialEq` in
-/// the following sense:
-///
-/// - `a == b` if and only if `partial_cmp(a, b) == Some(Equal)`.
-/// - `a < b` if and only if `partial_cmp(a, b) == Some(Less)`
-/// (ensured by the default implementation).
-/// - `a > b` if and only if `partial_cmp(a, b) == Some(Greater)`
-/// (ensured by the default implementation).
-/// - `a <= b` if and only if `a < b || a == b`
-/// (ensured by the default implementation).
-/// - `a >= b` if and only if `a > b || a == b`
-/// (ensured by the default implementation).
-/// - `a != b` if and only if `!(a == b)` (already part of `PartialEq`).
+/// The methods of this trait must be consistent with each other and with those of [`PartialEq`].
+/// The following conditions must hold:
+///
+/// 1. `a == b` if and only if `partial_cmp(a, b) == Some(Equal)`.
+/// 2. `a < b` if and only if `partial_cmp(a, b) == Some(Less)`
+/// 3. `a > b` if and only if `partial_cmp(a, b) == Some(Greater)`
+/// 4. `a <= b` if and only if `a < b || a == b`
+/// 5. `a >= b` if and only if `a > b || a == b`
+/// 6. `a != b` if and only if `!(a == b)`.
+///
+/// Conditions 2–5 above are ensured by the default implementation.
+/// Condition 6 is already ensured by [`PartialEq`].
///
/// If [`Ord`] is also implemented for `Self` and `Rhs`, it must also be consistent with
/// `partial_cmp` (see the documentation of that trait for the exact requirements). It's
pub const fn black_box<T>(dummy: T) -> T {
crate::intrinsics::black_box(dummy)
}
+
+/// An identity function that causes an `unused_must_use` warning to be
+/// triggered if the given value is not used (returned, stored in a variable,
+/// etc) by the caller.
+///
+/// This is primarily intended for use in macro-generated code, in which a
+/// [`#[must_use]` attribute][must_use] either on a type or a function would not
+/// be convenient.
+///
+/// [must_use]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
+///
+/// # Example
+///
+/// ```
+/// #![feature(hint_must_use)]
+///
+/// use core::fmt;
+///
+/// pub struct Error(/* ... */);
+///
+/// #[macro_export]
+/// macro_rules! make_error {
+/// ($($args:expr),*) => {
+/// core::hint::must_use({
+/// let error = $crate::make_error(core::format_args!($($args),*));
+/// error
+/// })
+/// };
+/// }
+///
+/// // Implementation detail of make_error! macro.
+/// #[doc(hidden)]
+/// pub fn make_error(args: fmt::Arguments<'_>) -> Error {
+/// Error(/* ... */)
+/// }
+///
+/// fn demo() -> Option<Error> {
+/// if true {
+/// // Oops, meant to write `return Some(make_error!("..."));`
+/// Some(make_error!("..."));
+/// }
+/// None
+/// }
+/// #
+/// # // Make rustdoc not wrap the whole snippet in fn main, so that $crate::make_error works
+/// # fn main() {}
+/// ```
+///
+/// In the above example, we'd like an `unused_must_use` lint to apply to the
+/// value created by `make_error!`. However, neither `#[must_use]` on a struct
+/// nor `#[must_use]` on a function is appropriate here, so the macro expands
+/// using `core::hint::must_use` instead.
+///
+/// - We wouldn't want `#[must_use]` on the `struct Error` because that would
+/// make the following unproblematic code trigger a warning:
+///
+/// ```
+/// # struct Error;
+/// #
+/// fn f(arg: &str) -> Result<(), Error>
+/// # { Ok(()) }
+///
+/// #[test]
+/// fn t() {
+/// // Assert that `f` returns error if passed an empty string.
+/// // A value of type `Error` is unused here but that's not a problem.
+/// f("").unwrap_err();
+/// }
+/// ```
+///
+/// - Using `#[must_use]` on `fn make_error` can't help because the return value
+/// *is* used, as the right-hand side of a `let` statement. The `let`
+/// statement looks useless but is in fact necessary for ensuring that
+/// temporaries within the `format_args` expansion are not kept alive past the
+/// creation of the `Error`, as keeping them alive past that point can cause
+/// autotrait issues in async code:
+///
+/// ```
+/// # #![feature(hint_must_use)]
+/// #
+/// # struct Error;
+/// #
+/// # macro_rules! make_error {
+/// # ($($args:expr),*) => {
+/// # core::hint::must_use({
+/// # // If `let` isn't used, then `f()` produces a non-Send future.
+/// # let error = make_error(core::format_args!($($args),*));
+/// # error
+/// # })
+/// # };
+/// # }
+/// #
+/// # fn make_error(args: core::fmt::Arguments<'_>) -> Error {
+/// # Error
+/// # }
+/// #
+/// async fn f() {
+/// // Using `let` inside the make_error expansion causes temporaries like
+/// // `unsync()` to drop at the semicolon of that `let` statement, which
+/// // is prior to the await point. They would otherwise stay around until
+/// // the semicolon on *this* statement, which is after the await point,
+/// // and the enclosing Future would not implement Send.
+/// log(make_error!("look: {:p}", unsync())).await;
+/// }
+///
+/// async fn log(error: Error) {/* ... */}
+///
+/// // Returns something without a Sync impl.
+/// fn unsync() -> *const () {
+/// 0 as *const ()
+/// }
+/// #
+/// # fn test() {
+/// # fn assert_send(_: impl Send) {}
+/// # assert_send(f());
+/// # }
+/// ```
+#[unstable(feature = "hint_must_use", issue = "94745")]
+#[rustc_const_unstable(feature = "hint_must_use", issue = "94745")]
+#[must_use] // <-- :)
+pub const fn must_use<T>(value: T) -> T {
+ value
+}
/// }
/// ```
///
-/// This will print "('a', 1), ('b', 2), ('c', 3)".
+/// This will print `('a', 1), ('b', 2), ('c', 3)`.
///
/// Now consider this twist where we add a call to `rev`. This version will
/// print `('c', 1), ('b', 2), ('a', 3)`. Note that the letters are reversed,
/// ```
/// let a = [1, 2, 3];
///
- /// let (even, odd): (Vec<i32>, Vec<i32>) = a
- /// .iter()
- /// .partition(|&n| n % 2 == 0);
+ /// let (even, odd): (Vec<_>, Vec<_>) = a
+ /// .into_iter()
+ /// .partition(|n| n % 2 == 0);
///
/// assert_eq!(even, vec![2]);
/// assert_eq!(odd, vec![1, 3]);
#![feature(cfg_target_has_atomic)]
#![feature(cfg_target_has_atomic_equal_alignment)]
#![feature(const_fn_floating_point_arithmetic)]
-#![feature(const_fn_fn_ptr_basics)]
-#![feature(const_fn_trait_bound)]
-#![feature(const_impl_trait)]
+#![cfg_attr(bootstrap, feature(const_fn_fn_ptr_basics))]
+#![cfg_attr(bootstrap, feature(const_fn_trait_bound))]
+#![cfg_attr(bootstrap, feature(const_impl_trait))]
#![feature(const_mut_refs)]
#![feature(const_precise_live_drops)]
#![feature(const_refs_to_cell)]
#[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(all(miri, doctest)))] // Miri does not support all SIMD intrinsics
+#[cfg(not(all(miri, doctest)))] // Skip SIMD doctests in Miri
mod core_simd;
#[doc = include_str!("../../portable-simd/crates/core_simd/src/core_simd_docs.md")]
#[unstable(feature = "portable_simd", issue = "86656")]
-#[cfg(not(all(miri, doctest)))] // Miri does not support all SIMD intrinsics
+#[cfg(not(all(miri, doctest)))] // Skip SIMD doctests in Miri
pub mod simd {
#[unstable(feature = "portable_simd", issue = "86656")]
pub use crate::core_simd::simd::*;
/// ### Correct usage of this method:
///
/// ```rust
+ /// # #![allow(unexpected_cfgs)]
/// use std::mem::MaybeUninit;
///
/// # unsafe extern "C" fn initialize_buffer(buf: *mut [u8; 1024]) { *buf = [0; 1024] }
/// stuff(pin!(Foo { /* … */ }));
/// ```
///
-/// ### Manually polling a `Future` (wihout `Unpin` bounds)
+/// ### Manually polling a `Future` (without `Unpin` bounds)
///
/// ```rust
/// #![feature(pin_macro)]
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn ok(self) -> Option<T> {
+ #[rustc_const_unstable(feature = "const_result_drop", issue = "92384")]
+ pub const fn ok(self) -> Option<T>
+ where
+ E: ~const Drop,
+ {
match self {
Ok(x) => Some(x),
- Err(_) => None,
+ // FIXME: ~const Drop doesn't quite work right yet
+ #[allow(unused_variables)]
+ Err(x) => None,
}
}
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn err(self) -> Option<E> {
+ #[rustc_const_unstable(feature = "const_result_drop", issue = "92384")]
+ pub const fn err(self) -> Option<E>
+ where
+ T: ~const Drop,
+ {
match self {
- Ok(_) => None,
+ // FIXME: ~const Drop doesn't quite work right yet
+ #[allow(unused_variables)]
+ Ok(x) => None,
Err(x) => Some(x),
}
}
/// assert_eq!(x.and(y), Ok("different result type"));
/// ```
#[inline]
+ #[rustc_const_unstable(feature = "const_result_drop", issue = "92384")]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn and<U>(self, res: Result<U, E>) -> Result<U, E> {
+ pub const fn and<U>(self, res: Result<U, E>) -> Result<U, E>
+ where
+ T: ~const Drop,
+ U: ~const Drop,
+ E: ~const Drop,
+ {
match self {
- Ok(_) => res,
+ // FIXME: ~const Drop doesn't quite work right yet
+ #[allow(unused_variables)]
+ Ok(x) => res,
Err(e) => Err(e),
}
}
/// assert_eq!(x.or(y), Ok(2));
/// ```
#[inline]
+ #[rustc_const_unstable(feature = "const_result_drop", issue = "92384")]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn or<F>(self, res: Result<T, F>) -> Result<T, F> {
+ pub const fn or<F>(self, res: Result<T, F>) -> Result<T, F>
+ where
+ T: ~const Drop,
+ E: ~const Drop,
+ F: ~const Drop,
+ {
match self {
Ok(v) => Ok(v),
- Err(_) => res,
+ // FIXME: ~const Drop doesn't quite work right yet
+ #[allow(unused_variables)]
+ Err(e) => res,
}
}
/// assert_eq!(x.unwrap_or(default), default);
/// ```
#[inline]
+ #[rustc_const_unstable(feature = "const_result_drop", issue = "92384")]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn unwrap_or(self, default: T) -> T {
+ pub const fn unwrap_or(self, default: T) -> T
+ where
+ T: ~const Drop,
+ E: ~const Drop,
+ {
match self {
Ok(t) => t,
- Err(_) => default,
+ // FIXME: ~const Drop doesn't quite work right yet
+ #[allow(unused_variables)]
+ Err(e) => default,
}
}
use crate::ptr;
use crate::result::Result;
use crate::result::Result::{Err, Ok};
-#[cfg(not(miri))] // Miri does not support all SIMD intrinsics
+#[cfg(not(all(miri, doctest)))] // Miri skips SIMD doctests
use crate::simd::{self, Simd};
use crate::slice;
/// assert_eq!(basic_simd_sum(&numbers[1..99]), 4949.0);
/// ```
#[unstable(feature = "portable_simd", issue = "86656")]
- #[cfg(not(miri))] // Miri does not support all SIMD intrinsics
+ #[cfg(not(all(miri, doctest)))] // Miri skips SIMD doctests
pub fn as_simd<const LANES: usize>(&self) -> (&[T], &[Simd<T, LANES>], &[T])
where
Simd<T, LANES>: AsRef<[T; LANES]>,
/// be lifted in a way that would make it possible to see panics from this
/// method for something like `LANES == 3`.
#[unstable(feature = "portable_simd", issue = "86656")]
- #[cfg(not(miri))] // Miri does not support all SIMD intrinsics
+ #[cfg(not(all(miri, doctest)))] // Miri skips SIMD doctests
pub fn as_simd_mut<const LANES: usize>(&mut self) -> (&mut [T], &mut [Simd<T, LANES>], &mut [T])
where
Simd<T, LANES>: AsMut<[T; LANES]>,
/// let a = &*AtomicBool::from_mut_slice(&mut some_bools);
/// std::thread::scope(|s| {
/// for i in 0..a.len() {
- /// s.spawn(move |_| a[i].store(true, Ordering::Relaxed));
+ /// s.spawn(move || a[i].store(true, Ordering::Relaxed));
/// }
/// });
/// assert_eq!(some_bools, [true; 10]);
/// let a = &*AtomicPtr::from_mut_slice(&mut some_ptrs);
/// std::thread::scope(|s| {
/// for i in 0..a.len() {
- /// s.spawn(move |_| {
+ /// s.spawn(move || {
/// let name = Box::new(format!("thread{i}"));
/// a[i].store(Box::into_raw(name), Ordering::Relaxed);
/// });
#[doc = concat!("let a = &*", stringify!($atomic_type), "::from_mut_slice(&mut some_ints);")]
/// std::thread::scope(|s| {
/// for i in 0..a.len() {
- /// s.spawn(move |_| a[i].store(i as _, Ordering::Relaxed));
+ /// s.spawn(move || a[i].store(i as _, Ordering::Relaxed));
/// }
/// });
/// for (i, n) in some_ints.into_iter().enumerate() {
-#![cfg(not(miri))] // Miri does not support all SIMD intrinsics
-
use core::simd::f32x4;
#[test]
(take_last_mut_empty, (), None, &mut []),
}
+#[cfg(not(miri))] // unused in Miri
const EMPTY_MAX: &'static [()] = &[(); usize::MAX];
// can't be a constant due to const mutability rules
+#[cfg(not(miri))] // unused in Miri
macro_rules! empty_max_mut {
() => {
&mut [(); usize::MAX] as _
#![feature(rustc_allow_const_fn_unstable)]
#![feature(nll)]
#![feature(staged_api)]
-#![feature(const_fn_trait_bound)]
-#![feature(const_fn_fn_ptr_basics)]
+#![cfg_attr(bootstrap, feature(const_fn_trait_bound))]
+#![cfg_attr(bootstrap, feature(const_fn_fn_ptr_basics))]
#![feature(allow_internal_unstable)]
#![feature(decl_macro)]
#![feature(extern_types)]
pub use self::stdio::set_output_capture;
#[unstable(feature = "print_internals", issue = "none")]
pub use self::stdio::{_eprint, _print};
-#[unstable(feature = "stdio_locked", issue = "86845")]
-pub use self::stdio::{stderr_locked, stdin_locked, stdout_locked};
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::{
buffered::{BufReader, BufWriter, IntoInnerError, LineWriter},
}
}
-/// Constructs a new locked handle to the standard input of the current
-/// process.
-///
-/// Each handle returned is a guard granting locked access to a shared
-/// global buffer whose access is synchronized via a mutex. If you need
-/// more explicit control over locking, for example, in a multi-threaded
-/// program, use the [`io::stdin`] function to obtain an unlocked handle,
-/// along with the [`Stdin::lock`] method.
-///
-/// The lock is released when the returned guard goes out of scope. The
-/// returned guard also implements the [`Read`] and [`BufRead`] traits for
-/// accessing the underlying data.
-///
-/// **Note**: The mutex locked by this handle is not reentrant. Even in a
-/// single-threaded program, calling other code that accesses [`Stdin`]
-/// could cause a deadlock or panic, if this locked handle is held across
-/// that call.
-///
-/// ### Note: Windows Portability Consideration
-/// When operating in a console, the Windows implementation of this stream does not support
-/// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return
-/// an error.
-///
-/// # Examples
-///
-/// ```no_run
-/// #![feature(stdio_locked)]
-/// use std::io::{self, BufRead};
-///
-/// fn main() -> io::Result<()> {
-/// let mut buffer = String::new();
-/// let mut handle = io::stdin_locked();
-///
-/// handle.read_line(&mut buffer)?;
-/// Ok(())
-/// }
-/// ```
-#[unstable(feature = "stdio_locked", issue = "86845")]
-pub fn stdin_locked() -> StdinLock<'static> {
- stdin().into_locked()
-}
-
impl Stdin {
/// Locks this handle to the standard input stream, returning a readable
/// guard.
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn lock(&self) -> StdinLock<'_> {
- self.lock_any()
+ pub fn lock(&self) -> StdinLock<'static> {
+ // Locks this handle with 'static lifetime. This depends on the
+ // implementation detail that the underlying `Mutex` is static.
+ StdinLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) }
}
/// Locks this handle and reads a line of input, appending it to the specified buffer.
self.lock().read_line(buf)
}
- // Locks this handle with any lifetime. This depends on the
- // implementation detail that the underlying `Mutex` is static.
- fn lock_any<'a>(&self) -> StdinLock<'a> {
- StdinLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) }
- }
-
- /// Consumes this handle to the standard input stream, locking the
- /// shared global buffer associated with the stream and returning a
- /// readable guard.
- ///
- /// The lock is released when the returned guard goes out of scope. The
- /// returned guard also implements the [`Read`] and [`BufRead`] traits
- /// for accessing the underlying data.
- ///
- /// It is often simpler to directly get a locked handle using the
- /// [`stdin_locked`] function instead, unless nearby code also needs to
- /// use an unlocked handle.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// #![feature(stdio_locked)]
- /// use std::io::{self, BufRead};
- ///
- /// fn main() -> io::Result<()> {
- /// let mut buffer = String::new();
- /// let mut handle = io::stdin().into_locked();
- ///
- /// handle.read_line(&mut buffer)?;
- /// Ok(())
- /// }
- /// ```
- #[unstable(feature = "stdio_locked", issue = "86845")]
- pub fn into_locked(self) -> StdinLock<'static> {
- self.lock_any()
- }
-
/// Consumes this handle and returns an iterator over input lines.
///
/// For detailed semantics of this method, see the documentation on
#[must_use = "`self` will be dropped if the result is not used"]
#[unstable(feature = "stdin_forwarders", issue = "87096")]
pub fn lines(self) -> Lines<StdinLock<'static>> {
- self.into_locked().lines()
+ self.lock().lines()
}
}
}
}
-/// Constructs a new locked handle to the standard output of the current
-/// process.
-///
-/// Each handle returned is a guard granting locked access to a shared
-/// global buffer whose access is synchronized via a mutex. If you need
-/// more explicit control over locking, for example, in a multi-threaded
-/// program, use the [`io::stdout`] function to obtain an unlocked handle,
-/// along with the [`Stdout::lock`] method.
-///
-/// The lock is released when the returned guard goes out of scope. The
-/// returned guard also implements the [`Write`] trait for writing data.
-///
-/// ### Note: Windows Portability Consideration
-/// When operating in a console, the Windows implementation of this stream does not support
-/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
-/// an error.
-///
-/// # Examples
-///
-/// ```no_run
-/// #![feature(stdio_locked)]
-/// use std::io::{self, Write};
-///
-/// fn main() -> io::Result<()> {
-/// let mut handle = io::stdout_locked();
-///
-/// handle.write_all(b"hello world")?;
-///
-/// Ok(())
-/// }
-/// ```
-#[unstable(feature = "stdio_locked", issue = "86845")]
-pub fn stdout_locked() -> StdoutLock<'static> {
- stdout().into_locked()
-}
-
pub fn cleanup() {
if let Some(instance) = STDOUT.get() {
// Flush the data and disable buffering during shutdown
/// use std::io::{self, Write};
///
/// fn main() -> io::Result<()> {
- /// let stdout = io::stdout();
- /// let mut handle = stdout.lock();
+ /// let mut stdout = io::stdout().lock();
///
- /// handle.write_all(b"hello world")?;
+ /// stdout.write_all(b"hello world")?;
///
/// Ok(())
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn lock(&self) -> StdoutLock<'_> {
- self.lock_any()
- }
-
- // Locks this handle with any lifetime. This depends on the
- // implementation detail that the underlying `ReentrantMutex` is
- // static.
- fn lock_any<'a>(&self) -> StdoutLock<'a> {
+ pub fn lock(&self) -> StdoutLock<'static> {
+ // Locks this handle with 'static lifetime. This depends on the
+ // implementation detail that the underlying `ReentrantMutex` is
+ // static.
StdoutLock { inner: self.inner.lock() }
}
-
- /// Consumes this handle to the standard output stream, locking the
- /// shared global buffer associated with the stream and returning a
- /// writable guard.
- ///
- /// The lock is released when the returned lock goes out of scope. The
- /// returned guard also implements the [`Write`] trait for writing data.
- ///
- /// It is often simpler to directly get a locked handle using the
- /// [`io::stdout_locked`] function instead, unless nearby code also
- /// needs to use an unlocked handle.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// #![feature(stdio_locked)]
- /// use std::io::{self, Write};
- ///
- /// fn main() -> io::Result<()> {
- /// let mut handle = io::stdout().into_locked();
- ///
- /// handle.write_all(b"hello world")?;
- ///
- /// Ok(())
- /// }
- /// ```
- #[unstable(feature = "stdio_locked", issue = "86845")]
- pub fn into_locked(self) -> StdoutLock<'static> {
- self.lock_any()
- }
}
#[stable(feature = "std_debug", since = "1.16.0")]
}
}
-/// Constructs a new locked handle to the standard error of the current
-/// process.
-///
-/// This handle is not buffered.
-///
-/// ### Note: Windows Portability Consideration
-/// When operating in a console, the Windows implementation of this stream does not support
-/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
-/// an error.
-///
-/// # Example
-///
-/// ```no_run
-/// #![feature(stdio_locked)]
-/// use std::io::{self, Write};
-///
-/// fn main() -> io::Result<()> {
-/// let mut handle = io::stderr_locked();
-///
-/// handle.write_all(b"hello world")?;
-///
-/// Ok(())
-/// }
-/// ```
-#[unstable(feature = "stdio_locked", issue = "86845")]
-pub fn stderr_locked() -> StderrLock<'static> {
- stderr().into_locked()
-}
-
impl Stderr {
/// Locks this handle to the standard error stream, returning a writable
/// guard.
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn lock(&self) -> StderrLock<'_> {
- self.lock_any()
- }
-
- // Locks this handle with any lifetime. This depends on the
- // implementation detail that the underlying `ReentrantMutex` is
- // static.
- fn lock_any<'a>(&self) -> StderrLock<'a> {
+ pub fn lock(&self) -> StderrLock<'static> {
+ // Locks this handle with 'static lifetime. This depends on the
+ // implementation detail that the underlying `ReentrantMutex` is
+ // static.
StderrLock { inner: self.inner.lock() }
}
-
- /// Locks and consumes this handle to the standard error stream,
- /// returning a writable guard.
- ///
- /// The lock is released when the returned guard goes out of scope. The
- /// returned guard also implements the [`Write`] trait for writing
- /// data.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(stdio_locked)]
- /// use std::io::{self, Write};
- ///
- /// fn foo() -> io::Result<()> {
- /// let stderr = io::stderr();
- /// let mut handle = stderr.into_locked();
- ///
- /// handle.write_all(b"hello world")?;
- ///
- /// Ok(())
- /// }
- /// ```
- #[unstable(feature = "stdio_locked", issue = "86845")]
- pub fn into_locked(self) -> StderrLock<'static> {
- self.lock_any()
- }
}
#[stable(feature = "std_debug", since = "1.16.0")]
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn test_lock_stderr() {
- test_lock(stderr, stderr_locked);
+ test_lock(stderr, || stderr().lock());
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn test_lock_stdin() {
- test_lock(stdin, stdin_locked);
+ test_lock(stdin, || stdin().lock());
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn test_lock_stdout() {
- test_lock(stdout, stdout_locked);
+ test_lock(stdout, || stdout().lock());
}
// Helper trait to make lock testing function generic.
#![needs_panic_runtime]
// std may use features in a platform-specific way
#![allow(unused_features)]
-#![feature(rustc_allow_const_fn_unstable)]
#![cfg_attr(test, feature(internal_output_capture, print_internals, update_panic_count))]
#![cfg_attr(
all(target_vendor = "fortanix", target_env = "sgx"),
// std is implemented with unstable features, many of which are internal
// compiler details that will never be stable
// NB: the following list is sorted to minimize merge conflicts.
-#![feature(absolute_path)]
#![feature(alloc_error_handler)]
#![feature(alloc_layout_extra)]
#![feature(allocator_api)]
#![feature(allocator_internals)]
#![feature(allow_internal_unsafe)]
#![feature(allow_internal_unstable)]
-#![feature(arbitrary_self_types)]
#![feature(array_error_internals)]
#![feature(assert_matches)]
#![feature(associated_type_bounds)]
#![feature(async_iterator)]
#![feature(atomic_mut_ptr)]
-#![feature(auto_traits)]
#![feature(bench_black_box)]
-#![feature(bool_to_option)]
#![feature(box_syntax)]
#![feature(c_unwind)]
#![feature(c_variadic)]
#![feature(char_internals)]
#![feature(concat_bytes)]
#![feature(concat_idents)]
-#![feature(const_fn_floating_point_arithmetic)]
-#![feature(const_fn_fn_ptr_basics)]
-#![feature(const_fn_trait_bound)]
+#![cfg_attr(bootstrap, feature(const_fn_fn_ptr_basics))]
+#![cfg_attr(bootstrap, feature(const_fn_trait_bound))]
#![feature(const_format_args)]
#![feature(const_io_structs)]
#![feature(const_ip)]
#![feature(const_ipv4)]
#![feature(const_ipv6)]
-#![feature(const_option)]
#![feature(const_mut_refs)]
+#![feature(const_option)]
#![feature(const_socketaddr)]
#![feature(const_trait_impl)]
-#![feature(container_error_extra)]
#![feature(c_size_t)]
#![feature(core_ffi_c)]
#![feature(core_intrinsics)]
#![feature(exact_size_is_empty)]
#![feature(exhaustive_patterns)]
#![feature(extend_one)]
-#![feature(fn_traits)]
#![feature(float_minimum_maximum)]
#![feature(format_args_nl)]
-#![feature(gen_future)]
-#![feature(generator_trait)]
#![feature(get_mut_unchecked)]
#![feature(hashmap_internals)]
#![feature(int_error_internals)]
-#![feature(integer_atomics)]
-#![feature(int_log)]
-#![feature(into_future)]
#![feature(intra_doc_pointers)]
#![feature(lang_items)]
#![feature(linkage)]
#![feature(log_syntax)]
#![feature(map_try_insert)]
#![feature(maybe_uninit_slice)]
-#![feature(maybe_uninit_uninit_array)]
#![feature(maybe_uninit_write_slice)]
#![feature(min_specialization)]
#![feature(mixed_integer_ops)]
#![feature(portable_simd)]
#![feature(prelude_import)]
#![feature(ptr_as_uninit)]
-#![feature(ptr_internals)]
#![feature(raw_os_nonzero)]
#![feature(rustc_attrs)]
-#![feature(rustc_private)]
#![feature(saturating_int_impl)]
-#![feature(slice_concat_ext)]
#![feature(slice_internals)]
#![feature(slice_ptr_get)]
-#![feature(slice_ptr_len)]
#![feature(staged_api)]
#![feature(std_internals)]
#![feature(stdsimd)]
-#![feature(stmt_expr_attributes)]
#![feature(str_internals)]
#![feature(test)]
#![feature(thread_local)]
#![feature(trace_macros)]
#![feature(try_blocks)]
#![feature(try_reserve_kind)]
-#![feature(unboxed_closures)]
-#![feature(unwrap_infallible)]
#![feature(vec_into_raw_parts)]
// NB: the above list is sorted to minimize merge conflicts.
#![default_lib_allocator]
//! * [`ToSocketAddrs`] is a trait that used for generic address resolution when interacting
//! with networking objects like [`TcpListener`], [`TcpStream`] or [`UdpSocket`]
//! * Other types are return or parameter types for various methods in this module
+//!
+//! Rust disables inheritance of socket objects to child processes by default when possible. For
+//! example, through the use of the `CLOEXEC` flag in UNIX systems or the `HANDLE_FLAG_INHERIT`
+//! flag on Windows.
#![stable(feature = "rust1", since = "1.0.0")]
}
#[test]
-#[cfg(unix)] // test doesn't work on Windows, see #31657
fn close_read_wakes_up() {
each_ip(&mut |addr| {
let a = t!(TcpListener::bind(&addr));
/// # Examples
///
/// ```no_run
+ /// # #![allow(unexpected_cfgs)]
/// # #[cfg(for_demonstration_only)]
/// extern crate winapi;
/// # mod winapi { pub const FILE_FLAG_DELETE_ON_CLOSE: u32 = 0x04000000; }
/// # Examples
///
/// ```no_run
+ /// # #![allow(unexpected_cfgs)]
/// # #[cfg(for_demonstration_only)]
/// extern crate winapi;
/// # mod winapi { pub const FILE_ATTRIBUTE_HIDDEN: u32 = 2; }
/// # Examples
///
/// ```no_run
+ /// # #![allow(unexpected_cfgs)]
/// # #[cfg(for_demonstration_only)]
/// extern crate winapi;
/// # mod winapi { pub const SECURITY_IDENTIFICATION: u32 = 0; }
/// [`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: RawHandle,
let relative = "a/b";
let mut expected = crate::env::current_dir().unwrap();
expected.push(relative);
- assert_eq!(absolute(relative).unwrap(), expected);
+ assert_eq!(absolute(relative).unwrap().as_os_str(), expected.as_os_str());
// Test how components are collected.
- assert_eq!(absolute("/a/b/c").unwrap(), Path::new("/a/b/c"));
- assert_eq!(absolute("/a//b/c").unwrap(), Path::new("/a/b/c"));
- assert_eq!(absolute("//a/b/c").unwrap(), Path::new("//a/b/c"));
- assert_eq!(absolute("///a/b/c").unwrap(), Path::new("/a/b/c"));
- assert_eq!(absolute("/a/b/c/").unwrap(), Path::new("/a/b/c/"));
- assert_eq!(absolute("/a/./b/../c/.././..").unwrap(), Path::new("/a/b/../c/../.."));
+ assert_eq!(absolute("/a/b/c").unwrap().as_os_str(), Path::new("/a/b/c").as_os_str());
+ assert_eq!(absolute("/a//b/c").unwrap().as_os_str(), Path::new("/a/b/c").as_os_str());
+ assert_eq!(absolute("//a/b/c").unwrap().as_os_str(), Path::new("//a/b/c").as_os_str());
+ assert_eq!(absolute("///a/b/c").unwrap().as_os_str(), Path::new("/a/b/c").as_os_str());
+ assert_eq!(absolute("/a/b/c/").unwrap().as_os_str(), Path::new("/a/b/c/").as_os_str());
+ assert_eq!(
+ absolute("/a/./b/../c/.././..").unwrap().as_os_str(),
+ Path::new("/a/b/../c/../..").as_os_str()
+ );
+
+ // Test leading `.` and `..` components
+ let curdir = crate::env::current_dir().unwrap();
+ assert_eq!(absolute("./a").unwrap().as_os_str(), curdir.join("a").as_os_str());
+ assert_eq!(absolute("../a").unwrap().as_os_str(), curdir.join("../a").as_os_str()); // return /pwd/../a
}
#[test]
///
/// [poison]: struct.Mutex.html#poisoning
#[stable(feature = "rust1", since = "1.0.0")]
+ #[track_caller]
pub fn call_once<F>(&self, f: F)
where
F: FnOnce(),
// currently no way to take an `FnOnce` and call it via virtual dispatch
// without some allocation overhead.
#[cold]
+ #[track_caller]
fn call_inner(&self, ignore_poisoning: bool, init: &mut dyn FnMut(&OnceState)) {
let mut state_and_queue = self.state_and_queue.load(Ordering::Acquire);
loop {
unsafe impl Send for Dir {}
unsafe impl Sync for Dir {}
+#[cfg(any(
+ target_os = "android",
+ target_os = "linux",
+ target_os = "solaris",
+ target_os = "illumos",
+ target_os = "fuchsia",
+ target_os = "redox"
+))]
pub struct DirEntry {
- entry: dirent64,
dir: Arc<InnerReadDir>,
+ entry: dirent64_min,
// We need to store an owned copy of the entry name on platforms that use
// readdir() (not readdir_r()), because a) struct dirent may use a flexible
// array to store the name, b) it lives only until the next readdir() call.
- #[cfg(any(
- target_os = "android",
- target_os = "linux",
- target_os = "solaris",
- target_os = "illumos",
- target_os = "fuchsia",
- target_os = "redox"
- ))]
name: CString,
}
+// Define a minimal subset of fields we need from `dirent64`, especially since
+// we're not using the immediate `d_name` on these targets. Keeping this as an
+// `entry` field in `DirEntry` helps reduce the `cfg` boilerplate elsewhere.
+#[cfg(any(
+ target_os = "android",
+ target_os = "linux",
+ target_os = "solaris",
+ target_os = "illumos",
+ target_os = "fuchsia",
+ target_os = "redox"
+))]
+struct dirent64_min {
+ d_ino: u64,
+ #[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
+ d_type: u8,
+}
+
+#[cfg(not(any(
+ target_os = "android",
+ target_os = "linux",
+ target_os = "solaris",
+ target_os = "illumos",
+ target_os = "fuchsia",
+ target_os = "redox"
+)))]
+pub struct DirEntry {
+ dir: Arc<InnerReadDir>,
+ // The full entry includes a fixed-length `d_name`.
+ entry: dirent64,
+}
+
#[derive(Clone, Debug)]
pub struct OpenOptions {
// generic
// Only d_reclen bytes of *entry_ptr are valid, so we can't just copy the
// whole thing (#93384). Instead, copy everything except the name.
+ let mut copy: dirent64 = mem::zeroed();
+ // Can't dereference entry_ptr, so use the local entry to get
+ // offsetof(struct dirent, d_name)
+ let copy_bytes = &mut copy as *mut _ as *mut u8;
+ let copy_name = &mut copy.d_name as *mut _ as *mut u8;
+ let name_offset = copy_name.offset_from(copy_bytes) as usize;
let entry_bytes = entry_ptr as *const u8;
- let entry_name = ptr::addr_of!((*entry_ptr).d_name) as *const u8;
- let name_offset = entry_name.offset_from(entry_bytes) as usize;
- let mut entry: dirent64 = mem::zeroed();
- ptr::copy_nonoverlapping(entry_bytes, &mut entry as *mut _ as *mut u8, name_offset);
+ let entry_name = entry_bytes.add(name_offset);
+ ptr::copy_nonoverlapping(entry_bytes, copy_bytes, name_offset);
+
+ let entry = dirent64_min {
+ d_ino: copy.d_ino as u64,
+ #[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
+ d_type: copy.d_type as u8,
+ };
let ret = DirEntry {
entry,
pub use crate::sys_common::fs::remove_dir_all;
}
-// Dynamically choose implementation Macos x86-64: modern for 10.10+, fallback for older versions
-#[cfg(all(target_os = "macos", target_arch = "x86_64"))]
+// Modern implementation using openat(), unlinkat() and fdopendir()
+#[cfg(not(any(target_os = "redox", target_os = "espidf")))]
mod remove_dir_impl {
- use super::{cstr, lstat, Dir, InnerReadDir, ReadDir};
+ use super::{cstr, lstat, Dir, DirEntry, InnerReadDir, ReadDir};
use crate::ffi::CStr;
use crate::io;
use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
use crate::os::unix::prelude::{OwnedFd, RawFd};
use crate::path::{Path, PathBuf};
use crate::sync::Arc;
- use crate::sys::weak::weak;
use crate::sys::{cvt, cvt_r};
- use libc::{c_char, c_int, DIR};
- pub fn openat_nofollow_dironly(parent_fd: Option<RawFd>, p: &CStr) -> io::Result<OwnedFd> {
- weak!(fn openat(c_int, *const c_char, c_int) -> c_int);
- let fd = cvt_r(|| unsafe {
- openat.get().unwrap()(
- parent_fd.unwrap_or(libc::AT_FDCWD),
- p.as_ptr(),
- libc::O_CLOEXEC | libc::O_RDONLY | libc::O_NOFOLLOW | libc::O_DIRECTORY,
- )
- })?;
- Ok(unsafe { OwnedFd::from_raw_fd(fd) })
- }
-
- fn fdreaddir(dir_fd: OwnedFd) -> io::Result<(ReadDir, RawFd)> {
- weak!(fn fdopendir(c_int) -> *mut DIR, "fdopendir$INODE64");
- let ptr = unsafe { fdopendir.get().unwrap()(dir_fd.as_raw_fd()) };
- if ptr.is_null() {
- return Err(io::Error::last_os_error());
- }
- let dirp = Dir(ptr);
- // file descriptor is automatically closed by libc::closedir() now, so give up ownership
- let new_parent_fd = dir_fd.into_raw_fd();
- // a valid root is not needed because we do not call any functions involving the full path
- // of the DirEntrys.
- let dummy_root = PathBuf::new();
- Ok((
- ReadDir {
- inner: Arc::new(InnerReadDir { dirp, root: dummy_root }),
- end_of_stream: false,
- },
- new_parent_fd,
- ))
- }
-
- fn remove_dir_all_recursive(parent_fd: Option<RawFd>, p: &Path) -> io::Result<()> {
- weak!(fn unlinkat(c_int, *const c_char, c_int) -> c_int);
+ #[cfg(not(all(target_os = "macos", target_arch = "x86_64"),))]
+ use libc::{fdopendir, openat, unlinkat};
+ #[cfg(all(target_os = "macos", target_arch = "x86_64"))]
+ use macos_weak::{fdopendir, openat, unlinkat};
- let pcstr = cstr(p)?;
+ #[cfg(all(target_os = "macos", target_arch = "x86_64"))]
+ mod macos_weak {
+ use crate::sys::weak::weak;
+ use libc::{c_char, c_int, DIR};
- // entry is expected to be a directory, open as such
- let fd = openat_nofollow_dironly(parent_fd, &pcstr)?;
+ fn get_openat_fn() -> Option<unsafe extern "C" fn(c_int, *const c_char, c_int) -> c_int> {
+ weak!(fn openat(c_int, *const c_char, c_int) -> c_int);
+ openat.get()
+ }
- // open the directory passing ownership of the fd
- let (dir, fd) = fdreaddir(fd)?;
- for child in dir {
- let child = child?;
- match child.entry.d_type {
- libc::DT_DIR => {
- remove_dir_all_recursive(Some(fd), Path::new(&child.file_name()))?;
- }
- libc::DT_UNKNOWN => {
- match cvt(unsafe { unlinkat.get().unwrap()(fd, child.name_cstr().as_ptr(), 0) })
- {
- // type unknown - try to unlink
- Err(err) if err.raw_os_error() == Some(libc::EPERM) => {
- // if the file is a directory unlink fails with EPERM
- remove_dir_all_recursive(Some(fd), Path::new(&child.file_name()))?;
- }
- result => {
- result?;
- }
- }
- }
- _ => {
- // not a directory -> unlink
- cvt(unsafe { unlinkat.get().unwrap()(fd, child.name_cstr().as_ptr(), 0) })?;
- }
- }
+ pub fn has_openat() -> bool {
+ get_openat_fn().is_some()
}
- // unlink the directory after removing its contents
- cvt(unsafe {
- unlinkat.get().unwrap()(
- parent_fd.unwrap_or(libc::AT_FDCWD),
- pcstr.as_ptr(),
- libc::AT_REMOVEDIR,
- )
- })?;
- Ok(())
- }
+ pub unsafe fn openat(dirfd: c_int, pathname: *const c_char, flags: c_int) -> c_int {
+ get_openat_fn().map(|openat| openat(dirfd, pathname, flags)).unwrap_or_else(|| {
+ crate::sys::unix::os::set_errno(libc::ENOSYS);
+ -1
+ })
+ }
- fn remove_dir_all_modern(p: &Path) -> io::Result<()> {
- // We cannot just call remove_dir_all_recursive() here because that would not delete a passed
- // symlink. No need to worry about races, because remove_dir_all_recursive() does not recurse
- // into symlinks.
- let attr = lstat(p)?;
- if attr.file_type().is_symlink() {
- crate::fs::remove_file(p)
- } else {
- remove_dir_all_recursive(None, p)
+ pub unsafe fn fdopendir(fd: c_int) -> *mut DIR {
+ weak!(fn fdopendir(c_int) -> *mut DIR, "fdopendir$INODE64");
+ fdopendir.get().map(|fdopendir| fdopendir(fd)).unwrap_or_else(|| {
+ crate::sys::unix::os::set_errno(libc::ENOSYS);
+ crate::ptr::null_mut()
+ })
}
- }
- pub fn remove_dir_all(p: &Path) -> io::Result<()> {
- weak!(fn openat(c_int, *const c_char, c_int) -> c_int);
- if openat.get().is_some() {
- // openat() is available with macOS 10.10+, just like unlinkat() and fdopendir()
- remove_dir_all_modern(p)
- } else {
- // fall back to classic implementation
- crate::sys_common::fs::remove_dir_all(p)
+ pub unsafe fn unlinkat(dirfd: c_int, pathname: *const c_char, flags: c_int) -> c_int {
+ weak!(fn unlinkat(c_int, *const c_char, c_int) -> c_int);
+ unlinkat.get().map(|unlinkat| unlinkat(dirfd, pathname, flags)).unwrap_or_else(|| {
+ crate::sys::unix::os::set_errno(libc::ENOSYS);
+ -1
+ })
}
}
-}
-
-// Modern implementation using openat(), unlinkat() and fdopendir()
-#[cfg(not(any(
- all(target_os = "macos", target_arch = "x86_64"),
- target_os = "redox",
- target_os = "espidf"
-)))]
-mod remove_dir_impl {
- use super::{cstr, lstat, Dir, DirEntry, InnerReadDir, ReadDir};
- use crate::ffi::CStr;
- use crate::io;
- use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
- use crate::os::unix::prelude::{OwnedFd, RawFd};
- use crate::path::{Path, PathBuf};
- use crate::sync::Arc;
- use crate::sys::{cvt, cvt_r};
- use libc::{fdopendir, openat, unlinkat};
pub fn openat_nofollow_dironly(parent_fd: Option<RawFd>, p: &CStr) -> io::Result<OwnedFd> {
let fd = cvt_r(|| unsafe {
}
}
- fn remove_dir_all_recursive(parent_fd: Option<RawFd>, p: &Path) -> io::Result<()> {
- let pcstr = cstr(p)?;
-
- // entry is expected to be a directory, open as such
- let fd = openat_nofollow_dironly(parent_fd, &pcstr)?;
+ fn remove_dir_all_recursive(parent_fd: Option<RawFd>, path: &CStr) -> io::Result<()> {
+ // try opening as directory
+ let fd = match openat_nofollow_dironly(parent_fd, &path) {
+ Err(err) if err.raw_os_error() == Some(libc::ENOTDIR) => {
+ // not a directory - don't traverse further
+ return match parent_fd {
+ // unlink...
+ Some(parent_fd) => {
+ cvt(unsafe { unlinkat(parent_fd, path.as_ptr(), 0) }).map(drop)
+ }
+ // ...unless this was supposed to be the deletion root directory
+ None => Err(err),
+ };
+ }
+ result => result?,
+ };
// open the directory passing ownership of the fd
let (dir, fd) = fdreaddir(fd)?;
for child in dir {
let child = child?;
+ let child_name = child.name_cstr();
match is_dir(&child) {
Some(true) => {
- remove_dir_all_recursive(Some(fd), Path::new(&child.file_name()))?;
+ remove_dir_all_recursive(Some(fd), child_name)?;
}
Some(false) => {
- cvt(unsafe { unlinkat(fd, child.name_cstr().as_ptr(), 0) })?;
+ cvt(unsafe { unlinkat(fd, child_name.as_ptr(), 0) })?;
+ }
+ None => {
+ // POSIX specifies that calling unlink()/unlinkat(..., 0) on a directory can succeed
+ // if the process has the appropriate privileges. This however can causing orphaned
+ // directories requiring an fsck e.g. on Solaris and Illumos. So we try recursing
+ // into it first instead of trying to unlink() it.
+ remove_dir_all_recursive(Some(fd), child_name)?;
}
- None => match cvt(unsafe { unlinkat(fd, child.name_cstr().as_ptr(), 0) }) {
- // type unknown - try to unlink
- Err(err)
- if err.raw_os_error() == Some(libc::EISDIR)
- || err.raw_os_error() == Some(libc::EPERM) =>
- {
- // if the file is a directory unlink fails with EISDIR on Linux and EPERM everyhwere else
- remove_dir_all_recursive(Some(fd), Path::new(&child.file_name()))?;
- }
- result => {
- result?;
- }
- },
}
}
// unlink the directory after removing its contents
cvt(unsafe {
- unlinkat(parent_fd.unwrap_or(libc::AT_FDCWD), pcstr.as_ptr(), libc::AT_REMOVEDIR)
+ unlinkat(parent_fd.unwrap_or(libc::AT_FDCWD), path.as_ptr(), libc::AT_REMOVEDIR)
})?;
Ok(())
}
- pub fn remove_dir_all(p: &Path) -> io::Result<()> {
+ fn remove_dir_all_modern(p: &Path) -> io::Result<()> {
// We cannot just call remove_dir_all_recursive() here because that would not delete a passed
// symlink. No need to worry about races, because remove_dir_all_recursive() does not recurse
// into symlinks.
if attr.file_type().is_symlink() {
crate::fs::remove_file(p)
} else {
- remove_dir_all_recursive(None, p)
+ remove_dir_all_recursive(None, &cstr(p)?)
+ }
+ }
+
+ #[cfg(not(all(target_os = "macos", target_arch = "x86_64")))]
+ pub fn remove_dir_all(p: &Path) -> io::Result<()> {
+ remove_dir_all_modern(p)
+ }
+
+ #[cfg(all(target_os = "macos", target_arch = "x86_64"))]
+ pub fn remove_dir_all(p: &Path) -> io::Result<()> {
+ if macos_weak::has_openat() {
+ // openat() is available with macOS 10.10+, just like unlinkat() and fdopendir()
+ remove_dir_all_modern(p)
+ } else {
+ // fall back to classic implementation
+ crate::sys_common::fs::remove_dir_all(p)
}
}
}
// See 4.13 Pathname Resolution, IEEE Std 1003.1-2017
// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13
- let mut components = path.components();
+ // Get the components, skipping the redundant leading "." component if it exists.
+ let mut components = path.strip_prefix(".").unwrap_or(path).components();
let path_os = path.as_os_str().bytes();
let mut normalized = if path.is_absolute() {
}
panic!("rwlock read lock would result in deadlock");
} else {
- // According to POSIX, for a properly initialized rwlock this can only
- // return EAGAIN or EDEADLK or 0. We rely on that.
- debug_assert_eq!(r, 0);
+ // POSIX does not make guarantees about all the errors that may be returned.
+ // See issue #94705 for more details.
+ assert_eq!(r, 0, "unexpected error during rwlock read lock: {:?}", r);
self.num_readers.fetch_add(1, Ordering::Relaxed);
}
}
))] {
#[cfg(any(target_os = "android", target_os = "linux"))]
{
+ let quota = cgroup2_quota().max(1);
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) });
+ unsafe {
+ if libc::sched_getaffinity(0, mem::size_of::<libc::cpu_set_t>(), &mut set) == 0 {
+ let count = libc::CPU_COUNT(&set) as usize;
+ let count = count.min(quota);
+ // SAFETY: affinity mask can't be empty and the quota gets clamped to a minimum of 1
+ return Ok(NonZeroUsize::new_unchecked(count));
+ }
}
}
match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } {
}
}
+/// Returns cgroup CPU quota in core-equivalents, rounded down, or usize::MAX if the quota cannot
+/// be determined or is not set.
+#[cfg(any(target_os = "android", target_os = "linux"))]
+fn cgroup2_quota() -> usize {
+ use crate::ffi::OsString;
+ use crate::fs::{try_exists, File};
+ use crate::io::Read;
+ use crate::os::unix::ffi::OsStringExt;
+ use crate::path::PathBuf;
+
+ let mut quota = usize::MAX;
+ if cfg!(miri) {
+ // Attempting to open a file fails under default flags due to isolation.
+ // And Miri does not have parallelism anyway.
+ return quota;
+ }
+
+ let _: Option<()> = try {
+ let mut buf = Vec::with_capacity(128);
+ // find our place in the cgroup hierarchy
+ File::open("/proc/self/cgroup").ok()?.read_to_end(&mut buf).ok()?;
+ let cgroup_path = buf
+ .split(|&c| c == b'\n')
+ .filter_map(|line| {
+ let mut fields = line.splitn(3, |&c| c == b':');
+ // expect cgroupv2 which has an empty 2nd field
+ if fields.nth(1) != Some(b"") {
+ return None;
+ }
+ let path = fields.last()?;
+ // skip leading slash
+ Some(path[1..].to_owned())
+ })
+ .next()?;
+ let cgroup_path = PathBuf::from(OsString::from_vec(cgroup_path));
+
+ let mut path = PathBuf::with_capacity(128);
+ let mut read_buf = String::with_capacity(20);
+
+ let cgroup_mount = "/sys/fs/cgroup";
+
+ path.push(cgroup_mount);
+ path.push(&cgroup_path);
+
+ path.push("cgroup.controllers");
+
+ // skip if we're not looking at cgroup2
+ if matches!(try_exists(&path), Err(_) | Ok(false)) {
+ return usize::MAX;
+ };
+
+ path.pop();
+
+ while path.starts_with(cgroup_mount) {
+ path.push("cpu.max");
+
+ read_buf.clear();
+
+ if File::open(&path).and_then(|mut f| f.read_to_string(&mut read_buf)).is_ok() {
+ let raw_quota = read_buf.lines().next()?;
+ let mut raw_quota = raw_quota.split(' ');
+ let limit = raw_quota.next()?;
+ let period = raw_quota.next()?;
+ match (limit.parse::<usize>(), period.parse::<usize>()) {
+ (Ok(limit), Ok(period)) => {
+ quota = quota.min(limit / period);
+ }
+ _ => {}
+ }
+ }
+
+ path.pop(); // pop filename
+ path.pop(); // pop dir
+ }
+ };
+
+ quota
+}
+
#[cfg(all(
not(target_os = "linux"),
not(target_os = "freebsd"),
use crate::mem;
use crate::os::raw::{c_char, c_int, c_long, c_longlong, c_uint, c_ulong, c_ushort};
+use crate::os::windows::io::{BorrowedHandle, HandleOrInvalid, HandleOrNull};
use crate::ptr;
use core::ffi::NonZero_c_ulong;
lpParameter: LPVOID,
dwCreationFlags: DWORD,
lpThreadId: LPDWORD,
- ) -> HANDLE;
+ ) -> HandleOrNull;
pub fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD;
pub fn SwitchToThread() -> BOOL;
pub fn Sleep(dwMilliseconds: DWORD);
dwOptions: DWORD,
) -> BOOL;
pub fn ReadFile(
- hFile: HANDLE,
+ hFile: BorrowedHandle<'_>,
lpBuffer: LPVOID,
nNumberOfBytesToRead: DWORD,
lpNumberOfBytesRead: LPDWORD,
lpOverlapped: LPOVERLAPPED,
) -> BOOL;
pub fn WriteFile(
- hFile: HANDLE,
+ hFile: BorrowedHandle<'_>,
lpBuffer: LPVOID,
nNumberOfBytesToWrite: DWORD,
lpNumberOfBytesWritten: LPDWORD,
dwCreationDisposition: DWORD,
dwFlagsAndAttributes: DWORD,
hTemplateFile: HANDLE,
- ) -> HANDLE;
+ ) -> HandleOrInvalid;
pub fn FindFirstFileW(fileName: LPCWSTR, findFileData: LPWIN32_FIND_DATAW) -> HANDLE;
pub fn FindNextFileW(findFile: HANDLE, findFileData: LPWIN32_FIND_DATAW) -> BOOL;
use crate::os::windows::prelude::*;
+use crate::convert::TryInto;
use crate::ffi::OsString;
use crate::fmt;
use crate::io::{self, Error, IoSlice, IoSliceMut, ReadBuf, SeekFrom};
ptr::null_mut(),
)
};
- if handle == c::INVALID_HANDLE_VALUE {
- Err(Error::last_os_error())
+ if let Ok(handle) = handle.try_into() {
+ Ok(File { handle: Handle::from_inner(handle) })
} else {
- unsafe { Ok(File { handle: Handle::from_raw_handle(handle) }) }
+ Err(Error::last_os_error())
}
}
let len = cmp::min(buf.len(), <c::DWORD>::MAX as usize) as c::DWORD;
let res = cvt(unsafe {
c::ReadFile(
- self.as_raw_handle(),
+ self.as_handle(),
buf.as_mut_ptr() as c::LPVOID,
len,
&mut read,
overlapped.Offset = offset as u32;
overlapped.OffsetHigh = (offset >> 32) as u32;
cvt(c::ReadFile(
- self.as_raw_handle(),
+ self.as_handle(),
buf.as_mut_ptr() as c::LPVOID,
len,
&mut read,
let len = cmp::min(buf.remaining(), <c::DWORD>::MAX as usize) as c::DWORD;
let res = cvt(unsafe {
c::ReadFile(
- self.as_raw_handle(),
+ self.as_handle(),
buf.unfilled_mut().as_mut_ptr() as c::LPVOID,
len,
&mut read,
let len = cmp::min(buf.len(), <c::DWORD>::MAX as usize) as c::DWORD;
let mut amt = 0;
let res = cvt(c::ReadFile(
- self.as_raw_handle(),
+ self.as_handle(),
buf.as_ptr() as c::LPVOID,
len,
&mut amt,
let len = cmp::min(buf.len(), <c::DWORD>::MAX as usize) as c::DWORD;
cvt(unsafe {
c::WriteFile(
- self.as_raw_handle(),
+ self.as_handle(),
buf.as_ptr() as c::LPVOID,
len,
&mut amt,
overlapped.Offset = offset as u32;
overlapped.OffsetHigh = (offset >> 32) as u32;
cvt(c::WriteFile(
- self.as_raw_handle(),
+ self.as_handle(),
buf.as_ptr() as c::LPVOID,
len,
&mut written,
} as usize;
if k == n && c::GetLastError() == c::ERROR_INSUFFICIENT_BUFFER {
n *= 2;
- } else if k >= n {
+ } else if k > n {
n = k;
+ } else if k == n {
+ // It is impossible to reach this point.
+ // On success, k is the returned string length excluding the null.
+ // On failure, k is the required buffer length including the null.
+ // Therefore k never equals n.
+ unreachable!();
} else {
return Ok(f2(&buf[..k]));
}
+use crate::convert::TryInto;
use crate::ffi::CStr;
use crate::io;
use crate::num::NonZeroUsize;
-use crate::os::windows::io::{AsRawHandle, FromRawHandle};
+use crate::os::windows::io::AsRawHandle;
use crate::ptr;
use crate::sys::c;
use crate::sys::handle::Handle;
use crate::sys::stack_overflow;
+use crate::sys_common::FromInner;
use crate::time::Duration;
use libc::c_void;
// PTHREAD_STACK_MIN bytes big. Windows has no such lower limit, it's
// just that below a certain threshold you can't do anything useful.
// That threshold is application and architecture-specific, however.
- // Round up to the next 64 kB because that's what the NT kernel does,
- // might as well make it explicit.
- let stack_size = (stack + 0xfffe) & (!0xfffe);
let ret = c::CreateThread(
ptr::null_mut(),
- stack_size,
+ stack,
thread_start,
p as *mut _,
c::STACK_SIZE_PARAM_IS_A_RESERVATION,
ptr::null_mut(),
);
- return if ret as usize == 0 {
+ return if let Ok(handle) = ret.try_into() {
+ Ok(Thread { handle: Handle::from_inner(handle) })
+ } else {
// The thread failed to start and as a result p was not consumed. Therefore, it is
// safe to reconstruct the box so that it gets deallocated.
drop(Box::from_raw(p));
Err(io::Error::last_os_error())
- } else {
- Ok(Thread { handle: Handle::from_raw_handle(ret) })
};
extern "system" fn thread_start(main: *mut c_void) -> c::DWORD {
#[cfg(test)]
mod dynamic_tests;
+use crate::cell::{Cell, RefCell};
use crate::error::Error;
use crate::fmt;
// trivially devirtualizable by LLVM because the value of `inner` never
// changes and the constant should be readonly within a crate. This mainly
// only runs into problems when TLS statics are exported across crates.
- inner: unsafe fn() -> Option<&'static T>,
+ inner: unsafe fn(Option<&mut Option<T>>) -> Option<&'static T>,
}
#[stable(feature = "std_debug", since = "1.16.0")]
// used to generate the `LocalKey` value for const-initialized thread locals
(@key $t:ty, const $init:expr) => {{
#[cfg_attr(not(windows), inline(always))] // see comments below
- unsafe fn __getit() -> $crate::option::Option<&'static $t> {
+ unsafe fn __getit(
+ _init: $crate::option::Option<&mut $crate::option::Option<$t>>,
+ ) -> $crate::option::Option<&'static $t> {
const INIT_EXPR: $t = $init;
// wasm without atomics maps directly to `static mut`, and dtors
static __KEY: $crate::thread::__OsLocalKeyInner<$t> =
$crate::thread::__OsLocalKeyInner::new();
#[allow(unused_unsafe)]
- unsafe { __KEY.get(__init) }
+ unsafe {
+ __KEY.get(move || {
+ if let $crate::option::Option::Some(init) = _init {
+ if let $crate::option::Option::Some(value) = init.take() {
+ return value;
+ } else if $crate::cfg!(debug_assertions) {
+ unreachable!("missing initial value");
+ }
+ }
+ __init()
+ })
+ }
}
}
//
// The issue of "should enable on Windows sometimes" is #84933
#[cfg_attr(not(windows), inline(always))]
- unsafe fn __getit() -> $crate::option::Option<&'static $t> {
+ unsafe fn __getit(
+ init: $crate::option::Option<&mut $crate::option::Option<$t>>,
+ ) -> $crate::option::Option<&'static $t> {
#[cfg(all(target_family = "wasm", not(target_feature = "atomics")))]
static __KEY: $crate::thread::__StaticLocalKeyInner<$t> =
$crate::thread::__StaticLocalKeyInner::new();
// raise warning for missing/extraneous unsafe blocks anymore.
// See https://github.com/rust-lang/rust/issues/74838.
#[allow(unused_unsafe)]
- unsafe { __KEY.get(__init) }
+ unsafe {
+ __KEY.get(move || {
+ if let $crate::option::Option::Some(init) = init {
+ if let $crate::option::Option::Some(value) = init.take() {
+ return value;
+ } else if $crate::cfg!(debug_assertions) {
+ unreachable!("missing default value");
+ }
+ }
+ __init()
+ })
+ }
}
unsafe {
issue = "none"
)]
#[rustc_const_unstable(feature = "thread_local_internals", issue = "none")]
- pub const unsafe fn new(inner: unsafe fn() -> Option<&'static T>) -> LocalKey<T> {
+ pub const unsafe fn new(
+ inner: unsafe fn(Option<&mut Option<T>>) -> Option<&'static T>,
+ ) -> LocalKey<T> {
LocalKey { inner }
}
F: FnOnce(&T) -> R,
{
unsafe {
- let thread_local = (self.inner)().ok_or(AccessError)?;
+ let thread_local = (self.inner)(None).ok_or(AccessError)?;
Ok(f(thread_local))
}
}
+
+ /// Acquires a reference to the value in this TLS key, initializing it with
+ /// `init` if it wasn't already initialized on this thread.
+ ///
+ /// If `init` was used to initialize the thread local variable, `None` is
+ /// passed as the first argument to `f`. If it was already initialized,
+ /// `Some(init)` is passed to `f`.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if the key currently has its destructor
+ /// running, and it **may** panic if the destructor has previously been run
+ /// for this thread.
+ fn initialize_with<F, R>(&'static self, init: T, f: F) -> R
+ where
+ F: FnOnce(Option<T>, &T) -> R,
+ {
+ unsafe {
+ let mut init = Some(init);
+ let reference = (self.inner)(Some(&mut init)).expect(
+ "cannot access a Thread Local Storage value \
+ during or after destruction",
+ );
+ f(init, reference)
+ }
+ }
+}
+
+impl<T: 'static> LocalKey<Cell<T>> {
+ /// Sets or initializes the contained value.
+ ///
+ /// Unlike the other methods, this will *not* run the lazy initializer of
+ /// the thread local. Instead, it will be directly initialized with the
+ /// given value if it wasn't initialized yet.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the key currently has its destructor running,
+ /// and it **may** panic if the destructor has previously been run for this thread.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(local_key_cell_methods)]
+ /// use std::cell::Cell;
+ ///
+ /// thread_local! {
+ /// static X: Cell<i32> = panic!("!");
+ /// }
+ ///
+ /// // Calling X.get() here would result in a panic.
+ ///
+ /// X.set(123); // But X.set() is fine, as it skips the initializer above.
+ ///
+ /// assert_eq!(X.get(), 123);
+ /// ```
+ #[unstable(feature = "local_key_cell_methods", issue = "92122")]
+ pub fn set(&'static self, value: T) {
+ self.initialize_with(Cell::new(value), |value, cell| {
+ if let Some(value) = value {
+ // The cell was already initialized, so `value` wasn't used to
+ // initialize it. So we overwrite the current value with the
+ // new one instead.
+ cell.set(value.into_inner());
+ }
+ });
+ }
+
+ /// Returns a copy of the contained value.
+ ///
+ /// This will lazily initialize the value if this thread has not referenced
+ /// this key yet.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the key currently has its destructor running,
+ /// and it **may** panic if the destructor has previously been run for this thread.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(local_key_cell_methods)]
+ /// use std::cell::Cell;
+ ///
+ /// thread_local! {
+ /// static X: Cell<i32> = Cell::new(1);
+ /// }
+ ///
+ /// assert_eq!(X.get(), 1);
+ /// ```
+ #[unstable(feature = "local_key_cell_methods", issue = "92122")]
+ pub fn get(&'static self) -> T
+ where
+ T: Copy,
+ {
+ self.with(|cell| cell.get())
+ }
+
+ /// Takes the contained value, leaving `Default::default()` in its place.
+ ///
+ /// This will lazily initialize the value if this thread has not referenced
+ /// this key yet.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the key currently has its destructor running,
+ /// and it **may** panic if the destructor has previously been run for this thread.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(local_key_cell_methods)]
+ /// use std::cell::Cell;
+ ///
+ /// thread_local! {
+ /// static X: Cell<Option<i32>> = Cell::new(Some(1));
+ /// }
+ ///
+ /// assert_eq!(X.take(), Some(1));
+ /// assert_eq!(X.take(), None);
+ /// ```
+ #[unstable(feature = "local_key_cell_methods", issue = "92122")]
+ pub fn take(&'static self) -> T
+ where
+ T: Default,
+ {
+ self.with(|cell| cell.take())
+ }
+
+ /// Replaces the contained value, returning the old value.
+ ///
+ /// This will lazily initialize the value if this thread has not referenced
+ /// this key yet.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the key currently has its destructor running,
+ /// and it **may** panic if the destructor has previously been run for this thread.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(local_key_cell_methods)]
+ /// use std::cell::Cell;
+ ///
+ /// thread_local! {
+ /// static X: Cell<i32> = Cell::new(1);
+ /// }
+ ///
+ /// assert_eq!(X.replace(2), 1);
+ /// assert_eq!(X.replace(3), 2);
+ /// ```
+ #[unstable(feature = "local_key_cell_methods", issue = "92122")]
+ pub fn replace(&'static self, value: T) -> T {
+ self.with(|cell| cell.replace(value))
+ }
+}
+
+impl<T: 'static> LocalKey<RefCell<T>> {
+ /// Acquires a reference to the contained value.
+ ///
+ /// This will lazily initialize the value if this thread has not referenced
+ /// this key yet.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the value is currently mutably borrowed.
+ ///
+ /// Panics if the key currently has its destructor running,
+ /// and it **may** panic if the destructor has previously been run for this thread.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// #![feature(local_key_cell_methods)]
+ /// use std::cell::RefCell;
+ ///
+ /// thread_local! {
+ /// static X: RefCell<Vec<i32>> = RefCell::new(Vec::new());
+ /// }
+ ///
+ /// X.with_borrow(|v| assert!(v.is_empty()));
+ /// ```
+ #[unstable(feature = "local_key_cell_methods", issue = "92122")]
+ pub fn with_borrow<F, R>(&'static self, f: F) -> R
+ where
+ F: FnOnce(&T) -> R,
+ {
+ self.with(|cell| f(&cell.borrow()))
+ }
+
+ /// Acquires a mutable reference to the contained value.
+ ///
+ /// This will lazily initialize the value if this thread has not referenced
+ /// this key yet.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the value is currently borrowed.
+ ///
+ /// Panics if the key currently has its destructor running,
+ /// and it **may** panic if the destructor has previously been run for this thread.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// #![feature(local_key_cell_methods)]
+ /// use std::cell::RefCell;
+ ///
+ /// thread_local! {
+ /// static X: RefCell<Vec<i32>> = RefCell::new(Vec::new());
+ /// }
+ ///
+ /// X.with_borrow_mut(|v| v.push(1));
+ ///
+ /// X.with_borrow(|v| assert_eq!(*v, vec![1]));
+ /// ```
+ #[unstable(feature = "local_key_cell_methods", issue = "92122")]
+ pub fn with_borrow_mut<F, R>(&'static self, f: F) -> R
+ where
+ F: FnOnce(&mut T) -> R,
+ {
+ self.with(|cell| f(&mut cell.borrow_mut()))
+ }
+
+ /// Sets or initializes the contained value.
+ ///
+ /// Unlike the other methods, this will *not* run the lazy initializer of
+ /// the thread local. Instead, it will be directly initialized with the
+ /// given value if it wasn't initialized yet.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the value is currently borrowed.
+ ///
+ /// Panics if the key currently has its destructor running,
+ /// and it **may** panic if the destructor has previously been run for this thread.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(local_key_cell_methods)]
+ /// use std::cell::RefCell;
+ ///
+ /// thread_local! {
+ /// static X: RefCell<Vec<i32>> = panic!("!");
+ /// }
+ ///
+ /// // Calling X.with() here would result in a panic.
+ ///
+ /// X.set(vec![1, 2, 3]); // But X.set() is fine, as it skips the initializer above.
+ ///
+ /// X.with_borrow(|v| assert_eq!(*v, vec![1, 2, 3]));
+ /// ```
+ #[unstable(feature = "local_key_cell_methods", issue = "92122")]
+ pub fn set(&'static self, value: T) {
+ self.initialize_with(RefCell::new(value), |value, cell| {
+ if let Some(value) = value {
+ // The cell was already initialized, so `value` wasn't used to
+ // initialize it. So we overwrite the current value with the
+ // new one instead.
+ *cell.borrow_mut() = value.into_inner();
+ }
+ });
+ }
+
+ /// Takes the contained value, leaving `Default::default()` in its place.
+ ///
+ /// This will lazily initialize the value if this thread has not referenced
+ /// this key yet.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the value is currently borrowed.
+ ///
+ /// Panics if the key currently has its destructor running,
+ /// and it **may** panic if the destructor has previously been run for this thread.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(local_key_cell_methods)]
+ /// use std::cell::RefCell;
+ ///
+ /// thread_local! {
+ /// static X: RefCell<Vec<i32>> = RefCell::new(Vec::new());
+ /// }
+ ///
+ /// X.with_borrow_mut(|v| v.push(1));
+ ///
+ /// let a = X.take();
+ ///
+ /// assert_eq!(a, vec![1]);
+ ///
+ /// X.with_borrow(|v| assert!(v.is_empty()));
+ /// ```
+ #[unstable(feature = "local_key_cell_methods", issue = "92122")]
+ pub fn take(&'static self) -> T
+ where
+ T: Default,
+ {
+ self.with(|cell| cell.take())
+ }
+
+ /// Replaces the contained value, returning the old value.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the value is currently borrowed.
+ ///
+ /// Panics if the key currently has its destructor running,
+ /// and it **may** panic if the destructor has previously been run for this thread.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(local_key_cell_methods)]
+ /// use std::cell::RefCell;
+ ///
+ /// thread_local! {
+ /// static X: RefCell<Vec<i32>> = RefCell::new(Vec::new());
+ /// }
+ ///
+ /// let prev = X.replace(vec![1, 2, 3]);
+ /// assert!(prev.is_empty());
+ ///
+ /// X.with_borrow(|v| assert_eq!(*v, vec![1, 2, 3]));
+ /// ```
+ #[unstable(feature = "local_key_cell_methods", issue = "92122")]
+ pub fn replace(&'static self, value: T) -> T {
+ self.with(|cell| cell.replace(value))
+ }
}
mod lazy {
Key { inner: LazyKeyInner::new() }
}
- pub unsafe fn get(&self, init: fn() -> T) -> Option<&'static T> {
+ pub unsafe fn get(&self, init: impl FnOnce() -> T) -> Option<&'static T> {
// SAFETY: The caller must ensure no reference is ever handed out to
// the inner cell nor mutable reference to the Option<T> inside said
// cell. This make it safe to hand a reference, though the lifetime
/// It is a requirement for the caller to ensure that no mutable
/// reference is active when this method is called.
- pub unsafe fn get(&'static self, init: fn() -> T) -> Option<&'static T> {
+ pub unsafe fn get(&'static self, init: impl FnOnce() -> T) -> Option<&'static T> {
// SAFETY: See the documentation for this method.
let ptr = unsafe { self.os.get() as *mut Value<T> };
if ptr as usize > 1 {
// `try_initialize` is only called once per os thread local variable,
// except in corner cases where thread_local dtors reference other
// thread_local's, or it is being recursively initialized.
- unsafe fn try_initialize(&'static self, init: fn() -> T) -> Option<&'static T> {
+ unsafe fn try_initialize(&'static self, init: impl FnOnce() -> T) -> Option<&'static T> {
// SAFETY: No mutable references are ever handed out meaning getting
// the value is ok.
let ptr = unsafe { self.os.get() as *mut Value<T> };
self.0.join()
}
- /// Checks if the associated thread is still running its main function.
+ /// Checks if the associated thread has finished running its main function.
///
- /// This might return `false` for a brief moment after the thread's main
+ /// This might return `true` for a brief moment after the thread's main
/// function has returned, but before the thread itself has stopped running.
+ /// However, once this returns `true`, [`join`][Self::join] can be expected
+ /// to return quickly, without blocking for any significant amount of time.
+ ///
+ /// This function does not block. To block while waiting on the thread to finish,
+ /// use [`join`][Self::join].
#[unstable(feature = "thread_is_running", issue = "90470")]
- pub fn is_running(&self) -> bool {
- Arc::strong_count(&self.0.packet) > 1
+ pub fn is_finished(&self) -> bool {
+ Arc::strong_count(&self.0.packet) == 1
}
}
///
/// On Linux:
/// - It may overcount the amount of parallelism available when limited by a
-/// process-wide affinity mask, or when affected by cgroup limits.
+/// process-wide affinity mask or cgroup quotas and cgroup2 fs or `sched_getaffinity()` can't be
+/// queried, e.g. due to sandboxing.
+/// - It may undercount the amount of parallelism if the current thread's affinity mask
+/// does not reflect the process' cpuset, e.g. due to pinned threads.
///
/// On all targets:
/// - It may overcount the amount of parallelism available when running in a VM
/// A scope to spawn scoped threads in.
///
/// See [`scope`] for details.
-pub struct Scope<'env> {
+pub struct Scope<'scope, 'env: 'scope> {
data: ScopeData,
- /// Invariance over 'env, to make sure 'env cannot shrink,
+ /// Invariance over 'scope, to make sure 'scope cannot shrink,
/// which is necessary for soundness.
///
/// Without invariance, this would compile fine but be unsound:
///
- /// ```compile_fail
+ /// ```compile_fail,E0373
/// #![feature(scoped_threads)]
///
/// std::thread::scope(|s| {
- /// s.spawn(|s| {
+ /// s.spawn(|| {
/// let a = String::from("abcd");
- /// s.spawn(|_| println!("{:?}", a)); // might run after `a` is dropped
+ /// s.spawn(|| println!("{:?}", a)); // might run after `a` is dropped
/// });
/// });
/// ```
+ scope: PhantomData<&'scope mut &'scope ()>,
env: PhantomData<&'env mut &'env ()>,
}
/// let mut x = 0;
///
/// thread::scope(|s| {
-/// s.spawn(|_| {
+/// s.spawn(|| {
/// println!("hello from the first scoped thread");
/// // We can borrow `a` here.
/// dbg!(&a);
/// });
-/// s.spawn(|_| {
+/// s.spawn(|| {
/// println!("hello from the second scoped thread");
/// // We can even mutably borrow `x` here,
/// // because no other threads are using it.
#[track_caller]
pub fn scope<'env, F, T>(f: F) -> T
where
- F: FnOnce(&Scope<'env>) -> T,
+ F: for<'scope> FnOnce(&'scope Scope<'scope, 'env>) -> T,
{
let scope = Scope {
data: ScopeData {
a_thread_panicked: AtomicBool::new(false),
},
env: PhantomData,
+ scope: PhantomData,
};
// Run `f`, but catch panics so we can make sure to wait for all the threads to join.
}
}
-impl<'env> Scope<'env> {
+impl<'scope, 'env> Scope<'scope, 'env> {
/// Spawns a new thread within a scope, returning a [`ScopedJoinHandle`] for it.
///
/// Unlike non-scoped threads, threads spawned with this function may
/// to recover from such errors.
///
/// [`join`]: ScopedJoinHandle::join
- pub fn spawn<'scope, F, T>(&'scope self, f: F) -> ScopedJoinHandle<'scope, T>
+ pub fn spawn<F, T>(&'scope self, f: F) -> ScopedJoinHandle<'scope, T>
where
- F: FnOnce(&Scope<'env>) -> T + Send + 'env,
- T: Send + 'env,
+ F: FnOnce() -> T + Send + 'scope,
+ T: Send + 'scope,
{
Builder::new().spawn_scoped(self, f).expect("failed to spawn thread")
}
/// thread::scope(|s| {
/// thread::Builder::new()
/// .name("first".to_string())
- /// .spawn_scoped(s, |_|
+ /// .spawn_scoped(s, ||
/// {
/// println!("hello from the {:?} scoped thread", thread::current().name());
/// // We can borrow `a` here.
/// .unwrap();
/// thread::Builder::new()
/// .name("second".to_string())
- /// .spawn_scoped(s, |_|
+ /// .spawn_scoped(s, ||
/// {
/// println!("hello from the {:?} scoped thread", thread::current().name());
/// // We can even mutably borrow `x` here,
/// ```
pub fn spawn_scoped<'scope, 'env, F, T>(
self,
- scope: &'scope Scope<'env>,
+ scope: &'scope Scope<'scope, 'env>,
f: F,
) -> io::Result<ScopedJoinHandle<'scope, T>>
where
- F: FnOnce(&Scope<'env>) -> T + Send + 'env,
- T: Send + 'env,
+ F: FnOnce() -> T + Send + 'scope,
+ T: Send + 'scope,
{
- Ok(ScopedJoinHandle(unsafe { self.spawn_unchecked_(|| f(scope), Some(&scope.data)) }?))
+ Ok(ScopedJoinHandle(unsafe { self.spawn_unchecked_(f, Some(&scope.data)) }?))
}
}
///
/// ```
/// #![feature(scoped_threads)]
- /// #![feature(thread_is_running)]
///
/// use std::thread;
///
/// thread::scope(|s| {
- /// let t = s.spawn(|_| {
+ /// let t = s.spawn(|| {
/// println!("hello");
/// });
/// println!("thread id: {:?}", t.thread().id());
///
/// ```
/// #![feature(scoped_threads)]
- /// #![feature(thread_is_running)]
///
/// use std::thread;
///
/// thread::scope(|s| {
- /// let t = s.spawn(|_| {
+ /// let t = s.spawn(|| {
/// panic!("oh no");
/// });
/// assert!(t.join().is_err());
self.0.join()
}
- /// Checks if the associated thread is still running its main function.
+ /// Checks if the associated thread has finished running its main function.
///
- /// This might return `false` for a brief moment after the thread's main
+ /// This might return `true` for a brief moment after the thread's main
/// function has returned, but before the thread itself has stopped running.
+ /// However, once this returns `true`, [`join`][Self::join] can be expected
+ /// to return quickly, without blocking for any significant amount of time.
+ ///
+ /// This function does not block. To block while waiting on the thread to finish,
+ /// use [`join`][Self::join].
#[unstable(feature = "thread_is_running", issue = "90470")]
- pub fn is_running(&self) -> bool {
- Arc::strong_count(&self.0.packet) > 1
+ pub fn is_finished(&self) -> bool {
+ Arc::strong_count(&self.0.packet) == 1
}
}
-impl<'env> fmt::Debug for Scope<'env> {
+impl fmt::Debug for Scope<'_, '_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Scope")
.field("num_running_threads", &self.data.num_running_threads.load(Ordering::Relaxed))
}
#[test]
-fn test_is_running() {
+fn test_is_finished() {
let b = Arc::new(Barrier::new(2));
let t = thread::spawn({
let b = b.clone();
});
// Thread is definitely running here, since it's still waiting for the barrier.
- assert_eq!(t.is_running(), true);
+ assert_eq!(t.is_finished(), false);
// Unblock the barrier.
b.wait();
- // Now check that t.is_running() becomes false within a reasonable time.
+ // Now check that t.is_finished() becomes true within a reasonable time.
let start = Instant::now();
- while t.is_running() {
+ while !t.is_finished() {
assert!(start.elapsed() < Duration::from_secs(2));
thread::sleep(Duration::from_millis(15));
}
extern "C-unwind" {
pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
}
+ #[cfg_attr(
+ all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")),
+ link(name = "unwind", kind = "static", modifiers = "-bundle")
+ )]
extern "C" {
pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
trace_argument: *mut c_void)
version = "0.0.0"
edition = "2021"
build = "build.rs"
+default-run = "bootstrap"
[lib]
path = "lib.rs"
test = false
[dependencies]
-build_helper = { path = "../build_helper" }
cmake = "0.1.38"
filetime = "0.2"
-num_cpus = "1.0"
getopts = "0.2.19"
cc = "1.0.69"
libc = "0.2"
build.check_vendored_status()
build_dir = build.get_toml('build-dir', 'build') or 'build'
- build.build_dir = os.path.abspath(build_dir.replace("$ROOT", build.rust_root))
+ build.build_dir = os.path.abspath(build_dir)
with open(os.path.join(build.rust_root, "src", "stage0.json")) as f:
data = json.load(f)
env = os.environ.copy()
env["BOOTSTRAP_PARENT_ID"] = str(os.getpid())
env["BOOTSTRAP_PYTHON"] = sys.executable
- env["BUILD_DIR"] = build.build_dir
env["RUSTC_BOOTSTRAP"] = '1'
- if toml_path:
- env["BOOTSTRAP_CONFIG"] = toml_path
if build.rustc_commit is not None:
env["BOOTSTRAP_DOWNLOAD_RUSTC"] = '1'
run(args, env=env, verbose=build.verbose, is_bootstrap=True)
use std::process::Command;
use std::time::{Duration, Instant};
-use build_helper::{output, t};
-
use crate::cache::{Cache, Interned, INTERNER};
use crate::check;
use crate::compile;
use crate::run;
use crate::test;
use crate::tool::{self, SourceType};
-use crate::util::{self, add_dylib_path, add_link_lib_path, exe, libdir};
-use crate::{Build, DocTests, GitRepo, Mode};
+use crate::util::{self, add_dylib_path, add_link_lib_path, exe, libdir, output, t};
+use crate::EXTRA_CHECK_CFGS;
+use crate::{Build, CLang, DocTests, GitRepo, Mode};
pub use crate::Compiler;
// FIXME: replace with std::lazy after it gets stabilized and reaches beta
}
pub fn rustdoc_cmd(&self, compiler: Compiler) -> Command {
- let mut cmd = Command::new(&self.out.join("bootstrap/debug/rustdoc"));
+ let mut cmd = Command::new(&self.bootstrap_out.join("rustdoc"));
cmd.env("RUSTC_STAGE", compiler.stage.to_string())
.env("RUSTC_SYSROOT", self.sysroot(compiler))
// Note that this is *not* the sysroot_libdir because rustdoc must be linked
rustflags.arg("-Zunstable-options");
}
+ // #[cfg(not(bootstrap)]
+ if stage != 0 {
+ // Enable cfg checking of cargo features
+ // FIXME: De-comment this when cargo beta get support for it
+ // cargo.arg("-Zcheck-cfg-features");
+
+ // Enable cfg checking of rustc well-known names
+ rustflags.arg("-Zunstable-options").arg("--check-cfg=names()");
+
+ // Add extra cfg not defined in rustc
+ for (restricted_mode, name, values) in EXTRA_CHECK_CFGS {
+ if *restricted_mode == None || *restricted_mode == Some(mode) {
+ // Creating a string of the values by concatenating each value:
+ // ',"tvos","watchos"' or '' (nothing) when there are no values
+ let values = match values {
+ Some(values) => values
+ .iter()
+ .map(|val| [",", "\"", val, "\""])
+ .flatten()
+ .collect::<String>(),
+ None => String::new(),
+ };
+ rustflags.arg(&format!("--check-cfg=values({name}{values})"));
+ }
+ }
+ }
+
// FIXME: It might be better to use the same value for both `RUSTFLAGS` and `RUSTDOCFLAGS`,
// but this breaks CI. At the very least, stage0 `rustdoc` needs `--cfg bootstrap`. See
// #71458.
.env("RUSTC_STAGE", stage.to_string())
.env("RUSTC_SYSROOT", &sysroot)
.env("RUSTC_LIBDIR", &libdir)
- .env("RUSTDOC", self.out.join("bootstrap/debug/rustdoc"))
+ .env("RUSTDOC", self.bootstrap_out.join("rustdoc"))
.env(
"RUSTDOC_REAL",
if cmd == "doc" || cmd == "rustdoc" || (cmd == "test" && want_rustdoc) {
// Clippy support is a hack and uses the default `cargo-clippy` in path.
// Don't override RUSTC so that the `cargo-clippy` in path will be run.
if cmd != "clippy" {
- cargo.env("RUSTC", self.out.join("bootstrap/debug/rustc"));
+ cargo.env("RUSTC", self.bootstrap_out.join("rustc"));
}
// Dealing with rpath here is a little special, so let's go into some
let cc = ccacheify(&self.cc(target));
cargo.env(format!("CC_{}", target.triple), &cc);
- let cflags = self.cflags(target, GitRepo::Rustc).join(" ");
+ let cflags = self.cflags(target, GitRepo::Rustc, CLang::C).join(" ");
cargo.env(format!("CFLAGS_{}", target.triple), &cflags);
if let Some(ar) = self.ar(target) {
if let Ok(cxx) = self.cxx(target) {
let cxx = ccacheify(&cxx);
+ let cxxflags = self.cflags(target, GitRepo::Rustc, CLang::Cxx).join(" ");
cargo
.env(format!("CXX_{}", target.triple), &cxx)
- .env(format!("CXXFLAGS_{}", target.triple), cflags);
+ .env(format!("CXXFLAGS_{}", target.triple), cxxflags);
}
}
config.save_toolstates = None;
config.dry_run = true;
config.ninja_in_file = false;
- // try to avoid spurious failures in dist where we create/delete each others file
config.out = PathBuf::from(env::var_os("BOOTSTRAP_OUTPUT_DIRECTORY").unwrap());
config.initial_rustc = PathBuf::from(env::var_os("RUSTC").unwrap());
config.initial_cargo = PathBuf::from(env::var_os("BOOTSTRAP_INITIAL_CARGO").unwrap());
+ // try to avoid spurious failures in dist where we create/delete each others file
let dir = config
.out
.join("tmp-rustbuild-tests")
use std::process::Command;
use std::{env, iter};
-use build_helper::output;
-
use crate::config::{Target, TargetSelection};
-use crate::{Build, GitRepo};
+use crate::util::output;
+use crate::{Build, CLang, GitRepo};
// The `cc` crate doesn't provide a way to obtain a path to the detected archiver,
// so use some simplified logic here. First we respect the environment variable `AR`, then
};
build.cc.insert(target, compiler.clone());
- let cflags = build.cflags(target, GitRepo::Rustc);
+ let cflags = build.cflags(target, GitRepo::Rustc, CLang::C);
// If we use llvm-libunwind, we will need a C++ compiler as well for all targets
// We'll need one anyways if the target triple is also a host triple
build.verbose(&format!("CC_{} = {:?}", &target.triple, build.cc(target)));
build.verbose(&format!("CFLAGS_{} = {:?}", &target.triple, cflags));
if let Ok(cxx) = build.cxx(target) {
+ let cxxflags = build.cflags(target, GitRepo::Rustc, CLang::Cxx);
build.verbose(&format!("CXX_{} = {:?}", &target.triple, cxx));
- build.verbose(&format!("CXXFLAGS_{} = {:?}", &target.triple, cflags));
+ build.verbose(&format!("CXXFLAGS_{} = {:?}", &target.triple, cxxflags));
}
if let Some(ar) = ar {
build.verbose(&format!("AR_{} = {:?}", &target.triple, ar));
use std::path::Path;
use std::process::Command;
-use build_helper::output;
-
+use crate::util::output;
use crate::Build;
pub enum GitInfo {
use std::io::{self, ErrorKind};
use std::path::Path;
-use build_helper::t;
-
+use crate::util::t;
use crate::Build;
pub fn clean(build: &Build, all: bool) {
use std::process::{exit, Command, Stdio};
use std::str;
-use build_helper::{output, t, up_to_date};
use serde::Deserialize;
use crate::builder::Cargo;
use crate::dist;
use crate::native;
use crate::tool::SourceType;
-use crate::util::{exe, is_debug_info, is_dylib, symlink_dir};
+use crate::util::{exe, is_debug_info, is_dylib, output, symlink_dir, t, up_to_date};
use crate::LLVM_TOOLS;
-use crate::{Compiler, DependencyType, GitRepo, Mode};
+use crate::{CLang, Compiler, DependencyType, GitRepo, Mode};
#[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Std {
}
} else if target.contains("windows-gnu") {
for obj in ["crt2.o", "dllcrt2.o"].iter() {
- let src = compiler_file(builder, builder.cc(target), target, obj);
+ let src = compiler_file(builder, builder.cc(target), target, CLang::C, obj);
let target = libdir_self_contained.join(obj);
builder.copy(&src, &target);
target_deps.push((target, DependencyType::TargetSelfContained));
&& !target.contains("msvc")
&& !target.contains("apple")
{
- let file = compiler_file(builder, builder.cxx(target).unwrap(), target, "libstdc++.a");
+ let file = compiler_file(
+ builder,
+ builder.cxx(target).unwrap(),
+ target,
+ CLang::Cxx,
+ "libstdc++.a",
+ );
cargo.env("LLVM_STATIC_STDCPP", file);
}
if builder.config.llvm_link_shared {
builder: &Builder<'_>,
compiler: &Path,
target: TargetSelection,
+ c: CLang,
file: &str,
) -> PathBuf {
let mut cmd = Command::new(compiler);
- cmd.args(builder.cflags(target, GitRepo::Rustc));
+ cmd.args(builder.cflags(target, GitRepo::Rustc, c));
cmd.arg(format!("-print-file-name={}", file));
let out = output(&mut cmd);
PathBuf::from(out.trim())
use std::cmp;
use std::collections::{HashMap, HashSet};
use std::env;
-use std::ffi::OsString;
use std::fmt;
use std::fs;
use std::path::{Path, PathBuf};
use crate::channel::GitInfo;
pub use crate::flags::Subcommand;
use crate::flags::{Color, Flags};
-use crate::util::exe;
-use build_helper::t;
+use crate::util::{exe, t};
use serde::Deserialize;
macro_rules! check_ci_llvm {
derive_merge! {
/// TOML representation of various global build decisions.
- #[derive(Deserialize, Default, Clone)]
+ #[derive(Deserialize, Default)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
struct Build {
build: Option<String>,
host: Option<Vec<String>>,
target: Option<Vec<String>>,
- // This is ignored, the rust code always gets the build directory from the `BUILD_DIR` env variable
build_dir: Option<String>,
cargo: Option<String>,
rustc: Option<String>,
derive_merge! {
/// TOML representation of various global install decisions.
- #[derive(Deserialize, Default, Clone)]
+ #[derive(Deserialize)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
struct Install {
prefix: Option<String>,
derive_merge! {
/// TOML representation of how the LLVM build is configured.
- #[derive(Deserialize, Default)]
+ #[derive(Deserialize)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
struct Llvm {
skip_rebuild: Option<bool>,
}
derive_merge! {
- #[derive(Deserialize, Default, Clone)]
+ #[derive(Deserialize)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
struct Dist {
sign_folder: Option<String>,
derive_merge! {
/// TOML representation of how the Rust build is configured.
- #[derive(Deserialize, Default)]
+ #[derive(Deserialize)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
struct Rust {
optimize: Option<bool>,
derive_merge! {
/// TOML representation of how each build target is configured.
- #[derive(Deserialize, Default)]
+ #[derive(Deserialize)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
struct TomlTarget {
cc: Option<String>,
}
impl Config {
- fn path_from_python(var_key: &str) -> PathBuf {
- match env::var_os(var_key) {
- Some(var_val) => Self::normalize_python_path(var_val),
- _ => panic!("expected '{}' to be set", var_key),
- }
- }
-
- /// Normalizes paths from Python slightly. We don't trust paths from Python (#49785).
- fn normalize_python_path(path: OsString) -> PathBuf {
- Path::new(&path).components().collect()
- }
-
pub fn default_opts() -> Config {
let mut config = Config::default();
config.llvm_optimize = true;
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
// Undo `src/bootstrap`
config.src = manifest_dir.parent().unwrap().parent().unwrap().to_owned();
- config.out = Config::path_from_python("BUILD_DIR");
+ config.out = PathBuf::from("build");
config.initial_cargo = PathBuf::from(env!("CARGO"));
config.initial_rustc = PathBuf::from(env!("RUSTC"));
config.llvm_profile_use = flags.llvm_profile_use;
config.llvm_profile_generate = flags.llvm_profile_generate;
- if config.dry_run {
- let dir = config.out.join("tmp-dry-run");
- t!(fs::create_dir_all(&dir));
- config.out = dir;
- }
-
#[cfg(test)]
let get_toml = |_| TomlConfig::default();
#[cfg(not(test))]
}
};
- let mut toml = flags.config.as_deref().map(get_toml).unwrap_or_else(TomlConfig::default);
+ // check --config first, then `$RUST_BOOTSTRAP_CONFIG` first, then `config.toml`
+ let toml_path = flags
+ .config
+ .clone()
+ .or_else(|| env::var_os("RUST_BOOTSTRAP_CONFIG").map(PathBuf::from))
+ .unwrap_or_else(|| PathBuf::from("config.toml"));
+ let mut toml =
+ if toml_path.exists() { get_toml(&toml_path) } else { TomlConfig::default() };
+
if let Some(include) = &toml.profile {
let mut include_path = config.src.clone();
include_path.push("src");
}
config.changelog_seen = toml.changelog_seen;
- if let Some(cfg) = flags.config {
- config.config = cfg;
- }
+ config.config = toml_path;
let build = toml.build.unwrap_or_default();
+ set(&mut config.initial_rustc, build.rustc.map(PathBuf::from));
+ set(&mut config.out, build.build_dir.map(PathBuf::from));
+ // NOTE: Bootstrap spawns various commands with different working directories.
+ // To avoid writing to random places on the file system, `config.out` needs to be an absolute path.
+ if !config.out.is_absolute() {
+ // `canonicalize` requires the path to already exist. Use our vendored copy of `absolute` instead.
+ config.out = crate::util::absolute(&config.out);
+ }
+
+ if config.dry_run {
+ let dir = config.out.join("tmp-dry-run");
+ t!(fs::create_dir_all(&dir));
+ config.out = dir;
+ }
+
config.hosts = if let Some(arg_host) = flags.host {
arg_host
} else if let Some(file_host) = build.host {
fn threads_from_config(v: u32) -> u32 {
match v {
- 0 => num_cpus::get() as u32,
+ 0 => std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get) as u32,
n => n,
}
}
use std::path::{Path, PathBuf};
use std::process::Command;
-use build_helper::{output, t};
-
use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
use crate::cache::{Interned, INTERNER};
use crate::compile;
use crate::config::TargetSelection;
use crate::tarball::{GeneratedTarball, OverlayKind, Tarball};
use crate::tool::{self, Tool};
-use crate::util::{exe, is_dylib, timeit};
+use crate::util::{exe, is_dylib, output, t, timeit};
use crate::{Compiler, DependencyType, Mode, LLVM_TOOLS};
pub fn pkgname(builder: &Builder<'_>, component: &str) -> String {
&[],
&tarball.image_dir().join("lib/rustlib/rustc-src/rust"),
);
- // This particular crate is used as a build dependency of the above.
- copy_src_dirs(
- builder,
- &builder.src,
- &["src/build_helper"],
- &[],
- &tarball.image_dir().join("lib/rustlib/rustc-src/rust"),
- );
for file in src_files {
tarball.add_file(builder.src.join(file), "lib/rustlib/rustc-src/rust", 0o644);
}
use std::io;
use std::path::{Path, PathBuf};
-use crate::Mode;
-use build_helper::{t, up_to_date};
-
use crate::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step};
use crate::cache::{Interned, INTERNER};
use crate::compile;
use crate::config::{Config, TargetSelection};
use crate::tool::{self, prepare_tool_cargo, SourceType, Tool};
-use crate::util::symlink_dir;
+use crate::util::{symlink_dir, t, up_to_date};
+use crate::Mode;
macro_rules! submodule_helper {
($path:expr, submodule) => {
//! This module implements the command-line parsing of the build system which
//! has various flags to configure how it's run.
-use std::env;
use std::path::PathBuf;
use std::process;
-use build_helper::t;
use getopts::Options;
use crate::builder::Builder;
use crate::config::{Config, TargetSelection};
use crate::setup::Profile;
+use crate::util::t;
use crate::{Build, DocTests};
pub enum Color {
let j_msg = format!(
"number of jobs to run in parallel; \
defaults to {} (this host's logical CPU count)",
- num_cpus::get()
+ std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get)
);
opts.optopt("j", "jobs", &j_msg, "JOBS");
opts.optflag("h", "help", "print this help message");
// Get any optional paths which occur after the subcommand
let mut paths = matches.free[1..].iter().map(|p| p.into()).collect::<Vec<PathBuf>>();
- let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from);
let verbose = matches.opt_present("verbose");
// User passed in -h/--help?
} else {
None
},
- config: cfg_file,
+ config: matches.opt_str("config").map(PathBuf::from),
jobs: matches.opt_str("jobs").map(|j| j.parse().expect("`jobs` should be a number")),
cmd,
incremental: matches.opt_present("incremental"),
//! Runs rustfmt on the repository.
+use crate::util::{output, t};
use crate::Build;
-use build_helper::{output, t};
use ignore::WalkBuilder;
use std::collections::VecDeque;
use std::path::{Path, PathBuf};
});
for untracked_path in untracked_paths {
eprintln!("skip untracked path {} during rustfmt invocations", untracked_path);
- ignore_fmt.add(&format!("!{}", untracked_path)).expect(&untracked_path);
+ // The leading `/` makes it an exact match against the
+ // repository root, rather than a glob. Without that, if you
+ // have `foo.rs` in the repository root it will also match
+ // against anything like `compiler/rustc_foo/src/foo.rs`,
+ // preventing the latter from being formatted.
+ ignore_fmt.add(&format!("!/{}", untracked_path)).expect(&untracked_path);
}
} else {
eprintln!("Not in git tree. Skipping git-aware format checks");
use std::path::{Component, PathBuf};
use std::process::Command;
-use build_helper::t;
+use crate::util::t;
use crate::dist::{self, sanitize_sh};
use crate::tarball::GeneratedTarball;
#[cfg(windows)]
use std::os::windows::fs::symlink_file;
-use build_helper::{mtime, output, run, run_suppressed, t, try_run, try_run_suppressed};
use filetime::FileTime;
use crate::builder::Kind;
use crate::config::{LlvmLibunwind, TargetSelection};
-use crate::util::{exe, libdir, CiEnv};
+use crate::util::{
+ exe, libdir, mtime, output, run, run_suppressed, t, try_run, try_run_suppressed, CiEnv,
+};
mod builder;
mod cache;
pub const VERSION: usize = 2;
+/// Extra --check-cfg to add when building
+/// (Mode restriction, config name, config values (if any))
+const EXTRA_CHECK_CFGS: &[(Option<Mode>, &'static str, Option<&[&'static str]>)] = &[
+ (None, "bootstrap", None),
+ (Some(Mode::Rustc), "parallel_compiler", None),
+ (Some(Mode::ToolRustc), "parallel_compiler", None),
+ (Some(Mode::Std), "miri", None),
+ (Some(Mode::Std), "stdarch_intel_sde", None),
+ (Some(Mode::Std), "no_fp_fmt_parse", None),
+ (Some(Mode::Std), "no_global_oom_handling", None),
+ (Some(Mode::Std), "freebsd12", None),
+ (Some(Mode::Std), "backtrace_in_libstd", None),
+ // FIXME: Used by rustfmt is their test but is invalid (neither cargo nor bootstrap ever set
+ // this config) should probably by removed or use a allow attribute.
+ (Some(Mode::ToolRustc), "release", None),
+ // FIXME: Used by stdarch in their test, should use a allow attribute instead.
+ (Some(Mode::Std), "dont_compile_me", None),
+ // FIXME: Used by serde_json, but we should not be triggering on external dependencies.
+ (Some(Mode::Rustc), "no_btreemap_remove_entry", None),
+ (Some(Mode::ToolRustc), "no_btreemap_remove_entry", None),
+ // FIXME: Used by crossbeam-utils, but we should not be triggering on external dependencies.
+ (Some(Mode::Rustc), "crossbeam_loom", None),
+ (Some(Mode::ToolRustc), "crossbeam_loom", None),
+ // FIXME: Used by proc-macro2, but we should not be triggering on external dependencies.
+ (Some(Mode::Rustc), "span_locations", None),
+ (Some(Mode::ToolRustc), "span_locations", None),
+];
+
/// A structure representing a Rust compiler.
///
/// Each compiler has a `stage` that it is associated with and a `host` that
// Properties derived from the above configuration
src: PathBuf,
out: PathBuf,
+ bootstrap_out: PathBuf,
rust_info: channel::GitInfo,
cargo_info: channel::GitInfo,
rls_info: channel::GitInfo,
}
}
+pub enum CLang {
+ C,
+ Cxx,
+}
+
impl Build {
/// Creates a new set of build configuration from the `flags` on the command
/// line and the filesystem `config`.
.expect("failed to read src/version");
let version = version.trim();
+ let bootstrap_out = if std::env::var("BOOTSTRAP_PYTHON").is_ok() {
+ out.join("bootstrap").join("debug")
+ } else {
+ let workspace_target_dir = std::env::var("CARGO_TARGET_DIR")
+ .map(PathBuf::from)
+ .unwrap_or_else(|_| src.join("target"));
+ let bootstrap_out = workspace_target_dir.join("debug");
+ if !bootstrap_out.join("rustc").exists() {
+ // this restriction can be lifted whenever https://github.com/rust-lang/rfcs/pull/3028 is implemented
+ panic!("run `cargo build --bins` before `cargo run`")
+ }
+ bootstrap_out
+ };
+
let mut build = Build {
initial_rustc: config.initial_rustc.clone(),
initial_cargo: config.initial_cargo.clone(),
version: version.to_string(),
src,
out,
+ bootstrap_out,
rust_info,
cargo_info,
}
if let Subcommand::Setup { profile } = &self.config.cmd {
- return setup::setup(&self.config.src, *profile);
+ return setup::setup(&self.config, *profile);
}
{
/// Returns the number of parallel jobs that have been configured for this
/// build.
fn jobs(&self) -> u32 {
- self.config.jobs.unwrap_or_else(|| num_cpus::get() as u32)
+ self.config.jobs.unwrap_or_else(|| {
+ std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get) as u32
+ })
}
fn debuginfo_map_to(&self, which: GitRepo) -> Option<String> {
/// Returns a list of flags to pass to the C compiler for the target
/// specified.
- fn cflags(&self, target: TargetSelection, which: GitRepo) -> Vec<String> {
+ fn cflags(&self, target: TargetSelection, which: GitRepo, c: CLang) -> Vec<String> {
+ let base = match c {
+ CLang::C => &self.cc[&target],
+ CLang::Cxx => &self.cxx[&target],
+ };
+
// Filter out -O and /O (the optimization flags) that we picked up from
// cc-rs because the build scripts will determine that for themselves.
- let mut base = self.cc[&target]
+ let mut base = base
.args()
.iter()
.map(|s| s.to_string_lossy().into_owned())
}
// Don't include optional deps if their features are not
// enabled. Ideally this would be computed from `cargo
- // metadata --features …`, but that is somewhat slow. Just
- // skip `build_helper` since there aren't any operations we
- // want to perform on it. In the future, we may want to
- // consider just filtering all build and dev dependencies in
- // metadata::build.
+ // metadata --features …`, but that is somewhat slow. In
+ // the future, we may want to consider just filtering all
+ // build and dev dependencies in metadata::build.
if visited.insert(dep)
- && dep != "build_helper"
&& (dep != "profiler_builtins"
|| target
.map(|t| self.config.profiler_enabled(t))
use std::path::PathBuf;
use std::process::Command;
-use build_helper::output;
use serde::Deserialize;
use crate::cache::INTERNER;
+use crate::util::output;
use crate::{Build, Crate};
#[derive(Deserialize)]
use std::path::{Path, PathBuf};
use std::process::Command;
-use build_helper::{output, t};
-
use crate::builder::{Builder, RunConfig, ShouldRun, Step};
use crate::config::TargetSelection;
-use crate::util::{self, exe};
-use crate::GitRepo;
-use build_helper::up_to_date;
+use crate::util::{self, exe, output, t, up_to_date};
+use crate::{CLang, GitRepo};
pub struct Meta {
stamp: HashStamp,
}
cfg.build_arg("-j").build_arg(builder.jobs().to_string());
- let mut cflags: OsString = builder.cflags(target, GitRepo::Llvm).join(" ").into();
+ let mut cflags: OsString = builder.cflags(target, GitRepo::Llvm, CLang::C).join(" ").into();
if let Some(ref s) = builder.config.llvm_cflags {
cflags.push(" ");
cflags.push(s);
if builder.config.llvm_clang_cl.is_some() {
cflags.push(&format!(" --target={}", target));
}
- if let Some(flags) = env::var_os("CFLAGS") {
- cflags.push(" ");
- cflags.push(flags);
- }
cfg.define("CMAKE_C_FLAGS", cflags);
- let mut cxxflags: OsString = builder.cflags(target, GitRepo::Llvm).join(" ").into();
+ let mut cxxflags: OsString = builder.cflags(target, GitRepo::Llvm, CLang::Cxx).join(" ").into();
if let Some(ref s) = builder.config.llvm_cxxflags {
cxxflags.push(" ");
cxxflags.push(s);
if builder.config.llvm_clang_cl.is_some() {
cxxflags.push(&format!(" --target={}", target));
}
- if let Some(flags) = env::var_os("CXXFLAGS") {
- cxxflags.push(" ");
- cxxflags.push(flags);
- }
cfg.define("CMAKE_CXX_FLAGS", cxxflags);
if let Some(ar) = builder.ar(target) {
if ar.is_absolute() {
ldflags.push_all(flags);
}
- if let Some(flags) = env::var_os("LDFLAGS") {
+ if let Some(flags) = get_var("LDFLAGS", &builder.config.build.triple, &target.triple) {
ldflags.push_all(&flags);
}
}
}
+// Adapted from https://github.com/alexcrichton/cc-rs/blob/fba7feded71ee4f63cfe885673ead6d7b4f2f454/src/lib.rs#L2347-L2365
+fn get_var(var_base: &str, host: &str, target: &str) -> Option<OsString> {
+ let kind = if host == target { "HOST" } else { "TARGET" };
+ let target_u = target.replace("-", "_");
+ env::var_os(&format!("{}_{}", var_base, target))
+ .or_else(|| env::var_os(&format!("{}_{}", var_base, target_u)))
+ .or_else(|| env::var_os(&format!("{}_{}", kind, var_base)))
+ .or_else(|| env::var_os(var_base))
+}
+
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Lld {
pub target: TargetSelection,
// there's probably a lot of reasons you can't do that other than this.
let llvm_config_shim = env::current_exe().unwrap().with_file_name("llvm-config-wrapper");
+ // Re-use the same flags as llvm to control the level of debug information
+ // generated for lld.
+ let profile = match (builder.config.llvm_optimize, builder.config.llvm_release_debuginfo) {
+ (false, _) => "Debug",
+ (true, false) => "Release",
+ (true, true) => "RelWithDebInfo",
+ };
+
cfg.out_dir(&out_dir)
- .profile("Release")
+ .profile(profile)
.env("LLVM_CONFIG_REAL", &llvm_config)
.define("LLVM_CONFIG_PATH", llvm_config_shim)
.define("LLVM_INCLUDE_TESTS", "OFF");
use crate::builder::{Builder, RunConfig, ShouldRun, Step};
use crate::dist::distdir;
use crate::tool::Tool;
-use build_helper::output;
+use crate::util::output;
use std::process::Command;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
use std::path::PathBuf;
use std::process::Command;
-use build_helper::output;
-
use crate::cache::INTERNER;
use crate::config::Target;
+use crate::util::output;
use crate::Build;
pub struct Finder {
-use crate::TargetSelection;
use crate::{t, VERSION};
+use crate::{Config, TargetSelection};
use std::env::consts::EXE_SUFFIX;
use std::fmt::Write as _;
use std::fs::File;
}
}
-pub fn setup(src_path: &Path, profile: Profile) {
- let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from);
+pub fn setup(config: &Config, profile: Profile) {
+ let path = &config.config;
- if cfg_file.as_ref().map_or(false, |f| f.exists()) {
- let file = cfg_file.unwrap();
+ if path.exists() {
println!(
"error: you asked `x.py` to setup a new config file, but one already exists at `{}`",
- file.display()
+ path.display()
);
- println!("help: try adding `profile = \"{}\"` at the top of {}", profile, file.display());
+ println!("help: try adding `profile = \"{}\"` at the top of {}", profile, path.display());
println!(
"note: this will use the configuration in {}",
- profile.include_path(src_path).display()
+ profile.include_path(&config.src).display()
);
std::process::exit(1);
}
- let path = cfg_file.unwrap_or_else(|| "config.toml".into());
let settings = format!(
"# Includes one of the default files in src/bootstrap/defaults\n\
profile = \"{}\"\n\
);
t!(fs::write(path, settings));
- let include_path = profile.include_path(src_path);
+ let include_path = profile.include_path(&config.src);
println!("`x.py` will now use the configuration at {}", include_path.display());
let build = TargetSelection::from_user(&env!("BUILD_TRIPLE"));
println!();
- t!(install_git_hook_maybe(src_path));
+ t!(install_git_hook_maybe(&config.src));
println!();
process::Command,
};
-use build_helper::t;
-
use crate::builder::Builder;
+use crate::util::t;
#[derive(Copy, Clone)]
pub(crate) enum OverlayKind {
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
-use build_helper::{self, output, t};
-
use crate::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step};
use crate::cache::Interned;
use crate::compile;
use crate::native;
use crate::tool::{self, SourceType, Tool};
use crate::toolstate::ToolState;
-use crate::util::{self, add_link_lib_path, dylib_path, dylib_path_var};
+use crate::util::{self, add_link_lib_path, dylib_path, dylib_path_var, output, t};
use crate::Crate as CargoCrate;
-use crate::{envify, DocTests, GitRepo, Mode};
+use crate::{envify, CLang, DocTests, GitRepo, Mode};
const ADB_TEST_DIR: &str = "/data/tmp/work";
}
fn run(self, builder: &Builder<'_>) {
- let rustdoc = builder.out.join("bootstrap/debug/rustdoc");
+ let rustdoc = builder.bootstrap_out.join("rustdoc");
let mut cmd = builder.tool_cmd(Tool::RustdocTheme);
cmd.arg(rustdoc.to_str().unwrap())
.arg(builder.src.join("src/librustdoc/html/static/css/themes").to_str().unwrap())
.arg("--cxx")
.arg(builder.cxx(target).unwrap())
.arg("--cflags")
- .arg(builder.cflags(target, GitRepo::Rustc).join(" "));
+ .arg(builder.cflags(target, GitRepo::Rustc, CLang::C).join(" "))
+ .arg("--cxxflags")
+ .arg(builder.cflags(target, GitRepo::Rustc, CLang::Cxx).join(" "));
copts_passed = true;
if let Some(ar) = builder.ar(target) {
cmd.arg("--ar").arg(ar);
cmd.arg("--llvm-components").arg("");
}
if !copts_passed {
- cmd.arg("--cc").arg("").arg("--cxx").arg("").arg("--cflags").arg("");
+ cmd.arg("--cc")
+ .arg("")
+ .arg("--cxx")
+ .arg("")
+ .arg("--cflags")
+ .arg("")
+ .arg("--cxxflags")
+ .arg("");
}
if builder.remote_tested(target) {
.current_dir(&dir),
);
builder.run(
- Command::new(build_helper::make(&builder.config.build.triple))
- .arg("check")
- .current_dir(&dir),
+ Command::new(util::make(&builder.config.build.triple)).arg("check").current_dir(&dir),
);
// Now make sure that rust-src has all of libstd's dependencies
.current_dir(builder.src.join("src/bootstrap"))
.env("RUSTFLAGS", "-Cdebuginfo=2")
.env("CARGO_TARGET_DIR", builder.out.join("bootstrap"))
+ // HACK: bootstrap's tests want to know the output directory, but there's no way to set
+ // it except through config.toml. Set it through an env variable instead.
.env("BOOTSTRAP_OUTPUT_DIRECTORY", &builder.config.out)
.env("BOOTSTRAP_INITIAL_CARGO", &builder.config.initial_cargo)
.env("RUSTC_BOOTSTRAP", "1")
use std::path::{Path, PathBuf};
use std::process::{exit, Command};
-use build_helper::t;
-
use crate::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step};
use crate::channel::GitInfo;
use crate::compile;
use crate::config::TargetSelection;
use crate::toolstate::ToolState;
-use crate::util::{add_dylib_path, exe};
+use crate::util::{add_dylib_path, exe, t};
use crate::Compiler;
use crate::Mode;
use crate::builder::{Builder, RunConfig, ShouldRun, Step};
-use build_helper::t;
+use crate::util::t;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::env;
type ToolstateData = HashMap<Box<str>, ToolState>;
-#[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq, PartialOrd)]
+#[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, PartialOrd)]
#[serde(rename_all = "kebab-case")]
/// Whether a tool can be compiled, tested or neither
pub enum ToolState {
}
}
-impl Default for ToolState {
- fn default() -> Self {
- // err on the safe side
- ToolState::BuildFail
- }
-}
-
/// Number of days after the last promotion of beta.
/// Its value is 41 on the Tuesday where "Promote master to beta (T-2)" happens.
/// The Wednesday after this has value 0.
t!(fs::write(&history_path, file));
}
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Deserialize)]
struct RepoState {
tool: String,
windows: ToolState,
linux: ToolState,
- commit: String,
- datetime: String,
}
impl RepoState {
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
-use std::process::Command;
+use std::process::{Command, Stdio};
use std::str;
-use std::time::Instant;
-
-use build_helper::t;
+use std::time::{Instant, SystemTime, UNIX_EPOCH};
use crate::builder::Builder;
use crate::config::{Config, TargetSelection};
+/// A helper macro to `unwrap` a result except also print out details like:
+///
+/// * The file/line of the panic
+/// * The expression that failed
+/// * The error itself
+///
+/// This is currently used judiciously throughout the build system rather than
+/// using a `Result` with `try!`, but this may change one day...
+macro_rules! t {
+ ($e:expr) => {
+ match $e {
+ Ok(e) => e,
+ Err(e) => panic!("{} failed with {}", stringify!($e), e),
+ }
+ };
+ // it can show extra info in the second parameter
+ ($e:expr, $extra:expr) => {
+ match $e {
+ Ok(e) => e,
+ Err(e) => panic!("{} failed with {} ({:?})", stringify!($e), e, $extra),
+ }
+ };
+}
+pub(crate) use t;
+
/// Given an executable called `name`, return the filename for the
/// executable for a particular target.
pub fn exe(name: &str, target: TargetSelection) -> String {
_ => None,
}
}
+
+pub fn run(cmd: &mut Command, print_cmd_on_fail: bool) {
+ if !try_run(cmd, print_cmd_on_fail) {
+ std::process::exit(1);
+ }
+}
+
+pub fn try_run(cmd: &mut Command, print_cmd_on_fail: bool) -> bool {
+ let status = match cmd.status() {
+ Ok(status) => status,
+ Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", cmd, e)),
+ };
+ if !status.success() && print_cmd_on_fail {
+ println!(
+ "\n\ncommand did not execute successfully: {:?}\n\
+ expected success, got: {}\n\n",
+ cmd, status
+ );
+ }
+ status.success()
+}
+
+pub fn run_suppressed(cmd: &mut Command) {
+ if !try_run_suppressed(cmd) {
+ std::process::exit(1);
+ }
+}
+
+pub fn try_run_suppressed(cmd: &mut Command) -> bool {
+ let output = match cmd.output() {
+ Ok(status) => status,
+ Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", cmd, e)),
+ };
+ if !output.status.success() {
+ println!(
+ "\n\ncommand did not execute successfully: {:?}\n\
+ expected success, got: {}\n\n\
+ stdout ----\n{}\n\
+ stderr ----\n{}\n\n",
+ cmd,
+ output.status,
+ String::from_utf8_lossy(&output.stdout),
+ String::from_utf8_lossy(&output.stderr)
+ );
+ }
+ output.status.success()
+}
+
+pub fn make(host: &str) -> PathBuf {
+ if host.contains("dragonfly")
+ || host.contains("freebsd")
+ || host.contains("netbsd")
+ || host.contains("openbsd")
+ {
+ PathBuf::from("gmake")
+ } else {
+ PathBuf::from("make")
+ }
+}
+
+#[track_caller]
+pub fn output(cmd: &mut Command) -> String {
+ let output = match cmd.stderr(Stdio::inherit()).output() {
+ Ok(status) => status,
+ Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", cmd, e)),
+ };
+ if !output.status.success() {
+ panic!(
+ "command did not execute successfully: {:?}\n\
+ expected success, got: {}",
+ cmd, output.status
+ );
+ }
+ String::from_utf8(output.stdout).unwrap()
+}
+
+/// Returns the last-modified time for `path`, or zero if it doesn't exist.
+pub fn mtime(path: &Path) -> SystemTime {
+ fs::metadata(path).and_then(|f| f.modified()).unwrap_or(UNIX_EPOCH)
+}
+
+/// Returns `true` if `dst` is up to date given that the file or files in `src`
+/// are used to generate it.
+///
+/// Uses last-modified time checks to verify this.
+pub fn up_to_date(src: &Path, dst: &Path) -> bool {
+ if !dst.exists() {
+ return false;
+ }
+ let threshold = mtime(dst);
+ let meta = match fs::metadata(src) {
+ Ok(meta) => meta,
+ Err(e) => panic!("source {:?} failed to get metadata: {}", src, e),
+ };
+ if meta.is_dir() {
+ dir_up_to_date(src, threshold)
+ } else {
+ meta.modified().unwrap_or(UNIX_EPOCH) <= threshold
+ }
+}
+
+fn dir_up_to_date(src: &Path, threshold: SystemTime) -> bool {
+ t!(fs::read_dir(src)).map(|e| t!(e)).all(|e| {
+ let meta = t!(e.metadata());
+ if meta.is_dir() {
+ dir_up_to_date(&e.path(), threshold)
+ } else {
+ meta.modified().unwrap_or(UNIX_EPOCH) < threshold
+ }
+ })
+}
+
+fn fail(s: &str) -> ! {
+ println!("\n\n{}\n\n", s);
+ std::process::exit(1);
+}
+
+/// Copied from `std::path::absolute` until it stabilizes.
+///
+/// FIXME: this shouldn't exist.
+pub(crate) fn absolute(path: &Path) -> PathBuf {
+ if path.as_os_str().is_empty() {
+ panic!("can't make empty path absolute");
+ }
+ #[cfg(unix)]
+ {
+ t!(absolute_unix(path), format!("could not make path absolute: {}", path.display()))
+ }
+ #[cfg(windows)]
+ {
+ t!(absolute_windows(path), format!("could not make path absolute: {}", path.display()))
+ }
+ #[cfg(not(any(unix, windows)))]
+ {
+ println!("warning: bootstrap is not supported on non-unix platforms");
+ t!(std::fs::canonicalize(t!(std::env::current_dir()))).join(path)
+ }
+}
+
+#[cfg(unix)]
+/// Make a POSIX path absolute without changing its semantics.
+fn absolute_unix(path: &Path) -> io::Result<PathBuf> {
+ // This is mostly a wrapper around collecting `Path::components`, with
+ // exceptions made where this conflicts with the POSIX specification.
+ // See 4.13 Pathname Resolution, IEEE Std 1003.1-2017
+ // https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13
+
+ use std::os::unix::prelude::OsStrExt;
+ let mut components = path.components();
+ let path_os = path.as_os_str().as_bytes();
+
+ let mut normalized = if path.is_absolute() {
+ // "If a pathname begins with two successive <slash> characters, the
+ // first component following the leading <slash> characters may be
+ // interpreted in an implementation-defined manner, although more than
+ // two leading <slash> characters shall be treated as a single <slash>
+ // character."
+ if path_os.starts_with(b"//") && !path_os.starts_with(b"///") {
+ components.next();
+ PathBuf::from("//")
+ } else {
+ PathBuf::new()
+ }
+ } else {
+ env::current_dir()?
+ };
+ normalized.extend(components);
+
+ // "Interfaces using pathname resolution may specify additional constraints
+ // when a pathname that does not name an existing directory contains at
+ // least one non- <slash> character and contains one or more trailing
+ // <slash> characters".
+ // A trailing <slash> is also meaningful if "a symbolic link is
+ // encountered during pathname resolution".
+
+ if path_os.ends_with(b"/") {
+ normalized.push("");
+ }
+
+ Ok(normalized)
+}
+
+#[cfg(windows)]
+fn absolute_windows(path: &std::path::Path) -> std::io::Result<std::path::PathBuf> {
+ use std::ffi::OsString;
+ use std::io::Error;
+ use std::os::windows::ffi::{OsStrExt, OsStringExt};
+ use std::ptr::null_mut;
+ #[link(name = "kernel32")]
+ extern "system" {
+ fn GetFullPathNameW(
+ lpFileName: *const u16,
+ nBufferLength: u32,
+ lpBuffer: *mut u16,
+ lpFilePart: *mut *const u16,
+ ) -> u32;
+ }
+
+ unsafe {
+ // encode the path as UTF-16
+ let path: Vec<u16> = path.as_os_str().encode_wide().chain([0]).collect();
+ let mut buffer = Vec::new();
+ // Loop until either success or failure.
+ loop {
+ // Try to get the absolute path
+ let len = GetFullPathNameW(
+ path.as_ptr(),
+ buffer.len().try_into().unwrap(),
+ buffer.as_mut_ptr(),
+ null_mut(),
+ );
+ match len as usize {
+ // Failure
+ 0 => return Err(Error::last_os_error()),
+ // Buffer is too small, resize.
+ len if len > buffer.len() => buffer.resize(len, 0),
+ // Success!
+ len => {
+ buffer.truncate(len);
+ return Ok(OsString::from_wide(&buffer).into());
+ }
+ }
+ }
+ }
+}
+++ /dev/null
-[package]
-name = "build_helper"
-version = "0.1.0"
-edition = "2021"
-
-[lib]
-path = "lib.rs"
+++ /dev/null
-use std::ffi::{OsStr, OsString};
-use std::fmt::Display;
-use std::path::{Path, PathBuf};
-use std::process::{Command, Stdio};
-use std::time::{SystemTime, UNIX_EPOCH};
-use std::{env, fs};
-
-/// A helper macro to `unwrap` a result except also print out details like:
-///
-/// * The file/line of the panic
-/// * The expression that failed
-/// * The error itself
-///
-/// This is currently used judiciously throughout the build system rather than
-/// using a `Result` with `try!`, but this may change one day...
-#[macro_export]
-macro_rules! t {
- ($e:expr) => {
- match $e {
- Ok(e) => e,
- Err(e) => panic!("{} failed with {}", stringify!($e), e),
- }
- };
- // it can show extra info in the second parameter
- ($e:expr, $extra:expr) => {
- match $e {
- Ok(e) => e,
- Err(e) => panic!("{} failed with {} ({:?})", stringify!($e), e, $extra),
- }
- };
-}
-
-/// Reads an environment variable and adds it to dependencies.
-/// Supposed to be used for all variables except those set for build scripts by cargo
-/// <https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts>
-pub fn tracked_env_var_os<K: AsRef<OsStr> + Display>(key: K) -> Option<OsString> {
- println!("cargo:rerun-if-env-changed={}", key);
- env::var_os(key)
-}
-
-// Because Cargo adds the compiler's dylib path to our library search path, llvm-config may
-// break: the dylib path for the compiler, as of this writing, contains a copy of the LLVM
-// shared library, which means that when our freshly built llvm-config goes to load it's
-// associated LLVM, it actually loads the compiler's LLVM. In particular when building the first
-// compiler (i.e., in stage 0) that's a problem, as the compiler's LLVM is likely different from
-// the one we want to use. As such, we restore the environment to what bootstrap saw. This isn't
-// perfect -- we might actually want to see something from Cargo's added library paths -- but
-// for now it works.
-pub fn restore_library_path() {
- let key = tracked_env_var_os("REAL_LIBRARY_PATH_VAR").expect("REAL_LIBRARY_PATH_VAR");
- if let Some(env) = tracked_env_var_os("REAL_LIBRARY_PATH") {
- env::set_var(&key, &env);
- } else {
- env::remove_var(&key);
- }
-}
-
-pub fn run(cmd: &mut Command, print_cmd_on_fail: bool) {
- if !try_run(cmd, print_cmd_on_fail) {
- std::process::exit(1);
- }
-}
-
-pub fn try_run(cmd: &mut Command, print_cmd_on_fail: bool) -> bool {
- let status = match cmd.status() {
- Ok(status) => status,
- Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", cmd, e)),
- };
- if !status.success() && print_cmd_on_fail {
- println!(
- "\n\ncommand did not execute successfully: {:?}\n\
- expected success, got: {}\n\n",
- cmd, status
- );
- }
- status.success()
-}
-
-pub fn run_suppressed(cmd: &mut Command) {
- if !try_run_suppressed(cmd) {
- std::process::exit(1);
- }
-}
-
-pub fn try_run_suppressed(cmd: &mut Command) -> bool {
- let output = match cmd.output() {
- Ok(status) => status,
- Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", cmd, e)),
- };
- if !output.status.success() {
- println!(
- "\n\ncommand did not execute successfully: {:?}\n\
- expected success, got: {}\n\n\
- stdout ----\n{}\n\
- stderr ----\n{}\n\n",
- cmd,
- output.status,
- String::from_utf8_lossy(&output.stdout),
- String::from_utf8_lossy(&output.stderr)
- );
- }
- output.status.success()
-}
-
-pub fn make(host: &str) -> PathBuf {
- if host.contains("dragonfly")
- || host.contains("freebsd")
- || host.contains("netbsd")
- || host.contains("openbsd")
- {
- PathBuf::from("gmake")
- } else {
- PathBuf::from("make")
- }
-}
-
-#[track_caller]
-pub fn output(cmd: &mut Command) -> String {
- let output = match cmd.stderr(Stdio::inherit()).output() {
- Ok(status) => status,
- Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", cmd, e)),
- };
- if !output.status.success() {
- panic!(
- "command did not execute successfully: {:?}\n\
- expected success, got: {}",
- cmd, output.status
- );
- }
- String::from_utf8(output.stdout).unwrap()
-}
-
-pub fn rerun_if_changed_anything_in_dir(dir: &Path) {
- let mut stack = dir
- .read_dir()
- .unwrap()
- .map(|e| e.unwrap())
- .filter(|e| &*e.file_name() != ".git")
- .collect::<Vec<_>>();
- while let Some(entry) = stack.pop() {
- let path = entry.path();
- if entry.file_type().unwrap().is_dir() {
- stack.extend(path.read_dir().unwrap().map(|e| e.unwrap()));
- } else {
- println!("cargo:rerun-if-changed={}", path.display());
- }
- }
-}
-
-/// Returns the last-modified time for `path`, or zero if it doesn't exist.
-pub fn mtime(path: &Path) -> SystemTime {
- fs::metadata(path).and_then(|f| f.modified()).unwrap_or(UNIX_EPOCH)
-}
-
-/// Returns `true` if `dst` is up to date given that the file or files in `src`
-/// are used to generate it.
-///
-/// Uses last-modified time checks to verify this.
-pub fn up_to_date(src: &Path, dst: &Path) -> bool {
- if !dst.exists() {
- return false;
- }
- let threshold = mtime(dst);
- let meta = match fs::metadata(src) {
- Ok(meta) => meta,
- Err(e) => panic!("source {:?} failed to get metadata: {}", src, e),
- };
- if meta.is_dir() {
- dir_up_to_date(src, threshold)
- } else {
- meta.modified().unwrap_or(UNIX_EPOCH) <= threshold
- }
-}
-
-fn dir_up_to_date(src: &Path, threshold: SystemTime) -> bool {
- t!(fs::read_dir(src)).map(|e| t!(e)).all(|e| {
- let meta = t!(e.metadata());
- if meta.is_dir() {
- dir_up_to_date(&e.path(), threshold)
- } else {
- meta.modified().unwrap_or(UNIX_EPOCH) < threshold
- }
- })
-}
-
-fn fail(s: &str) -> ! {
- println!("\n\n{}\n\n", s);
- std::process::exit(1);
-}
-<link rel="shortcut icon" href="https://www.rust-lang.org/favicon.ico">
+<link rel="icon" href="https://www.rust-lang.org/favicon.ico">
<meta name="robots" content="noindex,follow">
-<link rel="shortcut icon" href="https://www.rust-lang.org/favicon.ico">
+<link rel="icon" href="https://www.rust-lang.org/favicon.ico">
All tier 2 targets with host tools support the full standard library.
-**NOTE:** Tier 2 targets currently do not build the `rust-docs` component.
+**NOTE:** The `rust-docs` component is not usually built for tier 2 targets,
+so Rustup may install the documentation for a similar tier 1 target instead.
target | notes
-------|-------
[`no_std`]: https://rust-embedded.github.io/book/intro/no-std.html
-**NOTE:** Tier 2 targets currently do not build the `rust-docs` component.
+**NOTE:** The `rust-docs` component is not usually built for tier 2 targets,
+so Rustup may install the documentation for a similar tier 1 target instead.
target | std | notes
-------|:---:|-------
#![doc(html_favicon_url = "https://example.com/favicon.ico")]
```
-This will put `<link rel="shortcut icon" href="{}">` into your docs, where
+This will put `<link rel="icon" href="{}">` into your docs, where
the string for the attribute goes into the `{}`.
If you don't use this attribute, there will be no favicon.
------------------------
The `c_variadic` language feature enables C-variadic functions to be
-defined in Rust. The may be called both from within Rust and via FFI.
+defined in Rust. They may be called both from within Rust and via FFI.
## Examples
askama = { version = "0.11", default-features = false, features = ["config"] }
atty = "0.2"
pulldown-cmark = { version = "0.9", default-features = false }
-minifier = "0.0.42"
+minifier = "0.0.43"
rayon = "1.5.1"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
smallvec = "1.6.1"
tempfile = "3"
-itertools = "0.10"
+itertools = "0.10.1"
regex = "1"
rustdoc-json-types = { path = "../rustdoc-json-types" }
tracing = "0.1"
}
WherePredicate::EqPredicate { lhs, rhs } => {
match lhs {
- Type::QPath { name: left_name, ref self_type, ref trait_, .. } => {
+ Type::QPath { ref assoc, ref self_type, ref trait_, .. } => {
let ty = &*self_type;
let mut new_trait = trait_.clone();
- if self.is_fn_trait(trait_) && left_name == sym::Output {
+ if self.is_fn_trait(trait_) && assoc.name == sym::Output {
ty_to_fn
.entry(*ty.clone())
.and_modify(|e| {
// to 'T: Iterator<Item=u8>'
GenericArgs::AngleBracketed { ref mut bindings, .. } => {
bindings.push(TypeBinding {
- name: left_name,
+ assoc: *assoc.clone(),
kind: TypeBindingKind::Equality { term: rhs },
});
}
g.where_predicates.retain(|pred| match pred {
clean::WherePredicate::BoundPredicate {
- ty: clean::QPath { self_type: box clean::Generic(ref s), trait_, name: _, .. },
+ ty: clean::QPath { self_type: box clean::Generic(ref s), trait_, .. },
bounds,
..
} => !(bounds.is_empty() || *s == kw::SelfUpper && trait_.def_id() == trait_did),
let trait_ = lifted.trait_ref(cx.tcx).clean(cx);
let self_type = self.self_ty().clean(cx);
Type::QPath {
- name: cx.tcx.associated_item(self.item_def_id).name,
+ assoc: Box::new(projection_to_path_segment(*self, cx)),
self_def_id: self_type.def_id(&cx.cache),
self_type: box self_type,
trait_,
}
}
+fn projection_to_path_segment(ty: ty::ProjectionTy<'_>, cx: &mut DocContext<'_>) -> PathSegment {
+ let item = cx.tcx.associated_item(ty.item_def_id);
+ let generics = cx.tcx.generics_of(ty.item_def_id);
+ PathSegment {
+ name: item.name,
+ args: GenericArgs::AngleBracketed {
+ args: substs_to_args(cx, &ty.substs[generics.parent_count..], false),
+ bindings: Default::default(),
+ },
+ }
+}
+
impl Clean<GenericParamDef> for ty::GenericParamDef {
fn clean(&self, cx: &mut DocContext<'_>) -> GenericParamDef {
let (name, kind) = match self.kind {
},
)
}
- ty::GenericParamDefKind::Const { has_default, .. } => (
+ ty::GenericParamDefKind::Const { has_default } => (
self.name,
GenericParamDefKind::Const {
did: self.def_id,
})
.collect::<Vec<GenericParamDef>>();
- // param index -> [(DefId of trait, associated type name, type)]
- let mut impl_trait_proj = FxHashMap::<u32, Vec<(DefId, Symbol, Ty<'_>)>>::default();
+ // param index -> [(DefId of trait, associated type name and generics, type)]
+ let mut impl_trait_proj = FxHashMap::<u32, Vec<(DefId, PathSegment, Ty<'_>)>>::default();
let where_predicates = preds
.predicates
let proj = projection
.map(|p| (p.skip_binder().projection_ty.clean(cx), p.skip_binder().term));
- if let Some(((_, trait_did, name), rhs)) =
- proj.as_ref().and_then(|(lhs, rhs)| Some((lhs.projection()?, rhs)))
+ if let Some(((_, trait_did, name), rhs)) = proj
+ .as_ref()
+ .and_then(|(lhs, rhs): &(Type, _)| Some((lhs.projection()?, rhs)))
{
// FIXME(...): Remove this unwrap()
impl_trait_proj.entry(param_idx).or_default().push((
TyMethodItem(t)
}
hir::TraitItemKind::Type(bounds, ref default) => {
+ let generics = enter_impl_trait(cx, |cx| self.generics.clean(cx));
let bounds = bounds.iter().filter_map(|x| x.clean(cx)).collect();
let default = default.map(|t| t.clean(cx));
- AssocTypeItem(bounds, default)
+ AssocTypeItem(Box::new(generics), bounds, default)
}
};
let what_rustc_thinks =
}
hir::ImplItemKind::TyAlias(ref hir_ty) => {
let type_ = hir_ty.clean(cx);
+ let generics = self.generics.clean(cx);
let item_type = hir_ty_to_ty(cx.tcx, hir_ty).clean(cx);
- TypedefItem(
- Typedef {
- type_,
- generics: Generics::default(),
- item_type: Some(item_type),
- },
- true,
- )
+ TypedefItem(Typedef { type_, generics, item_type: Some(item_type) }, true)
}
};
ty::AssocKind::Type => {
let my_name = self.name;
+ fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool {
+ match (¶m.kind, arg) {
+ (GenericParamDefKind::Type { .. }, GenericArg::Type(Type::Generic(ty)))
+ if *ty == param.name =>
+ {
+ true
+ }
+ (
+ GenericParamDefKind::Lifetime { .. },
+ GenericArg::Lifetime(Lifetime(lt)),
+ ) if *lt == param.name => true,
+ (GenericParamDefKind::Const { .. }, GenericArg::Const(c)) => {
+ match &c.kind {
+ ConstantKind::TyConst { expr } => expr == param.name.as_str(),
+ _ => false,
+ }
+ }
+ _ => false,
+ }
+ }
+
if let ty::TraitContainer(_) = self.container {
let bounds = tcx.explicit_item_bounds(self.def_id);
let predicates = ty::GenericPredicates { parent: None, predicates: bounds };
- let generics = clean_ty_generics(cx, tcx.generics_of(self.def_id), predicates);
+ let mut generics =
+ clean_ty_generics(cx, tcx.generics_of(self.def_id), predicates);
+ // Filter out the bounds that are (likely?) directly attached to the associated type,
+ // as opposed to being located in the where clause.
let mut bounds = generics
.where_predicates
- .iter()
- .filter_map(|pred| {
- let (name, self_type, trait_, bounds) = match *pred {
- WherePredicate::BoundPredicate {
- ty: QPath { ref name, ref self_type, ref trait_, .. },
- ref bounds,
- ..
- } => (name, self_type, trait_, bounds),
- _ => return None,
- };
- if *name != my_name {
- return None;
- }
- if trait_.def_id() != self.container.id() {
- return None;
+ .drain_filter(|pred| match *pred {
+ WherePredicate::BoundPredicate {
+ ty: QPath { ref assoc, ref self_type, ref trait_, .. },
+ ..
+ } => {
+ if assoc.name != my_name {
+ return false;
+ }
+ if trait_.def_id() != self.container.id() {
+ return false;
+ }
+ match **self_type {
+ Generic(ref s) if *s == kw::SelfUpper => {}
+ _ => return false,
+ }
+ match &assoc.args {
+ GenericArgs::AngleBracketed { args, bindings } => {
+ if !bindings.is_empty()
+ || generics
+ .params
+ .iter()
+ .zip(args)
+ .any(|(param, arg)| !param_eq_arg(param, arg))
+ {
+ return false;
+ }
+ }
+ GenericArgs::Parenthesized { .. } => {
+ // The only time this happens is if we're inside the rustdoc for Fn(),
+ // which only has one associated type, which is not a GAT, so whatever.
+ }
+ }
+ true
}
- match **self_type {
- Generic(ref s) if *s == kw::SelfUpper => {}
- _ => return None,
+ _ => false,
+ })
+ .flat_map(|pred| {
+ if let WherePredicate::BoundPredicate { bounds, .. } = pred {
+ bounds
+ } else {
+ unreachable!()
}
- Some(bounds)
})
- .flat_map(|i| i.iter().cloned())
.collect::<Vec<_>>();
// Our Sized/?Sized bound didn't get handled when creating the generics
// because we didn't actually get our whole set of bounds until just now
None
};
- AssocTypeItem(bounds, ty.map(|t| t.clean(cx)))
+ AssocTypeItem(Box::new(generics), 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);
};
register_res(cx, trait_.res);
Type::QPath {
- name: p.segments.last().expect("segments were empty").ident.name,
+ assoc: Box::new(p.segments.last().expect("segments were empty").clean(cx)),
self_def_id: Some(DefId::local(qself.hir_id.owner.local_def_index)),
self_type: box qself.clean(cx),
trait_,
let trait_ = hir::Path { span, res, segments: &[] }.clean(cx);
register_res(cx, trait_.res);
Type::QPath {
- name: segment.ident.name,
+ assoc: Box::new(segment.clean(cx)),
self_def_id: res.opt_def_id(),
self_type: box qself.clean(cx),
trait_,
});
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()
- };
+ let cleaned = if !lt.is_elided() { lt.clean(cx) } else { Lifetime::elided() };
substs.insert(lt_def_id.to_def_id(), SubstParam::Lifetime(cleaned));
}
indices.lifetimes += 1;
let mut bindings = vec![];
for pb in obj.projection_bounds() {
bindings.push(TypeBinding {
- name: cx.tcx.associated_item(pb.item_def_id()).name,
+ assoc: projection_to_path_segment(
+ pb.skip_binder()
+ .lift_to_tcx(cx.tcx)
+ .unwrap()
+ // HACK(compiler-errors): Doesn't actually matter what self
+ // type we put here, because we're only using the GAT's substs.
+ .with_self_ty(cx.tcx, cx.tcx.types.self_param)
+ .projection_ty,
+ cx,
+ ),
kind: TypeBindingKind::Equality { term: pb.skip_binder().term.clean(cx) },
});
}
== trait_ref.skip_binder()
{
Some(TypeBinding {
- name: cx
- .tcx
- .associated_item(proj.projection_ty.item_def_id)
- .name,
+ assoc: projection_to_path_segment(
+ proj.projection_ty,
+ cx,
+ ),
kind: TypeBindingKind::Equality {
term: proj.term.clean(cx),
},
impl Clean<TypeBinding> for hir::TypeBinding<'_> {
fn clean(&self, cx: &mut DocContext<'_>) -> TypeBinding {
- TypeBinding { name: self.ident.name, kind: self.kind.clean(cx) }
+ TypeBinding {
+ assoc: PathSegment { name: self.ident.name, args: self.gen_args.clean(cx) },
+ kind: self.kind.clean(cx),
+ }
}
}
cx: &clean::DocContext<'_>,
bounds: &mut Vec<clean::GenericBound>,
trait_did: DefId,
- name: Symbol,
+ assoc: clean::PathSegment,
rhs: &clean::Term,
) -> bool {
!bounds.iter_mut().any(|b| {
match last.args {
PP::AngleBracketed { ref mut bindings, .. } => {
bindings.push(clean::TypeBinding {
- name,
+ assoc: assoc.clone(),
kind: clean::TypeBindingKind::Equality { term: rhs.clone() },
});
}
///
/// The bounds may be non-empty if there is a `where` clause.
/// The `Option<Type>` is the default concrete type (e.g. `trait Trait { type Target = usize; }`)
- AssocTypeItem(Vec<GenericBound>, Option<Type>),
+ AssocTypeItem(Box<Generics>, Vec<GenericBound>, Option<Type>),
/// An item that has been stripped by a rustdoc pass
StrippedItem(Box<ItemKind>),
KeywordItem(Symbol),
| ProcMacroItem(_)
| PrimitiveItem(_)
| AssocConstItem(_, _)
- | AssocTypeItem(_, _)
+ | AssocTypeItem(..)
| StrippedItem(_)
| KeywordItem(_) => [].iter(),
}
/// A qualified path to an associated item: `<Type as Trait>::Name`
QPath {
- name: Symbol,
+ assoc: Box<PathSegment>,
self_type: Box<Type>,
/// FIXME: This is a hack that should be removed; see [this discussion][1].
///
// `Type` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Type, 72);
+rustc_data_structures::static_assert_size!(Type, 80);
impl Type {
/// When comparing types for equality, it can help to ignore `&` wrapping.
self.primitive_type().is_some()
}
- crate fn projection(&self) -> Option<(&Type, DefId, Symbol)> {
- let (self_, trait_, name) = match self {
- QPath { self_type, trait_, name, .. } => (self_type, trait_, name),
- _ => return None,
- };
- Some((&self_, trait_.def_id(), *name))
+ crate fn projection(&self) -> Option<(&Type, DefId, PathSegment)> {
+ if let QPath { self_type, trait_, assoc, .. } = self {
+ Some((&self_type, trait_.def_id(), *assoc.clone()))
+ } else {
+ None
+ }
}
fn inner_def_id(&self, cache: Option<&Cache>) -> Option<DefId> {
// `GenericArg` can occur many times in a single `Path`, so make sure it
// doesn't increase in size unexpectedly.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(GenericArg, 80);
+rustc_data_structures::static_assert_size!(GenericArg, 88);
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
crate enum GenericArgs {
/// `A: Send + Sync` in `Foo<A: Send + Sync>`).
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
crate struct TypeBinding {
- crate name: Symbol,
+ crate assoc: PathSegment,
crate kind: TypeBindingKind,
}
Crate { module, primitives, external_traits: cx.external_traits.clone() }
}
-fn external_generic_args(
+crate fn substs_to_args(
cx: &mut DocContext<'_>,
- did: DefId,
- has_self: bool,
- bindings: Vec<TypeBinding>,
- substs: SubstsRef<'_>,
-) -> GenericArgs {
- let mut skip_self = has_self;
- let mut ty_kind = None;
- let args: Vec<_> = substs
+ substs: &[ty::subst::GenericArg<'_>],
+ mut skip_first: bool,
+) -> Vec<GenericArg> {
+ substs
.iter()
.filter_map(|kind| match kind.unpack() {
GenericArgKind::Lifetime(lt) => match *lt {
}
_ => lt.clean(cx).map(GenericArg::Lifetime),
},
- GenericArgKind::Type(_) if skip_self => {
- skip_self = false;
+ GenericArgKind::Type(_) if skip_first => {
+ skip_first = false;
None
}
- GenericArgKind::Type(ty) => {
- ty_kind = Some(ty.kind());
- Some(GenericArg::Type(ty.clean(cx)))
- }
+ GenericArgKind::Type(ty) => Some(GenericArg::Type(ty.clean(cx))),
GenericArgKind::Const(ct) => Some(GenericArg::Const(Box::new(ct.clean(cx)))),
})
- .collect();
+ .collect()
+}
+
+fn external_generic_args(
+ cx: &mut DocContext<'_>,
+ did: DefId,
+ has_self: bool,
+ bindings: Vec<TypeBinding>,
+ substs: SubstsRef<'_>,
+) -> GenericArgs {
+ let args = substs_to_args(cx, &substs, has_self);
if cx.tcx.fn_trait_kind_from_lang_item(did).is_some() {
- let inputs = match ty_kind.unwrap() {
- ty::Tuple(tys) => tys.iter().map(|t| t.clean(cx)).collect(),
- _ => return GenericArgs::AngleBracketed { args, bindings: bindings.into() },
- };
+ let inputs =
+ // The trait's first substitution is the one after self, if there is one.
+ match substs.iter().nth(if has_self { 1 } else { 0 }).unwrap().expect_ty().kind() {
+ ty::Tuple(tys) => tys.iter().map(|t| t.clean(cx)).collect(),
+ _ => return GenericArgs::AngleBracketed { args, bindings: bindings.into() },
+ };
let output = None;
// FIXME(#20299) return type comes from a projection now
// match types[1].kind {
| ProcMacroItem(_)
| PrimitiveItem(_)
| AssocConstItem(_, _)
- | AssocTypeItem(_, _)
+ | AssocTypeItem(..)
| KeywordItem(_) => kind,
}
}
}
}
-fn comma_sep<T: fmt::Display>(items: impl Iterator<Item = T>) -> impl fmt::Display {
+fn comma_sep<T: fmt::Display>(
+ items: impl Iterator<Item = T>,
+ space_after_comma: bool,
+) -> impl fmt::Display {
display_fn(move |f| {
for (i, item) in items.enumerate() {
if i != 0 {
- write!(f, ", ")?;
+ write!(f, ",{}", if space_after_comma { " " } else { "" })?;
}
fmt::Display::fmt(&item, f)?;
}
}
if f.alternate() {
- write!(f, "<{:#}>", comma_sep(real_params.map(|g| g.print(cx))))
+ write!(f, "<{:#}>", comma_sep(real_params.map(|g| g.print(cx)), true))
} else {
- write!(f, "<{}>", comma_sep(real_params.map(|g| g.print(cx))))
+ write!(f, "<{}>", comma_sep(real_params.map(|g| g.print(cx)), true))
}
})
}
end_newline: bool,
) -> impl fmt::Display + 'a + Captures<'tcx> {
display_fn(move |f| {
- if gens.where_predicates.is_empty() {
+ let mut where_predicates = gens.where_predicates.iter().filter(|pred| {
+ !matches!(pred, clean::WherePredicate::BoundPredicate { bounds, .. } if bounds.is_empty())
+ }).map(|pred| {
+ display_fn(move |f| {
+ if f.alternate() {
+ f.write_str(" ")?;
+ } else {
+ f.write_str("<br>")?;
+ }
+
+ match pred {
+ clean::WherePredicate::BoundPredicate { ty, bounds, bound_params } => {
+ let bounds = bounds;
+ let for_prefix = if bound_params.is_empty() {
+ String::new()
+ } else if f.alternate() {
+ format!(
+ "for<{:#}> ",
+ comma_sep(bound_params.iter().map(|lt| lt.print()), true)
+ )
+ } else {
+ format!(
+ "for<{}> ",
+ comma_sep(bound_params.iter().map(|lt| lt.print()), true)
+ )
+ };
+
+ if f.alternate() {
+ write!(
+ f,
+ "{}{:#}: {:#}",
+ for_prefix,
+ ty.print(cx),
+ print_generic_bounds(bounds, cx)
+ )
+ } else {
+ write!(
+ f,
+ "{}{}: {}",
+ for_prefix,
+ ty.print(cx),
+ print_generic_bounds(bounds, cx)
+ )
+ }
+ }
+ clean::WherePredicate::RegionPredicate { lifetime, bounds } => {
+ write!(
+ f,
+ "{}: {}",
+ lifetime.print(),
+ bounds
+ .iter()
+ .map(|b| b.print(cx).to_string())
+ .collect::<Vec<_>>()
+ .join(" + ")
+ )
+ }
+ clean::WherePredicate::EqPredicate { lhs, rhs } => {
+ if f.alternate() {
+ write!(f, "{:#} == {:#}", lhs.print(cx), rhs.print(cx),)
+ } else {
+ write!(f, "{} == {}", lhs.print(cx), rhs.print(cx),)
+ }
+ }
+ }
+ })
+ }).peekable();
+
+ if where_predicates.peek().is_none() {
return Ok(());
}
+
let mut clause = String::new();
+
if f.alternate() {
clause.push_str(" where");
} else {
clause.push_str(" <span class=\"where\">where");
}
}
- for (i, pred) in gens.where_predicates.iter().enumerate() {
- if f.alternate() {
- clause.push(' ');
- } else {
- clause.push_str("<br>");
- }
- match pred {
- clean::WherePredicate::BoundPredicate { ty, bounds, bound_params } => {
- let bounds = bounds;
- let for_prefix = match bound_params.len() {
- 0 => String::new(),
- _ if f.alternate() => {
- format!(
- "for<{:#}> ",
- comma_sep(bound_params.iter().map(|lt| lt.print()))
- )
- }
- _ => format!(
- "for<{}> ",
- comma_sep(bound_params.iter().map(|lt| lt.print()))
- ),
- };
-
- if f.alternate() {
- clause.push_str(&format!(
- "{}{:#}: {:#}",
- for_prefix,
- ty.print(cx),
- print_generic_bounds(bounds, cx)
- ));
- } else {
- clause.push_str(&format!(
- "{}{}: {}",
- for_prefix,
- ty.print(cx),
- print_generic_bounds(bounds, cx)
- ));
- }
- }
- clean::WherePredicate::RegionPredicate { lifetime, bounds } => {
- clause.push_str(&format!(
- "{}: {}",
- lifetime.print(),
- bounds
- .iter()
- .map(|b| b.print(cx).to_string())
- .collect::<Vec<_>>()
- .join(" + ")
- ));
- }
- clean::WherePredicate::EqPredicate { lhs, rhs } => {
- if f.alternate() {
- clause.push_str(&format!("{:#} == {:#}", lhs.print(cx), rhs.print(cx),));
- } else {
- clause.push_str(&format!("{} == {}", lhs.print(cx), rhs.print(cx),));
- }
- }
- }
-
- if i < gens.where_predicates.len() - 1 || end_newline {
- clause.push(',');
- }
- }
+ clause.push_str(&comma_sep(where_predicates, false).to_string());
if end_newline {
+ clause.push(',');
// add a space so stripping <br> tags and breaking spaces still renders properly
if f.alternate() {
clause.push(' ');
write!(
f,
"for<{:#}> ",
- comma_sep(self.generic_params.iter().map(|g| g.print(cx)))
+ comma_sep(self.generic_params.iter().map(|g| g.print(cx)), true)
)?;
} else {
write!(
f,
"for<{}> ",
- comma_sep(self.generic_params.iter().map(|g| g.print(cx)))
+ comma_sep(self.generic_params.iter().map(|g| g.print(cx)), true)
)?;
}
}
let modifier_str = match modifier {
hir::TraitBoundModifier::None => "",
hir::TraitBoundModifier::Maybe => "?",
- hir::TraitBoundModifier::MaybeConst => "~const",
+ // ~const is experimental; do not display those bounds in rustdoc
+ hir::TraitBoundModifier::MaybeConst => "",
};
if f.alternate() {
write!(f, "{}{:#}", modifier_str, ty.print(cx))
write!(f, "impl {}", print_generic_bounds(bounds, cx))
}
}
- clean::QPath { ref name, ref self_type, ref trait_, ref self_def_id } => {
+ clean::QPath { ref assoc, ref self_type, ref trait_, ref self_def_id } => {
let should_show_cast = !trait_.segments.is_empty()
&& self_def_id
.zip(Some(trait_.def_id()))
write!(
f,
"<a class=\"associatedtype\" href=\"{url}#{shortty}.{name}\" \
- title=\"type {path}::{name}\">{name}</a>",
+ title=\"type {path}::{name}\">{name}</a>{args}",
url = url,
shortty = ItemType::AssocType,
- name = name,
+ name = assoc.name,
path = join_with_double_colon(path),
+ args = assoc.args.print(cx),
)?;
}
- _ => write!(f, "{}", name)?,
+ _ => write!(f, "{}{:#}", assoc.name, assoc.args.print(cx))?,
}
Ok(())
}
write!(
f,
"for<{}> ",
- comma_sep(self.generic_params.iter().map(|g| g.print(cx)))
+ comma_sep(self.generic_params.iter().map(|g| g.print(cx)), true)
)
} else {
Ok(())
cx: &'a Context<'tcx>,
) -> impl fmt::Display + 'a + Captures<'tcx> {
display_fn(move |f| {
- f.write_str(self.name.as_str())?;
+ f.write_str(self.assoc.name.as_str())?;
+ if f.alternate() {
+ write!(f, "{:#}", self.assoc.args.print(cx))?;
+ } else {
+ write!(f, "{}", self.assoc.args.print(cx))?;
+ }
match self.kind {
clean::TypeBindingKind::Equality { ref term } => {
if f.alternate() {
fn assoc_type(
w: &mut Buffer,
it: &clean::Item,
+ generics: &clean::Generics,
bounds: &[clean::GenericBound],
default: Option<&clean::Type>,
link: AssocItemLink<'_>,
- extra: &str,
+ indent: usize,
cx: &Context<'_>,
) {
write!(
w,
- "{}type <a href=\"{}\" class=\"associatedtype\">{}</a>",
- extra,
- naive_assoc_href(it, link, cx),
- it.name.as_ref().unwrap()
+ "{indent}type <a href=\"{href}\" class=\"associatedtype\">{name}</a>{generics}",
+ indent = " ".repeat(indent),
+ href = naive_assoc_href(it, link, cx),
+ name = it.name.as_ref().unwrap(),
+ generics = generics.print(cx),
);
if !bounds.is_empty() {
write!(w, ": {}", print_generic_bounds(bounds, cx))
}
+ write!(w, "{}", print_where_clause(generics, cx, indent, false));
if let Some(default) = default {
write!(w, " = {}", default.print(cx))
}
}
+fn assoc_method(
+ w: &mut Buffer,
+ meth: &clean::Item,
+ header: hir::FnHeader,
+ g: &clean::Generics,
+ d: &clean::FnDecl,
+ link: AssocItemLink<'_>,
+ parent: ItemType,
+ cx: &Context<'_>,
+ render_mode: RenderMode,
+) {
+ let name = meth.name.as_ref().unwrap();
+ let href = match link {
+ AssocItemLink::Anchor(Some(ref id)) => Some(format!("#{}", id)),
+ AssocItemLink::Anchor(None) => Some(format!("#{}.{}", meth.type_(), name)),
+ AssocItemLink::GotoSource(did, provided_methods) => {
+ // We're creating a link from an impl-item to the corresponding
+ // trait-item and need to map the anchored type accordingly.
+ let ty =
+ if provided_methods.contains(name) { ItemType::Method } else { ItemType::TyMethod };
+
+ match (href(did.expect_def_id(), cx), ty) {
+ (Ok(p), ty) => Some(format!("{}#{}.{}", p.0, ty, name)),
+ (Err(HrefError::DocumentationNotBuilt), ItemType::TyMethod) => None,
+ (Err(_), ty) => Some(format!("#{}.{}", ty, name)),
+ }
+ }
+ };
+ let vis = meth.visibility.print_with_space(meth.def_id, cx).to_string();
+ // FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove
+ // this condition.
+ let constness = match render_mode {
+ RenderMode::Normal => {
+ print_constness_with_space(&header.constness, meth.const_stability(cx.tcx()))
+ }
+ RenderMode::ForDeref { .. } => "",
+ };
+ let asyncness = header.asyncness.print_with_space();
+ let unsafety = header.unsafety.print_with_space();
+ let defaultness = print_default_space(meth.is_default());
+ let abi = print_abi_with_space(header.abi).to_string();
+
+ // NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`.
+ let generics_len = format!("{:#}", g.print(cx)).len();
+ let mut header_len = "fn ".len()
+ + vis.len()
+ + constness.len()
+ + asyncness.len()
+ + unsafety.len()
+ + defaultness.len()
+ + abi.len()
+ + name.as_str().len()
+ + generics_len;
+
+ let (indent, indent_str, end_newline) = if parent == ItemType::Trait {
+ header_len += 4;
+ let indent_str = " ";
+ render_attributes_in_pre(w, meth, indent_str);
+ (4, indent_str, false)
+ } else {
+ render_attributes_in_code(w, meth);
+ (0, "", true)
+ };
+ w.reserve(header_len + "<a href=\"\" class=\"fnname\">{".len() + "</a>".len());
+ write!(
+ w,
+ "{indent}{vis}{constness}{asyncness}{unsafety}{defaultness}{abi}fn <a {href} class=\"fnname\">{name}</a>\
+ {generics}{decl}{notable_traits}{where_clause}",
+ indent = indent_str,
+ vis = vis,
+ constness = constness,
+ asyncness = asyncness,
+ unsafety = unsafety,
+ defaultness = defaultness,
+ abi = abi,
+ // links without a href are valid - https://www.w3schools.com/tags/att_a_href.asp
+ href = href.map(|href| format!("href=\"{}\"", href)).unwrap_or_else(|| "".to_string()),
+ name = name,
+ generics = g.print(cx),
+ decl = d.full_print(header_len, indent, header.asyncness, cx),
+ notable_traits = notable_traits_decl(d, cx),
+ where_clause = print_where_clause(g, cx, indent, end_newline),
+ )
+}
+
/// Writes a span containing the versions at which an item became stable and/or const-stable. For
/// example, if the item became stable at 1.0.0, and const-stable at 1.45.0, this function would
/// write a span containing "1.0.0 (const: 1.45.0)".
cx: &Context<'_>,
render_mode: RenderMode,
) {
- fn method(
- w: &mut Buffer,
- meth: &clean::Item,
- header: hir::FnHeader,
- g: &clean::Generics,
- d: &clean::FnDecl,
- link: AssocItemLink<'_>,
- parent: ItemType,
- cx: &Context<'_>,
- render_mode: RenderMode,
- ) {
- let name = meth.name.as_ref().unwrap();
- let href = match link {
- AssocItemLink::Anchor(Some(ref id)) => Some(format!("#{}", id)),
- AssocItemLink::Anchor(None) => Some(format!("#{}.{}", meth.type_(), name)),
- AssocItemLink::GotoSource(did, provided_methods) => {
- // We're creating a link from an impl-item to the corresponding
- // trait-item and need to map the anchored type accordingly.
- let ty = if provided_methods.contains(name) {
- ItemType::Method
- } else {
- ItemType::TyMethod
- };
-
- match (href(did.expect_def_id(), cx), ty) {
- (Ok(p), ty) => Some(format!("{}#{}.{}", p.0, ty, name)),
- (Err(HrefError::DocumentationNotBuilt), ItemType::TyMethod) => None,
- (Err(_), ty) => Some(format!("#{}.{}", ty, name)),
- }
- }
- };
- let vis = meth.visibility.print_with_space(meth.def_id, cx).to_string();
- // FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove
- // this condition.
- let constness = match render_mode {
- RenderMode::Normal => {
- print_constness_with_space(&header.constness, meth.const_stability(cx.tcx()))
- }
- RenderMode::ForDeref { .. } => "",
- };
- let asyncness = header.asyncness.print_with_space();
- let unsafety = header.unsafety.print_with_space();
- let defaultness = print_default_space(meth.is_default());
- let abi = print_abi_with_space(header.abi).to_string();
-
- // NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`.
- let generics_len = format!("{:#}", g.print(cx)).len();
- let mut header_len = "fn ".len()
- + vis.len()
- + constness.len()
- + asyncness.len()
- + unsafety.len()
- + defaultness.len()
- + abi.len()
- + name.as_str().len()
- + generics_len;
-
- let (indent, indent_str, end_newline) = if parent == ItemType::Trait {
- header_len += 4;
- let indent_str = " ";
- render_attributes_in_pre(w, meth, indent_str);
- (4, indent_str, false)
- } else {
- render_attributes_in_code(w, meth);
- (0, "", true)
- };
- w.reserve(header_len + "<a href=\"\" class=\"fnname\">{".len() + "</a>".len());
- write!(
- w,
- "{indent}{vis}{constness}{asyncness}{unsafety}{defaultness}{abi}fn <a {href} class=\"fnname\">{name}</a>\
- {generics}{decl}{notable_traits}{where_clause}",
- indent = indent_str,
- vis = vis,
- constness = constness,
- asyncness = asyncness,
- unsafety = unsafety,
- defaultness = defaultness,
- abi = abi,
- // links without a href are valid - https://www.w3schools.com/tags/att_a_href.asp
- href = href.map(|href| format!("href=\"{}\"", href)).unwrap_or_else(|| "".to_string()),
- name = name,
- generics = g.print(cx),
- decl = d.full_print(header_len, indent, header.asyncness, cx),
- notable_traits = notable_traits_decl(d, cx),
- where_clause = print_where_clause(g, cx, indent, end_newline),
- )
- }
match *item.kind {
clean::StrippedItem(..) => {}
clean::TyMethodItem(ref m) => {
- method(w, item, m.header, &m.generics, &m.decl, link, parent, cx, render_mode)
+ assoc_method(w, item, m.header, &m.generics, &m.decl, link, parent, cx, render_mode)
}
clean::MethodItem(ref m, _) => {
- method(w, item, m.header, &m.generics, &m.decl, link, parent, cx, render_mode)
+ assoc_method(w, item, m.header, &m.generics, &m.decl, link, parent, cx, render_mode)
}
clean::AssocConstItem(ref ty, _) => {
assoc_const(w, item, ty, link, if parent == ItemType::Trait { " " } else { "" }, cx)
}
- clean::AssocTypeItem(ref bounds, ref default) => assoc_type(
+ clean::AssocTypeItem(ref generics, ref bounds, ref default) => assoc_type(
w,
item,
+ generics,
bounds,
default.as_ref(),
link,
- if parent == ItemType::Trait { " " } else { "" },
+ if parent == ItemType::Trait { 4 } else { 0 },
cx,
),
_ => panic!("render_assoc_item called on non-associated-item"),
let empty_set = FxHashSet::default();
let src_link =
AssocItemLink::GotoSource(trait_did.into(), &empty_set);
- assoc_type(&mut out, it, &[], Some(&tydef.type_), src_link, "", cx);
+ assoc_type(
+ &mut out,
+ it,
+ &tydef.generics,
+ &[],
+ Some(&tydef.type_),
+ src_link,
+ 0,
+ cx,
+ );
out.push_str(";</span>");
}
}
assoc_type(
w,
item,
- &Vec::new(),
+ &tydef.generics,
+ &[],
Some(&tydef.type_),
link.anchor(if trait_.is_some() { &source_id } else { &id }),
- "",
+ 0,
cx,
);
w.write_str("</h4>");
w.write_str("</h4>");
w.write_str("</section>");
}
- clean::AssocTypeItem(ref bounds, ref default) => {
+ clean::AssocTypeItem(ref generics, ref bounds, ref default) => {
let source_id = format!("{}.{}", item_type, name);
let id = cx.derive_id(source_id.clone());
write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class,);
assoc_type(
w,
item,
+ generics,
bounds,
default.as_ref(),
link.anchor(if trait_.is_some() { &source_id } else { &id }),
- "",
+ 0,
cx,
);
w.write_str("</h4>");
for it in &i.inner_impl().items {
if let clean::TypedefItem(ref tydef, _) = *it.kind {
w.write_str("<span class=\"where fmt-newline\"> ");
- assoc_type(w, it, &[], Some(&tydef.type_), AssocItemLink::Anchor(None), "", cx);
+ assoc_type(
+ w,
+ it,
+ &tydef.generics,
+ &[],
+ Some(&tydef.type_),
+ AssocItemLink::Anchor(None),
+ 0,
+ cx,
+ );
w.write_str(";</span>");
}
}
}
fn document_type_layout(w: &mut Buffer, cx: &Context<'_>, ty_def_id: DefId) {
- fn write_size_of_layout(w: &mut Buffer, layout: &Layout, tag_size: u64) {
- if layout.abi.is_unsized() {
+ fn write_size_of_layout(w: &mut Buffer, layout: Layout<'_>, tag_size: u64) {
+ if layout.abi().is_unsized() {
write!(w, "(unsized)");
} else {
- let bytes = layout.size.bytes() - tag_size;
+ let bytes = layout.size().bytes() - tag_size;
write!(w, "{size} byte{pl}", size = bytes, pl = if bytes == 1 { "" } else { "s" },);
}
}
write_size_of_layout(w, ty_layout.layout, 0);
writeln!(w, "</p>");
if let Variants::Multiple { variants, tag, tag_encoding, .. } =
- &ty_layout.layout.variants
+ &ty_layout.layout.variants()
{
if !variants.is_empty() {
w.write_str(
for (index, layout) in variants.iter_enumerated() {
let name = adt.variants[index].name;
write!(w, "<li><code>{name}</code>: ", name = name);
- write_size_of_layout(w, layout, tag_size);
+ write_size_of_layout(w, *layout, tag_size);
writeln!(w, "</li>");
}
w.write_str("</ul>");
) {
let lines = s.lines().count();
let mut line_numbers = Buffer::empty_from(buf);
- let mut cols = 0;
- let mut tmp = lines;
- while tmp > 0 {
- cols += 1;
- tmp /= 10;
- }
line_numbers.write_str("<pre class=\"line-numbers\">");
match source_context {
SourceContext::Standalone => {
for line in 1..=lines {
- writeln!(line_numbers, "<span id=\"{0}\">{0:1$}</span>", line, cols)
+ writeln!(line_numbers, "<span id=\"{0}\">{0}</span>", line)
}
}
SourceContext::Embedded { offset } => {
for line in 1..=lines {
- writeln!(line_numbers, "<span>{0:1$}</span>", line + offset, cols)
+ writeln!(line_numbers, "<span>{0}</span>", line + offset)
}
}
}
text-decoration: underline;
}
+.line-numbers {
+ text-align: right;
+}
.rustdoc:not(.source) .example-wrap > pre:not(.line-number) {
width: 100%;
overflow-x: auto;
var lineNumbersRegex = /^#?(\d+)(?:-(\d+))?$/;
-function highlightSourceLines(scrollTo, match) {
+function highlightSourceLines(match) {
if (typeof match === "undefined") {
match = window.location.hash.match(lineNumbersRegex);
}
if (!elem) {
return;
}
- if (scrollTo) {
- var x = document.getElementById(from);
- if (x) {
- x.scrollIntoView();
- }
+ var x = document.getElementById(from);
+ if (x) {
+ x.scrollIntoView();
}
onEachLazy(document.getElementsByClassName("line-numbers"), function(e) {
onEachLazy(e.getElementsByTagName("span"), function(i_e) {
y = window.scrollY;
if (searchState.browserSupportsHistoryApi()) {
history.replaceState(null, null, "#" + name);
- highlightSourceLines(true);
+ highlightSourceLines();
} else {
location.replace("#" + name);
}
window.addEventListener("hashchange", function() {
var match = window.location.hash.match(lineNumbersRegex);
if (match) {
- return highlightSourceLines(false, match);
+ return highlightSourceLines(match);
}
});
el.addEventListener("click", handleSourceHighlight);
});
-highlightSourceLines(true);
+highlightSourceLines();
window.createSourceSidebar = createSourceSidebar;
})();
href="{{static_root_path|safe}}theme{{page.resource_suffix}}.css"> {#- -#}
{%- endif -%}
{%- if !layout.favicon.is_empty() -%}
- <link rel="shortcut icon" href="{{layout.favicon}}"> {#- -#}
+ <link rel="icon" href="{{layout.favicon}}"> {#- -#}
{%- else -%}
<link rel="alternate icon" type="image/png" {# -#}
href="{{static_root_path|safe}}favicon-16x16{{page.resource_suffix}}.png"> {#- -#}
impl FromWithTcx<clean::TypeBinding> for TypeBinding {
fn from_tcx(binding: clean::TypeBinding, tcx: TyCtxt<'_>) -> Self {
- TypeBinding { name: binding.name.to_string(), binding: binding.kind.into_tcx(tcx) }
+ TypeBinding {
+ name: binding.assoc.name.to_string(),
+ args: binding.assoc.args.into_tcx(tcx),
+ binding: binding.kind.into_tcx(tcx),
+ }
}
}
AssocConstItem(ty, default) => {
ItemEnum::AssocConst { type_: ty.into_tcx(tcx), default: default.map(|c| c.expr(tcx)) }
}
- AssocTypeItem(g, t) => ItemEnum::AssocType {
- bounds: g.into_iter().map(|x| x.into_tcx(tcx)).collect(),
+ AssocTypeItem(g, b, t) => ItemEnum::AssocType {
+ generics: (*g).into_tcx(tcx),
+ bounds: b.into_iter().map(|x| x.into_tcx(tcx)).collect(),
default: t.map(|x| x.into_tcx(tcx)),
},
// `convert_item` early returns `None` for striped items
mutable: mutability == ast::Mutability::Mut,
type_: Box::new((*type_).into_tcx(tcx)),
},
- QPath { name, self_type, trait_, .. } => {
+ QPath { assoc, self_type, trait_, .. } => {
// FIXME: should `trait_` be a clean::Path equivalent in JSON?
let trait_ = clean::Type::Path { path: trait_ }.into_tcx(tcx);
Type::QualifiedPath {
- name: name.to_string(),
+ name: assoc.name.to_string(),
+ args: Box::new(assoc.args.clone().into_tcx(tcx)),
self_type: Box::new((*self_type).into_tcx(tcx)),
trait_: Box::new(trait_),
}
#![feature(box_patterns)]
#![feature(control_flow_enum)]
#![feature(box_syntax)]
+#![feature(drain_filter)]
#![feature(let_else)]
#![feature(nll)]
#![feature(test)]
clean::StructFieldItem(_)
| clean::VariantItem(_)
| clean::AssocConstItem(_, _)
- | clean::AssocTypeItem(_, _)
+ | clean::AssocTypeItem(..)
| clean::TypedefItem(_, _)
| clean::StaticItem(_)
| clean::ConstantItem(_)
use std::mem;
use std::ops::Range;
-use crate::clean::{self, utils::find_nearest_parent_module, Crate, Item, ItemLink, PrimitiveType};
+use crate::clean::{self, utils::find_nearest_parent_module};
+use crate::clean::{Crate, Item, ItemId, ItemLink, PrimitiveType};
use crate::core::DocContext;
use crate::html::markdown::{markdown_links, MarkdownLink};
use crate::lint::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS};
/// The link failed to resolve. [`resolution_failure`] should look to see if there's
/// a more helpful error that can be given.
NotResolved {
+ /// Item on which the link is resolved, used for resolving `Self`.
+ item_id: ItemId,
/// The scope the link was resolved in.
module_id: DefId,
/// If part of the link resolved, this has the `Res`.
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
struct ResolutionInfo {
+ item_id: ItemId,
module_id: DefId,
dis: Option<Disambiguator>,
path_str: String,
fn variant_field<'path>(
&self,
path_str: &'path str,
+ item_id: ItemId,
module_id: DefId,
) -> Result<(Res, Option<ItemFragment>), ErrorKind<'path>> {
let tcx = self.cx.tcx;
let no_res = || ResolutionFailure::NotResolved {
+ item_id,
module_id,
partial_res: None,
unresolved: path_str.into(),
// If there's no third component, we saw `[a::b]` before and it failed to resolve.
// So there's no partial res.
.ok_or_else(no_res)?;
- let ty_res = self
- .cx
- .enter_resolver(|resolver| {
- resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id)
- })
- .and_then(|(_, res)| res.try_into())
- .map_err(|()| no_res())?;
+ let ty_res = self.resolve_path(&path, TypeNS, item_id, module_id).ok_or_else(no_res)?;
match ty_res {
Res::Def(DefKind::Enum, did) => {
Ok((ty_res, Some(ItemFragment(FragmentKind::VariantField, field.did))))
} else {
Err(ResolutionFailure::NotResolved {
+ item_id,
module_id,
partial_res: Some(Res::Def(DefKind::Enum, def.did)),
unresolved: variant_field_name.to_string().into(),
}
}
_ => Err(ResolutionFailure::NotResolved {
+ item_id,
module_id,
partial_res: Some(ty_res),
unresolved: variant_name.to_string().into(),
fn resolve_macro(
&self,
path_str: &'a str,
+ item_id: ItemId,
module_id: DefId,
) -> Result<Res, ResolutionFailure<'a>> {
self.cx.enter_resolver(|resolver| {
return Ok(res.try_into().unwrap());
}
Err(ResolutionFailure::NotResolved {
+ item_id,
module_id,
partial_res: None,
unresolved: path_str.into(),
})
}
+ fn resolve_self_ty(&self, path_str: &str, ns: Namespace, item_id: ItemId) -> Option<Res> {
+ if ns != TypeNS || path_str != "Self" {
+ return None;
+ }
+
+ let tcx = self.cx.tcx;
+ item_id
+ .as_def_id()
+ .map(|def_id| match tcx.def_kind(def_id) {
+ def_kind @ (DefKind::AssocFn
+ | DefKind::AssocConst
+ | DefKind::AssocTy
+ | DefKind::Variant
+ | DefKind::Field) => {
+ let parent_def_id = tcx.parent(def_id).expect("nested item has no parent");
+ if def_kind == DefKind::Field && tcx.def_kind(parent_def_id) == DefKind::Variant
+ {
+ tcx.parent(parent_def_id).expect("variant has no parent")
+ } else {
+ parent_def_id
+ }
+ }
+ _ => def_id,
+ })
+ .and_then(|self_id| match tcx.def_kind(self_id) {
+ DefKind::Impl => self.def_id_to_res(self_id),
+ def_kind => Some(Res::Def(def_kind, self_id)),
+ })
+ }
+
/// Convenience wrapper around `resolve_str_path_error`.
///
/// This also handles resolving `true` and `false` as booleans.
/// NOTE: `resolve_str_path_error` knows only about paths, not about types.
/// Associated items will never be resolved by this function.
- fn resolve_path(&self, path_str: &str, ns: Namespace, module_id: DefId) -> Option<Res> {
+ fn resolve_path(
+ &self,
+ path_str: &str,
+ ns: Namespace,
+ item_id: ItemId,
+ module_id: DefId,
+ ) -> Option<Res> {
+ if let res @ Some(..) = self.resolve_self_ty(path_str, ns, item_id) {
+ return res;
+ }
+
let result = self.cx.enter_resolver(|resolver| {
resolver
.resolve_str_path_error(DUMMY_SP, path_str, ns, module_id)
&mut self,
path_str: &'path str,
ns: Namespace,
+ item_id: ItemId,
module_id: DefId,
user_fragment: &Option<String>,
) -> Result<(Res, Option<UrlFragment>), ErrorKind<'path>> {
- let (res, rustdoc_fragment) = self.resolve_inner(path_str, ns, module_id)?;
+ let (res, rustdoc_fragment) = self.resolve_inner(path_str, ns, item_id, module_id)?;
let chosen_fragment = match (user_fragment, rustdoc_fragment) {
(Some(_), Some(r_frag)) => {
let diag_res = match r_frag {
&mut self,
path_str: &'path str,
ns: Namespace,
+ item_id: ItemId,
module_id: DefId,
) -> Result<(Res, Option<ItemFragment>), ErrorKind<'path>> {
- if let Some(res) = self.resolve_path(path_str, ns, module_id) {
+ if let Some(res) = self.resolve_path(path_str, ns, item_id, module_id) {
match res {
// FIXME(#76467): make this fallthrough to lookup the associated
// item a separate function.
.ok_or_else(|| {
debug!("found no `::`, assumming {} was correctly not in scope", item_name);
ResolutionFailure::NotResolved {
+ item_id,
module_id,
partial_res: None,
unresolved: item_str.into(),
// error instead and special case *only* modules with `#[doc(primitive)]`, not all
// primitives.
resolve_primitive(&path_root, TypeNS)
- .or_else(|| self.resolve_path(&path_root, TypeNS, module_id))
+ .or_else(|| self.resolve_path(&path_root, TypeNS, item_id, module_id))
.and_then(|ty_res| {
let (res, fragment) =
self.resolve_associated_item(ty_res, item_name, ns, module_id)?;
})
.unwrap_or_else(|| {
if ns == Namespace::ValueNS {
- self.variant_field(path_str, module_id)
+ self.variant_field(path_str, item_id, module_id)
} else {
Err(ResolutionFailure::NotResolved {
+ item_id,
module_id,
partial_res: None,
unresolved: path_root.into(),
self.resolve_associated_item(res, item_name, ns, module_id)
}
Res::Def(
- DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::ForeignTy,
+ def_kind @ (DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::ForeignTy),
did,
) => {
debug!("looking for associated item named {} for item {:?}", item_name, did);
+ // Checks if item_name is a variant of the `SomeItem` enum
+ if ns == TypeNS && def_kind == DefKind::Enum {
+ match tcx.type_of(did).kind() {
+ ty::Adt(adt_def, _) => {
+ for variant in &adt_def.variants {
+ if variant.name == item_name {
+ return Some((
+ root_res,
+ ItemFragment(FragmentKind::Variant, variant.def_id),
+ ));
+ }
+ }
+ }
+ _ => unreachable!(),
+ }
+ }
+
// Checks if item_name belongs to `impl SomeItem`
let assoc_item = tcx
.inherent_impls(did)
&mut self,
ns: Namespace,
path_str: &str,
+ item_id: ItemId,
module_id: DefId,
extra_fragment: &Option<String>,
) -> Option<Res> {
// resolve() can't be used for macro namespace
let result = match ns {
Namespace::MacroNS => self
- .resolve_macro(path_str, module_id)
+ .resolve_macro(path_str, item_id, module_id)
.map(|res| (res, None))
.map_err(ErrorKind::from),
Namespace::TypeNS | Namespace::ValueNS => {
- self.resolve(path_str, ns, module_id, extra_fragment)
+ self.resolve(path_str, ns, item_id, module_id, extra_fragment)
}
};
trace!("got parent node for {:?} {:?}, id {:?}", item.type_(), item.name, item.def_id);
}
- // find item's parent to resolve `Self` in item's docs below
- debug!("looking for the `Self` type");
- let self_id = match item.def_id.as_def_id() {
- None => None,
- Some(did)
- if (matches!(self.cx.tcx.def_kind(did), DefKind::Field)
- && matches!(
- self.cx.tcx.def_kind(self.cx.tcx.parent(did).unwrap()),
- DefKind::Variant
- )) =>
- {
- self.cx.tcx.parent(did).and_then(|item_id| self.cx.tcx.parent(item_id))
- }
- Some(did)
- if matches!(
- self.cx.tcx.def_kind(did),
- DefKind::AssocConst
- | DefKind::AssocFn
- | DefKind::AssocTy
- | DefKind::Variant
- | DefKind::Field
- ) =>
- {
- self.cx.tcx.parent(did)
- }
- Some(did) => Some(did),
- };
-
- // FIXME(jynelson): this shouldn't go through stringification, rustdoc should just use the DefId directly
- let self_name = self_id.and_then(|self_id| {
- if matches!(self.cx.tcx.def_kind(self_id), DefKind::Impl) {
- // using `ty.to_string()` (or any variant) has issues with raw idents
- let ty = self.cx.tcx.type_of(self_id);
- let name = match ty.kind() {
- ty::Adt(def, _) => Some(self.cx.tcx.item_name(def.did).to_string()),
- other if other.is_primitive() => Some(ty.to_string()),
- _ => None,
- };
- debug!("using type_of(): {:?}", name);
- name
- } else {
- let name = self.cx.tcx.opt_item_name(self_id).map(|sym| sym.to_string());
- debug!("using item_name(): {:?}", name);
- name
- }
- });
-
let inner_docs = item.inner_docs(self.cx.tcx);
if item.is_mod() && inner_docs {
// NOTE: if there are links that start in one crate and end in another, this will not resolve them.
// This is a degenerate case and it's not supported by rustdoc.
for md_link in markdown_links(&doc) {
- let link = self.resolve_link(&item, &doc, &self_name, parent_node, krate, md_link);
+ let link = self.resolve_link(&item, &doc, parent_node, krate, md_link);
if let Some(link) = link {
self.cx.cache.intra_doc_links.entry(item.def_id).or_default().push(link);
}
&mut self,
item: &Item,
dox: &str,
- self_name: &Option<String>,
parent_node: Option<DefId>,
krate: CrateNum,
ori_link: MarkdownLink,
};
let resolved_self;
- // replace `Self` with suitable item's parent name
- let is_lone_self = path_str == "Self";
let is_lone_crate = path_str == "crate";
- if path_str.starts_with("Self::") || is_lone_self {
- if let Some(ref name) = self_name {
- if is_lone_self {
- path_str = name;
- } else {
- resolved_self = format!("{}::{}", name, &path_str[6..]);
- path_str = &resolved_self;
- }
- }
- } else if path_str.starts_with("crate::") || is_lone_crate {
+ if path_str.starts_with("crate::") || is_lone_crate {
use rustc_span::def_id::CRATE_DEF_INDEX;
// HACK(jynelson): rustc_resolve thinks that `crate` is the crate currently being documented.
let (mut res, fragment) = self.resolve_with_disambiguator_cached(
ResolutionInfo {
+ item_id: item.def_id,
module_id,
dis: disambiguator,
path_str: path_str.to_owned(),
) -> Option<(Res, Option<UrlFragment>)> {
let disambiguator = key.dis;
let path_str = &key.path_str;
+ let item_id = key.item_id;
let base_node = key.module_id;
let extra_fragment = &key.extra_fragment;
match disambiguator.map(Disambiguator::ns) {
Some(expected_ns @ (ValueNS | TypeNS)) => {
- match self.resolve(path_str, expected_ns, base_node, extra_fragment) {
+ match self.resolve(path_str, expected_ns, item_id, base_node, extra_fragment) {
Ok(res) => Some(res),
Err(ErrorKind::Resolve(box mut kind)) => {
// We only looked in one namespace. Try to give a better error if possible.
// FIXME: really it should be `resolution_failure` that does this, not `resolve_with_disambiguator`
// See https://github.com/rust-lang/rust/pull/76955#discussion_r493953382 for a good approach
for new_ns in [other_ns, MacroNS] {
- if let Some(res) =
- self.check_full_res(new_ns, path_str, base_node, extra_fragment)
- {
+ if let Some(res) = self.check_full_res(
+ new_ns,
+ path_str,
+ item_id,
+ base_node,
+ extra_fragment,
+ ) {
kind = ResolutionFailure::WrongNamespace { res, expected_ns };
break;
}
// Try everything!
let mut candidates = PerNS {
macro_ns: self
- .resolve_macro(path_str, base_node)
+ .resolve_macro(path_str, item_id, base_node)
.map(|res| (res, extra_fragment.clone().map(UrlFragment::UserWritten))),
- type_ns: match self.resolve(path_str, TypeNS, base_node, extra_fragment) {
+ type_ns: match self.resolve(
+ path_str,
+ TypeNS,
+ item_id,
+ base_node,
+ extra_fragment,
+ ) {
Ok(res) => {
debug!("got res in TypeNS: {:?}", res);
Ok(res)
}
Err(ErrorKind::Resolve(box kind)) => Err(kind),
},
- value_ns: match self.resolve(path_str, ValueNS, base_node, extra_fragment) {
+ value_ns: match self.resolve(
+ path_str,
+ ValueNS,
+ item_id,
+ base_node,
+ extra_fragment,
+ ) {
Ok(res) => Ok(res),
Err(ErrorKind::AnchorFailure(msg)) => {
anchor_failure(self.cx, diag, msg);
}
}
Some(MacroNS) => {
- match self.resolve_macro(path_str, base_node) {
+ match self.resolve_macro(path_str, item_id, base_node) {
Ok(res) => Some((res, extra_fragment.clone().map(UrlFragment::UserWritten))),
Err(mut kind) => {
// `resolve_macro` only looks in the macro namespace. Try to give a better error if possible.
for ns in [TypeNS, ValueNS] {
- if let Some(res) =
- self.check_full_res(ns, path_str, base_node, extra_fragment)
- {
+ if let Some(res) = self.check_full_res(
+ ns,
+ path_str,
+ item_id,
+ base_node,
+ extra_fragment,
+ ) {
kind =
ResolutionFailure::WrongNamespace { res, expected_ns: MacroNS };
break;
}
variants_seen.push(variant);
- if let ResolutionFailure::NotResolved { module_id, partial_res, unresolved } =
- &mut failure
+ if let ResolutionFailure::NotResolved {
+ item_id,
+ module_id,
+ partial_res,
+ unresolved,
+ } = &mut failure
{
use DefKind::*;
+ let item_id = *item_id;
let module_id = *module_id;
// FIXME(jynelson): this might conflict with my `Self` fix in #76467
// FIXME: maybe use itertools `collect_tuple` instead?
};
name = start;
for ns in [TypeNS, ValueNS, MacroNS] {
- if let Some(res) = collector.check_full_res(ns, start, module_id, &None)
+ if let Some(res) =
+ collector.check_full_res(ns, start, item_id, module_id, &None)
{
debug!("found partial_res={:?}", res);
*partial_res = Some(res);
| ProcMacroItem(_)
| PrimitiveItem(_)
| AssocConstItem(_, _)
- | AssocTypeItem(_, _)
+ | AssocTypeItem(..)
| KeywordItem(_) => {}
}
}
use serde::{Deserialize, Serialize};
/// rustdoc format-version.
-pub const FORMAT_VERSION: u32 = 11;
+pub const FORMAT_VERSION: u32 = 12;
/// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
/// about the language items in the local crate, as well as info about external items to allow
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct TypeBinding {
pub name: String,
+ pub args: GenericArgs,
pub binding: TypeBindingKind,
}
default: Option<String>,
},
AssocType {
+ generics: Generics,
bounds: Vec<GenericBound>,
/// e.g. `type X = usize;`
default: Option<Type>,
/// `<Type as Trait>::Name` or associated types like `T::Item` where `T: Iterator`
QualifiedPath {
name: String,
+ args: Box<GenericArgs>,
self_type: Box<Type>,
#[serde(rename = "trait")]
trait_: Box<Type>,
+++ /dev/null
-//! Check that types of up to 128 bits are passed and returned by-value instead of via pointer.
-
-// compile-flags: -C no-prepopulate-passes -O
-// only-x86_64
-
-#![crate_type = "lib"]
-
-pub struct S {
- a: u64,
- b: u32,
- c: u32,
-}
-
-// CHECK: define i128 @modify(i128{{( %0)?}})
-#[no_mangle]
-pub fn modify(s: S) -> S {
- S { a: s.a + s.a, b: s.b + s.b, c: s.c + s.c }
-}
-
-#[repr(packed)]
-pub struct TooBig {
- a: u64,
- b: u32,
- c: u32,
- d: u8,
-}
-
-// CHECK: define void @m_big(%TooBig* [[ATTRS:.*sret.*]], %TooBig* [[ATTRS2:.*]] %s)
-#[no_mangle]
-pub fn m_big(s: TooBig) -> TooBig {
- TooBig { a: s.a + s.a, b: s.b + s.b, c: s.c + s.c, d: s.d + s.d }
-}
// CHECK-LABEL: @array_eq_value
#[no_mangle]
-pub fn array_eq_value(a: [u16; 6], b: [u16; 6]) -> bool {
+pub fn array_eq_value(a: [u16; 3], b: [u16; 3]) -> bool {
// CHECK-NEXT: start:
- // CHECK-NEXT: %2 = icmp eq i96 %0, %1
+ // CHECK-NEXT: %2 = icmp eq i48 %0, %1
// CHECK-NEXT: ret i1 %2
a == b
}
// CHECK-LABEL: @array_eq_ref
#[no_mangle]
-pub fn array_eq_ref(a: &[u16; 6], b: &[u16; 6]) -> bool {
+pub fn array_eq_ref(a: &[u16; 3], b: &[u16; 3]) -> bool {
// CHECK: start:
- // CHECK: load i96, i96* %{{.+}}, align 2
- // CHECK: load i96, i96* %{{.+}}, align 2
- // CHECK: icmp eq i96
+ // CHECK: load i48, i48* %{{.+}}, align 2
+ // CHECK: load i48, i48* %{{.+}}, align 2
+ // CHECK: icmp eq i48
// CHECK-NEXT: ret
a == b
}
a == b
}
-// CHECK-LABEL: @array_eq_zero(i128 %0)
+// CHECK-LABEL: @array_eq_zero_short(i48
#[no_mangle]
-pub fn array_eq_zero(x: [u16; 8]) -> bool {
+pub fn array_eq_zero_short(x: [u16; 3]) -> bool {
// CHECK-NEXT: start:
- // CHECK-NEXT: %[[EQ:.+]] = icmp eq i128 %0, 0
+ // CHECK-NEXT: %[[EQ:.+]] = icmp eq i48 %0, 0
+ // CHECK-NEXT: ret i1 %[[EQ]]
+ x == [0; 3]
+}
+
+// CHECK-LABEL: @array_eq_zero_mid([8 x i16]*
+#[no_mangle]
+pub fn array_eq_zero_mid(x: [u16; 8]) -> bool {
+ // CHECK-NEXT: start:
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: %[[LOAD:.+]] = load i128,
+ // CHECK-NEXT: %[[EQ:.+]] = icmp eq i128 %[[LOAD]], 0
// CHECK-NEXT: ret i1 %[[EQ]]
x == [0; 8]
}
+
+// CHECK-LABEL: @array_eq_zero_long([1234 x i16]*
+#[no_mangle]
+pub fn array_eq_zero_long(x: [u16; 1234]) -> bool {
+ // CHECK-NEXT: start:
+ // CHECK-NOT: alloca
+ // CHECK: %[[CMP:.+]] = tail call i32 @{{bcmp|memcmp}}(
+ // CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[CMP]], 0
+ // CHECK-NEXT: ret i1 %[[EQ]]
+ x == [0; 1234]
+}
--- /dev/null
+// compile-flags: -C opt-level=3
+// only-x86_64
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @auto_vectorize_direct
+#[no_mangle]
+pub fn auto_vectorize_direct(a: [f32; 4], b: [f32; 4]) -> [f32; 4] {
+// CHECK: load <4 x float>
+// CHECK: load <4 x float>
+// CHECK: fadd <4 x float>
+// CHECK: store <4 x float>
+ [
+ a[0] + b[0],
+ a[1] + b[1],
+ a[2] + b[2],
+ a[3] + b[3],
+ ]
+}
+
+// CHECK-LABEL: @auto_vectorize_loop
+#[no_mangle]
+pub fn auto_vectorize_loop(a: [f32; 4], b: [f32; 4]) -> [f32; 4] {
+// CHECK: load <4 x float>
+// CHECK: load <4 x float>
+// CHECK: fadd <4 x float>
+// CHECK: store <4 x float>
+ let mut c = [0.0; 4];
+ for i in 0..4 {
+ c[i] = a[i] + b[i];
+ }
+ c
+}
False,
}
+#[repr(align(16))]
+pub struct Align16(u128);
+
+// CHECK: @ptr_alignment_helper({}** {{.*}}align [[PTR_ALIGNMENT:[0-9]+]]
+#[no_mangle]
+pub fn ptr_alignment_helper(x: &&()) {}
+
// CHECK-LABEL: @load_ref
#[no_mangle]
pub fn load_ref<'a>(x: &&'a i32) -> &'a i32 {
-// Alignment of a reference itself is target dependent, so just match any alignment:
-// the main thing we care about here is !nonnull and !noundef.
-// CHECK: load i32*, i32** %x, align {{[0-9]+}}, !nonnull !{{[0-9]+}}, !noundef !{{[0-9]+}}
+// CHECK: load i32*, i32** %x, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !align ![[ALIGN_4_META:[0-9]+]], !noundef !{{[0-9]+}}
+ *x
+}
+
+// CHECK-LABEL: @load_ref_higher_alignment
+#[no_mangle]
+pub fn load_ref_higher_alignment<'a>(x: &&'a Align16) -> &'a Align16 {
+// CHECK: load {{%Align16|i128}}*, {{%Align16|i128}}** %x, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !align ![[ALIGN_16_META:[0-9]+]], !noundef !{{[0-9]+}}
+ *x
+}
+
+// CHECK-LABEL: @load_scalar_pair
+#[no_mangle]
+pub fn load_scalar_pair<'a>(x: &(&'a i32, &'a Align16)) -> (&'a i32, &'a Align16) {
+// CHECK: load i32*, i32** %{{.+}}, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !align ![[ALIGN_4_META]], !noundef !{{[0-9]+}}
+// CHECK: load i64*, i64** %{{.+}}, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !align ![[ALIGN_16_META]], !noundef !{{[0-9]+}}
+ *x
+}
+
+// CHECK-LABEL: @load_raw_pointer
+#[no_mangle]
+pub fn load_raw_pointer<'a>(x: &*const i32) -> *const i32 {
+// loaded raw pointer should not have !nonnull, !align, or !noundef metadata
+// CHECK: load i32*, i32** %x, align [[PTR_ALIGNMENT]]{{$}}
*x
}
// CHECK-LABEL: @load_box
#[no_mangle]
pub fn load_box<'a>(x: Box<Box<i32>>) -> Box<i32> {
-// Alignment of a box itself is target dependent, so just match any alignment:
-// the main thing we care about here is !nonnull and !noundef.
-// CHECK: load i32*, i32** %x, align {{[0-9]+}}, !nonnull !{{[0-9]+}}, !noundef !{{[0-9]+}}
+// CHECK: load i32*, i32** %x, align [[PTR_ALIGNMENT]], !nonnull !{{[0-9]+}}, !align ![[ALIGN_4_META]], !noundef !{{[0-9]+}}
*x
}
x
}
-// CHECK: ![[BOOL_RANGE]] = !{i8 0, i8 2}
-// CHECK: ![[NONZEROU16_RANGE]] = !{i16 1, i16 0}
+// CHECK-DAG: ![[BOOL_RANGE]] = !{i8 0, i8 2}
+// CHECK-DAG: ![[NONZEROU16_RANGE]] = !{i16 1, i16 0}
+// CHECK-DAG: ![[ALIGN_4_META]] = !{i64 4}
+// CHECK-DAG: ![[ALIGN_16_META]] = !{i64 16}
peach()
}
-// target features same as global (not reflected or overriden in IR)
+// target features same as global
#[no_mangle]
pub unsafe fn banana() -> u32 {
// CHECK-LABEL: @banana()
// COMPAT-SAME: "target-features"="+avx2,+avx,+avx"
// INCOMPAT-SAME: "target-features"="-avx2,-avx,+avx"
// CHECK: attributes [[BANANAATTRS]]
-// CHECK-NOT: target-features
-// CHECK-SAME: }
+// COMPAT-SAME: "target-features"="+avx2,+avx"
+// INCOMPAT-SAME: "target-features"="-avx2,-avx"
#[no_mangle]
pub fn test_UnionU128(_: UnionU128) -> UnionU128 { loop {} }
-pub union UnionU128x2{a:(u128, u128)}
-// CHECK: define void @test_UnionU128x2(i128 %_1.0, i128 %_1.1)
-#[no_mangle]
-pub fn test_UnionU128x2(_: UnionU128x2) { loop {} }
-
#[repr(C)]
-pub union CUnionU128x2{a:(u128, u128)}
-// CHECK: define void @test_CUnionU128x2(%CUnionU128x2* {{.*}} %_1)
+pub union CUnionU128{a:u128}
+// CHECK: define void @test_CUnionU128(%CUnionU128* {{.*}} %_1)
#[no_mangle]
-pub fn test_CUnionU128x2(_: CUnionU128x2) { loop {} }
+pub fn test_CUnionU128(_: CUnionU128) { loop {} }
pub union UnionBool { b:bool }
// CHECK: define noundef zeroext i1 @test_UnionBool(i8 %b)
--- /dev/null
+// We check that when the anchor changes and is output of the displayed content,
+// the page is scrolled to it.
+goto: file://|DOC_PATH|/src/link_to_definition/lib.rs.html
+
+// We reduce the window size to make it easier to make an element "out of the page".
+size: (600, 800)
+// We check that the scroll is at the top first.
+assert-property: ("html", {"scrollTop": "0"})
+
+click: '//a[text() = "barbar"]'
+assert-property: ("html", {"scrollTop": "125"})
+click: '//a[text() = "bar"]'
+assert-property: ("html", {"scrollTop": "166"})
+click: '//a[text() = "sub_fn"]'
+assert-property: ("html", {"scrollTop": "53"})
+
+// We now check that clicking on lines doesn't change the scroll
+// Extra information: the "sub_fn" function header is on line 1.
+click: '//*[@id="6"]'
+assert-property: ("html", {"scrollTop": "53"})
assert-attribute-false: (".line-numbers > span:nth-child(7)", {"class": "line-highlighted"})
// This is to ensure that the content is correctly align with the line numbers.
compare-elements-position: ("//*[@id='1']", ".rust > code > span", ("y"))
+
+// Assert that the line numbers text is aligned to the right.
+assert-css: (".line-numbers", {"text-align": "right"})
+pub fn sub_fn() {
+ barbar();
+}
+fn barbar() {
+ bar(vec![], vec![], vec![], vec![], Bar { a: "a".into(), b: 0 });
+}
+
pub struct Bar {
pub a: String,
pub b: u32,
}
pub fn foo(_b: &Bar) {}
+
+// The goal now is to add
+// a lot of lines so
+// that the next content
+// will be out of the screen
+// to allow us to test that
+// if the anchor changes to
+// something outside of the
+// current view, it'll
+// scroll to it as expected.
+
+// More filling content.
+
+pub fn bar(
+ _a: Vec<String>,
+ _b: Vec<String>,
+ _c: Vec<String>,
+ _d: Vec<String>,
+ _e: Bar,
+) {
+ sub_fn();
+}
--- /dev/null
+// ignore-tidy-linelength
+
+#![no_core]
+#![feature(generic_associated_types, lang_items, no_core)]
+
+#[lang = "sized"]
+pub trait Sized {}
+
+pub trait Display {}
+
+// @has gats.json
+pub trait LendingIterator {
+ // @count - "$.index[*][?(@.name=='LendingItem')].inner.generics.params[*]" 1
+ // @is - "$.index[*][?(@.name=='LendingItem')].inner.generics.params[*].name" \"\'a\"
+ // @count - "$.index[*][?(@.name=='LendingItem')].inner.generics.where_predicates[*]" 1
+ // @is - "$.index[*][?(@.name=='LendingItem')].inner.generics.where_predicates[*].bound_predicate.ty.inner" \"Self\"
+ // @is - "$.index[*][?(@.name=='LendingItem')].inner.generics.where_predicates[*].bound_predicate.bounds[*].outlives" \"\'a\"
+ // @count - "$.index[*][?(@.name=='LendingItem')].inner.bounds[*]" 1
+ type LendingItem<'a>: Display where Self: 'a;
+
+ // @is - "$.index[*][?(@.name=='lending_next')].inner.decl.output.kind" \"qualified_path\"
+ // @count - "$.index[*][?(@.name=='lending_next')].inner.decl.output.inner.args.angle_bracketed.args[*]" 1
+ // @count - "$.index[*][?(@.name=='lending_next')].inner.decl.output.inner.args.angle_bracketed.bindings[*]" 0
+ // @is - "$.index[*][?(@.name=='lending_next')].inner.decl.output.inner.self_type.inner" \"Self\"
+ // @is - "$.index[*][?(@.name=='lending_next')].inner.decl.output.inner.name" \"LendingItem\"
+ fn lending_next<'a>(&'a self) -> Self::LendingItem<'a>;
+}
+
+// @has gats.json
+pub trait Iterator {
+ // @count - "$.index[*][?(@.name=='Item')].inner.generics.params[*]" 0
+ // @count - "$.index[*][?(@.name=='Item')].inner.generics.where_predicates[*]" 0
+ // @count - "$.index[*][?(@.name=='Item')].inner.bounds[*]" 1
+ type Item: Display;
+
+ // @is - "$.index[*][?(@.name=='next')].inner.decl.output.kind" \"qualified_path\"
+ // @count - "$.index[*][?(@.name=='next')].inner.decl.output.inner.args.angle_bracketed.args[*]" 0
+ // @count - "$.index[*][?(@.name=='next')].inner.decl.output.inner.args.angle_bracketed.bindings[*]" 0
+ // @is - "$.index[*][?(@.name=='next')].inner.decl.output.inner.self_type.inner" \"Self\"
+ // @is - "$.index[*][?(@.name=='next')].inner.decl.output.inner.name" \"Item\"
+ fn next<'a>(&'a self) -> Self::Item;
+}
#![allow(incomplete_features)]
// make sure that `ConstEvaluatable` predicates dont cause rustdoc to ICE #77647
// @has foo/struct.Ice.html '//pre[@class="rust struct"]' \
-// 'pub struct Ice<const N: usize> where [(); N + 1]: ;'
+// 'pub struct Ice<const N: usize>;'
pub struct Ice<const N: usize> where [(); N + 1]:;
--- /dev/null
+#![crate_name = "foo"]
+#![feature(generic_associated_types)]
+
+// @has foo/trait.LendingIterator.html
+pub trait LendingIterator {
+ // @has - '//*[@id="associatedtype.Item"]//h4[@class="code-header"]' "type Item<'a> where Self: 'a"
+ type Item<'a> where Self: 'a;
+
+ // @has - '//*[@id="tymethod.next"]//h4[@class="code-header"]' \
+ // "fn next<'a>(&'a self) -> Self::Item<'a>"
+ // @has - '//*[@id="tymethod.next"]//h4[@class="code-header"]//a[@href="trait.LendingIterator.html#associatedtype.Item"]' \
+ // "Item"
+ fn next<'a>(&'a self) -> Self::Item<'a>;
+}
+
+// @has foo/trait.LendingIterator.html
+// @has - '//*[@id="associatedtype.Item-1"]//h4[@class="code-header"]' "type Item<'a> = ()"
+impl LendingIterator for () {
+ type Item<'a> = ();
+
+ fn next<'a>(&self) -> () {}
+}
+
+pub struct Infinite<T>(T);
+
+// @has foo/trait.LendingIterator.html
+// @has - '//*[@id="associatedtype.Item-2"]//h4[@class="code-header"]' "type Item<'a> where Self: 'a = &'a T"
+impl<T> LendingIterator for Infinite<T> {
+ type Item<'a> where Self: 'a = &'a T;
+
+ fn next<'a>(&'a self) -> Self::Item<'a> {
+ &self.0
+ }
+}
--- /dev/null
+#![crate_name = "foo"]
+#![feature(generic_associated_types)]
+
+pub trait Trait {
+ type Gat<'a>;
+}
+
+// Make sure that the elided lifetime shows up
+
+// @has foo/type.T.html
+// @has - "pub type T = "
+// @has - "<'_>"
+pub type T = fn(&<() as Trait>::Gat<'_>);
fn ambiguous_method() {}
}
+// @has associated_items/enum.MyEnum.html '//a/@href' 'enum.MyEnum.html#variant.MyVariant'
+/// Link to [MyEnumAlias::MyVariant]
+pub enum MyEnum {
+ MyVariant,
+}
+
+pub type MyEnumAlias = MyEnum;
+
fn main() {}
--- /dev/null
+#![crate_name = "foo"]
+
+pub struct TyCtxt<'tcx>(&'tcx u8);
+
+macro_rules! gen {
+ ($(($name:ident, $tcx:lifetime, [$k:ty], [$r:ty]))*) => {
+ pub struct Providers {
+ $(pub $name: for<$tcx> fn(TyCtxt<$tcx>, $k) -> $r,)*
+ }
+ }
+}
+
+// @has 'foo/struct.Providers.html'
+// @has - '//*[@class="docblock item-decl"]//code' "pub a: for<'tcx> fn(_: TyCtxt<'tcx>, _: u8) -> i8,"
+// @has - '//*[@class="docblock item-decl"]//code' "pub b: for<'tcx> fn(_: TyCtxt<'tcx>, _: u16) -> i16,"
+// @has - '//*[@id="structfield.a"]/code' "a: for<'tcx> fn(_: TyCtxt<'tcx>, _: u8) -> i8"
+// @has - '//*[@id="structfield.b"]/code' "b: for<'tcx> fn(_: TyCtxt<'tcx>, _: u16) -> i16"
+gen! {
+ (a, 'tcx, [u8], [i8])
+ (b, 'tcx, [u16], [i16])
+}
--- /dev/null
+// Test that we do not currently display `~const` in rustdoc
+// as that syntax is currently provisional; `~const Drop` has
+// no effect on stable code so it should be hidden as well.
+//
+// To future blessers: make sure that `const_trait_impl` is
+// stabilized when changing `@!has` to `@has`, and please do
+// not remove this test.
+#![feature(const_trait_impl)]
+#![crate_name = "foo"]
+
+pub struct S<T>(T);
+
+// @!has foo/trait.Tr.html '//pre[@class="rust trait"]/code/a[@class="trait"]' '~const'
+// @!has - '//pre[@class="rust trait"]/code/a[@class="trait"]' 'Drop'
+// @has - '//pre[@class="rust trait"]/code/a[@class="trait"]' 'Clone'
+// @!has - '//pre[@class="rust trait"]/code/span[@class="where"]' '~const'
+// @!has - '//pre[@class="rust trait"]/code/span[@class="where"]' 'Drop'
+// @has - '//pre[@class="rust trait"]/code/span[@class="where"]' ': Clone'
+pub trait Tr<T> {
+ // @!has - '//div[@id="method.a"]/h4[@class="code-header"]' '~const'
+ // @!has - '//div[@id="method.a"]/h4[@class="code-header"]/a[@class="trait"]' 'Drop'
+ // @has - '//div[@id="method.a"]/h4[@class="code-header"]/a[@class="trait"]' 'Clone'
+ // @!has - '//div[@id="method.a"]/h4[@class="code-header"]/span[@class="where"]' '~const'
+ // @!has - '//div[@id="method.a"]/h4[@class="code-header"]/span[@class="where fmt-newline"]' 'Drop'
+ // @has - '//div[@id="method.a"]/h4[@class="code-header"]/span[@class="where fmt-newline"]' ': Clone'
+ #[default_method_body_is_const]
+ fn a<A: ~const Drop + ~const Clone>() where Option<A>: ~const Drop + ~const Clone {}
+}
+
+// @!has - '//section[@id="impl-Tr%3CT%3E"]/h3[@class="code-header in-band"]' '~const'
+// @!has - '//section[@id="impl-Tr%3CT%3E"]/h3[@class="code-header in-band"]/a[@class="trait"]' 'Drop'
+// @has - '//section[@id="impl-Tr%3CT%3E"]/h3[@class="code-header in-band"]/a[@class="trait"]' 'Clone'
+// @!has - '//section[@id="impl-Tr%3CT%3E"]/h3[@class="code-header in-band"]/span[@class="where"]' '~const'
+// @!has - '//section[@id="impl-Tr%3CT%3E"]/h3[@class="code-header in-band"]/span[@class="where fmt-newline"]' 'Drop'
+// @has - '//section[@id="impl-Tr%3CT%3E"]/h3[@class="code-header in-band"]/span[@class="where fmt-newline"]' ': Clone'
+impl<T: ~const Drop + ~const Clone> const Tr<T> for T where Option<T>: ~const Drop + ~const Clone {
+ fn a<A: ~const Drop + ~const Clone>() where Option<A>: ~const Drop + ~const Clone {}
+}
+
+// @!has foo/fn.foo.html '//pre[@class="rust fn"]/code/a[@class="trait"]' '~const'
+// @!has - '//pre[@class="rust fn"]/code/a[@class="trait"]' 'Drop'
+// @has - '//pre[@class="rust fn"]/code/a[@class="trait"]' 'Clone'
+// @!has - '//pre[@class="rust fn"]/code/span[@class="where fmt-newline"]' '~const'
+// @!has - '//pre[@class="rust fn"]/code/span[@class="where fmt-newline"]' 'Drop'
+// @has - '//pre[@class="rust fn"]/code/span[@class="where fmt-newline"]' ': Clone'
+pub const fn foo<F: ~const Drop + ~const Clone>() where Option<F>: ~const Drop + ~const Clone {
+ F::a()
+}
+
+impl<T> S<T> {
+ // @!has foo/struct.S.html '//section[@id="method.foo"]/h4[@class="code-header"]' '~const'
+ // @!has - '//section[@id="method.foo"]/h4[@class="code-header"]/a[@class="trait"]' 'Drop'
+ // @has - '//section[@id="method.foo"]/h4[@class="code-header"]/a[@class="trait"]' 'Clone'
+ // @!has - '//section[@id="method.foo"]/h4[@class="code-header"]/span[@class="where"]' '~const'
+ // @!has - '//section[@id="method.foo"]/h4[@class="code-header"]/span[@class="where fmt-newline"]' 'Drop'
+ // @has - '//section[@id="method.foo"]/h4[@class="code-header"]/span[@class="where fmt-newline"]' ': Clone'
+ pub const fn foo<B: ~const Drop + ~const Clone>() where B: ~const Drop + ~const Clone {
+ B::a()
+ }
+}
// compile-flags:-C panic=abort
-#![feature(alloc_error_handler, panic_handler)]
+#![feature(alloc_error_handler)]
#![no_std]
#![no_main]
// compile-flags:-C panic=abort
-#![feature(alloc_error_handler, panic_handler)]
+#![feature(alloc_error_handler)]
#![no_std]
#![no_main]
// compile-flags:-C panic=abort
-#![feature(alloc_error_handler, panic_handler)]
+#![feature(alloc_error_handler)]
#![no_std]
#![no_main]
// ignore-wasm32
#![feature(naked_functions)]
-#![feature(or_patterns)]
#![feature(asm_const, asm_sym, asm_unwind)]
#![crate_type = "lib"]
error: asm with the `pure` option must have at least one output
- --> $DIR/naked-functions.rs:111:14
+ --> $DIR/naked-functions.rs:110:14
|
LL | asm!("", options(readonly, nostack), options(pure));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^
error: patterns not allowed in naked function parameters
- --> $DIR/naked-functions.rs:21:5
+ --> $DIR/naked-functions.rs:20:5
|
LL | mut a: u32,
| ^^^^^
error: patterns not allowed in naked function parameters
- --> $DIR/naked-functions.rs:23:5
+ --> $DIR/naked-functions.rs:22:5
|
LL | &b: &i32,
| ^^
error: patterns not allowed in naked function parameters
- --> $DIR/naked-functions.rs:25:6
+ --> $DIR/naked-functions.rs:24:6
|
LL | (None | Some(_)): Option<std::ptr::NonNull<u8>>,
| ^^^^^^^^^^^^^^
error: patterns not allowed in naked function parameters
- --> $DIR/naked-functions.rs:27:5
+ --> $DIR/naked-functions.rs:26:5
|
LL | P { x, y }: P,
| ^^^^^^^^^^
error: referencing function parameters is not allowed in naked functions
- --> $DIR/naked-functions.rs:36:5
+ --> $DIR/naked-functions.rs:35:5
|
LL | a + 1
| ^
= help: follow the calling convention in asm block to use parameters
error[E0787]: naked functions must contain a single asm block
- --> $DIR/naked-functions.rs:34:1
+ --> $DIR/naked-functions.rs:33:1
|
LL | / pub unsafe extern "C" fn inc(a: u32) -> u32 {
LL | |
| |_^
error: referencing function parameters is not allowed in naked functions
- --> $DIR/naked-functions.rs:42:31
+ --> $DIR/naked-functions.rs:41:31
|
LL | asm!("/* {0} */", in(reg) a, options(noreturn));
| ^
= help: follow the calling convention in asm block to use parameters
error[E0787]: only `const` and `sym` operands are supported in naked functions
- --> $DIR/naked-functions.rs:42:23
+ --> $DIR/naked-functions.rs:41:23
|
LL | asm!("/* {0} */", in(reg) a, options(noreturn));
| ^^^^^^^^^
error[E0787]: naked functions must contain a single asm block
- --> $DIR/naked-functions.rs:48:1
+ --> $DIR/naked-functions.rs:47:1
|
LL | / pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
LL | |
| |_^
error[E0787]: only `const` and `sym` operands are supported in naked functions
- --> $DIR/naked-functions.rs:65:10
+ --> $DIR/naked-functions.rs:64:10
|
LL | in(reg) a,
| ^^^^^^^^^
| ^^^^^^^^^^
error[E0787]: asm in naked functions must use `noreturn` option
- --> $DIR/naked-functions.rs:63:5
+ --> $DIR/naked-functions.rs:62:5
|
LL | / asm!("/* {0} {1} {2} {3} {4} {5} {6} */",
LL | |
| |_____^
error[E0787]: naked functions must contain a single asm block
- --> $DIR/naked-functions.rs:54:1
+ --> $DIR/naked-functions.rs:53:1
|
LL | / pub unsafe extern "C" fn unsupported_operands() {
LL | |
| |_^
error[E0787]: naked functions must contain a single asm block
- --> $DIR/naked-functions.rs:77:1
+ --> $DIR/naked-functions.rs:76:1
|
LL | / pub extern "C" fn missing_assembly() {
LL | |
| |_^
error[E0787]: asm in naked functions must use `noreturn` option
- --> $DIR/naked-functions.rs:84:5
+ --> $DIR/naked-functions.rs:83:5
|
LL | asm!("");
| ^^^^^^^^
error[E0787]: asm in naked functions must use `noreturn` option
- --> $DIR/naked-functions.rs:86:5
+ --> $DIR/naked-functions.rs:85:5
|
LL | asm!("");
| ^^^^^^^^
error[E0787]: asm in naked functions must use `noreturn` option
- --> $DIR/naked-functions.rs:88:5
+ --> $DIR/naked-functions.rs:87:5
|
LL | asm!("");
| ^^^^^^^^
error[E0787]: naked functions must contain a single asm block
- --> $DIR/naked-functions.rs:82:1
+ --> $DIR/naked-functions.rs:81:1
|
LL | / pub extern "C" fn too_many_asm_blocks() {
LL | |
| |_^
error: referencing function parameters is not allowed in naked functions
- --> $DIR/naked-functions.rs:97:11
+ --> $DIR/naked-functions.rs:96:11
|
LL | *&y
| ^
= help: follow the calling convention in asm block to use parameters
error[E0787]: naked functions must contain a single asm block
- --> $DIR/naked-functions.rs:95:5
+ --> $DIR/naked-functions.rs:94:5
|
LL | / pub extern "C" fn inner(y: usize) -> usize {
LL | |
| |_____^
error[E0787]: asm options unsupported in naked functions: `nomem`, `preserves_flags`
- --> $DIR/naked-functions.rs:105:5
+ --> $DIR/naked-functions.rs:104:5
|
LL | asm!("", options(nomem, preserves_flags, noreturn));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0787]: asm options unsupported in naked functions: `nostack`, `pure`, `readonly`
- --> $DIR/naked-functions.rs:111:5
+ --> $DIR/naked-functions.rs:110:5
|
LL | asm!("", options(readonly, nostack), options(pure));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0787]: asm in naked functions must use `noreturn` option
- --> $DIR/naked-functions.rs:111:5
+ --> $DIR/naked-functions.rs:110:5
|
LL | asm!("", options(readonly, nostack), options(pure));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0787]: asm options unsupported in naked functions: `may_unwind`
- --> $DIR/naked-functions.rs:119:5
+ --> $DIR/naked-functions.rs:118:5
|
LL | asm!("", options(noreturn, may_unwind));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: Rust ABI is unsupported in naked functions
- --> $DIR/naked-functions.rs:124:15
+ --> $DIR/naked-functions.rs:123: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:130:15
+ --> $DIR/naked-functions.rs:129:15
|
LL | pub unsafe fn rust_abi() {
| ^^^^^^^^
error: naked functions cannot be inlined
- --> $DIR/naked-functions.rs:170:1
+ --> $DIR/naked-functions.rs:169:1
|
LL | #[inline]
| ^^^^^^^^^
error: naked functions cannot be inlined
- --> $DIR/naked-functions.rs:177:1
+ --> $DIR/naked-functions.rs:176:1
|
LL | #[inline(always)]
| ^^^^^^^^^^^^^^^^^
error: naked functions cannot be inlined
- --> $DIR/naked-functions.rs:184:1
+ --> $DIR/naked-functions.rs:183:1
|
LL | #[inline(never)]
| ^^^^^^^^^^^^^^^^
error: naked functions cannot be inlined
- --> $DIR/naked-functions.rs:191:1
+ --> $DIR/naked-functions.rs:190:1
|
LL | #[inline]
| ^^^^^^^^^
error: naked functions cannot be inlined
- --> $DIR/naked-functions.rs:193:1
+ --> $DIR/naked-functions.rs:192:1
|
LL | #[inline(always)]
| ^^^^^^^^^^^^^^^^^
error: naked functions cannot be inlined
- --> $DIR/naked-functions.rs:195:1
+ --> $DIR/naked-functions.rs:194:1
|
LL | #[inline(never)]
| ^^^^^^^^^^^^^^^^
// #29924
-#![feature(associated_consts)]
-
trait Trait {
const N: usize;
}
error[E0038]: the trait `Trait` cannot be made into an object
- --> $DIR/associated-const-in-trait.rs:9:6
+ --> $DIR/associated-const-in-trait.rs:7:6
|
LL | impl dyn Trait {
| ^^^^^^^^^ `Trait` 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/associated-const-in-trait.rs:6:11
+ --> $DIR/associated-const-in-trait.rs:4:11
|
LL | trait Trait {
| ----- this trait cannot be made into an object...
{
fn get_service(
//~^ ERROR the trait bound `Bug: Foo` is not satisfied
- //~| ERROR the trait bound `Bug: Foo` is not satisfied
&self,
) -> Self::AssocType;
+ //~^ the trait bound `Bug: Foo` is not satisfied
}
fn with_factory<H>(factory: dyn ThriftService<()>) {}
LL | |
LL | | Service<AssocType = <Bug as Foo>::OnlyFoo>
... |
-LL | | ) -> Self::AssocType;
+LL | |
LL | | }
| |_^ the trait `Foo` is not implemented for `Bug`
|
LL | |
LL | | Service<AssocType = <Bug as Foo>::OnlyFoo>
... |
-LL | | ) -> Self::AssocType;
+LL | |
LL | | }
| |_^ the trait `Foo` is not implemented for `Bug`
|
|
LL | / fn get_service(
LL | |
-LL | |
LL | | &self,
LL | | ) -> Self::AssocType;
| |_________________________^ the trait `Foo` is not implemented for `Bug`
| +++++
error[E0277]: the trait bound `Bug: Foo` is not satisfied
- --> $DIR/issue-59324.rs:16:8
+ --> $DIR/issue-59324.rs:19:10
|
-LL | fn get_service(
- | ^^^^^^^^^^^ the trait `Foo` is not implemented for `Bug`
+LL | ) -> Self::AssocType;
+ | ^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `Bug`
|
help: consider further restricting this bound
|
// edition:2018
-// compile-flags: --crate-type lib
-
-// FIXME(eholk): temporarily disabled while drop range tracking is disabled
-// (see generator_interior.rs:27)
-// ignore-test
+// compile-flags: --crate-type lib -Zdrop-tracking
use std::{cell::RefCell, fmt::Debug, rc::Rc};
--- /dev/null
+// edition:2021
+// compile-flags: -Zdrop-tracking
+// build-pass
+
+struct A;
+impl Drop for A { fn drop(&mut self) {} }
+
+pub async fn f() {
+ let mut a = A;
+ a = A;
+ drop(a);
+ async {}.await;
+}
+
+fn assert_send<T: Send>(_: T) {}
+
+fn main() {
+ let _ = f();
+}
LL | async fn foo() {}
| ^^^^^ to use `async fn`, switch to Rust 2018 or later
|
- = help: set `edition = "2021"` in `Cargo.toml`
+ = help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error[E0670]: `async fn` is not permitted in Rust 2015
LL | fn baz() { async fn foo() {} }
| ^^^^^ to use `async fn`, switch to Rust 2018 or later
|
- = help: set `edition = "2021"` in `Cargo.toml`
+ = help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error[E0670]: `async fn` is not permitted in Rust 2015
LL | async fn async_baz() {
| ^^^^^ to use `async fn`, switch to Rust 2018 or later
|
- = help: set `edition = "2021"` in `Cargo.toml`
+ = help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error[E0670]: `async fn` is not permitted in Rust 2015
LL | async fn bar() {}
| ^^^^^ to use `async fn`, switch to Rust 2018 or later
|
- = help: set `edition = "2021"` in `Cargo.toml`
+ = help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error[E0670]: `async fn` is not permitted in Rust 2015
LL | async fn foo() {}
| ^^^^^ to use `async fn`, switch to Rust 2018 or later
|
- = help: set `edition = "2021"` in `Cargo.toml`
+ = help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error[E0670]: `async fn` is not permitted in Rust 2015
LL | async fn foo() {}
| ^^^^^ to use `async fn`, switch to Rust 2018 or later
|
- = help: set `edition = "2021"` in `Cargo.toml`
+ = help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error[E0670]: `async fn` is not permitted in Rust 2015
LL | async fn bar() {}
| ^^^^^ to use `async fn`, switch to Rust 2018 or later
|
- = help: set `edition = "2021"` in `Cargo.toml`
+ = help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error[E0670]: `async fn` is not permitted in Rust 2015
LL | async fn foo() {}
| ^^^^^ to use `async fn`, switch to Rust 2018 or later
|
- = help: set `edition = "2021"` in `Cargo.toml`
+ = help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error[E0670]: `async fn` is not permitted in Rust 2015
LL | async fn bar() {}
| ^^^^^ to use `async fn`, switch to Rust 2018 or later
|
- = help: set `edition = "2021"` in `Cargo.toml`
+ = help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error[E0706]: functions in traits cannot be declared `async`
--- /dev/null
+// rustc-env:CARGO=/usr/bin/cargo
+
+use std::pin::Pin;
+use std::future::Future;
+
+fn main() {}
+
+fn await_on_struct_missing() {
+ struct S;
+ let x = S;
+ x.await;
+ //~^ ERROR no field `await` on type
+ //~| NOTE unknown field
+ //~| NOTE to `.await` a `Future`, switch to Rust 2018
+ //~| HELP set `edition = "2021"` in `Cargo.toml`
+ //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
+}
+
+fn await_on_struct_similar() {
+ struct S {
+ awai: u8,
+ }
+ let x = S { awai: 42 };
+ x.await;
+ //~^ ERROR no field `await` on type
+ //~| HELP a field with a similar name exists
+ //~| NOTE to `.await` a `Future`, switch to Rust 2018
+ //~| HELP set `edition = "2021"` in `Cargo.toml`
+ //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
+}
+
+fn await_on_63533(x: Pin<&mut dyn Future<Output = ()>>) {
+ x.await;
+ //~^ ERROR no field `await` on type
+ //~| NOTE unknown field
+ //~| NOTE to `.await` a `Future`, switch to Rust 2018
+ //~| HELP set `edition = "2021"` in `Cargo.toml`
+ //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
+}
+
+fn await_on_apit(x: impl Future<Output = ()>) {
+ x.await;
+ //~^ ERROR no field `await` on type
+ //~| NOTE to `.await` a `Future`, switch to Rust 2018
+ //~| HELP set `edition = "2021"` in `Cargo.toml`
+ //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
+}
--- /dev/null
+error[E0609]: no field `await` on type `await_on_struct_missing::S`
+ --> $DIR/suggest-switching-edition-on-await-cargo.rs:11:7
+ |
+LL | x.await;
+ | ^^^^^ unknown field
+ |
+ = note: to `.await` a `Future`, switch to Rust 2018 or later
+ = help: set `edition = "2021"` in `Cargo.toml`
+ = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error[E0609]: no field `await` on type `await_on_struct_similar::S`
+ --> $DIR/suggest-switching-edition-on-await-cargo.rs:24:7
+ |
+LL | x.await;
+ | ^^^^^ help: a field with a similar name exists: `awai`
+ |
+ = note: to `.await` a `Future`, switch to Rust 2018 or later
+ = help: set `edition = "2021"` in `Cargo.toml`
+ = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error[E0609]: no field `await` on type `Pin<&mut dyn Future<Output = ()>>`
+ --> $DIR/suggest-switching-edition-on-await-cargo.rs:33:7
+ |
+LL | x.await;
+ | ^^^^^ unknown field
+ |
+ = note: to `.await` a `Future`, switch to Rust 2018 or later
+ = help: set `edition = "2021"` in `Cargo.toml`
+ = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error[E0609]: no field `await` on type `impl Future<Output = ()>`
+ --> $DIR/suggest-switching-edition-on-await-cargo.rs:42:7
+ |
+LL | x.await;
+ | ^^^^^
+ |
+ = note: to `.await` a `Future`, switch to Rust 2018 or later
+ = help: set `edition = "2021"` in `Cargo.toml`
+ = note: for more on editions, read https://doc.rust-lang.org/edition-guide
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0609`.
//~^ ERROR no field `await` on type
//~| NOTE unknown field
//~| NOTE to `.await` a `Future`, switch to Rust 2018
- //~| HELP set `edition = "2021"` in `Cargo.toml`
+ //~| HELP pass `--edition 2021` to `rustc`
//~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
}
//~^ ERROR no field `await` on type
//~| HELP a field with a similar name exists
//~| NOTE to `.await` a `Future`, switch to Rust 2018
- //~| HELP set `edition = "2021"` in `Cargo.toml`
+ //~| HELP pass `--edition 2021` to `rustc`
//~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
}
//~^ ERROR no field `await` on type
//~| NOTE unknown field
//~| NOTE to `.await` a `Future`, switch to Rust 2018
- //~| HELP set `edition = "2021"` in `Cargo.toml`
+ //~| HELP pass `--edition 2021` to `rustc`
//~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
}
x.await;
//~^ ERROR no field `await` on type
//~| NOTE to `.await` a `Future`, switch to Rust 2018
- //~| HELP set `edition = "2021"` in `Cargo.toml`
+ //~| HELP pass `--edition 2021` to `rustc`
//~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
}
| ^^^^^ unknown field
|
= note: to `.await` a `Future`, switch to Rust 2018 or later
- = help: set `edition = "2021"` in `Cargo.toml`
+ = help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error[E0609]: no field `await` on type `await_on_struct_similar::S`
| ^^^^^ help: a field with a similar name exists: `awai`
|
= note: to `.await` a `Future`, switch to Rust 2018 or later
- = help: set `edition = "2021"` in `Cargo.toml`
+ = help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error[E0609]: no field `await` on type `Pin<&mut dyn Future<Output = ()>>`
| ^^^^^ unknown field
|
= note: to `.await` a `Future`, switch to Rust 2018 or later
- = help: set `edition = "2021"` in `Cargo.toml`
+ = help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error[E0609]: no field `await` on type `impl Future<Output = ()>`
| ^^^^^
|
= note: to `.await` a `Future`, switch to Rust 2018 or later
- = help: set `edition = "2021"` in `Cargo.toml`
+ = help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error: aborting due to 4 previous errors
-#![feature(try_trait, async_closure)]
+#![feature(async_closure)]
// edition:2018
fn main() {}
// Error message should pinpoint the type parameter T as needing to be bound
// (rather than give a general error message)
// edition:2018
-
-// FIXME(eholk): temporarily disabled while drop range tracking is disabled
-// (see generator_interior.rs:27)
-// ignore-test
+// compile-flags: -Zdrop-tracking
async fn bar<T>() -> () {}
error[E0698]: type inside `async fn` body must be known in this context
- --> $DIR/unresolved_type_param.rs:9:5
+ --> $DIR/unresolved_type_param.rs:10:5
|
LL | bar().await;
| ^^^ cannot infer type for type parameter `T` declared on the function `bar`
|
note: the type is part of the `async fn` body because of this `await`
- --> $DIR/unresolved_type_param.rs:9:10
+ --> $DIR/unresolved_type_param.rs:10:10
|
LL | bar().await;
| ^^^^^^
error[E0698]: type inside `async fn` body must be known in this context
- --> $DIR/unresolved_type_param.rs:9:5
+ --> $DIR/unresolved_type_param.rs:10:5
|
LL | bar().await;
| ^^^ cannot infer type for type parameter `T` declared on the function `bar`
|
note: the type is part of the `async fn` body because of this `await`
- --> $DIR/unresolved_type_param.rs:9:10
+ --> $DIR/unresolved_type_param.rs:10:10
|
LL | bar().await;
| ^^^^^^
error[E0698]: type inside `async fn` body must be known in this context
- --> $DIR/unresolved_type_param.rs:9:5
+ --> $DIR/unresolved_type_param.rs:10:5
|
LL | bar().await;
| ^^^ cannot infer type for type parameter `T` declared on the function `bar`
|
note: the type is part of the `async fn` body because of this `await`
- --> $DIR/unresolved_type_param.rs:9:10
+ --> $DIR/unresolved_type_param.rs:10:10
|
LL | bar().await;
| ^^^^^^
+#![feature(staged_api)]
+#![stable(feature = "rust1", since = "1.0.0")]
+
#[rustc_const_stable(feature = "foo", since = "0")]
//~^ ERROR macros cannot have const stability attributes
macro_rules! foo {
error: macros cannot have const stability attributes
- --> $DIR/const-stability-on-macro.rs:1:1
+ --> $DIR/const-stability-on-macro.rs:4:1
|
LL | #[rustc_const_stable(feature = "foo", since = "0")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid const stability attribute
| ---------------- const stability attribute affects this macro
error: macros cannot have const stability attributes
- --> $DIR/const-stability-on-macro.rs:7:1
+ --> $DIR/const-stability-on-macro.rs:10:1
|
LL | #[rustc_const_unstable(feature = "bar", issue="none")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid const stability attribute
// normalize-stderr-test: "couldn't read.*" -> "couldn't read the file"
-#![feature(extended_key_value_attributes)]
#![doc = include_str!("../not_existing_file.md")]
struct Documented {}
//~^^ ERROR couldn't read
error: couldn't read the file
- --> $DIR/extented-attribute-macro-error.rs:4:10
+ --> $DIR/extented-attribute-macro-error.rs:3:10
|
LL | #![doc = include_str!("../not_existing_file.md")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#![u=||{static d=||1;}]
//~^ unexpected token
//~| cannot find attribute `u` in this scope
-//~| `main` function not found in crate `issue_90873`
//~| missing type for `static` item
#![a={impl std::ops::Neg for i8 {}}]
//~^ ERROR unexpected token
//~| ERROR cannot find attribute `a` in this scope
+//~| ERROR `main` function not found in crate `issue_90873`
error: unexpected token: `{
impl std::ops::Neg for i8 {}
}`
- --> $DIR/issue-90873.rs:7:6
+ --> $DIR/issue-90873.rs:6:6
|
LL | #![a={impl std::ops::Neg for i8 {}}]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^
error: cannot find attribute `a` in this scope
- --> $DIR/issue-90873.rs:7:4
+ --> $DIR/issue-90873.rs:6:4
|
LL | #![a={impl std::ops::Neg for i8 {}}]
| ^
error[E0601]: `main` function not found in crate `issue_90873`
- --> $DIR/issue-90873.rs:1:1
+ --> $DIR/issue-90873.rs:6:37
|
-LL | / #![u=||{static d=||1;}]
-LL | |
-LL | |
-LL | |
-LL | |
-LL | |
-LL | | #![a={impl std::ops::Neg for i8 {}}]
- | |____________________________________^ consider adding a `main` function to `$DIR/issue-90873.rs`
+LL | #![a={impl std::ops::Neg for i8 {}}]
+ | ^ consider adding a `main` function to `$DIR/issue-90873.rs`
error: missing type for `static` item
--> $DIR/issue-90873.rs:1:16
--- /dev/null
+pub struct DataStruct();
+
+pub struct HelperStruct<'n> {
+ pub helpers: [Vec<&'n i64>; 2],
+ pub is_empty: bool,
+}
+
+impl DataStruct {
+ pub fn f(&self) -> HelperStruct {
+ let helpers = [vec![], vec![]];
+
+ HelperStruct { helpers, is_empty: helpers[0].is_empty() }
+ //~^ ERROR borrow of moved value
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0382]: borrow of moved value: `helpers`
+ --> $DIR/copy-suggestion-region-vid.rs:12:43
+ |
+LL | let helpers = [vec![], vec![]];
+ | ------- move occurs because `helpers` has type `[Vec<&i64>; 2]`, which does not implement the `Copy` trait
+LL |
+LL | HelperStruct { helpers, is_empty: helpers[0].is_empty() }
+ | ------- ^^^^^^^^^^^^^^^^^^^^^ value borrowed here after move
+ | |
+ | value moved here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
-#![feature(const_fn_trait_bound)]
// Regression test related to issue 88434
const _CONST: &() = &f(&|_| {});
error[E0080]: evaluation of constant value failed
- --> $DIR/issue-88434-minimal-example.rs:10:5
+ --> $DIR/issue-88434-minimal-example.rs:9:5
|
LL | const _CONST: &() = &f(&|_| {});
- | ---------- inside `_CONST` at $DIR/issue-88434-minimal-example.rs:4:22
+ | ---------- inside `_CONST` at $DIR/issue-88434-minimal-example.rs:3:22
...
LL | panic!()
| ^^^^^^^^
| |
- | the evaluated program panicked at 'explicit panic', $DIR/issue-88434-minimal-example.rs:10:5
- | inside `f::<[closure@$DIR/issue-88434-minimal-example.rs:4:25: 4:31]>` at $SRC_DIR/std/src/panic.rs:LL:COL
+ | the evaluated program panicked at 'explicit panic', $DIR/issue-88434-minimal-example.rs:9:5
+ | inside `f::<[closure@$DIR/issue-88434-minimal-example.rs:3:25: 3:31]>` at $SRC_DIR/std/src/panic.rs:LL:COL
|
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
-#![feature(const_fn_trait_bound)]
// Regression test for issue 88434
const _CONST: &[u8] = &f(&[], |_| {});
error[E0080]: evaluation of constant value failed
- --> $DIR/issue-88434-removal-index-should-be-less.rs:10:5
+ --> $DIR/issue-88434-removal-index-should-be-less.rs:9:5
|
LL | const _CONST: &[u8] = &f(&[], |_| {});
- | -------------- inside `_CONST` at $DIR/issue-88434-removal-index-should-be-less.rs:4:24
+ | -------------- inside `_CONST` at $DIR/issue-88434-removal-index-should-be-less.rs:3:24
...
LL | panic!()
| ^^^^^^^^
| |
- | the evaluated program panicked at 'explicit panic', $DIR/issue-88434-removal-index-should-be-less.rs:10:5
- | inside `f::<[closure@$DIR/issue-88434-removal-index-should-be-less.rs:4:31: 4:37]>` at $SRC_DIR/std/src/panic.rs:LL:COL
+ | the evaluated program panicked at 'explicit panic', $DIR/issue-88434-removal-index-should-be-less.rs:9:5
+ | inside `f::<[closure@$DIR/issue-88434-removal-index-should-be-less.rs:3:31: 3:37]>` at $SRC_DIR/std/src/panic.rs:LL:COL
|
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
-// Check that a an empty values() is rejected
+// Check warning for unexpected cfg value
//
-// check-fail
+// check-pass
// compile-flags: --check-cfg=values() -Z unstable-options
+#[cfg(test = "value")]
+//~^ WARNING unexpected `cfg` condition value
+pub fn f() {}
+
fn main() {}
-error: invalid `--check-cfg` argument: `values()` (expected `names(name1, name2, ... nameN)` or `values(name, "value1", "value2", ... "valueN")`)
+warning: unexpected `cfg` condition value
+ --> $DIR/empty-values.rs:6:7
+ |
+LL | #[cfg(test = "value")]
+ | ^^^^----------
+ | |
+ | help: remove the value
+ |
+ = note: `#[warn(unexpected_cfgs)]` on by default
+ = note: no expected value for `test`
+
+warning: 1 warning emitted
// Check that we detect unexpected value when none are allowed
//
// check-pass
-// compile-flags: --check-cfg=values(feature) -Z unstable-options
+// compile-flags: --check-cfg=values(test) --check-cfg=values(feature) -Z unstable-options
#[cfg(feature = "foo")]
//~^ WARNING unexpected `cfg` condition value
fn do_foo() {}
+#[cfg(test = "foo")]
+//~^ WARNING unexpected `cfg` condition value
+fn do_foo() {}
+
fn main() {}
= note: `#[warn(unexpected_cfgs)]` on by default
= note: no expected value for `feature`
-warning: 1 warning emitted
+warning: unexpected `cfg` condition value
+ --> $DIR/no-values.rs:10:7
+ |
+LL | #[cfg(test = "foo")]
+ | ^^^^--------
+ | |
+ | help: remove the value
+ |
+ = note: no expected value for `test`
+
+warning: 2 warnings emitted
--- /dev/null
+// This test checks that there is no ICE with this code
+//
+// check-pass
+// compile-flags:--check-cfg=names() -Z unstable-options
+
+fn main() {
+ #[cfg(crossbeam_loom)]
+ //~^ WARNING unexpected `cfg` condition name
+ {}
+}
--- /dev/null
+warning: unexpected `cfg` condition name
+ --> $DIR/stmt-no-ice.rs:7:11
+ |
+LL | #[cfg(crossbeam_loom)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: 1 warning emitted
+
--- /dev/null
+// This test check that we lint on non well known values and that we don't lint on well known
+// values
+//
+// check-pass
+// compile-flags: --check-cfg=values() -Z unstable-options
+
+#[cfg(target_os = "linuz")]
+//~^ WARNING unexpected `cfg` condition value
+fn target_os_linux_misspell() {}
+
+#[cfg(target_os = "linux")]
+fn target_os_linux() {}
+
+#[cfg(target_has_atomic = "0")]
+//~^ WARNING unexpected `cfg` condition value
+fn target_has_atomic_invalid() {}
+
+#[cfg(target_has_atomic = "8")]
+fn target_has_atomic() {}
+
+#[cfg(unix = "aa")]
+//~^ WARNING unexpected `cfg` condition value
+fn unix_with_value() {}
+
+#[cfg(unix)]
+fn unix() {}
+
+fn main() {}
--- /dev/null
+warning: unexpected `cfg` condition value
+ --> $DIR/well-known-values.rs:7:7
+ |
+LL | #[cfg(target_os = "linuz")]
+ | ^^^^^^^^^^^^-------
+ | |
+ | help: did you mean: `"linux"`
+ |
+ = note: `#[warn(unexpected_cfgs)]` on by default
+ = note: expected values for `target_os` are: android, cuda, dragonfly, emscripten, espidf, freebsd, fuchsia, haiku, hermit, horizon, illumos, ios, l4re, linux, macos, netbsd, none, openbsd, psp, redox, solaris, solid_asp3, tvos, uefi, unknown, vxworks, wasi, windows
+
+warning: unexpected `cfg` condition value
+ --> $DIR/well-known-values.rs:14:7
+ |
+LL | #[cfg(target_has_atomic = "0")]
+ | ^^^^^^^^^^^^^^^^^^^^---
+ | |
+ | help: did you mean: `"8"`
+ |
+ = note: expected values for `target_has_atomic` are: 128, 16, 32, 64, 8, ptr
+
+warning: unexpected `cfg` condition value
+ --> $DIR/well-known-values.rs:21:7
+ |
+LL | #[cfg(unix = "aa")]
+ | ^^^^-------
+ | |
+ | help: remove the value
+ |
+ = note: no expected value for `unix`
+
+warning: 3 warnings emitted
+
error[E0004]: non-exhaustive patterns: `Opcode(0_u8)` and `Opcode(2_u8..=u8::MAX)` not covered
--> $DIR/issue-88331.rs:11:20
|
-LL | pub struct Opcode(pub u8);
- | -------------------------- `Opcode` defined here
-...
LL | move |i| match msg_type {
| ^^^^^^^^ patterns `Opcode(0_u8)` and `Opcode(2_u8..=u8::MAX)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Opcode` defined here
+ --> $DIR/issue-88331.rs:4:12
+ |
+LL | pub struct Opcode(pub u8);
+ | ^^^^^^
= note: the matched value is of type `Opcode`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ Opcode::OP1 => unimplemented!(),
+LL ~ Opcode(0_u8) | Opcode(2_u8..=u8::MAX) => todo!(),
+ |
error[E0004]: non-exhaustive patterns: `Opcode2(Opcode(0_u8))` and `Opcode2(Opcode(2_u8..=u8::MAX))` not covered
--> $DIR/issue-88331.rs:27:20
|
-LL | pub struct Opcode2(Opcode);
- | --------------------------- `Opcode2` defined here
-...
LL | move |i| match msg_type {
| ^^^^^^^^ patterns `Opcode2(Opcode(0_u8))` and `Opcode2(Opcode(2_u8..=u8::MAX))` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Opcode2` defined here
+ --> $DIR/issue-88331.rs:18:12
+ |
+LL | pub struct Opcode2(Opcode);
+ | ^^^^^^^
= note: the matched value is of type `Opcode2`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ Opcode2::OP2=> unimplemented!(),
+LL ~ Opcode2(Opcode(0_u8)) | Opcode2(Opcode(2_u8..=u8::MAX)) => todo!(),
+ |
error: aborting due to 2 previous errors
error[E0004]: non-exhaustive patterns: `B` not covered
--> $DIR/non-exhaustive-match.rs:26:25
|
-LL | enum L1 { A, B }
- | ----------------
- | | |
- | | not covered
- | `L1` defined here
-...
LL | let _b = || { match l1 { L1::A => () } };
| ^^ pattern `B` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `L1` defined here
+ --> $DIR/non-exhaustive-match.rs:12:14
+ |
+LL | enum L1 { A, B }
+ | -- ^ not covered
= note: the matched value is of type `L1`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL | let _b = || { match l1 { L1::A => (), B => todo!() } };
+ | ++++++++++++++
error[E0004]: non-exhaustive patterns: type `E1` is non-empty
--> $DIR/non-exhaustive-match.rs:37:25
LL | let _d = || { match e1 {} };
| ^^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `E1` defined here
+ --> $DIR/auxiliary/match_non_exhaustive_lib.rs:2:1
+ |
+LL | pub enum E1 {}
+ | ^^^^^^^^^^^^^^
= note: the matched value is of type `E1`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ let _d = || { match e1 {
+LL + _ => todo!(),
+LL ~ } };
+ |
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/non-exhaustive-match.rs:39:25
LL | let _e = || { match e2 { E2::A => (), E2::B => () } };
| ^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `E2` defined here
+ --> $DIR/auxiliary/match_non_exhaustive_lib.rs:5:1
+ |
+LL | pub enum E2 { A, B }
+ | ^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `E2`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL | let _e = || { match e2 { E2::A => (), E2::B => (), _ => todo!() } };
+ | ++++++++++++++
error[E0505]: cannot move out of `e3` because it is borrowed
--> $DIR/non-exhaustive-match.rs:46:22
LL | let c1 = || match x { };
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ let c1 = || match x {
+LL + _ => todo!(),
+LL ~ };
+ |
error[E0381]: use of possibly-uninitialized variable: `x`
--> $DIR/pattern-matching-should-fail.rs:8:23
error[E0601]: `main` function not found in crate `cfg_attr_cfg_2`
- --> $DIR/cfg-attr-cfg-2.rs:8:1
+ --> $DIR/cfg-attr-cfg-2.rs:9:14
|
-LL | / #[cfg_attr(foo, cfg(bar))]
-LL | | fn main() { }
- | |_____________^ consider adding a `main` function to `$DIR/cfg-attr-cfg-2.rs`
+LL | fn main() { }
+ | ^ consider adding a `main` function to `$DIR/cfg-attr-cfg-2.rs`
error: aborting due to previous error
error[E0601]: `main` function not found in crate `cfg_in_crate_1`
- --> $DIR/cfg-in-crate-1.rs:3:1
+ --> $DIR/cfg-in-crate-1.rs:3:13
|
LL | #![cfg(bar)]
- | ^^^^^^^^^^^^ consider adding a `main` function to `$DIR/cfg-in-crate-1.rs`
+ | ^ consider adding a `main` function to `$DIR/cfg-in-crate-1.rs`
error: aborting due to previous error
-#![feature(const_fn_trait_bound, generic_const_exprs)]
+#![feature(generic_const_exprs)]
#![allow(incomplete_features)]
trait _Contains<T> {
-#![feature(const_fn_trait_bound, generic_const_exprs)]
+#![feature(generic_const_exprs)]
#![allow(incomplete_features)]
trait MiniTypeId {
-#![feature(generic_const_exprs, array_map)]
+#![feature(generic_const_exprs)]
#![allow(incomplete_features)]
pub struct ConstCheck<const CHECK: bool>;
// Crate that exports a const fn. Used for testing cross-crate.
-#![feature(const_fn_fn_ptr_basics)]
#![crate_type="rlib"]
pub const fn foo() -> usize { 22 }
-#![feature(const_indexing)]
-
const ARR: [i32; 6] = [42, 43, 44, 45, 46, 47];
const IDX: usize = 3;
const VAL: i32 = ARR[IDX];
error[E0308]: mismatched types
- --> $DIR/const-array-oob-arith.rs:7:45
+ --> $DIR/const-array-oob-arith.rs:5:45
|
LL | const BLUB: [i32; (ARR[0] - 40) as usize] = [5];
| ^^^ expected an array with a fixed size of 2 elements, found one with 1 element
error[E0308]: mismatched types
- --> $DIR/const-array-oob-arith.rs:10:44
+ --> $DIR/const-array-oob-arith.rs:8:44
|
LL | const BOO: [i32; (ARR[0] - 41) as usize] = [5, 99];
| ^^^^^^^ expected an array with a fixed size of 1 element, found one with 2 elements
-#![feature(const_indexing)]
-
const FOO: [usize; 3] = [1, 2, 3];
const BAR: usize = FOO[5]; // no error, because the error below occurs before regular const eval
error[E0080]: evaluation of constant value failed
- --> $DIR/const-array-oob.rs:6:19
+ --> $DIR/const-array-oob.rs:4:19
|
LL | const BLUB: [u32; FOO[4]] = [5, 6];
| ^^^^^^ index out of bounds: the length is 3 but the index is 4
#![allow(unused)]
-#![feature(const_fn_trait_bound, const_trait_impl, inline_const, negative_impls)]
+#![feature(const_trait_impl, inline_const, negative_impls)]
const fn f<T: ~const Drop>(x: T) {}
|
LL | X_CONST(x)
| ^^^^^^^^^^
-help: skipping check for `const_fn_fn_ptr_basics` feature
- --> $DIR/const_fn_ptr.rs:18:14
- |
-LL | const fn foo(x: fn(usize) -> usize, y: usize) -> usize {
- | ^
-help: skipping check for `const_fn_fn_ptr_basics` feature
- --> $DIR/const_fn_ptr.rs:19:5
- |
-LL | x(y)
- | ^
help: skipping check that does not even have a feature gate
--> $DIR/const_fn_ptr.rs:19:5
|
LL | x(y)
| ^^^^
-error: `-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature gates, except when testing error paths in the CTFE engine
-
-error: aborting due to previous error; 1 warning emitted
+warning: 1 warning emitted
warning: skipping const checks
|
-help: skipping check for `const_fn_fn_ptr_basics` feature
- --> $DIR/const_fn_ptr_fail2.rs:11:14
- |
-LL | const fn bar(x: fn(usize) -> usize, y: usize) -> usize {
- | ^
-help: skipping check for `const_fn_fn_ptr_basics` feature
- --> $DIR/const_fn_ptr_fail2.rs:12:5
- |
-LL | x(y)
- | ^
help: skipping check that does not even have a feature gate
--> $DIR/const_fn_ptr_fail2.rs:12:5
|
// issue-49296: Unsafe shenigans in constants can result in missing errors
-#![feature(const_fn_trait_bound)]
-
use std::mem::transmute;
const fn wat(x: u64) -> &'static u64 {
error[E0080]: evaluation of constant value failed
- --> $DIR/issue-49296.rs:11:16
+ --> $DIR/issue-49296.rs:9:16
|
LL | const X: u64 = *wat(42);
| ^^^^^^^^ pointer to alloc2 was dereferenced after this allocation got freed
// check-pass
-#![feature(const_fn_fn_ptr_basics)]
const fn nested(x: (for<'a> fn(&'a ()), String)) -> (fn(&'static ()), String) {
x
-#![feature(const_transmute)]
-
use std::mem;
fn main() {
error[E0716]: temporary value dropped while borrowed
- --> $DIR/transmute-const-promotion.rs:6:37
+ --> $DIR/transmute-const-promotion.rs:4:37
|
LL | let x: &'static u32 = unsafe { &mem::transmute(3.0f32) };
| ------------ ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
const extern "C" fn unsize(x: &[u8; 3]) -> &[u8] { x }
const unsafe extern "C" fn closure() -> fn() { || {} }
-//~^ ERROR function pointer
-//~| ERROR function pointer cast
const unsafe extern "C" fn use_float() { 1.0 + 1.0; }
//~^ ERROR floating point arithmetic
const extern "C" fn ptr_cast(val: *const u8) { val as usize; }
-error[E0658]: function pointers cannot appear in constant functions
- --> $DIR/const-extern-fn-min-const-fn.rs:4:41
- |
-LL | const unsafe extern "C" fn closure() -> fn() { || {} }
- | ^^^^
- |
- = 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[E0658]: function pointer casts are not allowed in constant functions
- --> $DIR/const-extern-fn-min-const-fn.rs:4:48
- |
-LL | const unsafe extern "C" fn closure() -> fn() { || {} }
- | ^^^^^
- |
- = 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[E0658]: floating point arithmetic is not allowed in constant functions
- --> $DIR/const-extern-fn-min-const-fn.rs:7:42
+ --> $DIR/const-extern-fn-min-const-fn.rs:5:42
|
LL | const unsafe extern "C" fn use_float() { 1.0 + 1.0; }
| ^^^^^^^^^
= help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable
error: pointers cannot be cast to integers during const eval
- --> $DIR/const-extern-fn-min-const-fn.rs:9:48
+ --> $DIR/const-extern-fn-min-const-fn.rs:7:48
|
LL | const extern "C" fn ptr_cast(val: *const u8) { val 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 4 previous errors
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0658`.
// A very basic test of const fn functionality.
#![feature(const_indexing)]
-#![feature(const_fn_trait_bound)]
const fn add(x: u32, y: u32) -> u32 {
x + y
+++ /dev/null
-error: fatal error triggered by #[rustc_error]
- --> $DIR/const_fn_trait_bound.rs:17:1
- |
-LL | fn main() {}
- | ^^^^^^^^^
-
-error: aborting due to previous error
-
+++ /dev/null
-// gate-test-const_fn_trait_bound
-
-// revisions: stock gated
-
-#![feature(rustc_attrs)]
-#![cfg_attr(gated, feature(const_fn_trait_bound))]
-
-const fn test1<T: std::ops::Add>() {}
-//[stock]~^ trait bounds
-const fn test2(_x: &dyn Send) {}
-//[stock]~^ trait objects in const fn are unstable
-const fn test3() -> &'static dyn Send { loop {} }
-//[stock]~^ trait objects in const fn are unstable
-
-
-#[rustc_error]
-fn main() {} //[gated]~ fatal error triggered by #[rustc_error]
+++ /dev/null
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/const_fn_trait_bound.rs:8:16
- |
-LL | const fn test1<T: std::ops::Add>() {}
- | ^
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait objects in const fn are unstable
- --> $DIR/const_fn_trait_bound.rs:10:16
- |
-LL | const fn test2(_x: &dyn Send) {}
- | ^^
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait objects in const fn are unstable
- --> $DIR/const_fn_trait_bound.rs:12:21
- |
-LL | const fn test3() -> &'static dyn Send { loop {} }
- | ^^^^^^^^^^^^^^^^^
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
+// check-pass
+
const fn x() {
let t = true;
- let x = || t; //~ ERROR function pointer
+ let x = || t;
}
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`.
#![allow(dead_code)]
#![allow(unused_variables)]
-#![feature(const_fn_fn_ptr_basics)]
-
const fn x() {
let t = true;
let x = || t;
// run-pass
-#![feature(const_fn_fn_ptr_basics)]
#![deny(const_err)]
pub struct Data<T> {
-#![feature(const_fn_fn_ptr_basics)]
-
const fn foo() { (||{})() }
//~^ ERROR cannot call non-const closure
error[E0015]: cannot call non-const closure in constant functions
- --> $DIR/issue-56164.rs:3:18
+ --> $DIR/issue-56164.rs:1:18
|
LL | const fn foo() { (||{})() }
| ^^^^^^^^
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
error: function pointers are not allowed in const fn
- --> $DIR/issue-56164.rs:7:5
+ --> $DIR/issue-56164.rs:5:5
|
LL | input()
| ^^^^^^^
#![crate_type="lib"]
#![allow(unreachable_patterns)]
-#![feature(const_fn_union)]
#[derive(PartialEq, Eq)]
#[repr(transparent)]
error: cannot use unsized non-slice type `Username` in constant patterns
- --> $DIR/issue-87046.rs:29:13
+ --> $DIR/issue-87046.rs:28:13
|
LL | ROOT_USER => true,
| ^^^^^^^^^
// regression test for #88071
#![feature(const_btree_new)]
-#![feature(const_fn_trait_bound)]
use std::collections::BTreeMap;
--- /dev/null
+#![feature(const_trait_impl, const_mut_refs)]
+
+struct Foo<'a> {
+ bar: &'a mut Vec<usize>,
+}
+
+impl<'a> Foo<'a> {
+ const fn spam(&mut self, baz: &mut Vec<u32>) {
+ self.bar[0] = baz.len();
+ //~^ ERROR cannot call non-const fn `Vec::<u32>::len` in constant functions
+ //~| ERROR the trait bound `Vec<usize>: ~const IndexMut<usize>` is not satisfied
+ //~| ERROR cannot call non-const operator in constant functions
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0015]: cannot call non-const fn `Vec::<u32>::len` in constant functions
+ --> $DIR/issue-94675.rs:9:27
+ |
+LL | self.bar[0] = baz.len();
+ | ^^^^^
+ |
+ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error[E0277]: the trait bound `Vec<usize>: ~const IndexMut<usize>` is not satisfied
+ --> $DIR/issue-94675.rs:9:9
+ |
+LL | self.bar[0] = baz.len();
+ | ^^^^^^^^^^^ vector indices are of type `usize` or ranges of `usize`
+ |
+ = help: the trait `~const IndexMut<usize>` is not implemented for `Vec<usize>`
+note: the trait `IndexMut<usize>` is implemented for `Vec<usize>`, but that implementation is not `const`
+ --> $DIR/issue-94675.rs:9:9
+ |
+LL | self.bar[0] = baz.len();
+ | ^^^^^^^^^^^
+
+error[E0015]: cannot call non-const operator in constant functions
+ --> $DIR/issue-94675.rs:9:9
+ |
+LL | self.bar[0] = baz.len();
+ | ^^^^^^^^^^^
+ |
+note: impl defined here, but it is not `const`
+ --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+ |
+LL | impl<T, I: SliceIndex<[T]>, A: Allocator> IndexMut<I> for Vec<T, A> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0015, E0277.
+For more information about an error, try `rustc --explain E0015`.
+++ /dev/null
-#![feature(rustc_attrs, staged_api, rustc_allow_const_fn_unstable)]
-#![feature(const_fn_fn_ptr_basics)]
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_stable(since="1.0.0", feature = "mep")]
-const fn error(_: fn()) {}
-//~^ ERROR const-stable function cannot use `#[feature(const_fn_fn_ptr_basics)]`
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_stable(since="1.0.0", feature = "mep")]
-#[rustc_allow_const_fn_unstable(const_fn_fn_ptr_basics)]
-const fn compiles(_: fn()) {}
-
-fn main() {}
+++ /dev/null
-error: const-stable function cannot use `#[feature(const_fn_fn_ptr_basics)]`
- --> $DIR/allow_const_fn_ptr.rs:6:16
- |
-LL | const fn error(_: fn()) {}
- | ^
- |
-help: if it is not part of the public API, make this function unstably const
- |
-LL | #[rustc_const_unstable(feature = "...", issue = "...")]
- |
-help: otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks
- |
-LL | #[rustc_allow_const_fn_unstable(const_fn_fn_ptr_basics)]
- |
-
-error: aborting due to previous error
-
// run-pass
#![feature(rustc_allow_const_fn_unstable)]
-#![feature(const_fn_fn_ptr_basics)]
#![feature(rustc_attrs, staged_api)]
#![stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(since="1.0.0", feature = "mep")]
-#[rustc_allow_const_fn_unstable(const_fn_fn_ptr_basics)]
const fn takes_fn_ptr(_: fn()) {}
const FN: fn() = || ();
+++ /dev/null
-fn main() {}
-
-const fn unsize(x: &[u8; 3]) -> &[u8] { x }
-const fn closure() -> fn() { || {} }
-//~^ ERROR function pointer
-//~| ERROR function pointer cast
-const fn closure2() {
- (|| {}) as fn();
-//~^ ERROR function pointer
-}
-const fn reify(f: fn()) -> unsafe fn() { f }
-//~^ ERROR function pointer
-//~| ERROR function pointer
-//~| ERROR function pointer cast
-const fn reify2() { main as unsafe fn(); }
-//~^ ERROR function pointer
-//~| ERROR function pointer cast
+++ /dev/null
-error[E0658]: function pointers cannot appear in constant functions
- --> $DIR/cast_errors.rs:4:23
- |
-LL | const fn closure() -> fn() { || {} }
- | ^^^^
- |
- = 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[E0658]: function pointer casts are not allowed in constant functions
- --> $DIR/cast_errors.rs:4:30
- |
-LL | const fn closure() -> fn() { || {} }
- | ^^^^^
- |
- = 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[E0658]: function pointer casts are not allowed in constant functions
- --> $DIR/cast_errors.rs:8:5
- |
-LL | (|| {}) as fn();
- | ^^^^^^^
- |
- = 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[E0658]: function pointers cannot appear in constant functions
- --> $DIR/cast_errors.rs:11:16
- |
-LL | const fn reify(f: fn()) -> unsafe fn() { f }
- | ^
- |
- = 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[E0658]: function pointers cannot appear in constant functions
- --> $DIR/cast_errors.rs:11:28
- |
-LL | const fn reify(f: fn()) -> unsafe fn() { f }
- | ^^^^^^^^^^^
- |
- = 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[E0658]: function pointer casts are not allowed in constant functions
- --> $DIR/cast_errors.rs:11:42
- |
-LL | const fn reify(f: fn()) -> unsafe fn() { f }
- | ^
- |
- = 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[E0658]: function pointer casts are not allowed in constant functions
- --> $DIR/cast_errors.rs:15:21
- |
-LL | const fn reify2() { main as unsafe fn(); }
- | ^^^^
- |
- = 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[E0658]: function pointer casts are not allowed in constant functions
- --> $DIR/cast_errors.rs:15:21
- |
-LL | const fn reify2() { main as unsafe fn(); }
- | ^^^^
- |
- = 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 8 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// check-pass
+
+fn main() {}
+
+const fn unsize(x: &[u8; 3]) -> &[u8] { x }
+const fn closure() -> fn() { || {} }
+const fn closure2() {
+ (|| {}) as fn();
+}
+const fn reify(f: fn()) -> unsafe fn() { f }
+const fn reify2() { main as unsafe fn(); }
const fn cmp(x: fn(), y: fn()) -> bool {
- //~^ ERROR function pointer
- //~| ERROR function pointer
unsafe { x == y }
//~^ ERROR pointers cannot be reliably compared
}
-error[E0658]: function pointers cannot appear in constant functions
- --> $DIR/cmp_fn_pointers.rs:1:14
- |
-LL | const fn cmp(x: fn(), y: fn()) -> bool {
- | ^
- |
- = 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[E0658]: function pointers cannot appear in constant functions
- --> $DIR/cmp_fn_pointers.rs:1:23
- |
-LL | const fn cmp(x: fn(), y: fn()) -> bool {
- | ^
- |
- = 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: pointers cannot be reliably compared during const eval
- --> $DIR/cmp_fn_pointers.rs:4:14
+ --> $DIR/cmp_fn_pointers.rs:2:14
|
LL | unsafe { x == y }
| ^^^^^^
|
= note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
-error: aborting due to 3 previous errors
+error: aborting due to previous error
-For more information about this error, try `rustc --explain E0658`.
const unsafe fn ret_null_ptr_no_unsafe<T>() -> *const T { core::ptr::null() }
const unsafe fn ret_null_mut_ptr_no_unsafe<T>() -> *mut T { core::ptr::null_mut() }
-// not ok
const fn foo11<T: std::fmt::Display>(t: T) -> T { t }
-//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
const fn foo11_2<T: Send>(t: T) -> T { t }
-//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
+
+// not ok
static BAR: u32 = 42;
const fn foo25() -> u32 { BAR } //~ ERROR cannot refer to statics
fn main() {}
impl<T: std::fmt::Debug> Foo<T> {
-//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
const fn foo(&self) {}
}
impl<T: std::fmt::Debug + Sized> Foo<T> {
-//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
const fn foo2(&self) {}
}
impl<T: Sync + Sized> Foo<T> {
-//~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable
const fn foo3(&self) {}
}
struct AlanTuring<T>(T);
const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
-//~^ ERROR trait bounds other than `Sized`
-//~| ERROR destructor
+//~^ ERROR destructor
const fn no_apit(_x: impl std::fmt::Debug) {}
-//~^ ERROR trait bounds other than `Sized`
-//~| ERROR destructor
+//~^ ERROR destructor
const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {}
-//~^ ERROR trait objects in const fn are unstable
const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
-//~^ ERROR trait objects in const fn are unstable
const fn no_unsafe() { unsafe {} }
-const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
-//~^ ERROR trait objects in const fn are unstable
-//~| ERROR trait objects in const fn are unstable
-//~| ERROR trait objects in const fn are unstable
+const fn traits_are_ok_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
-const fn no_fn_ptrs(_x: fn()) {}
-//~^ ERROR function pointer
-const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
-//~^ ERROR function pointer
-//~| ERROR function pointer cast
+const fn fn_ptrs(_x: fn()) {}
+const fn fn_ptrs2() -> fn() { fn foo() {} foo }
= note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:84:16
- |
-LL | const fn foo11<T: std::fmt::Display>(t: T) -> T { t }
- | ^
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:86:18
- |
-LL | const fn foo11_2<T: Send>(t: T) -> T { t }
- | ^
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
error[E0013]: constant functions cannot refer to statics
- --> $DIR/min_const_fn.rs:90:27
+ --> $DIR/min_const_fn.rs:89:27
|
LL | const fn foo25() -> u32 { BAR }
| ^^^
= help: consider extracting the value of the `static` to a `const`, and referring to that
error[E0013]: constant functions cannot refer to statics
- --> $DIR/min_const_fn.rs:91:37
+ --> $DIR/min_const_fn.rs:90:37
|
LL | const fn foo26() -> &'static u32 { &BAR }
| ^^^
= help: consider extracting the value of the `static` to a `const`, and referring to that
error: pointers cannot be cast to integers during const eval
- --> $DIR/min_const_fn.rs:92:42
+ --> $DIR/min_const_fn.rs:91:42
|
LL | const fn foo30(x: *const u32) -> usize { x as usize }
| ^^^^^^^^^^
= note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
error: pointers cannot be cast to integers during const eval
- --> $DIR/min_const_fn.rs:94:63
+ --> $DIR/min_const_fn.rs:93:63
|
LL | const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } }
| ^^^^^^^^^^
= note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
error: pointers cannot be cast to integers during const eval
- --> $DIR/min_const_fn.rs:96:42
+ --> $DIR/min_const_fn.rs:95:42
|
LL | const fn foo30_2(x: *mut u32) -> usize { x as usize }
| ^^^^^^^^^^
= note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
error: pointers cannot be cast to integers during const eval
- --> $DIR/min_const_fn.rs:98:63
+ --> $DIR/min_const_fn.rs:97:63
|
LL | const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } }
| ^^^^^^^^^^
= note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
error[E0658]: mutable references are not allowed in constant functions
- --> $DIR/min_const_fn.rs:101:14
+ --> $DIR/min_const_fn.rs:100:14
|
LL | const fn inc(x: &mut i32) { *x += 1 }
| ^
= note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:110:6
- |
-LL | impl<T: std::fmt::Debug> Foo<T> {
- | ^
-LL |
-LL | const fn foo(&self) {}
- | ------------------- function declared as const here
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:115:6
- |
-LL | impl<T: std::fmt::Debug + Sized> Foo<T> {
- | ^
-LL |
-LL | const fn foo2(&self) {}
- | -------------------- function declared as const here
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:120:6
- |
-LL | impl<T: Sync + Sized> Foo<T> {
- | ^
-LL |
-LL | const fn foo3(&self) {}
- | -------------------- function declared as const here
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:126:34
- |
-LL | const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
- | ^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
error[E0493]: destructors cannot be evaluated at compile-time
- --> $DIR/min_const_fn.rs:126:19
+ --> $DIR/min_const_fn.rs:122:19
|
LL | const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
| ^^ - value is dropped here
| |
| constant functions cannot evaluate destructors
-error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:129:22
- |
-LL | const fn no_apit(_x: impl std::fmt::Debug) {}
- | ^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
error[E0493]: destructors cannot be evaluated at compile-time
- --> $DIR/min_const_fn.rs:129:18
+ --> $DIR/min_const_fn.rs:124:18
|
LL | const fn no_apit(_x: impl std::fmt::Debug) {}
| ^^ - value is dropped here
| |
| constant functions cannot evaluate destructors
-error[E0658]: trait objects in const fn are unstable
- --> $DIR/min_const_fn.rs:132:23
- |
-LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {}
- | ^^
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait objects in const fn are unstable
- --> $DIR/min_const_fn.rs:134:32
- |
-LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait objects in const fn are unstable
- --> $DIR/min_const_fn.rs:139:41
- |
-LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
- | ------------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- | |
- | function declared as const here
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait objects in const fn are unstable
- --> $DIR/min_const_fn.rs:139:42
- |
-LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
- | ------------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^
- | |
- | function declared as const here
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait objects in const fn are unstable
- --> $DIR/min_const_fn.rs:139:42
- |
-LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
- | ------------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^
- | |
- | function declared as const here
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: function pointers cannot appear in constant functions
- --> $DIR/min_const_fn.rs:144:21
- |
-LL | const fn no_fn_ptrs(_x: fn()) {}
- | ^^
- |
- = 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[E0658]: function pointers cannot appear in constant functions
- --> $DIR/min_const_fn.rs:146:27
- |
-LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
- | ^^^^
- |
- = 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[E0658]: function pointer casts are not allowed in constant functions
- --> $DIR/min_const_fn.rs:146:46
- |
-LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
- | ^^^
- |
- = 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 39 previous errors
+error: aborting due to 24 previous errors
Some errors have detailed explanations: E0013, E0493, E0658.
For more information about an error, try `rustc --explain E0013`.
+// check-pass
+
struct HasDyn {
field: &'static dyn std::fmt::Debug,
}
const fn no_inner_dyn_trait(_x: Hide) {}
const fn no_inner_dyn_trait2(x: Hide) {
x.0.field;
-//~^ ERROR trait objects in const fn are unstable
}
const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) }
-//~^ ERROR trait objects in const fn are unstable
fn main() {}
+++ /dev/null
-error[E0658]: trait objects in const fn are unstable
- --> $DIR/min_const_fn_dyn.rs:9:5
- |
-LL | const fn no_inner_dyn_trait2(x: Hide) {
- | ------------------------------------- function declared as const here
-LL | x.0.field;
- | ^^^^^^^^^
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error[E0658]: trait objects in const fn are unstable
- --> $DIR/min_const_fn_dyn.rs:12:66
- |
-LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) }
- | ----------------------------------------- ^^
- | |
- | function declared as const here
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
+++ /dev/null
-// gate-test-const_fn_fn_ptr_basics
-
-struct HasPtr {
- field: fn(),
-}
-
-struct Hide(HasPtr);
-
-fn field() {}
-
-const fn no_inner_dyn_trait(_x: Hide) {}
-const fn no_inner_dyn_trait2(x: Hide) {
- x.0.field;
-//~^ ERROR function pointer
-}
-const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasPtr { field }) }
-//~^ ERROR function pointer
-
-fn main() {}
+++ /dev/null
-error[E0658]: function pointers cannot appear in constant functions
- --> $DIR/min_const_fn_fn_ptr.rs:13:5
- |
-LL | x.0.field;
- | ^^^^^^^^^
- |
- = 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[E0658]: function pointer casts are not allowed in constant functions
- --> $DIR/min_const_fn_fn_ptr.rs:16:59
- |
-LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasPtr { field }) }
- | ^^^^^
- |
- = 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 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
+++ /dev/null
-// gate-test-const_impl_trait
-
-struct AlanTuring<T>(T);
-const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> { //~ `impl Trait`
- AlanTuring(0)
-}
-
-const fn no_rpit() -> impl std::fmt::Debug {} //~ `impl Trait`
-
-fn main() {}
+++ /dev/null
-error[E0658]: `impl Trait` is not allowed in constant functions
- --> $DIR/min_const_fn_impl_trait.rs:4:24
- |
-LL | const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #77463 <https://github.com/rust-lang/rust/issues/77463> for more information
- = help: add `#![feature(const_impl_trait)]` to the crate attributes to enable
-
-error[E0658]: `impl Trait` is not allowed in constant functions
- --> $DIR/min_const_fn_impl_trait.rs:8:23
- |
-LL | const fn no_rpit() -> impl std::fmt::Debug {}
- | ^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #77463 <https://github.com/rust-lang/rust/issues/77463> for more information
- = help: add `#![feature(const_impl_trait)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
// can't call non-min_const_fn
const fn bar() -> u32 { foo() } //~ ERROR not yet stable as a const fn
-#[unstable(feature = "rust1", issue = "none")]
+#[unstable(feature = "foo2", issue = "none")]
const fn foo2() -> u32 { 42 }
#[stable(feature = "rust1", since = "1.0.0")]
// can't call non-min_const_fn
const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR not yet stable as a const fn
-#[unstable(feature = "rust1", issue = "none")]
+#[unstable(feature = "foo2", issue = "none")]
const unsafe fn foo2() -> u32 { 42 }
#[stable(feature = "rust1", since = "1.0.0")]
// can't call non-min_const_fn
const unsafe fn bar() -> u32 { foo() } //~ ERROR not yet stable as a const fn
-#[unstable(feature = "rust1", issue = "none")]
+#[unstable(feature = "foo2", issue = "none")]
const fn foo2() -> u32 { 42 }
#[stable(feature = "rust1", since = "1.0.0")]
warning: skipping const checks
|
-help: skipping check for `const_fn_fn_ptr_basics` feature
- --> $DIR/abi-mismatch.rs:9:23
- |
-LL | const fn call_rust_fn(my_fn: extern "Rust" fn()) {
- | ^^^^^
-help: skipping check for `const_fn_fn_ptr_basics` feature
- --> $DIR/abi-mismatch.rs:10:5
- |
-LL | my_fn();
- | ^^^^^
help: skipping check that does not even have a feature gate
--> $DIR/abi-mismatch.rs:10:5
|
-#![feature(const_transmute)]
-
// normalize-stderr-64bit "64 bits" -> "word size"
// normalize-stderr-32bit "32 bits" -> "word size"
// normalize-stderr-64bit "128 bits" -> "2 * word size"
error: any use of this value will cause an error
- --> $DIR/transmute-size-mismatch-before-typeck.rs:15:29
+ --> $DIR/transmute-size-mismatch-before-typeck.rs:13:29
|
LL | const ZST: &[u8] = unsafe { std::mem::transmute(1usize) };
| ----------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^---
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
error: could not evaluate constant pattern
- --> $DIR/transmute-size-mismatch-before-typeck.rs:10:9
+ --> $DIR/transmute-size-mismatch-before-typeck.rs:8:9
|
LL | ZST => {}
| ^^^
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
- --> $DIR/transmute-size-mismatch-before-typeck.rs:15:29
+ --> $DIR/transmute-size-mismatch-before-typeck.rs:13:29
|
LL | const ZST: &[u8] = unsafe { std::mem::transmute(1usize) };
| ^^^^^^^^^^^^^^^^^^^
= note: target type: `&[u8]` (2 * word size)
error: could not evaluate constant pattern
- --> $DIR/transmute-size-mismatch-before-typeck.rs:10:9
+ --> $DIR/transmute-size-mismatch-before-typeck.rs:8:9
|
LL | ZST => {}
| ^^^
// gate was not enabled in libcore.
#![stable(feature = "core", since = "1.6.0")]
-#![feature(rustc_const_unstable)]
#![feature(staged_api)]
-#![feature(const_fn_trait_bound)]
enum Opt<T> {
Some(T),
error[E0015]: cannot call non-const closure in constant functions
- --> $DIR/unstable-const-fn-in-libcore.rs:24:26
+ --> $DIR/unstable-const-fn-in-libcore.rs:22:26
|
LL | Opt::None => f(),
| ^^^
| +++++++++++++++++++++++++++++
error[E0493]: destructors cannot be evaluated at compile-time
- --> $DIR/unstable-const-fn-in-libcore.rs:19:53
+ --> $DIR/unstable-const-fn-in-libcore.rs:17:53
|
LL | const fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
| ^ constant functions cannot evaluate destructors
| - value is dropped here
error[E0493]: destructors cannot be evaluated at compile-time
- --> $DIR/unstable-const-fn-in-libcore.rs:19:47
+ --> $DIR/unstable-const-fn-in-libcore.rs:17:47
|
LL | const fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
| ^^^^ constant functions cannot evaluate destructors
error[E0601]: `main` function not found in crate `continue_after_missing_main`
- --> $DIR/continue-after-missing-main.rs:1:1
+ --> $DIR/continue-after-missing-main.rs:30:2
|
-LL | / #![allow(dead_code)]
-LL | |
-LL | | struct Tableau<'a, MP> {
-LL | | provider: &'a MP,
-... |
-LL | |
-LL | | }
- | |_^ consider adding a `main` function to `$DIR/continue-after-missing-main.rs`
+LL | }
+ | ^ consider adding a `main` function to `$DIR/continue-after-missing-main.rs`
error: aborting due to previous error
-#![allow(dead_code)] //~ ERROR `main` function not found in crate
+#![allow(dead_code)]
struct Tableau<'a, MP> {
provider: &'a MP,
) {
let _: AdaptedMatrixProvider<'original_data, MP> = tableau.provider().clone_with_extra_bound();
//~^ ERROR lifetime mismatch
-}
+} //~ ERROR `main` function not found in crate
error[E0601]: `main` function not found in crate `continue_after_missing_main`
- --> $DIR/continue-after-missing-main.rs:1:1
+ --> $DIR/continue-after-missing-main.rs:30:2
|
-LL | / #![allow(dead_code)]
-LL | |
-LL | | struct Tableau<'a, MP> {
-LL | | provider: &'a MP,
-... |
-LL | |
-LL | | }
- | |_^ consider adding a `main` function to `$DIR/continue-after-missing-main.rs`
+LL | }
+ | ^ consider adding a `main` function to `$DIR/continue-after-missing-main.rs`
error[E0623]: lifetime mismatch
--> $DIR/continue-after-missing-main.rs:28:56
|
LL | #[deprecated]
| ^^^^^^^^^^^^^ use `#[rustc_deprecated]` instead
-LL | fn main() {}
- | ------------
error: aborting due to previous error
async fn foo() {
//~^ ERROR `async fn` is not permitted in Rust 2015
//~| NOTE to use `async fn`, switch to Rust 2018 or later
-//~| HELP set `edition = "2021"` in `Cargo.toml`
+//~| HELP pass `--edition 2021` to `rustc`
//~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
let x = async {};
let x = 42;
//~^ ERROR expected identifier, found keyword `let`
//~| NOTE expected identifier, found keyword
- //~| HELP set `edition = "2021"` in `Cargo.toml`
+ //~| HELP pass `--edition 2021` to `rustc`
//~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
42
};
42
//~^ ERROR expected identifier, found `42`
//~| NOTE expected identifier
- //~| HELP set `edition = "2021"` in `Cargo.toml`
+ //~| HELP pass `--edition 2021` to `rustc`
//~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
};
y.await;
LL | async fn foo() {
| ^^^^^ to use `async fn`, switch to Rust 2018 or later
|
- = help: set `edition = "2021"` in `Cargo.toml`
+ = help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error: expected identifier, found keyword `let`
LL | let x = 42;
| ^^^ expected identifier, found keyword
|
- = help: set `edition = "2021"` in `Cargo.toml`
+ = help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error: expected identifier, found `42`
LL | 42
| ^^ expected identifier
|
- = help: set `edition = "2021"` in `Cargo.toml`
+ = help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error[E0422]: cannot find struct, variant or union type `async` in this scope
error[E0601]: `main` function not found in crate `elided_test`
- --> $DIR/elided-test.rs:5:1
+ --> $DIR/elided-test.rs:7:2
|
-LL | / #[test]
-LL | | fn main() {
-LL | | }
- | |_^ consider adding a `main` function to `$DIR/elided-test.rs`
+LL | }
+ | ^ consider adding a `main` function to `$DIR/elided-test.rs`
error: aborting due to previous error
+#![feature(lint_reasons)]
+
#![deny(unused_attributes)]
#![allow()] //~ ERROR unused attribute
+#![expect()] //~ ERROR unused attribute
#![warn()] //~ ERROR unused attribute
#![deny()] //~ ERROR unused attribute
#![forbid()] //~ ERROR unused attribute
error: unused attribute
- --> $DIR/empty-attributes.rs:8:1
+ --> $DIR/empty-attributes.rs:11:1
|
LL | #[repr()]
| ^^^^^^^^^ help: remove this attribute
|
note: the lint level is defined here
- --> $DIR/empty-attributes.rs:1:9
+ --> $DIR/empty-attributes.rs:3:9
|
LL | #![deny(unused_attributes)]
| ^^^^^^^^^^^^^^^^^
= note: attribute `repr` with an empty list has no effect
error: unused attribute
- --> $DIR/empty-attributes.rs:11:1
+ --> $DIR/empty-attributes.rs:14:1
|
LL | #[target_feature()]
| ^^^^^^^^^^^^^^^^^^^ help: remove this attribute
= note: attribute `target_feature` with an empty list has no effect
error: unused attribute
- --> $DIR/empty-attributes.rs:2:1
+ --> $DIR/empty-attributes.rs:4:1
|
LL | #![allow()]
| ^^^^^^^^^^^ help: remove this attribute
= note: attribute `allow` with an empty list has no effect
error: unused attribute
- --> $DIR/empty-attributes.rs:3:1
+ --> $DIR/empty-attributes.rs:5:1
+ |
+LL | #![expect()]
+ | ^^^^^^^^^^^^ help: remove this attribute
+ |
+ = note: attribute `expect` with an empty list has no effect
+
+error: unused attribute
+ --> $DIR/empty-attributes.rs:6:1
|
LL | #![warn()]
| ^^^^^^^^^^ help: remove this attribute
= note: attribute `warn` with an empty list has no effect
error: unused attribute
- --> $DIR/empty-attributes.rs:4:1
+ --> $DIR/empty-attributes.rs:7:1
|
LL | #![deny()]
| ^^^^^^^^^^ help: remove this attribute
= note: attribute `deny` with an empty list has no effect
error: unused attribute
- --> $DIR/empty-attributes.rs:5:1
+ --> $DIR/empty-attributes.rs:8:1
|
LL | #![forbid()]
| ^^^^^^^^^^^^ help: remove this attribute
= note: attribute `forbid` with an empty list has no effect
error: unused attribute
- --> $DIR/empty-attributes.rs:6:1
+ --> $DIR/empty-attributes.rs:9:1
|
LL | #![feature()]
| ^^^^^^^^^^^^^ help: remove this attribute
|
= note: attribute `feature` with an empty list has no effect
-error: aborting due to 7 previous errors
+error: aborting due to 8 previous errors
error[E0005]: refutable pattern in local binding: `T(_, _)` not covered
--> $DIR/empty-never-array.rs:10:9
|
-LL | / enum Helper<T, U> {
-LL | | T(T, [!; 0]),
- | | - not covered
-LL | | #[allow(dead_code)]
-LL | | U(U),
-LL | | }
- | |_- `Helper<T, U>` defined here
-...
-LL | let Helper::U(u) = Helper::T(t, []);
- | ^^^^^^^^^^^^ pattern `T(_, _)` not covered
+LL | let Helper::U(u) = Helper::T(t, []);
+ | ^^^^^^^^^^^^ pattern `T(_, _)` not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Helper<T, U>` defined here
+ --> $DIR/empty-never-array.rs:4:5
+ |
+LL | enum Helper<T, U> {
+ | ------
+LL | T(T, [!; 0]),
+ | ^ not covered
= note: the matched value is of type `Helper<T, U>`
help: you might want to use `if let` to ignore the variant that isn't matched
|
#![feature(imported_main)]
#![feature(type_alias_impl_trait)]
#![allow(incomplete_features)]
-//~^^^ ERROR `main` function not found in crate
pub mod foo {
type MainFn = impl Fn();
//~^ ERROR could not find defining uses
//~^ ERROR mismatched types [E0308]
}
-use foo::BAR as main;
+use foo::BAR as main; //~ ERROR `main` function not found in crate
error[E0601]: `main` function not found in crate `imported_main_const_fn_item_type_forbidden`
- --> $DIR/imported_main_const_fn_item_type_forbidden.rs:1:1
+ --> $DIR/imported_main_const_fn_item_type_forbidden.rs:13:22
|
-LL | / #![feature(imported_main)]
-LL | | #![feature(type_alias_impl_trait)]
-LL | | #![allow(incomplete_features)]
-LL | |
-... |
-LL | |
-LL | | use foo::BAR as main;
- | |_____----------------^ consider adding a `main` function to `$DIR/imported_main_const_fn_item_type_forbidden.rs`
- | |
- | non-function item at `crate::main` is found
+LL | use foo::BAR as main;
+ | ---------------- ^ consider adding a `main` function to `$DIR/imported_main_const_fn_item_type_forbidden.rs`
+ | |
+ | non-function item at `crate::main` is found
error[E0308]: mismatched types
- --> $DIR/imported_main_const_fn_item_type_forbidden.rs:10:29
+ --> $DIR/imported_main_const_fn_item_type_forbidden.rs:9:29
|
LL | type MainFn = impl Fn();
| --------- the expected opaque type
found fn item `fn() {bar}`
error: could not find defining uses
- --> $DIR/imported_main_const_fn_item_type_forbidden.rs:6:19
+ --> $DIR/imported_main_const_fn_item_type_forbidden.rs:5:19
|
LL | type MainFn = impl Fn();
| ^^^^^^^^^
#![feature(imported_main)]
-//~^ ERROR `main` function not found in crate
pub mod foo {
pub const BAR: usize = 42;
}
-use foo::BAR as main;
+use foo::BAR as main; //~ ERROR `main` function not found in crate
error[E0601]: `main` function not found in crate `imported_main_const_forbidden`
- --> $DIR/imported_main_const_forbidden.rs:1:1
+ --> $DIR/imported_main_const_forbidden.rs:6:22
|
-LL | / #![feature(imported_main)]
-LL | |
-LL | | pub mod foo {
-LL | | pub const BAR: usize = 42;
-LL | | }
-LL | |
-LL | | use foo::BAR as main;
- | |_____----------------^ consider adding a `main` function to `$DIR/imported_main_const_forbidden.rs`
- | |
- | non-function item at `crate::main` is found
+LL | use foo::BAR as main;
+ | ---------------- ^ consider adding a `main` function to `$DIR/imported_main_const_forbidden.rs`
+ | |
+ | non-function item at `crate::main` is found
error: aborting due to previous error
LL | match x { }
| ^ patterns `None` and `Some(_)` not covered
|
- ::: $SRC_DIR/core/src/option.rs:LL:COL
+note: `Option<i32>` defined here
+ --> $SRC_DIR/core/src/option.rs:LL:COL
|
-LL | None,
- | ---- not covered
-...
-LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
- | ---- not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | / pub enum Option<T> {
+LL | | /// No value.
+LL | | #[lang = "None"]
+LL | | #[stable(feature = "rust1", since = "1.0.0")]
+LL | | None,
+ | | ^^^^ not covered
+... |
+LL | | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+ | | ^^^^ not covered
+LL | | }
+ | |_-
= note: the matched value is of type `Option<i32>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ match x {
+LL + None | Some(_) => todo!(),
+LL ~ }
+ |
error: aborting due to previous error
error[E0004]: non-exhaustive patterns: `HastaLaVistaBaby` not covered
--> $DIR/E0004.rs:9:11
|
-LL | / enum Terminator {
-LL | | HastaLaVistaBaby,
- | | ---------------- not covered
-LL | | TalkToMyHand,
-LL | | }
- | |_- `Terminator` defined here
-...
-LL | match x {
- | ^ pattern `HastaLaVistaBaby` not covered
+LL | match x {
+ | ^ pattern `HastaLaVistaBaby` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Terminator` defined here
+ --> $DIR/E0004.rs:2:5
+ |
+LL | enum Terminator {
+ | ----------
+LL | HastaLaVistaBaby,
+ | ^^^^^^^^^^^^^^^^ not covered
= note: the matched value is of type `Terminator`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ Terminator::TalkToMyHand => {}
+LL + HastaLaVistaBaby => todo!()
+ |
error: aborting due to previous error
LL | let Some(y) = x;
| ^^^^^^^ pattern `None` not covered
|
- ::: $SRC_DIR/core/src/option.rs:LL:COL
- |
-LL | None,
- | ---- not covered
- |
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Option<i32>` defined here
+ --> $SRC_DIR/core/src/option.rs:LL:COL
+ |
+LL | / pub enum Option<T> {
+LL | | /// No value.
+LL | | #[lang = "None"]
+LL | | #[stable(feature = "rust1", since = "1.0.0")]
+LL | | None,
+ | | ^^^^ not covered
+... |
+LL | | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+LL | | }
+ | |_-
= note: the matched value is of type `Option<i32>`
help: you might want to use `if let` to ignore the variant that isn't matched
|
LL | for Some(x) in xs {}
| ^^^^^^^ pattern `None` not covered
|
- ::: $SRC_DIR/core/src/option.rs:LL:COL
- |
-LL | None,
- | ---- not covered
+note: `Option<i32>` defined here
+ --> $SRC_DIR/core/src/option.rs:LL:COL
|
+LL | / pub enum Option<T> {
+LL | | /// No value.
+LL | | #[lang = "None"]
+LL | | #[stable(feature = "rust1", since = "1.0.0")]
+LL | | None,
+ | | ^^^^ not covered
+... |
+LL | | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+LL | | }
+ | |_-
= note: the matched value is of type `Option<i32>`
error: aborting due to previous error
// aux-build:pub-and-stability.rs
-#![feature(unused_feature)]
-
// A big point of this test is that we *declare* `unstable_declared`,
// but do *not* declare `unstable_undeclared`. This way we can check
// that the compiler is letting in uses of declared feature-gated
error[E0658]: use of unstable library feature 'unstable_undeclared'
- --> $DIR/explore-issue-38412.rs:21:63
+ --> $DIR/explore-issue-38412.rs:19:63
|
LL | let Record { a_stable_pub: _, a_unstable_declared_pub: _, a_unstable_undeclared_pub: _, .. } =
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: add `#![feature(unstable_undeclared)]` to the crate attributes to enable
error[E0658]: use of unstable library feature 'unstable_undeclared'
- --> $DIR/explore-issue-38412.rs:30:5
+ --> $DIR/explore-issue-38412.rs:28:5
|
LL | r.a_unstable_undeclared_pub;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: add `#![feature(unstable_undeclared)]` to the crate attributes to enable
error[E0616]: field `b_crate` of struct `Record` is private
- --> $DIR/explore-issue-38412.rs:31:7
+ --> $DIR/explore-issue-38412.rs:29:7
|
LL | r.b_crate;
| ^^^^^^^ private field
error[E0616]: field `c_mod` of struct `Record` is private
- --> $DIR/explore-issue-38412.rs:32:7
+ --> $DIR/explore-issue-38412.rs:30:7
|
LL | r.c_mod;
| ^^^^^ private field
error[E0616]: field `d_priv` of struct `Record` is private
- --> $DIR/explore-issue-38412.rs:33:7
+ --> $DIR/explore-issue-38412.rs:31:7
|
LL | r.d_priv;
| ^^^^^^ private field
error[E0658]: use of unstable library feature 'unstable_undeclared'
- --> $DIR/explore-issue-38412.rs:37:5
+ --> $DIR/explore-issue-38412.rs:35:5
|
LL | t.2;
| ^^^
= help: add `#![feature(unstable_undeclared)]` to the crate attributes to enable
error[E0616]: field `3` of struct `Tuple` is private
- --> $DIR/explore-issue-38412.rs:38:7
+ --> $DIR/explore-issue-38412.rs:36:7
|
LL | t.3;
| ^ private field
error[E0616]: field `4` of struct `Tuple` is private
- --> $DIR/explore-issue-38412.rs:39:7
+ --> $DIR/explore-issue-38412.rs:37:7
|
LL | t.4;
| ^ private field
error[E0616]: field `5` of struct `Tuple` is private
- --> $DIR/explore-issue-38412.rs:40:7
+ --> $DIR/explore-issue-38412.rs:38:7
|
LL | t.5;
| ^ private field
error[E0658]: use of unstable library feature 'unstable_undeclared'
- --> $DIR/explore-issue-38412.rs:44:7
+ --> $DIR/explore-issue-38412.rs:42:7
|
LL | r.unstable_undeclared_trait_method();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: add `#![feature(unstable_undeclared)]` to the crate attributes to enable
error[E0658]: use of unstable library feature 'unstable_undeclared'
- --> $DIR/explore-issue-38412.rs:48:7
+ --> $DIR/explore-issue-38412.rs:46:7
|
LL | r.unstable_undeclared();
| ^^^^^^^^^^^^^^^^^^^
= help: add `#![feature(unstable_undeclared)]` to the crate attributes to enable
error[E0624]: associated function `pub_crate` is private
- --> $DIR/explore-issue-38412.rs:50:7
+ --> $DIR/explore-issue-38412.rs:48:7
|
LL | r.pub_crate();
| ^^^^^^^^^ private associated function
| ------------------------------------- private associated function defined here
error[E0624]: associated function `pub_mod` is private
- --> $DIR/explore-issue-38412.rs:51:7
+ --> $DIR/explore-issue-38412.rs:49:7
|
LL | r.pub_mod();
| ^^^^^^^ private associated function
| ---------------------------------- private associated function defined here
error[E0624]: associated function `private` is private
- --> $DIR/explore-issue-38412.rs:52:7
+ --> $DIR/explore-issue-38412.rs:50:7
|
LL | r.private();
| ^^^^^^^ private associated function
| ------------------------ private associated function defined here
error[E0658]: use of unstable library feature 'unstable_undeclared'
- --> $DIR/explore-issue-38412.rs:57:7
+ --> $DIR/explore-issue-38412.rs:55:7
|
LL | t.unstable_undeclared_trait_method();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: add `#![feature(unstable_undeclared)]` to the crate attributes to enable
error[E0658]: use of unstable library feature 'unstable_undeclared'
- --> $DIR/explore-issue-38412.rs:61:7
+ --> $DIR/explore-issue-38412.rs:59:7
|
LL | t.unstable_undeclared();
| ^^^^^^^^^^^^^^^^^^^
= help: add `#![feature(unstable_undeclared)]` to the crate attributes to enable
error[E0624]: associated function `pub_crate` is private
- --> $DIR/explore-issue-38412.rs:63:7
+ --> $DIR/explore-issue-38412.rs:61:7
|
LL | t.pub_crate();
| ^^^^^^^^^ private associated function
| ------------------------------------- private associated function defined here
error[E0624]: associated function `pub_mod` is private
- --> $DIR/explore-issue-38412.rs:64:7
+ --> $DIR/explore-issue-38412.rs:62:7
|
LL | t.pub_mod();
| ^^^^^^^ private associated function
| ---------------------------------- private associated function defined here
error[E0624]: associated function `private` is private
- --> $DIR/explore-issue-38412.rs:65:7
+ --> $DIR/explore-issue-38412.rs:63:7
|
LL | t.private();
| ^^^^^^^ private associated function
LL | let Ok(_x) = foo();
| ^^^^^^ pattern `Err(_)` not covered
|
- ::: $SRC_DIR/core/src/result.rs:LL:COL
- |
-LL | Err(#[stable(feature = "rust1", since = "1.0.0")] E),
- | --- not covered
- |
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Result<u32, !>` defined here
+ --> $SRC_DIR/core/src/result.rs:LL:COL
+ |
+LL | / pub enum Result<T, E> {
+LL | | /// Contains the success value
+LL | | #[lang = "Ok"]
+LL | | #[stable(feature = "rust1", since = "1.0.0")]
+... |
+LL | | Err(#[stable(feature = "rust1", since = "1.0.0")] E),
+ | | ^^^ not covered
+LL | | }
+ | |_-
= note: the matched value is of type `Result<u32, !>`
help: you might want to use `if let` to ignore the variant that isn't matched
|
}
impl Bar for Foo {
- type Assoc where Self: Sized = Foo;
+ type Assoc = Foo where Self: Sized;
//~^ ERROR where clauses on associated types are unstable
}
error[E0658]: where clauses on associated types are unstable
--> $DIR/feature-gate-generic_associated_types.rs:27:5
|
-LL | type Assoc where Self: Sized = Foo;
+LL | type Assoc = Foo where Self: Sized;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
LL | match 0usize {
| ^^^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `usize`
= note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ 0..=usize::MAX => {}
+LL + _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/feature-gate-precise_pointer_size_matching.rs:10:11
LL | match 0isize {
| ^^^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `isize`
= note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ isize::MIN..=isize::MAX => {}
+LL + _ => todo!()
+ |
error: aborting due to 2 previous errors
#[rustc_variance] //~ ERROR the `#[rustc_variance]` attribute is just used for rustc unit tests and will never be stable
#[rustc_error] //~ ERROR the `#[rustc_error]` attribute is just used for rustc unit tests and will never be stable
-#[rustc_nonnull_optimization_guaranteed] //~ ERROR the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable niche optimizations in libcore and will never be stable
+#[rustc_nonnull_optimization_guaranteed] //~ ERROR the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable niche optimizations in libcore and libstd and will never be stable
fn main() {}
|
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
-error[E0658]: the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable niche optimizations in libcore and will never be stable
+error[E0658]: the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable niche optimizations in libcore and libstd and will never be stable
--> $DIR/feature-gate-rustc-attrs-1.rs:5:1
|
LL | #[rustc_nonnull_optimization_guaranteed]
-error[E0734]: stability attributes may not be used outside of the standard library
- --> $DIR/feature-gate-staged_api.rs:1:1
- |
-LL | #![stable(feature = "a", since = "b")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
error[E0734]: stability attributes may not be used outside of the standard library
--> $DIR/feature-gate-staged_api.rs:8:1
|
LL | #[stable(feature = "a", since = "b")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error[E0734]: stability attributes may not be used outside of the standard library
+ --> $DIR/feature-gate-staged_api.rs:1:1
+ |
+LL | #![stable(feature = "a", since = "b")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0734`.
#![feature(foo_bar_baz, foo(bar), foo = "baz", foo)]
//~^ ERROR malformed `feature`
//~| ERROR malformed `feature`
-
+//~| ERROR unknown feature `foo`
+//~| ERROR unknown feature `foo_bar_baz`
#![feature] //~ ERROR malformed `feature` attribute
#![feature = "foo"] //~ ERROR malformed `feature` attribute
-
#![feature(test_removed_feature)] //~ ERROR: feature has been removed
fn main() {}
| ^^^^^^^^^^^^^^^^^^^^ feature has been removed
error: malformed `feature` attribute input
- --> $DIR/gated-bad-feature.rs:5:1
+ --> $DIR/gated-bad-feature.rs:6:1
|
LL | #![feature]
| ^^^^^^^^^^^ help: must be of the form: `#![feature(name1, name2, ...)]`
error: malformed `feature` attribute input
- --> $DIR/gated-bad-feature.rs:6:1
+ --> $DIR/gated-bad-feature.rs:7:1
|
LL | #![feature = "foo"]
| ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![feature(name1, name2, ...)]`
-error: aborting due to 5 previous errors
+error[E0635]: unknown feature `foo_bar_baz`
+ --> $DIR/gated-bad-feature.rs:1:12
+ |
+LL | #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)]
+ | ^^^^^^^^^^^
+
+error[E0635]: unknown feature `foo`
+ --> $DIR/gated-bad-feature.rs:1:48
+ |
+LL | #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)]
+ | ^^^
+
+error: aborting due to 7 previous errors
-Some errors have detailed explanations: E0556, E0557.
+Some errors have detailed explanations: E0556, E0557, E0635.
For more information about an error, try `rustc --explain E0556`.
#![rustc_deprecated()]
//~^ ERROR stability attributes may not be used outside of the standard library
+//~| ERROR missing 'since' [E0542]
#[rustc_deprecated()]
//~^ ERROR stability attributes may not be used outside of the standard library
+//~| ERROR missing 'since' [E0542]
mod rustc_deprecated {
- mod inner { #![rustc_deprecated()] }
- //~^ ERROR stability attributes may not be used outside of the standard library
+ mod inner {
+ #![rustc_deprecated()]
+ //~^ ERROR stability attributes may not be used outside of the standard library
+ //~| ERROR missing 'since' [E0542]
+ }
- #[rustc_deprecated()] fn f() { }
+ #[rustc_deprecated()]
//~^ ERROR stability attributes may not be used outside of the standard library
+ //~| ERROR missing 'since' [E0542]
+ fn f() {}
- #[rustc_deprecated()] struct S;
+ #[rustc_deprecated()]
//~^ ERROR stability attributes may not be used outside of the standard library
- //~| ERROR stability attributes may not be used outside of the standard library
+ //~| ERROR missing 'since' [E0542]
+ //~| ERROR missing 'since' [E0542]
+ struct S;
- #[rustc_deprecated()] type T = S;
+ #[rustc_deprecated()]
//~^ ERROR stability attributes may not be used outside of the standard library
+ //~| ERROR missing 'since' [E0542]
+ type T = S;
- #[rustc_deprecated()] impl S { }
+ #[rustc_deprecated()]
//~^ ERROR stability attributes may not be used outside of the standard library
+ //~| ERROR missing 'since' [E0542]
+ impl S {}
}
fn main() {}
error[E0734]: stability attributes may not be used outside of the standard library
- --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:7:1
+ --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:16:9
|
-LL | #![rustc_deprecated()]
- | ^^^^^^^^^^^^^^^^^^^^^^
+LL | #![rustc_deprecated()]
+ | ^^^^^^^^^^^^^^^^^^^^^^
error[E0734]: stability attributes may not be used outside of the standard library
- --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:10:1
+ --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:21:5
|
-LL | #[rustc_deprecated()]
- | ^^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_deprecated()]
+ | ^^^^^^^^^^^^^^^^^^^^^
error[E0734]: stability attributes may not be used outside of the standard library
- --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:13:17
+ --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:26:5
|
-LL | mod inner { #![rustc_deprecated()] }
- | ^^^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_deprecated()]
+ | ^^^^^^^^^^^^^^^^^^^^^
error[E0734]: stability attributes may not be used outside of the standard library
- --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:16:5
+ --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:32:5
|
-LL | #[rustc_deprecated()] fn f() { }
+LL | #[rustc_deprecated()]
| ^^^^^^^^^^^^^^^^^^^^^
error[E0734]: stability attributes may not be used outside of the standard library
- --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:19:5
+ --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:37:5
|
-LL | #[rustc_deprecated()] struct S;
+LL | #[rustc_deprecated()]
| ^^^^^^^^^^^^^^^^^^^^^
error[E0734]: stability attributes may not be used outside of the standard library
- --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:19:5
+ --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:11:1
|
-LL | #[rustc_deprecated()] struct S;
- | ^^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_deprecated()]
+ | ^^^^^^^^^^^^^^^^^^^^^
error[E0734]: stability attributes may not be used outside of the standard library
- --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:23:5
+ --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:7:1
+ |
+LL | #![rustc_deprecated()]
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0542]: missing 'since'
+ --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:7:1
+ |
+LL | #![rustc_deprecated()]
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0542]: missing 'since'
+ --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:11:1
+ |
+LL | #[rustc_deprecated()]
+ | ^^^^^^^^^^^^^^^^^^^^^
+
+error[E0542]: missing 'since'
+ --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:16:9
+ |
+LL | #![rustc_deprecated()]
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0542]: missing 'since'
+ --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:21:5
|
-LL | #[rustc_deprecated()] type T = S;
+LL | #[rustc_deprecated()]
| ^^^^^^^^^^^^^^^^^^^^^
-error[E0734]: stability attributes may not be used outside of the standard library
+error[E0542]: missing 'since'
--> $DIR/issue-43106-gating-of-rustc_deprecated.rs:26:5
|
-LL | #[rustc_deprecated()] impl S { }
+LL | #[rustc_deprecated()]
+ | ^^^^^^^^^^^^^^^^^^^^^
+
+error[E0542]: missing 'since'
+ --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:26:5
+ |
+LL | #[rustc_deprecated()]
+ | ^^^^^^^^^^^^^^^^^^^^^
+
+error[E0542]: missing 'since'
+ --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:32:5
+ |
+LL | #[rustc_deprecated()]
+ | ^^^^^^^^^^^^^^^^^^^^^
+
+error[E0542]: missing 'since'
+ --> $DIR/issue-43106-gating-of-rustc_deprecated.rs:37:5
+ |
+LL | #[rustc_deprecated()]
| ^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 8 previous errors
+error: aborting due to 15 previous errors
-For more information about this error, try `rustc --explain E0734`.
+Some errors have detailed explanations: E0542, E0734.
+For more information about an error, try `rustc --explain E0542`.
#[stable()]
//~^ ERROR stability attributes may not be used outside of the standard library
mod stable {
- mod inner { #![stable()] }
- //~^ ERROR stability attributes may not be used outside of the standard library
+ mod inner {
+ #![stable()]
+ //~^ ERROR stability attributes may not be used outside of the standard library
+ }
- #[stable()] fn f() { }
+ #[stable()]
//~^ ERROR stability attributes may not be used outside of the standard library
+ fn f() {}
- #[stable()] struct S;
+ #[stable()]
//~^ ERROR stability attributes may not be used outside of the standard library
- //~| ERROR stability attributes may not be used outside of the standard library
+ struct S;
- #[stable()] type T = S;
+ #[stable()]
//~^ ERROR stability attributes may not be used outside of the standard library
+ type T = S;
- #[stable()] impl S { }
+ #[stable()]
//~^ ERROR stability attributes may not be used outside of the standard library
+ impl S {}
}
fn main() {}
error[E0734]: stability attributes may not be used outside of the standard library
- --> $DIR/issue-43106-gating-of-stable.rs:7:1
- |
-LL | #![stable()]
- | ^^^^^^^^^^^^
-
-error[E0734]: stability attributes may not be used outside of the standard library
- --> $DIR/issue-43106-gating-of-stable.rs:10:1
+ --> $DIR/issue-43106-gating-of-stable.rs:14:9
|
-LL | #[stable()]
- | ^^^^^^^^^^^
+LL | #![stable()]
+ | ^^^^^^^^^^^^
error[E0734]: stability attributes may not be used outside of the standard library
- --> $DIR/issue-43106-gating-of-stable.rs:13:17
+ --> $DIR/issue-43106-gating-of-stable.rs:18:5
|
-LL | mod inner { #![stable()] }
- | ^^^^^^^^^^^^
+LL | #[stable()]
+ | ^^^^^^^^^^^
error[E0734]: stability attributes may not be used outside of the standard library
- --> $DIR/issue-43106-gating-of-stable.rs:16:5
+ --> $DIR/issue-43106-gating-of-stable.rs:22:5
|
-LL | #[stable()] fn f() { }
+LL | #[stable()]
| ^^^^^^^^^^^
error[E0734]: stability attributes may not be used outside of the standard library
- --> $DIR/issue-43106-gating-of-stable.rs:19:5
+ --> $DIR/issue-43106-gating-of-stable.rs:26:5
|
-LL | #[stable()] struct S;
+LL | #[stable()]
| ^^^^^^^^^^^
error[E0734]: stability attributes may not be used outside of the standard library
- --> $DIR/issue-43106-gating-of-stable.rs:19:5
+ --> $DIR/issue-43106-gating-of-stable.rs:30:5
|
-LL | #[stable()] struct S;
+LL | #[stable()]
| ^^^^^^^^^^^
error[E0734]: stability attributes may not be used outside of the standard library
- --> $DIR/issue-43106-gating-of-stable.rs:23:5
+ --> $DIR/issue-43106-gating-of-stable.rs:10:1
|
-LL | #[stable()] type T = S;
- | ^^^^^^^^^^^
+LL | #[stable()]
+ | ^^^^^^^^^^^
error[E0734]: stability attributes may not be used outside of the standard library
- --> $DIR/issue-43106-gating-of-stable.rs:26:5
+ --> $DIR/issue-43106-gating-of-stable.rs:7:1
|
-LL | #[stable()] impl S { }
- | ^^^^^^^^^^^
+LL | #![stable()]
+ | ^^^^^^^^^^^^
-error: aborting due to 8 previous errors
+error: aborting due to 7 previous errors
For more information about this error, try `rustc --explain E0734`.
#[unstable()]
//~^ ERROR stability attributes may not be used outside of the standard library
mod unstable {
- mod inner { #![unstable()] }
- //~^ ERROR stability attributes may not be used outside of the standard library
+ mod inner {
+ #![unstable()]
+ //~^ ERROR stability attributes may not be used outside of the standard library
+ }
- #[unstable()] fn f() { }
+ #[unstable()]
//~^ ERROR stability attributes may not be used outside of the standard library
+ fn f() {}
- #[unstable()] struct S;
+ #[unstable()]
//~^ ERROR stability attributes may not be used outside of the standard library
- //~| ERROR stability attributes may not be used outside of the standard library
+ struct S;
- #[unstable()] type T = S;
+ #[unstable()]
//~^ ERROR stability attributes may not be used outside of the standard library
+ type T = S;
- #[unstable()] impl S { }
+ #[unstable()]
//~^ ERROR stability attributes may not be used outside of the standard library
+ impl S {}
}
fn main() {}
error[E0734]: stability attributes may not be used outside of the standard library
- --> $DIR/issue-43106-gating-of-unstable.rs:7:1
- |
-LL | #![unstable()]
- | ^^^^^^^^^^^^^^
-
-error[E0734]: stability attributes may not be used outside of the standard library
- --> $DIR/issue-43106-gating-of-unstable.rs:10:1
+ --> $DIR/issue-43106-gating-of-unstable.rs:14:9
|
-LL | #[unstable()]
- | ^^^^^^^^^^^^^
+LL | #![unstable()]
+ | ^^^^^^^^^^^^^^
error[E0734]: stability attributes may not be used outside of the standard library
- --> $DIR/issue-43106-gating-of-unstable.rs:13:17
+ --> $DIR/issue-43106-gating-of-unstable.rs:18:5
|
-LL | mod inner { #![unstable()] }
- | ^^^^^^^^^^^^^^
+LL | #[unstable()]
+ | ^^^^^^^^^^^^^
error[E0734]: stability attributes may not be used outside of the standard library
- --> $DIR/issue-43106-gating-of-unstable.rs:16:5
+ --> $DIR/issue-43106-gating-of-unstable.rs:22:5
|
-LL | #[unstable()] fn f() { }
+LL | #[unstable()]
| ^^^^^^^^^^^^^
error[E0734]: stability attributes may not be used outside of the standard library
- --> $DIR/issue-43106-gating-of-unstable.rs:19:5
+ --> $DIR/issue-43106-gating-of-unstable.rs:26:5
|
-LL | #[unstable()] struct S;
+LL | #[unstable()]
| ^^^^^^^^^^^^^
error[E0734]: stability attributes may not be used outside of the standard library
- --> $DIR/issue-43106-gating-of-unstable.rs:19:5
+ --> $DIR/issue-43106-gating-of-unstable.rs:30:5
|
-LL | #[unstable()] struct S;
+LL | #[unstable()]
| ^^^^^^^^^^^^^
error[E0734]: stability attributes may not be used outside of the standard library
- --> $DIR/issue-43106-gating-of-unstable.rs:23:5
+ --> $DIR/issue-43106-gating-of-unstable.rs:10:1
|
-LL | #[unstable()] type T = S;
- | ^^^^^^^^^^^^^
+LL | #[unstable()]
+ | ^^^^^^^^^^^^^
error[E0734]: stability attributes may not be used outside of the standard library
- --> $DIR/issue-43106-gating-of-unstable.rs:26:5
+ --> $DIR/issue-43106-gating-of-unstable.rs:7:1
|
-LL | #[unstable()] impl S { }
- | ^^^^^^^^^^^^^
+LL | #![unstable()]
+ | ^^^^^^^^^^^^^^
-error: aborting due to 8 previous errors
+error: aborting due to 7 previous errors
For more information about this error, try `rustc --explain E0734`.
// build-pass
// compile-flags: -Zdrop-tracking
-// FIXME(eholk): temporarily disabled while drop range tracking is disabled
-// (see generator_interior.rs:27)
-// ignore-test
-
// A test to ensure generators capture values that were conditionally dropped,
// and also that values that are dropped along all paths to a yield do not get
// included in the generator type.
-#![feature(generators, generator_trait, box_leak)]
+#![feature(generators, generator_trait)]
use std::cell::RefCell;
use std::ops::Generator;
// check-pass
-
-// FIXME(eholk): temporarily disabled while drop range tracking is disabled
-// (see generator_interior.rs:27)
-// ignore-test
+// compile-flags: -Zdrop-tracking
#![feature(negative_impls, generators)]
-// FIXME(eholk): temporarily disabled while drop range tracking is disabled
-// (see generator_interior.rs:27)
-// ignore-test
+// compile-flags: -Zdrop-tracking
#![feature(negative_impls, generators)]
error: generator cannot be sent between threads safely
- --> $DIR/partial-drop.rs:12:5
+ --> $DIR/partial-drop.rs:14:5
|
LL | assert_send(|| {
| ^^^^^^^^^^^ generator is not `Send`
|
- = help: within `[generator@$DIR/partial-drop.rs:12:17: 18:6]`, the trait `Send` is not implemented for `Foo`
+ = help: within `[generator@$DIR/partial-drop.rs:14:17: 20:6]`, the trait `Send` is not implemented for `Foo`
note: generator is not `Send` as this value is used across a yield
- --> $DIR/partial-drop.rs:17:9
+ --> $DIR/partial-drop.rs:19:9
|
LL | let guard = Bar { foo: Foo, x: 42 };
| ----- has type `Bar` which is not `Send`
LL | });
| - `guard` is later dropped here
note: required by a bound in `assert_send`
- --> $DIR/partial-drop.rs:40:19
+ --> $DIR/partial-drop.rs:42:19
|
LL | fn assert_send<T: Send>(_: T) {}
| ^^^^ required by this bound in `assert_send`
error: generator cannot be sent between threads safely
- --> $DIR/partial-drop.rs:20:5
+ --> $DIR/partial-drop.rs:22:5
|
LL | assert_send(|| {
| ^^^^^^^^^^^ generator is not `Send`
|
- = help: within `[generator@$DIR/partial-drop.rs:20:17: 28:6]`, the trait `Send` is not implemented for `Foo`
+ = help: within `[generator@$DIR/partial-drop.rs:22:17: 30:6]`, the trait `Send` is not implemented for `Foo`
note: generator is not `Send` as this value is used across a yield
- --> $DIR/partial-drop.rs:27:9
+ --> $DIR/partial-drop.rs:29:9
|
LL | let guard = Bar { foo: Foo, x: 42 };
| ----- has type `Bar` which is not `Send`
LL | });
| - `guard` is later dropped here
note: required by a bound in `assert_send`
- --> $DIR/partial-drop.rs:40:19
+ --> $DIR/partial-drop.rs:42:19
|
LL | fn assert_send<T: Send>(_: T) {}
| ^^^^ required by this bound in `assert_send`
error: generator cannot be sent between threads safely
- --> $DIR/partial-drop.rs:30:5
+ --> $DIR/partial-drop.rs:32:5
|
LL | assert_send(|| {
| ^^^^^^^^^^^ generator is not `Send`
|
- = help: within `[generator@$DIR/partial-drop.rs:30:17: 37:6]`, the trait `Send` is not implemented for `Foo`
+ = help: within `[generator@$DIR/partial-drop.rs:32:17: 39:6]`, the trait `Send` is not implemented for `Foo`
note: generator is not `Send` as this value is used across a yield
- --> $DIR/partial-drop.rs:36:9
+ --> $DIR/partial-drop.rs:38:9
|
LL | let guard = Bar { foo: Foo, x: 42 };
| ----- has type `Bar` which is not `Send`
LL | });
| - `guard` is later dropped here
note: required by a bound in `assert_send`
- --> $DIR/partial-drop.rs:40:19
+ --> $DIR/partial-drop.rs:42:19
|
LL | fn assert_send<T: Send>(_: T) {}
| ^^^^ required by this bound in `assert_send`
}
impl<T> AsRef2 for Vec<T> {
- type Output<'a> where Self: 'a = &'a [T];
+ type Output<'a> = &'a [T] where Self: 'a;
fn as_ref2<'a>(&'a self) -> Self::Output<'a> {
&self[..]
T: AsRef2<Output<'b> = &'b [U]>,
U: 'b
{
- type Output<'a> where Self: 'a = FooRef<'a, U>;
+ type Output<'a> = FooRef<'a, U> where Self: 'a;
fn as_ref2<'a>(&'a self) -> Self::Output<'a> {
FooRef(self.0.as_ref2())
struct Foo;
impl MyTrait for Foo {
- type Assoc<'a, 'b> where 'b: 'a = u32;
+ type Assoc<'a, 'b> = u32 where 'b: 'a;
fn do_sth(_: u32) {}
// fn do_sth(_: Self::Assoc<'static, 'static>) {}
}
impl<T> Collection<T> for Vec<T> {
- type Iter<'iter> where T: 'iter = std::slice::Iter<'iter, T>;
+ type Iter<'iter> = std::slice::Iter<'iter, T> where T: 'iter;
type Family = VecFamily;
fn empty() -> Self {
}
impl<T> Collection<T> for Vec<T> {
- type Iter<'iter> where T: 'iter = std::slice::Iter<'iter, T>;
+ type Iter<'iter> = std::slice::Iter<'iter, T> where T: 'iter;
type Family = VecFamily;
fn empty() -> Self {
}
impl<T> Baz for T where T: Foo {
- type Quux<'a> where T: 'a = T;
+ type Quux<'a> = T where T: 'a;
- type Baa<'a> where T: 'a = &'a <T as Foo>::Bar<'a, 'static>;
+ type Baa<'a> = &'a <T as Foo>::Bar<'a, 'static> where T: 'a;
}
fn main() {}
struct Fooer<T>(T);
impl<T> Foo for Fooer<T> {
- type A<'x> where T: 'x = &'x ();
+ type A<'x> = &'x () where T: 'x;
}
fn f(_arg : Box<dyn for<'a> Foo<A<'a> = &'a ()>>) {}
type Assoc = usize;
type Assoc2<T> = Vec<T>;
//~^ ERROR `T` doesn't implement `std::fmt::Display`
- type Assoc3<T> where T: Iterator = Vec<T>;
+ type Assoc3<T> = Vec<T> where T: Iterator;
//~^ ERROR impl has stricter requirements than trait
type WithDefault<'a, T: Debug + 'a> = &'a dyn Iterator<Item=T>;
type NoGenerics = ::std::cell::Cell<i32>;
LL | type Assoc3<T>;
| --------------- definition of `Assoc3` from trait
...
-LL | type Assoc3<T> where T: Iterator = Vec<T>;
+LL | type Assoc3<T> = Vec<T> where T: Iterator;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: Iterator`
error: aborting due to 2 previous errors
struct Fooy<T>(T);
impl<T> Foo for Fooy<T> {
- type A<'a> where Self: 'static = (&'a ());
+ type A<'a> = (&'a ()) where Self: 'static;
//~^ ERROR `impl` associated type
- type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
+ type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a;
//~^ ERROR `impl` associated type
//~| ERROR lifetime bound not satisfied
- type C where Self: Copy = String;
+ type C = String where Self: Copy;
//~^ ERROR the trait bound `T: Copy` is not satisfied
fn d() where Self: Copy {}
//~^ ERROR the trait bound `T: Copy` is not satisfied
LL | type A<'a> where Self: 'a;
| -------------------------- expected
...
-LL | type A<'a> where Self: 'static = (&'a ());
+LL | type A<'a> = (&'a ()) where Self: 'static;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found
error: `impl` associated type signature for `B` doesn't match `trait` associated type signature
LL | type B<'a, 'b> where 'a: 'b;
| ---------------------------- expected
...
-LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
+LL | type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found
error[E0478]: lifetime bound not satisfied
- --> $DIR/impl_bounds.rs:17:35
+ --> $DIR/impl_bounds.rs:17:22
|
LL | type B<'a, 'b> where 'a: 'b;
| ---------------------------- definition of `B` from trait
...
-LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
- | - ^^^^^^^^^^^^^^^
- | |
- | help: try copying this clause from the trait: `, 'a: 'b`
+LL | type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a;
+ | ^^^^^^^^^^^^^^^ - help: try copying this clause from the trait: `, 'a: 'b`
|
note: lifetime parameter instantiated with the lifetime `'a` as defined here
--> $DIR/impl_bounds.rs:17:12
|
-LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
+LL | type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a;
| ^^
note: but lifetime parameter must outlive the lifetime `'b` as defined here
--> $DIR/impl_bounds.rs:17:16
|
-LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
+LL | type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a;
| ^^
error[E0277]: the trait bound `T: Copy` is not satisfied
--> $DIR/impl_bounds.rs:20:5
|
-LL | type C where Self: Copy = String;
+LL | type C = String where Self: Copy;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T`
|
note: required because of the requirements on the impl of `Copy` for `Fooy<T>`
struct Fooer<T>(T);
impl<T> Foo for Fooer<T> {
- type A<'x> where T: 'x = (&'x ());
- type B<'u, 'v> where 'u: 'v = (&'v &'u ());
- type C where Self: Clone + ToOwned = String;
+ type A<'x> = (&'x ()) where T: 'x;
+ type B<'u, 'v> = (&'v &'u ()) where 'u: 'v;
+ type C = String where Self: Clone + ToOwned;
}
fn main() {}
struct Bar;
impl Foo for Bar {
- type Assoc3<T> where T: Iterator = Vec<T>;
+ type Assoc3<T> = Vec<T> where T: Iterator;
//~^ ERROR impl has stricter requirements than trait
}
LL | type Assoc3<T>;
| --------------- definition of `Assoc3` from trait
...
-LL | type Assoc3<T> where T: Iterator = Vec<T>;
+LL | type Assoc3<T> = Vec<T> where T: Iterator;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: Iterator`
error: aborting due to previous error
}
impl<T> Iter for Windows<T> {
- type Item<'a> where T: 'a = &'a mut [T];
+ type Item<'a> = &'a mut [T] where T: 'a;
fn next<'a>(&'a mut self) -> Option<Self::Item<'a>> {
let slice = self.items.get_mut(self.start..self.start + self.len)?;
}
impl<K: Ord, V: 'static> MapLike<K, V> for std::collections::BTreeMap<K, V> {
- type VRefCont<'a> where Self: 'a = &'a V;
+ type VRefCont<'a> = &'a V where Self: 'a;
fn get<'a>(&'a self, key: &K) -> Option<&'a V> {
std::collections::BTreeMap::get(self, key)
}
--> $DIR/issue-84931.rs:15:21
|
LL | type Item<'a> = &'a mut T;
- | - ^^^^^^^^^ ...so that the reference type `&'a mut T` does not outlive the data it points at
- | |
- | help: consider adding a where clause: `where T: 'a`
+ | ^^^^^^^^^- help: consider adding a where clause: `where T: 'a`
+ | |
+ | ...so that the reference type `&'a mut T` does not outlive the data it points at
error: aborting due to previous error
Right: HasChildrenOf,
{
type T = Either<Left::T, Right::T>;
- // We used to error below because the where clause doesn't match the trait.
- // Now, we error early on the trait itself.
- type TRef<'a>
+ type TRef<'a> = Either<&'a Left::T, &'a Right::T>
where
- <Left as HasChildrenOf>::T: 'a,
- <Right as HasChildrenOf>::T: 'a
- = Either<&'a Left::T, &'a Right::T>;
+ <Left as HasChildrenOf>::T: 'a,
+ <Right as HasChildrenOf>::T: 'a;
fn ref_children<'a>(&'a self) -> Vec<Self::TRef<'a>> {
todo!()
where
T: SearchableResource<Criteria>,
{
- type Future<'f, A, B: 'f>
+ type Future<'f, A, B: 'f> = SearchFutureTy<'f, A, B>
where
A: SearchableResource<B> + ?Sized + 'f,
- Self: 'f,
- = SearchFutureTy<'f, A, B>;
+ Self: 'f;
fn search<'c>(&'c self, _client: &'c ()) -> Self::Future<'c, Self, Criteria> {
async move { todo!() }
| ---------------------------- definition of `Fut` from trait
...
LL | type Fut<'a> = impl Future<Output = ()>;
- | - ^^^^^^^^^^^^^^^^^^^^^^^^
- | |
- | help: try copying this clause from the trait: `where Self: 'a`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^- help: try copying this clause from the trait: `where Self: 'a`
|
note: type must outlive the lifetime `'a` as defined here
--> $DIR/issue-90014.rs:14:14
--- /dev/null
+// check-pass
+
+#![feature(generic_associated_types)]
+
+use std::marker::PhantomData;
+
+pub trait Type {
+ type Ref<'a>;
+}
+
+pub trait AsBytes {}
+
+impl AsBytes for &str {}
+
+pub struct Utf8;
+
+impl Type for Utf8 {
+ type Ref<'a> = &'a str;
+}
+
+pub struct Bytes<T: Type> {
+ _marker: PhantomData<T>,
+}
+
+impl<T: Type> Bytes<T>
+where
+ for<'a> T::Ref<'a>: AsBytes,
+{
+ pub fn new() -> Self {
+ Self {
+ _marker: PhantomData,
+ }
+ }
+}
+
+fn main() {
+ let _b = Bytes::<Utf8>::new();
+}
--- /dev/null
+error[E0311]: the parameter type `T` may not live long enough
+ --> $DIR/issue-91139.rs:27:12
+ |
+LL | fn foo<T>() {
+ | - help: consider adding an explicit lifetime bound...: `T: 'a`
+LL | let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+
+error: aborting due to previous error
+
-// check-pass
+// revisions: migrate nll
+//[nll]compile-flags: -Z borrowck=mir
+
+// Since we are testing nll (and migration) explicitly as a separate
+// revisions, don't worry about the --compare-mode=nll on this test.
+
+// ignore-compare-mode-nll
+
+//[nll] check-pass
+//[migrate] check-fail
#![feature(generic_associated_types)]
}
impl<T> Foo<T> for () {
- type Type<'a>
+ type Type<'a> = ()
where
- T: 'a,
- = ();
+ T: 'a;
}
fn foo<T>() {
let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
+ //[migrate]~^ the parameter type `T` may not live long enough
}
pub fn main() {}
| |_________________- definition of `TextureIter` from trait
...
LL | type TextureIter<'a> = std::option::IntoIter<&'a Texture>;
- | - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- | |
- | help: try copying this clause from the trait: `where Self: 'a`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: try copying this clause from the trait: `where Self: 'a`
|
note: type must outlive the lifetime `'a` as defined here
--> $DIR/issue-92033.rs:22:22
key: T,
}
impl<S: HasAssoc> Iterate<S> for KeySegment_Broken<S::Assoc> {
- type Iter<'a>
+ type Iter<'a> = ()
where
- Self: 'a,
- = ();
+ Self: 'a;
}
fn main() {}
--- /dev/null
+// check-pass
+
+#![feature(generic_associated_types)]
+use std::marker::PhantomData;
+
+pub struct Id<'id>(PhantomData<fn(&'id ()) -> &'id ()>);
+
+fn new_id() -> Id<'static> {
+ Id(PhantomData)
+}
+
+pub trait HasLifetime where {
+ type AtLifetime<'a>;
+}
+
+pub struct ExistentialLifetime<S: HasLifetime>(S::AtLifetime<'static>);
+
+impl<S: HasLifetime> ExistentialLifetime<S> {
+ pub fn new<F>(f: F) -> ExistentialLifetime<S>
+ where for<'id> F: FnOnce(Id<'id>) -> S::AtLifetime<'id> {
+ ExistentialLifetime(f(new_id()))
+ }
+}
+
+
+struct ExampleS<'id>(Id<'id>);
+
+struct ExampleMarker;
+
+impl HasLifetime for ExampleMarker {
+ type AtLifetime<'id> = ExampleS<'id>;
+}
+
+
+fn broken0() -> ExistentialLifetime<ExampleMarker> {
+ fn new_helper<'id>(id: Id<'id>) -> ExampleS<'id> {
+ ExampleS(id)
+ }
+
+ ExistentialLifetime::<ExampleMarker>::new(new_helper)
+}
+
+fn broken1() -> ExistentialLifetime<ExampleMarker> {
+ fn new_helper<'id>(id: Id<'id>) -> <ExampleMarker as HasLifetime>::AtLifetime<'id> {
+ ExampleS(id)
+ }
+
+ ExistentialLifetime::<ExampleMarker>::new(new_helper)
+}
+
+fn broken2() -> ExistentialLifetime<ExampleMarker> {
+ ExistentialLifetime::<ExampleMarker>::new(|id| ExampleS(id))
+}
+
+fn main() {}
--- /dev/null
+// check-pass
+
+#![feature(generic_associated_types)]
+
+use std::marker::PhantomData;
+
+pub trait Scalar: 'static {
+ type RefType<'a>: ScalarRef<'a>;
+}
+
+pub trait ScalarRef<'a>: 'a {}
+
+impl Scalar for i32 {
+ type RefType<'a> = i32;
+}
+
+impl Scalar for String {
+ type RefType<'a> = &'a str;
+}
+
+impl Scalar for bool {
+ type RefType<'a> = i32;
+}
+
+impl<'a> ScalarRef<'a> for bool {}
+
+impl<'a> ScalarRef<'a> for i32 {}
+
+impl<'a> ScalarRef<'a> for &'a str {}
+
+fn str_contains(a: &str, b: &str) -> bool {
+ a.contains(b)
+}
+
+pub struct BinaryExpression<A: Scalar, B: Scalar, O: Scalar, F>
+where
+ F: Fn(A::RefType<'_>, B::RefType<'_>) -> O,
+{
+ f: F,
+ _phantom: PhantomData<(A, B, O)>,
+}
+
+impl<A: Scalar, B: Scalar, O: Scalar, F> BinaryExpression<A, B, O, F>
+where
+ F: Fn(A::RefType<'_>, B::RefType<'_>) -> O,
+{
+ pub fn new(f: F) -> Self {
+ Self {
+ f,
+ _phantom: PhantomData,
+ }
+ }
+}
+
+fn main() {
+ BinaryExpression::<String, String, bool, _>::new(str_contains);
+}
// Impl for struct type
impl<T> Iterable for Vec<T> {
- type Item<'a> where T: 'a = <std::slice::Iter<'a, T> as Iterator>::Item;
- type Iter<'a> where T: 'a = std::slice::Iter<'a, T>;
+ type Item<'a> = <std::slice::Iter<'a, T> as Iterator>::Item where T: 'a;
+ type Iter<'a> = std::slice::Iter<'a, T> where T: 'a;
fn iter<'a>(&'a self) -> Self::Iter<'a> {
self[..].iter()
// Impl for a primitive type
impl<T> Iterable for [T] {
- type Item<'a> where T: 'a = <std::slice::Iter<'a, T> as Iterator>::Item;
- type Iter<'a> where T: 'a = std::slice::Iter<'a, T>;
+ type Item<'a> = <std::slice::Iter<'a, T> as Iterator>::Item where T: 'a;
+ type Iter<'a> = std::slice::Iter<'a, T> where T: 'a;
fn iter<'a>(&'a self) -> Self::Iter<'a> {
self.iter()
type Assoc<'a, 'b>;
}
impl Foo for () {
- type Assoc<'a, 'b> where 'a: 'b = ();
+ type Assoc<'a, 'b> = () where 'a: 'b;
//~^ `impl` associated type
}
LL | type Assoc<'a, 'b>;
| ------------------- expected
...
-LL | type Assoc<'a, 'b> where 'a: 'b = ();
+LL | type Assoc<'a, 'b> = () where 'a: 'b;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found
error: aborting due to previous error
// }
// ```
// which it is :)
- type Item where [T]: Sized = [T];
+ type Item = [T] where [T]: Sized;
}
struct OnlySized<T> where T: Sized { f: T }
// }
// ```
// which it is :)
- type Item where str: Sized = str;
+ type Item = str where str: Sized;
}
struct OnlySized<T> where T: Sized { f: T }
}
impl<I: StreamingIterator> StreamingIterator for StreamEnumerate<I> {
- type Item<'a> where Self: 'a = (usize, I::Item<'a>);
+ type Item<'a> = (usize, I::Item<'a>) where Self: 'a;
fn next<'a>(&'a mut self) -> Option<Self::Item<'a>> {
match self.iter.next() {
None => None,
}
impl<I: Iterator> StreamingIterator for I {
- type Item<'a> where Self: 'a = <I as Iterator>::Item;
+ type Item<'a> = <I as Iterator>::Item where Self: 'a;
fn next(&mut self) -> Option<<I as StreamingIterator>::Item<'_>> {
Iterator::next(self)
}
LL | m!(0f32, f32::NEG_INFINITY..);
| ^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `f32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ _ => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:17:8
LL | m!(0f32, ..f32::INFINITY);
| ^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `f32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ _ => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `'\u{10ffff}'` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:26:8
LL | m!('a', ..core::char::MAX);
| ^^^ pattern `'\u{10ffff}'` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `char`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ '\u{10ffff}' => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `'\u{10fffe}'..='\u{10ffff}'` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:27:8
LL | m!('a', ..ALMOST_MAX);
| ^^^ pattern `'\u{10fffe}'..='\u{10ffff}'` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `char`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ '\u{10fffe}'..='\u{10ffff}' => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `'\u{0}'` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:28:8
LL | m!('a', ALMOST_MIN..);
| ^^^ pattern `'\u{0}'` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `char`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ '\u{0}' => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `'\u{10ffff}'` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:29:8
LL | m!('a', ..=ALMOST_MAX);
| ^^^ pattern `'\u{10ffff}'` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `char`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ '\u{10ffff}' => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `'b'` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:30:8
LL | m!('a', ..=VAL | VAL_2..);
| ^^^ pattern `'b'` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `char`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 'b' => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `'b'` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:31:8
LL | m!('a', ..VAL_1 | VAL_2..);
| ^^^ pattern `'b'` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `char`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 'b' => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:41:12
LL | m!(0, ..u8::MAX);
| ^ pattern `u8::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ u8::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `254_u8..=u8::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:42:12
LL | m!(0, ..ALMOST_MAX);
| ^ pattern `254_u8..=u8::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 254_u8..=u8::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `0_u8` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:43:12
LL | m!(0, ALMOST_MIN..);
| ^ pattern `0_u8` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 0_u8 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:44:12
LL | m!(0, ..=ALMOST_MAX);
| ^ pattern `u8::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ u8::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_u8` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:45:12
LL | m!(0, ..=VAL | VAL_2..);
| ^ pattern `43_u8` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_u8 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_u8` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:46:12
LL | m!(0, ..VAL_1 | VAL_2..);
| ^ pattern `43_u8` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_u8 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `u16::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:54:12
LL | m!(0, ..u16::MAX);
| ^ pattern `u16::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ u16::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `65534_u16..=u16::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:55:12
LL | m!(0, ..ALMOST_MAX);
| ^ pattern `65534_u16..=u16::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 65534_u16..=u16::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `0_u16` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:56:12
LL | m!(0, ALMOST_MIN..);
| ^ pattern `0_u16` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 0_u16 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `u16::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:57:12
LL | m!(0, ..=ALMOST_MAX);
| ^ pattern `u16::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ u16::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_u16` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:58:12
LL | m!(0, ..=VAL | VAL_2..);
| ^ pattern `43_u16` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_u16 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_u16` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:59:12
LL | m!(0, ..VAL_1 | VAL_2..);
| ^ pattern `43_u16` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_u16 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `u32::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:67:12
LL | m!(0, ..u32::MAX);
| ^ pattern `u32::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ u32::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `4294967294_u32..=u32::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:68:12
LL | m!(0, ..ALMOST_MAX);
| ^ pattern `4294967294_u32..=u32::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 4294967294_u32..=u32::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `0_u32` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:69:12
LL | m!(0, ALMOST_MIN..);
| ^ pattern `0_u32` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 0_u32 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `u32::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:70:12
LL | m!(0, ..=ALMOST_MAX);
| ^ pattern `u32::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ u32::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_u32` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:71:12
LL | m!(0, ..=VAL | VAL_2..);
| ^ pattern `43_u32` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_u32 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_u32` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:72:12
LL | m!(0, ..VAL_1 | VAL_2..);
| ^ pattern `43_u32` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_u32 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `u64::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:80:12
LL | m!(0, ..u64::MAX);
| ^ pattern `u64::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ u64::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `18446744073709551614_u64..=u64::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:81:12
LL | m!(0, ..ALMOST_MAX);
| ^ pattern `18446744073709551614_u64..=u64::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 18446744073709551614_u64..=u64::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `0_u64` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:82:12
LL | m!(0, ALMOST_MIN..);
| ^ pattern `0_u64` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 0_u64 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `u64::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:83:12
LL | m!(0, ..=ALMOST_MAX);
| ^ pattern `u64::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ u64::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_u64` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:84:12
LL | m!(0, ..=VAL | VAL_2..);
| ^ pattern `43_u64` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_u64 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_u64` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:85:12
LL | m!(0, ..VAL_1 | VAL_2..);
| ^ pattern `43_u64` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_u64 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `u128::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:93:12
LL | m!(0, ..u128::MAX);
| ^ pattern `u128::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ u128::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `340282366920938463463374607431768211454_u128..=u128::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:94:12
LL | m!(0, ..ALMOST_MAX);
| ^ pattern `340282366920938463463374607431768211454_u128..=u128::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 340282366920938463463374607431768211454_u128..=u128::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `0_u128` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:95:12
LL | m!(0, ALMOST_MIN..);
| ^ pattern `0_u128` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 0_u128 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `u128::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:96:12
LL | m!(0, ..=ALMOST_MAX);
| ^ pattern `u128::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ u128::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_u128` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:97:12
LL | m!(0, ..=VAL | VAL_2..);
| ^ pattern `43_u128` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_u128 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_u128` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:98:12
LL | m!(0, ..VAL_1 | VAL_2..);
| ^ pattern `43_u128` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_u128 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:109:12
LL | m!(0, ..i8::MAX);
| ^ pattern `i8::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i8::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `126_i8..=i8::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:110:12
LL | m!(0, ..ALMOST_MAX);
| ^ pattern `126_i8..=i8::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 126_i8..=i8::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i8::MIN` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:111:12
LL | m!(0, ALMOST_MIN..);
| ^ pattern `i8::MIN` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i8::MIN => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:112:12
LL | m!(0, ..=ALMOST_MAX);
| ^ pattern `i8::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i8::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_i8` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:113:12
LL | m!(0, ..=VAL | VAL_2..);
| ^ pattern `43_i8` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_i8 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_i8` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:114:12
LL | m!(0, ..VAL_1 | VAL_2..);
| ^ pattern `43_i8` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_i8 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i16::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:122:12
LL | m!(0, ..i16::MAX);
| ^ pattern `i16::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i16::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `32766_i16..=i16::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:123:12
LL | m!(0, ..ALMOST_MAX);
| ^ pattern `32766_i16..=i16::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 32766_i16..=i16::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i16::MIN` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:124:12
LL | m!(0, ALMOST_MIN..);
| ^ pattern `i16::MIN` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i16::MIN => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i16::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:125:12
LL | m!(0, ..=ALMOST_MAX);
| ^ pattern `i16::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i16::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_i16` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:126:12
LL | m!(0, ..=VAL | VAL_2..);
| ^ pattern `43_i16` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_i16 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_i16` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:127:12
LL | m!(0, ..VAL_1 | VAL_2..);
| ^ pattern `43_i16` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_i16 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i32::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:135:12
LL | m!(0, ..i32::MAX);
| ^ pattern `i32::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i32::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `2147483646_i32..=i32::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:136:12
LL | m!(0, ..ALMOST_MAX);
| ^ pattern `2147483646_i32..=i32::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 2147483646_i32..=i32::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i32::MIN` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:137:12
LL | m!(0, ALMOST_MIN..);
| ^ pattern `i32::MIN` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i32::MIN => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i32::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:138:12
LL | m!(0, ..=ALMOST_MAX);
| ^ pattern `i32::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i32::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_i32` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:139:12
LL | m!(0, ..=VAL | VAL_2..);
| ^ pattern `43_i32` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_i32 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_i32` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:140:12
LL | m!(0, ..VAL_1 | VAL_2..);
| ^ pattern `43_i32` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_i32 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i64::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:148:12
LL | m!(0, ..i64::MAX);
| ^ pattern `i64::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i64::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `9223372036854775806_i64..=i64::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:149:12
LL | m!(0, ..ALMOST_MAX);
| ^ pattern `9223372036854775806_i64..=i64::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 9223372036854775806_i64..=i64::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i64::MIN` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:150:12
LL | m!(0, ALMOST_MIN..);
| ^ pattern `i64::MIN` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i64::MIN => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i64::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:151:12
LL | m!(0, ..=ALMOST_MAX);
| ^ pattern `i64::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i64::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_i64` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:152:12
LL | m!(0, ..=VAL | VAL_2..);
| ^ pattern `43_i64` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_i64 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_i64` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:153:12
LL | m!(0, ..VAL_1 | VAL_2..);
| ^ pattern `43_i64` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_i64 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i128::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:161:12
LL | m!(0, ..i128::MAX);
| ^ pattern `i128::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i128::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `170141183460469231731687303715884105726_i128..=i128::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:162:12
LL | m!(0, ..ALMOST_MAX);
| ^ pattern `170141183460469231731687303715884105726_i128..=i128::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 170141183460469231731687303715884105726_i128..=i128::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i128::MIN` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:163:12
LL | m!(0, ALMOST_MIN..);
| ^ pattern `i128::MIN` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i128::MIN => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i128::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:164:12
LL | m!(0, ..=ALMOST_MAX);
| ^ pattern `i128::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i128::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_i128` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:165:12
LL | m!(0, ..=VAL | VAL_2..);
| ^ pattern `43_i128` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_i128 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `43_i128` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:166:12
LL | m!(0, ..VAL_1 | VAL_2..);
| ^ pattern `43_i128` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 43_i128 => todo!() }
+ |
error: aborting due to 68 previous errors
+// check-pass
+
// FamilyType (GAT workaround)
pub trait FamilyLt<'a> {
type Out;
fn main() {
task(annotate(
- //~^ the size
- //~^^ the trait bound
Annotate::<RefMutFamily<usize>>::new(),
|value: &mut usize| {
*value = 2;
+++ /dev/null
-error[E0277]: the size for values of type `impl Execute` cannot be known at compilation time
- --> $DIR/issue-62529-1.rs:80:10
- |
-LL | task(annotate(
- | _____----_^
- | | |
- | | required by a bound introduced by this call
-LL | |
-LL | |
-LL | | Annotate::<RefMutFamily<usize>>::new(),
-... |
-LL | | }
-LL | | ));
- | |_____^ doesn't have a size known at compile-time
- |
- = help: the trait `Sized` is not implemented for `impl Execute`
-note: required by a bound in `task`
- --> $DIR/issue-62529-1.rs:69:9
- |
-LL | fn task<P>(processor: P) -> Task
- | ^ required by this bound in `task`
-help: consider relaxing the implicit `Sized` restriction
- |
-LL | fn task<P: ?Sized>(processor: P) -> Task
- | ++++++++
-
-error[E0277]: the trait bound `impl Execute: Execute` is not satisfied
- --> $DIR/issue-62529-1.rs:80:10
- |
-LL | task(annotate(
- | _____----_^
- | | |
- | | required by a bound introduced by this call
-LL | |
-LL | |
-LL | | Annotate::<RefMutFamily<usize>>::new(),
-... |
-LL | | }
-LL | | ));
- | |_____^ the trait `Execute` is not implemented for `impl Execute`
- |
-note: required by a bound in `task`
- --> $DIR/issue-62529-1.rs:70:10
- |
-LL | fn task<P>(processor: P) -> Task
- | ---- required by a bound in this
-LL | where P: Execute + 'static {
- | ^^^^^^^ required by this bound in `task`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:57:5
+ --> $DIR/issue-71955.rs:54:5
|
LL | foo(bar, "string", |s| s.len() == 5);
| ^^^ implementation of `Parser` is not general enough
= note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:57:5
- |
-LL | foo(bar, "string", |s| s.len() == 5);
- | ^^^ implementation of `Parser` is not general enough
- |
- = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
- = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
-
-error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:57:5
- |
-LL | foo(bar, "string", |s| s.len() == 5);
- | ^^^ implementation of `Parser` is not general enough
- |
- = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
- = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
-
-error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:57:5
- |
-LL | foo(bar, "string", |s| s.len() == 5);
- | ^^^ implementation of `Parser` is not general enough
- |
- = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
- = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
-
-error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:57:5
- |
-LL | foo(bar, "string", |s| s.len() == 5);
- | ^^^ implementation of `Parser` is not general enough
- |
- = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
- = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
-
-error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:63:5
- |
-LL | foo(baz, "string", |s| s.0.len() == 5);
- | ^^^ implementation of `Parser` is not general enough
- |
- = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
- = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
-
-error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:63:5
- |
-LL | foo(baz, "string", |s| s.0.len() == 5);
- | ^^^ implementation of `Parser` is not general enough
- |
- = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
- = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
-
-error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:63:5
- |
-LL | foo(baz, "string", |s| s.0.len() == 5);
- | ^^^ implementation of `Parser` is not general enough
- |
- = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
- = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
-
-error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:63:5
- |
-LL | foo(baz, "string", |s| s.0.len() == 5);
- | ^^^ implementation of `Parser` is not general enough
- |
- = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
- = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
-
-error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:63:5
+ --> $DIR/issue-71955.rs:58:5
|
LL | foo(baz, "string", |s| s.0.len() == 5);
| ^^^ implementation of `Parser` is not general enough
= note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
= note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
-error: aborting due to 10 previous errors
+error: aborting due to 2 previous errors
-error: fatal error triggered by #[rustc_error]
- --> $DIR/issue-71955.rs:47:1
+error[E0308]: mismatched types
+ --> $DIR/issue-71955.rs:54:5
|
-LL | fn main() {
- | ^^^^^^^^^
+LL | foo(bar, "string", |s| s.len() == 5);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+ |
+ = note: expected type `for<'r, 's> FnOnce<(&'r &'s str,)>`
+ found type `for<'r> FnOnce<(&'r &str,)>`
+note: this closure does not fulfill the lifetime requirements
+ --> $DIR/issue-71955.rs:54:24
+ |
+LL | foo(bar, "string", |s| s.len() == 5);
+ | ^^^^^^^^^^^^^^^^
+note: the lifetime requirement is introduced here
+ --> $DIR/issue-71955.rs:34:9
+ |
+LL | F2: FnOnce(&<F1 as Parser>::Output) -> bool
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/issue-71955.rs:54:5
+ |
+LL | foo(bar, "string", |s| s.len() == 5);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+ |
+ = note: expected type `FnOnce<(&&str,)>`
+ found type `for<'r> FnOnce<(&'r &str,)>`
+note: this closure does not fulfill the lifetime requirements
+ --> $DIR/issue-71955.rs:54:24
+ |
+LL | foo(bar, "string", |s| s.len() == 5);
+ | ^^^^^^^^^^^^^^^^
+note: the lifetime requirement is introduced here
+ --> $DIR/issue-71955.rs:34:44
+ |
+LL | F2: FnOnce(&<F1 as Parser>::Output) -> bool
+ | ^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/issue-71955.rs:58:5
+ |
+LL | foo(baz, "string", |s| s.0.len() == 5);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+ |
+ = note: expected type `for<'r, 's> FnOnce<(&'r Wrapper<'s>,)>`
+ found type `for<'r> FnOnce<(&'r Wrapper<'_>,)>`
+note: this closure does not fulfill the lifetime requirements
+ --> $DIR/issue-71955.rs:58:24
+ |
+LL | foo(baz, "string", |s| s.0.len() == 5);
+ | ^^^^^^^^^^^^^^^^^^
+note: the lifetime requirement is introduced here
+ --> $DIR/issue-71955.rs:34:9
+ |
+LL | F2: FnOnce(&<F1 as Parser>::Output) -> bool
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/issue-71955.rs:58:5
+ |
+LL | foo(baz, "string", |s| s.0.len() == 5);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+ |
+ = note: expected type `FnOnce<(&Wrapper<'_>,)>`
+ found type `for<'r> FnOnce<(&'r Wrapper<'_>,)>`
+note: this closure does not fulfill the lifetime requirements
+ --> $DIR/issue-71955.rs:58:24
+ |
+LL | foo(baz, "string", |s| s.0.len() == 5);
+ | ^^^^^^^^^^^^^^^^^^
+note: the lifetime requirement is introduced here
+ --> $DIR/issue-71955.rs:34:44
+ |
+LL | F2: FnOnce(&<F1 as Parser>::Output) -> bool
+ | ^^^^
-error: aborting due to previous error
+error: aborting due to 4 previous errors
+For more information about this error, try `rustc --explain E0308`.
struct Wrapper<'a>(&'a str);
-// Because nll currently succeeds and migrate doesn't
-#[rustc_error]
fn main() {
- //[nll]~^ fatal
fn bar<'a>(s: &'a str) -> (&'a str, &'a str) {
(&s[..1], &s[..])
}
foo(bar, "string", |s| s.len() == 5);
//[migrate]~^ ERROR implementation of `Parser` is not general enough
- //[migrate]~| ERROR implementation of `Parser` is not general enough
- //[migrate]~| ERROR implementation of `Parser` is not general enough
- //[migrate]~| ERROR implementation of `Parser` is not general enough
- //[migrate]~| ERROR implementation of `Parser` is not general enough
+ //[nll]~^^ ERROR mismatched types
+ //[nll]~| ERROR mismatched types
foo(baz, "string", |s| s.0.len() == 5);
//[migrate]~^ ERROR implementation of `Parser` is not general enough
- //[migrate]~| ERROR implementation of `Parser` is not general enough
- //[migrate]~| ERROR implementation of `Parser` is not general enough
- //[migrate]~| ERROR implementation of `Parser` is not general enough
- //[migrate]~| ERROR implementation of `Parser` is not general enough
+ //[nll]~^^ ERROR mismatched types
+ //[nll]~| ERROR mismatched types
}
fn give_me_ice<T>() {
callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>();
- //~^ ERROR: the trait bound `T: SomeTrait<'_>` is not satisfied
+ //~^ ERROR the trait bound `T: SomeTrait<'_>` is not satisfied [E0277]
+ //~| ERROR the trait bound `T: SomeTrait<'_>` is not satisfied [E0277]
}
fn callee<T: Fn<(&'static (),)>>() {
LL | fn give_me_ice<T: SomeTrait<'_>>() {
| +++++++++++++++
-error: aborting due to previous error
+error[E0277]: the trait bound `T: SomeTrait<'_>` is not satisfied
+ --> $DIR/issue-85455.rs:8:14
+ |
+LL | callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `SomeTrait<'_>` is not implemented for `T`
+ |
+help: consider restricting type parameter `T`
+ |
+LL | fn give_me_ice<T: SomeTrait<'_>>() {
+ | +++++++++++++++
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.
| |
| `async` blocks are only allowed in Rust 2018 or later
|
- = help: set `edition = "2021"` in `Cargo.toml`
+ = help: pass `--edition 2021` to `rustc`
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding
-#![feature(universal_impl_trait)]
-
use std::fmt::Debug;
fn foo<T>(x: impl Debug) { }
error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position
- --> $DIR/universal-issue-48703.rs:8:11
+ --> $DIR/universal-issue-48703.rs:6:11
|
LL | foo::<String>('a');
| ^^^^^^ explicit generic argument not allowed
-#![feature(question_mark, question_mark_carrier)]
-
// Test that type inference fails where there are multiple possible return types
// for the `?` operator.
error[E0284]: type annotations needed
- --> $DIR/question-mark-type-infer.rs:12:21
+ --> $DIR/question-mark-type-infer.rs:10:21
|
LL | l.iter().map(f).collect()?
| ^^^^^^^ cannot infer type
#[rustc_legacy_const_generics(0)] //~ ERROR #[rustc_legacy_const_generics] functions must only have
fn foo8<X>() {}
+impl S {
+ #[rustc_legacy_const_generics(0)] //~ ERROR attribute should be applied to a function
+ fn foo9<const X: usize>() {}
+}
+
#[rustc_legacy_const_generics] //~ ERROR malformed `rustc_legacy_const_generics` attribute
fn bar1() {}
= help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
error: malformed `rustc_legacy_const_generics` attribute input
- --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:32:1
+ --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:37:1
|
LL | #[rustc_legacy_const_generics]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_legacy_const_generics(N)]`
error: malformed `rustc_legacy_const_generics` attribute input
- --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:35:1
+ --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:40:1
|
LL | #[rustc_legacy_const_generics = 1]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_legacy_const_generics(N)]`
LL | fn foo8<X>() {}
| - non-const generic parameter
+error: attribute should be applied to a function
+ --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:33:5
+ |
+LL | #[rustc_legacy_const_generics(0)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn foo9<const X: usize>() {}
+ | ---------------------------- not a function
+
error: attribute should be applied to a function
--> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:25:5
|
|
= help: replace the const parameters with concrete consts
-error: aborting due to 12 previous errors
+error: aborting due to 13 previous errors
For more information about this error, try `rustc --explain E0044`.
error[E0015]: cannot call non-const fn `Y::foo` in statics
- --> $DIR/issue-16538.rs:15:23
+ --> $DIR/issue-16538.rs:14:23
|
LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
error[E0133]: use of extern static is unsafe and requires unsafe function or block
- --> $DIR/issue-16538.rs:15:30
+ --> $DIR/issue-16538.rs:14:30
|
LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X);
| ^^^^ 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[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
- --> $DIR/issue-16538.rs:15:21
+ --> $DIR/issue-16538.rs:14:21
|
LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereference of raw pointer
// revisions: mir thir
// [thir]compile-flags: -Z thir-unsafeck
-#![feature(const_raw_ptr_deref)]
mod Y {
pub type X = usize;
extern "C" {
error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
- --> $DIR/issue-16538.rs:15:22
+ --> $DIR/issue-16538.rs:14:22
|
LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereference of raw pointer
= note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
error[E0133]: use of extern static is unsafe and requires unsafe function or block
- --> $DIR/issue-16538.rs:15:30
+ --> $DIR/issue-16538.rs:14:30
|
LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X);
| ^^^^ 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[E0015]: cannot call non-const fn `Y::foo` in statics
- --> $DIR/issue-16538.rs:15:23
+ --> $DIR/issue-16538.rs:14:23
|
LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-#![feature(associated_consts)]
-
trait Foo {
const BAR: i32;
fn foo(self) -> &'static i32 {
error[E0277]: the size for values of type `Self` cannot be known at compilation time
- --> $DIR/issue-27078.rs:5:12
+ --> $DIR/issue-27078.rs:3:12
|
LL | fn foo(self) -> &'static i32 {
| ^^^^ doesn't have a size known at compile-time
-#![feature(associated_consts)]
-
trait VecN {
const DIM: usize;
}
error: constant expression depends on a generic parameter
- --> $DIR/issue-39211.rs:11:17
+ --> $DIR/issue-39211.rs:9:17
|
LL | let a = [3; M::Row::DIM];
| ^^^^^^^^^^^
-#![feature(use_extern_macros)]
trait Foo {}
#[derive(Foo::Anything)] //~ ERROR failed to resolve: partially resolved path in a derive macro
//~| ERROR failed to resolve: partially resolved path in a derive macro
error[E0433]: failed to resolve: partially resolved path in a derive macro
- --> $DIR/issue-46101.rs:3:10
+ --> $DIR/issue-46101.rs:2:10
|
LL | #[derive(Foo::Anything)]
| ^^^^^^^^^^^^^ partially resolved path in a derive macro
error[E0433]: failed to resolve: partially resolved path in a derive macro
- --> $DIR/issue-46101.rs:3:10
+ --> $DIR/issue-46101.rs:2:10
|
LL | #[derive(Foo::Anything)]
| ^^^^^^^^^^^^^ partially resolved path in a derive macro
+// check-fail
+// known-bug
+
// Regression test for #47511: anonymous lifetimes can appear
// unconstrained in a return type, but only if they appear just once
// in the input, as the input to a projection.
fn f(_: X) -> X {
- //~^ ERROR return type references an anonymous lifetime
unimplemented!()
}
fn g<'a>(_: X<'a>) -> X<'a> {
- //~^ ERROR return type references lifetime `'a`, which is not constrained
unimplemented!()
}
error[E0581]: return type references an anonymous lifetime, which is not constrained by the fn input types
- --> $DIR/issue-47511.rs:5:15
+ --> $DIR/issue-47511.rs:8:15
|
LL | fn f(_: X) -> X {
| ^
= note: lifetimes appearing in an associated type are not considered constrained
error[E0581]: return type references lifetime `'a`, which is not constrained by the fn input types
- --> $DIR/issue-47511.rs:10:23
+ --> $DIR/issue-47511.rs:12:23
|
LL | fn g<'a>(_: X<'a>) -> X<'a> {
| ^^^^^
-#![feature(macro_rules)]
-
macro_rules! g {
($inp:ident) => (
{ $inp $nonexistent }
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `$`
- --> $DIR/issue-6596-2.rs:5:16
+ --> $DIR/issue-6596-2.rs:3:16
|
LL | { $inp $nonexistent }
| ^^^^^^^^^^^^ expected one of 8 possible tokens
error: lifetime may not live long enough
- --> $DIR/issue-75777.rs:13:5
+ --> $DIR/issue-75777.rs:11:5
|
LL | fn inject<'a, Env: 'a, A: 'a + Send>(v: A) -> Box<dyn FnOnce(&'a Env) -> BoxFuture<'a, A>> {
| -- lifetime `'a` defined here
// Regression test for #75777.
// Checks that a boxed future can be properly constructed.
-#![feature(future_readiness_fns)]
-
use std::future::{self, Future};
use std::pin::Pin;
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
- --> $DIR/issue-75777.rs:13:14
+ --> $DIR/issue-75777.rs:11:14
|
LL | Box::new(move |_| fut)
| ^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
- --> $DIR/issue-75777.rs:11:11
+ --> $DIR/issue-75777.rs:9:11
|
LL | fn inject<'a, Env: 'a, A: 'a + Send>(v: A) -> Box<dyn FnOnce(&'a Env) -> BoxFuture<'a, A>> {
| ^^
note: ...so that the types are compatible
- --> $DIR/issue-75777.rs:13:14
+ --> $DIR/issue-75777.rs:11:14
|
LL | Box::new(move |_| fut)
| ^^^^^^^^^^^^
found `(Pin<Box<(dyn Future<Output = A> + Send + 'a)>>,)`
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the types are compatible
- --> $DIR/issue-75777.rs:13:5
+ --> $DIR/issue-75777.rs:11:5
|
LL | Box::new(move |_| fut)
| ^^^^^^^^^^^^^^^^^^^^^^
#![deny(unused_attributes)]
-#![feature(min_const_generics)]
use std::marker::PhantomData;
error[E0518]: attribute should be applied to function or closure
- --> $DIR/issue-78957.rs:6:16
+ --> $DIR/issue-78957.rs:5:16
|
LL | pub struct Foo<#[inline] const N: usize>;
| ^^^^^^^^^ - not a function or closure
error: attribute should be applied to a function
- --> $DIR/issue-78957.rs:8:16
+ --> $DIR/issue-78957.rs:7:16
|
LL | pub struct Bar<#[cold] const N: usize>;
| ^^^^^^^ - not a function
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
error[E0517]: attribute should be applied to a struct, enum, or union
- --> $DIR/issue-78957.rs:11:23
+ --> $DIR/issue-78957.rs:10:23
|
LL | pub struct Baz<#[repr(C)] const N: usize>;
| ^ - not a struct, enum, or union
error[E0518]: attribute should be applied to function or closure
- --> $DIR/issue-78957.rs:14:17
+ --> $DIR/issue-78957.rs:13:17
|
LL | pub struct Foo2<#[inline] 'a>(PhantomData<&'a ()>);
| ^^^^^^^^^ -- not a function or closure
error: attribute should be applied to a function
- --> $DIR/issue-78957.rs:16:17
+ --> $DIR/issue-78957.rs:15:17
|
LL | pub struct Bar2<#[cold] 'a>(PhantomData<&'a ()>);
| ^^^^^^^ -- not a function
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
error[E0517]: attribute should be applied to a struct, enum, or union
- --> $DIR/issue-78957.rs:19:24
+ --> $DIR/issue-78957.rs:18:24
|
LL | pub struct Baz2<#[repr(C)] 'a>(PhantomData<&'a ()>);
| ^ -- not a struct, enum, or union
error[E0518]: attribute should be applied to function or closure
- --> $DIR/issue-78957.rs:22:17
+ --> $DIR/issue-78957.rs:21:17
|
LL | pub struct Foo3<#[inline] T>(PhantomData<T>);
| ^^^^^^^^^ - not a function or closure
error: attribute should be applied to a function
- --> $DIR/issue-78957.rs:24:17
+ --> $DIR/issue-78957.rs:23:17
|
LL | pub struct Bar3<#[cold] T>(PhantomData<T>);
| ^^^^^^^ - not a function
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
error[E0517]: attribute should be applied to a struct, enum, or union
- --> $DIR/issue-78957.rs:27:24
+ --> $DIR/issue-78957.rs:26:24
|
LL | pub struct Baz3<#[repr(C)] T>(PhantomData<T>);
| ^ - not a struct, enum, or union
--- /dev/null
+// test for #87707
+// edition:2018
+// run-fail
+// exec-env:RUST_BACKTRACE=0
+// check-run-results
+
+use std::sync::Once;
+use std::panic;
+
+fn main() {
+ let o = Once::new();
+ let _ = panic::catch_unwind(|| {
+ o.call_once(|| panic!("Here Once instance is poisoned."));
+ });
+ o.call_once(|| {});
+}
--- /dev/null
+thread 'main' panicked at 'Here Once instance is poisoned.', $DIR/issue-87707.rs:13:24
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
+thread 'main' panicked at 'Once instance has previously been poisoned', $DIR/issue-87707.rs:15:7
+++ /dev/null
-// Regression test for issue #87308.
-
-// compile-flags: -Zunpretty=everybody_loops
-// check-pass
-
-macro_rules! foo {
- () => { break 'x; }
-}
-
-pub fn main() {
- 'x: loop { foo!() }
-}
+++ /dev/null
-#![feature(prelude_import)]
-#![no_std]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
-#[macro_use]
-extern crate std;
-// Regression test for issue #87308.
-
-// compile-flags: -Zunpretty=everybody_loops
-// check-pass
-
-macro_rules! foo { () => { break 'x ; } }
-
-pub fn main() { loop {} }
--- /dev/null
+// check-pass
+
+#![feature(lint_reasons)]
+
+#![warn(unused)]
+
+// This expect attribute should catch all lint triggers
+#[expect(unused_variables)]
+fn check_multiple_lints_1() {
+ let value_i = 0xff00ff;
+ let value_ii = 0xff00ff;
+ let value_iii = 0xff00ff;
+ let value_iiii = 0xff00ff;
+ let value_iiiii = 0xff00ff;
+}
+
+// This expect attribute should catch all lint triggers
+#[expect(unused_mut)]
+fn check_multiple_lints_2() {
+ let mut a = 0xa;
+ let mut b = 0xb;
+ let mut c = 0xc;
+ println!("The ABC goes as: {:#x} {:#x} {:#x}", a, b, c);
+}
+
+// This expect attribute should catch all lint triggers
+#[expect(while_true)]
+fn check_multiple_lints_3() {
+ // `while_true` is an early lint
+ while true {}
+
+ while true {}
+
+ while true {}
+
+ while true {}
+
+ while true {}
+}
+
+fn main() {
+ check_multiple_lints_1();
+ check_multiple_lints_2();
+ check_multiple_lints_3();
+}
--- /dev/null
+// check-pass
+
+#![feature(lint_reasons)]
+
+#![warn(unused)]
+
+#![expect(unused_mut)]
+//~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+//~| NOTE `#[warn(unfulfilled_lint_expectations)]` on by default
+
+#![expect(unused_variables)]
+
+fn main() {
+ let x = 0;
+}
--- /dev/null
+warning: this lint expectation is unfulfilled
+ --> $DIR/crate_level_expect.rs:7:11
+ |
+LL | #![expect(unused_mut)]
+ | ^^^^^^^^^^
+ |
+ = note: `#[warn(unfulfilled_lint_expectations)]` on by default
+
+warning: 1 warning emitted
+
--- /dev/null
+// check-pass
+
+#![feature(lint_reasons)]
+
+#![warn(unused)]
+
+macro_rules! expect_inside_macro {
+ () => {
+ #[expect(unused_variables)]
+ let x = 0;
+ };
+}
+
+fn main() {
+ expect_inside_macro!();
+}
--- /dev/null
+// check-pass
+
+#![feature(lint_reasons)]
+
+#![warn(unused_variables)]
+
+macro_rules! trigger_unused_variables_macro {
+ () => {
+ let x = 0;
+ //~^ WARNING unused variable: `x` [unused_variables]
+ //~| WARNING unused variable: `x` [unused_variables]
+ };
+}
+
+pub fn check_macro() {
+ // This should trigger the `unused_variables` from inside the macro
+ trigger_unused_variables_macro!();
+}
+
+// This should be fulfilled by the macro
+#[expect(unused_variables)]
+pub fn check_expect_on_item() {
+ trigger_unused_variables_macro!();
+}
+
+pub fn check_expect_on_macro() {
+ // This should be fulfilled by the macro
+ #[expect(unused_variables)]
+ trigger_unused_variables_macro!();
+
+ // FIXME: Lint attributes currently don't work directly on macros, and
+ // therefore also doesn't work for the new `expect` attribute. This bug
+ // is being tracked in rust#87391. The test will until then produce two
+ // warnings about the unused variable x.
+ //
+ // The expectation is still marked as fulfilled. I'm not totally why but
+ // my guess is that this will remain working when rust#87391 has been fixed.
+}
+
+fn main() {
+
+}
--- /dev/null
+warning: unused variable: `x`
+ --> $DIR/expect_lint_from_macro.rs:9:13
+ |
+LL | let x = 0;
+ | ^ help: if this is intentional, prefix it with an underscore: `_x`
+...
+LL | trigger_unused_variables_macro!();
+ | --------------------------------- in this macro invocation
+ |
+note: the lint level is defined here
+ --> $DIR/expect_lint_from_macro.rs:5:9
+ |
+LL | #![warn(unused_variables)]
+ | ^^^^^^^^^^^^^^^^
+ = note: this warning originates in the macro `trigger_unused_variables_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: unused variable: `x`
+ --> $DIR/expect_lint_from_macro.rs:9:13
+ |
+LL | let x = 0;
+ | ^ help: if this is intentional, prefix it with an underscore: `_x`
+...
+LL | trigger_unused_variables_macro!();
+ | --------------------------------- in this macro invocation
+ |
+ = note: this warning originates in the macro `trigger_unused_variables_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: 2 warnings emitted
+
--- /dev/null
+// should error due to missing feature gate.
+
+#![warn(unused)]
+
+#[expect(unused)]
+//~^ ERROR: the `#[expect]` attribute is an experimental feature [E0658]
+fn main() {
+ let x = 1;
+}
--- /dev/null
+error[E0658]: the `#[expect]` attribute is an experimental feature
+ --> $DIR/expect_missing_feature_gate.rs:5:1
+ |
+LL | #[expect(unused)]
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #54503 <https://github.com/rust-lang/rust/issues/54503> for more information
+ = help: add `#![feature(lint_reasons)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// check-pass
+
+#![feature(lint_reasons)]
+
+#![warn(unused)]
+
+// The warnings are not double triggers, they identify different unfulfilled lint
+// expectations one for each listed lint.
+
+#[expect(unused_variables, unused_mut, while_true)]
+//~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+//~| NOTE `#[warn(unfulfilled_lint_expectations)]` on by default
+//~| WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+fn check_multiple_lints_1() {
+ // This only trigger `unused_variables`
+ let who_am_i = 666;
+}
+
+#[expect(unused_variables, unused_mut, while_true)]
+//~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+//~| WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+fn check_multiple_lints_2() {
+ // This only triggers `unused_mut`
+ let mut x = 0;
+ println!("I use x: {}", x);
+}
+
+#[expect(unused_variables, unused_mut, while_true)]
+//~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+//~| WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+fn check_multiple_lints_3() {
+ // This only triggers `while_true` which is also an early lint
+ while true {}
+}
+
+#[expect(unused, while_true)]
+//~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+fn check_multiple_lints_with_lint_group_1() {
+ let who_am_i = 666;
+
+ let mut x = 0;
+ println!("I use x: {}", x);
+}
+
+#[expect(unused, while_true)]
+//~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+fn check_multiple_lints_with_lint_group_2() {
+ while true {}
+}
+
+fn main() {
+ check_multiple_lints_1();
+ check_multiple_lints_2();
+ check_multiple_lints_3();
+
+ check_multiple_lints_with_lint_group_1();
+ check_multiple_lints_with_lint_group_2();
+}
--- /dev/null
+warning: this lint expectation is unfulfilled
+ --> $DIR/expect_multiple_lints.rs:10:28
+ |
+LL | #[expect(unused_variables, unused_mut, while_true)]
+ | ^^^^^^^^^^
+ |
+ = note: `#[warn(unfulfilled_lint_expectations)]` on by default
+
+warning: this lint expectation is unfulfilled
+ --> $DIR/expect_multiple_lints.rs:10:40
+ |
+LL | #[expect(unused_variables, unused_mut, while_true)]
+ | ^^^^^^^^^^
+
+warning: this lint expectation is unfulfilled
+ --> $DIR/expect_multiple_lints.rs:19:10
+ |
+LL | #[expect(unused_variables, unused_mut, while_true)]
+ | ^^^^^^^^^^^^^^^^
+
+warning: this lint expectation is unfulfilled
+ --> $DIR/expect_multiple_lints.rs:19:40
+ |
+LL | #[expect(unused_variables, unused_mut, while_true)]
+ | ^^^^^^^^^^
+
+warning: this lint expectation is unfulfilled
+ --> $DIR/expect_multiple_lints.rs:28:10
+ |
+LL | #[expect(unused_variables, unused_mut, while_true)]
+ | ^^^^^^^^^^^^^^^^
+
+warning: this lint expectation is unfulfilled
+ --> $DIR/expect_multiple_lints.rs:28:28
+ |
+LL | #[expect(unused_variables, unused_mut, while_true)]
+ | ^^^^^^^^^^
+
+warning: this lint expectation is unfulfilled
+ --> $DIR/expect_multiple_lints.rs:36:18
+ |
+LL | #[expect(unused, while_true)]
+ | ^^^^^^^^^^
+
+warning: this lint expectation is unfulfilled
+ --> $DIR/expect_multiple_lints.rs:45:10
+ |
+LL | #[expect(unused, while_true)]
+ | ^^^^^^
+
+warning: 8 warnings emitted
+
--- /dev/null
+// ignore-tidy-linelength
+
+#![feature(lint_reasons)]
+#![warn(unused_mut)]
+
+#[expect(
+ unused_mut,
+ //~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+ //~| NOTE `#[warn(unfulfilled_lint_expectations)]` on by default
+ //~| NOTE this `expect` is overridden by a `allow` attribute before the `unused_mut` lint is triggered
+ reason = "this `expect` is overridden by a `allow` attribute before the `unused_mut` lint is triggered"
+)]
+mod foo {
+ fn bar() {
+ #[allow(
+ unused_mut,
+ reason = "this overrides the previous `expect` lint level and allows the `unused_mut` lint here"
+ )]
+ let mut v = 0;
+ }
+}
+
+#[expect(
+ unused_mut,
+ //~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+ //~| NOTE this `expect` is overridden by a `warn` attribute before the `unused_mut` lint is triggered
+ reason = "this `expect` is overridden by a `warn` attribute before the `unused_mut` lint is triggered"
+)]
+mod oof {
+ #[warn(
+ unused_mut,
+ //~^ NOTE the lint level is defined here
+ reason = "this overrides the previous `expect` lint level and warns about the `unused_mut` lint here"
+ )]
+ fn bar() {
+ let mut v = 0;
+ //~^ WARNING variable does not need to be mutable [unused_mut]
+ //~| NOTE this overrides the previous `expect` lint level and warns about the `unused_mut` lint here
+ //~| HELP remove this `mut`
+ }
+}
+
+#[expect(unused_variables)]
+//~^ WARNING this lint expectation is unfulfilled
+#[forbid(unused_variables)]
+//~^ NOTE the lint level is defined here
+fn check_expect_then_forbid() {
+ let this_is_my_function = 3;
+ //~^ ERROR unused variable: `this_is_my_function` [unused_variables]
+ //~| HELP if this is intentional, prefix it with an underscore
+}
+
+fn main() {}
--- /dev/null
+error: unused variable: `this_is_my_function`
+ --> $DIR/expect_nested_lint_levels.rs:48:9
+ |
+LL | let this_is_my_function = 3;
+ | ^^^^^^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_this_is_my_function`
+ |
+note: the lint level is defined here
+ --> $DIR/expect_nested_lint_levels.rs:45:10
+ |
+LL | #[forbid(unused_variables)]
+ | ^^^^^^^^^^^^^^^^
+
+warning: variable does not need to be mutable
+ --> $DIR/expect_nested_lint_levels.rs:36:13
+ |
+LL | let mut v = 0;
+ | ----^
+ | |
+ | help: remove this `mut`
+ |
+ = note: this overrides the previous `expect` lint level and warns about the `unused_mut` lint here
+note: the lint level is defined here
+ --> $DIR/expect_nested_lint_levels.rs:31:9
+ |
+LL | unused_mut,
+ | ^^^^^^^^^^
+
+warning: this lint expectation is unfulfilled
+ --> $DIR/expect_nested_lint_levels.rs:7:5
+ |
+LL | unused_mut,
+ | ^^^^^^^^^^
+ |
+ = note: `#[warn(unfulfilled_lint_expectations)]` on by default
+ = note: this `expect` is overridden by a `allow` attribute before the `unused_mut` lint is triggered
+
+warning: this lint expectation is unfulfilled
+ --> $DIR/expect_nested_lint_levels.rs:24:5
+ |
+LL | unused_mut,
+ | ^^^^^^^^^^
+ |
+ = note: this `expect` is overridden by a `warn` attribute before the `unused_mut` lint is triggered
+
+warning: this lint expectation is unfulfilled
+ --> $DIR/expect_nested_lint_levels.rs:43:10
+ |
+LL | #[expect(unused_variables)]
+ | ^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 4 warnings emitted
+
--- /dev/null
+#![feature(lint_reasons)]
+
+#[forbid(unused_variables)]
+//~^ NOTE `forbid` level set here
+//~| NOTE `forbid` level set here
+#[expect(unused_variables)]
+//~^ ERROR incompatible with previous forbid [E0453]
+//~| NOTE overruled by previous forbid
+//~| ERROR incompatible with previous forbid [E0453]
+//~| NOTE overruled by previous forbid
+fn expect_forbidden_lint_1() {}
+
+#[forbid(while_true)]
+//~^ NOTE `forbid` level set here
+//~| NOTE `forbid` level set here
+//~| NOTE the lint level is defined here
+#[expect(while_true)]
+//~^ ERROR incompatible with previous forbid [E0453]
+//~| NOTE overruled by previous forbid
+//~| ERROR incompatible with previous forbid [E0453]
+//~| NOTE overruled by previous forbid
+fn expect_forbidden_lint_2() {
+ // This while loop will produce a `while_true` lint as the lint level
+ // at this node is still `forbid` and the `while_true` check happens
+ // before the compilation terminates due to `E0453`
+ while true {}
+ //~^ ERROR denote infinite loops with `loop { ... }`
+ //~| HELP use `loop`
+}
+
+fn main() {
+ expect_forbidden_lint_1();
+ expect_forbidden_lint_2();
+}
--- /dev/null
+error[E0453]: expect(unused_variables) incompatible with previous forbid
+ --> $DIR/expect_with_forbid.rs:6:10
+ |
+LL | #[forbid(unused_variables)]
+ | ---------------- `forbid` level set here
+...
+LL | #[expect(unused_variables)]
+ | ^^^^^^^^^^^^^^^^ overruled by previous forbid
+
+error[E0453]: expect(while_true) incompatible with previous forbid
+ --> $DIR/expect_with_forbid.rs:17:10
+ |
+LL | #[forbid(while_true)]
+ | ---------- `forbid` level set here
+...
+LL | #[expect(while_true)]
+ | ^^^^^^^^^^ overruled by previous forbid
+
+error[E0453]: expect(unused_variables) incompatible with previous forbid
+ --> $DIR/expect_with_forbid.rs:6:10
+ |
+LL | #[forbid(unused_variables)]
+ | ---------------- `forbid` level set here
+...
+LL | #[expect(unused_variables)]
+ | ^^^^^^^^^^^^^^^^ overruled by previous forbid
+
+error[E0453]: expect(while_true) incompatible with previous forbid
+ --> $DIR/expect_with_forbid.rs:17:10
+ |
+LL | #[forbid(while_true)]
+ | ---------- `forbid` level set here
+...
+LL | #[expect(while_true)]
+ | ^^^^^^^^^^ overruled by previous forbid
+
+error: denote infinite loops with `loop { ... }`
+ --> $DIR/expect_with_forbid.rs:26:5
+ |
+LL | while true {}
+ | ^^^^^^^^^^ help: use `loop`
+ |
+note: the lint level is defined here
+ --> $DIR/expect_with_forbid.rs:13:10
+ |
+LL | #[forbid(while_true)]
+ | ^^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0453`.
--- /dev/null
+// check-pass
+
+#![feature(lint_reasons)]
+#![warn(unused)]
+
+#![expect(unused_variables, reason = "<This should fail and display this reason>")]
+//~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+//~| NOTE `#[warn(unfulfilled_lint_expectations)]` on by default
+//~| NOTE <This should fail and display this reason>
+
+fn main() {}
--- /dev/null
+warning: this lint expectation is unfulfilled
+ --> $DIR/expect_with_reason.rs:6:11
+ |
+LL | #![expect(unused_variables, reason = "<This should fail and display this reason>")]
+ | ^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(unfulfilled_lint_expectations)]` on by default
+ = note: <This should fail and display this reason>
+
+warning: 1 warning emitted
+
--- /dev/null
+// check-pass
+
+#![feature(lint_reasons)]
+
+fn expect_early_pass_lints() {
+ #[expect(while_true)]
+ while true {
+ println!("I never stop")
+ }
+
+ #[expect(unused_doc_comments)]
+ /// This comment triggers the `unused_doc_comments` lint
+ let _sheep = "wolf";
+
+ let x = 123;
+ #[expect(ellipsis_inclusive_range_patterns)]
+ match x {
+ 0...100 => {}
+ _ => {}
+ }
+}
+
+fn main() {}
--- /dev/null
+// check-pass
+
+#![feature(lint_reasons)]
+#![warn(unused)]
+
+#[expect(unused_variables)]
+fn check_specific_lint() {
+ let x = 2;
+}
+
+#[expect(unused)]
+fn check_lint_group() {
+ let x = 15;
+}
+
+#[expect(unused_variables)]
+fn check_multiple_lint_emissions() {
+ let r = 1;
+ let u = 8;
+ let s = 2;
+ let t = 9;
+}
+
+mod check_fulfilled_expect_in_macro {
+ macro_rules! expect_inside_macro {
+ () => {
+ #[expect(unused_variables)]
+ let x = 0;
+ };
+ }
+
+ pub fn check_macro() {
+ expect_inside_macro!();
+ }
+}
+
+fn main() {
+ check_specific_lint();
+ check_lint_group();
+ check_multiple_lint_emissions();
+
+ check_fulfilled_expect_in_macro::check_macro();
+}
--- /dev/null
+#![feature(lint_reasons)]
+
+#![deny(unused_attributes)]
+
+#[allow(reason = "I want to allow something")]//~ ERROR unused attribute
+#[expect(reason = "I don't know what I'm waiting for")]//~ ERROR unused attribute
+#[warn(reason = "This should be warn by default")]//~ ERROR unused attribute
+#[deny(reason = "All listed lints are denied")]//~ ERROR unused attribute
+#[forbid(reason = "Just some reason")]//~ ERROR unused attribute
+
+#[allow(clippy::box_collection, reason = "This is still valid")]
+#[warn(dead_code, reason = "This is also reasonable")]
+
+fn main() {}
--- /dev/null
+error: unused attribute
+ --> $DIR/lint-attribute-only-with-reason.rs:5:1
+ |
+LL | #[allow(reason = "I want to allow something")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+ |
+note: the lint level is defined here
+ --> $DIR/lint-attribute-only-with-reason.rs:3:9
+ |
+LL | #![deny(unused_attributes)]
+ | ^^^^^^^^^^^^^^^^^
+ = note: attribute `allow` without any lints has no effect
+
+error: unused attribute
+ --> $DIR/lint-attribute-only-with-reason.rs:6:1
+ |
+LL | #[expect(reason = "I don't know what I'm waiting for")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+ |
+ = note: attribute `expect` without any lints has no effect
+
+error: unused attribute
+ --> $DIR/lint-attribute-only-with-reason.rs:7:1
+ |
+LL | #[warn(reason = "This should be warn by default")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+ |
+ = note: attribute `warn` without any lints has no effect
+
+error: unused attribute
+ --> $DIR/lint-attribute-only-with-reason.rs:8:1
+ |
+LL | #[deny(reason = "All listed lints are denied")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+ |
+ = note: attribute `deny` without any lints has no effect
+
+error: unused attribute
+ --> $DIR/lint-attribute-only-with-reason.rs:9:1
+ |
+LL | #[forbid(reason = "Just some reason")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+ |
+ = note: attribute `forbid` without any lints has no effect
+
+error: aborting due to 5 previous errors
+
--- /dev/null
+// check-pass
+
+#![feature(lint_reasons)]
+#![warn(unused)]
+
+#[warn(unused_variables)]
+#[expect(unused_variables)]
+//~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+//~| NOTE `#[warn(unfulfilled_lint_expectations)]` on by default
+#[allow(unused_variables)]
+#[expect(unused_variables)] // Only this expectation will be fulfilled
+fn main() {
+ let x = 2;
+}
--- /dev/null
+warning: this lint expectation is unfulfilled
+ --> $DIR/multiple_expect_attrs.rs:7:10
+ |
+LL | #[expect(unused_variables)]
+ | ^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(unfulfilled_lint_expectations)]` on by default
+
+warning: 1 warning emitted
+
warning: Linking globals named 'foo': symbol multiply defined!
-error: failed to load bc of "lto-duplicate-symbols2.lto_duplicate_symbols2.HASH-cgu.0.rcgu.o":
+error: failed to load bitcode of module "lto-duplicate-symbols2.lto_duplicate_symbols2.HASH-cgu.0.rcgu.o":
error: aborting due to previous error; 1 warning emitted
// Test for issue #50381: non-lifetime passed to :lifetime.
-#![feature(macro_lifetime_matcher)]
-
macro_rules! m { ($x:lifetime) => { } }
fn main() {
error: no rules expected the token `a`
- --> $DIR/macro-non-lifetime.rs:8:8
+ --> $DIR/macro-non-lifetime.rs:6:8
|
LL | macro_rules! m { ($x:lifetime) => { } }
| -------------- when calling this macro
-#![feature(extern_prelude)]
-
mod m {
fn check() {
Vec::clone!(); //~ ERROR failed to resolve: `Vec` is a struct, not a module
error[E0433]: failed to resolve: `Vec` is a struct, not a module
- --> $DIR/macro-path-prelude-fail-1.rs:5:9
+ --> $DIR/macro-path-prelude-fail-1.rs:3:9
|
LL | Vec::clone!();
| ^^^ `Vec` is a struct, not a module
error[E0433]: failed to resolve: `u8` is a builtin type, not a module
- --> $DIR/macro-path-prelude-fail-1.rs:6:9
+ --> $DIR/macro-path-prelude-fail-1.rs:4:9
|
LL | u8::clone!();
| ^^ `u8` is a builtin type, not a module
// aux-build:macro-in-other-crate.rs
-#![feature(decl_macro, extern_prelude)]
+#![feature(decl_macro)]
macro_rules! add_macro_expanded_things_to_macro_prelude {() => {
#[macro_use]
#![feature(decl_macro)]
#![feature(staged_api)]
-#[macro_use] extern crate unstable_macros;
+#![stable(feature = "rust1", since = "1.0.0")]
+
+#[macro_use]
+extern crate unstable_macros;
#[unstable(feature = "local_unstable", issue = "none")]
macro_rules! local_unstable { () => () }
error[E0658]: use of unstable library feature 'local_unstable'
- --> $DIR/macro-stability.rs:19:5
+ --> $DIR/macro-stability.rs:22:5
|
LL | local_unstable!();
| ^^^^^^^^^^^^^^
= help: add `#![feature(local_unstable)]` to the crate attributes to enable
error[E0658]: use of unstable library feature 'local_unstable'
- --> $DIR/macro-stability.rs:20:5
+ --> $DIR/macro-stability.rs:23:5
|
LL | local_unstable_modern!();
| ^^^^^^^^^^^^^^^^^^^^^
= help: add `#![feature(local_unstable)]` to the crate attributes to enable
error[E0658]: use of unstable library feature 'unstable_macros'
- --> $DIR/macro-stability.rs:21:5
+ --> $DIR/macro-stability.rs:24:5
|
LL | unstable_macro!();
| ^^^^^^^^^^^^^^
= help: add `#![feature(unstable_macros)]` to the crate attributes to enable
warning: use of deprecated macro `deprecated_macro`: deprecation reason
- --> $DIR/macro-stability.rs:24:5
+ --> $DIR/macro-stability.rs:27:5
|
LL | deprecated_macro!();
| ^^^^^^^^^^^^^^^^
= note: `#[warn(deprecated)]` on by default
warning: use of deprecated macro `local_deprecated`: local deprecation reason
- --> $DIR/macro-stability.rs:26:5
+ --> $DIR/macro-stability.rs:29:5
|
LL | local_deprecated!();
| ^^^^^^^^^^^^^^^^
mod m {
-//~^ ERROR `main` function not found
// An inferred main entry point
// must appear at the top of the crate
fn main() { }
-}
+} //~ ERROR `main` function not found
error[E0601]: `main` function not found in crate `main_wrong_location`
- --> $DIR/main-wrong-location.rs:1:1
+ --> $DIR/main-wrong-location.rs:5:2
|
-LL | / mod m {
-LL | |
-LL | | // An inferred main entry point
-LL | | // must appear at the top of the crate
-LL | | fn main() { }
-LL | | }
- | |_^ the main function must be defined at the crate level (in `$DIR/main-wrong-location.rs`)
+LL | }
+ | ^ the main function must be defined at the crate level (in `$DIR/main-wrong-location.rs`)
|
note: here is a function named `main`
- --> $DIR/main-wrong-location.rs:5:5
+ --> $DIR/main-wrong-location.rs:4:5
|
LL | fn main() { }
| ^^^^^^^^^^^^^
error[E0004]: non-exhaustive patterns: `B` not covered
--> $DIR/match_non_exhaustive.rs:23:11
|
-LL | enum L { A, B }
- | ---------------
- | | |
- | | not covered
- | `L` defined here
-...
LL | match l { L::A => () };
| ^ pattern `B` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `L` defined here
+ --> $DIR/match_non_exhaustive.rs:10:13
+ |
+LL | enum L { A, B }
+ | - ^ not covered
= note: the matched value is of type `L`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL | match l { L::A => (), B => todo!() };
+ | ++++++++++++++
error[E0004]: non-exhaustive patterns: type `E1` is non-empty
--> $DIR/match_non_exhaustive.rs:28:11
LL | match e1 {};
| ^^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `E1` defined here
+ --> $DIR/auxiliary/match_non_exhaustive_lib.rs:2:1
+ |
+LL | pub enum E1 {}
+ | ^^^^^^^^^^^^^^
= note: the matched value is of type `E1`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match e1 {
+LL + _ => todo!(),
+LL ~ };
+ |
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/match_non_exhaustive.rs:30:11
LL | match e2 { E2::A => (), E2::B => () };
| ^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `E2` defined here
+ --> $DIR/auxiliary/match_non_exhaustive_lib.rs:5:1
+ |
+LL | pub enum E2 { A, B }
+ | ^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `E2`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL | match e2 { E2::A => (), E2::B => (), _ => todo!() };
+ | ++++++++++++++
error: aborting due to 3 previous errors
//~^ ERROR this function takes 1 argument but 0 arguments were supplied
let ans = s("burma", "shave");
//~^ ERROR this function takes 1 argument but 2 arguments were supplied
+ //~| ERROR mismatched types
}
LL | extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
| ^^^^^^^^
+error[E0308]: mismatched types
+ --> $DIR/overloaded-calls-bad.rs:31:17
+ |
+LL | let ans = s("burma", "shave");
+ | ^^^^^^^ expected `isize`, found `&str`
+
error[E0057]: this function takes 1 argument but 2 arguments were supplied
--> $DIR/overloaded-calls-bad.rs:31:15
|
LL | extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
| ^^^^^^^^
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
Some errors have detailed explanations: E0057, E0308.
For more information about an error, try `rustc --explain E0057`.
#![no_std]
#![crate_type = "staticlib"]
-#![feature(panic_handler, alloc_error_handler)]
+#![feature(alloc_error_handler)]
#[panic_handler]
fn panic(_: &core::panic::PanicInfo) -> ! {
#![no_std]
#![crate_type = "staticlib"]
-#![feature(panic_handler, alloc_error_handler)]
+#![feature(alloc_error_handler)]
#[panic_handler]
fn panic(_: &core::panic::PanicInfo) -> ! {
error[E0601]: `main` function not found in crate `missing_main`
- --> $DIR/missing-main.rs:2:1
+ --> $DIR/missing-main.rs:2:14
|
LL | fn mian() { }
- | ^^^^^^^^^^^^^ consider adding a `main` function to `$DIR/missing-main.rs`
+ | ^ consider adding a `main` function to `$DIR/missing-main.rs`
error: aborting due to previous error
// Regression test for issue #55825
// Tests that we don't emit a spurious warning in NLL mode
+// check-pass
+
#![feature(nll)]
-const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } //~ ERROR const
+const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
fn main() { }
+++ /dev/null
-error[E0658]: trait objects in const fn are unstable
- --> $DIR/issue-55825-const-fn.rs:6:32
- |
-LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
- = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// check-pass
+
+// mir borrowck previously incorrectly set `tainted_by_errors`
+// when buffering lints, which resulted in ICE later on,
+// see #94502.
+
+// Errors with `nll` which is already tested in enough other tests,
+// so we ignore it here.
+//
+// ignore-compare-mode-nll
+
+struct Repro;
+impl Repro {
+ fn get(&self) -> &i32 {
+ &3
+ }
+
+ fn insert(&mut self, _: i32) {}
+}
+
+fn main() {
+ let x = &0;
+ let mut conflict = Repro;
+ let prev = conflict.get();
+ conflict.insert(*prev + *x);
+ //~^ WARN cannot borrow `conflict` as mutable because it is also borrowed as immutable
+ //~| WARN this borrowing pattern was not meant to be accepted
+}
--- /dev/null
+warning: cannot borrow `conflict` as mutable because it is also borrowed as immutable
+ --> $DIR/lint-no-err.rs:25:5
+ |
+LL | let prev = conflict.get();
+ | -------------- immutable borrow occurs here
+LL | conflict.insert(*prev + *x);
+ | ^^^^^^^^^^^^^^^^-----^^^^^^
+ | | |
+ | | immutable borrow later used here
+ | mutable borrow occurs here
+ |
+ = note: `#[warn(mutable_borrow_reservation_conflict)]` on by default
+ = warning: this borrowing pattern was not meant to be accepted, and may become a hard error in the future
+ = note: for more information, see issue #59159 <https://github.com/rust-lang/rust/issues/59159>
+
+warning: 1 warning emitted
+
#![allow(dead_code)]
-#![feature(recover)]
use std::panic::UnwindSafe;
error[E0277]: the type `&mut i32` may not be safely transferred across an unwind boundary
- --> $DIR/not-panic-safe.rs:9:5
+ --> $DIR/not-panic-safe.rs:8:5
|
LL | assert::<&mut i32>();
| ^^^^^^^^^^^^^^^^^^ `&mut i32` may not be safely transferred across an unwind boundary
= help: the trait `UnwindSafe` is not implemented for `&mut i32`
= note: `UnwindSafe` is implemented for `&i32`, but not for `&mut i32`
note: required by a bound in `assert`
- --> $DIR/not-panic-safe.rs:6:14
+ --> $DIR/not-panic-safe.rs:5:14
|
LL | fn assert<T: UnwindSafe + ?Sized>() {}
| ^^^^^^^^^^ required by this bound in `assert`
error: lifetime may not live long enough
- --> $DIR/object-lifetime-default-from-rptr-struct-error.rs:21:5
+ --> $DIR/object-lifetime-default-from-rptr-struct-error.rs:20:5
|
LL | fn c<'a>(t: &'a MyBox<dyn Test+'a>, mut ss: SomeStruct<'a>) {
| -- lifetime `'a` defined here
// through the `MyBox` struct.
#![allow(dead_code)]
-#![feature(rustc_error)]
trait Test {
fn foo(&self) { }
error[E0308]: mismatched types
- --> $DIR/object-lifetime-default-from-rptr-struct-error.rs:21:12
+ --> $DIR/object-lifetime-default-from-rptr-struct-error.rs:20:12
|
LL | ss.t = t;
| ^ lifetime mismatch
= note: expected reference `&'a MyBox<(dyn Test + 'static)>`
found reference `&'a MyBox<(dyn Test + 'a)>`
note: the lifetime `'a` as defined here...
- --> $DIR/object-lifetime-default-from-rptr-struct-error.rs:20:6
+ --> $DIR/object-lifetime-default-from-rptr-struct-error.rs:19:6
|
LL | fn c<'a>(t: &'a MyBox<dyn Test+'a>, mut ss: SomeStruct<'a>) {
| ^^
--- /dev/null
+#![feature(rustc_attrs)]
+
+trait Foo<A> {
+ fn foo(self);
+}
+
+#[rustc_on_unimplemented = "an impl did not match: {A} {B} {C}"]
+impl<A, B, C> Foo<A> for (A, B, C) {
+ fn foo(self) {}
+}
+
+fn main() {
+ Foo::<usize>::foo((1i32, 1i32, 1i32));
+ //~^ ERROR the trait bound `(i32, i32, i32): Foo<usize>` is not satisfied
+}
--- /dev/null
+error[E0277]: the trait bound `(i32, i32, i32): Foo<usize>` is not satisfied
+ --> $DIR/impl-substs.rs:13:23
+ |
+LL | Foo::<usize>::foo((1i32, 1i32, 1i32));
+ | ----------------- ^^^^^^^^^^^^^^^^^^ an impl did not match: usize _ _
+ | |
+ | required by a bound introduced by this call
+ |
+ = help: the trait `Foo<usize>` is not implemented for `(i32, i32, i32)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
// Testing guarantees provided by once functions.
// This program would segfault if it were legal.
-#![feature(once_fns)]
use std::sync::Arc;
fn foo<F:FnOnce()>(blk: F) {
error[E0382]: use of moved value: `blk`
- --> $DIR/once-cant-call-twice-on-heap.rs:9:5
+ --> $DIR/once-cant-call-twice-on-heap.rs:8:5
|
LL | fn foo<F:FnOnce()>(blk: F) {
| --- move occurs because `blk` has type `F`, which does not implement the `Copy` trait
| ^^^ value used here after move
|
note: this value implements `FnOnce`, which causes it to be moved when called
- --> $DIR/once-cant-call-twice-on-heap.rs:8:5
+ --> $DIR/once-cant-call-twice-on-heap.rs:7:5
|
LL | blk();
| ^^^
LL | match (0u8, 0u8) {
| ^^^^^^^^^^ pattern `(2_u8..=u8::MAX, _)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(u8, u8)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ (0 | 1, 2 | 3) => {}
+LL + (2_u8..=u8::MAX, _) => todo!()
+ |
error[E0004]: non-exhaustive patterns: `((4_u8..=u8::MAX))` not covered
--> $DIR/exhaustiveness-non-exhaustive.rs:9:11
LL | match ((0u8,),) {
| ^^^^^^^^^ pattern `((4_u8..=u8::MAX))` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `((u8,),)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ ((0 | 1,) | (2 | 3,),) => {}
+LL + ((4_u8..=u8::MAX)) => todo!()
+ |
error[E0004]: non-exhaustive patterns: `(Some(2_u8..=u8::MAX))` not covered
--> $DIR/exhaustiveness-non-exhaustive.rs:13:11
LL | match (Some(0u8),) {
| ^^^^^^^^^^^^ pattern `(Some(2_u8..=u8::MAX))` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(Option<u8>,)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ (None | Some(0 | 1),) => {}
+LL + (Some(2_u8..=u8::MAX)) => todo!()
+ |
error: aborting due to 3 previous errors
LL | match 0 {
| ^ patterns `i32::MIN..=-1_i32` and `3_i32..=i32::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ 0 | (1 | 2) => {}
+LL + i32::MIN..=-1_i32 | 3_i32..=i32::MAX => todo!()
+ |
error: aborting due to 2 previous errors
// types of patterns that allow undelimited subpatterns that could cause the same ambiguity.
// Currently, those should be impossible due to precedence rule. This test enforces that.
-#![feature(or_patterns)]
-
enum E {
A,
B,
error: top-level or-patterns are not allowed in `let` bindings
- --> $DIR/nested-undelimited-precedence.rs:21:9
+ --> $DIR/nested-undelimited-precedence.rs:19:9
|
LL | let b @ A | B: E = A;
| ^^^^^^^^^ help: wrap the pattern in parentheses: `(b @ A | B)`
error: top-level or-patterns are not allowed in `let` bindings
- --> $DIR/nested-undelimited-precedence.rs:36:9
+ --> $DIR/nested-undelimited-precedence.rs:34:9
|
LL | let &A(_) | B(_): F = A(3);
| ^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(&A(_) | B(_))`
error: top-level or-patterns are not allowed in `let` bindings
- --> $DIR/nested-undelimited-precedence.rs:38:9
+ --> $DIR/nested-undelimited-precedence.rs:36:9
|
LL | let &&A(_) | B(_): F = A(3);
| ^^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(&&A(_) | B(_))`
error: top-level or-patterns are not allowed in `let` bindings
- --> $DIR/nested-undelimited-precedence.rs:40:9
+ --> $DIR/nested-undelimited-precedence.rs:38:9
|
LL | let &mut A(_) | B(_): F = A(3);
| ^^^^^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(&mut A(_) | B(_))`
error: top-level or-patterns are not allowed in `let` bindings
- --> $DIR/nested-undelimited-precedence.rs:42:9
+ --> $DIR/nested-undelimited-precedence.rs:40:9
|
LL | let &&mut A(_) | B(_): F = A(3);
| ^^^^^^^^^^^^^^^^^ help: wrap the pattern in parentheses: `(&&mut A(_) | B(_))`
error[E0408]: variable `b` is not bound in all patterns
- --> $DIR/nested-undelimited-precedence.rs:21:17
+ --> $DIR/nested-undelimited-precedence.rs:19:17
|
LL | let b @ A | B: E = A;
| - ^ pattern doesn't bind `b`
| variable not in all patterns
error[E0308]: mismatched types
- --> $DIR/nested-undelimited-precedence.rs:36:9
+ --> $DIR/nested-undelimited-precedence.rs:34:9
|
LL | let &A(_) | B(_): F = A(3);
| ^^^^^ - expected due to this
found reference `&_`
error[E0308]: mismatched types
- --> $DIR/nested-undelimited-precedence.rs:38:9
+ --> $DIR/nested-undelimited-precedence.rs:36:9
|
LL | let &&A(_) | B(_): F = A(3);
| ^^^^^^ - expected due to this
found reference `&_`
error[E0308]: mismatched types
- --> $DIR/nested-undelimited-precedence.rs:40:9
+ --> $DIR/nested-undelimited-precedence.rs:38:9
|
LL | let &mut A(_) | B(_): F = A(3);
| ^^^^^^^^^ - expected due to this
found mutable reference `&mut _`
error[E0308]: mismatched types
- --> $DIR/nested-undelimited-precedence.rs:42:9
+ --> $DIR/nested-undelimited-precedence.rs:40:9
|
LL | let &&mut A(_) | B(_): F = A(3);
| ^^^^^^^^^^ - expected due to this
// edition:2018
-#![feature(or_patterns)]
-
fn main() {}
// Test the `pat` macro fragment parser:
error: no rules expected the token `|`
- --> $DIR/or-patterns-syntactic-fail-2018.rs:14:15
+ --> $DIR/or-patterns-syntactic-fail-2018.rs:12:15
|
LL | macro_rules! accept_pat {
| ----------------------- when calling this macro
| ^ no rules expected this token in macro call
error: no rules expected the token `|`
- --> $DIR/or-patterns-syntactic-fail-2018.rs:15:13
+ --> $DIR/or-patterns-syntactic-fail-2018.rs:13:13
|
LL | macro_rules! accept_pat {
| ----------------------- when calling this macro
--- /dev/null
+#[derive(Debug, Clone)]; //~ERROR expected item after attributes
+struct Foo;
+
+fn main() {}
--- /dev/null
+error: expected item after attributes
+ --> $DIR/attr-with-a-semicolon.rs:1:1
+ |
+LL | #[derive(Debug, Clone)];
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: consider removing this semicolon
+ |
+LL - #[derive(Debug, Clone)];
+LL + #[derive(Debug, Clone)]
+ |
+
+error: aborting due to previous error
+
type A where 'a: 'b + 'c = u8; // OK
type A where = u8; // OK
type A where 'a: 'b + = u8; // OK
-type A where , = u8; //~ ERROR expected one of `;`, `=`, lifetime, or type, found `,`
+type A where , = u8; //~ ERROR expected one of `;`, `=`, `where`, lifetime, or type, found `,`
fn main() {}
-error: expected one of `;`, `=`, lifetime, or type, found `,`
+error: expected one of `;`, `=`, `where`, lifetime, or type, found `,`
--> $DIR/bounds-lifetime-where.rs:8:14
|
LL | type A where , = u8;
- | ^ expected one of `;`, `=`, lifetime, or type
+ | ^ expected one of `;`, `=`, `where`, lifetime, or type
error: aborting due to previous error
| ^ help: remove this semicolon
error[E0601]: `main` function not found in crate `issue_49040`
- --> $DIR/issue-49040.rs:1:1
+ --> $DIR/issue-49040.rs:1:29
|
LL | #![allow(unused_variables)];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ consider adding a `main` function to `$DIR/issue-49040.rs`
+ | ^ consider adding a `main` function to `$DIR/issue-49040.rs`
error: aborting due to 2 previous errors
-type bptr = &lifetime/isize; //~ ERROR expected one of `!`, `(`, `::`, `;`, or `<`, found `/`
+type bptr = &lifetime/isize; //~ ERROR expected one of `!`, `(`, `::`, `;`, `<`, or `where`, found `/`
-error: expected one of `!`, `(`, `::`, `;`, or `<`, found `/`
+error: expected one of `!`, `(`, `::`, `;`, `<`, or `where`, found `/`
--> $DIR/removed-syntax-ptr-lifetime.rs:1:22
|
LL | type bptr = &lifetime/isize;
- | ^ expected one of `!`, `(`, `::`, `;`, or `<`
+ | ^ expected one of `!`, `(`, `::`, `;`, `<`, or `where`
error: aborting due to previous error
--- /dev/null
+macro_rules! fn_expr {
+ ($return_type:ty : $body:expr) => {
+ (|| -> $return_type { $body })()
+ };
+ ($body:expr) => {
+ (|| $body)()
+ };
+}
+
+
+fn main() {
+ fn_expr!{ o?.when(|&i| i > 0)?.when(|&i| i%2 == 0) };
+ //~^ ERROR cannot find value `o` in this scope
+}
--- /dev/null
+error[E0425]: cannot find value `o` in this scope
+ --> $DIR/trailing-question-in-macro-type.rs:12:15
+ |
+LL | fn_expr!{ o?.when(|&i| i > 0)?.when(|&i| i%2 == 0) };
+ | ^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
--- /dev/null
+// check-pass
+// run-rustfix
+
+#![feature(generic_associated_types)]
+
+trait Trait {
+ // Fine.
+ type Assoc where u32: Copy;
+ // Fine.
+ type Assoc2 where u32: Copy, i32: Copy;
+}
+
+impl Trait for u32 {
+ // Not fine, suggests moving.
+ type Assoc = () where u32: Copy;
+ //~^ WARNING where clause not allowed here
+ // Not fine, suggests moving `u32: Copy`
+ type Assoc2 = () where i32: Copy, u32: Copy;
+ //~^ WARNING where clause not allowed here
+}
+
+impl Trait for i32 {
+ // Fine.
+ type Assoc = () where u32: Copy;
+ // Not fine, suggests moving both.
+ type Assoc2 = () where u32: Copy, i32: Copy;
+ //~^ WARNING where clause not allowed here
+}
+
+fn main() {}
--- /dev/null
+// check-pass
+// run-rustfix
+
+#![feature(generic_associated_types)]
+
+trait Trait {
+ // Fine.
+ type Assoc where u32: Copy;
+ // Fine.
+ type Assoc2 where u32: Copy, i32: Copy;
+}
+
+impl Trait for u32 {
+ // Not fine, suggests moving.
+ type Assoc where u32: Copy = ();
+ //~^ WARNING where clause not allowed here
+ // Not fine, suggests moving `u32: Copy`
+ type Assoc2 where u32: Copy = () where i32: Copy;
+ //~^ WARNING where clause not allowed here
+}
+
+impl Trait for i32 {
+ // Fine.
+ type Assoc = () where u32: Copy;
+ // Not fine, suggests moving both.
+ type Assoc2 where u32: Copy, i32: Copy = ();
+ //~^ WARNING where clause not allowed here
+}
+
+fn main() {}
--- /dev/null
+warning: where clause not allowed here
+ --> $DIR/type-alias-where-fixable.rs:15:16
+ |
+LL | type Assoc where u32: Copy = ();
+ | ^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(deprecated_where_clause_location)]` on by default
+ = note: see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
+help: move it to the end of the type declaration
+ |
+LL - type Assoc where u32: Copy = ();
+LL + type Assoc = () where u32: Copy;
+ |
+
+warning: where clause not allowed here
+ --> $DIR/type-alias-where-fixable.rs:18:17
+ |
+LL | type Assoc2 where u32: Copy = () where i32: Copy;
+ | ^^^^^^^^^^^^^^^
+ |
+ = note: see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
+help: move it to the end of the type declaration
+ |
+LL - type Assoc2 where u32: Copy = () where i32: Copy;
+LL + type Assoc2 = () where i32: Copy, u32: Copy;
+ |
+
+warning: where clause not allowed here
+ --> $DIR/type-alias-where-fixable.rs:26:17
+ |
+LL | type Assoc2 where u32: Copy, i32: Copy = ();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
+help: move it to the end of the type declaration
+ |
+LL - type Assoc2 where u32: Copy, i32: Copy = ();
+LL + type Assoc2 = () where u32: Copy, i32: Copy;
+ |
+
+warning: 3 warnings emitted
+
type Foo where u32: Copy = ();
// Not fine.
type Bar = () where u32: Copy;
-//~^ ERROR where clause not allowed here
+//~^ ERROR where clauses are not allowed
type Baz = () where;
-//~^ ERROR where clause not allowed here
-
-trait Trait {
- // Fine.
- type Assoc where u32: Copy;
- // Fine.
- type Assoc2 where u32: Copy, i32: Copy;
-}
-
-impl Trait for u32 {
- // Fine.
- type Assoc where u32: Copy = ();
- // Not fine, suggests moving `i32: Copy`
- type Assoc2 where u32: Copy = () where i32: Copy;
- //~^ ERROR where clause not allowed here
-}
-
-impl Trait for i32 {
- // Not fine, suggests moving `u32: Copy`
- type Assoc = () where u32: Copy;
- //~^ ERROR where clause not allowed here
- // Not fine, suggests moving both.
- type Assoc2 = () where u32: Copy, i32: Copy;
- //~^ ERROR where clause not allowed here
-}
+//~^ ERROR where clauses are not allowed
fn main() {}
-error: where clause not allowed here
+error: where clauses are not allowed after the type for type aliases
--> $DIR/type-alias-where.rs:8:15
|
LL | type Bar = () where u32: Copy;
- | - ^^^^^^^^^^^^^^^
- | |
- | help: move it here: `where u32: Copy`
+ | ^^^^^^^^^^^^^^^
+ |
+ = note: see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
-error: where clause not allowed here
+error: where clauses are not allowed after the type for type aliases
--> $DIR/type-alias-where.rs:10:15
|
LL | type Baz = () where;
| ^^^^^
-
-error: where clause not allowed here
- --> $DIR/type-alias-where.rs:24:38
- |
-LL | type Assoc2 where u32: Copy = () where i32: Copy;
- | - ^^^^^^^^^^^^^^^
- | |
- | help: move it here: `, i32: Copy`
-
-error: where clause not allowed here
- --> $DIR/type-alias-where.rs:30:21
- |
-LL | type Assoc = () where u32: Copy;
- | - ^^^^^^^^^^^^^^^
- | |
- | help: move it here: `where u32: Copy`
-
-error: where clause not allowed here
- --> $DIR/type-alias-where.rs:33:22
|
-LL | type Assoc2 = () where u32: Copy, i32: Copy;
- | - ^^^^^^^^^^^^^^^^^^^^^^^^^^
- | |
- | help: move it here: `where u32: Copy, i32: Copy`
+ = note: see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
-error: aborting due to 5 previous errors
+error: aborting due to 2 previous errors
LL | match uninhab_ref() {
| ^^^^^^^^^^^^^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&!`
= note: references are always considered inhabited
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match uninhab_ref() {
+LL + _ => todo!(),
+LL + }
+ |
error[E0004]: non-exhaustive patterns: type `Foo` is non-empty
--> $DIR/always-inhabited-union-ref.rs:27:11
|
-LL | / pub union Foo {
-LL | | foo: !,
-LL | | }
- | |_- `Foo` defined here
-...
-LL | match uninhab_union() {
- | ^^^^^^^^^^^^^^^
+LL | match uninhab_union() {
+ | ^^^^^^^^^^^^^^^
+ |
+note: `Foo` defined here
+ --> $DIR/always-inhabited-union-ref.rs:10:11
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | pub union Foo {
+ | ^^^
= note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match uninhab_union() {
+LL + _ => todo!(),
+LL + }
+ |
error: aborting due to 2 previous errors
LL | match Foo::A {
| ^^^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Foo` defined here
+ --> $DIR/auxiliary/hidden.rs:1:1
+ |
+LL | / pub enum Foo {
+LL | | A,
+LL | | B,
+LL | | #[doc(hidden)]
+LL | | C,
+LL | | }
+ | |_^
= note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ Foo::B => {}
+LL + _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `B` not covered
--> $DIR/doc-hidden-non-exhaustive.rs:14:11
LL | match Foo::A {
| ^^^^^^ pattern `B` not covered
|
- ::: $DIR/auxiliary/hidden.rs:3:5
+note: `Foo` defined here
+ --> $DIR/auxiliary/hidden.rs:3:5
|
-LL | B,
- | - not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | / pub enum Foo {
+LL | | A,
+LL | | B,
+ | | ^ not covered
+LL | | #[doc(hidden)]
+LL | | C,
+LL | | }
+ | |_-
= note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ Foo::C => {}
+LL + B => todo!()
+ |
error[E0004]: non-exhaustive patterns: `B` and `_` not covered
--> $DIR/doc-hidden-non-exhaustive.rs:20:11
LL | match Foo::A {
| ^^^^^^ patterns `B` and `_` not covered
|
- ::: $DIR/auxiliary/hidden.rs:3:5
+note: `Foo` defined here
+ --> $DIR/auxiliary/hidden.rs:3:5
|
-LL | B,
- | - not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | / pub enum Foo {
+LL | | A,
+LL | | B,
+ | | ^ not covered
+LL | | #[doc(hidden)]
+LL | | C,
+LL | | }
+ | |_-
= note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ Foo::A => {}
+LL + B | _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `Some(B)` and `Some(_)` not covered
--> $DIR/doc-hidden-non-exhaustive.rs:25:11
LL | match None {
| ^^^^ patterns `Some(B)` and `Some(_)` not covered
|
- ::: $SRC_DIR/core/src/option.rs:LL:COL
+note: `Option<Foo>` defined here
+ --> $SRC_DIR/core/src/option.rs:LL:COL
|
-LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
- | ---- not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | / pub enum Option<T> {
+LL | | /// No value.
+LL | | #[lang = "None"]
+LL | | #[stable(feature = "rust1", since = "1.0.0")]
+... |
+LL | | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+ | | ^^^^ not covered
+LL | | }
+ | |_-
= note: the matched value is of type `Option<Foo>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ Some(Foo::A) => {}
+LL + Some(B) | Some(_) => todo!()
+ |
error: aborting due to 4 previous errors
LL | match_no_arms!(0u8);
| ^^^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty
--> $DIR/empty-match.rs:79:20
|
-LL | struct NonEmptyStruct1;
- | ----------------------- `NonEmptyStruct1` defined here
-...
LL | match_no_arms!(NonEmptyStruct1);
| ^^^^^^^^^^^^^^^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyStruct1` defined here
+ --> $DIR/empty-match.rs:14:8
+ |
+LL | struct NonEmptyStruct1;
+ | ^^^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyStruct1`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty
--> $DIR/empty-match.rs:80:20
|
-LL | struct NonEmptyStruct2(bool);
- | ----------------------------- `NonEmptyStruct2` defined here
-...
LL | match_no_arms!(NonEmptyStruct2(true));
| ^^^^^^^^^^^^^^^^^^^^^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyStruct2` defined here
+ --> $DIR/empty-match.rs:15:8
+ |
+LL | struct NonEmptyStruct2(bool);
+ | ^^^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyStruct2`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty
--> $DIR/empty-match.rs:81:20
|
-LL | / union NonEmptyUnion1 {
-LL | | foo: (),
-LL | | }
- | |_- `NonEmptyUnion1` defined here
-...
-LL | match_no_arms!((NonEmptyUnion1 { foo: () }));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | match_no_arms!((NonEmptyUnion1 { foo: () }));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: `NonEmptyUnion1` defined here
+ --> $DIR/empty-match.rs:16:7
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | union NonEmptyUnion1 {
+ | ^^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyUnion1`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty
--> $DIR/empty-match.rs:82:20
|
-LL | / union NonEmptyUnion2 {
-LL | | foo: (),
-LL | | bar: (),
-LL | | }
- | |_- `NonEmptyUnion2` defined here
-...
-LL | match_no_arms!((NonEmptyUnion2 { foo: () }));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | match_no_arms!((NonEmptyUnion2 { foo: () }));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: `NonEmptyUnion2` defined here
+ --> $DIR/empty-match.rs:19:7
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | union NonEmptyUnion2 {
+ | ^^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyUnion2`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
--> $DIR/empty-match.rs:83:20
|
-LL | / enum NonEmptyEnum1 {
-LL | | Foo(bool),
- | | --- not covered
-LL | | }
- | |_- `NonEmptyEnum1` defined here
-...
-LL | match_no_arms!(NonEmptyEnum1::Foo(true));
- | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+LL | match_no_arms!(NonEmptyEnum1::Foo(true));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyEnum1` defined here
+ --> $DIR/empty-match.rs:24:5
+ |
+LL | enum NonEmptyEnum1 {
+ | -------------
+LL | Foo(bool),
+ | ^^^ not covered
= note: the matched value is of type `NonEmptyEnum1`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern
error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
--> $DIR/empty-match.rs:84:20
|
-LL | / enum NonEmptyEnum2 {
-LL | | Foo(bool),
- | | --- not covered
-LL | | Bar,
- | | --- not covered
-LL | | }
- | |_- `NonEmptyEnum2` defined here
-...
-LL | match_no_arms!(NonEmptyEnum2::Foo(true));
- | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | match_no_arms!(NonEmptyEnum2::Foo(true));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+ |
+note: `NonEmptyEnum2` defined here
+ --> $DIR/empty-match.rs:27:5
+ |
+LL | enum NonEmptyEnum2 {
+ | -------------
+LL | Foo(bool),
+ | ^^^ not covered
+LL | Bar,
+ | ^^^ not covered
= note: the matched value is of type `NonEmptyEnum2`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms
error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
--> $DIR/empty-match.rs:85:20
|
-LL | / enum NonEmptyEnum5 {
-LL | | V1, V2, V3, V4, V5,
-LL | | }
- | |_- `NonEmptyEnum5` defined here
-...
-LL | match_no_arms!(NonEmptyEnum5::V1);
- | ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+LL | match_no_arms!(NonEmptyEnum5::V1);
+ | ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+ |
+note: `NonEmptyEnum5` defined here
+ --> $DIR/empty-match.rs:30:6
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum NonEmptyEnum5 {
+ | ^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyEnum5`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/empty-match.rs:87:24
LL | match_guarded_arm!(0u8);
| ^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered
--> $DIR/empty-match.rs:88:24
|
-LL | struct NonEmptyStruct1;
- | ----------------------- `NonEmptyStruct1` defined here
-...
LL | match_guarded_arm!(NonEmptyStruct1);
| ^^^^^^^^^^^^^^^ pattern `NonEmptyStruct1` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyStruct1` defined here
+ --> $DIR/empty-match.rs:14:8
+ |
+LL | struct NonEmptyStruct1;
+ | ^^^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyStruct1`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + NonEmptyStruct1 => todo!()
+ |
error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered
--> $DIR/empty-match.rs:89:24
|
-LL | struct NonEmptyStruct2(bool);
- | ----------------------------- `NonEmptyStruct2` defined here
-...
LL | match_guarded_arm!(NonEmptyStruct2(true));
| ^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct2(_)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyStruct2` defined here
+ --> $DIR/empty-match.rs:15:8
+ |
+LL | struct NonEmptyStruct2(bool);
+ | ^^^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyStruct2`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + NonEmptyStruct2(_) => todo!()
+ |
error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered
--> $DIR/empty-match.rs:90:24
|
-LL | / union NonEmptyUnion1 {
-LL | | foo: (),
-LL | | }
- | |_- `NonEmptyUnion1` defined here
-...
-LL | match_guarded_arm!((NonEmptyUnion1 { foo: () }));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
+LL | match_guarded_arm!((NonEmptyUnion1 { foo: () }));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
+ |
+note: `NonEmptyUnion1` defined here
+ --> $DIR/empty-match.rs:16:7
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | union NonEmptyUnion1 {
+ | ^^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyUnion1`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + NonEmptyUnion1 { .. } => todo!()
+ |
error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered
--> $DIR/empty-match.rs:91:24
|
-LL | / union NonEmptyUnion2 {
-LL | | foo: (),
-LL | | bar: (),
-LL | | }
- | |_- `NonEmptyUnion2` defined here
-...
-LL | match_guarded_arm!((NonEmptyUnion2 { foo: () }));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
+LL | match_guarded_arm!((NonEmptyUnion2 { foo: () }));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
+ |
+note: `NonEmptyUnion2` defined here
+ --> $DIR/empty-match.rs:19:7
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | union NonEmptyUnion2 {
+ | ^^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyUnion2`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + NonEmptyUnion2 { .. } => todo!()
+ |
error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
--> $DIR/empty-match.rs:92:24
|
-LL | / enum NonEmptyEnum1 {
-LL | | Foo(bool),
- | | --- not covered
-LL | | }
- | |_- `NonEmptyEnum1` defined here
-...
-LL | match_guarded_arm!(NonEmptyEnum1::Foo(true));
- | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+LL | match_guarded_arm!(NonEmptyEnum1::Foo(true));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyEnum1` defined here
+ --> $DIR/empty-match.rs:24:5
+ |
+LL | enum NonEmptyEnum1 {
+ | -------------
+LL | Foo(bool),
+ | ^^^ not covered
= note: the matched value is of type `NonEmptyEnum1`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + Foo(_) => todo!()
+ |
error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
--> $DIR/empty-match.rs:93:24
|
-LL | / enum NonEmptyEnum2 {
-LL | | Foo(bool),
- | | --- not covered
-LL | | Bar,
- | | --- not covered
-LL | | }
- | |_- `NonEmptyEnum2` defined here
-...
-LL | match_guarded_arm!(NonEmptyEnum2::Foo(true));
- | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | match_guarded_arm!(NonEmptyEnum2::Foo(true));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+ |
+note: `NonEmptyEnum2` defined here
+ --> $DIR/empty-match.rs:27:5
+ |
+LL | enum NonEmptyEnum2 {
+ | -------------
+LL | Foo(bool),
+ | ^^^ not covered
+LL | Bar,
+ | ^^^ not covered
= note: the matched value is of type `NonEmptyEnum2`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ _ if false => {}
+LL + Foo(_) | Bar => todo!()
+ |
error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
--> $DIR/empty-match.rs:94:24
|
-LL | / enum NonEmptyEnum5 {
-LL | | V1, V2, V3, V4, V5,
-LL | | }
- | |_- `NonEmptyEnum5` defined here
-...
-LL | match_guarded_arm!(NonEmptyEnum5::V1);
- | ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+LL | match_guarded_arm!(NonEmptyEnum5::V1);
+ | ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+ |
+note: `NonEmptyEnum5` defined here
+ --> $DIR/empty-match.rs:30:6
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum NonEmptyEnum5 {
+ | ^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyEnum5`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ _ if false => {}
+LL + _ => todo!()
+ |
error: aborting due to 22 previous errors
LL | match_no_arms!(0u8);
| ^^^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty
--> $DIR/empty-match.rs:79:20
|
-LL | struct NonEmptyStruct1;
- | ----------------------- `NonEmptyStruct1` defined here
-...
LL | match_no_arms!(NonEmptyStruct1);
| ^^^^^^^^^^^^^^^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyStruct1` defined here
+ --> $DIR/empty-match.rs:14:8
+ |
+LL | struct NonEmptyStruct1;
+ | ^^^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyStruct1`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty
--> $DIR/empty-match.rs:80:20
|
-LL | struct NonEmptyStruct2(bool);
- | ----------------------------- `NonEmptyStruct2` defined here
-...
LL | match_no_arms!(NonEmptyStruct2(true));
| ^^^^^^^^^^^^^^^^^^^^^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyStruct2` defined here
+ --> $DIR/empty-match.rs:15:8
+ |
+LL | struct NonEmptyStruct2(bool);
+ | ^^^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyStruct2`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty
--> $DIR/empty-match.rs:81:20
|
-LL | / union NonEmptyUnion1 {
-LL | | foo: (),
-LL | | }
- | |_- `NonEmptyUnion1` defined here
-...
-LL | match_no_arms!((NonEmptyUnion1 { foo: () }));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | match_no_arms!((NonEmptyUnion1 { foo: () }));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: `NonEmptyUnion1` defined here
+ --> $DIR/empty-match.rs:16:7
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | union NonEmptyUnion1 {
+ | ^^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyUnion1`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty
--> $DIR/empty-match.rs:82:20
|
-LL | / union NonEmptyUnion2 {
-LL | | foo: (),
-LL | | bar: (),
-LL | | }
- | |_- `NonEmptyUnion2` defined here
-...
-LL | match_no_arms!((NonEmptyUnion2 { foo: () }));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | match_no_arms!((NonEmptyUnion2 { foo: () }));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: `NonEmptyUnion2` defined here
+ --> $DIR/empty-match.rs:19:7
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | union NonEmptyUnion2 {
+ | ^^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyUnion2`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
--> $DIR/empty-match.rs:83:20
|
-LL | / enum NonEmptyEnum1 {
-LL | | Foo(bool),
- | | --- not covered
-LL | | }
- | |_- `NonEmptyEnum1` defined here
-...
-LL | match_no_arms!(NonEmptyEnum1::Foo(true));
- | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+LL | match_no_arms!(NonEmptyEnum1::Foo(true));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyEnum1` defined here
+ --> $DIR/empty-match.rs:24:5
+ |
+LL | enum NonEmptyEnum1 {
+ | -------------
+LL | Foo(bool),
+ | ^^^ not covered
= note: the matched value is of type `NonEmptyEnum1`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern
error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
--> $DIR/empty-match.rs:84:20
|
-LL | / enum NonEmptyEnum2 {
-LL | | Foo(bool),
- | | --- not covered
-LL | | Bar,
- | | --- not covered
-LL | | }
- | |_- `NonEmptyEnum2` defined here
-...
-LL | match_no_arms!(NonEmptyEnum2::Foo(true));
- | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | match_no_arms!(NonEmptyEnum2::Foo(true));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+ |
+note: `NonEmptyEnum2` defined here
+ --> $DIR/empty-match.rs:27:5
+ |
+LL | enum NonEmptyEnum2 {
+ | -------------
+LL | Foo(bool),
+ | ^^^ not covered
+LL | Bar,
+ | ^^^ not covered
= note: the matched value is of type `NonEmptyEnum2`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms
error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
--> $DIR/empty-match.rs:85:20
|
-LL | / enum NonEmptyEnum5 {
-LL | | V1, V2, V3, V4, V5,
-LL | | }
- | |_- `NonEmptyEnum5` defined here
-...
-LL | match_no_arms!(NonEmptyEnum5::V1);
- | ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+LL | match_no_arms!(NonEmptyEnum5::V1);
+ | ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+ |
+note: `NonEmptyEnum5` defined here
+ --> $DIR/empty-match.rs:30:6
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum NonEmptyEnum5 {
+ | ^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyEnum5`
+ = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/empty-match.rs:87:24
LL | match_guarded_arm!(0u8);
| ^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered
--> $DIR/empty-match.rs:88:24
|
-LL | struct NonEmptyStruct1;
- | ----------------------- `NonEmptyStruct1` defined here
-...
LL | match_guarded_arm!(NonEmptyStruct1);
| ^^^^^^^^^^^^^^^ pattern `NonEmptyStruct1` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyStruct1` defined here
+ --> $DIR/empty-match.rs:14:8
+ |
+LL | struct NonEmptyStruct1;
+ | ^^^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyStruct1`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + NonEmptyStruct1 => todo!()
+ |
error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered
--> $DIR/empty-match.rs:89:24
|
-LL | struct NonEmptyStruct2(bool);
- | ----------------------------- `NonEmptyStruct2` defined here
-...
LL | match_guarded_arm!(NonEmptyStruct2(true));
| ^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct2(_)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyStruct2` defined here
+ --> $DIR/empty-match.rs:15:8
+ |
+LL | struct NonEmptyStruct2(bool);
+ | ^^^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyStruct2`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + NonEmptyStruct2(_) => todo!()
+ |
error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered
--> $DIR/empty-match.rs:90:24
|
-LL | / union NonEmptyUnion1 {
-LL | | foo: (),
-LL | | }
- | |_- `NonEmptyUnion1` defined here
-...
-LL | match_guarded_arm!((NonEmptyUnion1 { foo: () }));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
+LL | match_guarded_arm!((NonEmptyUnion1 { foo: () }));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
+ |
+note: `NonEmptyUnion1` defined here
+ --> $DIR/empty-match.rs:16:7
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | union NonEmptyUnion1 {
+ | ^^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyUnion1`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + NonEmptyUnion1 { .. } => todo!()
+ |
error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered
--> $DIR/empty-match.rs:91:24
|
-LL | / union NonEmptyUnion2 {
-LL | | foo: (),
-LL | | bar: (),
-LL | | }
- | |_- `NonEmptyUnion2` defined here
-...
-LL | match_guarded_arm!((NonEmptyUnion2 { foo: () }));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
+LL | match_guarded_arm!((NonEmptyUnion2 { foo: () }));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
+ |
+note: `NonEmptyUnion2` defined here
+ --> $DIR/empty-match.rs:19:7
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | union NonEmptyUnion2 {
+ | ^^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyUnion2`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + NonEmptyUnion2 { .. } => todo!()
+ |
error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
--> $DIR/empty-match.rs:92:24
|
-LL | / enum NonEmptyEnum1 {
-LL | | Foo(bool),
- | | --- not covered
-LL | | }
- | |_- `NonEmptyEnum1` defined here
-...
-LL | match_guarded_arm!(NonEmptyEnum1::Foo(true));
- | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+LL | match_guarded_arm!(NonEmptyEnum1::Foo(true));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonEmptyEnum1` defined here
+ --> $DIR/empty-match.rs:24:5
+ |
+LL | enum NonEmptyEnum1 {
+ | -------------
+LL | Foo(bool),
+ | ^^^ not covered
= note: the matched value is of type `NonEmptyEnum1`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ _ if false => {}
+LL + Foo(_) => todo!()
+ |
error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
--> $DIR/empty-match.rs:93:24
|
-LL | / enum NonEmptyEnum2 {
-LL | | Foo(bool),
- | | --- not covered
-LL | | Bar,
- | | --- not covered
-LL | | }
- | |_- `NonEmptyEnum2` defined here
-...
-LL | match_guarded_arm!(NonEmptyEnum2::Foo(true));
- | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | match_guarded_arm!(NonEmptyEnum2::Foo(true));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+ |
+note: `NonEmptyEnum2` defined here
+ --> $DIR/empty-match.rs:27:5
+ |
+LL | enum NonEmptyEnum2 {
+ | -------------
+LL | Foo(bool),
+ | ^^^ not covered
+LL | Bar,
+ | ^^^ not covered
= note: the matched value is of type `NonEmptyEnum2`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ _ if false => {}
+LL + Foo(_) | Bar => todo!()
+ |
error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
--> $DIR/empty-match.rs:94:24
|
-LL | / enum NonEmptyEnum5 {
-LL | | V1, V2, V3, V4, V5,
-LL | | }
- | |_- `NonEmptyEnum5` defined here
-...
-LL | match_guarded_arm!(NonEmptyEnum5::V1);
- | ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+LL | match_guarded_arm!(NonEmptyEnum5::V1);
+ | ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+ |
+note: `NonEmptyEnum5` defined here
+ --> $DIR/empty-match.rs:30:6
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum NonEmptyEnum5 {
+ | ^^^^^^^^^^^^^
= note: the matched value is of type `NonEmptyEnum5`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ _ if false => {}
+LL + _ => todo!()
+ |
error: aborting due to 22 previous errors
LL | match 0.0 {
| ^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `f64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ 0.0..=1.0 => {}
+LL + _ => todo!()
+ |
error: unreachable pattern
--> $DIR/floats.rs:16:7
LL | match 0u8 {
| ^^^ pattern `128_u8..=u8::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ 128 ..= 255 if true => {}
+LL + 128_u8..=u8::MAX => todo!()
+ |
error: aborting due to previous error
#![feature(exclusive_range_pattern)]
-#![feature(assoc_char_consts)]
#![allow(overlapping_range_endpoints)]
#![deny(unreachable_patterns)]
error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
- --> $DIR/exhaustiveness.rs:48:8
+ --> $DIR/exhaustiveness.rs:47:8
|
LL | m!(0u8, 0..255);
| ^^^ pattern `u8::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ u8::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
- --> $DIR/exhaustiveness.rs:49:8
+ --> $DIR/exhaustiveness.rs:48:8
|
LL | m!(0u8, 0..=254);
| ^^^ pattern `u8::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ u8::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `0_u8` not covered
- --> $DIR/exhaustiveness.rs:50:8
+ --> $DIR/exhaustiveness.rs:49:8
|
LL | m!(0u8, 1..=255);
| ^^^ pattern `0_u8` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 0_u8 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `42_u8` not covered
- --> $DIR/exhaustiveness.rs:51:8
+ --> $DIR/exhaustiveness.rs:50:8
|
LL | m!(0u8, 0..42 | 43..=255);
| ^^^ pattern `42_u8` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 42_u8 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
- --> $DIR/exhaustiveness.rs:52:8
+ --> $DIR/exhaustiveness.rs:51:8
|
LL | m!(0i8, -128..127);
| ^^^ pattern `i8::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i8::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
- --> $DIR/exhaustiveness.rs:53:8
+ --> $DIR/exhaustiveness.rs:52:8
|
LL | m!(0i8, -128..=126);
| ^^^ pattern `i8::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i8::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `i8::MIN` not covered
- --> $DIR/exhaustiveness.rs:54:8
+ --> $DIR/exhaustiveness.rs:53:8
|
LL | m!(0i8, -127..=127);
| ^^^ pattern `i8::MIN` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ i8::MIN => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `0_i8` not covered
- --> $DIR/exhaustiveness.rs:55:11
+ --> $DIR/exhaustiveness.rs:54:11
|
LL | match 0i8 {
| ^^^ pattern `0_i8` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ 1 ..= i8::MAX => {}
+LL + 0_i8 => todo!()
+ |
error[E0004]: non-exhaustive patterns: `u128::MAX` not covered
- --> $DIR/exhaustiveness.rs:60:8
+ --> $DIR/exhaustiveness.rs:59:8
|
LL | m!(0u128, 0..=ALMOST_MAX);
| ^^^^^ pattern `u128::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ u128::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `5_u128..=u128::MAX` not covered
- --> $DIR/exhaustiveness.rs:61:8
+ --> $DIR/exhaustiveness.rs:60:8
|
LL | m!(0u128, 0..=4);
| ^^^^^ pattern `5_u128..=u128::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 5_u128..=u128::MAX => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `0_u128` not covered
- --> $DIR/exhaustiveness.rs:62:8
+ --> $DIR/exhaustiveness.rs:61:8
|
LL | m!(0u128, 1..=u128::MAX);
| ^^^^^ pattern `0_u128` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ 0_u128 => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `(126_u8..=127_u8, false)` not covered
- --> $DIR/exhaustiveness.rs:70:11
+ --> $DIR/exhaustiveness.rs:69:11
|
LL | match (0u8, true) {
| ^^^^^^^^^^^ pattern `(126_u8..=127_u8, false)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(u8, bool)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ (0 ..= 255, true) => {}
+LL + (126_u8..=127_u8, false) => todo!()
+ |
error: aborting due to 12 previous errors
LL | match 7usize {}
| ^^^^^^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `usize`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match 7usize {
+LL + _ => todo!(),
+LL + }
+ |
error: aborting due to previous error
LL | match 0usize {
| ^^^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `usize`
= note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ 0 ..= usize::MAX => {}
+LL + _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/pointer-sized-int.rs:17:11
LL | match 0isize {
| ^^^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `isize`
= note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ isize::MIN ..= isize::MAX => {}
+LL + _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/pointer-sized-int.rs:22:8
LL | m!(0usize, 0..=usize::MAX);
| ^^^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `usize`
= note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ _ => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/pointer-sized-int.rs:24:8
LL | m!(0usize, 0..5 | 5..=usize::MAX);
| ^^^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `usize`
= note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ _ => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/pointer-sized-int.rs:26:8
LL | m!(0usize, 0..usize::MAX | usize::MAX);
| ^^^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `usize`
= note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ _ => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `(_, _)` not covered
--> $DIR/pointer-sized-int.rs:28:8
LL | m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false));
| ^^^^^^^^^^^^^^ pattern `(_, _)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(usize, bool)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ (_, _) => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/pointer-sized-int.rs:31:8
LL | m!(0isize, isize::MIN..=isize::MAX);
| ^^^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `isize`
= note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ _ => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/pointer-sized-int.rs:33:8
LL | m!(0isize, isize::MIN..5 | 5..=isize::MAX);
| ^^^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `isize`
= note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ _ => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/pointer-sized-int.rs:35:8
LL | m!(0isize, isize::MIN..isize::MAX | isize::MAX);
| ^^^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `isize`
= note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ _ => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `(_, _)` not covered
--> $DIR/pointer-sized-int.rs:37:8
LL | m!((0isize, true), (isize::MIN..5, true)
| ^^^^^^^^^^^^^^ pattern `(_, _)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(isize, bool)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match $s { $($t)+ => {}
+LL ~ (_, _) => todo!() }
+ |
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/pointer-sized-int.rs:41:11
LL | match 0isize {
| ^^^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `isize`
= note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ 1 ..= isize::MAX => {}
+LL + _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: type `usize` is non-empty
--> $DIR/pointer-sized-int.rs:48:11
LL | match 7usize {}
| ^^^^^^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `usize`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match 7usize {
+LL + _ => todo!(),
+LL + }
+ |
error: aborting due to 12 previous errors
LL | match 0usize {
| ^^^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `usize`
= note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ 0..=usize::MAX => {}
+LL + _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/precise_pointer_matching-message.rs:11:11
LL | match 0isize {
| ^^^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `isize`
= note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ isize::MIN..=isize::MAX => {}
+LL + _ => todo!()
+ |
error: aborting due to 2 previous errors
LL | match (T::T1(()), V::V2(true)) {
| ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `(T1(()), V2(_))` and `(T2(()), V1(_))` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(T, V)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ (T::T2(()), V::V2(b)) => (),
+LL ~ (T1(()), V2(_)) | (T2(()), V1(_)) => todo!(),
+ |
error: aborting due to previous error
LL | match (a, b) {
| ^^^^^^ patterns `(None, None)` and `(Some(_), Some(_))` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(Option<usize>, Option<usize>)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ (Some(_), None) | (None, Some(_)) => {}
+LL + (None, None) | (Some(_), Some(_)) => todo!()
+ |
error: aborting due to previous error
LL | match "world" {
| ^^^^^^^ pattern `&_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&str`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ "hello" => {}
+LL + &_ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&_` not covered
--> $DIR/issue-30240.rs:6:11
LL | match "world" {
| ^^^^^^^ pattern `&_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&str`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ "hello" => {}
+LL + &_ => todo!()
+ |
error: aborting due to 2 previous errors
LL | match () { }
| ^^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `()`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match () {
+LL + _ => todo!(),
+LL ~ }
+ |
error: aborting due to previous error
LL | match x { }
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `*const Bottom`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error: aborting due to previous error
error[E0005]: refutable pattern in local binding: `Bar` and `Baz` not covered
--> $DIR/issue-31561.rs:8:9
|
-LL | / enum Thing {
-LL | | Foo(u8),
-LL | | Bar,
- | | --- not covered
-LL | | Baz
- | | --- not covered
-LL | | }
- | |_- `Thing` defined here
-...
-LL | let Thing::Foo(y) = Thing::Foo(1);
- | ^^^^^^^^^^^^^ patterns `Bar` and `Baz` not covered
+LL | let Thing::Foo(y) = Thing::Foo(1);
+ | ^^^^^^^^^^^^^ patterns `Bar` and `Baz` not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Thing` defined here
+ --> $DIR/issue-31561.rs:3:5
+ |
+LL | enum Thing {
+ | -----
+LL | Foo(u8),
+LL | Bar,
+ | ^^^ not covered
+LL | Baz
+ | ^^^ not covered
= note: the matched value is of type `Thing`
help: you might want to use `if let` to ignore the variant that isn't matched
|
LL | match (A, ()) {
| ^^^^^^^ patterns `(B, _)`, `(C, _)`, `(D, _)` and 2 more not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(Enum, ())`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ (A, _) => {}
+LL + _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `(_, B)`, `(_, C)`, `(_, D)` and 2 more not covered
--> $DIR/issue-35609.rs:14:11
LL | match (A, A) {
| ^^^^^^ patterns `(_, B)`, `(_, C)`, `(_, D)` and 2 more not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(Enum, Enum)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ (_, A) => {}
+LL + _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
--> $DIR/issue-35609.rs:18:11
LL | match ((A, ()), ()) {
| ^^^^^^^^^^^^^ patterns `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `((Enum, ()), ())`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ ((A, ()), _) => {}
+LL + _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
--> $DIR/issue-35609.rs:22:11
LL | match ((A, ()), A) {
| ^^^^^^^^^^^^ patterns `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `((Enum, ()), Enum)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ ((A, ()), _) => {}
+LL + _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
--> $DIR/issue-35609.rs:26:11
LL | match ((A, ()), ()) {
| ^^^^^^^^^^^^^ patterns `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `((Enum, ()), ())`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ ((A, _), _) => {}
+LL + _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `S(B, _)`, `S(C, _)`, `S(D, _)` and 2 more not covered
--> $DIR/issue-35609.rs:31:11
|
-LL | struct S(Enum, ());
- | ------------------- `S` defined here
-...
LL | match S(A, ()) {
| ^^^^^^^^ patterns `S(B, _)`, `S(C, _)`, `S(D, _)` and 2 more not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `S` defined here
+ --> $DIR/issue-35609.rs:6:8
+ |
+LL | struct S(Enum, ());
+ | ^
= note: the matched value is of type `S`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ S(A, _) => {}
+LL + _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `Sd { x: B, .. }`, `Sd { x: C, .. }`, `Sd { x: D, .. }` and 2 more not covered
--> $DIR/issue-35609.rs:35:11
|
-LL | struct Sd { x: Enum, y: () }
- | ---------------------------- `Sd` defined here
-...
LL | match (Sd { x: A, y: () }) {
| ^^^^^^^^^^^^^^^^^^^^ patterns `Sd { x: B, .. }`, `Sd { x: C, .. }`, `Sd { x: D, .. }` and 2 more not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Sd` defined here
+ --> $DIR/issue-35609.rs:7:8
+ |
+LL | struct Sd { x: Enum, y: () }
+ | ^^
= note: the matched value is of type `Sd`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ Sd { x: A, y: _ } => {}
+LL + _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `Some(B)`, `Some(C)`, `Some(D)` and 2 more not covered
--> $DIR/issue-35609.rs:39:11
LL | match Some(A) {
| ^^^^^^^ patterns `Some(B)`, `Some(C)`, `Some(D)` and 2 more not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Option<Enum>` defined here
+ --> $SRC_DIR/core/src/option.rs:LL:COL
+ |
+LL | / pub enum Option<T> {
+LL | | /// No value.
+LL | | #[lang = "None"]
+LL | | #[stable(feature = "rust1", since = "1.0.0")]
+... |
+LL | | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+LL | | }
+ | |_^
= note: the matched value is of type `Option<Enum>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ None => (),
+LL + _ => todo!()
+ |
error: aborting due to 8 previous errors
LL | box NodeKind::Element(ed) => match ed.kind {
| ^^^^^^^ pattern `box _` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Box<ElementKind>` defined here
+ --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
+ |
+LL | / pub struct Box<
+LL | | T: ?Sized,
+LL | | #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
+LL | | >(Unique<T>, A);
+ | |________________^
= note: the matched value is of type `Box<ElementKind>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ box ElementKind::HTMLImageElement(ref d) if d.image.is_some() => { true }
+LL + box _ => todo!()
+ |
error: aborting due to previous error
error[E0004]: non-exhaustive patterns: `Bar { bar: C, .. }`, `Bar { bar: D, .. }`, `Bar { bar: E, .. }` and 1 more not covered
--> $DIR/issue-39362.rs:10:11
|
-LL | / enum Foo {
-LL | | Bar { bar: Bar, id: usize }
-LL | | }
- | |_- `Foo` defined here
-...
-LL | match f {
- | ^ patterns `Bar { bar: C, .. }`, `Bar { bar: D, .. }`, `Bar { bar: E, .. }` and 1 more not covered
+LL | match f {
+ | ^ patterns `Bar { bar: C, .. }`, `Bar { bar: D, .. }`, `Bar { bar: E, .. }` and 1 more not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Foo` defined here
+ --> $DIR/issue-39362.rs:2:5
+ |
+LL | enum Foo {
+ | ---
+LL | Bar { bar: Bar, id: usize }
+ | ^^^ not covered
= note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ Foo::Bar { bar: Bar::B, .. } => (),
+LL ~ _ => todo!(),
+ |
error: aborting due to previous error
error[E0004]: non-exhaustive patterns: `C(QA)` not covered
--> $DIR/issue-40221.rs:11:11
|
-LL | / enum P {
-LL | | C(PC),
- | | - not covered
-LL | | }
- | |_- `P` defined here
-...
-LL | match proto {
- | ^^^^^ pattern `C(QA)` not covered
+LL | match proto {
+ | ^^^^^ pattern `C(QA)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `P` defined here
+ --> $DIR/issue-40221.rs:2:5
+ |
+LL | enum P {
+ | -
+LL | C(PC),
+ | ^ not covered
= note: the matched value is of type `P`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ P::C(PC::Q) => (),
+LL ~ C(QA) => todo!(),
+ |
error: aborting due to previous error
LL | println!("foo {:}", match tup {
| ^^^ pattern `(true, false)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(bool, bool)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ (true, true) => "baz",
+LL + (true, false) => todo!()
+ |
error: aborting due to previous error
error[E0004]: non-exhaustive patterns: `Tag(Exif, _)` not covered
--> $DIR/issue-50900.rs:15:11
|
-LL | pub struct Tag(pub Context, pub u16);
- | ------------------------------------- `Tag` defined here
-...
LL | match Tag::ExifIFDPointer {
| ^^^^^^^^^^^^^^^^^^^ pattern `Tag(Exif, _)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Tag` defined here
+ --> $DIR/issue-50900.rs:2:12
+ |
+LL | pub struct Tag(pub Context, pub u16);
+ | ^^^
= note: the matched value is of type `Tag`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ Tag::ExifIFDPointer => {}
+LL + Tag(Exif, _) => todo!()
+ |
error: aborting due to previous error
error[E0004]: non-exhaustive patterns: `A(false)`, `B(false)` and `C(false)` not covered
--> $DIR/issue-56379.rs:8:11
|
-LL | / enum Foo {
-LL | | A(bool),
- | | - not covered
-LL | | B(bool),
- | | - not covered
-LL | | C(bool),
- | | - not covered
-LL | | }
- | |_- `Foo` defined here
-...
-LL | match Foo::A(true) {
- | ^^^^^^^^^^^^ patterns `A(false)`, `B(false)` and `C(false)` not covered
+LL | match Foo::A(true) {
+ | ^^^^^^^^^^^^ patterns `A(false)`, `B(false)` and `C(false)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Foo` defined here
+ --> $DIR/issue-56379.rs:2:5
+ |
+LL | enum Foo {
+ | ---
+LL | A(bool),
+ | ^ not covered
+LL | B(bool),
+ | ^ not covered
+LL | C(bool),
+ | ^ not covered
= note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ Foo::C(true) => {}
+LL + A(false) | B(false) | C(false) => todo!()
+ |
error: aborting due to previous error
LL | match (x, y) {
| ^^^^^^ patterns `(A, Some(A))`, `(A, Some(B))`, `(B, Some(B))` and 2 more not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(X, Option<X>)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ (X::A, Some(X::C)) | (X::C, Some(X::A)) => false,
+LL ~ _ => todo!(),
+ |
error: aborting due to previous error
enum A {}
//~^ NOTE `A` defined here
+ //~| NOTE
fn f(a: &A) {
match a {}
error[E0004]: non-exhaustive patterns: type `&A` is non-empty
- --> $DIR/issue-78123-non-exhaustive-reference.rs:5:11
+ --> $DIR/issue-78123-non-exhaustive-reference.rs:6:11
|
-LL | enum A {}
- | --------- `A` defined here
-...
LL | match a {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `A` defined here
+ --> $DIR/issue-78123-non-exhaustive-reference.rs:1:6
+ |
+LL | enum A {}
+ | ^
= note: the matched value is of type `&A`
= note: references are always considered inhabited
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match a {
+LL + _ => todo!(),
+LL + }
+ |
error: aborting due to previous error
LL | match (true, false) {
| ^^^^^^^^^^^^^ pattern `(true, false)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(bool, bool)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ (false, true) => (),
+LL + (true, false) => todo!()
+ |
error[E0004]: non-exhaustive patterns: `Some(Some(West))` not covered
--> $DIR/match-arm-statics-2.rs:29:11
LL | match Some(Some(North)) {
| ^^^^^^^^^^^^^^^^^ pattern `Some(Some(West))` not covered
|
- ::: $SRC_DIR/core/src/option.rs:LL:COL
+note: `Option<Option<Direction>>` defined here
+ --> $SRC_DIR/core/src/option.rs:LL:COL
+ |
+LL | / pub enum Option<T> {
+LL | | /// No value.
+LL | | #[lang = "None"]
+LL | | #[stable(feature = "rust1", since = "1.0.0")]
+... |
+LL | | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+ | | ^^^^
+ | | |
+ | | not covered
+ | | not covered
+LL | | }
+ | |_-
+ = note: the matched value is of type `Option<Option<Direction>>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
-LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
- | ----
- | |
- | not covered
- | not covered
+LL ~ None => (),
+LL + Some(Some(West)) => todo!()
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `Option<Option<Direction>>`
error[E0004]: non-exhaustive patterns: `Foo { bar: Some(North), baz: NewBool(true) }` not covered
--> $DIR/match-arm-statics-2.rs:48:11
|
-LL | / struct Foo {
-LL | | bar: Option<Direction>,
-LL | | baz: NewBool
-LL | | }
- | |_- `Foo` defined here
-...
-LL | match (Foo { bar: Some(North), baz: NewBool(true) }) {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo { bar: Some(North), baz: NewBool(true) }` not covered
+LL | match (Foo { bar: Some(North), baz: NewBool(true) }) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo { bar: Some(North), baz: NewBool(true) }` not covered
+ |
+note: `Foo` defined here
+ --> $DIR/match-arm-statics-2.rs:40:8
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | struct Foo {
+ | ^^^
= note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ Foo { bar: Some(EAST), .. } => (),
+LL + Foo { bar: Some(North), baz: NewBool(true) } => todo!()
+ |
error: aborting due to 3 previous errors
LL | match buf {
| ^^^ patterns `&[0_u8..=64_u8, _, _, _]` and `&[66_u8..=u8::MAX, _, _, _]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[u8; 4]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ b"AAAA" => {}
+LL + &[0_u8..=64_u8, _, _, _] | &[66_u8..=u8::MAX, _, _, _] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[]`, `&[_]`, `&[_, _]` and 2 more not covered
--> $DIR/match-byte-array-patterns-2.rs:10:11
LL | match buf {
| ^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 2 more not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[u8]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ b"AAAA" => {}
+LL + _ => todo!()
+ |
error: aborting due to 2 previous errors
LL | match 0 { 1 => () }
| ^ patterns `i32::MIN..=0_i32` and `2_i32..=i32::MAX` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL | match 0 { 1 => (), i32::MIN..=0_i32 | 2_i32..=i32::MAX => todo!() }
+ | ++++++++++++++++++++++++++++++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/match-non-exhaustive.rs:3:11
LL | match 0 { 0 if false => () }
| ^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL | match 0 { 0 if false => (), _ => todo!() }
+ | ++++++++++++++
error: aborting due to 2 previous errors
LL | match private::DATA {
| ^^^^^^^^^^^^^ pattern `Some(Private { misc: true, .. })` not covered
|
- ::: $SRC_DIR/core/src/option.rs:LL:COL
+note: `Option<Private>` defined here
+ --> $SRC_DIR/core/src/option.rs:LL:COL
|
-LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
- | ---- not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | / pub enum Option<T> {
+LL | | /// No value.
+LL | | #[lang = "None"]
+LL | | #[stable(feature = "rust1", since = "1.0.0")]
+... |
+LL | | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+ | | ^^^^ not covered
+LL | | }
+ | |_-
= note: the matched value is of type `Option<Private>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ }) => {}
+LL + Some(Private { misc: true, .. }) => todo!()
+ |
error: aborting due to previous error
LL | match list {
| ^^^^ pattern `&[_, Some(_), .., None, _]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[Option<()>]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ &[.., Some(_), _] => {}
+LL ~ &[_, Some(_), .., None, _] => todo!(),
+ |
error: aborting due to previous error
#[derive(Clone)]
enum E {
-//~^ `E` defined here
-//~| `E` defined here
-//~| `E` defined here
-//~| `E` defined here
-//~| `E` defined here
-//~| `E` defined here
+ //~^ NOTE
+ //~| NOTE
+ //~| NOTE
+ //~| NOTE
+ //~| NOTE
+ //~| NOTE
A,
B,
- //~^ not covered
- //~| not covered
- //~| not covered
- //~| not covered
- //~| not covered
- //~| not covered
+ //~^ NOTE `E` defined here
+ //~| NOTE `E` defined here
+ //~| NOTE `E` defined here
+ //~| NOTE `E` defined here
+ //~| NOTE `E` defined here
+ //~| NOTE `E` defined here
+ //~| NOTE not covered
+ //~| NOTE not covered
+ //~| NOTE not covered
+ //~| NOTE not covered
+ //~| NOTE not covered
+ //~| NOTE not covered
C
//~^ not covered
//~| not covered
fn by_val(e: E) {
let e1 = e.clone();
match e1 { //~ ERROR non-exhaustive patterns: `B` and `C` not covered
+ //~^ NOTE patterns `B` and `C` not covered
+ //~| NOTE the matched value is of type `E`
E::A => {}
}
let E::A = e; //~ ERROR refutable pattern in local binding: `B` and `C` not covered
+ //~^ NOTE patterns `B` and `C` not covered
+ //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with
+ //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+ //~| NOTE the matched value is of type `E`
}
fn by_ref_once(e: &E) {
match e { //~ ERROR non-exhaustive patterns: `&B` and `&C` not covered
+ //~^ NOTE patterns `&B` and `&C` not covered
+ //~| NOTE the matched value is of type `&E`
E::A => {}
}
let E::A = e; //~ ERROR refutable pattern in local binding: `&B` and `&C` not covered
+ //~^ NOTE patterns `&B` and `&C` not covered
+ //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with
+ //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+ //~| NOTE the matched value is of type `&E`
}
fn by_ref_thrice(e: & &mut &E) {
match e { //~ ERROR non-exhaustive patterns: `&&mut &B` and `&&mut &C` not covered
+ //~^ NOTE patterns `&&mut &B` and `&&mut &C` not covered
+ //~| NOTE the matched value is of type `&&mut &E`
E::A => {}
}
let E::A = e;
//~^ ERROR refutable pattern in local binding: `&&mut &B` and `&&mut &C` not covered
+ //~| NOTE patterns `&&mut &B` and `&&mut &C` not covered
+ //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with
+ //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+ //~| NOTE the matched value is of type `&&mut &E`
}
enum Opt {
-//~^ `Opt` defined here
-//~| `Opt` defined here
+ //~^ NOTE
+ //~| NOTE
Some(u8),
None,
- //~^ not covered
+ //~^ NOTE `Opt` defined here
+ //~| NOTE `Opt` defined here
+ //~| NOTE not covered
+ //~| NOTE not covered
}
fn ref_pat(e: Opt) {
match e {//~ ERROR non-exhaustive patterns: `None` not covered
+ //~^ NOTE pattern `None` not covered
+ //~| NOTE the matched value is of type `Opt`
Opt::Some(ref _x) => {}
}
let Opt::Some(ref _x) = e; //~ ERROR refutable pattern in local binding: `None` not covered
+ //~^ NOTE the matched value is of type `Opt`
+ //~| NOTE pattern `None` not covered
+ //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with
+ //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
}
fn main() {}
error[E0004]: non-exhaustive patterns: `B` and `C` not covered
- --> $DIR/non-exhaustive-defined-here.rs:32:11
- |
-LL | / enum E {
-LL | |
-LL | |
-LL | |
-... |
-LL | | B,
- | | - not covered
-... |
-LL | | C
- | | - not covered
-... |
-LL | |
-LL | | }
- | |_- `E` defined here
-...
-LL | match e1 {
- | ^^ patterns `B` and `C` not covered
+ --> $DIR/non-exhaustive-defined-here.rs:38:11
+ |
+LL | match e1 {
+ | ^^ patterns `B` and `C` not covered
+ |
+note: `E` defined here
+ --> $DIR/non-exhaustive-defined-here.rs:14:5
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum E {
+ | -
+...
+LL | B,
+ | ^ not covered
+...
+LL | C
+ | ^ not covered
= note: the matched value is of type `E`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ E::A => {}
+LL + B | C => todo!()
+ |
error[E0005]: refutable pattern in local binding: `B` and `C` not covered
- --> $DIR/non-exhaustive-defined-here.rs:36:9
- |
-LL | / enum E {
-LL | |
-LL | |
-LL | |
-... |
-LL | | B,
- | | - not covered
-... |
-LL | | C
- | | - not covered
-... |
-LL | |
-LL | | }
- | |_- `E` defined here
-...
-LL | let E::A = e;
- | ^^^^ patterns `B` and `C` not covered
+ --> $DIR/non-exhaustive-defined-here.rs:44:9
+ |
+LL | let E::A = e;
+ | ^^^^ patterns `B` and `C` not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `E` defined here
+ --> $DIR/non-exhaustive-defined-here.rs:14:5
+ |
+LL | enum E {
+ | -
+...
+LL | B,
+ | ^ not covered
+...
+LL | C
+ | ^ not covered
= note: the matched value is of type `E`
help: you might want to use `if let` to ignore the variant that isn't matched
|
| ~~~~~~~~~~~~~~~~~~~~~~~~~
error[E0004]: non-exhaustive patterns: `&B` and `&C` not covered
- --> $DIR/non-exhaustive-defined-here.rs:40:11
- |
-LL | / enum E {
-LL | |
-LL | |
-LL | |
-... |
-LL | | B,
- | | - not covered
-... |
-LL | | C
- | | - not covered
-... |
-LL | |
-LL | | }
- | |_- `E` defined here
-...
-LL | match e {
- | ^ patterns `&B` and `&C` not covered
+ --> $DIR/non-exhaustive-defined-here.rs:52:11
+ |
+LL | match e {
+ | ^ patterns `&B` and `&C` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `E` defined here
+ --> $DIR/non-exhaustive-defined-here.rs:14:5
+ |
+LL | enum E {
+ | -
+...
+LL | B,
+ | ^ not covered
+...
+LL | C
+ | ^ not covered
= note: the matched value is of type `&E`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ E::A => {}
+LL + &B | &C => todo!()
+ |
error[E0005]: refutable pattern in local binding: `&B` and `&C` not covered
- --> $DIR/non-exhaustive-defined-here.rs:44:9
+ --> $DIR/non-exhaustive-defined-here.rs:58:9
|
-LL | / enum E {
-LL | |
-LL | |
-LL | |
-... |
-LL | | B,
- | | - not covered
-... |
-LL | | C
- | | - not covered
-... |
-LL | |
-LL | | }
- | |_- `E` defined here
-...
-LL | let E::A = e;
- | ^^^^ patterns `&B` and `&C` not covered
+LL | let E::A = e;
+ | ^^^^ patterns `&B` and `&C` not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `E` defined here
+ --> $DIR/non-exhaustive-defined-here.rs:14:5
+ |
+LL | enum E {
+ | -
+...
+LL | B,
+ | ^ not covered
+...
+LL | C
+ | ^ not covered
= note: the matched value is of type `&E`
help: you might want to use `if let` to ignore the variant that isn't matched
|
| ~~~~~~~~~~~~~~~~~~~~~~~~~
error[E0004]: non-exhaustive patterns: `&&mut &B` and `&&mut &C` not covered
- --> $DIR/non-exhaustive-defined-here.rs:48:11
- |
-LL | / enum E {
-LL | |
-LL | |
-LL | |
-... |
-LL | | B,
- | | - not covered
-... |
-LL | | C
- | | - not covered
-... |
-LL | |
-LL | | }
- | |_- `E` defined here
-...
-LL | match e {
- | ^ patterns `&&mut &B` and `&&mut &C` not covered
+ --> $DIR/non-exhaustive-defined-here.rs:66:11
+ |
+LL | match e {
+ | ^ patterns `&&mut &B` and `&&mut &C` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `E` defined here
+ --> $DIR/non-exhaustive-defined-here.rs:14:5
+ |
+LL | enum E {
+ | -
+...
+LL | B,
+ | ^ not covered
+...
+LL | C
+ | ^ not covered
= note: the matched value is of type `&&mut &E`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ E::A => {}
+LL + &&mut &B | &&mut &C => todo!()
+ |
error[E0005]: refutable pattern in local binding: `&&mut &B` and `&&mut &C` not covered
- --> $DIR/non-exhaustive-defined-here.rs:52:9
- |
-LL | / enum E {
-LL | |
-LL | |
-LL | |
-... |
-LL | | B,
- | | - not covered
-... |
-LL | | C
- | | - not covered
-... |
-LL | |
-LL | | }
- | |_- `E` defined here
-...
-LL | let E::A = e;
- | ^^^^ patterns `&&mut &B` and `&&mut &C` not covered
+ --> $DIR/non-exhaustive-defined-here.rs:72:9
+ |
+LL | let E::A = e;
+ | ^^^^ patterns `&&mut &B` and `&&mut &C` not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `E` defined here
+ --> $DIR/non-exhaustive-defined-here.rs:14:5
+ |
+LL | enum E {
+ | -
+...
+LL | B,
+ | ^ not covered
+...
+LL | C
+ | ^ not covered
= note: the matched value is of type `&&mut &E`
help: you might want to use `if let` to ignore the variant that isn't matched
|
|
error[E0004]: non-exhaustive patterns: `None` not covered
- --> $DIR/non-exhaustive-defined-here.rs:65:11
- |
-LL | / enum Opt {
-LL | |
-LL | |
-LL | | Some(u8),
-LL | | None,
- | | ---- not covered
-LL | |
-LL | | }
- | |_- `Opt` defined here
-...
-LL | match e {
- | ^ pattern `None` not covered
+ --> $DIR/non-exhaustive-defined-here.rs:92:11
+ |
+LL | match e {
+ | ^ pattern `None` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Opt` defined here
+ --> $DIR/non-exhaustive-defined-here.rs:84:5
+ |
+LL | enum Opt {
+ | ---
+...
+LL | None,
+ | ^^^^ not covered
= note: the matched value is of type `Opt`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ Opt::Some(ref _x) => {}
+LL + None => todo!()
+ |
error[E0005]: refutable pattern in local binding: `None` not covered
- --> $DIR/non-exhaustive-defined-here.rs:69:9
- |
-LL | / enum Opt {
-LL | |
-LL | |
-LL | | Some(u8),
-LL | | None,
- | | ---- not covered
-LL | |
-LL | | }
- | |_- `Opt` defined here
-...
-LL | let Opt::Some(ref _x) = e;
- | ^^^^^^^^^^^^^^^^^ pattern `None` not covered
+ --> $DIR/non-exhaustive-defined-here.rs:98:9
+ |
+LL | let Opt::Some(ref _x) = e;
+ | ^^^^^^^^^^^^^^^^^ pattern `None` not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Opt` defined here
+ --> $DIR/non-exhaustive-defined-here.rs:84:5
+ |
+LL | enum Opt {
+ | ---
+...
+LL | None,
+ | ^^^^ not covered
= note: the matched value is of type `Opt`
help: you might want to use `if let` to ignore the variant that isn't matched
|
LL | match (l1, l2) {
| ^^^^^^^^ pattern `(Some(&[]), Err(_))` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(Option<&[T]>, Result<&[T], ()>)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ (None, Ok(&[_, _, ..])) => "None, Ok(at least two elements)",
+LL + (Some(&[]), Err(_)) => todo!()
+ |
error[E0004]: non-exhaustive patterns: `A(C)` not covered
--> $DIR/non-exhaustive-match-nested.rs:15:11
|
-LL | enum T { A(U), B }
- | ------------------
- | | |
- | | not covered
- | `T` defined here
-...
LL | match x {
| ^ pattern `A(C)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `T` defined here
+ --> $DIR/non-exhaustive-match-nested.rs:1:10
+ |
+LL | enum T { A(U), B }
+ | - ^ not covered
= note: the matched value is of type `T`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ T::B => { panic!("goodbye"); }
+LL + A(C) => todo!()
+ |
error: aborting due to 2 previous errors
error[E0004]: non-exhaustive patterns: `A` not covered
--> $DIR/non-exhaustive-match.rs:7:11
|
-LL | enum T { A, B }
- | ---------------
- | | |
- | | not covered
- | `T` defined here
-...
LL | match x { T::B => { } }
| ^ pattern `A` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `T` defined here
+ --> $DIR/non-exhaustive-match.rs:3:10
+ |
+LL | enum T { A, B }
+ | - ^ not covered
= note: the matched value is of type `T`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL | match x { T::B => { } A => todo!() }
+ | ++++++++++++
error[E0004]: non-exhaustive patterns: `false` not covered
--> $DIR/non-exhaustive-match.rs:8:11
LL | match true {
| ^^^^ pattern `false` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `bool`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ true => {}
+LL + false => todo!()
+ |
error[E0004]: non-exhaustive patterns: `Some(_)` not covered
--> $DIR/non-exhaustive-match.rs:11:11
LL | match Some(10) {
| ^^^^^^^^ pattern `Some(_)` not covered
|
- ::: $SRC_DIR/core/src/option.rs:LL:COL
+note: `Option<i32>` defined here
+ --> $SRC_DIR/core/src/option.rs:LL:COL
+ |
+LL | / pub enum Option<T> {
+LL | | /// No value.
+LL | | #[lang = "None"]
+LL | | #[stable(feature = "rust1", since = "1.0.0")]
+... |
+LL | | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
+ | | ^^^^ not covered
+LL | | }
+ | |_-
+ = note: the matched value is of type `Option<i32>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
-LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
- | ---- not covered
+LL ~ None => {}
+LL + Some(_) => todo!()
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `Option<i32>`
error[E0004]: non-exhaustive patterns: `(_, _, i32::MIN..=3_i32)` and `(_, _, 5_i32..=i32::MAX)` not covered
--> $DIR/non-exhaustive-match.rs:14:11
LL | match (2, 3, 4) {
| ^^^^^^^^^ patterns `(_, _, i32::MIN..=3_i32)` and `(_, _, 5_i32..=i32::MAX)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(i32, i32, i32)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ (_, _, 4) => {}
+LL + (_, _, i32::MIN..=3_i32) | (_, _, 5_i32..=i32::MAX) => todo!()
+ |
error[E0004]: non-exhaustive patterns: `(A, A)` and `(B, B)` not covered
--> $DIR/non-exhaustive-match.rs:18:11
LL | match (T::A, T::A) {
| ^^^^^^^^^^^^ patterns `(A, A)` and `(B, B)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(T, T)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ (T::B, T::A) => {}
+LL + (A, A) | (B, B) => todo!()
+ |
error[E0004]: non-exhaustive patterns: `B` not covered
--> $DIR/non-exhaustive-match.rs:22:11
|
-LL | enum T { A, B }
- | ---------------
- | | |
- | | not covered
- | `T` defined here
-...
LL | match T::A {
| ^^^^ pattern `B` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `T` defined here
+ --> $DIR/non-exhaustive-match.rs:3:13
+ |
+LL | enum T { A, B }
+ | - ^ not covered
= note: the matched value is of type `T`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ T::A => {}
+LL + B => todo!()
+ |
error[E0004]: non-exhaustive patterns: `[]` not covered
--> $DIR/non-exhaustive-match.rs:33:11
LL | match *vec {
| ^^^^ pattern `[]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `[Option<isize>]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [None] => {}
+LL + [] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `[_, _, _, _, ..]` not covered
--> $DIR/non-exhaustive-match.rs:46:11
LL | match *vec {
| ^^^^ pattern `[_, _, _, _, ..]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `[f32]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [] => (),
+LL + [_, _, _, _, ..] => todo!()
+ |
error: aborting due to 8 previous errors
error[E0004]: non-exhaustive patterns: `Foo { first: false, second: Some([_, _, _, _]) }` not covered
--> $DIR/non-exhaustive-pattern-witness.rs:7:11
|
-LL | / struct Foo {
-LL | | first: bool,
-LL | | second: Option<[usize; 4]>
-LL | | }
- | |_- `Foo` defined here
-...
-LL | match (Foo { first: true, second: None }) {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo { first: false, second: Some([_, _, _, _]) }` not covered
+LL | match (Foo { first: true, second: None }) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo { first: false, second: Some([_, _, _, _]) }` not covered
+ |
+note: `Foo` defined here
+ --> $DIR/non-exhaustive-pattern-witness.rs:1:8
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | struct Foo {
+ | ^^^
= note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ Foo { first: false, second: Some([1, 2, 3, 4]) } => (),
+LL + Foo { first: false, second: Some([_, _, _, _]) } => todo!()
+ |
error[E0004]: non-exhaustive patterns: `Red` not covered
--> $DIR/non-exhaustive-pattern-witness.rs:23:11
|
-LL | / enum Color {
-LL | | Red,
- | | --- not covered
-LL | | Green,
-LL | | CustomRGBA { a: bool, r: u8, g: u8, b: u8 }
-LL | | }
- | |_- `Color` defined here
-...
-LL | match Color::Red {
- | ^^^^^^^^^^ pattern `Red` not covered
+LL | match Color::Red {
+ | ^^^^^^^^^^ pattern `Red` not covered
+ |
+note: `Color` defined here
+ --> $DIR/non-exhaustive-pattern-witness.rs:17:5
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum Color {
+ | -----
+LL | Red,
+ | ^^^ not covered
= note: the matched value is of type `Color`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ Color::Green => (),
+LL + Red => todo!()
+ |
error[E0004]: non-exhaustive patterns: `East`, `South` and `West` not covered
--> $DIR/non-exhaustive-pattern-witness.rs:35:11
|
-LL | / enum Direction {
-LL | | North, East, South, West
- | | ---- ----- ---- not covered
- | | | |
- | | | not covered
- | | not covered
-LL | | }
- | |_- `Direction` defined here
-...
-LL | match Direction::North {
- | ^^^^^^^^^^^^^^^^ patterns `East`, `South` and `West` not covered
+LL | match Direction::North {
+ | ^^^^^^^^^^^^^^^^ patterns `East`, `South` and `West` not covered
+ |
+note: `Direction` defined here
+ --> $DIR/non-exhaustive-pattern-witness.rs:31:12
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum Direction {
+ | ---------
+LL | North, East, South, West
+ | ^^^^ ^^^^^ ^^^^ not covered
+ | | |
+ | | not covered
+ | not covered
= note: the matched value is of type `Direction`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ Direction::North => (),
+LL + East | South | West => todo!()
+ |
error[E0004]: non-exhaustive patterns: `Second`, `Third`, `Fourth` and 8 more not covered
--> $DIR/non-exhaustive-pattern-witness.rs:46:11
|
-LL | / enum ExcessiveEnum {
-LL | | First, Second, Third, Fourth, Fifth, Sixth, Seventh, Eighth, Ninth, Tenth, Eleventh, Twelfth
-LL | | }
- | |_- `ExcessiveEnum` defined here
-...
-LL | match ExcessiveEnum::First {
- | ^^^^^^^^^^^^^^^^^^^^ patterns `Second`, `Third`, `Fourth` and 8 more not covered
+LL | match ExcessiveEnum::First {
+ | ^^^^^^^^^^^^^^^^^^^^ patterns `Second`, `Third`, `Fourth` and 8 more not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `ExcessiveEnum` defined here
+ --> $DIR/non-exhaustive-pattern-witness.rs:41:6
+ |
+LL | enum ExcessiveEnum {
+ | ^^^^^^^^^^^^^
= note: the matched value is of type `ExcessiveEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ ExcessiveEnum::First => (),
+LL + _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `CustomRGBA { a: true, .. }` not covered
--> $DIR/non-exhaustive-pattern-witness.rs:54:11
|
-LL | / enum Color {
-LL | | Red,
-LL | | Green,
-LL | | CustomRGBA { a: bool, r: u8, g: u8, b: u8 }
- | | ---------- not covered
-LL | | }
- | |_- `Color` defined here
-...
-LL | match Color::Red {
- | ^^^^^^^^^^ pattern `CustomRGBA { a: true, .. }` not covered
+LL | match Color::Red {
+ | ^^^^^^^^^^ pattern `CustomRGBA { a: true, .. }` not covered
+ |
+note: `Color` defined here
+ --> $DIR/non-exhaustive-pattern-witness.rs:19:5
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | enum Color {
+ | -----
+...
+LL | CustomRGBA { a: bool, r: u8, g: u8, b: u8 }
+ | ^^^^^^^^^^ not covered
= note: the matched value is of type `Color`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ Color::CustomRGBA { a: false, r: _, g: _, b: _ } => (),
+LL + CustomRGBA { a: true, .. } => todo!()
+ |
error[E0004]: non-exhaustive patterns: `[Second(true), Second(false)]` not covered
--> $DIR/non-exhaustive-pattern-witness.rs:70:11
LL | match *x {
| ^^ pattern `[Second(true), Second(false)]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `[Enum]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [_, _, ref tail @ .., _] => (),
+LL + [Second(true), Second(false)] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `((), false)` not covered
--> $DIR/non-exhaustive-pattern-witness.rs:83:11
LL | match ((), false) {
| ^^^^^^^^^^^ pattern `((), false)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `((), bool)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ ((), true) => (),
+LL + ((), false) => todo!()
+ |
error: aborting due to 7 previous errors
LL | match s2 {
| ^^ pattern `&[false, _]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool; 2]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [true, .., true] => {}
+LL + &[false, _] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[false, ..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:12:11
LL | match s3 {
| ^^ pattern `&[false, ..]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool; 3]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [true, .., true] => {}
+LL + &[false, ..] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[false, ..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:16:11
LL | match s10 {
| ^^^ pattern `&[false, ..]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool; 10]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [true, .., true] => {}
+LL + &[false, ..] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[false, true]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:25:11
LL | match s2 {
| ^^ pattern `&[false, true]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool; 2]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [.., false] => {}
+LL + &[false, true] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[false, .., true]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:30:11
LL | match s3 {
| ^^ pattern `&[false, .., true]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool; 3]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [.., false] => {}
+LL + &[false, .., true] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[false, .., true]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:35:11
LL | match s {
| ^ pattern `&[false, .., true]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [.., false] => {}
+LL + &[false, .., true] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:42:11
LL | match s {
| ^ pattern `&[_, ..]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [] => {}
+LL + &[_, ..] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:46:11
LL | match s {
| ^ pattern `&[_, _, ..]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [_] => {}
+LL + &[_, _, ..] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[false, ..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:51:11
LL | match s {
| ^ pattern `&[false, ..]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [true, ..] => {}
+LL + &[false, ..] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[false, _, ..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:56:11
LL | match s {
| ^ pattern `&[false, _, ..]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [true, ..] => {}
+LL + &[false, _, ..] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[_, .., false]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:62:11
LL | match s {
| ^ pattern `&[_, .., false]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [.., true] => {}
+LL + &[_, .., false] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[_, _, .., true]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:69:11
LL | match s {
| ^ pattern `&[_, _, .., true]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [.., false] => {}
+LL + &[_, _, .., true] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[true, _, .., _]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:76:11
LL | match s {
| ^ pattern `&[true, _, .., _]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [false, .., false] => {}
+LL + &[true, _, .., _] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:85:11
LL | match s {
| ^ patterns `&[]` and `&[_, _, ..]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ &[true] => {}
+LL + &[] | &[_, _, ..] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:89:11
LL | match s {
| ^ patterns `&[]` and `&[_, _, ..]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ CONST => {}
+LL + &[] | &[_, _, ..] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:93:11
LL | match s {
| ^ patterns `&[]` and `&[_, _, ..]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ &[false] => {}
+LL + &[] | &[_, _, ..] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:98:11
LL | match s {
| ^ patterns `&[]` and `&[_, _, ..]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ CONST => {}
+LL + &[] | &[_, _, ..] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:103:11
LL | match s {
| ^ pattern `&[_, _, ..]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ CONST => {}
+LL + &[_, _, ..] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[false]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:108:11
LL | match s {
| ^ pattern `&[false]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ &[_, _, ..] => {}
+LL + &[false] => todo!()
+ |
error[E0004]: non-exhaustive patterns: `&[false]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:121:11
LL | match s1 {
| ^^ pattern `&[false]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[bool; 1]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ CONST1 => {}
+LL + &[false] => todo!()
+ |
error: aborting due to 20 previous errors
LL | match Foo::Stable {
| ^^^^^^^^^^^ patterns `Stable2` and `_` not covered
|
- ::: $DIR/auxiliary/unstable.rs:9:5
+note: `Foo` defined here
+ --> $DIR/auxiliary/unstable.rs:9:5
|
-LL | Stable2,
- | ------- not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | / pub enum Foo {
+LL | | #[stable(feature = "stable_test_feature", since = "1.0.0")]
+LL | | Stable,
+LL | | #[stable(feature = "stable_test_feature", since = "1.0.0")]
+LL | | Stable2,
+ | | ^^^^^^^ not covered
+LL | | #[unstable(feature = "unstable_test_feature", issue = "none")]
+LL | | Unstable,
+LL | | }
+ | |_-
= note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ Foo::Stable => {}
+LL + Stable2 | _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/stable-gated-patterns.rs:13:11
LL | match Foo::Stable {
| ^^^^^^^^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Foo` defined here
+ --> $DIR/auxiliary/unstable.rs:5:1
+ |
+LL | / pub enum Foo {
+LL | | #[stable(feature = "stable_test_feature", since = "1.0.0")]
+LL | | Stable,
+LL | | #[stable(feature = "stable_test_feature", since = "1.0.0")]
+... |
+LL | | Unstable,
+LL | | }
+ | |_^
= note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ Foo::Stable2 => {}
+LL + _ => todo!()
+ |
error: aborting due to 2 previous errors
error[E0004]: non-exhaustive patterns: `B { x: Some(_) }` not covered
--> $DIR/struct-like-enum-nonexhaustive.rs:8:11
|
-LL | / enum A {
-LL | | B { x: Option<isize> },
- | | - not covered
-LL | | C
-LL | | }
- | |_- `A` defined here
-...
-LL | match x {
- | ^ pattern `B { x: Some(_) }` not covered
+LL | match x {
+ | ^ pattern `B { x: Some(_) }` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `A` defined here
+ --> $DIR/struct-like-enum-nonexhaustive.rs:2:5
+ |
+LL | enum A {
+ | -
+LL | B { x: Option<isize> },
+ | ^ not covered
= note: the matched value is of type `A`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ A::B { x: None } => {}
+LL + B { x: Some(_) } => todo!()
+ |
error: aborting due to previous error
error[E0004]: non-exhaustive patterns: `Foo(_, _)` not covered
--> $DIR/tuple-struct-nonexhaustive.rs:5:11
|
-LL | struct Foo(isize, isize);
- | ------------------------- `Foo` defined here
-...
LL | match x {
| ^ pattern `Foo(_, _)` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Foo` defined here
+ --> $DIR/tuple-struct-nonexhaustive.rs:1:8
+ |
+LL | struct Foo(isize, isize);
+ | ^^^
= note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ Foo(2, b) => println!("{}", b)
+LL + Foo(_, _) => todo!()
+ |
error: aborting due to previous error
LL | match data {
| ^^^^ pattern `&[_, ..]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[u8]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ b"" => 1,
+LL ~ &[_, ..] => todo!(),
+ |
error[E0004]: non-exhaustive patterns: `&[]`, `&[_]`, `&[_, _]` and 1 more not covered
--> $DIR/type_polymorphic_byte_str_literals.rs:23:11
LL | match data {
| ^^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 1 more not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[u8]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+ |
+LL ~ [_, _, _] => 1,
+LL ~ _ => todo!(),
+ |
error: aborting due to 2 previous errors
LL | match Foo::Stable {
| ^^^^^^^^^^^ pattern `Unstable` not covered
|
- ::: $DIR/auxiliary/unstable.rs:11:5
+note: `Foo` defined here
+ --> $DIR/auxiliary/unstable.rs:11:5
|
-LL | Unstable,
- | -------- not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | / pub enum Foo {
+LL | | #[stable(feature = "stable_test_feature", since = "1.0.0")]
+LL | | Stable,
+LL | | #[stable(feature = "stable_test_feature", since = "1.0.0")]
+... |
+LL | | Unstable,
+ | | ^^^^^^^^ not covered
+LL | | }
+ | |_-
= note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ Foo::Stable2 => {}
+LL + Unstable => todo!()
+ |
error: aborting due to previous error
-#![feature(pub_restricted)]
-
struct Bar(pub(()));
struct Foo {
error: expected identifier, found `(`
- --> $DIR/pub-restricted-error.rs:6:16
+ --> $DIR/pub-restricted-error.rs:4:16
|
LL | pub(crate) () foo: usize,
| ^ expected identifier
-#![feature(pub_restricted)]
-
mod a {}
pub (a) fn afn() {} //~ incorrect visibility restriction
error[E0704]: incorrect visibility restriction
- --> $DIR/pub-restricted.rs:5:6
+ --> $DIR/pub-restricted.rs:3:6
|
LL | pub (a) fn afn() {}
| ^ help: make this visible only to module `a` with `in`: `in a`
`pub(in path::to::module)`: visible only on the specified path
error[E0704]: incorrect visibility restriction
- --> $DIR/pub-restricted.rs:6:6
+ --> $DIR/pub-restricted.rs:4:6
|
LL | pub (b) fn bfn() {}
| ^ help: make this visible only to module `b` with `in`: `in b`
`pub(in path::to::module)`: visible only on the specified path
error[E0704]: incorrect visibility restriction
- --> $DIR/pub-restricted.rs:7:6
+ --> $DIR/pub-restricted.rs:5:6
|
LL | pub (crate::a) fn cfn() {}
| ^^^^^^^^ help: make this visible only to module `crate::a` with `in`: `in crate::a`
`pub(in path::to::module)`: visible only on the specified path
error[E0704]: incorrect visibility restriction
- --> $DIR/pub-restricted.rs:24:14
+ --> $DIR/pub-restricted.rs:22:14
|
LL | pub (a) invalid: usize,
| ^ help: make this visible only to module `a` with `in`: `in a`
`pub(in path::to::module)`: visible only on the specified path
error[E0704]: incorrect visibility restriction
- --> $DIR/pub-restricted.rs:33:6
+ --> $DIR/pub-restricted.rs:31:6
|
LL | pub (xyz) fn xyz() {}
| ^^^ help: make this visible only to module `xyz` with `in`: `in xyz`
`pub(in path::to::module)`: visible only on the specified path
error[E0742]: visibilities can only be restricted to ancestor modules
- --> $DIR/pub-restricted.rs:25:17
+ --> $DIR/pub-restricted.rs:23:17
|
LL | pub (in x) non_parent_invalid: usize,
| ^
LL | let Ok(x) = res;
| ^^^^^ pattern `Err(_)` not covered
|
- ::: $SRC_DIR/core/src/result.rs:LL:COL
- |
-LL | Err(#[stable(feature = "rust1", since = "1.0.0")] E),
- | --- not covered
- |
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Result<u32, &R>` defined here
+ --> $SRC_DIR/core/src/result.rs:LL:COL
+ |
+LL | / pub enum Result<T, E> {
+LL | | /// Contains the success value
+LL | | #[lang = "Ok"]
+LL | | #[stable(feature = "rust1", since = "1.0.0")]
+... |
+LL | | Err(#[stable(feature = "rust1", since = "1.0.0")] E),
+ | | ^^^ not covered
+LL | | }
+ | |_-
= note: the matched value is of type `Result<u32, &R>`
help: you might want to use `if let` to ignore the variant that isn't matched
|
+++ /dev/null
-error[E0565]: meta item in `repr` must be an identifier
- --> $DIR/issue-83921-pretty.rs:10:8
- |
-LL | #[repr("C")]
- | ^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0565`.
+++ /dev/null
-#![feature(prelude_import)]
-#![no_std]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
-#[macro_use]
-extern crate std;
-// Regression test for #83921. A `delay_span_bug()` call was issued, but the
-// error was never reported because the pass responsible for detecting and
-// reporting the error does not run in certain modes of pretty-printing.
-
-// Make sure the error is reported if we do not just pretty-print:
-// revisions: pretty normal
-// [pretty]compile-flags: -Zunpretty=everybody_loops
-// [pretty]check-pass
-#[repr("C")]
-struct A {}
-
-fn main() { loop {} }
+++ /dev/null
-// Regression test for #83921. A `delay_span_bug()` call was issued, but the
-// error was never reported because the pass responsible for detecting and
-// reporting the error does not run in certain modes of pretty-printing.
-
-// Make sure the error is reported if we do not just pretty-print:
-// revisions: pretty normal
-// [pretty]compile-flags: -Zunpretty=everybody_loops
-// [pretty]check-pass
-
-#[repr("C")]
-//[normal]~^ ERROR: meta item in `repr` must be an identifier [E0565]
-struct A {}
-
-fn main() {}
-#![feature(repr_align)]
-
// See also repr-transparent.rs
#[repr(transparent, C)] //~ ERROR cannot have other repr
error[E0692]: transparent struct cannot have other repr hints
- --> $DIR/repr-transparent-other-reprs.rs:5:8
+ --> $DIR/repr-transparent-other-reprs.rs:3:8
|
LL | #[repr(transparent, C)]
| ^^^^^^^^^^^ ^
error[E0692]: transparent struct cannot have other repr hints
- --> $DIR/repr-transparent-other-reprs.rs:10:8
+ --> $DIR/repr-transparent-other-reprs.rs:8:8
|
LL | #[repr(transparent, packed)]
| ^^^^^^^^^^^ ^^^^^^
error[E0692]: transparent struct cannot have other repr hints
- --> $DIR/repr-transparent-other-reprs.rs:13:8
+ --> $DIR/repr-transparent-other-reprs.rs:11:8
|
LL | #[repr(transparent, align(2))]
| ^^^^^^^^^^^ ^^^^^^^^
error[E0692]: transparent struct cannot have other repr hints
- --> $DIR/repr-transparent-other-reprs.rs:16:8
+ --> $DIR/repr-transparent-other-reprs.rs:14:8
|
LL | #[repr(transparent)]
| ^^^^^^^^^^^
LL | match sl {
| ^^ pattern `&[]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[u8]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ [first, remainder @ ..] => {}
+LL ~ &[] => todo!(),
+ |
error: aborting due to previous error
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `EmptyNonExhaustiveEnum` defined here
+ --> $DIR/auxiliary/enums.rs:18:1
+ |
+LL | pub enum EmptyNonExhaustiveEnum {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `EmptyNonExhaustiveEnum`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/enum.rs:16:11
LL | match enum_unit {
| ^^^^^^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonExhaustiveEnum` defined here
+ --> $DIR/auxiliary/enums.rs:4:1
+ |
+LL | / pub enum NonExhaustiveEnum {
+LL | | Unit,
+LL | | Tuple(u32),
+LL | | Struct { field: u32 },
+LL | | }
+ | |_^
= note: the matched value is of type `NonExhaustiveEnum`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ NonExhaustiveEnum::Struct { .. } => "third",
+LL + _ => todo!()
+ |
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/enum.rs:23:11
LL | match enum_unit {};
| ^^^^^^^^^ pattern `_` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `NonExhaustiveEnum` defined here
+ --> $DIR/auxiliary/enums.rs:4:1
+ |
+LL | / pub enum NonExhaustiveEnum {
+LL | | Unit,
+LL | | Tuple(u32),
+LL | | Struct { field: u32 },
+LL | | }
+ | |_^
= note: the matched value is of type `NonExhaustiveEnum`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ match enum_unit {
+LL + _ => todo!(),
+LL ~ };
+ |
error: aborting due to 3 previous errors
error[E0004]: non-exhaustive patterns: `Unit`, `Tuple(_)` and `Struct { .. }` not covered
--> $DIR/enum_same_crate_empty_match.rs:33:11
|
-LL | / pub enum NonExhaustiveEnum {
-LL | | Unit,
- | | ---- not covered
-LL | |
-LL | | Tuple(u32),
- | | ----- not covered
-LL | |
-LL | | Struct { field: u32 }
- | | ------ not covered
-LL | |
-LL | | }
- | |_- `NonExhaustiveEnum` defined here
-...
-LL | match NonExhaustiveEnum::Unit {}
- | ^^^^^^^^^^^^^^^^^^^^^^^ patterns `Unit`, `Tuple(_)` and `Struct { .. }` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | match NonExhaustiveEnum::Unit {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^ patterns `Unit`, `Tuple(_)` and `Struct { .. }` not covered
+ |
+note: `NonExhaustiveEnum` defined here
+ --> $DIR/enum_same_crate_empty_match.rs:5:5
+ |
+LL | pub enum NonExhaustiveEnum {
+ | -----------------
+LL | Unit,
+ | ^^^^ not covered
+LL |
+LL | Tuple(u32),
+ | ^^^^^ not covered
+LL |
+LL | Struct { field: u32 }
+ | ^^^^^^ not covered
= note: the matched value is of type `NonExhaustiveEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ match NonExhaustiveEnum::Unit {
+LL + Unit | Tuple(_) | Struct { .. } => todo!(),
+LL + }
+ |
error[E0004]: non-exhaustive patterns: `Unit`, `Tuple(_)` and `Struct { .. }` not covered
--> $DIR/enum_same_crate_empty_match.rs:35:11
|
-LL | / pub enum NormalEnum {
-LL | | Unit,
- | | ---- not covered
-LL | |
-LL | | Tuple(u32),
- | | ----- not covered
-LL | |
-LL | | Struct { field: u32 }
- | | ------ not covered
-LL | |
-LL | | }
- | |_- `NormalEnum` defined here
-...
-LL | match NormalEnum::Unit {}
- | ^^^^^^^^^^^^^^^^ patterns `Unit`, `Tuple(_)` and `Struct { .. }` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | match NormalEnum::Unit {}
+ | ^^^^^^^^^^^^^^^^ patterns `Unit`, `Tuple(_)` and `Struct { .. }` not covered
+ |
+note: `NormalEnum` defined here
+ --> $DIR/enum_same_crate_empty_match.rs:14:5
+ |
+LL | pub enum NormalEnum {
+ | ----------
+LL | Unit,
+ | ^^^^ not covered
+LL |
+LL | Tuple(u32),
+ | ^^^^^ not covered
+LL |
+LL | Struct { field: u32 }
+ | ^^^^^^ not covered
= note: the matched value is of type `NormalEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ match NormalEnum::Unit {
+LL + Unit | Tuple(_) | Struct { .. } => todo!(),
+LL + }
+ |
error: aborting due to 3 previous errors
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedEnum` defined here
+ --> $DIR/auxiliary/uninhabited.rs:26:1
+ |
+LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `IndirectUninhabitedEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedStruct` is non-empty
--> $DIR/indirect_match.rs:23:11
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedStruct` defined here
+ --> $DIR/auxiliary/uninhabited.rs:28:1
+ |
+LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `IndirectUninhabitedStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedTupleStruct` is non-empty
--> $DIR/indirect_match.rs:27:11
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedTupleStruct` defined here
+ --> $DIR/auxiliary/uninhabited.rs:30:1
+ |
+LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `IndirectUninhabitedTupleStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedVariants` is non-empty
--> $DIR/indirect_match.rs:33:11
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedVariants` defined here
+ --> $DIR/auxiliary/uninhabited.rs:32:1
+ |
+LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `IndirectUninhabitedVariants`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error: aborting due to 4 previous errors
error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedEnum` is non-empty
--> $DIR/indirect_match_same_crate.rs:34:11
|
-LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum);
- | ---------------------------------------------------- `IndirectUninhabitedEnum` defined here
-...
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedEnum` defined here
+ --> $DIR/indirect_match_same_crate.rs:20:12
+ |
+LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum);
+ | ^^^^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `IndirectUninhabitedEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedStruct` is non-empty
--> $DIR/indirect_match_same_crate.rs:38:11
|
-LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct);
- | -------------------------------------------------------- `IndirectUninhabitedStruct` defined here
-...
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedStruct` defined here
+ --> $DIR/indirect_match_same_crate.rs:22:12
+ |
+LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `IndirectUninhabitedStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedTupleStruct` is non-empty
--> $DIR/indirect_match_same_crate.rs:42:11
|
-LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
- | ------------------------------------------------------------------ `IndirectUninhabitedTupleStruct` defined here
-...
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedTupleStruct` defined here
+ --> $DIR/indirect_match_same_crate.rs:24:12
+ |
+LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `IndirectUninhabitedTupleStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedVariants` is non-empty
--> $DIR/indirect_match_same_crate.rs:48:11
|
-LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants);
- | ------------------------------------------------------------ `IndirectUninhabitedVariants` defined here
-...
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedVariants` defined here
+ --> $DIR/indirect_match_same_crate.rs:26:12
+ |
+LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `IndirectUninhabitedVariants`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error: aborting due to 4 previous errors
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedEnum` defined here
+ --> $DIR/auxiliary/uninhabited.rs:26:1
+ |
+LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `IndirectUninhabitedEnum`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedStruct` is non-empty
--> $DIR/indirect_match_with_exhaustive_patterns.rs:27:11
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedStruct` defined here
+ --> $DIR/auxiliary/uninhabited.rs:28:1
+ |
+LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `IndirectUninhabitedStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedTupleStruct` is non-empty
--> $DIR/indirect_match_with_exhaustive_patterns.rs:31:11
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedTupleStruct` defined here
+ --> $DIR/auxiliary/uninhabited.rs:30:1
+ |
+LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `IndirectUninhabitedTupleStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedVariants` is non-empty
--> $DIR/indirect_match_with_exhaustive_patterns.rs:37:11
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `IndirectUninhabitedVariants` defined here
+ --> $DIR/auxiliary/uninhabited.rs:32:1
+ |
+LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `IndirectUninhabitedVariants`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error: aborting due to 4 previous errors
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `UninhabitedEnum` defined here
+ --> $DIR/auxiliary/uninhabited.rs:5:1
+ |
+LL | / pub enum UninhabitedEnum {
+LL | | }
+ | |_^
= note: the matched value is of type `UninhabitedEnum`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty
--> $DIR/match.rs:23:11
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `UninhabitedStruct` defined here
+ --> $DIR/auxiliary/uninhabited.rs:9:1
+ |
+LL | / pub struct UninhabitedStruct {
+LL | | _priv: !,
+LL | | }
+ | |_^
= note: the matched value is of type `UninhabitedStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty
--> $DIR/match.rs:27:11
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `UninhabitedTupleStruct` defined here
+ --> $DIR/auxiliary/uninhabited.rs:14:1
+ |
+LL | pub struct UninhabitedTupleStruct(!);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `UninhabitedTupleStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered
--> $DIR/match.rs:31:11
LL | match x {}
| ^ patterns `Tuple(_)` and `Struct { .. }` not covered
|
- ::: $DIR/auxiliary/uninhabited.rs:17:23
+note: `UninhabitedVariants` defined here
+ --> $DIR/auxiliary/uninhabited.rs:17:23
|
-LL | #[non_exhaustive] Tuple(!),
- | ----- not covered
-LL | #[non_exhaustive] Struct { x: ! }
- | ------ not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | / pub enum UninhabitedVariants {
+LL | | #[non_exhaustive] Tuple(!),
+ | | ^^^^^ not covered
+LL | | #[non_exhaustive] Struct { x: ! }
+ | | ^^^^^^ not covered
+LL | | }
+ | |_-
= note: the matched value is of type `UninhabitedVariants`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ match x {
+LL + Tuple(_) | Struct { .. } => todo!(),
+LL ~ }
+ |
error: aborting due to 4 previous errors
error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty
--> $DIR/match_same_crate.rs:30:11
|
-LL | / pub struct UninhabitedStruct {
-LL | | _priv: !,
-LL | | }
- | |_- `UninhabitedStruct` defined here
-...
-LL | match x {}
- | ^
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | match x {}
+ | ^
+ |
+note: `UninhabitedStruct` defined here
+ --> $DIR/match_same_crate.rs:8:12
+ |
+LL | pub struct UninhabitedStruct {
+ | ^^^^^^^^^^^^^^^^^
= note: the matched value is of type `UninhabitedStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty
--> $DIR/match_same_crate.rs:34:11
|
-LL | pub struct UninhabitedTupleStruct(!);
- | ------------------------------------- `UninhabitedTupleStruct` defined here
-...
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `UninhabitedTupleStruct` defined here
+ --> $DIR/match_same_crate.rs:13:12
+ |
+LL | pub struct UninhabitedTupleStruct(!);
+ | ^^^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `UninhabitedTupleStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered
--> $DIR/match_same_crate.rs:38:11
|
-LL | / pub enum UninhabitedVariants {
-LL | | #[non_exhaustive] Tuple(!),
- | | ----- not covered
-LL | | #[non_exhaustive] Struct { x: ! }
- | | ------ not covered
-LL | | }
- | |_- `UninhabitedVariants` defined here
-...
-LL | match x {}
- | ^ patterns `Tuple(_)` and `Struct { .. }` not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | match x {}
+ | ^ patterns `Tuple(_)` and `Struct { .. }` not covered
+ |
+note: `UninhabitedVariants` defined here
+ --> $DIR/match_same_crate.rs:16:23
+ |
+LL | pub enum UninhabitedVariants {
+ | -------------------
+LL | #[non_exhaustive] Tuple(!),
+ | ^^^^^ not covered
+LL | #[non_exhaustive] Struct { x: ! }
+ | ^^^^^^ not covered
= note: the matched value is of type `UninhabitedVariants`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ match x {
+LL + Tuple(_) | Struct { .. } => todo!(),
+LL ~ }
+ |
error: aborting due to 3 previous errors
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `UninhabitedEnum` defined here
+ --> $DIR/auxiliary/uninhabited.rs:5:1
+ |
+LL | / pub enum UninhabitedEnum {
+LL | | }
+ | |_^
= note: the matched value is of type `UninhabitedEnum`, which is marked as non-exhaustive
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty
--> $DIR/match_with_exhaustive_patterns.rs:26:11
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `UninhabitedStruct` defined here
+ --> $DIR/auxiliary/uninhabited.rs:9:1
+ |
+LL | / pub struct UninhabitedStruct {
+LL | | _priv: !,
+LL | | }
+ | |_^
= note: the matched value is of type `UninhabitedStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty
--> $DIR/match_with_exhaustive_patterns.rs:30:11
LL | match x {}
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `UninhabitedTupleStruct` defined here
+ --> $DIR/auxiliary/uninhabited.rs:14:1
+ |
+LL | pub struct UninhabitedTupleStruct(!);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `UninhabitedTupleStruct`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ match x {
+LL + _ => todo!(),
+LL ~ }
+ |
error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered
--> $DIR/match_with_exhaustive_patterns.rs:34:11
LL | match x {}
| ^ patterns `Tuple(_)` and `Struct { .. }` not covered
|
- ::: $DIR/auxiliary/uninhabited.rs:17:23
+note: `UninhabitedVariants` defined here
+ --> $DIR/auxiliary/uninhabited.rs:17:23
|
-LL | #[non_exhaustive] Tuple(!),
- | ----- not covered
-LL | #[non_exhaustive] Struct { x: ! }
- | ------ not covered
- |
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+LL | / pub enum UninhabitedVariants {
+LL | | #[non_exhaustive] Tuple(!),
+ | | ^^^^^ not covered
+LL | | #[non_exhaustive] Struct { x: ! }
+ | | ^^^^^^ not covered
+LL | | }
+ | |_-
= note: the matched value is of type `UninhabitedVariants`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+ |
+LL ~ match x {
+LL + Tuple(_) | Struct { .. } => todo!(),
+LL ~ }
+ |
error: aborting due to 4 previous errors
warning: skipping const checks
|
-help: skipping check for `const_fn_fn_ptr_basics` feature
- --> $DIR/caller-location-fnptr-rt-ctfe-equiv.rs:20:9
- |
-LL | let ptr: fn() -> L = attributed;
- | ^^^
-help: skipping check for `const_fn_fn_ptr_basics` feature
- --> $DIR/caller-location-fnptr-rt-ctfe-equiv.rs:21:5
- |
-LL | ptr()
- | ^^^
-help: skipping check for `const_fn_fn_ptr_basics` feature
- --> $DIR/caller-location-fnptr-rt-ctfe-equiv.rs:20:26
- |
-LL | let ptr: fn() -> L = attributed;
- | ^^^^^^^^^^
help: skipping check that does not even have a feature gate
--> $DIR/caller-location-fnptr-rt-ctfe-equiv.rs:21:5
|
LL | ptr()
| ^^^^^
-error: `-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature gates, except when testing error paths in the CTFE engine
-
-error: aborting due to previous error; 1 warning emitted
+warning: 1 warning emitted
-#![feature(dyn_trait)]
#![feature(rustc_attrs)]
trait Trait<'x, T> where T: 'x {
error: rustc_outlives
- --> $DIR/explicit-dyn.rs:8:1
+ --> $DIR/explicit-dyn.rs:7:1
|
LL | / struct Foo<'a, A>
LL | | {
-#![feature(dyn_trait)]
#![feature(rustc_attrs)]
trait Trait<'x, 's, T> where T: 'x,
error: rustc_outlives
- --> $DIR/self-dyn.rs:9:1
+ --> $DIR/self-dyn.rs:8:1
|
LL | / struct Foo<'a, 'b, A>
LL | | {
-#![feature(crate_in_paths)]
-
struct S;
pub mod m {
error[E0433]: failed to resolve: `crate` in paths can only be used in start position
- --> $DIR/crate-path-non-absolute.rs:7:22
+ --> $DIR/crate-path-non-absolute.rs:5:22
|
LL | let s = ::m::crate::S;
| ^^^^^ `crate` in paths can only be used in start position
error[E0433]: failed to resolve: global paths cannot start with `crate`
- --> $DIR/crate-path-non-absolute.rs:8:20
+ --> $DIR/crate-path-non-absolute.rs:6:20
|
LL | let s1 = ::crate::S;
| ^^^^^ global paths cannot start with `crate`
-#![feature(crate_in_paths)]
-
fn main() {
let crate = 0;
//~^ ERROR expected unit struct, unit variant or constant, found module `crate`
error[E0532]: expected unit struct, unit variant or constant, found module `crate`
- --> $DIR/keyword-crate-as-identifier.rs:4:9
+ --> $DIR/keyword-crate-as-identifier.rs:2:9
|
LL | let crate = 0;
| ^^^^^ not a unit struct, unit variant or constant
-#![feature(const_fn_trait_bound)]
#![feature(const_trait_impl)]
pub trait MyTrait {
// check-pass
-#![feature(const_fn_trait_bound)]
#![feature(const_trait_impl)]
trait MyPartialEq {
// check-pass
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
struct S;
// check-pass
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
struct S;
-#![feature(const_fn_trait_bound)]
#![feature(const_trait_impl)]
pub const fn equals_self<T: PartialEq>(t: &T) -> bool {
error[E0277]: can't compare `T` with `T` in const contexts
- --> $DIR/call-generic-method-fail.rs:5:5
+ --> $DIR/call-generic-method-fail.rs:4:5
|
LL | *t == *t
| ^^^^^^^^ no implementation for `T == T`
|
note: the trait `PartialEq` is implemented for `T`, but that implementation is not `const`
- --> $DIR/call-generic-method-fail.rs:5:5
+ --> $DIR/call-generic-method-fail.rs:4:5
|
LL | *t == *t
| ^^^^^^^^
error[E0015]: cannot call non-const operator in constant functions
- --> $DIR/call-generic-method-fail.rs:5:5
+ --> $DIR/call-generic-method-fail.rs:4:5
|
LL | *t == *t
| ^^^^^^^^
// check-pass
-#![feature(const_fn_trait_bound)]
-
struct S;
impl PartialEq for S {
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
struct S;
error[E0277]: can't compare `S` with `S` in const contexts
- --> $DIR/call-generic-method-nonconst.rs:19:34
+ --> $DIR/call-generic-method-nonconst.rs:18:34
|
LL | pub const EQ: bool = equals_self(&S);
| ----------- ^^ no implementation for `S == S`
|
= help: the trait `~const PartialEq` is not implemented for `S`
note: the trait `PartialEq` is implemented for `S`, but that implementation is not `const`
- --> $DIR/call-generic-method-nonconst.rs:19:34
+ --> $DIR/call-generic-method-nonconst.rs:18:34
|
LL | pub const EQ: bool = equals_self(&S);
| ^^
note: required by a bound in `equals_self`
- --> $DIR/call-generic-method-nonconst.rs:12:25
+ --> $DIR/call-generic-method-nonconst.rs:11:25
|
LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool {
| ^^^^^^^^^^^^^^^^ required by this bound in `equals_self`
// check-pass
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
struct S;
// run-pass
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
const fn answer_p1<F>(f: &F) -> u8
where
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)] // FIXME is this needed?
trait ConstDefaultFn: Sized {
fn b(self);
error[E0277]: the trait bound `NonConstImpl: ~const ConstDefaultFn` is not satisfied
- --> $DIR/const-default-method-bodies.rs:25:18
+ --> $DIR/const-default-method-bodies.rs:24:18
|
LL | NonConstImpl.a();
| ^^^ the trait `~const ConstDefaultFn` is not implemented for `NonConstImpl`
|
note: the trait `ConstDefaultFn` is implemented for `NonConstImpl`, but that implementation is not `const`
- --> $DIR/const-default-method-bodies.rs:25:18
+ --> $DIR/const-default-method-bodies.rs:24:18
|
LL | NonConstImpl.a();
| ^^^
error[E0015]: cannot call non-const fn `<NonConstImpl as ConstDefaultFn>::a` in constant functions
- --> $DIR/const-default-method-bodies.rs:25:18
+ --> $DIR/const-default-method-bodies.rs:24:18
|
LL | NonConstImpl.a();
| ^^^
// check-pass
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
#![feature(const_precise_live_drops)]
const fn foo<T, E>(res: Result<T, E>) -> Option<T> where E: ~const Drop {
error[E0277]: the trait bound `NonTrivialDrop: ~const Drop` is not satisfied
- --> $DIR/const-drop-fail.rs:44:5
+ --> $DIR/const-drop-fail.rs:43:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
| ^^^^^^^^^^^^^^ expected an implementor of trait `~const Drop`
|
note: required by a bound in `check`
- --> $DIR/const-drop-fail.rs:35:19
+ --> $DIR/const-drop-fail.rs:34:19
|
LL | const fn check<T: ~const Drop>(_: T) {}
| ^^^^^^^^^^^ required by this bound in `check`
| ++++
error[E0277]: the trait bound `NonTrivialDrop: ~const Drop` is not satisfied in `ConstImplWithDropGlue`
- --> $DIR/const-drop-fail.rs:46:5
+ --> $DIR/const-drop-fail.rs:45:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `ConstImplWithDropGlue`, the trait `~const Drop` is not implemented for `NonTrivialDrop`
|
note: the trait `Drop` is implemented for `NonTrivialDrop`, but that implementation is not `const`
- --> $DIR/const-drop-fail.rs:46:5
+ --> $DIR/const-drop-fail.rs:45:5
|
LL | ConstImplWithDropGlue(NonTrivialDrop),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: required because it appears within the type `ConstImplWithDropGlue`
- --> $DIR/const-drop-fail.rs:17:8
+ --> $DIR/const-drop-fail.rs:16:8
|
LL | struct ConstImplWithDropGlue(NonTrivialDrop);
| ^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `check`
- --> $DIR/const-drop-fail.rs:35:19
+ --> $DIR/const-drop-fail.rs:34:19
|
LL | const fn check<T: ~const Drop>(_: T) {}
| ^^^^^^^^^^^ required by this bound in `check`
error[E0277]: the trait bound `ConstDropImplWithBounds<NonTrivialDrop>: ~const Drop` is not satisfied
- --> $DIR/const-drop-fail.rs:48:5
+ --> $DIR/const-drop-fail.rs:47:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an implementor of trait `~const Drop`
|
note: required because of the requirements on the impl of `~const Drop` for `ConstDropImplWithBounds<NonTrivialDrop>`
- --> $DIR/const-drop-fail.rs:29:25
+ --> $DIR/const-drop-fail.rs:28:25
|
LL | impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> {
| ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `check`
- --> $DIR/const-drop-fail.rs:35:19
+ --> $DIR/const-drop-fail.rs:34:19
|
LL | const fn check<T: ~const Drop>(_: T) {}
| ^^^^^^^^^^^ required by this bound in `check`
// revisions: stock precise
#![feature(const_trait_impl)]
#![feature(const_mut_refs)]
-#![feature(const_fn_trait_bound)]
#![cfg_attr(precise, feature(const_precise_live_drops))]
use std::marker::PhantomData;
error[E0277]: the trait bound `NonTrivialDrop: ~const Drop` is not satisfied
- --> $DIR/const-drop-fail.rs:44:5
+ --> $DIR/const-drop-fail.rs:43:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
| ^^^^^^^^^^^^^^ expected an implementor of trait `~const Drop`
|
note: required by a bound in `check`
- --> $DIR/const-drop-fail.rs:35:19
+ --> $DIR/const-drop-fail.rs:34:19
|
LL | const fn check<T: ~const Drop>(_: T) {}
| ^^^^^^^^^^^ required by this bound in `check`
| ++++
error[E0277]: the trait bound `NonTrivialDrop: ~const Drop` is not satisfied in `ConstImplWithDropGlue`
- --> $DIR/const-drop-fail.rs:46:5
+ --> $DIR/const-drop-fail.rs:45:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `ConstImplWithDropGlue`, the trait `~const Drop` is not implemented for `NonTrivialDrop`
|
note: the trait `Drop` is implemented for `NonTrivialDrop`, but that implementation is not `const`
- --> $DIR/const-drop-fail.rs:46:5
+ --> $DIR/const-drop-fail.rs:45:5
|
LL | ConstImplWithDropGlue(NonTrivialDrop),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: required because it appears within the type `ConstImplWithDropGlue`
- --> $DIR/const-drop-fail.rs:17:8
+ --> $DIR/const-drop-fail.rs:16:8
|
LL | struct ConstImplWithDropGlue(NonTrivialDrop);
| ^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `check`
- --> $DIR/const-drop-fail.rs:35:19
+ --> $DIR/const-drop-fail.rs:34:19
|
LL | const fn check<T: ~const Drop>(_: T) {}
| ^^^^^^^^^^^ required by this bound in `check`
error[E0277]: the trait bound `ConstDropImplWithBounds<NonTrivialDrop>: ~const Drop` is not satisfied
- --> $DIR/const-drop-fail.rs:48:5
+ --> $DIR/const-drop-fail.rs:47:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an implementor of trait `~const Drop`
|
note: required because of the requirements on the impl of `~const Drop` for `ConstDropImplWithBounds<NonTrivialDrop>`
- --> $DIR/const-drop-fail.rs:29:25
+ --> $DIR/const-drop-fail.rs:28:25
|
LL | impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> {
| ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `check`
- --> $DIR/const-drop-fail.rs:35:19
+ --> $DIR/const-drop-fail.rs:34:19
|
LL | const fn check<T: ~const Drop>(_: T) {}
| ^^^^^^^^^^^ required by this bound in `check`
// run-pass
// revisions: stock precise
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
#![feature(const_mut_refs)]
#![feature(never_type)]
#![cfg_attr(precise, feature(const_precise_live_drops))]
-#![feature(const_fn_trait_bound)]
#![feature(const_trait_impl)]
trait Tr {}
error[E0277]: the trait bound `(): ~const Tr` is not satisfied
- --> $DIR/default-method-body-is-const-body-checking.rs:12:15
+ --> $DIR/default-method-body-is-const-body-checking.rs:11:15
|
LL | foo::<()>();
| ^^ the trait `~const Tr` is not implemented for `()`
|
note: the trait `Tr` is implemented for `()`, but that implementation is not `const`
- --> $DIR/default-method-body-is-const-body-checking.rs:12:15
+ --> $DIR/default-method-body-is-const-body-checking.rs:11:15
|
LL | foo::<()>();
| ^^
note: required by a bound in `foo`
- --> $DIR/default-method-body-is-const-body-checking.rs:7:28
+ --> $DIR/default-method-body-is-const-body-checking.rs:6:28
|
LL | const fn foo<T>() where T: ~const Tr {}
| ^^^^^^^^^ required by this bound in `foo`
-#![feature(const_fn_trait_bound)]
#![feature(const_trait_impl)]
pub trait Tr {
error[E0277]: the trait bound `(): ~const Tr` is not satisfied
- --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:12
+ --> $DIR/default-method-body-is-const-same-trait-ck.rs:9:12
|
LL | ().a()
| ^^^ the trait `~const Tr` is not implemented for `()`
|
note: the trait `Tr` is implemented for `()`, but that implementation is not `const`
- --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:12
+ --> $DIR/default-method-body-is-const-same-trait-ck.rs:9:12
|
LL | ().a()
| ^^^
error[E0015]: cannot call non-const fn `<() as Tr>::a` in constant functions
- --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:12
+ --> $DIR/default-method-body-is-const-same-trait-ck.rs:9:12
|
LL | ().a()
| ^^^
#![feature(staged_api)]
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
#![stable(since = "1", feature = "foo")]
trait Tr {
// run-pass
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
use std::marker::PhantomData;
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
trait Tr {
fn req(&self);
error: const trait implementations may not use non-const default functions
- --> $DIR/impl-with-default-fn-fail.rs:18:1
+ --> $DIR/impl-with-default-fn-fail.rs:17:1
|
LL | / impl const Tr for S {
LL | | fn req(&self) {}
= note: `prov` not implemented
error: const trait implementations may not use non-const default functions
- --> $DIR/impl-with-default-fn-fail.rs:28:1
+ --> $DIR/impl-with-default-fn-fail.rs:27:1
|
LL | / impl const Tr for u32 {
LL | | fn req(&self) {}
= note: `prov` not implemented
error[E0046]: not all trait items implemented, missing: `req`
- --> $DIR/impl-with-default-fn-fail.rs:22:1
+ --> $DIR/impl-with-default-fn-fail.rs:21:1
|
LL | fn req(&self);
| -------------- `req` from trait
// check-pass
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
trait Tr {
fn req(&self);
// check-pass
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
struct S;
-#![feature(const_fn_trait_bound)]
#![feature(const_trait_impl)]
pub trait A {
error[E0277]: the trait bound `T: ~const A` is not satisfied
- --> $DIR/issue-88155.rs:9:5
+ --> $DIR/issue-88155.rs:8:5
|
LL | T::assoc()
| ^^^^^^^^^^ the trait `~const A` is not implemented for `T`
|
note: the trait `A` is implemented for `T`, but that implementation is not `const`
- --> $DIR/issue-88155.rs:9:5
+ --> $DIR/issue-88155.rs:8:5
|
LL | T::assoc()
| ^^^^^^^^^^
error[E0015]: cannot call non-const fn `<T as A>::assoc` in constant functions
- --> $DIR/issue-88155.rs:9:5
+ --> $DIR/issue-88155.rs:8:5
|
LL | T::assoc()
| ^^^^^^^^^^
// check-pass
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
pub trait Tr {}
//
// check-pass
-#![feature(const_fn_trait_bound)]
#![feature(const_trait_impl)]
pub trait Super {}
// check-pass
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
trait Convert<T> {
fn to(self) -> T;
#![feature(const_add)]
#![feature(const_trait_impl)]
#![feature(staged_api)]
+#![stable(feature = "rust1", since = "1.0.0")]
+#[stable(feature = "rust1", since = "1.0.0")]
pub struct Int(i32);
#[stable(feature = "rust1", since = "1.0.0")]
}
}
+#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_add", issue = "none")]
impl const std::ops::Add for Int {
type Output = Self;
error: trait methods cannot be stable const fn
- --> $DIR/stability.rs:13:5
+ --> $DIR/stability.rs:15:5
|
LL | / fn sub(self, rhs: Self) -> Self {
LL | |
| |_____^
error: `<Int as Add>::add` is not yet stable as a const fn
- --> $DIR/stability.rs:31:5
+ --> $DIR/stability.rs:34:5
|
LL | Int(1i32) + Int(2i32)
| ^^^^^^^^^^^^^^^^^^^^^
#![feature(staged_api)]
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
#![feature(const_t_try)]
#![feature(const_try)]
#![feature(try_trait_v2)]
// run-pass
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
trait Bar {
fn bar() -> u8;
// check-pass
#![feature(const_trait_impl)]
-#![feature(const_fn_trait_bound)]
trait Foo {
fn bar() where Self: ~const Foo;
-#![feature(const_fn_trait_bound)]
#![feature(const_trait_impl)]
trait Bar {}
error[E0277]: the trait bound `T: ~const Bar` is not satisfied
- --> $DIR/trait-where-clause.rs:14:5
+ --> $DIR/trait-where-clause.rs:13:5
|
LL | T::b();
| ^^^^ the trait `~const Bar` is not implemented for `T`
|
note: the trait `Bar` is implemented for `T`, but that implementation is not `const`
- --> $DIR/trait-where-clause.rs:14:5
+ --> $DIR/trait-where-clause.rs:13:5
|
LL | T::b();
| ^^^^
note: required by a bound in `Foo::b`
- --> $DIR/trait-where-clause.rs:8:24
+ --> $DIR/trait-where-clause.rs:7:24
|
LL | fn b() where Self: ~const Bar;
| ^^^^^^^^^^ required by this bound in `Foo::b`
| ++++++++++++
error[E0277]: the trait bound `T: ~const Bar` is not satisfied
- --> $DIR/trait-where-clause.rs:16:5
+ --> $DIR/trait-where-clause.rs:15:5
|
LL | T::c::<T>();
| ^^^^^^^^^ the trait `~const Bar` is not implemented for `T`
|
note: the trait `Bar` is implemented for `T`, but that implementation is not `const`
- --> $DIR/trait-where-clause.rs:16:5
+ --> $DIR/trait-where-clause.rs:15:5
|
LL | T::c::<T>();
| ^^^^^^^^^
note: required by a bound in `Foo::c`
- --> $DIR/trait-where-clause.rs:9:13
+ --> $DIR/trait-where-clause.rs:8:13
|
LL | fn c<T: ~const Bar>();
| ^^^^^^^^^^ required by this bound in `Foo::c`
| ++++++++++++
error[E0277]: the trait bound `T: Bar` is not satisfied
- --> $DIR/trait-where-clause.rs:28:5
+ --> $DIR/trait-where-clause.rs:27:5
|
LL | T::b();
| ^^^^ the trait `Bar` is not implemented for `T`
|
note: required by a bound in `Foo::b`
- --> $DIR/trait-where-clause.rs:8:24
+ --> $DIR/trait-where-clause.rs:7:24
|
LL | fn b() where Self: ~const Bar;
| ^^^^^^^^^^ required by this bound in `Foo::b`
| +++++
error[E0277]: the trait bound `T: Bar` is not satisfied
- --> $DIR/trait-where-clause.rs:30:5
+ --> $DIR/trait-where-clause.rs:29:5
|
LL | T::c::<T>();
| ^^^^^^^^^ the trait `Bar` is not implemented for `T`
|
note: required by a bound in `Foo::c`
- --> $DIR/trait-where-clause.rs:9:13
+ --> $DIR/trait-where-clause.rs:8:13
|
LL | fn c<T: ~const Bar>();
| ^^^^^^^^^^ required by this bound in `Foo::c`
// compile-flags: --extern issue_56596
// aux-build:issue-56596.rs
-#![feature(uniform_paths)]
-
mod m {
pub mod issue_56596 {}
}
error[E0659]: `issue_56596` is ambiguous
- --> $DIR/issue-56596.rs:12:5
+ --> $DIR/issue-56596.rs:10:5
|
LL | use issue_56596;
| ^^^^^^^^^^^ ambiguous name
= note: `issue_56596` could refer to a crate passed with `--extern`
= help: use `::issue_56596` to refer to this crate unambiguously
note: `issue_56596` could also refer to the module imported here
- --> $DIR/issue-56596.rs:11:5
+ --> $DIR/issue-56596.rs:9:5
|
LL | use m::*;
| ^^^^
--- /dev/null
+// edition:2018
+
+use not_existing_crate::*; //~ ERROR unresolved import `not_existing_crate
+use std as foo;
+
+fn main() {}
--- /dev/null
+error[E0432]: unresolved import `not_existing_crate`
+ --> $DIR/unresolved-asterisk-imports.rs:3:5
+ |
+LL | use not_existing_crate::*;
+ | ^^^^^^^^^^^^^^^^^^ use of undeclared crate or module `not_existing_crate`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0432`.
// Regression test for #23827
-#![feature(core, fn_traits, unboxed_closures)]
+#![feature(fn_traits, unboxed_closures)]
pub struct Prototype {
pub target: u32
#[unstable()] //~ ERROR: stability attributes may not be used
#[stable()] //~ ERROR: stability attributes may not be used
#[rustc_deprecated()] //~ ERROR: stability attributes may not be used
-fn main() { }
+//~^ ERROR missing 'since'
+fn main() {}
LL | #[rustc_deprecated()]
| ^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 3 previous errors
+error[E0542]: missing 'since'
+ --> $DIR/stability-attribute-non-staged-force-unstable.rs:5:1
+ |
+LL | #[rustc_deprecated()]
+ | ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
-For more information about this error, try `rustc --explain E0734`.
+Some errors have detailed explanations: E0542, E0734.
+For more information about an error, try `rustc --explain E0542`.
#[unstable()] //~ ERROR: stability attributes may not be used
#[stable()] //~ ERROR: stability attributes may not be used
#[rustc_deprecated()] //~ ERROR: stability attributes may not be used
-fn main() { }
+//~^ ERROR missing 'since'
+fn main() {}
LL | #[rustc_deprecated()]
| ^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 3 previous errors
+error[E0542]: missing 'since'
+ --> $DIR/stability-attribute-non-staged.rs:3:1
+ |
+LL | #[rustc_deprecated()]
+ | ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
-For more information about this error, try `rustc --explain E0734`.
+Some errors have detailed explanations: E0542, E0734.
+For more information about an error, try `rustc --explain E0542`.
#[stable(feature = "a", since = "b")]
#[rustc_deprecated] //~ ERROR malformed `rustc_deprecated` attribute
+ //~^ ERROR missing 'since'
fn f5() { }
#[stable(feature = "a", since = "b")]
#[rustc_deprecated = "a"] //~ ERROR malformed `rustc_deprecated` attribute
+ //~^ ERROR missing 'since'
fn f6() { }
}
| ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_deprecated(since = "version", reason = "...")]`
error: malformed `rustc_deprecated` attribute input
- --> $DIR/stability-attribute-sanity-4.rs:25:5
+ --> $DIR/stability-attribute-sanity-4.rs:26:5
|
LL | #[rustc_deprecated = "a"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_deprecated(since = "version", reason = "...")]`
-error: aborting due to 6 previous errors
+error[E0542]: missing 'since'
+ --> $DIR/stability-attribute-sanity-4.rs:21:5
+ |
+LL | #[rustc_deprecated]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error[E0542]: missing 'since'
+ --> $DIR/stability-attribute-sanity-4.rs:26:5
+ |
+LL | #[rustc_deprecated = "a"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 8 previous errors
+For more information about this error, try `rustc --explain E0542`.
pub const fn multiple4() { }
#[stable(feature = "a", since = "1.0.0")] //~ ERROR invalid deprecation version found
+//~^ ERROR feature `a` is declared stable since 1.0.0
#[rustc_deprecated(since = "invalid", reason = "text")]
fn invalid_deprecation_version() {}
|
LL | #[stable(feature = "a", since = "1.0.0")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid deprecation version
-LL | #[rustc_deprecated(since = "invalid", reason = "text")]
+...
LL | fn invalid_deprecation_version() {}
| ----------------------------------- the stability attribute annotates this item
error[E0549]: rustc_deprecated attribute must be paired with either stable or unstable attribute
- --> $DIR/stability-attribute-sanity.rs:71:1
+ --> $DIR/stability-attribute-sanity.rs:72:1
|
LL | #[rustc_deprecated(since = "a", reason = "text")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 19 previous errors
+error[E0711]: feature `a` is declared stable since 1.0.0, but was previously declared stable since b
+ --> $DIR/stability-attribute-sanity.rs:67:1
+ |
+LL | #[stable(feature = "a", since = "1.0.0")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 20 previous errors
Some errors have detailed explanations: E0539, E0541, E0542, E0543, E0544, E0546, E0547, E0549, E0550.
For more information about an error, try `rustc --explain E0539`.
//~| ERROR this union takes 2 lifetime arguments but 1 lifetime argument was supplied
//~| ERROR this union takes 2 lifetime arguments but 1 lifetime argument was supplied
//~| ERROR this union takes 2 lifetime arguments but 1 lifetime argument was supplied
+ //~| ERROR this union takes 2 lifetime arguments but 1 lifetime argument was supplied
}
thread_local! {
static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
//~| ERROR this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
//~| ERROR this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
//~| ERROR this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
+ //~| ERROR this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
//~| ERROR missing lifetime
//~| ERROR missing lifetime
}
error[E0106]: missing lifetime specifiers
--> $DIR/missing-lifetime-specifier.rs:18:44
|
-LL | static a: RefCell<HashMap<i32, Vec<Vec<Foo>>>> = RefCell::new(HashMap::new());
- | ^^^ expected 2 lifetime parameters
- |
- = 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 | static a: RefCell<HashMap<i32, Vec<Vec<Foo<'static, 'static>>>>> = RefCell::new(HashMap::new());
- | ~~~~~~~~~~~~~~~~~~~~~
+LL | / thread_local! {
+LL | | static a: RefCell<HashMap<i32, Vec<Vec<Foo>>>> = RefCell::new(HashMap::new());
+ | | ^^^ expected 2 lifetime parameters
+LL | |
+LL | |
+LL | | }
+ | |_-
+ |
+ = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from
error[E0106]: missing lifetime specifier
--> $DIR/missing-lifetime-specifier.rs:23:44
error[E0106]: missing lifetime specifier
--> $DIR/missing-lifetime-specifier.rs:23:44
|
-LL | static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new());
- | ^ 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 | static b: RefCell<HashMap<i32, Vec<Vec<&'static Bar>>>> = RefCell::new(HashMap::new());
- | ~~~~~~~~
+LL | / thread_local! {
+LL | | static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new());
+ | | ^ expected named lifetime parameter
+LL | |
+LL | |
+LL | |
+LL | |
+LL | | }
+ | |_-
+ |
+ = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 4 lifetimes it is borrowed from
error[E0106]: missing lifetime specifiers
--> $DIR/missing-lifetime-specifier.rs:23:45
|
-LL | static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new());
- | ^^^ expected 2 lifetime parameters
- |
- = 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 | static b: RefCell<HashMap<i32, Vec<Vec<&Bar<'static, 'static>>>>> = RefCell::new(HashMap::new());
- | ~~~~~~~~~~~~~~~~~~~~~
+LL | / thread_local! {
+LL | | static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new());
+ | | ^^^ expected 2 lifetime parameters
+LL | |
+LL | |
+LL | |
+LL | |
+LL | | }
+ | |_-
+ |
+ = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 4 lifetimes it is borrowed from
error[E0106]: missing lifetime specifiers
--> $DIR/missing-lifetime-specifier.rs:30:48
error[E0106]: missing lifetime specifiers
--> $DIR/missing-lifetime-specifier.rs:30:48
|
-LL | static c: RefCell<HashMap<i32, Vec<Vec<Qux<i32>>>>> = RefCell::new(HashMap::new());
- | ^ expected 2 lifetime parameters
- |
- = 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 | / thread_local! {
+LL | | static c: RefCell<HashMap<i32, Vec<Vec<Qux<i32>>>>> = RefCell::new(HashMap::new());
+ | | ^ expected 2 lifetime parameters
+LL | |
+LL | |
+LL | | }
+ | |_-
|
-LL | static c: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
- | +++++++++++++++++
+ = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from
error[E0106]: missing lifetime specifier
--> $DIR/missing-lifetime-specifier.rs:35:44
error[E0106]: missing lifetime specifier
--> $DIR/missing-lifetime-specifier.rs:35:44
|
-LL | static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
- | ^ 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 | static d: RefCell<HashMap<i32, Vec<Vec<&'static Tar<i32>>>>> = RefCell::new(HashMap::new());
- | ~~~~~~~~
+LL | / thread_local! {
+LL | | static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
+ | | ^ expected named lifetime parameter
+LL | |
+LL | |
+LL | |
+LL | |
+LL | | }
+ | |_-
+ |
+ = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 4 lifetimes it is borrowed from
error[E0106]: missing lifetime specifiers
--> $DIR/missing-lifetime-specifier.rs:35:49
|
-LL | static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
- | ^ expected 2 lifetime parameters
+LL | / thread_local! {
+LL | | static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
+ | | ^ expected 2 lifetime parameters
+LL | |
+LL | |
+LL | |
+LL | |
+LL | | }
+ | |_-
+ |
+ = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 4 lifetimes it is borrowed from
+
+error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied
+ --> $DIR/missing-lifetime-specifier.rs:43:44
|
- = 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 | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new());
+ | ^^^ ------- supplied 1 lifetime argument
+ | |
+ | expected 2 lifetime arguments
|
-LL | static d: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
- | +++++++++++++++++
+note: union defined here, with 2 lifetime parameters: `'t`, `'k`
+ --> $DIR/missing-lifetime-specifier.rs:11:11
+ |
+LL | pub union Qux<'t, 'k, I> {
+ | ^^^ -- --
+help: add missing lifetime argument
+ |
+LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, '_, i32>>>>> = RefCell::new(HashMap::new());
+ | ++++
error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied
--> $DIR/missing-lifetime-specifier.rs:43:44
| ^^^ -- --
help: add missing lifetime argument
|
-LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, '_, i32>>>>> = RefCell::new(HashMap::new());
+LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'k, i32>>>>> = RefCell::new(HashMap::new());
| ++++
error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied
| ++++
error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/missing-lifetime-specifier.rs:50:45
+ --> $DIR/missing-lifetime-specifier.rs:51:45
|
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
| ^^^ ------- supplied 1 lifetime argument
| ++++
error[E0106]: missing lifetime specifier
- --> $DIR/missing-lifetime-specifier.rs:50:44
+ --> $DIR/missing-lifetime-specifier.rs:51:44
|
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
| ^ expected named lifetime parameter
| ~~~~~~~~
error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/missing-lifetime-specifier.rs:50:45
+ --> $DIR/missing-lifetime-specifier.rs:51:45
|
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
| ^^^ ------- supplied 1 lifetime argument
| ++++
error[E0106]: missing lifetime specifier
- --> $DIR/missing-lifetime-specifier.rs:50:44
+ --> $DIR/missing-lifetime-specifier.rs:51:44
+ |
+LL | / thread_local! {
+LL | | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
+ | | ^ expected named lifetime parameter
+LL | |
+LL | |
+... |
+LL | |
+LL | | }
+ | |_-
+ |
+ = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from
+
+error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
+ --> $DIR/missing-lifetime-specifier.rs:51:45
|
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
- | ^ expected named lifetime parameter
+ | ^^^ ------- supplied 1 lifetime argument
+ | |
+ | expected 2 lifetime arguments
|
- = 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
+note: trait defined here, with 2 lifetime parameters: `'t`, `'k`
+ --> $DIR/missing-lifetime-specifier.rs:15:7
|
-LL | static f: RefCell<HashMap<i32, Vec<Vec<&'static Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
- | ~~~~~~~~
+LL | trait Tar<'t, 'k, I> {}
+ | ^^^ -- --
+help: add missing lifetime argument
+ |
+LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'k, i32>>>>> = RefCell::new(HashMap::new());
+ | ++++
error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/missing-lifetime-specifier.rs:50:45
+ --> $DIR/missing-lifetime-specifier.rs:51:45
|
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
| ^^^ ------- supplied 1 lifetime argument
| ++++
error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
- --> $DIR/missing-lifetime-specifier.rs:50:45
+ --> $DIR/missing-lifetime-specifier.rs:51:45
|
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
| ^^^ ------- supplied 1 lifetime argument
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, '_, i32>>>>> = RefCell::new(HashMap::new());
| ++++
-error: aborting due to 22 previous errors
+error: aborting due to 24 previous errors
Some errors have detailed explanations: E0106, E0107.
For more information about an error, try `rustc --explain E0106`.
// ignore-sparc
// ignore-sparc64
-#![feature(target_feature)]
#![warn(unused_attributes)]
#[target_feature = "+sse2"]
error: malformed `target_feature` attribute input
- --> $DIR/invalid-attribute.rs:18:1
+ --> $DIR/invalid-attribute.rs:17:1
|
LL | #[target_feature = "+sse2"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[target_feature(enable = "name")]`
error: the feature named `foo` is not valid for this target
- --> $DIR/invalid-attribute.rs:20:18
+ --> $DIR/invalid-attribute.rs:19:18
|
LL | #[target_feature(enable = "foo")]
| ^^^^^^^^^^^^^^ `foo` is not valid for this target
error: malformed `target_feature` attribute input
- --> $DIR/invalid-attribute.rs:23:18
+ --> $DIR/invalid-attribute.rs:22:18
|
LL | #[target_feature(bar)]
| ^^^ help: must be of the form: `enable = ".."`
error: malformed `target_feature` attribute input
- --> $DIR/invalid-attribute.rs:25:18
+ --> $DIR/invalid-attribute.rs:24:18
|
LL | #[target_feature(disable = "baz")]
| ^^^^^^^^^^^^^^^ help: must be of the form: `enable = ".."`
error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions
- --> $DIR/invalid-attribute.rs:29:1
+ --> $DIR/invalid-attribute.rs:28:1
|
LL | #[target_feature(enable = "sse2")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: add `#![feature(target_feature_11)]` to the crate attributes to enable
error: attribute should be applied to a function
- --> $DIR/invalid-attribute.rs:35:1
+ --> $DIR/invalid-attribute.rs:34:1
|
LL | #[target_feature(enable = "sse2")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| -------------- not a function
error: attribute should be applied to a function
- --> $DIR/invalid-attribute.rs:40:1
+ --> $DIR/invalid-attribute.rs:39:1
|
LL | #[target_feature(enable = "sse2")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| --------------------- not a function
error: attribute should be applied to a function
- --> $DIR/invalid-attribute.rs:45:1
+ --> $DIR/invalid-attribute.rs:44:1
|
LL | #[target_feature(enable = "sse2")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ----------- not a function
error: attribute should be applied to a function
- --> $DIR/invalid-attribute.rs:50:1
+ --> $DIR/invalid-attribute.rs:49:1
|
LL | #[target_feature(enable = "sse2")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ----------- not a function
error: attribute should be applied to a function
- --> $DIR/invalid-attribute.rs:55:1
+ --> $DIR/invalid-attribute.rs:54:1
|
LL | #[target_feature(enable = "sse2")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |_- not a function
error: attribute should be applied to a function
- --> $DIR/invalid-attribute.rs:63:1
+ --> $DIR/invalid-attribute.rs:62:1
|
LL | #[target_feature(enable = "sse2")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ------------ not a function
error: cannot use `#[inline(always)]` with `#[target_feature]`
- --> $DIR/invalid-attribute.rs:68:1
+ --> $DIR/invalid-attribute.rs:67:1
|
LL | #[inline(always)]
| ^^^^^^^^^^^^^^^^^
error: attribute should be applied to a function
- --> $DIR/invalid-attribute.rs:86:5
+ --> $DIR/invalid-attribute.rs:85:5
|
LL | #[target_feature(enable = "sse2")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |_____- not a function
error: attribute should be applied to a function
- --> $DIR/invalid-attribute.rs:94:5
+ --> $DIR/invalid-attribute.rs:93:5
|
LL | #[target_feature(enable = "sse2")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ----- not a function
error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions
- --> $DIR/invalid-attribute.rs:78:5
+ --> $DIR/invalid-attribute.rs:77:5
|
LL | #[target_feature(enable = "sse2")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
() => {};
}
-#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function
+#[test] //~ WARN: the `#[test]` attribute may only be used on a non-associated function
foo!();
// make sure it doesn't erroneously trigger on a real test
--> $DIR/test-on-not-fn.rs:3:1
|
LL | #[test]
- | ^^^^^^^
+ | ^^^^^^^ the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
LL | mod test {}
| ----------- expected a non-associated function, found a module
|
- = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
help: replace with conditional compilation to make the item only exist when tests are being run
|
LL | #[cfg(test)]
--> $DIR/test-on-not-fn.rs:6:1
|
LL | #[test]
- | ^^^^^^^
+ | ^^^^^^^ the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
LL | / mod loooooooooooooong_teeeeeeeeeest {
LL | | /*
LL | | this is a comment
LL | | }
| |_- expected a non-associated function, found a module
|
- = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
help: replace with conditional compilation to make the item only exist when tests are being run
|
LL | #[cfg(test)]
--> $DIR/test-on-not-fn.rs:20:1
|
LL | #[test]
- | ^^^^^^^
+ | ^^^^^^^ the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
LL | extern "C" {}
| ------------- expected a non-associated function, found an extern block
|
- = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
help: replace with conditional compilation to make the item only exist when tests are being run
|
LL | #[cfg(test)]
--> $DIR/test-on-not-fn.rs:23:1
|
LL | #[test]
- | ^^^^^^^
+ | ^^^^^^^ the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
LL | trait Foo {}
| ------------ expected a non-associated function, found a trait
|
- = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
help: replace with conditional compilation to make the item only exist when tests are being run
|
LL | #[cfg(test)]
--> $DIR/test-on-not-fn.rs:26:1
|
LL | #[test]
- | ^^^^^^^
+ | ^^^^^^^ the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
LL | impl Foo for i32 {}
| ------------------- expected a non-associated function, found an implementation
|
- = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
help: replace with conditional compilation to make the item only exist when tests are being run
|
LL | #[cfg(test)]
--> $DIR/test-on-not-fn.rs:29:1
|
LL | #[test]
- | ^^^^^^^
+ | ^^^^^^^ the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
LL | const FOO: i32 = -1_i32;
| ------------------------ expected a non-associated function, found a constant item
|
- = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
help: replace with conditional compilation to make the item only exist when tests are being run
|
LL | #[cfg(test)]
--> $DIR/test-on-not-fn.rs:32:1
|
LL | #[test]
- | ^^^^^^^
+ | ^^^^^^^ the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
LL | static BAR: u64 = 10_000_u64;
| ----------------------------- expected a non-associated function, found a static item
|
- = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
help: replace with conditional compilation to make the item only exist when tests are being run
|
LL | #[cfg(test)]
--> $DIR/test-on-not-fn.rs:35:1
|
LL | #[test]
- | ^^^^^^^
+ | ^^^^^^^ the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
LL | / enum MyUnit {
LL | | Unit,
LL | | }
| |_- expected a non-associated function, found an enum
|
- = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
help: replace with conditional compilation to make the item only exist when tests are being run
|
LL | #[cfg(test)]
--> $DIR/test-on-not-fn.rs:40:1
|
LL | #[test]
- | ^^^^^^^
+ | ^^^^^^^ the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
LL | struct NewI32(i32);
| ------------------- expected a non-associated function, found a struct
|
- = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
help: replace with conditional compilation to make the item only exist when tests are being run
|
LL | #[cfg(test)]
--> $DIR/test-on-not-fn.rs:43:1
|
LL | #[test]
- | ^^^^^^^
+ | ^^^^^^^ the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
LL | / union Spooky {
LL | | x: i32,
LL | | y: u32,
LL | | }
| |_- expected a non-associated function, found a union
|
- = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
help: replace with conditional compilation to make the item only exist when tests are being run
|
LL | #[cfg(test)]
--> $DIR/test-on-not-fn.rs:50:1
|
LL | #[test]
- | ^^^^^^^
+ | ^^^^^^^ the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
LL | #[derive(Copy, Clone, Debug)]
LL | / struct MoreAttrs {
LL | | a: i32,
LL | | }
| |_- expected a non-associated function, found a struct
|
- = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
help: replace with conditional compilation to make the item only exist when tests are being run
|
LL | #[cfg(test)]
| ~~~~~~~~~~~~
-error: the `#[test]` attribute may only be used on a non-associated function
+warning: the `#[test]` attribute may only be used on a non-associated function
--> $DIR/test-on-not-fn.rs:61:1
|
LL | #[test]
- | ^^^^^^^
+ | ^^^^^^^ the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
LL | foo!();
| ------- expected a non-associated function, found an item macro invocation
|
- = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
help: replace with conditional compilation to make the item only exist when tests are being run
|
LL | #[cfg(test)]
| ~~~~~~~~~~~~
-error: aborting due to 12 previous errors
+error: aborting due to 11 previous errors; 1 warning emitted
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
- --> $DIR/issue-43733.rs:17:5
+ --> $DIR/issue-43733.rs:19:5
|
LL | __KEY.get(Default::default)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
= note: consult the function's documentation for information on how to avoid undefined behavior
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
- --> $DIR/issue-43733.rs:20:42
+ --> $DIR/issue-43733.rs:22:42
|
LL | static FOO: std::thread::LocalKey<Foo> = std::thread::LocalKey::new(__getit);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
#![feature(thread_local)]
#![feature(cfg_target_thread_local, thread_local_internals)]
+use std::cell::RefCell;
+
type Foo = std::cell::RefCell<String>;
#[cfg(target_thread_local)]
#[cfg(not(target_thread_local))]
static __KEY: std::thread::__OsLocalKeyInner<Foo> = std::thread::__OsLocalKeyInner::new();
-fn __getit() -> std::option::Option<&'static Foo> {
+fn __getit(_: Option<&mut Option<RefCell<String>>>) -> std::option::Option<&'static Foo> {
__KEY.get(Default::default) //~ ERROR call to unsafe function is unsafe
}
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
- --> $DIR/issue-43733.rs:17:5
+ --> $DIR/issue-43733.rs:19:5
|
LL | __KEY.get(Default::default)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
= note: consult the function's documentation for information on how to avoid undefined behavior
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
- --> $DIR/issue-43733.rs:20:42
+ --> $DIR/issue-43733.rs:22:42
|
LL | static FOO: std::thread::LocalKey<Foo> = std::thread::LocalKey::new(__getit);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
-#![feature(try_trait)]
// edition:2018
+
fn main() {}
fn a_function() -> u32 {
-#![feature(try_trait)]
-
fn main() {}
fn foo() -> Result<u32, ()> {
error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result`
- --> $DIR/try-on-option.rs:7:6
+ --> $DIR/try-on-option.rs:5:6
|
LL | / fn foo() -> Result<u32, ()> {
LL | | let x: Option<u32> = None;
= help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<u32, ()>`
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
- --> $DIR/try-on-option.rs:13:6
+ --> $DIR/try-on-option.rs:11:6
|
LL | / fn bar() -> u32 {
LL | | let x: Option<u32> = None;
--- /dev/null
+struct Process;
+
+pub type Group = (Vec<String>, Vec<Process>);
+
+fn test(process: &Process, groups: Vec<Group>) -> Vec<Group> {
+ let new_group = vec![String::new()];
+
+ if groups.capacity() == 0 {
+ groups.push(new_group, vec![process]);
+ //~^ ERROR this function takes 1 argument but 2 arguments were supplied
+ return groups;
+ }
+
+ todo!()
+}
+
+fn main() {}
--- /dev/null
+error[E0061]: this function takes 1 argument but 2 arguments were supplied
+ --> $DIR/wrong_argument_ice-3.rs:9:16
+ |
+LL | groups.push(new_group, vec![process]);
+ | ^^^^ --------- ------------- supplied 2 arguments
+ | |
+ | expected 1 argument
+ |
+note: associated function defined here
+ --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+ |
+LL | pub fn push(&mut self, value: T) {
+ | ^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0061`.
--- /dev/null
+fn main() {
+ (|| {})(|| {
+ //~^ ERROR this function takes 0 arguments but 1 argument was supplied
+ let b = 1;
+ });
+}
--- /dev/null
+error[E0057]: this function takes 0 arguments but 1 argument was supplied
+ --> $DIR/wrong_argument_ice-4.rs:2:5
+ |
+LL | (|| {})(|| {
+ | _____^^^^^^^_-
+ | | |
+ | | expected 0 arguments
+LL | |
+LL | | let b = 1;
+LL | | });
+ | |_____- supplied 1 argument
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0057`.
fn main() {}
type Two<A, B> = impl Debug;
-//~^ ERROR the trait bound `A: Foo` is not satisfied in `(A, B, <A as Foo>::Bar)`
+//~^ ERROR the trait bound `A: Foo` is not satisfied
//~| ERROR `A` doesn't implement `Debug`
//~| ERROR `B` doesn't implement `Debug`
LL | fn two<T: Debug + Foo, U: Debug>(t: T, u: U) -> Two<T, U> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error[E0277]: the trait bound `A: Foo` is not satisfied in `(A, B, <A as Foo>::Bar)`
+error[E0277]: the trait bound `A: Foo` is not satisfied
--> $DIR/generic_duplicate_param_use9.rs:7:18
|
LL | type Two<A, B> = impl Debug;
- | ^^^^^^^^^^ within `(A, B, <A as Foo>::Bar)`, the trait `Foo` is not implemented for `A`
+ | ^^^^^^^^^^ the trait `Foo` is not implemented for `A`
|
- = note: required because it appears within the type `(A, B, <A as Foo>::Bar)`
help: consider restricting type parameter `A`
|
LL | type Two<A: Foo, B> = impl Debug;
LL | type Two<A, B> = impl Debug;
| ^^^^^^^^^^ `A` cannot be formatted using `{:?}` because it doesn't implement `Debug`
|
- = note: required because of the requirements on the impl of `Debug` for `(A, B, <A as Foo>::Bar)`
+ = note: required because of the requirements on the impl of `Debug` for `(A, B, _)`
help: consider restricting type parameter `A`
|
LL | type Two<A: std::fmt::Debug, B> = impl Debug;
LL | type Two<A, B> = impl Debug;
| ^^^^^^^^^^ `B` cannot be formatted using `{:?}` because it doesn't implement `Debug`
|
- = note: required because of the requirements on the impl of `Debug` for `(A, B, <A as Foo>::Bar)`
+ = note: required because of the requirements on the impl of `Debug` for `(A, B, _)`
help: consider restricting type parameter `B`
|
LL | type Two<A, B: std::fmt::Debug> = impl Debug;
-#![feature(const_impl_trait, const_fn_fn_ptr_basics, rustc_attrs)]
+#![feature(rustc_attrs)]
#![feature(type_alias_impl_trait)]
type Foo = impl Fn() -> usize;
-#![feature(const_impl_trait, generators, generator_trait, rustc_attrs)]
+#![feature(generators, generator_trait, rustc_attrs)]
#![feature(type_alias_impl_trait)]
use std::ops::Generator;
#![feature(type_alias_impl_trait)]
-#![feature(type_alias_impl_trait)]
#![allow(incomplete_features)]
pub trait Foo {}
error[E0271]: type mismatch resolving `<() as Bar>::Foo == ()`
- --> $DIR/issue-63355.rs:34:20
+ --> $DIR/issue-63355.rs:33:20
|
LL | pub type FooImpl = impl Foo;
| -------- the found opaque type
| ^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<() as Bar>::Foo == ()`
|
note: expected this to be `()`
- --> $DIR/issue-63355.rs:24:16
+ --> $DIR/issue-63355.rs:23:16
|
LL | type Foo = FooImpl;
| ^^^^^^^
#![feature(type_alias_impl_trait)]
-#![feature(type_alias_impl_trait)]
#![allow(incomplete_features)]
trait MyTrait {}
error: cannot implement trait on type alias impl trait
- --> $DIR/issue-65384.rs:11:1
+ --> $DIR/issue-65384.rs:10:1
|
LL | impl MyTrait for Bar {}
| ^^^^^^^^^^^^^^^^^^^^
|
note: type alias impl trait defined here
- --> $DIR/issue-65384.rs:9:12
+ --> $DIR/issue-65384.rs:8:12
|
LL | type Bar = impl MyTrait;
| ^^^^^^^^^^^^
use std::future::Future;
type G<'a, T> = impl Future<Output = ()>;
-//~^ ERROR: type mismatch resolving `<impl Future<Output = [async output]> as Future>::Output == ()`
-//~| ERROR: the trait bound `T: Trait` is not satisfied
+//~^ ERROR: the trait bound `T: Trait` is not satisfied
trait Trait {
type F: Future<Output = ()>;
-error[E0271]: type mismatch resolving `<impl Future<Output = [async output]> as Future>::Output == ()`
- --> $DIR/issue-89686.rs:7:17
- |
-LL | type G<'a, T> = impl Future<Output = ()>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type
-...
-LL | async move { self.f().await }
- | ------------------ the found `async` block
- |
- ::: $SRC_DIR/core/src/future/mod.rs:LL:COL
- |
-LL | pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
- | ------------------------------- the found opaque type
- |
- = note: expected unit type `()`
- found associated type `<impl Future<Output = [async output]> as Future>::Output`
- = help: consider constraining the associated type `<impl Future<Output = [async output]> as Future>::Output` to `()`
- = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
-
error[E0277]: the trait bound `T: Trait` is not satisfied
--> $DIR/issue-89686.rs:7:17
|
LL | type G<'a, T: Trait> = impl Future<Output = ()>;
| +++++++
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors have detailed explanations: E0271, E0277.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0277`.
-#![feature(const_impl_trait)]
#![feature(type_alias_impl_trait)]
type Bar = impl Send;
error: `impl Send` cannot be used in patterns
- --> $DIR/structural-match-no-leak.rs:15:9
+ --> $DIR/structural-match-no-leak.rs:14:9
|
LL | LEAK_FREE => (),
| ^^^^^^^^^
-#![feature(const_impl_trait)]
#![feature(type_alias_impl_trait)]
type Foo = impl Send;
error: `impl Send` cannot be used in patterns
- --> $DIR/structural-match.rs:16:9
+ --> $DIR/structural-match.rs:15:9
|
LL | VALUE => (),
| ^^^^^
// Test a default that references `Self` which is then used in an object type.
// Issue #18956.
-#![feature(default_type_params)]
-
trait Foo<T=Self> {
fn method(&self);
}
error[E0393]: the type parameter `T` must be explicitly specified
- --> $DIR/type-parameter-defaults-referencing-Self.rs:10:16
+ --> $DIR/type-parameter-defaults-referencing-Self.rs:8:16
|
LL | / trait Foo<T=Self> {
LL | | fn method(&self);
+// check-pass
+
#![feature(unboxed_closures)]
trait Lt<'a> {
fn main() {
let v: <() as Lt<'_>>::T = ();
let f: &mut dyn FnMut<(_,), Output = ()> = &mut |_: <() as Lt<'_>>::T| {};
- //~^ ERROR: the size for values of type `<() as Lt<'_>>::T` cannot be known
f(v);
}
+++ /dev/null
-error[E0277]: the size for values of type `<() as Lt<'_>>::T` cannot be known at compilation time
- --> $DIR/issue-53448.rs:12:54
- |
-LL | let f: &mut dyn FnMut<(_,), Output = ()> = &mut |_: <() as Lt<'_>>::T| {};
- | ^ doesn't have a size known at compile-time
- |
- = help: the trait `Sized` is not implemented for `<() as Lt<'_>>::T`
- = help: unsized fn params are gated as an unstable feature
-help: consider further restricting the associated type
- |
-LL | fn main() where <() as Lt<'_>>::T: Sized {
- | ++++++++++++++++++++++++++++++
-help: function arguments must have a statically known size, borrowed types always have a known size
- |
-LL | let f: &mut dyn FnMut<(_,), Output = ()> = &mut |_: &<() as Lt<'_>>::T| {};
- | +
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0277`.
// Fn to be used where FnMut is implemented.
#![feature(fn_traits, unboxed_closures)]
-#![feature(overloaded_calls)]
use std::ops::{Fn,FnMut,FnOnce};
error[E0277]: expected a `Fn<(isize,)>` closure, found `S`
- --> $DIR/unboxed-closures-fnmut-as-fn.rs:28:21
+ --> $DIR/unboxed-closures-fnmut-as-fn.rs:27:21
|
LL | let x = call_it(&S, 22);
| ------- ^^ expected an `Fn<(isize,)>` closure, found `S`
|
= help: the trait `Fn<(isize,)>` is not implemented for `S`
note: required by a bound in `call_it`
- --> $DIR/unboxed-closures-fnmut-as-fn.rs:23:14
+ --> $DIR/unboxed-closures-fnmut-as-fn.rs:22:14
|
LL | fn call_it<F:Fn(isize)->isize>(f: &F, x: isize) -> isize {
| ^^^^^^^^^^^^^^^^ required by this bound in `call_it`
-#![feature(core, fn_traits, unboxed_closures)]
+#![feature(fn_traits, unboxed_closures)]
use std::marker::PhantomData;
error[E0005]: refutable pattern in local binding: `A(_)` not covered
--> $DIR/uninhabited-irrefutable.rs:27:9
|
-LL | / enum Foo {
-LL | | A(foo::SecretlyEmpty),
- | | - not covered
-LL | | B(foo::NotSoSecretlyEmpty),
-LL | | C(NotSoSecretlyEmpty),
-LL | | D(u32),
-LL | | }
- | |_- `Foo` defined here
-...
-LL | let Foo::D(_y) = x;
- | ^^^^^^^^^^ pattern `A(_)` not covered
+LL | let Foo::D(_y) = x;
+ | ^^^^^^^^^^ pattern `A(_)` not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Foo` defined here
+ --> $DIR/uninhabited-irrefutable.rs:19:5
+ |
+LL | enum Foo {
+ | ---
+LL | A(foo::SecretlyEmpty),
+ | ^ not covered
= note: the matched value is of type `Foo`
help: you might want to use `if let` to ignore the variant that isn't matched
|
LL | let _ = match x {
| ^ pattern `Err(_)` not covered
|
- ::: $SRC_DIR/core/src/result.rs:LL:COL
+note: `Result<u32, &Void>` defined here
+ --> $SRC_DIR/core/src/result.rs:LL:COL
+ |
+LL | / pub enum Result<T, E> {
+LL | | /// Contains the success value
+LL | | #[lang = "Ok"]
+LL | | #[stable(feature = "rust1", since = "1.0.0")]
+... |
+LL | | Err(#[stable(feature = "rust1", since = "1.0.0")] E),
+ | | ^^^ not covered
+LL | | }
+ | |_-
+ = note: the matched value is of type `Result<u32, &Void>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
-LL | Err(#[stable(feature = "rust1", since = "1.0.0")] E),
- | --- not covered
+LL ~ Ok(n) => n,
+LL ~ Err(_) => todo!(),
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `Result<u32, &Void>`
error[E0004]: non-exhaustive patterns: type `&Void` is non-empty
--> $DIR/uninhabited-matches-feature-gated.rs:15:19
|
-LL | enum Void {}
- | ------------ `Void` defined here
-...
LL | let _ = match x {};
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+note: `Void` defined here
+ --> $DIR/uninhabited-matches-feature-gated.rs:2:6
+ |
+LL | enum Void {}
+ | ^^^^
= note: the matched value is of type `&Void`
= note: references are always considered inhabited
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ let _ = match x {
+LL + _ => todo!(),
+LL ~ };
+ |
error[E0004]: non-exhaustive patterns: type `(Void,)` is non-empty
--> $DIR/uninhabited-matches-feature-gated.rs:18:19
LL | let _ = match x {};
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `(Void,)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ let _ = match x {
+LL + _ => todo!(),
+LL ~ };
+ |
error[E0004]: non-exhaustive patterns: type `[Void; 1]` is non-empty
--> $DIR/uninhabited-matches-feature-gated.rs:21:19
LL | let _ = match x {};
| ^
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `[Void; 1]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ |
+LL ~ let _ = match x {
+LL + _ => todo!(),
+LL ~ };
+ |
error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
--> $DIR/uninhabited-matches-feature-gated.rs:24:19
LL | let _ = match x {
| ^ pattern `&[_, ..]` not covered
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `&[Void]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ &[] => (),
+LL ~ &[_, ..] => todo!(),
+ |
error[E0004]: non-exhaustive patterns: `Err(_)` not covered
--> $DIR/uninhabited-matches-feature-gated.rs:32:19
LL | let _ = match x {
| ^ pattern `Err(_)` not covered
|
- ::: $SRC_DIR/core/src/result.rs:LL:COL
+note: `Result<u32, Void>` defined here
+ --> $SRC_DIR/core/src/result.rs:LL:COL
+ |
+LL | / pub enum Result<T, E> {
+LL | | /// Contains the success value
+LL | | #[lang = "Ok"]
+LL | | #[stable(feature = "rust1", since = "1.0.0")]
+... |
+LL | | Err(#[stable(feature = "rust1", since = "1.0.0")] E),
+ | | ^^^ not covered
+LL | | }
+ | |_-
+ = note: the matched value is of type `Result<u32, Void>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
-LL | Err(#[stable(feature = "rust1", since = "1.0.0")] E),
- | --- not covered
+LL ~ Ok(x) => x,
+LL ~ Err(_) => todo!(),
|
- = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
- = note: the matched value is of type `Result<u32, Void>`
error[E0005]: refutable pattern in local binding: `Err(_)` not covered
--> $DIR/uninhabited-matches-feature-gated.rs:37:9
LL | let Ok(x) = x;
| ^^^^^ pattern `Err(_)` not covered
|
- ::: $SRC_DIR/core/src/result.rs:LL:COL
- |
-LL | Err(#[stable(feature = "rust1", since = "1.0.0")] E),
- | --- not covered
- |
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `Result<u32, Void>` defined here
+ --> $SRC_DIR/core/src/result.rs:LL:COL
+ |
+LL | / pub enum Result<T, E> {
+LL | | /// Contains the success value
+LL | | #[lang = "Ok"]
+LL | | #[stable(feature = "rust1", since = "1.0.0")]
+... |
+LL | | Err(#[stable(feature = "rust1", since = "1.0.0")] E),
+ | | ^^^ not covered
+LL | | }
+ | |_-
= note: the matched value is of type `Result<u32, Void>`
help: you might want to use `if let` to ignore the variant that isn't matched
|
--- /dev/null
+use not_existing_crate::*; //~ ERROR unresolved import `not_existing_crate
+use std as foo;
+
+fn main() {}
--- /dev/null
+error[E0432]: unresolved import `not_existing_crate`
+ --> $DIR/unresolved-asterisk-imports.rs:1:5
+ |
+LL | use not_existing_crate::*;
+ | ^^^^^^^^^^^^^^^^^^ maybe a missing crate `not_existing_crate`?
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0432`.
sha2 = "0.10.1"
rayon = "1.5.1"
hex = "0.4.2"
-num_cpus = "1.13.0"
let num_threads = if let Some(num) = env::var_os("BUILD_MANIFEST_NUM_THREADS") {
num.to_str().unwrap().parse().expect("invalid number for BUILD_MANIFEST_NUM_THREADS")
} else {
- num_cpus::get()
+ std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get)
};
rayon::ThreadPoolBuilder::new()
.num_threads(num_threads)
-Subproject commit 3d6970d50e30e797b8e26b2b9b1bdf92dc381f34
+Subproject commit 65c82664263feddc5fe2d424be0993c28d46377a
clippy_utils = { path = "clippy_utils" }
derive-new = "0.5"
if_chain = "1.0"
-itertools = "0.10"
+itertools = "0.10.1"
quote = "1.0"
serde = { version = "1.0", features = ["derive"] }
syn = { version = "1.0", features = ["full"] }
bytecount = "0.6"
clap = "2.33"
indoc = "1.0"
-itertools = "0.10"
+itertools = "0.10.1"
opener = "0.5"
regex = "1.5"
shell-escape = "0.1"
cargo_metadata = "0.14"
clippy_utils = { path = "../clippy_utils" }
if_chain = "1.0"
-itertools = "0.10"
+itertools = "0.10.1"
pulldown-cmark = { version = "0.9", default-features = false }
quine-mc_cluskey = "0.2"
regex-syntax = "0.6"
use clippy_utils::ty::has_drop;
use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, meets_msrv, msrvs, trait_ref_of_method};
use rustc_hir as hir;
+use rustc_hir::def_id::CRATE_DEF_ID;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{Body, Constness, FnDecl, GenericParamKind, HirId};
use rustc_lint::{LateContext, LateLintPass};
FnKind::Closure => return,
}
+ // Const fns are not allowed as methods in a trait.
+ {
+ let parent = cx.tcx.hir().get_parent_item(hir_id);
+ if parent != CRATE_DEF_ID {
+ if let hir::Node::Item(item) = cx.tcx.hir().get_by_def_id(parent) {
+ if let hir::ItemKind::Trait(..) = &item.kind {
+ return;
+ }
+ }
+ }
+ }
+
let mir = cx.tcx.optimized_mir(def_id);
if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, self.msrv.as_ref()) {
if let Ok(ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, ty);
if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty));
then {
- layout.layout.size.bytes() == 0
+ layout.layout.size().bytes() == 0
} else {
false
}
(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 ast::TyAlias {
- defaultness: ld,
- generics: lg,
- bounds: lb,
- ty: lt,
- }),
- TyAlias(box ast::TyAlias {
- defaultness: rd,
- generics: rg,
- bounds: rb,
- ty: 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)
) => {
eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r))
},
- (
- TyAlias(box ast::TyAlias {
- defaultness: ld,
- generics: lg,
- bounds: lb,
- ty: lt,
- }),
- TyAlias(box ast::TyAlias {
- defaultness: rd,
- generics: rg,
- bounds: rb,
- ty: 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)
) => {
eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r))
},
- (
- TyAlias(box ast::TyAlias {
- defaultness: ld,
- generics: lg,
- bounds: lb,
- ty: lt,
- }),
- TyAlias(box ast::TyAlias {
- defaultness: rd,
- generics: rg,
- bounds: rb,
- ty: 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)
ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => match result.ty().kind() {
ty::Ref(_, tam, _) => match tam.kind() {
ty::Str => String::from_utf8(
- data.inspect_with_uninit_and_ptr_outside_interpreter(start..end)
+ data.inner().inspect_with_uninit_and_ptr_outside_interpreter(start..end)
.to_owned(),
)
.ok()
ty::ConstKind::Value(ConstValue::ByRef { alloc, offset: _ }) => match result.ty().kind() {
ty::Array(sub_type, len) => match sub_type.kind() {
ty::Float(FloatTy::F32) => match miri_to_const(*len) {
- Some(Constant::Int(len)) => alloc
+ Some(Constant::Int(len)) => alloc.inner()
.inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * len as usize))
.to_owned()
.chunks(4)
_ => None,
},
ty::Float(FloatTy::F64) => match miri_to_const(*len) {
- Some(Constant::Int(len)) => alloc
+ Some(Constant::Int(len)) => alloc.inner()
.inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * len as usize))
.to_owned()
.chunks(8)
| ty::PredicateKind::Projection(_)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::Trait(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => continue,
ty::PredicateKind::ObjectSafe(_) => panic!("object safe predicate on function: {:#?}", predicate),
ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {:#?}", predicate),
ty::PredicateKind::Subtype(_) => panic!("subtype predicate on function: {:#?}", predicate),
ty::PredicateKind::Coerce(_) => panic!("coerce predicate on function: {:#?}", predicate),
- ty::PredicateKind::Trait(pred) => {
- if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
- continue;
- }
- match pred.self_ty().kind() {
- ty::Param(ref p) => {
- let generics = tcx.generics_of(current);
- let def = generics.type_param(p, tcx);
- let span = tcx.def_span(def.def_id);
- return Err((
- span,
- "trait bounds other than `Sized` \
- on const fn parameters are unstable"
- .into(),
- ));
- },
- // other kinds of bounds are either tautologies
- // or cause errors in other passes
- _ => continue,
- }
- },
}
}
match predicates.parent {
error[E0601]: `main` function not found in crate `ice_6250`
- --> $DIR/ice-6250.rs:4:1
+ --> $DIR/ice-6250.rs:16:2
|
-LL | / pub struct Cache {
-LL | | data: Vec<i32>,
-LL | | }
-LL | |
-... |
-LL | | }
-LL | | }
- | |_^ consider adding a `main` function to `$DIR/ice-6250.rs`
+LL | }
+ | ^ consider adding a `main` function to `$DIR/ice-6250.rs`
error[E0308]: mismatched types
--> $DIR/ice-6250.rs:12:14
error[E0601]: `main` function not found in crate `ice_6251`
- --> $DIR/ice-6251.rs:4:1
+ --> $DIR/ice-6251.rs:6:2
|
-LL | / fn bug<T>() -> impl Iterator<Item = [(); { |x: [u8]| x }]> {
-LL | | std::iter::empty()
-LL | | }
- | |_^ consider adding a `main` function to `$DIR/ice-6251.rs`
+LL | }
+ | ^ consider adding a `main` function to `$DIR/ice-6251.rs`
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
--> $DIR/ice-6251.rs:4:45
unsafe { transmute(&x) }
}
-// NOTE: This is currently not yet allowed to be const
-// Once implemented, Clippy should be able to suggest this as const, too.
fn generic_arr<T: Copy>(t: [T; 1]) -> T {
t[0]
}
| |_^
error: this could be a `const fn`
- --> $DIR/could_be_const.rs:67:9
+ --> $DIR/could_be_const.rs:52:1
+ |
+LL | / fn generic_arr<T: Copy>(t: [T; 1]) -> T {
+LL | | t[0]
+LL | | }
+ | |_^
+
+error: this could be a `const fn`
+ --> $DIR/could_be_const.rs:65:9
|
LL | / pub fn b(self, a: &A) -> B {
LL | | B
| |_________^
error: this could be a `const fn`
- --> $DIR/could_be_const.rs:77:5
+ --> $DIR/could_be_const.rs:75:5
|
LL | / fn const_fn_stabilized_before_msrv(byte: u8) {
LL | | byte.is_ascii_digit();
LL | | }
| |_____^
-error: aborting due to 9 previous errors
+error: aborting due to 10 previous errors
pub cc: String,
pub cxx: String,
pub cflags: String,
+ pub cxxflags: String,
pub ar: String,
pub linker: Option<String>,
pub llvm_components: String,
"--cc=c",
"--cxx=c++",
"--cflags=",
+ "--cxxflags=",
"--llvm-components=",
"--android-cross-path=",
"--target=x86_64-unknown-linux-gnu",
.reqopt("", "cc", "path to a C compiler", "PATH")
.reqopt("", "cxx", "path to a C++ compiler", "PATH")
.reqopt("", "cflags", "flags for the C compiler", "FLAGS")
+ .reqopt("", "cxxflags", "flags for the CXX compiler", "FLAGS")
.optopt("", "ar", "path to an archiver", "PATH")
.optopt("", "linker", "path to a linker", "PATH")
.reqopt("", "llvm-components", "list of LLVM components built in", "LIST")
cc: matches.opt_str("cc").unwrap(),
cxx: matches.opt_str("cxx").unwrap(),
cflags: matches.opt_str("cflags").unwrap(),
+ cxxflags: matches.opt_str("cxxflags").unwrap(),
ar: matches.opt_str("ar").unwrap_or_else(|| String::from("ar")),
linker: matches.opt_str("linker"),
llvm_components: matches.opt_str("llvm-components").unwrap(),
.map(|s| s.replace("/", "-"))
.collect::<Vec<_>>()
.join(" ");
+ let cxxflags = self
+ .config
+ .cxxflags
+ .split(' ')
+ .map(|s| s.replace("/", "-"))
+ .collect::<Vec<_>>()
+ .join(" ");
cmd.env("IS_MSVC", "1")
.env("IS_WINDOWS", "1")
.env("MSVC_LIB", format!("'{}' -nologo", lib.display()))
.env("CC", format!("'{}' {}", self.config.cc, cflags))
- .env("CXX", format!("'{}'", &self.config.cxx));
+ .env("CXX", format!("'{}' {}", &self.config.cxx, cxxflags));
} else {
cmd.env("CC", format!("{} {}", self.config.cc, self.config.cflags))
- .env("CXX", format!("{} {}", self.config.cxx, self.config.cflags))
+ .env("CXX", format!("{} {}", self.config.cxx, self.config.cxxflags))
.env("AR", &self.config.ar);
if self.config.target.contains("windows") {
-Subproject commit c6b3f687d5d9917b626f80a730552a185052ff28
+Subproject commit 722475ccc143d2dbf9fad5891207dcb5576e3d17
-Subproject commit 4e72700e38421a12993fe5fa5c33d712652bc6c8
+Subproject commit 5fae65dd28b450a437ebc800a410164c3af1d516
generic-simd = ["bytecount/generic-simd"]
[dependencies]
-itertools = "0.9"
+itertools = "0.10.1"
toml = "0.5"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
let where_span_end = context.snippet_provider.opt_span_before(missing_span, "{");
let where_clause_str = rewrite_where_clause(
context,
- &generics.where_clause,
+ &generics.where_clause.predicates,
+ generics.where_clause.span,
context.config.brace_style(),
Shape::legacy(where_budget, offset.block_only()),
false,
let option = WhereClauseOption::snuggled(&generics_str);
let where_clause_str = rewrite_where_clause(
context,
- &generics.where_clause,
+ &generics.where_clause.predicates,
+ generics.where_clause.span,
context.config.brace_style(),
Shape::legacy(where_budget, offset.block_only()),
where_on_new_line,
let where_str = rewrite_where_clause(
context,
- &self.generics.where_clause,
+ &self.generics.where_clause.predicates,
+ self.generics.where_clause.span,
context.config.brace_style(),
shape,
false,
let option = WhereClauseOption::new(true, WhereClauseSpace::Newline);
rewrite_where_clause(
context,
- &generics.where_clause,
+ &generics.where_clause.predicates,
+ generics.where_clause.span,
context.config.brace_style(),
Shape::legacy(where_budget, offset.block_only()),
false,
&'c RewriteContext<'c>,
Indent,
&'g ast::Generics,
+ (ast::TyAliasWhereClause, ast::TyAliasWhereClause),
+ usize,
symbol::Ident,
Span,
);
ref generics,
ref bounds,
ref ty,
+ where_clauses,
+ where_predicates_split,
} = *ty_alias_kind;
let ty_opt = ty.as_ref();
let (ident, vis) = match visitor_kind {
AssocTraitItem(i) | AssocImplItem(i) => (i.ident, &i.vis),
ForeignItem(i) => (i.ident, &i.vis),
};
- let rw_info = &TyAliasRewriteInfo(context, indent, generics, ident, span);
+ let rw_info = &TyAliasRewriteInfo(
+ context,
+ indent,
+ generics,
+ where_clauses,
+ where_predicates_split,
+ ident,
+ span,
+ );
let op_ty = opaque_ty(ty);
// Type Aliases are formatted slightly differently depending on the context
// in which they appear, whether they are opaque, and whether they are associated.
vis: &ast::Visibility,
) -> Option<String> {
let mut result = String::with_capacity(128);
- let TyAliasRewriteInfo(context, indent, generics, ident, span) = *rw_info;
+ let TyAliasRewriteInfo(
+ context,
+ indent,
+ generics,
+ where_clauses,
+ where_predicates_split,
+ ident,
+ span,
+ ) = *rw_info;
+ let (before_where_predicates, after_where_predicates) = generics
+ .where_clause
+ .predicates
+ .split_at(where_predicates_split);
+ if !after_where_predicates.is_empty() {
+ return None;
+ }
result.push_str(&format!("{}type ", format_visibility(context, vis)));
let ident_str = rewrite_ident(context, ident);
}
let where_clause_str = rewrite_where_clause(
context,
- &generics.where_clause,
+ before_where_predicates,
+ where_clauses.0.1,
context.config.brace_style(),
Shape::legacy(where_budget, indent),
false,
if let Some(ty) = rhs {
// If there's a where clause, add a newline before the assignment. Otherwise just add a
// space.
- let has_where = !generics.where_clause.predicates.is_empty();
+ let has_where = !before_where_predicates.is_empty();
if has_where {
result.push_str(&indent.to_string_with_newline(context.config));
} else {
let comment_span = context
.snippet_provider
.opt_span_before(span, "=")
- .map(|op_lo| mk_sp(generics.where_clause.span.hi(), op_lo));
+ .map(|op_lo| mk_sp(where_clauses.0.1.hi(), op_lo));
let lhs = match comment_span {
Some(comment_span)
let generics_str = rewrite_generics(
context,
rewrite_ident(context, ident),
- fn_sig.generics,
+ &fn_sig.generics,
shape,
)?;
result.push_str(&generics_str);
}
let where_clause_str = rewrite_where_clause(
context,
- where_clause,
+ &where_clause.predicates,
+ where_clause.span,
context.config.brace_style(),
Shape::indented(indent, context.config),
true,
fn rewrite_where_clause_rfc_style(
context: &RewriteContext<'_>,
- where_clause: &ast::WhereClause,
+ predicates: &[ast::WherePredicate],
+ where_span: Span,
shape: Shape,
terminator: &str,
span_end: Option<BytePos>,
) -> Option<String> {
let (where_keyword, allow_single_line) = rewrite_where_keyword(
context,
- where_clause,
+ predicates,
+ where_span,
shape,
span_end_before_where,
where_clause_option,
.block_left(context.config.tab_spaces())?
.sub_width(1)?;
let force_single_line = context.config.where_single_line()
- && where_clause.predicates.len() == 1
+ && predicates.len() == 1
&& !where_clause_option.veto_single_line;
let preds_str = rewrite_bounds_on_where_clause(
context,
- where_clause,
+ predicates,
clause_shape,
terminator,
span_end,
/// Rewrite `where` and comment around it.
fn rewrite_where_keyword(
context: &RewriteContext<'_>,
- where_clause: &ast::WhereClause,
+ predicates: &[ast::WherePredicate],
+ where_span: Span,
shape: Shape,
span_end_before_where: BytePos,
where_clause_option: WhereClauseOption,
};
let (span_before, span_after) =
- missing_span_before_after_where(span_end_before_where, where_clause);
+ missing_span_before_after_where(span_end_before_where, predicates, where_span);
let (comment_before, comment_after) =
rewrite_comments_before_after_where(context, span_before, span_after, shape)?;
/// Rewrite bounds on a where clause.
fn rewrite_bounds_on_where_clause(
context: &RewriteContext<'_>,
- where_clause: &ast::WhereClause,
+ predicates: &[ast::WherePredicate],
shape: Shape,
terminator: &str,
span_end: Option<BytePos>,
where_clause_option: WhereClauseOption,
force_single_line: bool,
) -> Option<String> {
- let span_start = where_clause.predicates[0].span().lo();
+ let span_start = predicates[0].span().lo();
// If we don't have the start of the next span, then use the end of the
// predicates, but that means we miss comments.
- let len = where_clause.predicates.len();
- let end_of_preds = where_clause.predicates[len - 1].span().hi();
+ let len = predicates.len();
+ let end_of_preds = predicates[len - 1].span().hi();
let span_end = span_end.unwrap_or(end_of_preds);
let items = itemize_list(
context.snippet_provider,
- where_clause.predicates.iter(),
+ predicates.iter(),
terminator,
",",
|pred| pred.span().lo(),
fn rewrite_where_clause(
context: &RewriteContext<'_>,
- where_clause: &ast::WhereClause,
+ predicates: &[ast::WherePredicate],
+ where_span: Span,
brace_style: BraceStyle,
shape: Shape,
on_new_line: bool,
span_end_before_where: BytePos,
where_clause_option: WhereClauseOption,
) -> Option<String> {
- if where_clause.predicates.is_empty() {
+ if predicates.is_empty() {
return Some(String::new());
}
if context.config.indent_style() == IndentStyle::Block {
return rewrite_where_clause_rfc_style(
context,
- where_clause,
+ predicates,
+ where_span,
shape,
terminator,
span_end,
// be out by a char or two.
let budget = context.config.max_width() - offset.width();
- let span_start = where_clause.predicates[0].span().lo();
+ let span_start = predicates[0].span().lo();
// If we don't have the start of the next span, then use the end of the
// predicates, but that means we miss comments.
- let len = where_clause.predicates.len();
- let end_of_preds = where_clause.predicates[len - 1].span().hi();
+ let len = predicates.len();
+ let end_of_preds = predicates[len - 1].span().hi();
let span_end = span_end.unwrap_or(end_of_preds);
let items = itemize_list(
context.snippet_provider,
- where_clause.predicates.iter(),
+ predicates.iter(),
terminator,
",",
|pred| pred.span().lo(),
fn missing_span_before_after_where(
before_item_span_end: BytePos,
- where_clause: &ast::WhereClause,
+ predicates: &[ast::WherePredicate],
+ where_span: Span,
) -> (Span, Span) {
- let missing_span_before = mk_sp(before_item_span_end, where_clause.span.lo());
+ let missing_span_before = mk_sp(before_item_span_end, where_span.lo());
// 5 = `where`
- let pos_after_where = where_clause.span.lo() + BytePos(5);
- let missing_span_after = mk_sp(pos_after_where, where_clause.predicates[0].span().lo());
+ let pos_after_where = where_span.lo() + BytePos(5);
+ let missing_span_after = mk_sp(pos_after_where, predicates[0].span().lo());
(missing_span_before, missing_span_after)
}
}
let where_clause_str = rewrite_where_clause(
context,
- &generics.where_clause,
+ &generics.where_clause.predicates,
+ generics.where_clause.span,
brace_style,
Shape::legacy(budget, offset.block_only()),
true,
"""
label = "O-riscv"
+[ping.fuchsia]
+message = """\
+Hey friends of Fuchsia! This issue could use some guidance on how this should be
+resolved/implemented on Fuchsia. Could one of you weigh in?
+"""
+label = "O-fuchsia"
+
[prioritize]
label = "I-prioritize"