use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
+use rustc_hir::PredicateOrigin;
use rustc_index::vec::{Idx, IndexVec};
use rustc_session::utils::NtToTokenstream;
use rustc_session::Session;
let mut predicates = SmallVec::new();
predicates.extend(generics.params.iter().filter_map(|param| {
let bounds = self.lower_param_bounds(¶m.bounds, itctx.reborrow());
- self.lower_generic_bound_predicate(param.ident, param.id, ¶m.kind, bounds)
+ self.lower_generic_bound_predicate(
+ param.ident,
+ param.id,
+ ¶m.kind,
+ bounds,
+ PredicateOrigin::GenericParam,
+ )
}));
predicates.extend(
generics
id: NodeId,
kind: &GenericParamKind,
bounds: &'hir [hir::GenericBound<'hir>],
+ origin: PredicateOrigin,
) -> Option<hir::WherePredicate<'hir>> {
// Do not create a clause if we do not have anything inside it.
if bounds.is_empty() {
bounds,
span,
bound_generic_params: &[],
- in_where_clause: false,
+ origin,
}))
}
GenericParamKind::Lifetime => {
)
})),
span: self.lower_span(span),
- in_where_clause: true,
+ origin: PredicateOrigin::WhereClause,
}),
WherePredicate::RegionPredicate(WhereRegionPredicate {
ref lifetime,
def_node_id,
&GenericParamKind::Type { default: None },
hir_bounds,
+ hir::PredicateOrigin::ImplTrait,
) {
in_band_ty_bounds.push(preds)
}
continue;
}
- if let Some((_, span)) = &depr {
- struct_span_err!(diagnostic, attr.span, E0550, "multiple deprecated attributes")
- .span_label(attr.span, "repeated deprecation attribute")
- .span_label(*span, "first deprecation attribute")
+ // FIXME(jhpratt) remove this eventually
+ if attr.has_name(sym::rustc_deprecated) {
+ diagnostic
+ .struct_span_err(attr.span, "`#[rustc_deprecated]` has been removed")
+ .help("use `#[deprecated]` instead")
.emit();
- break;
}
let Some(meta) = attr.meta() else {
continue 'outer;
}
}
- // FIXME(jhpratt) remove this after a bootstrap occurs. Emitting an
- // error specific to the renaming would be a good idea as well.
+ // FIXME(jhpratt) remove this eventually
sym::reason if attr.has_name(sym::rustc_deprecated) => {
if !get(mi, &mut note) {
continue 'outer;
}
+
+ let mut diag = diagnostic
+ .struct_span_err(mi.span, "`reason` has been renamed");
+ match note {
+ Some(note) => diag.span_suggestion(
+ mi.span,
+ "use `note` instead",
+ format!("note = \"{note}\""),
+ Applicability::MachineApplicable,
+ ),
+ None => diag.span_help(mi.span, "use `note` instead"),
+ };
+ diag.emit();
}
sym::suggestion => {
if !sess.features_untracked().deprecated_suggestion {
let mut rpo = traversal::reverse_postorder(body);
let ccx = ConstCx::new(tcx, body);
- let (temps, all_candidates) = collect_temps_and_candidates(&ccx, &mut rpo);
+ let (mut temps, all_candidates) = collect_temps_and_candidates(&ccx, &mut rpo);
- let promotable_candidates = validate_candidates(&ccx, &temps, &all_candidates);
+ let promotable_candidates = validate_candidates(&ccx, &mut temps, &all_candidates);
let promoted = promote_candidates(body, tcx, temps, promotable_candidates);
self.promoted_fragments.set(promoted);
/// One direct assignment and any number of direct uses.
/// A borrow of this temp is promotable if the assigned
/// value is qualified as constant.
- Defined { location: Location, uses: usize },
+ Defined { location: Location, uses: usize, valid: Result<(), ()> },
/// Any other combination of assignments/uses.
Unpromotable,
/// This temp was part of an rvalue which got extracted
match context {
PlaceContext::MutatingUse(MutatingUseContext::Store)
| PlaceContext::MutatingUse(MutatingUseContext::Call) => {
- *temp = TempState::Defined { location, uses: 0 };
+ *temp = TempState::Defined { location, uses: 0, valid: Err(()) };
return;
}
_ => { /* mark as unpromotable below */ }
/// This wraps an `Item`, and has access to all fields of that `Item` via `Deref` coercion.
struct Validator<'a, 'tcx> {
ccx: &'a ConstCx<'a, 'tcx>,
- temps: &'a IndexVec<Local, TempState>,
+ temps: &'a mut IndexVec<Local, TempState>,
}
impl<'a, 'tcx> std::ops::Deref for Validator<'a, 'tcx> {
struct Unpromotable;
impl<'tcx> Validator<'_, 'tcx> {
- fn validate_candidate(&self, candidate: Candidate) -> Result<(), Unpromotable> {
+ fn validate_candidate(&mut self, candidate: Candidate) -> Result<(), Unpromotable> {
let loc = candidate.location;
let statement = &self.body[loc.block].statements[loc.statement_index];
match &statement.kind {
}
// FIXME(eddyb) maybe cache this?
- fn qualif_local<Q: qualifs::Qualif>(&self, local: Local) -> bool {
+ fn qualif_local<Q: qualifs::Qualif>(&mut self, local: Local) -> bool {
if let TempState::Defined { location: loc, .. } = self.temps[local] {
let num_stmts = self.body[loc.block].statements.len();
}
}
- // FIXME(eddyb) maybe cache this?
- fn validate_local(&self, local: Local) -> Result<(), Unpromotable> {
- if let TempState::Defined { location: loc, .. } = self.temps[local] {
- let block = &self.body[loc.block];
- let num_stmts = block.statements.len();
-
- if loc.statement_index < num_stmts {
- let statement = &block.statements[loc.statement_index];
- match &statement.kind {
- StatementKind::Assign(box (_, rhs)) => self.validate_rvalue(rhs),
- _ => {
- span_bug!(
- statement.source_info.span,
- "{:?} is not an assignment",
- statement
- );
- }
- }
- } else {
- let terminator = block.terminator();
- match &terminator.kind {
- TerminatorKind::Call { func, args, .. } => self.validate_call(func, args),
- TerminatorKind::Yield { .. } => Err(Unpromotable),
- kind => {
- span_bug!(terminator.source_info.span, "{:?} not promotable", kind);
+ fn validate_local(&mut self, local: Local) -> Result<(), Unpromotable> {
+ if let TempState::Defined { location: loc, uses, valid } = self.temps[local] {
+ valid.or_else(|_| {
+ let ok = {
+ let block = &self.body[loc.block];
+ let num_stmts = block.statements.len();
+
+ if loc.statement_index < num_stmts {
+ let statement = &block.statements[loc.statement_index];
+ match &statement.kind {
+ StatementKind::Assign(box (_, rhs)) => self.validate_rvalue(rhs),
+ _ => {
+ span_bug!(
+ statement.source_info.span,
+ "{:?} is not an assignment",
+ statement
+ );
+ }
+ }
+ } else {
+ let terminator = block.terminator();
+ match &terminator.kind {
+ TerminatorKind::Call { func, args, .. } => {
+ self.validate_call(func, args)
+ }
+ TerminatorKind::Yield { .. } => Err(Unpromotable),
+ kind => {
+ span_bug!(terminator.source_info.span, "{:?} not promotable", kind);
+ }
+ }
}
- }
- }
+ };
+ self.temps[local] = match ok {
+ Ok(()) => TempState::Defined { location: loc, uses, valid: Ok(()) },
+ Err(_) => TempState::Unpromotable,
+ };
+ ok
+ })
} else {
Err(Unpromotable)
}
}
- fn validate_place(&self, place: PlaceRef<'tcx>) -> Result<(), Unpromotable> {
+ fn validate_place(&mut self, place: PlaceRef<'tcx>) -> Result<(), Unpromotable> {
match place.last_projection() {
None => self.validate_local(place.local),
Some((place_base, elem)) => {
}
}
- fn validate_operand(&self, operand: &Operand<'tcx>) -> Result<(), Unpromotable> {
+ fn validate_operand(&mut self, operand: &Operand<'tcx>) -> Result<(), Unpromotable> {
match operand {
Operand::Copy(place) | Operand::Move(place) => self.validate_place(place.as_ref()),
}
}
- fn validate_ref(&self, kind: BorrowKind, place: &Place<'tcx>) -> Result<(), Unpromotable> {
+ fn validate_ref(&mut self, kind: BorrowKind, place: &Place<'tcx>) -> Result<(), Unpromotable> {
match kind {
// Reject these borrow types just to be safe.
// FIXME(RalfJung): could we allow them? Should we? No point in it until we have a usecase.
Ok(())
}
- fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
+ fn validate_rvalue(&mut self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
match rvalue {
Rvalue::Use(operand) | Rvalue::Repeat(operand, _) => {
self.validate_operand(operand)?;
}
fn validate_call(
- &self,
+ &mut self,
callee: &Operand<'tcx>,
args: &[Operand<'tcx>],
) -> Result<(), Unpromotable> {
// FIXME(eddyb) remove the differences for promotability in `static`, `const`, `const fn`.
pub fn validate_candidates(
ccx: &ConstCx<'_, '_>,
- temps: &IndexVec<Local, TempState>,
+ temps: &mut IndexVec<Local, TempState>,
candidates: &[Candidate],
) -> Vec<Candidate> {
- let validator = Validator { ccx, temps };
+ let mut validator = Validator { ccx, temps };
candidates
.iter()
fn promote_temp(&mut self, temp: Local) -> Local {
let old_keep_original = self.keep_original;
let loc = match self.temps[temp] {
- TempState::Defined { location, uses } if uses > 0 => {
+ TempState::Defined { location, uses, .. } if uses > 0 => {
if uses > 1 {
self.keep_original = true;
}
#![feature(staged_api)]
#![stable(since = "1.0.0", feature = "test")]
-#[rustc_deprecated(reason)] // error!
+#[deprecated(note)] // error!
#[unstable(feature = "deprecated_fn", issue = "123")]
fn deprecated() {}
#![feature(staged_api)]
#![stable(since = "1.0.0", feature = "test")]
-#[rustc_deprecated(since = "1.39.0", reason = "reason")] // ok!
+#[deprecated(since = "1.39.0", note = "reason")] // ok!
#[unstable(feature = "deprecated_fn", issue = "123")]
fn deprecated() {}
const fn _stable_const_fn() {}
#[stable(feature = "_deprecated_fn", since = "0.1.0")]
-#[rustc_deprecated(
- reason = "explanation for deprecation"
+#[deprecated(
+ note = "explanation for deprecation"
)] // invalid
fn _deprecated_fn() {}
```
const fn _stable_const_fn() {}
#[stable(feature = "_deprecated_fn", since = "0.1.0")]
-#[rustc_deprecated(
+#[deprecated(
since = "1.0.0",
- reason = "explanation for deprecation"
+ note = "explanation for deprecation"
)] // ok!
fn _deprecated_fn() {}
```
-The `reason` value is missing in a stability attribute.
+The `note` value is missing in a stability attribute.
Erroneous code example:
#![stable(since = "1.0.0", feature = "test")]
#[stable(since = "0.1.0", feature = "_deprecated_fn")]
-#[rustc_deprecated(
+#[deprecated(
since = "1.0.0"
)] // invalid
fn _deprecated_fn() {}
```
-To fix this issue, you need to provide the `reason` field. Example:
+To fix this issue, you need to provide the `note` field. Example:
```
#![feature(staged_api)]
#![stable(since = "1.0.0", feature = "test")]
#[stable(since = "0.1.0", feature = "_deprecated_fn")]
-#[rustc_deprecated(
+#[deprecated(
since = "1.0.0",
- reason = "explanation for deprecation"
+ note = "explanation for deprecation"
)] // ok!
fn _deprecated_fn() {}
```
-A `rustc_deprecated` attribute wasn't paired with a `stable`/`unstable`
-attribute.
+A `deprecated` attribute wasn't paired with a `stable`/`unstable` attribute with
+`#![feature(staged_api)]` enabled.
Erroneous code example:
#![feature(staged_api)]
#![stable(since = "1.0.0", feature = "test")]
-#[rustc_deprecated(
+#[deprecated(
since = "1.0.1",
- reason = "explanation for deprecation"
+ note = "explanation for deprecation"
)] // invalid
fn _deprecated_fn() {}
```
#![stable(since = "1.0.0", feature = "test")]
#[stable(since = "1.0.0", feature = "test")]
-#[rustc_deprecated(
+#[deprecated(
since = "1.0.1",
- reason = "explanation for deprecation"
+ note = "explanation for deprecation"
)] // ok!
fn _deprecated_fn() {}
```
+#### Note: this error code is no longer emitted by the compiler
+
More than one `deprecated` attribute has been put on an item.
Erroneous code example:
-```compile_fail,E0550
+```compile_fail
#[deprecated(note = "because why not?")]
#[deprecated(note = "right?")] // error!
fn the_banished() {}
Erroneous code example:
```compile_fail,E0734
-#[rustc_deprecated(since = "b", reason = "text")] // invalid
#[stable(feature = "a", since = "b")] // invalid
#[unstable(feature = "b", issue = "none")] // invalid
fn foo(){}
typeck-trait-object-declared-with-no-traits =
at least one trait is required for an object type
+ .alias-span = this alias does not contain a trait
typeck-ambiguous-lifetime-bound =
ambiguous lifetime bound, explicit lifetime bound required
future_breakage_diagnostics: Vec<Diagnostic>,
+ /// The [`Self::unstable_expect_diagnostics`] should be empty when this struct is
+ /// dropped. However, it can have values if the compilation is stopped early
+ /// or is only partially executed. To avoid ICEs, like in rust#94953 we only
+ /// check if [`Self::unstable_expect_diagnostics`] is empty, if the expectation ids
+ /// have been converted.
+ check_unstable_expect_diagnostics: bool,
+
/// 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
);
}
- assert!(
- self.unstable_expect_diagnostics.is_empty(),
- "all diagnostics with unstable expectations should have been converted",
- );
+ if self.check_unstable_expect_diagnostics {
+ assert!(
+ self.unstable_expect_diagnostics.is_empty(),
+ "all diagnostics with unstable expectations should have been converted",
+ );
+ }
}
}
emitted_diagnostics: Default::default(),
stashed_diagnostics: Default::default(),
future_breakage_diagnostics: Vec::new(),
+ check_unstable_expect_diagnostics: false,
unstable_expect_diagnostics: Vec::new(),
fulfilled_expectations: Default::default(),
}),
&self,
unstable_to_stable: &FxHashMap<LintExpectationId, LintExpectationId>,
) {
- let diags = std::mem::take(&mut self.inner.borrow_mut().unstable_expect_diagnostics);
+ let mut inner = self.inner.borrow_mut();
+ let diags = std::mem::take(&mut inner.unstable_expect_diagnostics);
+ inner.check_unstable_expect_diagnostics = true;
if diags.is_empty() {
return;
}
- let mut inner = self.inner.borrow_mut();
for mut diag in diags.into_iter() {
diag.update_unstable_expectation_id(unstable_to_stable);
// Unstable `#[target_feature]` directives.
(active, aarch64_ver_target_feature, "1.27.0", Some(44839), None),
- (active, adx_target_feature, "1.32.0", Some(44839), None),
(active, arm_target_feature, "1.27.0", Some(44839), None),
(active, avx512_target_feature, "1.27.0", Some(44839), None),
(active, bpf_target_feature, "1.54.0", Some(44839), None),
List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#,
NameValueStr: "reason"
),
- // This has special duplicate handling in E0550 to handle duplicates with rustc_deprecated
- DuplicatesOk
+ ErrorFollowing
),
// Crate properties:
// ==========================================================================
ungated!(feature, CrateLevel, template!(List: "name1, name2, ..."), DuplicatesOk),
- // DuplicatesOk since it has its own validation
+ // FIXME(jhpratt) remove this eventually
ungated!(
rustc_deprecated, Normal,
- template!(List: r#"since = "version", note = "...""#), DuplicatesOk // See E0550
+ template!(List: r#"since = "version", note = "...""#), ErrorFollowing
),
// DuplicatesOk since it has its own validation
ungated!(
_ => false,
}
}
+
+ /// Whether `query get_codegen_attrs` should be used with this definition.
+ pub fn has_codegen_attrs(self) -> bool {
+ match self {
+ DefKind::Fn
+ | DefKind::AssocFn
+ | DefKind::Ctor(..)
+ | DefKind::Closure
+ | DefKind::Generator
+ | DefKind::Static(_) => true,
+ DefKind::Mod
+ | DefKind::Struct
+ | DefKind::Union
+ | DefKind::Enum
+ | DefKind::Variant
+ | DefKind::Trait
+ | DefKind::TyAlias
+ | DefKind::ForeignTy
+ | DefKind::TraitAlias
+ | DefKind::AssocTy
+ | DefKind::Const
+ | DefKind::AssocConst
+ | DefKind::Macro(..)
+ | DefKind::Use
+ | DefKind::ForeignMod
+ | DefKind::OpaqueTy
+ | DefKind::Impl
+ | DefKind::Field
+ | DefKind::TyParam
+ | DefKind::ConstParam
+ | DefKind::LifetimeParam
+ | DefKind::AnonConst
+ | DefKind::InlineConst
+ | DefKind::GlobalAsm
+ | DefKind::ExternCrate => false,
+ }
+ }
}
/// The resolution of a path or export.
pub fn in_where_clause(&self) -> bool {
match self {
- WherePredicate::BoundPredicate(p) => p.in_where_clause,
+ WherePredicate::BoundPredicate(p) => p.origin == PredicateOrigin::WhereClause,
WherePredicate::RegionPredicate(p) => p.in_where_clause,
WherePredicate::EqPredicate(_) => false,
}
}
}
+#[derive(Debug, HashStable_Generic, PartialEq, Eq)]
+pub enum PredicateOrigin {
+ WhereClause,
+ GenericParam,
+ ImplTrait,
+}
+
/// A type bound (e.g., `for<'c> Foo: Send + Clone + 'c`).
#[derive(Debug, HashStable_Generic)]
pub struct WhereBoundPredicate<'hir> {
pub span: Span,
- pub in_where_clause: bool,
+ /// Origin of the predicate.
+ pub origin: PredicateOrigin,
/// Any generics from a `for` binding.
pub bound_generic_params: &'hir [GenericParam<'hir>],
/// The type being bounded.
Variable(ty::error::ExpectedFound<Ty<'a>>),
Fixed(&'static str),
}
- let (expected_found, exp_found, is_simple_error) = match values {
- None => (None, Mismatch::Fixed("type"), false),
+ let (expected_found, exp_found, is_simple_error, values) = match values {
+ None => (None, Mismatch::Fixed("type"), false, None),
Some(values) => {
+ let values = self.resolve_vars_if_possible(values);
let (is_simple_error, exp_found) = match values {
ValuePairs::Terms(infer::ExpectedFound {
expected: ty::Term::Ty(expected),
return;
}
};
- (vals, exp_found, is_simple_error)
+ (vals, exp_found, is_simple_error, Some(values))
}
};
});
}
);
+
+ // This check has to be run after all lints are done processing. We don't
+ // define a lint filter, as all lint checks should have finished at this point.
+ sess.time("check_lint_expectations", || tcx.check_expectations(None));
});
Ok(())
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID};
-use rustc_hir::{ForeignItemKind, GenericParamKind, HirId, PatKind};
+use rustc_hir::{ForeignItemKind, GenericParamKind, HirId, PatKind, PredicateOrigin};
use rustc_index::vec::Idx;
-use rustc_middle::lint::LintDiagnosticBuilder;
+use rustc_middle::lint::{in_external_macro, LintDiagnosticBuilder};
use rustc_middle::ty::layout::{LayoutError, LayoutOf};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::subst::GenericArgKind;
None
}
})
+ .filter(|(_, span)| !in_external_macro(tcx.sess, *span))
.collect()
}
Self::lifetimes_outliving_type(inferred_outlives, index),
&predicate.bounds,
predicate.span,
- predicate.in_where_clause,
+ predicate.origin == PredicateOrigin::WhereClause,
)
}
_ => {
use crate::builtin;
use rustc_hir::HirId;
+use rustc_middle::ty::query::Providers;
use rustc_middle::{lint::LintExpectation, ty::TyCtxt};
use rustc_session::lint::LintExpectationId;
use rustc_span::symbol::sym;
+use rustc_span::Symbol;
-pub fn check_expectations(tcx: TyCtxt<'_>) {
+pub(crate) fn provide(providers: &mut Providers) {
+ *providers = Providers { check_expectations, ..*providers };
+}
+
+fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) {
if !tcx.sess.features_untracked().enabled(sym::lint_reasons) {
return;
}
let lint_expectations = &tcx.lint_levels(()).lint_expectations;
for (id, expectation) in lint_expectations {
- if !fulfilled_expectations.contains(id) {
+ if !fulfilled_expectations.contains(id)
+ && tool_filter.map_or(true, |filter| expectation.lint_tool == Some(filter))
+ {
// This check will always be true, since `lint_expectations` only
// holds stable ids
if let LintExpectationId::Stable { hir_id, .. } = id {
});
},
);
-
- // 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));
}
};
self.lint_expectations.push((
expect_id,
- LintExpectation::new(reason, sp, is_unfulfilled_lint_expectations),
+ LintExpectation::new(
+ reason,
+ sp,
+ is_unfulfilled_lint_expectations,
+ tool_name,
+ ),
));
}
let src = LintLevelSource::Node(
self.insert_spec(*id, (level, src));
}
if let Level::Expect(expect_id) = level {
- self.lint_expectations
- .push((expect_id, LintExpectation::new(reason, sp, false)));
+ self.lint_expectations.push((
+ expect_id,
+ LintExpectation::new(reason, sp, false, tool_name),
+ ));
}
}
Err((Some(ids), ref new_lint_name)) => {
self.insert_spec(*id, (level, src));
}
if let Level::Expect(expect_id) = level {
- self.lint_expectations
- .push((expect_id, LintExpectation::new(reason, sp, false)));
+ self.lint_expectations.push((
+ expect_id,
+ LintExpectation::new(reason, sp, false, tool_name),
+ ));
}
}
Err((None, _)) => {
}
}
if let Level::Expect(expect_id) = level {
- self.lint_expectations
- .push((expect_id, LintExpectation::new(reason, sp, false)));
+ self.lint_expectations.push((
+ expect_id,
+ LintExpectation::new(reason, sp, false, tool_name),
+ ));
}
} else {
panic!("renamed lint does not exist: {}", new_name);
pub fn provide(providers: &mut Providers) {
levels::provide(providers);
+ expect::provide(providers);
*providers = Providers { lint_mod, ..*providers };
}
/// used by user code.
///
/// This lint is only enabled in the standard library. It works with the
- /// use of `#[rustc_deprecated]` with a `since` field of a version in the
- /// future. This allows something to be marked as deprecated in a future
- /// version, and then this lint will ensure that the item is no longer
- /// used in the standard library. See the [stability documentation] for
- /// more details.
+ /// use of `#[deprecated]` with a `since` field of a version in the future.
+ /// This allows something to be marked as deprecated in a future version,
+ /// and then this lint will ensure that the item is no longer used in the
+ /// standard library. See the [stability documentation] for more details.
///
- /// [stability documentation]: https://rustc-dev-guide.rust-lang.org/stability.html#rustc_deprecated
+ /// [stability documentation]: https://rustc-dev-guide.rust-lang.org/stability.html#deprecated
pub DEPRECATED_IN_FUTURE,
Allow,
"detects use of items that will be deprecated in a future version",
type_of => { table }
variances_of => { table }
fn_sig => { table }
+ codegen_fn_attrs => { table }
impl_trait_ref => { table }
const_param_default => { table }
thir_abstract_const => { table }
record!(self.tables.def_span[def_id] <- tcx.def_span(def_id));
self.encode_attrs(def_id);
record!(self.tables.expn_that_defined[def_id] <- self.tcx.expn_that_defined(def_id));
+ if def_kind.has_codegen_attrs() {
+ record!(self.tables.codegen_fn_attrs[def_id] <- self.tcx.codegen_fn_attrs(def_id));
+ }
if should_encode_visibility(def_kind) {
record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
}
use rustc_hir::lang_items;
use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec};
use rustc_middle::metadata::ModChild;
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
use rustc_middle::mir;
use rustc_middle::thir;
type_of: Table<DefIndex, Lazy!(Ty<'tcx>)>,
variances_of: Table<DefIndex, Lazy<[ty::Variance]>>,
fn_sig: Table<DefIndex, Lazy!(ty::PolyFnSig<'tcx>)>,
+ codegen_fn_attrs: Table<DefIndex, Lazy!(CodegenFnAttrs)>,
impl_trait_ref: Table<DefIndex, Lazy!(ty::TraitRef<'tcx>)>,
const_param_default: Table<DefIndex, Lazy<rustc_middle::ty::Const<'tcx>>>,
optimized_mir: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
/// adjusted to include an additional note. Therefore, we have to track if
/// the expectation is for the lint.
pub is_unfulfilled_lint_expectations: bool,
+ /// This will hold the name of the tool that this lint belongs to. For
+ /// the lint `clippy::some_lint` the tool would be `clippy`, the same
+ /// goes for `rustdoc`. This will be `None` for rustc lints
+ pub lint_tool: Option<Symbol>,
}
impl LintExpectation {
reason: Option<Symbol>,
emission_span: Span,
is_unfulfilled_lint_expectations: bool,
+ lint_tool: Option<Symbol>,
) -> Self {
- Self { reason, emission_span, is_unfulfilled_lint_expectations }
+ Self { reason, emission_span, is_unfulfilled_lint_expectations, lint_tool }
}
}
}
impl CodegenFnAttrs {
- pub fn new() -> CodegenFnAttrs {
+ pub const EMPTY: &'static Self = &Self::new();
+
+ pub const fn new() -> CodegenFnAttrs {
CodegenFnAttrs {
flags: CodegenFnAttrFlags::empty(),
inline: InlineAttr::None,
}
if !is_since_rustc_version {
- // The `since` field doesn't have semantic purpose in the stable `deprecated`
- // attribute, only in `rustc_deprecated`.
+ // The `since` field doesn't have semantic purpose without `#![staged_api]`.
return true;
}
// topmost deprecation. For example, if a struct is deprecated,
// the use of a field won't be linted.
//
- // #[rustc_deprecated] however wants to emit down the whole
+ // With #![staged_api], we want to emit down the whole
// hierarchy.
let depr_attr = &depr_entry.attr;
if !skip || depr_attr.is_since_rustc_version {
self.predecessor_cache.compute(&self.basic_blocks)
}
+ /// `body.switch_sources()[&(target, switch)]` returns a list of switch
+ /// values that lead to a `target` block from a `switch` block.
#[inline]
pub fn switch_sources(&self) -> &SwitchSources {
self.switch_source_cache.compute(&self.basic_blocks)
//! `Predecessors`/`PredecessorCache`.
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::stable_map::FxHashMap;
use rustc_data_structures::sync::OnceCell;
use rustc_index::vec::IndexVec;
use rustc_serialize as serialize;
use crate::mir::{BasicBlock, BasicBlockData, Terminator, TerminatorKind};
-pub type SwitchSources = IndexVec<BasicBlock, IndexVec<BasicBlock, SmallVec<[Option<u128>; 1]>>>;
+pub type SwitchSources = FxHashMap<(BasicBlock, BasicBlock), SmallVec<[Option<u128>; 1]>>;
#[derive(Clone, Debug)]
pub(super) struct SwitchSourceCache {
basic_blocks: &IndexVec<BasicBlock, BasicBlockData<'_>>,
) -> &SwitchSources {
self.cache.get_or_init(|| {
- let mut switch_sources = IndexVec::from_elem(
- IndexVec::from_elem(SmallVec::new(), basic_blocks),
- basic_blocks,
- );
+ let mut switch_sources: SwitchSources = FxHashMap::default();
for (bb, data) in basic_blocks.iter_enumerated() {
if let Some(Terminator {
kind: TerminatorKind::SwitchInt { targets, .. }, ..
}) = &data.terminator
{
for (value, target) in targets.iter() {
- switch_sources[target][bb].push(Some(value));
+ switch_sources.entry((target, bb)).or_default().push(Some(value));
}
- switch_sources[targets.otherwise()][bb].push(None);
+ switch_sources.entry((targets.otherwise(), bb)).or_default().push(None);
}
}
desc { "running analysis passes on this crate" }
}
+ /// This query checks the fulfillment of collected lint expectations.
+ /// All lint emitting queries have to be done before this is executed
+ /// to ensure that all expectations can be fulfilled.
+ ///
+ /// This is an extra query to enable other drivers (like rustdoc) to
+ /// only execute a small subset of the `analysis` query, while allowing
+ /// lints to be expected. In rustc, this query will be executed as part of
+ /// the `analysis` query and doesn't have to be called a second time.
+ ///
+ /// Tools can additionally pass in a tool filter. That will restrict the
+ /// expectations to only trigger for lints starting with the listed tool
+ /// name. This is useful for cases were not all linting code from rustc
+ /// was called. With the default `None` all registered lints will also
+ /// be checked for expectation fulfillment.
+ query check_expectations(key: Option<Symbol>) -> () {
+ eval_always
+ desc { "checking lint expectations (RFC 2383)" }
+ }
+
/// Maps from the `DefId` of an item (trait/struct/enum/fn) to its
/// associated generics.
query generics_of(key: DefId) -> ty::Generics {
query codegen_fn_attrs(def_id: DefId) -> CodegenFnAttrs {
desc { |tcx| "computing codegen attributes of `{}`", tcx.def_path_str(def_id) }
storage(ArenaCacheSelector<'tcx>)
- cache_on_disk_if { true }
+ cache_on_disk_if { def_id.is_local() }
+ separate_provide_extern
}
query asm_target_features(def_id: DefId) -> &'tcx FxHashSet<Symbol> {
use crate::hir::place::Place as HirPlace;
use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource};
+use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
use crate::middle::resolve_lifetime::{self, LifetimeScopeForPath};
use crate::middle::stability;
use crate::mir::interpret::{self, Allocation, ConstAllocation, ConstValue, Scalar};
}
impl<'tcx> TyCtxt<'tcx> {
+ /// Expects a body and returns its codegen attributes.
+ ///
+ /// Unlike `codegen_fn_attrs`, this returns `CodegenFnAttrs::EMPTY` for
+ /// constants.
+ pub fn body_codegen_attrs(self, def_id: DefId) -> &'tcx CodegenFnAttrs {
+ let def_kind = self.def_kind(def_id);
+ if def_kind.has_codegen_attrs() {
+ self.codegen_fn_attrs(def_id)
+ } else if matches!(
+ def_kind,
+ DefKind::AnonConst | DefKind::AssocConst | DefKind::Const | DefKind::InlineConst
+ ) {
+ CodegenFnAttrs::EMPTY
+ } else {
+ bug!(
+ "body_codegen_fn_attrs called on unexpected definition: {:?} {:?}",
+ def_id,
+ def_kind
+ )
+ }
+ }
+
pub fn typeck_opt_const_arg(
self,
def: ty::WithOptConstParam<LocalDefId>,
//
// In order to make it very unlikely for the sequence of bytes being hashed for
// a `GenericArgKind::Type` to be the same as the sequence of bytes being
- // hashed for one of the other variants, we hash a `0xFF` byte before hashing
- // their discriminant (since the discriminant of `TyKind` is unlikely to ever start
- // with 0xFF).
+ // hashed for one of the other variants, we hash some very high number instead
+ // of their actual discriminant since `TyKind` should never start with anything
+ // that high.
ty::subst::GenericArgKind::Type(ty) => ty.hash_stable(hcx, hasher),
ty::subst::GenericArgKind::Const(ct) => {
- 0xFFu8.hash_stable(hcx, hasher);
- mem::discriminant(self).hash_stable(hcx, hasher);
+ 0xF3u8.hash_stable(hcx, hasher);
ct.hash_stable(hcx, hasher);
}
ty::subst::GenericArgKind::Lifetime(lt) => {
- 0xFFu8.hash_stable(hcx, hasher);
- mem::discriminant(self).hash_stable(hcx, hasher);
+ 0xF5u8.hash_stable(hcx, hasher);
lt.hash_stable(hcx, hasher);
}
}
match *self {
InstanceDef::Item(ty::WithOptConstParam { did: def_id, .. })
| InstanceDef::Virtual(def_id, _) => {
- tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::TRACK_CALLER)
+ tcx.body_codegen_attrs(def_id).flags.contains(CodegenFnAttrFlags::TRACK_CALLER)
}
InstanceDef::ClosureOnceShim { call_once: _, track_caller } => track_caller,
_ => false,
use rustc_ast as ast;
use rustc_attr as attr;
use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_index::bit_set::BitSet;
use rustc_index::vec::{Idx, IndexVec};
}
}
+/// Enforce some basic invariants on layouts.
+fn sanity_check_layout<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ layout: &TyAndLayout<'tcx>,
+) {
+ // Type-level uninhabitedness should always imply ABI uninhabitedness.
+ if tcx.conservative_is_privately_uninhabited(param_env.and(layout.ty)) {
+ assert!(layout.abi.is_uninhabited());
+ }
+
+ if cfg!(debug_assertions) {
+ fn check_layout_abi<'tcx>(tcx: TyCtxt<'tcx>, layout: Layout<'tcx>) {
+ match layout.abi() {
+ Abi::Scalar(_scalar) => {
+ // No padding in scalars.
+ /* FIXME(#96185):
+ assert_eq!(
+ layout.align().abi,
+ scalar.align(&tcx).abi,
+ "alignment mismatch between ABI and layout in {layout:#?}"
+ );
+ assert_eq!(
+ layout.size(),
+ scalar.size(&tcx),
+ "size mismatch between ABI and layout in {layout:#?}"
+ );*/
+ }
+ Abi::Vector { count, element } => {
+ // No padding in vectors. Alignment can be strengthened, though.
+ assert!(
+ layout.align().abi >= element.align(&tcx).abi,
+ "alignment mismatch between ABI and layout in {layout:#?}"
+ );
+ let size = element.size(&tcx) * count;
+ assert_eq!(
+ layout.size(),
+ size.align_to(tcx.data_layout().vector_align(size).abi),
+ "size mismatch between ABI and layout in {layout:#?}"
+ );
+ }
+ Abi::ScalarPair(scalar1, scalar2) => {
+ // Sanity-check scalar pairs. These are a bit more flexible and support
+ // padding, but we can at least ensure both fields actually fit into the layout
+ // and the alignment requirement has not been weakened.
+ let align1 = scalar1.align(&tcx).abi;
+ let align2 = scalar2.align(&tcx).abi;
+ assert!(
+ layout.align().abi >= cmp::max(align1, align2),
+ "alignment mismatch between ABI and layout in {layout:#?}",
+ );
+ let field2_offset = scalar1.size(&tcx).align_to(align2);
+ assert!(
+ layout.size() >= field2_offset + scalar2.size(&tcx),
+ "size mismatch between ABI and layout in {layout:#?}"
+ );
+ }
+ Abi::Uninhabited | Abi::Aggregate { .. } => {} // Nothing to check.
+ }
+ }
+
+ check_layout_abi(tcx, layout.layout);
+
+ if let Variants::Multiple { variants, .. } = &layout.variants {
+ for variant in variants {
+ check_layout_abi(tcx, *variant);
+ // No nested "multiple".
+ assert!(matches!(variant.variants(), Variants::Single { .. }));
+ // Skip empty variants.
+ if variant.size() == Size::ZERO
+ || variant.fields().count() == 0
+ || variant.abi().is_uninhabited()
+ {
+ // These are never actually accessed anyway, so we can skip them. (Note that
+ // sometimes, variants with fields have size 0, and sometimes, variants without
+ // fields have non-0 size.)
+ continue;
+ }
+ // Variants should have the same or a smaller size as the full thing.
+ if variant.size() > layout.size {
+ bug!(
+ "Type with size {} bytes has variant with size {} bytes: {layout:#?}",
+ layout.size.bytes(),
+ variant.size().bytes(),
+ )
+ }
+ // The top-level ABI and the ABI of the variants should be coherent.
+ let abi_coherent = match (layout.abi, variant.abi()) {
+ (Abi::Scalar(..), Abi::Scalar(..)) => true,
+ (Abi::ScalarPair(..), Abi::ScalarPair(..)) => true,
+ (Abi::Uninhabited, _) => true,
+ (Abi::Aggregate { .. }, _) => true,
+ _ => false,
+ };
+ if !abi_coherent {
+ bug!(
+ "Variant ABI is incompatible with top-level ABI:\nvariant={:#?}\nTop-level: {layout:#?}",
+ variant
+ );
+ }
+ }
+ }
+ }
+}
+
#[instrument(skip(tcx, query), level = "debug")]
fn layout_of<'tcx>(
tcx: TyCtxt<'tcx>,
cx.record_layout_for_printing(layout);
- // Type-level uninhabitedness should always imply ABI uninhabitedness.
- if tcx.conservative_is_privately_uninhabited(param_env.and(ty)) {
- assert!(layout.abi.is_uninhabited());
- }
+ sanity_check_layout(tcx, param_env, &layout);
Ok(layout)
})
};
let mut abi = Abi::Aggregate { sized: true };
- // Without latter check aligned enums with custom discriminant values
- // Would result in ICE see the issue #92464 for more info
- if tag.size(dl) == size || variants.iter().all(|layout| layout.is_empty()) {
+ if layout_variants.iter().all(|v| v.abi.is_uninhabited()) {
+ abi = Abi::Uninhabited;
+ } else if tag.size(dl) == size || variants.iter().all(|layout| layout.is_empty()) {
+ // Without latter check aligned enums with custom discriminant values
+ // Would result in ICE see the issue #92464 for more info
abi = Abi::Scalar(tag);
} else {
// Try to use a ScalarPair for all tagged enums.
}
}
- if layout_variants.iter().all(|v| v.abi.is_uninhabited()) {
- abi = Abi::Uninhabited;
+ // If we pick a "clever" (by-value) ABI, we might have to adjust the ABI of the
+ // variants to ensure they are consistent. This is because a downcast is
+ // semantically a NOP, and thus should not affect layout.
+ if matches!(abi, Abi::Scalar(..) | Abi::ScalarPair(..)) {
+ for variant in &mut layout_variants {
+ // We only do this for variants with fields; the others are not accessed anyway.
+ // Also do not overwrite any already existing "clever" ABIs.
+ if variant.fields.count() > 0
+ && matches!(variant.abi, Abi::Aggregate { .. })
+ {
+ variant.abi = abi;
+ // Also need to bump up the size and alignment, so that the entire value fits in here.
+ variant.size = cmp::max(variant.size, size);
+ variant.align.abi = cmp::max(variant.align.abi, align.abi);
+ }
+ }
}
let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag);
/// with `-Cpanic=abort` will look like they can't unwind when in fact they
/// might (from a foreign exception or similar).
#[inline]
-pub fn fn_can_unwind<'tcx>(
- tcx: TyCtxt<'tcx>,
- codegen_fn_attr_flags: CodegenFnAttrFlags,
- abi: SpecAbi,
-) -> bool {
- // Special attribute for functions which can't unwind.
- if codegen_fn_attr_flags.contains(CodegenFnAttrFlags::NEVER_UNWIND) {
- return false;
+pub fn fn_can_unwind<'tcx>(tcx: TyCtxt<'tcx>, fn_def_id: Option<DefId>, abi: SpecAbi) -> bool {
+ if let Some(did) = fn_def_id {
+ // Special attribute for functions which can't unwind.
+ if tcx.codegen_fn_attrs(did).flags.contains(CodegenFnAttrFlags::NEVER_UNWIND) {
+ return false;
+ }
+
+ // With -Z panic-in-drop=abort, drop_in_place never unwinds.
+ //
+ // This is not part of `codegen_fn_attrs` as it can differ between crates
+ // and therefore cannot be computed in core.
+ if tcx.sess.opts.debugging_opts.panic_in_drop == PanicStrategy::Abort {
+ if Some(did) == tcx.lang_items().drop_in_place_fn() {
+ return false;
+ }
+ }
}
// Otherwise if this isn't special then unwinding is generally determined by
) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> {
let (param_env, (sig, extra_args)) = query.into_parts();
- LayoutCx { tcx, param_env }.fn_abi_new_uncached(
- sig,
- extra_args,
- None,
- CodegenFnAttrFlags::empty(),
- false,
- )
+ LayoutCx { tcx, param_env }.fn_abi_new_uncached(sig, extra_args, None, None, false)
}
fn fn_abi_of_instance<'tcx>(
None
};
- let attrs = tcx.codegen_fn_attrs(instance.def_id()).flags;
-
LayoutCx { tcx, param_env }.fn_abi_new_uncached(
sig,
extra_args,
caller_location,
- attrs,
+ Some(instance.def_id()),
matches!(instance.def, ty::InstanceDef::Virtual(..)),
)
}
sig: ty::PolyFnSig<'tcx>,
extra_args: &[Ty<'tcx>],
caller_location: Option<Ty<'tcx>>,
- codegen_fn_attr_flags: CodegenFnAttrFlags,
+ fn_def_id: Option<DefId>,
// FIXME(eddyb) replace this with something typed, like an `enum`.
force_thin_self_ptr: bool,
) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> {
c_variadic: sig.c_variadic,
fixed_count: inputs.len(),
conv,
- can_unwind: fn_can_unwind(self.tcx(), codegen_fn_attr_flags, sig.abi),
+ can_unwind: fn_can_unwind(self.tcx(), fn_def_id, sig.abi),
};
self.fn_abi_adjust_for_abi(&mut fn_abi, sig.abi)?;
debug!("fn_abi_new_uncached = {:?}", fn_abi);
use rustc_hir::def_id::DefId;
use rustc_macros::HashStable;
use rustc_serialize::{self, Decodable, Encodable};
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::DUMMY_SP;
use smallvec::SmallVec;
use core::intrinsics;
}
}
-///////////////////////////////////////////////////////////////////////////
-// Public trait `Subst`
-//
-// Just call `foo.subst(tcx, substs)` to perform a substitution across
-// `foo`. Or use `foo.subst_spanned(tcx, substs, Some(span))` when
-// there is more information available (for better errors).
-
+// Just call `foo.subst(tcx, substs)` to perform a substitution across `foo`.
pub trait Subst<'tcx>: Sized {
- fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Self {
- self.subst_spanned(tcx, substs, None)
- }
-
- fn subst_spanned(
- self,
- tcx: TyCtxt<'tcx>,
- substs: &[GenericArg<'tcx>],
- span: Option<Span>,
- ) -> Self;
+ fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Self;
}
impl<'tcx, T: TypeFoldable<'tcx>> Subst<'tcx> for T {
- fn subst_spanned(
- self,
- tcx: TyCtxt<'tcx>,
- substs: &[GenericArg<'tcx>],
- span: Option<Span>,
- ) -> T {
- let mut folder = SubstFolder { tcx, substs, span, binders_passed: 0 };
+ fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> T {
+ let mut folder = SubstFolder { tcx, substs, binders_passed: 0 };
self.fold_with(&mut folder)
}
}
tcx: TyCtxt<'tcx>,
substs: &'a [GenericArg<'tcx>],
- /// The location for which the substitution is performed, if available.
- span: Option<Span>,
-
/// Number of region binders we have passed through while doing the substitution
binders_passed: u32,
}
match rk {
Some(GenericArgKind::Lifetime(lt)) => self.shift_region_through_binders(lt),
_ => {
- let span = self.span.unwrap_or(DUMMY_SP);
let msg = format!(
"Region parameter out of range \
when substituting in region {} (index={})",
data.name, data.index
);
- span_bug!(span, "{}", msg);
+ span_bug!(DUMMY_SP, "{}", msg);
}
}
}
let ty = match opt_ty {
Some(GenericArgKind::Type(ty)) => ty,
Some(kind) => {
- let span = self.span.unwrap_or(DUMMY_SP);
span_bug!(
- span,
+ DUMMY_SP,
"expected type for `{:?}` ({:?}/{}) but found {:?} \
when substituting, substs={:?}",
p,
);
}
None => {
- let span = self.span.unwrap_or(DUMMY_SP);
span_bug!(
- span,
+ DUMMY_SP,
"type parameter `{:?}` ({:?}/{}) out of range \
when substituting, substs={:?}",
p,
let ct = match opt_ct {
Some(GenericArgKind::Const(ct)) => ct,
Some(kind) => {
- let span = self.span.unwrap_or(DUMMY_SP);
span_bug!(
- span,
+ DUMMY_SP,
"expected const for `{:?}` ({:?}/{}) but found {:?} \
when substituting substs={:?}",
p,
);
}
None => {
- let span = self.span.unwrap_or(DUMMY_SP);
span_bug!(
- span,
+ DUMMY_SP,
"const parameter `{:?}` ({:?}/{}) out of range \
when substituting substs={:?}",
p,
body_unsafety: BodyUnsafety,
/// The `#[target_feature]` attributes of the body. Used for checking
/// calls to functions with `#[target_feature]` (RFC 2396).
- body_target_features: &'tcx Vec<Symbol>,
+ body_target_features: &'tcx [Symbol],
/// When inside the LHS of an assignment to a field, this is the type
/// of the LHS and the span of the assignment expression.
assignment_info: Option<(Ty<'tcx>, Span)>,
return;
}
- let (thir, expr) = match tcx.thir_body(def) {
- Ok(body) => body,
- Err(_) => return,
+ let Ok((thir, expr)) = tcx.thir_body(def) else {
+ return
};
let thir = &thir.borrow();
// If `thir` is empty, a type error occurred, skip this body.
BodyUnsafety::Safe
}
});
- let body_target_features = &tcx.codegen_fn_attrs(def.did).target_features;
+ let body_target_features = &tcx.body_codegen_attrs(def.did.to_def_id()).target_features;
let safety_context =
if body_unsafety.is_unsafe() { SafetyContext::UnsafeFn } else { SafetyContext::Safe };
let mut visitor = UnsafetyVisitor {
mir::TerminatorKind::SwitchInt { targets: _, ref discr, switch_ty: _ } => {
let mut applier = BackwardSwitchIntEdgeEffectsApplier {
+ body,
pred,
exit_state,
- values: &body.switch_sources()[bb][pred],
bb,
propagate: &mut propagate,
effects_applied: false,
}
struct BackwardSwitchIntEdgeEffectsApplier<'a, D, F> {
+ body: &'a mir::Body<'a>,
pred: BasicBlock,
exit_state: &'a mut D,
- values: &'a [Option<u128>],
bb: BasicBlock,
propagate: &'a mut F,
fn apply(&mut self, mut apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)) {
assert!(!self.effects_applied);
- let targets = self.values.iter().map(|&value| SwitchIntTarget { value, target: self.bb });
+ let values = &self.body.switch_sources()[&(self.bb, self.pred)];
+ let targets = values.iter().map(|&value| SwitchIntTarget { value, target: self.bb });
let mut tmp = None;
for target in targets {
use crate::MirPass;
use rustc_hir::def::DefKind;
-use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir::*;
use rustc_middle::ty::layout;
use rustc_middle::ty::{self, TyCtxt};
//
// Here we test for this function itself whether its ABI allows
// unwinding or not.
- let body_flags = tcx.codegen_fn_attrs(def_id).flags;
let body_ty = tcx.type_of(def_id);
let body_abi = match body_ty.kind() {
ty::FnDef(..) => body_ty.fn_sig(tcx).abi(),
ty::Generator(..) => Abi::Rust,
_ => span_bug!(body.span, "unexpected body ty: {:?}", body_ty),
};
- let body_can_unwind = layout::fn_can_unwind(tcx, body_flags, body_abi);
+ let body_can_unwind = layout::fn_can_unwind(tcx, Some(def_id), body_abi);
// Look in this function body for any basic blocks which are terminated
// with a function call, and whose function we're calling may unwind.
TerminatorKind::Call { func, .. } => {
let ty = func.ty(body, tcx);
let sig = ty.fn_sig(tcx);
- let flags = match ty.kind() {
- ty::FnPtr(_) => CodegenFnAttrFlags::empty(),
- ty::FnDef(def_id, _) => tcx.codegen_fn_attrs(*def_id).flags,
+ let fn_def_id = match ty.kind() {
+ ty::FnPtr(_) => None,
+ &ty::FnDef(def_id, _) => Some(def_id),
_ => span_bug!(span, "invalid callee of type {:?}", ty),
};
- layout::fn_can_unwind(tcx, flags, sig.abi())
+ layout::fn_can_unwind(tcx, fn_def_id, sig.abi())
}
TerminatorKind::Drop { .. } | TerminatorKind::DropAndReplace { .. } => {
tcx.sess.opts.debugging_opts.panic_in_drop == PanicStrategy::Unwind
- && layout::fn_can_unwind(tcx, CodegenFnAttrFlags::empty(), Abi::Rust)
+ && layout::fn_can_unwind(tcx, None, Abi::Rust)
}
TerminatorKind::Assert { .. } | TerminatorKind::FalseUnwind { .. } => {
- layout::fn_can_unwind(tcx, CodegenFnAttrFlags::empty(), Abi::Rust)
+ layout::fn_can_unwind(tcx, None, Abi::Rust)
}
_ => continue,
};
}
let callee_features = &self.tcx.codegen_fn_attrs(func_did).target_features;
- let self_features = &self.tcx.codegen_fn_attrs(self.body_did).target_features;
+ // The body might be a constant, so it doesn't have codegen attributes.
+ let self_features = &self.tcx.body_codegen_attrs(self.body_did.to_def_id()).target_features;
// Is `callee_features` a subset of `calling_features`?
if !callee_features.iter().all(|feature| self_features.contains(feature)) {
//! conflicts between multiple such attributes attached to the same
//! item.
-use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
+use rustc_ast::tokenstream::DelimSpan;
+use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MacArgs, MetaItemKind, NestedMetaItem};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan};
use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
sym::rustc_allow_const_fn_unstable => {
self.check_rustc_allow_const_fn_unstable(hir_id, &attr, span, target)
}
+ sym::rustc_std_internal_symbol => {
+ self.check_rustc_std_internal_symbol(&attr, span, target)
+ }
sym::naked => self.check_naked(hir_id, attr, span, target),
sym::rustc_legacy_const_generics => {
self.check_rustc_legacy_const_generics(&attr, span, target, item)
return;
}
+ // FIXME(@lcnr): this doesn't belong here.
if matches!(target, Target::Closure | Target::Fn | Target::Method(_) | Target::ForeignFn) {
self.tcx.ensure().codegen_fn_attrs(self.tcx.hir().local_def_id(hir_id));
}
}
}
+ /// Checks `#[doc(hidden)]` attributes. Returns `true` if valid.
+ fn check_doc_hidden(
+ &self,
+ attr: &Attribute,
+ meta_index: usize,
+ meta: &NestedMetaItem,
+ hir_id: HirId,
+ target: Target,
+ ) -> bool {
+ if let Target::AssocConst
+ | Target::AssocTy
+ | Target::Method(MethodKind::Trait { body: true }) = target
+ {
+ let parent_hir_id = self.tcx.hir().get_parent_item(hir_id);
+ let containing_item = self.tcx.hir().expect_item(parent_hir_id);
+
+ if Target::from_item(containing_item) == Target::Impl {
+ let meta_items = attr.meta_item_list().unwrap();
+
+ let (span, replacement_span) = if meta_items.len() == 1 {
+ (attr.span, attr.span)
+ } else {
+ let meta_span = meta.span();
+ (
+ meta_span,
+ meta_span.until(match meta_items.get(meta_index + 1) {
+ Some(next_item) => next_item.span(),
+ None => match attr.get_normal_item().args {
+ MacArgs::Delimited(DelimSpan { close, .. }, ..) => close,
+ _ => unreachable!(),
+ },
+ }),
+ )
+ };
+
+ // FIXME: #[doc(hidden)] was previously erroneously allowed on trait impl items,
+ // so for backward compatibility only emit a warning and do not mark it as invalid.
+ self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, span, |lint| {
+ lint.build("`#[doc(hidden)]` is ignored on trait impl items")
+ .warn(
+ "this was previously accepted by the compiler but is \
+ being phased out; it will become a hard error in \
+ a future release!",
+ )
+ .note(
+ "whether the impl item is `doc(hidden)` or not \
+ entirely depends on the corresponding trait item",
+ )
+ .span_suggestion(
+ replacement_span,
+ "remove this attribute",
+ String::new(),
+ Applicability::MachineApplicable,
+ )
+ .emit();
+ });
+ }
+ }
+
+ true
+ }
+
/// Checks that an attribute is *not* used at the crate level. Returns `true` if valid.
fn check_attr_not_crate_level(
&self,
let mut is_valid = true;
if let Some(mi) = attr.meta() && let Some(list) = mi.meta_item_list() {
- for meta in list {
+ for (meta_index, meta) in list.into_iter().enumerate() {
if let Some(i_meta) = meta.meta_item() {
match i_meta.name_or_empty() {
sym::alias
is_valid = false;
}
+ sym::hidden if !self.check_doc_hidden(attr,
+ meta_index,
+ meta,
+ hir_id,
+ target,
+ ) => {
+ is_valid = false;
+ }
+
// no_default_passes: deprecated
// passes: deprecated
// plugins: removed, but rustdoc warns about it itself
}
}
sym::align => {
- if let (Target::Fn, true) = (target, !self.tcx.features().fn_align) {
+ if let (Target::Fn, false) = (target, self.tcx.features().fn_align) {
feature_err(
&self.tcx.sess.parse_sess,
sym::fn_align,
}
}
+ fn check_rustc_std_internal_symbol(
+ &self,
+ attr: &Attribute,
+ span: Span,
+ target: Target,
+ ) -> bool {
+ match target {
+ Target::Fn | Target::Static => true,
+ _ => {
+ self.tcx
+ .sess
+ .struct_span_err(attr.span, "attribute should be applied functions or statics")
+ .span_label(span, "not a function or static")
+ .emit();
+ false
+ }
+ }
+ }
+
/// default_method_body_is_const should only be applied to trait methods with default bodies.
fn check_default_method_body_is_const(
&self,
}
let def_id = tcx.hir().local_def_id(id);
- let cg_attrs = tcx.codegen_fn_attrs(def_id);
-
- // #[used], #[no_mangle], #[export_name], etc also keeps the item alive
- // forcefully, e.g., for placing it in a specific section.
- if cg_attrs.contains_extern_indicator()
- || cg_attrs.flags.contains(CodegenFnAttrFlags::USED)
- || cg_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
- {
- return true;
+ if tcx.def_kind(def_id).has_codegen_attrs() {
+ let cg_attrs = tcx.codegen_fn_attrs(def_id);
+
+ // #[used], #[no_mangle], #[export_name], etc also keeps the item alive
+ // forcefully, e.g., for placing it in a specific section.
+ if cg_attrs.contains_extern_indicator()
+ || cg_attrs.flags.contains(CodegenFnAttrFlags::USED)
+ || cg_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
+ {
+ return true;
+ }
}
tcx.lint_level_at_node(lint::builtin::DEAD_CODE, id).0 == lint::Allow
} else {
false
};
- let codegen_attrs = self.tcx.codegen_fn_attrs(search_item);
+ let codegen_attrs = if self.tcx.def_kind(search_item).has_codegen_attrs() {
+ self.tcx.codegen_fn_attrs(search_item)
+ } else {
+ CodegenFnAttrs::EMPTY
+ };
let is_extern = codegen_attrs.contains_extern_indicator();
let std_internal =
codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL);
// Anything which has custom linkage gets thrown on the worklist no
// matter where it is in the crate, along with "special std symbols"
// which are currently akin to allocator symbols.
- let codegen_attrs = self.tcx.codegen_fn_attrs(def_id);
- if codegen_attrs.contains_extern_indicator()
- || codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
- // FIXME(nbdd0121): `#[used]` are marked as reachable here so it's picked up by
- // `linked_symbols` in cg_ssa. They won't be exported in binary or cdylib due to their
- // `SymbolExportLevel::Rust` export level but may end up being exported in dylibs.
- || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED)
- || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
- {
- self.worklist.push(def_id);
+ if self.tcx.def_kind(def_id).has_codegen_attrs() {
+ let codegen_attrs = self.tcx.codegen_fn_attrs(def_id);
+ if codegen_attrs.contains_extern_indicator()
+ || codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
+ // FIXME(nbdd0121): `#[used]` are marked as reachable here so it's picked up by
+ // `linked_symbols` in cg_ssa. They won't be exported in binary or cdylib due to their
+ // `SymbolExportLevel::Rust` export level but may end up being exported in dylibs.
+ || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED)
+ || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
+ {
+ self.worklist.push(def_id);
+ }
}
}
}
}
}
+impl Key for Option<Symbol> {
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ true
+ }
+ fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
+ DUMMY_SP
+ }
+}
+
/// Canonical query goals correspond to abstract trait operations that
/// are not tied to any crate in particular.
impl<'tcx, T> Key for Canonical<'tcx, T> {
#[macro_use]
extern crate rustc_middle;
+use rustc_hir::def::DefKind;
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::subst::SubstsRef;
}
// FIXME(eddyb) Precompute a custom symbol name based on attributes.
- let attrs = tcx.codegen_fn_attrs(def_id);
+ let attrs = if tcx.def_kind(def_id).has_codegen_attrs() {
+ tcx.codegen_fn_attrs(def_id)
+ } else {
+ CodegenFnAttrs::EMPTY
+ };
// Foreign items by default use no mangling for their symbol name. There's a
// few exceptions to this rule though:
return tcx.item_name(def_id).to_string();
}
- let avoid_cross_crate_conflicts =
- // If this is an instance of a generic function, we also hash in
- // the ID of the instantiating crate. This avoids symbol conflicts
- // in case the same instances is emitted in two crates of the same
- // project.
- is_generic(substs) ||
+ // If we're dealing with an instance of a function that's inlined from
+ // another crate but we're marking it as globally shared to our
+ // compilation (aka we're not making an internal copy in each of our
+ // codegen units) then this symbol may become an exported (but hidden
+ // visibility) symbol. This means that multiple crates may do the same
+ // and we want to be sure to avoid any symbol conflicts here.
+ let is_globally_shared_function = matches!(
+ tcx.def_kind(instance.def_id()),
+ DefKind::Fn | DefKind::AssocFn | DefKind::Closure | DefKind::Generator | DefKind::Ctor(..)
+ ) && matches!(
+ MonoItem::Fn(instance).instantiation_mode(tcx),
+ InstantiationMode::GloballyShared { may_conflict: true }
+ );
- // If we're dealing with an instance of a function that's inlined from
- // another crate but we're marking it as globally shared to our
- // compilation (aka we're not making an internal copy in each of our
- // codegen units) then this symbol may become an exported (but hidden
- // visibility) symbol. This means that multiple crates may do the same
- // and we want to be sure to avoid any symbol conflicts here.
- matches!(MonoItem::Fn(instance).instantiation_mode(tcx), InstantiationMode::GloballyShared { may_conflict: true });
+ // If this is an instance of a generic function, we also hash in
+ // the ID of the instantiating crate. This avoids symbol conflicts
+ // in case the same instances is emitted in two crates of the same
+ // project.
+ let avoid_cross_crate_conflicts = is_generic(substs) || is_globally_shared_function;
let instantiating_crate =
if avoid_cross_crate_conflicts { Some(compute_instantiating_crate()) } else { None };
self.in_progress_typeck_results.map(|t| t.borrow())
&& let ty = typeck_results.expr_ty_adjusted(base)
&& let ty::FnDef(def_id, _substs) = ty.kind()
- && let Some(hir::Node::Item(hir::Item { span, ident, .. })) =
+ && let Some(hir::Node::Item(hir::Item { ident, span, vis_span, .. })) =
hir.get_if_local(*def_id)
{
- err.span_suggestion_verbose(
- span.shrink_to_lo(),
- &format!(
- "alternatively, consider making `fn {}` asynchronous",
- ident
- ),
- "async ".to_string(),
- Applicability::MaybeIncorrect,
+ let msg = format!(
+ "alternatively, consider making `fn {}` asynchronous",
+ ident
);
+ if vis_span.is_empty() {
+ err.span_suggestion_verbose(
+ span.shrink_to_lo(),
+ &msg,
+ "async ".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ err.span_suggestion_verbose(
+ vis_span.shrink_to_hi(),
+ &msg,
+ " async".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
}
}
}
debug!("impossible_predicates(predicates={:?})", predicates);
let result = tcx.infer_ctxt().enter(|infcx| {
+ // HACK: Set tainted by errors to gracefully exit in case of overflow.
+ infcx.set_tainted_by_errors();
+
let param_env = ty::ParamEnv::reveal_all();
let mut selcx = SelectionContext::new(&infcx);
let mut fulfill_cx = FulfillmentContext::new();
let errors = fulfill_cx.select_all_or_error(&infcx);
+ // Clean up after ourselves
+ let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+
!errors.is_empty()
});
debug!("impossible_predicates = {:?}", result);
debug!("subst_and_check_impossible_predicates(key={:?})", key);
let mut predicates = tcx.predicates_of(key.0).instantiate(tcx, key.1).predicates;
+
+ // Specifically check trait fulfillment to avoid an error when trying to resolve
+ // associated items.
+ if let Some(trait_def_id) = tcx.trait_of_item(key.0) {
+ let trait_ref = ty::TraitRef::from_method(tcx, trait_def_id, key.1);
+ predicates.push(ty::Binder::dummy(trait_ref).to_poly_trait_predicate().to_predicate(tcx));
+ }
+
predicates.retain(|predicate| !predicate.needs_subst());
let result = impossible_predicates(tcx, predicates);
// Get components of trait alias.
let predicates = tcx.super_predicates_of(trait_ref.def_id());
+ debug!(?predicates);
let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| {
pred.subst_supertrait(tcx, &trait_ref)
.to_opt_poly_trait_pred()
.map(|trait_ref| item.clone_and_push(trait_ref.map_bound(|t| t.trait_ref), *span))
});
- debug!("expand_trait_aliases: items={:?}", items.clone());
+ debug!("expand_trait_aliases: items={:?}", items.clone().collect::<Vec<_>>());
self.stack.extend(items);
self.astconv
.normalize_ty(
self.span,
- tcx.at(self.span).type_of(param.def_id).subst_spanned(
- tcx,
- substs,
- Some(self.span),
- ),
+ tcx.at(self.span).type_of(param.def_id).subst(tcx, substs),
)
.into()
}
GenericParamDefKind::Const { has_default } => {
let ty = tcx.at(self.span).type_of(param.def_id);
if !infer_args && has_default {
- tcx.const_param_default(param.def_id)
- .subst_spanned(tcx, substs.unwrap(), Some(self.span))
- .into()
+ tcx.const_param_default(param.def_id).subst(tcx, substs.unwrap()).into()
} else {
if infer_args {
self.astconv.ct_infer(ty, Some(param), self.span).into()
let mut bounds = Bounds::default();
self.add_bounds(param_ty, ast_bounds.iter(), &mut bounds, ty::List::empty());
+ debug!(?bounds);
bounds
}
// is used and no 'maybe' bounds are used.
let expanded_traits =
traits::expand_trait_aliases(tcx, bounds.trait_bounds.iter().map(|&(a, b, _)| (a, b)));
- let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) =
- expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
+ let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) = expanded_traits
+ .filter(|i| i.trait_ref().self_ty().skip_binder() == dummy_self)
+ .partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
if regular_traits.len() > 1 {
let first_trait = ®ular_traits[0];
let additional_trait = ®ular_traits[1];
}
if regular_traits.is_empty() && auto_traits.is_empty() {
- tcx.sess.emit_err(TraitObjectDeclaredWithNoTraits { span });
+ let trait_alias_span = bounds
+ .trait_bounds
+ .iter()
+ .map(|&(trait_ref, _, _)| trait_ref.def_id())
+ .find(|&trait_ref| tcx.is_trait_alias(trait_ref))
+ .map(|trait_ref| tcx.def_span(trait_ref));
+ tcx.sess.emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span });
return tcx.ty_error();
}
enum CallStep<'tcx> {
Builtin(Ty<'tcx>),
- DeferredClosure(ty::FnSig<'tcx>),
+ DeferredClosure(DefId, ty::FnSig<'tcx>),
/// E.g., enum variant constructors.
Overloaded(MethodCallee<'tcx>),
}
self.confirm_builtin_call(call_expr, callee_expr, callee_ty, arg_exprs, expected)
}
- Some(CallStep::DeferredClosure(fn_sig)) => {
- self.confirm_deferred_closure_call(call_expr, arg_exprs, expected, fn_sig)
+ Some(CallStep::DeferredClosure(def_id, fn_sig)) => {
+ self.confirm_deferred_closure_call(call_expr, arg_exprs, expected, def_id, fn_sig)
}
Some(CallStep::Overloaded(method_callee)) => {
closure_substs: substs,
},
);
- return Some(CallStep::DeferredClosure(closure_sig));
+ return Some(CallStep::DeferredClosure(def_id, closure_sig));
}
}
call_expr: &'tcx hir::Expr<'tcx>,
arg_exprs: &'tcx [hir::Expr<'tcx>],
expected: Expectation<'tcx>,
+ closure_def_id: DefId,
fn_sig: ty::FnSig<'tcx>,
) -> Ty<'tcx> {
// `fn_sig` is the *signature* of the closure being called. We
arg_exprs,
fn_sig.c_variadic,
TupleArgumentsFlag::TupleArguments,
- None,
+ Some(closure_def_id),
);
fn_sig.output()
use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind};
use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
use rustc_infer::traits::util;
-use rustc_middle::ty;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::subst::{InternalSubsts, Subst};
use rustc_middle::ty::util::ExplicitSelf;
+use rustc_middle::ty::{self, DefIdTree};
use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
use rustc_span::Span;
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
return;
}
+ if let Err(_) = compare_generic_param_kinds(tcx, impl_m, trait_m) {
+ return;
+ }
+
if let Err(_) =
compare_number_of_method_arguments(tcx, impl_m, impl_m_span, trait_m, trait_item_span)
{
{
return;
}
-
- if let Err(_) = compare_const_param_types(tcx, impl_m, trait_m, trait_item_span) {
- return;
- }
}
fn compare_predicate_entailment<'tcx>(
Ok(())
}
+/// Checks that the number of generics on a given assoc item in a trait impl is the same
+/// as the number of generics on the respective assoc item in the trait definition.
+///
+/// For example this code emits the errors in the following code:
+/// ```
+/// trait Trait {
+/// fn foo();
+/// type Assoc<T>;
+/// }
+///
+/// impl Trait for () {
+/// fn foo<T>() {}
+/// //~^ error
+/// type Assoc = u32;
+/// //~^ error
+/// }
+/// ```
+///
+/// Notably this does not error on `foo<T>` implemented as `foo<const N: u8>` or
+/// `foo<const N: u8>` implemented as `foo<const N: u32>`. This is handled in
+/// [`compare_generic_param_kinds`]. This function also does not handle lifetime parameters
fn compare_number_of_generics<'tcx>(
tcx: TyCtxt<'tcx>,
impl_: &ty::AssocItem,
let trait_own_counts = tcx.generics_of(trait_.def_id).own_counts();
let impl_own_counts = tcx.generics_of(impl_.def_id).own_counts();
+ // This avoids us erroring on `foo<T>` implemented as `foo<const N: u8>` as this is implemented
+ // in `compare_generic_param_kinds` which will give a nicer error message than something like:
+ // "expected 1 type parameter, found 0 type parameters"
+ if (trait_own_counts.types + trait_own_counts.consts)
+ == (impl_own_counts.types + impl_own_counts.consts)
+ {
+ return Ok(());
+ }
+
let matchings = [
("type", trait_own_counts.types, impl_own_counts.types),
("const", trait_own_counts.consts, impl_own_counts.consts),
if let Some(reported) = error_found { Err(reported) } else { Ok(()) }
}
-fn compare_const_param_types<'tcx>(
+/// Checks that all parameters in the generics of a given assoc item in a trait impl have
+/// the same kind as the respective generic parameter in the trait def.
+///
+/// For example all 4 errors in the following code are emitted here:
+/// ```
+/// trait Foo {
+/// fn foo<const N: u8>();
+/// type bar<const N: u8>;
+/// fn baz<const N: u32>();
+/// type blah<T>;
+/// }
+///
+/// impl Foo for () {
+/// fn foo<const N: u64>() {}
+/// //~^ error
+/// type bar<const N: u64> {}
+/// //~^ error
+/// fn baz<T>() {}
+/// //~^ error
+/// type blah<const N: i64> = u32;
+/// //~^ error
+/// }
+/// ```
+///
+/// This function does not handle lifetime parameters
+fn compare_generic_param_kinds<'tcx>(
tcx: TyCtxt<'tcx>,
- impl_m: &ty::AssocItem,
- trait_m: &ty::AssocItem,
- trait_item_span: Option<Span>,
+ impl_item: &ty::AssocItem,
+ trait_item: &ty::AssocItem,
) -> Result<(), ErrorGuaranteed> {
- let const_params_of = |def_id| {
- tcx.generics_of(def_id).params.iter().filter_map(|param| match param.kind {
- GenericParamDefKind::Const { .. } => Some(param.def_id),
- _ => None,
+ assert_eq!(impl_item.kind, trait_item.kind);
+
+ let ty_const_params_of = |def_id| {
+ tcx.generics_of(def_id).params.iter().filter(|param| {
+ matches!(
+ param.kind,
+ GenericParamDefKind::Const { .. } | GenericParamDefKind::Type { .. }
+ )
})
};
- let const_params_impl = const_params_of(impl_m.def_id);
- let const_params_trait = const_params_of(trait_m.def_id);
-
- for (const_param_impl, const_param_trait) in iter::zip(const_params_impl, const_params_trait) {
- let impl_ty = tcx.type_of(const_param_impl);
- let trait_ty = tcx.type_of(const_param_trait);
- if impl_ty != trait_ty {
- let (impl_span, impl_ident) = match tcx.hir().get_if_local(const_param_impl) {
- Some(hir::Node::GenericParam(hir::GenericParam { span, name, .. })) => (
- span,
- match name {
- hir::ParamName::Plain(ident) => Some(ident),
- _ => None,
- },
- ),
- other => bug!(
- "expected GenericParam, found {:?}",
- other.map_or_else(|| "nothing".to_string(), |n| format!("{:?}", n))
- ),
- };
- let trait_span = match tcx.hir().get_if_local(const_param_trait) {
- Some(hir::Node::GenericParam(hir::GenericParam { span, .. })) => Some(span),
- _ => None,
- };
+
+ for (param_impl, param_trait) in
+ iter::zip(ty_const_params_of(impl_item.def_id), ty_const_params_of(trait_item.def_id))
+ {
+ use GenericParamDefKind::*;
+ if match (¶m_impl.kind, ¶m_trait.kind) {
+ (Const { .. }, Const { .. })
+ if tcx.type_of(param_impl.def_id) != tcx.type_of(param_trait.def_id) =>
+ {
+ true
+ }
+ (Const { .. }, Type { .. }) | (Type { .. }, Const { .. }) => true,
+ // this is exhaustive so that anyone adding new generic param kinds knows
+ // to make sure this error is reported for them.
+ (Const { .. }, Const { .. }) | (Type { .. }, Type { .. }) => false,
+ (Lifetime { .. }, _) | (_, Lifetime { .. }) => unreachable!(),
+ } {
+ let param_impl_span = tcx.def_span(param_impl.def_id);
+ let param_trait_span = tcx.def_span(param_trait.def_id);
+
let mut err = struct_span_err!(
tcx.sess,
- *impl_span,
+ param_impl_span,
E0053,
- "method `{}` has an incompatible const parameter type for trait",
- trait_m.name
- );
- err.span_note(
- trait_span.map_or_else(|| trait_item_span.unwrap_or(*impl_span), |span| *span),
- &format!(
- "the const parameter{} has type `{}`, but the declaration \
- in trait `{}` has type `{}`",
- &impl_ident.map_or_else(|| "".to_string(), |ident| format!(" `{ident}`")),
- impl_ty,
- tcx.def_path_str(trait_m.def_id),
- trait_ty
- ),
+ "{} `{}` has an incompatible generic parameter for trait `{}`",
+ assoc_item_kind_str(&impl_item),
+ trait_item.name,
+ &tcx.def_path_str(tcx.parent(trait_item.def_id))
);
+
+ let make_param_message = |prefix: &str, param: &ty::GenericParamDef| match param.kind {
+ Const { .. } => {
+ format!("{} const parameter of type `{}`", prefix, tcx.type_of(param.def_id))
+ }
+ Type { .. } => format!("{} type parameter", prefix),
+ Lifetime { .. } => unreachable!(),
+ };
+
+ let trait_header_span = tcx.def_ident_span(tcx.parent(trait_item.def_id)).unwrap();
+ err.span_label(trait_header_span, "");
+ err.span_label(param_trait_span, make_param_message("expected", param_trait));
+
+ let impl_header_span =
+ tcx.sess.source_map().guess_head_span(tcx.def_span(tcx.parent(impl_item.def_id)));
+ err.span_label(impl_header_span, "");
+ err.span_label(param_impl_span, make_param_message("found", param_impl));
+
let reported = err.emit();
return Err(reported);
}
let _: Result<(), ErrorGuaranteed> = (|| {
compare_number_of_generics(tcx, impl_ty, impl_ty_span, trait_ty, trait_item_span)?;
+ compare_generic_param_kinds(tcx, impl_ty, trait_ty)?;
+
let sp = tcx.def_span(impl_ty.def_id);
compare_type_predicate_entailment(tcx, impl_ty, sp, trait_ty, impl_trait_ref)?;
use rustc_middle::ty::error::ExpectedFound;
use rustc_middle::ty::error::TypeError::{FieldMisMatch, Sorts};
use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, AdtKind, Ty, TypeFoldable};
+use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TypeFoldable};
use rustc_session::parse::feature_err;
use rustc_span::hygiene::DesugaringKind;
use rustc_span::lev_distance::find_best_match_for_name;
base: &'tcx hir::Expr<'tcx>,
def_id: DefId,
) {
- let local_id = def_id.expect_local();
- let hir_id = self.tcx.hir().local_def_id_to_hir_id(local_id);
- let node = self.tcx.hir().get(hir_id);
-
- if let Some(fields) = node.tuple_fields() {
- let kind = match self.tcx.opt_def_kind(local_id) {
- Some(DefKind::Ctor(of, _)) => of,
- _ => return,
- };
+ if let Some(local_id) = def_id.as_local() {
+ let hir_id = self.tcx.hir().local_def_id_to_hir_id(local_id);
+ let node = self.tcx.hir().get(hir_id);
+
+ if let Some(fields) = node.tuple_fields() {
+ let kind = match self.tcx.opt_def_kind(local_id) {
+ Some(DefKind::Ctor(of, _)) => of,
+ _ => return,
+ };
- suggest_call_constructor(base.span, kind, fields.len(), err);
+ suggest_call_constructor(base.span, kind, fields.len(), err);
+ }
+ } else {
+ // The logic here isn't smart but `associated_item_def_ids`
+ // doesn't work nicely on local.
+ if let DefKind::Ctor(of, _) = self.tcx.def_kind(def_id) {
+ let parent_def_id = self.tcx.parent(def_id);
+ let fields = self.tcx.associated_item_def_ids(parent_def_id);
+ suggest_call_constructor(base.span, of, fields.len(), err);
+ }
}
}
// is missing.
let default = tcx.type_of(param.def_id);
self.fcx
- .normalize_ty(
- self.span,
- default.subst_spanned(tcx, substs.unwrap(), Some(self.span)),
- )
+ .normalize_ty(self.span, default.subst(tcx, substs.unwrap()))
.into()
} else {
// If no type arguments were provided, we have to infer them.
}
GenericParamDefKind::Const { has_default } => {
if !infer_args && has_default {
- tcx.const_param_default(param.def_id)
- .subst_spanned(tcx, substs.unwrap(), Some(self.span))
- .into()
+ tcx.const_param_default(param.def_id).subst(tcx, substs.unwrap()).into()
} else {
self.fcx.var_for_def(self.span, param)
}
use rustc_middle::ty::error::TypeError;
// An issue that might be found in the compatibility matrix
+#[derive(Debug)]
enum Issue {
/// The given argument is the invalid type for the input
Invalid(usize),
}
/// Similar to `Issue`, but contains some extra information
+#[derive(Debug)]
pub(crate) enum Error<'tcx> {
- /// The given argument is the invalid type for the input
- Invalid(usize, Compatibility<'tcx>),
+ /// The provided argument is the invalid type for the expected input
+ Invalid(usize, usize, Compatibility<'tcx>), // provided, expected
/// There is a missing input
Missing(usize),
/// There's a superfluous argument
}
pub(crate) struct ArgMatrix<'tcx> {
+ /// Maps the indices in the `compatibility_matrix` rows to the indices of
+ /// the *user provided* inputs
input_indexes: Vec<usize>,
+ /// Maps the indices in the `compatibility_matrix` columns to the indices
+ /// of the *expected* args
arg_indexes: Vec<usize>,
+ /// The first dimension (rows) are the remaining user provided inputs to
+ /// match and the second dimension (cols) are the remaining expected args
+ /// to match
compatibility_matrix: Vec<Vec<Compatibility<'tcx>>>,
}
.map(|i| (0..minimum_input_count).map(|j| is_compatible(i, j)).collect())
.collect();
ArgMatrix {
- input_indexes: (0..minimum_input_count).collect(),
- arg_indexes: (0..provided_arg_count).collect(),
+ input_indexes: (0..provided_arg_count).collect(),
+ arg_indexes: (0..minimum_input_count).collect(),
compatibility_matrix,
}
}
/// Remove a given input from consideration
fn eliminate_input(&mut self, idx: usize) {
self.input_indexes.remove(idx);
- for row in &mut self.compatibility_matrix {
- row.remove(idx);
- }
+ self.compatibility_matrix.remove(idx);
}
/// Remove a given argument from consideration
fn eliminate_arg(&mut self, idx: usize) {
self.arg_indexes.remove(idx);
- self.compatibility_matrix.remove(idx);
+ for row in &mut self.compatibility_matrix {
+ row.remove(idx);
+ }
}
/// "satisfy" an input with a given arg, removing both from consideration
self.eliminate_arg(arg_idx);
}
+ // Returns a `Vec` of (user input, expected arg) of matched arguments. These
+ // are inputs on the remaining diagonal that match.
fn eliminate_satisfied(&mut self) -> Vec<(usize, usize)> {
let mut i = cmp::min(self.input_indexes.len(), self.arg_indexes.len());
let mut eliminated = vec![];
while i > 0 {
let idx = i - 1;
if matches!(self.compatibility_matrix[idx][idx], Compatibility::Compatible) {
- eliminated.push((self.arg_indexes[idx], self.input_indexes[idx]));
+ eliminated.push((self.input_indexes[idx], self.arg_indexes[idx]));
self.satisfy_input(idx, idx);
}
i -= 1;
return eliminated;
}
- // Check for the above mismatch cases
+ // Find some issue in the compatibility matrix
fn find_issue(&self) -> Option<Issue> {
let mat = &self.compatibility_matrix;
let ai = &self.arg_indexes;
if is_arg {
for j in 0..ii.len() {
// If we find at least one input this argument could satisfy
- // this argument isn't completely useless
- if matches!(mat[i][j], Compatibility::Compatible) {
- useless = false;
+ // this argument isn't unsatisfiable
+ if matches!(mat[j][i], Compatibility::Compatible) {
+ unsatisfiable = false;
break;
}
}
if is_input {
for j in 0..ai.len() {
// If we find at least one argument that could satisfy this input
- // this argument isn't unsatisfiable
- if matches!(mat[j][i], Compatibility::Compatible) {
- unsatisfiable = false;
+ // this argument isn't useless
+ if matches!(mat[i][j], Compatibility::Compatible) {
+ useless = false;
break;
}
}
}
- match (is_arg, is_input, useless, unsatisfiable) {
- // If an input is unsatisfied, and the argument in its position is useless
+ match (is_input, is_arg, useless, unsatisfiable) {
+ // If an argument is unsatisfied, and the input in its position is useless
// then the most likely explanation is that we just got the types wrong
(true, true, true, true) => return Some(Issue::Invalid(i)),
// Otherwise, if an input is useless, then indicate that this is an extra argument
_ => {
continue;
}
- };
+ }
}
// We didn't find any of the individual issues above, but
// We'll want to know which arguments and inputs these rows and columns correspond to
// even after we delete them.
pub(crate) fn find_errors(mut self) -> (Vec<Error<'tcx>>, Vec<Option<usize>>) {
- let provided_arg_count = self.arg_indexes.len();
+ let provided_arg_count = self.input_indexes.len();
let mut errors: Vec<Error<'tcx>> = vec![];
// For each expected argument, the matched *actual* input
- let mut matched_inputs: Vec<Option<usize>> = vec![None; self.input_indexes.len()];
+ let mut matched_inputs: Vec<Option<usize>> = vec![None; self.arg_indexes.len()];
// Before we start looking for issues, eliminate any arguments that are already satisfied,
// so that an argument which is already spoken for by the input it's in doesn't
// Without this elimination, the first argument causes the second argument
// to show up as both a missing input and extra argument, rather than
// just an invalid type.
- for (arg, inp) in self.eliminate_satisfied() {
- matched_inputs[inp] = Some(arg);
+ for (inp, arg) in self.eliminate_satisfied() {
+ matched_inputs[arg] = Some(inp);
}
while self.input_indexes.len() > 0 || self.arg_indexes.len() > 0 {
- // Check for the first relevant issue
match self.find_issue() {
Some(Issue::Invalid(idx)) => {
let compatibility = self.compatibility_matrix[idx][idx].clone();
let input_idx = self.input_indexes[idx];
+ let arg_idx = self.arg_indexes[idx];
self.satisfy_input(idx, idx);
- errors.push(Error::Invalid(input_idx, compatibility));
+ errors.push(Error::Invalid(input_idx, arg_idx, compatibility));
}
Some(Issue::Extra(idx)) => {
- let arg_idx = self.arg_indexes[idx];
- self.eliminate_arg(idx);
- errors.push(Error::Extra(arg_idx));
- }
- Some(Issue::Missing(idx)) => {
let input_idx = self.input_indexes[idx];
self.eliminate_input(idx);
- errors.push(Error::Missing(input_idx));
+ errors.push(Error::Extra(input_idx));
+ }
+ Some(Issue::Missing(idx)) => {
+ let arg_idx = self.arg_indexes[idx];
+ self.eliminate_arg(idx);
+ errors.push(Error::Missing(arg_idx));
}
Some(Issue::Swap(idx, other)) => {
let input_idx = self.input_indexes[idx];
// Subtract 1 because we already removed the "min" row
self.satisfy_input(max - 1, min);
errors.push(Error::Swap(input_idx, other_input_idx, arg_idx, other_arg_idx));
- matched_inputs[input_idx] = Some(other_arg_idx);
- matched_inputs[other_input_idx] = Some(arg_idx);
+ matched_inputs[other_arg_idx] = Some(input_idx);
+ matched_inputs[arg_idx] = Some(other_input_idx);
}
Some(Issue::Permutation(args)) => {
- // FIXME: If satisfy_input ever did anything non-trivial (emit obligations to help type checking, for example)
- // we'd want to call this function with the correct arg/input pairs, but for now, we just throw them in a bucket.
- // This works because they force a cycle, so each row is guaranteed to also be a column
let mut idxs: Vec<usize> = args.iter().filter_map(|&a| a).collect();
let mut real_idxs = vec![None; provided_arg_count];
for (src, dst) in
args.iter().enumerate().filter_map(|(src, dst)| dst.map(|dst| (src, dst)))
{
- let src_arg = self.arg_indexes[src];
- let dst_arg = self.arg_indexes[dst];
- let dest_input = self.input_indexes[dst];
- real_idxs[src_arg] = Some((dst_arg, dest_input));
- matched_inputs[dest_input] = Some(src_arg);
+ let src_input_idx = self.input_indexes[src];
+ let dst_input_idx = self.input_indexes[dst];
+ let dest_arg_idx = self.arg_indexes[dst];
+ real_idxs[src_input_idx] = Some((dest_arg_idx, dst_input_idx));
+ matched_inputs[dest_arg_idx] = Some(src_input_idx);
}
idxs.sort();
idxs.reverse();
None => {
// We didn't find any issues, so we need to push the algorithm forward
// First, eliminate any arguments that currently satisfy their inputs
- for (arg, inp) in self.eliminate_satisfied() {
- matched_inputs[inp] = Some(arg);
+ for (inp, arg) in self.eliminate_satisfied() {
+ matched_inputs[arg] = Some(inp);
}
}
};
use rustc_middle::ty::adjustment::AllowTwoPhase;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::fold::TypeFoldable;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::Session;
use rustc_span::symbol::Ident;
use rustc_span::{self, Span};
// A "softer" version of the helper above, which checks types without persisting them,
// and treats error types differently
// This will allow us to "probe" for other argument orders that would likely have been correct
- let check_compatible = |arg_idx, input_idx| {
- let formal_input_ty: Ty<'tcx> = formal_input_tys[input_idx];
- let expected_input_ty: Ty<'tcx> = expected_input_tys[input_idx];
+ let check_compatible = |input_idx, arg_idx| {
+ let formal_input_ty: Ty<'tcx> = formal_input_tys[arg_idx];
+ let expected_input_ty: Ty<'tcx> = expected_input_tys[arg_idx];
// If either is an error type, we defy the usual convention and consider them to *not* be
// coercible. This prevents our error message heuristic from trying to pass errors into
return Compatibility::Incompatible(None);
}
- let provided_arg: &hir::Expr<'tcx> = &provided_args[arg_idx];
+ let provided_arg: &hir::Expr<'tcx> = &provided_args[input_idx];
let expectation = Expectation::rvalue_hint(self, expected_input_ty);
// FIXME: check that this is safe; I don't believe this commits any of the obligations, but I can't be sure.
//
break 'errors;
}
+ self.set_tainted_by_errors();
+
// The algorithm here is inspired by levenshtein distance and longest common subsequence.
// We'll try to detect 4 different types of mistakes:
// - An extra parameter has been provided that doesn't satisfy *any* of the other inputs
let found_errors = !errors.is_empty();
errors.drain_filter(|error| {
- let Error::Invalid(input_idx, Compatibility::Incompatible(error)) = error else { return false };
- let expected_ty = expected_input_tys[*input_idx];
- let Some(Some((provided_ty, _))) = final_arg_types.get(*input_idx) else { return false };
+ let Error::Invalid(input_idx, arg_idx, Compatibility::Incompatible(error)) = error else { return false };
+ let expected_ty = expected_input_tys[*arg_idx];
+ let provided_ty = final_arg_types[*input_idx].map(|ty| ty.0).unwrap();
let cause = &self.misc(provided_args[*input_idx].span);
- let trace = TypeTrace::types(cause, true, expected_ty, *provided_ty);
+ let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
if let Some(e) = error {
if !matches!(trace.cause.as_failure_code(e), FailureCode::Error0308(_)) {
self.report_and_explain_type_error(trace, e).emit();
TupleMatchFound::Single => {
let expected_ty = expected_input_tys[0];
let provided_ty = final_arg_types[0].map(|ty| ty.0).unwrap();
+ let expected_ty = self.resolve_vars_if_possible(expected_ty);
+ let provided_ty = self.resolve_vars_if_possible(provided_ty);
let cause = &self.misc(provided_args[0].span);
let compatibility = demand_compatible(0, &mut final_arg_types);
let type_error = match compatibility {
format!("arguments to this {} are incorrect", call_name),
);
// Call out where the function is defined
- if let Some(def_id) = fn_def_id && let Some(def_span) = tcx.def_ident_span(def_id) {
- let mut spans: MultiSpan = def_span.into();
-
- let params = tcx
- .hir()
- .get_if_local(def_id)
- .and_then(|node| node.body_id())
- .into_iter()
- .map(|id| tcx.hir().body(id).params)
- .flatten();
-
- for param in params {
- spans.push_span_label(param.span, String::new());
- }
-
- let def_kind = tcx.def_kind(def_id);
- err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id)));
- }
+ label_fn_like(tcx, &mut err, fn_def_id);
err.emit();
break 'errors;
}
DiagnosticId::Error(err_code.to_owned()),
);
// Call out where the function is defined
- if let Some(def_id) = fn_def_id && let Some(def_span) = tcx.def_ident_span(def_id) {
- let mut spans: MultiSpan = def_span.into();
-
- let params = tcx
- .hir()
- .get_if_local(def_id)
- .and_then(|node| node.body_id())
- .into_iter()
- .map(|id| tcx.hir().body(id).params)
- .flatten();
-
- for param in params {
- spans.push_span_label(param.span, String::new());
- }
-
- let def_kind = tcx.def_kind(def_id);
- err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id)));
- }
+ label_fn_like(tcx, &mut err, fn_def_id);
err.multipart_suggestion(
"use parentheses to construct a tuple",
vec![(start, '('.to_string()), (end, ')'.to_string())],
// Next special case: if there is only one "Incompatible" error, just emit that
if errors.len() == 1 {
- if let Some(Error::Invalid(input_idx, Compatibility::Incompatible(Some(error)))) =
- errors.iter().next()
+ if let Some(Error::Invalid(
+ input_idx,
+ arg_idx,
+ Compatibility::Incompatible(Some(error)),
+ )) = errors.iter().next()
{
- let expected_ty = expected_input_tys[*input_idx];
- let provided_ty = final_arg_types[*input_idx].map(|ty| ty.0).unwrap();
+ let expected_ty = expected_input_tys[*arg_idx];
+ let provided_ty = final_arg_types[*arg_idx].map(|ty| ty.0).unwrap();
+ let expected_ty = self.resolve_vars_if_possible(expected_ty);
+ let provided_ty = self.resolve_vars_if_possible(provided_ty);
let cause = &self.misc(provided_args[*input_idx].span);
let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
let mut err = self.report_and_explain_type_error(trace, error);
self.emit_coerce_suggestions(
&mut err,
&provided_args[*input_idx],
- final_arg_types[*input_idx].map(|ty| ty.0).unwrap(),
+ provided_ty,
final_arg_types[*input_idx].map(|ty| ty.1).unwrap(),
None,
None,
format!("arguments to this {} are incorrect", call_name),
);
// Call out where the function is defined
- if let Some(def_id) = fn_def_id && let Some(def_span) = tcx.def_ident_span(def_id) {
- let mut spans: MultiSpan = def_span.into();
-
- let params = tcx
- .hir()
- .get_if_local(def_id)
- .and_then(|node| node.body_id())
- .into_iter()
- .map(|id| tcx.hir().body(id).params)
- .flatten();
-
- for param in params {
- spans.push_span_label(param.span, String::new());
- }
-
- let def_kind = tcx.def_kind(def_id);
- err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id)));
- }
+ label_fn_like(tcx, &mut err, fn_def_id);
err.emit();
break 'errors;
}
let mut errors = errors.into_iter().peekable();
while let Some(error) = errors.next() {
match error {
- Error::Invalid(input_idx, compatibility) => {
- let expected_ty = expected_input_tys[input_idx];
+ Error::Invalid(input_idx, arg_idx, compatibility) => {
+ let expected_ty = expected_input_tys[arg_idx];
+ let provided_ty = final_arg_types[input_idx].map(|ty| ty.0).unwrap();
+ let expected_ty = self.resolve_vars_if_possible(expected_ty);
+ let provided_ty = self.resolve_vars_if_possible(provided_ty);
if let Compatibility::Incompatible(error) = &compatibility {
- let provided_ty = final_arg_types
- .get(input_idx)
- .and_then(|x| x.as_ref())
- .map(|ty| ty.0)
- .unwrap_or(tcx.ty_error());
- let cause = &self.misc(
- provided_args.get(input_idx).map(|i| i.span).unwrap_or(call_span),
- );
+ let cause = &self.misc(provided_args[input_idx].span);
let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
if let Some(e) = error {
self.note_type_err(
}
}
- if let Some(expr) = provided_args.get(input_idx) {
- self.emit_coerce_suggestions(
- &mut err,
- &expr,
- final_arg_types[input_idx].map(|ty| ty.0).unwrap(),
- final_arg_types[input_idx].map(|ty| ty.1).unwrap(),
- None,
- None,
- );
- }
+ self.emit_coerce_suggestions(
+ &mut err,
+ &provided_args[input_idx],
+ final_arg_types[input_idx].map(|ty| ty.0).unwrap(),
+ final_arg_types[input_idx].map(|ty| ty.1).unwrap(),
+ None,
+ None,
+ );
}
Error::Extra(arg_idx) => {
let arg_type = if let Some((_, ty)) = final_arg_types[arg_idx] {
}
}
Error::Swap(input_idx, other_input_idx, arg_idx, other_arg_idx) => {
- let first_span = provided_args[arg_idx].span;
- let second_span = provided_args[other_arg_idx].span;
+ let first_span = provided_args[input_idx].span;
+ let second_span = provided_args[other_input_idx].span;
let first_expected_ty =
- self.resolve_vars_if_possible(expected_input_tys[input_idx]);
- let first_provided_ty = if let Some((ty, _)) = final_arg_types[arg_idx] {
+ self.resolve_vars_if_possible(expected_input_tys[arg_idx]);
+ let first_provided_ty = if let Some((ty, _)) = final_arg_types[input_idx] {
format!(",found `{}`", ty)
} else {
"".into()
format!("expected `{}`{}", first_expected_ty, first_provided_ty),
));
let other_expected_ty =
- self.resolve_vars_if_possible(expected_input_tys[other_input_idx]);
+ self.resolve_vars_if_possible(expected_input_tys[other_arg_idx]);
let other_provided_ty =
- if let Some((ty, _)) = final_arg_types[other_arg_idx] {
+ if let Some((ty, _)) = final_arg_types[other_input_idx] {
format!(",found `{}`", ty)
} else {
"".into()
}
// Call out where the function is defined
- if let Some(def_id) = fn_def_id && let Some(def_span) = tcx.def_ident_span(def_id) {
- let mut spans: MultiSpan = def_span.into();
-
- let params = tcx
- .hir()
- .get_if_local(def_id)
- .and_then(|node| node.body_id())
- .into_iter()
- .flat_map(|id| tcx.hir().body(id).params)
- ;
-
- for param in params {
- spans.push_span_label(param.span, String::new());
- }
-
- let def_kind = tcx.def_kind(def_id);
- err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id)));
- }
+ label_fn_like(tcx, &mut err, fn_def_id);
// And add a suggestion block for all of the parameters
let suggestion_text = match suggestion_text {
"{}(",
source_map.span_to_snippet(full_call_span).unwrap_or_else(|_| String::new())
);
- for (idx, arg) in matched_inputs.iter().enumerate() {
- let suggestion_text = if let Some(arg) = arg {
- let arg_span = provided_args[*arg].span.source_callsite();
+ for (arg_index, input_idx) in matched_inputs.iter().enumerate() {
+ let suggestion_text = if let Some(input_idx) = input_idx {
+ let arg_span = provided_args[*input_idx].span.source_callsite();
let arg_text = source_map.span_to_snippet(arg_span).unwrap();
arg_text
} else {
// Propose a placeholder of the correct type
- let expected_ty = expected_input_tys[idx];
+ let expected_ty = expected_input_tys[arg_index];
let input_ty = self.resolve_vars_if_possible(expected_ty);
if input_ty.is_unit() {
"()".to_string()
}
};
suggestion += &suggestion_text;
- if idx < minimum_input_count - 1 {
+ if arg_index < minimum_input_count - 1 {
suggestion += ", ";
}
}
}
}
}
+
+fn label_fn_like<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ err: &mut rustc_errors::DiagnosticBuilder<'tcx, rustc_errors::ErrorGuaranteed>,
+ def_id: Option<DefId>,
+) {
+ let Some(def_id) = def_id else {
+ return;
+ };
+
+ if let Some(def_span) = tcx.def_ident_span(def_id) {
+ let mut spans: MultiSpan = def_span.into();
+
+ let params = tcx
+ .hir()
+ .get_if_local(def_id)
+ .and_then(|node| node.body_id())
+ .into_iter()
+ .map(|id| tcx.hir().body(id).params)
+ .flatten();
+
+ for param in params {
+ spans.push_span_label(param.span, String::new());
+ }
+
+ let def_kind = tcx.def_kind(def_id);
+ err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id)));
+ } else {
+ match tcx.hir().get_if_local(def_id) {
+ Some(hir::Node::Expr(hir::Expr {
+ kind: hir::ExprKind::Closure(_, _, _, span, ..),
+ ..
+ })) => {
+ let spans: MultiSpan = (*span).into();
+
+ // Note: We don't point to param spans here because they overlap
+ // with the closure span itself
+
+ err.span_note(spans, "closure defined here");
+ }
+ _ => {}
+ }
+ }
+}
let sig = self.tcx.fn_sig(def_id);
- // Instantiate late-bound regions and substitute the trait
- // parameters into the method type to get the actual method type.
- //
- // N.B., instantiate late-bound regions first so that
- // `instantiate_type_scheme` can normalize associated types that
- // may reference those regions.
- let method_sig = self.replace_bound_vars_with_fresh_vars(sig);
- debug!("late-bound lifetimes from method instantiated, method_sig={:?}", method_sig);
+ let sig = sig.subst(self.tcx, all_substs);
+ debug!("type scheme substituted, sig={:?}", sig);
- let method_sig = method_sig.subst(self.tcx, all_substs);
- debug!("type scheme substituted, method_sig={:?}", method_sig);
+ let sig = self.replace_bound_vars_with_fresh_vars(sig);
+ debug!("late-bound lifetimes from method instantiated, sig={:?}", sig);
- (method_sig, method_predicates)
+ (sig, method_predicates)
}
fn add_obligations(
// `instantiate_type_scheme` can normalize associated types that
// may reference those regions.
let fn_sig = tcx.fn_sig(def_id);
- let fn_sig = self.replace_bound_vars_with_fresh_vars(span, infer::FnCall, fn_sig).0;
let fn_sig = fn_sig.subst(self.tcx, substs);
+ let fn_sig = self.replace_bound_vars_with_fresh_vars(span, infer::FnCall, fn_sig).0;
let InferOk { value, obligations: o } = if is_op {
self.normalize_op_associated_types_in_as_infer_ok(span, fn_sig, opt_input_expr)
let generics = self.tcx.generics_of(method);
assert_eq!(substs.len(), generics.parent_count as usize);
- // Erase any late-bound regions from the method and substitute
- // in the values from the substitution.
- let xform_fn_sig = self.erase_late_bound_regions(fn_sig);
-
- if generics.params.is_empty() {
- xform_fn_sig.subst(self.tcx, substs)
+ let xform_fn_sig = if generics.params.is_empty() {
+ fn_sig.subst(self.tcx, substs)
} else {
let substs = InternalSubsts::for_item(self.tcx, method, |param, _| {
let i = param.index as usize;
}
}
});
- xform_fn_sig.subst(self.tcx, substs)
- }
+ fn_sig.subst(self.tcx, substs)
+ };
+
+ self.erase_late_bound_regions(xform_fn_sig)
}
/// Gets the type of an impl and generate substitutions with placeholders.
use rustc_session::parse::feature_err;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
-use rustc_target::spec::{abi, PanicStrategy, SanitizerSet};
+use rustc_target::spec::{abi, SanitizerSet};
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
use std::iter;
mod item_bounds;
mod type_of;
+#[derive(Debug)]
struct OnlySelfBounds(bool);
///////////////////////////////////////////////////////////////////////////
/// AST. We do this to avoid having to convert *all* the bounds, which
/// would create artificial cycles. Instead, we can only convert the
/// bounds for a type parameter `X` if `X::Foo` is used.
+ #[instrument(level = "trace", skip(self, ast_generics))]
fn type_parameter_bounds_in_generics(
&self,
ast_generics: &'tcx hir::Generics<'tcx>,
assoc_name: Option<Ident>,
) -> Vec<(ty::Predicate<'tcx>, Span)> {
let param_def_id = self.tcx.hir().local_def_id(param_id).to_def_id();
+ debug!(?param_def_id);
ast_generics
.predicates
.iter()
};
let bvars = self.tcx.late_bound_vars(bp.bounded_ty.hir_id);
- bp.bounds
- .iter()
- .filter(|b| match assoc_name {
+ bp.bounds.iter().filter_map(move |b| bt.map(|bt| (bt, b, bvars))).filter(
+ |(_, b, _)| match assoc_name {
Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name),
None => true,
- })
- .filter_map(move |b| bt.map(|bt| (bt, b, bvars)))
+ },
+ )
})
.flat_map(|(bt, b, bvars)| predicates_from_bound(self, bt, b, bvars))
.collect()
// Combine the two lists to form the complete set of superbounds:
let superbounds = &*tcx.arena.alloc_from_iter(superbounds1.into_iter().chain(superbounds2));
+ debug!(?superbounds);
// Now require that immediate supertraits are converted,
// which will, in turn, reach indirect supertraits.
fn from_target_feature(
tcx: TyCtxt<'_>,
- id: DefId,
attr: &ast::Attribute,
supported_target_features: &FxHashMap<String, Option<Symbol>>,
target_features: &mut Vec<Symbol>,
Some(name) => bug!("unknown target feature gate {}", name),
None => true,
};
- if !allowed && id.is_local() {
+ if !allowed {
feature_err(
&tcx.sess.parse_sess,
feature_gate.unwrap(),
}
}
-fn linkage_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: &str) -> Linkage {
+fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage {
use rustc_middle::mir::mono::Linkage::*;
// Use the names from src/llvm/docs/LangRef.rst here. Most types are only
"private" => Private,
"weak" => WeakAny,
"weak_odr" => WeakODR,
- _ => {
- let span = tcx.hir().span_if_local(def_id);
- if let Some(span) = span {
- tcx.sess.span_fatal(span, "invalid linkage specified")
- } else {
- tcx.sess.fatal(&format!("invalid linkage specified: {}", name))
- }
- }
+ _ => tcx.sess.span_fatal(tcx.def_span(def_id), "invalid linkage specified"),
}
}
-fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
- let attrs = tcx.get_attrs(id);
+fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
+ if cfg!(debug_assertions) {
+ let def_kind = tcx.def_kind(did);
+ assert!(
+ def_kind.has_codegen_attrs(),
+ "unexpected `def_kind` in `codegen_fn_attrs`: {def_kind:?}",
+ );
+ }
+ let did = did.expect_local();
+ let attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(did));
let mut codegen_fn_attrs = CodegenFnAttrs::new();
- if tcx.should_inherit_track_caller(id) {
+ if tcx.should_inherit_track_caller(did) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
}
- // With -Z panic-in-drop=abort, drop_in_place never unwinds.
- if tcx.sess.opts.debugging_opts.panic_in_drop == PanicStrategy::Abort {
- if Some(id) == tcx.lang_items().drop_in_place_fn() {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
- }
- }
-
// The panic_no_unwind function called by TerminatorKind::Abort will never
// unwind. If the panic handler that it invokes unwind then it will simply
// call the panic handler again.
- if Some(id) == tcx.lang_items().panic_no_unwind() {
+ if Some(did.to_def_id()) == tcx.lang_items().panic_no_unwind() {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
}
} else if attr.has_name(sym::rustc_allocator) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR;
} else if attr.has_name(sym::ffi_returns_twice) {
- if tcx.is_foreign_item(id) {
+ if tcx.is_foreign_item(did) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE;
} else {
// `#[ffi_returns_twice]` is only allowed `extern fn`s.
.emit();
}
} else if attr.has_name(sym::ffi_pure) {
- if tcx.is_foreign_item(id) {
+ if tcx.is_foreign_item(did) {
if attrs.iter().any(|a| a.has_name(sym::ffi_const)) {
// `#[ffi_const]` functions cannot be `#[ffi_pure]`
struct_span_err!(
.emit();
}
} else if attr.has_name(sym::ffi_const) {
- if tcx.is_foreign_item(id) {
+ if tcx.is_foreign_item(did) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST;
} else {
// `#[ffi_const]` is only allowed on foreign functions
None => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED,
}
} else if attr.has_name(sym::cmse_nonsecure_entry) {
- if !matches!(tcx.fn_sig(id).abi(), abi::Abi::C { .. }) {
+ if !matches!(tcx.fn_sig(did).abi(), abi::Abi::C { .. }) {
struct_span_err!(
tcx.sess,
attr.span,
} else if attr.has_name(sym::thread_local) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL;
} else if attr.has_name(sym::track_caller) {
- if !tcx.is_closure(id) && tcx.fn_sig(id).abi() != abi::Abi::Rust {
+ if !tcx.is_closure(did.to_def_id()) && tcx.fn_sig(did).abi() != abi::Abi::Rust {
struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI")
.emit();
}
- if tcx.is_closure(id) && !tcx.features().closure_track_caller {
+ if tcx.is_closure(did.to_def_id()) && !tcx.features().closure_track_caller {
feature_err(
&tcx.sess.parse_sess,
sym::closure_track_caller,
codegen_fn_attrs.export_name = Some(s);
}
} else if attr.has_name(sym::target_feature) {
- if !tcx.is_closure(id) && tcx.fn_sig(id).unsafety() == hir::Unsafety::Normal {
+ if !tcx.is_closure(did.to_def_id())
+ && tcx.fn_sig(did).unsafety() == hir::Unsafety::Normal
+ {
if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
// The `#[target_feature]` attribute is allowed on
// WebAssembly targets on all functions, including safe
attr.span,
"`#[target_feature(..)]` can only be applied to `unsafe` functions",
);
- err.span_label(tcx.def_span(id), "not an `unsafe` function");
+ err.span_label(tcx.def_span(did), "not an `unsafe` function");
err.emit();
- } else if let Some(local_id) = id.as_local() {
- check_target_feature_trait_unsafe(tcx, local_id, attr.span);
+ } else {
+ check_target_feature_trait_unsafe(tcx, did, attr.span);
}
}
from_target_feature(
tcx,
- id,
attr,
supported_target_features,
&mut codegen_fn_attrs.target_features,
);
} else if attr.has_name(sym::linkage) {
if let Some(val) = attr.value_str() {
- codegen_fn_attrs.linkage = Some(linkage_by_name(tcx, id, val.as_str()));
+ codegen_fn_attrs.linkage = Some(linkage_by_name(tcx, did, val.as_str()));
}
} else if attr.has_name(sym::link_section) {
if let Some(val) = attr.value_str() {
});
// #73631: closures inherit `#[target_feature]` annotations
- if tcx.features().target_feature_11 && tcx.is_closure(id) {
- let owner_id = tcx.parent(id);
+ if tcx.features().target_feature_11 && tcx.is_closure(did.to_def_id()) {
+ let owner_id = tcx.parent(did.to_def_id());
codegen_fn_attrs
.target_features
.extend(tcx.codegen_fn_attrs(owner_id).target_features.iter().copied())
if !codegen_fn_attrs.no_sanitize.is_empty() {
if codegen_fn_attrs.inline == InlineAttr::Always {
if let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span) {
- let hir_id = tcx.hir().local_def_id_to_hir_id(id.expect_local());
+ let hir_id = tcx.hir().local_def_id_to_hir_id(did);
tcx.struct_span_lint_hir(
lint::builtin::INLINE_NO_SANITIZE,
hir_id,
// strippable by the linker.
//
// Additionally weak lang items have predetermined symbol names.
- if tcx.is_weak_lang_item(id) {
+ if tcx.is_weak_lang_item(did.to_def_id()) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
}
if let Some(name) = weak_lang_items::link_name(attrs) {
/// Computes the set of target features used in a function for the purposes of
/// inline assembly.
-fn asm_target_features<'tcx>(tcx: TyCtxt<'tcx>, id: DefId) -> &'tcx FxHashSet<Symbol> {
+fn asm_target_features<'tcx>(tcx: TyCtxt<'tcx>, did: DefId) -> &'tcx FxHashSet<Symbol> {
let mut target_features = tcx.sess.target_features.clone();
- let attrs = tcx.codegen_fn_attrs(id);
- target_features.extend(&attrs.target_features);
- match attrs.instruction_set {
- None => {}
- Some(InstructionSetAttr::ArmA32) => {
- target_features.remove(&sym::thumb_mode);
- }
- Some(InstructionSetAttr::ArmT32) => {
- target_features.insert(sym::thumb_mode);
+ if tcx.def_kind(did).has_codegen_attrs() {
+ let attrs = tcx.codegen_fn_attrs(did);
+ target_features.extend(&attrs.target_features);
+ match attrs.instruction_set {
+ None => {}
+ Some(InstructionSetAttr::ArmA32) => {
+ target_features.remove(&sym::thumb_mode);
+ }
+ Some(InstructionSetAttr::ArmT32) => {
+ target_features.insert(sym::thumb_mode);
+ }
}
}
+
tcx.arena.alloc(target_features)
}
pub struct TraitObjectDeclaredWithNoTraits {
#[primary_span]
pub span: Span,
+ #[label = "alias-span"]
+ pub trait_alias_span: Option<Span>,
}
#[derive(SessionDiagnostic)]
}
#[inline]
- #[doc(hidden)]
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
// Safety: The TrustedRandomAccess contract requires that callers only pass an index
// that is in bounds.
}
#[inline]
- #[doc(hidden)]
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
// Safety: The TrustedRandomAccess contract requires that callers only pass an index
// that is in bounds.
/// ```
#[rustc_allow_incoherent_impl]
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_deprecated(since = "1.3.0", reason = "renamed to join")]
+ #[deprecated(since = "1.3.0", note = "renamed to join")]
pub fn connect<Separator>(&self, sep: Separator) -> <Self as Join<Separator>>::Output
where
Self: Join<Separator>,
self.len()
}
- #[doc(hidden)]
unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> Self::Item
where
Self: TrustedRandomAccessNoCoerce,
}
#[stable(feature = "alloc_layout", since = "1.28.0")]
-#[rustc_deprecated(
+#[deprecated(
since = "1.52.0",
- reason = "Name does not follow std convention, use LayoutError",
+ note = "Name does not follow std convention, use LayoutError",
suggestion = "LayoutError"
)]
pub type LayoutErr = LayoutError;
#[stable(feature = "alloc_layout", since = "1.28.0")]
pub use self::layout::Layout;
#[stable(feature = "alloc_layout", since = "1.28.0")]
-#[rustc_deprecated(
+#[deprecated(
since = "1.52.0",
- reason = "Name does not follow std convention, use LayoutError",
+ note = "Name does not follow std convention, use LayoutError",
suggestion = "LayoutError"
)]
#[allow(deprecated, deprecated_in_future)]
impl<T, const N: usize> IntoIter<T, N> {
/// Creates a new iterator over the given `array`.
#[stable(feature = "array_value_iter", since = "1.51.0")]
- #[rustc_deprecated(since = "1.59.0", reason = "use `IntoIterator::into_iter` instead")]
+ #[deprecated(since = "1.59.0", note = "use `IntoIterator::into_iter` instead")]
pub fn new(array: [T; N]) -> Self {
IntoIterator::into_iter(array)
}
$(
#[unstable(feature = "convert_float_to_int", issue = "67057")]
impl FloatToInt<$Int> for $Float {
- #[doc(hidden)]
#[inline]
unsafe fn to_int_unchecked(self) -> $Int {
// SAFETY: the safety contract must be upheld by the caller.
mod num;
#[stable(feature = "fmt_flags_align", since = "1.28.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "Alignment")]
/// Possible alignments returned by `Formatter::align`
#[derive(Debug)]
pub enum Alignment {
///
/// [`format()`]: ../../std/fmt/fn.format.html
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "Arguments")]
#[derive(Copy, Clone)]
pub struct Arguments<'a> {
// Format string pieces to print.
/// Flags for formatting
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_deprecated(
+ #[deprecated(
since = "1.24.0",
- reason = "use the `sign_plus`, `sign_minus`, `alternate`, \
- or `sign_aware_zero_pad` methods instead"
+ note = "use the `sign_plus`, `sign_minus`, `alternate`, \
+ or `sign_aware_zero_pad` methods instead"
)]
pub fn flags(&self) -> u32 {
self.flags
/// instance (with [`write`] and [`write_u8`] etc.). Most of the time, `Hasher`
/// instances are used in conjunction with the [`Hash`] trait.
///
-/// This trait makes no assumptions about how the various `write_*` methods are
+/// This trait provides no guarantees about how the various `write_*` methods are
/// defined and implementations of [`Hash`] should not assume that they work one
/// way or another. You cannot assume, for example, that a [`write_u32`] call is
-/// equivalent to four calls of [`write_u8`].
+/// equivalent to four calls of [`write_u8`]. Nor can you assume that adjacent
+/// `write` calls are merged, so it's possible, for example, that
+/// ```
+/// # fn foo(hasher: &mut impl std::hash::Hasher) {
+/// hasher.write(&[1, 2]);
+/// hasher.write(&[3, 4, 5, 6]);
+/// # }
+/// ```
+/// and
+/// ```
+/// # fn foo(hasher: &mut impl std::hash::Hasher) {
+/// hasher.write(&[1, 2, 3, 4]);
+/// hasher.write(&[5, 6]);
+/// # }
+/// ```
+/// end up producing different hashes.
+///
+/// Thus to produce the same hash value, [`Hash`] implementations must ensure
+/// for equivalent items that exactly the same sequence of calls is made -- the
+/// same methods with the same parameters in the same order.
///
/// # Examples
///
///
/// See: <https://131002.net/siphash>
#[unstable(feature = "hashmap_internals", issue = "none")]
-#[rustc_deprecated(
- since = "1.13.0",
- reason = "use `std::collections::hash_map::DefaultHasher` instead"
-)]
+#[deprecated(since = "1.13.0", note = "use `std::collections::hash_map::DefaultHasher` instead")]
#[derive(Debug, Clone, Default)]
#[doc(hidden)]
pub struct SipHasher13 {
///
/// See: <https://131002.net/siphash/>
#[unstable(feature = "hashmap_internals", issue = "none")]
-#[rustc_deprecated(
- since = "1.13.0",
- reason = "use `std::collections::hash_map::DefaultHasher` instead"
-)]
+#[deprecated(since = "1.13.0", note = "use `std::collections::hash_map::DefaultHasher` instead")]
#[derive(Debug, Clone, Default)]
struct SipHasher24 {
hasher: Hasher<Sip24Rounds>,
/// it is not intended for cryptographic purposes. As such, all
/// cryptographic uses of this implementation are _strongly discouraged_.
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
- since = "1.13.0",
- reason = "use `std::collections::hash_map::DefaultHasher` instead"
-)]
+#[deprecated(since = "1.13.0", note = "use `std::collections::hash_map::DefaultHasher` instead")]
#[derive(Debug, Clone, Default)]
pub struct SipHasher(SipHasher24);
/// Creates a new `SipHasher` with the two initial keys set to 0.
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_deprecated(
+ #[deprecated(
since = "1.13.0",
- reason = "use `std::collections::hash_map::DefaultHasher` instead"
+ note = "use `std::collections::hash_map::DefaultHasher` instead"
)]
#[must_use]
pub fn new() -> SipHasher {
/// Creates a `SipHasher` that is keyed off the provided keys.
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_deprecated(
+ #[deprecated(
since = "1.13.0",
- reason = "use `std::collections::hash_map::DefaultHasher` instead"
+ note = "use `std::collections::hash_map::DefaultHasher` instead"
)]
#[must_use]
pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher {
/// Creates a new `SipHasher13` with the two initial keys set to 0.
#[inline]
#[unstable(feature = "hashmap_internals", issue = "none")]
- #[rustc_deprecated(
+ #[deprecated(
since = "1.13.0",
- reason = "use `std::collections::hash_map::DefaultHasher` instead"
+ note = "use `std::collections::hash_map::DefaultHasher` instead"
)]
pub fn new() -> SipHasher13 {
SipHasher13::new_with_keys(0, 0)
/// Creates a `SipHasher13` that is keyed off the provided keys.
#[inline]
#[unstable(feature = "hashmap_internals", issue = "none")]
- #[rustc_deprecated(
+ #[deprecated(
since = "1.13.0",
- reason = "use `std::collections::hash_map::DefaultHasher` instead"
+ note = "use `std::collections::hash_map::DefaultHasher` instead"
)]
pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 {
SipHasher13 { hasher: Hasher::new_with_keys(key0, key1) }
use crate::sync::atomic::{self, AtomicBool, AtomicI32, AtomicIsize, AtomicU32, Ordering};
#[stable(feature = "drop_in_place", since = "1.8.0")]
-#[rustc_deprecated(
- reason = "no longer an intrinsic - use `ptr::drop_in_place` directly",
- since = "1.52.0"
-)]
+#[deprecated(note = "no longer an intrinsic - use `ptr::drop_in_place` directly", since = "1.52.0")]
#[inline]
pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
// SAFETY: see `ptr::drop_in_place`
self.it.map(T::clone).fold(init, f)
}
- #[doc(hidden)]
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T
where
Self: TrustedRandomAccessNoCoerce,
self.it.advance_by(n)
}
- #[doc(hidden)]
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T
where
Self: TrustedRandomAccessNoCoerce,
}
#[rustc_inherit_overflow_checks]
- #[doc(hidden)]
#[inline]
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item
where
}
#[inline]
- #[doc(hidden)]
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
where
Self: TrustedRandomAccessNoCoerce,
self.iter.fold(init, map_fold(self.f, g))
}
- #[doc(hidden)]
#[inline]
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> B
where
}
#[inline]
- #[doc(hidden)]
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
where
Self: TrustedRandomAccessNoCoerce,
}
#[inline]
- #[doc(hidden)]
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
where
Self: TrustedRandomAccessNoCoerce,
/// ```
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "1.39.0", reason = "use the `?` operator instead")]
+#[deprecated(since = "1.39.0", note = "use the `?` operator instead")]
#[doc(alias = "?")]
macro_rules! r#try {
($expr:expr $(,)?) => {
#[rustc_builtin_macro]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable(core_intrinsics, libstd_sys_internals)]
- #[rustc_deprecated(
- since = "1.52.0",
- reason = "rustc-serialize is deprecated and no longer supported"
- )]
+ #[deprecated(since = "1.52.0", note = "rustc-serialize is deprecated and no longer supported")]
#[doc(hidden)] // While technically stable, using it is unstable, and deprecated. Hide it.
pub macro RustcDecodable($item:item) {
/* compiler built-in */
#[rustc_builtin_macro]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable(core_intrinsics)]
- #[rustc_deprecated(
- since = "1.52.0",
- reason = "rustc-serialize is deprecated and no longer supported"
- )]
+ #[deprecated(since = "1.52.0", note = "rustc-serialize is deprecated and no longer supported")]
#[doc(hidden)] // While technically stable, using it is unstable, and deprecated. Hide it.
pub macro RustcEncodable($item:item) {
/* compiler built-in */
#[inline]
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(reason = "use `align_of` instead", since = "1.2.0")]
+#[deprecated(note = "use `align_of` instead", since = "1.2.0")]
pub fn min_align_of<T>() -> usize {
intrinsics::min_align_of::<T>()
}
#[inline]
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(reason = "use `align_of_val` instead", since = "1.2.0")]
+#[deprecated(note = "use `align_of_val` instead", since = "1.2.0")]
pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize {
// SAFETY: val is a reference, so it's a valid raw pointer
unsafe { intrinsics::min_align_of_val(val) }
/// [inv]: MaybeUninit#initialization-invariant
#[inline(always)]
#[must_use]
-#[rustc_deprecated(since = "1.39.0", reason = "use `mem::MaybeUninit` instead")]
+#[deprecated(since = "1.39.0", note = "use `mem::MaybeUninit` instead")]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated_in_future)]
#[allow(deprecated)]
/// let r = f32::RADIX;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "TBD", reason = "replaced by the `RADIX` associated constant on `f32`")]
+#[deprecated(since = "TBD", note = "replaced by the `RADIX` associated constant on `f32`")]
pub const RADIX: u32 = f32::RADIX;
/// Number of significant digits in base 2.
/// let d = f32::MANTISSA_DIGITS;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
+#[deprecated(
since = "TBD",
- reason = "replaced by the `MANTISSA_DIGITS` associated constant on `f32`"
+ note = "replaced by the `MANTISSA_DIGITS` associated constant on `f32`"
)]
pub const MANTISSA_DIGITS: u32 = f32::MANTISSA_DIGITS;
/// let d = f32::DIGITS;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "TBD", reason = "replaced by the `DIGITS` associated constant on `f32`")]
+#[deprecated(since = "TBD", note = "replaced by the `DIGITS` associated constant on `f32`")]
pub const DIGITS: u32 = f32::DIGITS;
/// [Machine epsilon] value for `f32`.
/// let e = f32::EPSILON;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
- since = "TBD",
- reason = "replaced by the `EPSILON` associated constant on `f32`"
-)]
+#[deprecated(since = "TBD", note = "replaced by the `EPSILON` associated constant on `f32`")]
pub const EPSILON: f32 = f32::EPSILON;
/// Smallest finite `f32` value.
/// let min = f32::MIN;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "TBD", reason = "replaced by the `MIN` associated constant on `f32`")]
+#[deprecated(since = "TBD", note = "replaced by the `MIN` associated constant on `f32`")]
pub const MIN: f32 = f32::MIN;
/// Smallest positive normal `f32` value.
/// let min = f32::MIN_POSITIVE;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
- since = "TBD",
- reason = "replaced by the `MIN_POSITIVE` associated constant on `f32`"
-)]
+#[deprecated(since = "TBD", note = "replaced by the `MIN_POSITIVE` associated constant on `f32`")]
pub const MIN_POSITIVE: f32 = f32::MIN_POSITIVE;
/// Largest finite `f32` value.
/// let max = f32::MAX;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "TBD", reason = "replaced by the `MAX` associated constant on `f32`")]
+#[deprecated(since = "TBD", note = "replaced by the `MAX` associated constant on `f32`")]
pub const MAX: f32 = f32::MAX;
/// One greater than the minimum possible normal power of 2 exponent.
/// let min = f32::MIN_EXP;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
- since = "TBD",
- reason = "replaced by the `MIN_EXP` associated constant on `f32`"
-)]
+#[deprecated(since = "TBD", note = "replaced by the `MIN_EXP` associated constant on `f32`")]
pub const MIN_EXP: i32 = f32::MIN_EXP;
/// Maximum possible power of 2 exponent.
/// let max = f32::MAX_EXP;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
- since = "TBD",
- reason = "replaced by the `MAX_EXP` associated constant on `f32`"
-)]
+#[deprecated(since = "TBD", note = "replaced by the `MAX_EXP` associated constant on `f32`")]
pub const MAX_EXP: i32 = f32::MAX_EXP;
/// Minimum possible normal power of 10 exponent.
/// let min = f32::MIN_10_EXP;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
- since = "TBD",
- reason = "replaced by the `MIN_10_EXP` associated constant on `f32`"
-)]
+#[deprecated(since = "TBD", note = "replaced by the `MIN_10_EXP` associated constant on `f32`")]
pub const MIN_10_EXP: i32 = f32::MIN_10_EXP;
/// Maximum possible power of 10 exponent.
/// let max = f32::MAX_10_EXP;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
- since = "TBD",
- reason = "replaced by the `MAX_10_EXP` associated constant on `f32`"
-)]
+#[deprecated(since = "TBD", note = "replaced by the `MAX_10_EXP` associated constant on `f32`")]
pub const MAX_10_EXP: i32 = f32::MAX_10_EXP;
/// Not a Number (NaN).
/// let nan = f32::NAN;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "TBD", reason = "replaced by the `NAN` associated constant on `f32`")]
+#[deprecated(since = "TBD", note = "replaced by the `NAN` associated constant on `f32`")]
pub const NAN: f32 = f32::NAN;
/// Infinity (∞).
/// let inf = f32::INFINITY;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
- since = "TBD",
- reason = "replaced by the `INFINITY` associated constant on `f32`"
-)]
+#[deprecated(since = "TBD", note = "replaced by the `INFINITY` associated constant on `f32`")]
pub const INFINITY: f32 = f32::INFINITY;
/// Negative infinity (−∞).
/// let ninf = f32::NEG_INFINITY;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
- since = "TBD",
- reason = "replaced by the `NEG_INFINITY` associated constant on `f32`"
-)]
+#[deprecated(since = "TBD", note = "replaced by the `NEG_INFINITY` associated constant on `f32`")]
pub const NEG_INFINITY: f32 = f32::NEG_INFINITY;
/// Basic mathematical constants.
pub const MAX_10_EXP: i32 = 38;
/// Not a Number (NaN).
+ ///
+ /// Note that IEEE-745 doesn't define just a single NaN value;
+ /// a plethora of bit patterns are considered to be NaN.
+ /// Furthermore, the standard makes a difference
+ /// between a "signaling" and a "quiet" NaN,
+ /// and allows inspecting its "payload" (the unspecified bits in the bit pattern).
+ /// This constant isn't guaranteed to equal to any specific NaN bitpattern,
+ /// and the stability of its representation over Rust versions
+ /// and target platforms isn't guaranteed.
#[stable(feature = "assoc_int_consts", since = "1.43.0")]
pub const NAN: f32 = 0.0_f32 / 0.0_f32;
/// Infinity (∞).
#[stable(feature = "assoc_int_consts", since = "1.43.0")]
pub const NEG_INFINITY: f32 = -1.0_f32 / 0.0_f32;
- /// Returns `true` if this value is `NaN`.
+ /// Returns `true` if this value is NaN.
///
/// ```
/// let nan = f32::NAN;
(self == f32::INFINITY) | (self == f32::NEG_INFINITY)
}
- /// Returns `true` if this number is neither infinite nor `NaN`.
+ /// Returns `true` if this number is neither infinite nor NaN.
///
/// ```
/// let f = 7.0f32;
}
/// Returns `true` if the number is neither zero, infinite,
- /// [subnormal], or `NaN`.
+ /// [subnormal], or NaN.
///
/// ```
/// let min = f32::MIN_POSITIVE; // 1.17549435e-38f32
}
}
- /// Returns `true` if `self` has a positive sign, including `+0.0`, `NaN`s with
- /// positive sign bit and positive infinity.
+ /// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs with
+ /// positive sign bit and positive infinity. Note that IEEE-745 doesn't assign any
+ /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
+ /// the bit pattern of NaNs are conserved over arithmetic operations, the result of
+ /// `is_sign_positive` on a NaN might produce an unexpected result in some cases.
+ /// See [explanation of NaN as a special value](f32) for more info.
///
/// ```
/// let f = 7.0_f32;
!self.is_sign_negative()
}
- /// Returns `true` if `self` has a negative sign, including `-0.0`, `NaN`s with
- /// negative sign bit and negative infinity.
+ /// Returns `true` if `self` has a negative sign, including `-0.0`, NaNs with
+ /// negative sign bit and negative infinity. Note that IEEE-745 doesn't assign any
+ /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
+ /// the bit pattern of NaNs are conserved over arithmetic operations, the result of
+ /// `is_sign_negative` on a NaN might produce an unexpected result in some cases.
+ /// See [explanation of NaN as a special value](f32) for more info.
///
/// ```
/// let f = 7.0f32;
self * (value / 180.0f32)
}
- /// Returns the maximum of the two numbers.
+ /// Returns the maximum of the two numbers, ignoring NaN.
///
- /// Follows the IEEE-754 2008 semantics for maxNum, except for handling of signaling NaNs.
- /// This matches the behavior of libm’s fmax.
+ /// If one of the arguments is NaN, then the other argument is returned.
+ /// This follows the IEEE-754 2008 semantics for maxNum, except for handling of signaling NaNs;
+ /// this function handles all NaNs the same way and avoids maxNum's problems with associativity.
+ /// This also matches the behavior of libm’s fmax.
///
/// ```
/// let x = 1.0f32;
///
/// assert_eq!(x.max(y), y);
/// ```
- ///
- /// If one of the arguments is NaN, then the other argument is returned.
#[must_use = "this returns the result of the comparison, without modifying either input"]
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
intrinsics::maxnumf32(self, other)
}
- /// Returns the minimum of the two numbers.
+ /// Returns the minimum of the two numbers, ignoring NaN.
///
- /// Follows the IEEE-754 2008 semantics for minNum, except for handling of signaling NaNs.
- /// This matches the behavior of libm’s fmin.
+ /// If one of the arguments is NaN, then the other argument is returned.
+ /// This follows the IEEE-754 2008 semantics for minNum, except for handling of signaling NaNs;
+ /// this function handles all NaNs the same way and avoids minNum's problems with associativity.
+ /// This also matches the behavior of libm’s fmin.
///
/// ```
/// let x = 1.0f32;
///
/// assert_eq!(x.min(y), x);
/// ```
- ///
- /// If one of the arguments is NaN, then the other argument is returned.
#[must_use = "this returns the result of the comparison, without modifying either input"]
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
intrinsics::minnumf32(self, other)
}
- /// Returns the maximum of the two numbers, propagating NaNs.
+ /// Returns the maximum of the two numbers, propagating NaN.
///
/// This returns NaN when *either* argument is NaN, as opposed to
/// [`f32::max`] which only returns NaN when *both* arguments are NaN.
/// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the greater
/// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
/// Note that this follows the semantics specified in IEEE 754-2019.
+ ///
+ /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN
+ /// operand is conserved; see [explanation of NaN as a special value](f32) for more info.
#[must_use = "this returns the result of the comparison, without modifying either input"]
#[unstable(feature = "float_minimum_maximum", issue = "91079")]
#[inline]
}
}
- /// Returns the minimum of the two numbers, propagating NaNs.
+ /// Returns the minimum of the two numbers, propagating NaN.
///
/// This returns NaN when *either* argument is NaN, as opposed to
/// [`f32::min`] which only returns NaN when *both* arguments are NaN.
/// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the lesser
/// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
/// Note that this follows the semantics specified in IEEE 754-2019.
+ ///
+ /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN
+ /// operand is conserved; see [explanation of NaN as a special value](f32) for more info.
#[must_use = "this returns the result of the comparison, without modifying either input"]
#[unstable(feature = "float_minimum_maximum", issue = "91079")]
#[inline]
/// Return the memory representation of this floating point number as a byte array in
/// big-endian (network) byte order.
///
+ /// See [`from_bits`](Self::from_bits) for some discussion of the
+ /// portability of this operation (there are almost no issues).
+ ///
/// # Examples
///
/// ```
/// Return the memory representation of this floating point number as a byte array in
/// little-endian byte order.
///
+ /// See [`from_bits`](Self::from_bits) for some discussion of the
+ /// portability of this operation (there are almost no issues).
+ ///
/// # Examples
///
/// ```
/// [`to_be_bytes`]: f32::to_be_bytes
/// [`to_le_bytes`]: f32::to_le_bytes
///
+ /// See [`from_bits`](Self::from_bits) for some discussion of the
+ /// portability of this operation (there are almost no issues).
+ ///
/// # Examples
///
/// ```
/// Create a floating point value from its representation as a byte array in big endian.
///
+ /// See [`from_bits`](Self::from_bits) for some discussion of the
+ /// portability of this operation (there are almost no issues).
+ ///
/// # Examples
///
/// ```
/// Create a floating point value from its representation as a byte array in little endian.
///
+ /// See [`from_bits`](Self::from_bits) for some discussion of the
+ /// portability of this operation (there are almost no issues).
+ ///
/// # Examples
///
/// ```
/// [`from_be_bytes`]: f32::from_be_bytes
/// [`from_le_bytes`]: f32::from_le_bytes
///
+ /// See [`from_bits`](Self::from_bits) for some discussion of the
+ /// portability of this operation (there are almost no issues).
+ ///
/// # Examples
///
/// ```
/// let r = f64::RADIX;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "TBD", reason = "replaced by the `RADIX` associated constant on `f64`")]
+#[deprecated(since = "TBD", note = "replaced by the `RADIX` associated constant on `f64`")]
pub const RADIX: u32 = f64::RADIX;
/// Number of significant digits in base 2.
/// let d = f64::MANTISSA_DIGITS;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
+#[deprecated(
since = "TBD",
- reason = "replaced by the `MANTISSA_DIGITS` associated constant on `f64`"
+ note = "replaced by the `MANTISSA_DIGITS` associated constant on `f64`"
)]
pub const MANTISSA_DIGITS: u32 = f64::MANTISSA_DIGITS;
/// let d = f64::DIGITS;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "TBD", reason = "replaced by the `DIGITS` associated constant on `f64`")]
+#[deprecated(since = "TBD", note = "replaced by the `DIGITS` associated constant on `f64`")]
pub const DIGITS: u32 = f64::DIGITS;
/// [Machine epsilon] value for `f64`.
/// let e = f64::EPSILON;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
- since = "TBD",
- reason = "replaced by the `EPSILON` associated constant on `f64`"
-)]
+#[deprecated(since = "TBD", note = "replaced by the `EPSILON` associated constant on `f64`")]
pub const EPSILON: f64 = f64::EPSILON;
/// Smallest finite `f64` value.
/// let min = f64::MIN;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "TBD", reason = "replaced by the `MIN` associated constant on `f64`")]
+#[deprecated(since = "TBD", note = "replaced by the `MIN` associated constant on `f64`")]
pub const MIN: f64 = f64::MIN;
/// Smallest positive normal `f64` value.
/// let min = f64::MIN_POSITIVE;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
- since = "TBD",
- reason = "replaced by the `MIN_POSITIVE` associated constant on `f64`"
-)]
+#[deprecated(since = "TBD", note = "replaced by the `MIN_POSITIVE` associated constant on `f64`")]
pub const MIN_POSITIVE: f64 = f64::MIN_POSITIVE;
/// Largest finite `f64` value.
/// let max = f64::MAX;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "TBD", reason = "replaced by the `MAX` associated constant on `f64`")]
+#[deprecated(since = "TBD", note = "replaced by the `MAX` associated constant on `f64`")]
pub const MAX: f64 = f64::MAX;
/// One greater than the minimum possible normal power of 2 exponent.
/// let min = f64::MIN_EXP;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
- since = "TBD",
- reason = "replaced by the `MIN_EXP` associated constant on `f64`"
-)]
+#[deprecated(since = "TBD", note = "replaced by the `MIN_EXP` associated constant on `f64`")]
pub const MIN_EXP: i32 = f64::MIN_EXP;
/// Maximum possible power of 2 exponent.
/// let max = f64::MAX_EXP;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
- since = "TBD",
- reason = "replaced by the `MAX_EXP` associated constant on `f64`"
-)]
+#[deprecated(since = "TBD", note = "replaced by the `MAX_EXP` associated constant on `f64`")]
pub const MAX_EXP: i32 = f64::MAX_EXP;
/// Minimum possible normal power of 10 exponent.
/// let min = f64::MIN_10_EXP;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
- since = "TBD",
- reason = "replaced by the `MIN_10_EXP` associated constant on `f64`"
-)]
+#[deprecated(since = "TBD", note = "replaced by the `MIN_10_EXP` associated constant on `f64`")]
pub const MIN_10_EXP: i32 = f64::MIN_10_EXP;
/// Maximum possible power of 10 exponent.
/// let max = f64::MAX_10_EXP;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
- since = "TBD",
- reason = "replaced by the `MAX_10_EXP` associated constant on `f64`"
-)]
+#[deprecated(since = "TBD", note = "replaced by the `MAX_10_EXP` associated constant on `f64`")]
pub const MAX_10_EXP: i32 = f64::MAX_10_EXP;
/// Not a Number (NaN).
/// let nan = f64::NAN;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "TBD", reason = "replaced by the `NAN` associated constant on `f64`")]
+#[deprecated(since = "TBD", note = "replaced by the `NAN` associated constant on `f64`")]
pub const NAN: f64 = f64::NAN;
/// Infinity (∞).
/// let inf = f64::INFINITY;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
- since = "TBD",
- reason = "replaced by the `INFINITY` associated constant on `f64`"
-)]
+#[deprecated(since = "TBD", note = "replaced by the `INFINITY` associated constant on `f64`")]
pub const INFINITY: f64 = f64::INFINITY;
/// Negative infinity (−∞).
/// let ninf = f64::NEG_INFINITY;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
- since = "TBD",
- reason = "replaced by the `NEG_INFINITY` associated constant on `f64`"
-)]
+#[deprecated(since = "TBD", note = "replaced by the `NEG_INFINITY` associated constant on `f64`")]
pub const NEG_INFINITY: f64 = f64::NEG_INFINITY;
/// Basic mathematical constants.
pub const MAX_10_EXP: i32 = 308;
/// Not a Number (NaN).
+ ///
+ /// Note that IEEE-745 doesn't define just a single NaN value;
+ /// a plethora of bit patterns are considered to be NaN.
+ /// Furthermore, the standard makes a difference
+ /// between a "signaling" and a "quiet" NaN,
+ /// and allows inspecting its "payload" (the unspecified bits in the bit pattern).
+ /// This constant isn't guaranteed to equal to any specific NaN bitpattern,
+ /// and the stability of its representation over Rust versions
+ /// and target platforms isn't guaranteed.
#[stable(feature = "assoc_int_consts", since = "1.43.0")]
pub const NAN: f64 = 0.0_f64 / 0.0_f64;
/// Infinity (∞).
#[stable(feature = "assoc_int_consts", since = "1.43.0")]
pub const NEG_INFINITY: f64 = -1.0_f64 / 0.0_f64;
- /// Returns `true` if this value is `NaN`.
+ /// Returns `true` if this value is NaN.
///
/// ```
/// let nan = f64::NAN;
(self == f64::INFINITY) | (self == f64::NEG_INFINITY)
}
- /// Returns `true` if this number is neither infinite nor `NaN`.
+ /// Returns `true` if this number is neither infinite nor NaN.
///
/// ```
/// let f = 7.0f64;
}
/// Returns `true` if the number is neither zero, infinite,
- /// [subnormal], or `NaN`.
+ /// [subnormal], or NaN.
///
/// ```
/// let min = f64::MIN_POSITIVE; // 2.2250738585072014e-308f64
}
}
- /// Returns `true` if `self` has a positive sign, including `+0.0`, `NaN`s with
- /// positive sign bit and positive infinity.
+ /// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs with
+ /// positive sign bit and positive infinity. Note that IEEE-745 doesn't assign any
+ /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
+ /// the bit pattern of NaNs are conserved over arithmetic operations, the result of
+ /// `is_sign_positive` on a NaN might produce an unexpected result in some cases.
+ /// See [explanation of NaN as a special value](f32) for more info.
///
/// ```
/// let f = 7.0_f64;
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_positive")]
+ #[deprecated(since = "1.0.0", note = "renamed to is_sign_positive")]
#[inline]
#[doc(hidden)]
pub fn is_positive(self) -> bool {
self.is_sign_positive()
}
- /// Returns `true` if `self` has a negative sign, including `-0.0`, `NaN`s with
- /// negative sign bit and negative infinity.
+ /// Returns `true` if `self` has a negative sign, including `-0.0`, NaNs with
+ /// negative sign bit and negative infinity. Note that IEEE-745 doesn't assign any
+ /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
+ /// the bit pattern of NaNs are conserved over arithmetic operations, the result of
+ /// `is_sign_negative` on a NaN might produce an unexpected result in some cases.
+ /// See [explanation of NaN as a special value](f32) for more info.
///
/// ```
/// let f = 7.0_f64;
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_negative")]
+ #[deprecated(since = "1.0.0", note = "renamed to is_sign_negative")]
#[inline]
#[doc(hidden)]
pub fn is_negative(self) -> bool {
self * (value / 180.0)
}
- /// Returns the maximum of the two numbers.
+ /// Returns the maximum of the two numbers, ignoring NaN.
///
- /// Follows the IEEE-754 2008 semantics for maxNum, except for handling of signaling NaNs.
- /// This matches the behavior of libm’s fmax.
+ /// If one of the arguments is NaN, then the other argument is returned.
+ /// This follows the IEEE-754 2008 semantics for maxNum, except for handling of signaling NaNs;
+ /// this function handles all NaNs the same way and avoids maxNum's problems with associativity.
+ /// This also matches the behavior of libm’s fmax.
///
/// ```
/// let x = 1.0_f64;
///
/// assert_eq!(x.max(y), y);
/// ```
- ///
- /// If one of the arguments is NaN, then the other argument is returned.
#[must_use = "this returns the result of the comparison, without modifying either input"]
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
intrinsics::maxnumf64(self, other)
}
- /// Returns the minimum of the two numbers.
+ /// Returns the minimum of the two numbers, ignoring NaN.
///
- /// Follows the IEEE-754 2008 semantics for minNum, except for handling of signaling NaNs.
- /// This matches the behavior of libm’s fmin.
+ /// If one of the arguments is NaN, then the other argument is returned.
+ /// This follows the IEEE-754 2008 semantics for minNum, except for handling of signaling NaNs;
+ /// this function handles all NaNs the same way and avoids minNum's problems with associativity.
+ /// This also matches the behavior of libm’s fmin.
///
/// ```
/// let x = 1.0_f64;
///
/// assert_eq!(x.min(y), x);
/// ```
- ///
- /// If one of the arguments is NaN, then the other argument is returned.
#[must_use = "this returns the result of the comparison, without modifying either input"]
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
intrinsics::minnumf64(self, other)
}
- /// Returns the maximum of the two numbers, propagating NaNs.
+ /// Returns the maximum of the two numbers, propagating NaN.
///
/// This returns NaN when *either* argument is NaN, as opposed to
/// [`f64::max`] which only returns NaN when *both* arguments are NaN.
/// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the greater
/// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
/// Note that this follows the semantics specified in IEEE 754-2019.
+ ///
+ /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN
+ /// operand is conserved; see [explanation of NaN as a special value](f32) for more info.
#[must_use = "this returns the result of the comparison, without modifying either input"]
#[unstable(feature = "float_minimum_maximum", issue = "91079")]
#[inline]
}
}
- /// Returns the minimum of the two numbers, propagating NaNs.
+ /// Returns the minimum of the two numbers, propagating NaN.
///
/// This returns NaN when *either* argument is NaN, as opposed to
/// [`f64::min`] which only returns NaN when *both* arguments are NaN.
/// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the lesser
/// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
/// Note that this follows the semantics specified in IEEE 754-2019.
+ ///
+ /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN
+ /// operand is conserved; see [explanation of NaN as a special value](f32) for more info.
#[must_use = "this returns the result of the comparison, without modifying either input"]
#[unstable(feature = "float_minimum_maximum", issue = "91079")]
#[inline]
/// Return the memory representation of this floating point number as a byte array in
/// big-endian (network) byte order.
///
+ /// See [`from_bits`](Self::from_bits) for some discussion of the
+ /// portability of this operation (there are almost no issues).
+ ///
/// # Examples
///
/// ```
/// Return the memory representation of this floating point number as a byte array in
/// little-endian byte order.
///
+ /// See [`from_bits`](Self::from_bits) for some discussion of the
+ /// portability of this operation (there are almost no issues).
+ ///
/// # Examples
///
/// ```
/// [`to_be_bytes`]: f64::to_be_bytes
/// [`to_le_bytes`]: f64::to_le_bytes
///
+ /// See [`from_bits`](Self::from_bits) for some discussion of the
+ /// portability of this operation (there are almost no issues).
+ ///
/// # Examples
///
/// ```
/// Create a floating point value from its representation as a byte array in big endian.
///
+ /// See [`from_bits`](Self::from_bits) for some discussion of the
+ /// portability of this operation (there are almost no issues).
+ ///
/// # Examples
///
/// ```
/// Create a floating point value from its representation as a byte array in little endian.
///
+ /// See [`from_bits`](Self::from_bits) for some discussion of the
+ /// portability of this operation (there are almost no issues).
+ ///
/// # Examples
///
/// ```
/// [`from_be_bytes`]: f64::from_be_bytes
/// [`from_le_bytes`]: f64::from_le_bytes
///
+ /// See [`from_bits`](Self::from_bits) for some discussion of the
+ /// portability of this operation (there are almost no issues).
+ ///
/// # Examples
///
/// ```
#[inline(always)]
#[rustc_promotable]
#[rustc_const_stable(feature = "const_min_value", since = "1.32.0")]
- #[rustc_deprecated(since = "TBD", reason = "replaced by the `MIN` associated constant on this type")]
+ #[deprecated(since = "TBD", note = "replaced by the `MIN` associated constant on this type")]
pub const fn min_value() -> Self {
Self::MIN
}
#[inline(always)]
#[rustc_promotable]
#[rustc_const_stable(feature = "const_max_value", since = "1.32.0")]
- #[rustc_deprecated(since = "TBD", reason = "replaced by the `MAX` associated constant on this type")]
+ #[deprecated(since = "TBD", note = "replaced by the `MAX` associated constant on this type")]
pub const fn max_value() -> Self {
Self::MAX
}
//! New code should use the associated constants directly on the primitive type.
#![stable(feature = "i128", since = "1.26.0")]
-#![rustc_deprecated(
+#![deprecated(
since = "TBD",
- reason = "all constants in this module replaced by associated constants on `i128`"
+ note = "all constants in this module replaced by associated constants on `i128`"
)]
int_module! { i128, #[stable(feature = "i128", since="1.26.0")] }
//! New code should use the associated constants directly on the primitive type.
#![stable(feature = "rust1", since = "1.0.0")]
-#![rustc_deprecated(
+#![deprecated(
since = "TBD",
- reason = "all constants in this module replaced by associated constants on `i16`"
+ note = "all constants in this module replaced by associated constants on `i16`"
)]
int_module! { i16 }
//! New code should use the associated constants directly on the primitive type.
#![stable(feature = "rust1", since = "1.0.0")]
-#![rustc_deprecated(
+#![deprecated(
since = "TBD",
- reason = "all constants in this module replaced by associated constants on `i32`"
+ note = "all constants in this module replaced by associated constants on `i32`"
)]
int_module! { i32 }
//! New code should use the associated constants directly on the primitive type.
#![stable(feature = "rust1", since = "1.0.0")]
-#![rustc_deprecated(
+#![deprecated(
since = "TBD",
- reason = "all constants in this module replaced by associated constants on `i64`"
+ note = "all constants in this module replaced by associated constants on `i64`"
)]
int_module! { i64 }
//! New code should use the associated constants directly on the primitive type.
#![stable(feature = "rust1", since = "1.0.0")]
-#![rustc_deprecated(
+#![deprecated(
since = "TBD",
- reason = "all constants in this module replaced by associated constants on `i8`"
+ note = "all constants in this module replaced by associated constants on `i8`"
)]
int_module! { i8 }
/// ```
///
#[$attr]
- #[rustc_deprecated(since = "TBD", reason = "replaced by the `MIN` associated constant on this type")]
+ #[deprecated(since = "TBD", note = "replaced by the `MIN` associated constant on this type")]
pub const MIN: $T = $T::MIN;
#[doc = concat!(
/// ```
///
#[$attr]
- #[rustc_deprecated(since = "TBD", reason = "replaced by the `MAX` associated constant on this type")]
+ #[deprecated(since = "TBD", note = "replaced by the `MAX` associated constant on this type")]
pub const MAX: $T = $T::MAX;
)
}
//! New code should use the associated constants directly on the primitive type.
#![stable(feature = "rust1", since = "1.0.0")]
-#![rustc_deprecated(
+#![deprecated(
since = "TBD",
- reason = "all constants in this module replaced by associated constants on `isize`"
+ note = "all constants in this module replaced by associated constants on `isize`"
)]
int_module! { isize }
//! New code should use the associated constants directly on the primitive type.
#![stable(feature = "i128", since = "1.26.0")]
-#![rustc_deprecated(
+#![deprecated(
since = "TBD",
- reason = "all constants in this module replaced by associated constants on `u128`"
+ note = "all constants in this module replaced by associated constants on `u128`"
)]
int_module! { u128, #[stable(feature = "i128", since="1.26.0")] }
//! New code should use the associated constants directly on the primitive type.
#![stable(feature = "rust1", since = "1.0.0")]
-#![rustc_deprecated(
+#![deprecated(
since = "TBD",
- reason = "all constants in this module replaced by associated constants on `u16`"
+ note = "all constants in this module replaced by associated constants on `u16`"
)]
int_module! { u16 }
//! New code should use the associated constants directly on the primitive type.
#![stable(feature = "rust1", since = "1.0.0")]
-#![rustc_deprecated(
+#![deprecated(
since = "TBD",
- reason = "all constants in this module replaced by associated constants on `u32`"
+ note = "all constants in this module replaced by associated constants on `u32`"
)]
int_module! { u32 }
//! New code should use the associated constants directly on the primitive type.
#![stable(feature = "rust1", since = "1.0.0")]
-#![rustc_deprecated(
+#![deprecated(
since = "TBD",
- reason = "all constants in this module replaced by associated constants on `u64`"
+ note = "all constants in this module replaced by associated constants on `u64`"
)]
int_module! { u64 }
//! New code should use the associated constants directly on the primitive type.
#![stable(feature = "rust1", since = "1.0.0")]
-#![rustc_deprecated(
+#![deprecated(
since = "TBD",
- reason = "all constants in this module replaced by associated constants on `u8`"
+ note = "all constants in this module replaced by associated constants on `u8`"
)]
int_module! { u8 }
//! New code should use the associated constants directly on the primitive type.
#![stable(feature = "rust1", since = "1.0.0")]
-#![rustc_deprecated(
+#![deprecated(
since = "TBD",
- reason = "all constants in this module replaced by associated constants on `usize`"
+ note = "all constants in this module replaced by associated constants on `usize`"
)]
int_module! { usize }
#[rustc_promotable]
#[inline(always)]
#[rustc_const_stable(feature = "const_max_value", since = "1.32.0")]
- #[rustc_deprecated(since = "TBD", reason = "replaced by the `MIN` associated constant on this type")]
+ #[deprecated(since = "TBD", note = "replaced by the `MIN` associated constant on this type")]
pub const fn min_value() -> Self { Self::MIN }
/// New code should prefer to use
#[rustc_promotable]
#[inline(always)]
#[rustc_const_stable(feature = "const_max_value", since = "1.32.0")]
- #[rustc_deprecated(since = "TBD", reason = "replaced by the `MAX` associated constant on this type")]
+ #[deprecated(since = "TBD", note = "replaced by the `MAX` associated constant on this type")]
pub const fn max_value() -> Self { Self::MAX }
}
}
/// like `1.0 / 0.0`.
/// - [NaN (not a number)](#associatedconstant.NAN): this value results from
/// calculations like `(-1.0).sqrt()`. NaN has some potentially unexpected
-/// behavior: it is unequal to any float, including itself! It is also neither
-/// smaller nor greater than any float, making it impossible to sort. Lastly,
-/// it is considered infectious as almost all calculations where one of the
-/// operands is NaN will also result in NaN.
+/// behavior:
+/// - It is unequal to any float, including itself! This is the reason `f32`
+/// doesn't implement the `Eq` trait.
+/// - It is also neither smaller nor greater than any float, making it
+/// impossible to sort by the default comparison operation, which is the
+/// reason `f32` doesn't implement the `Ord` trait.
+/// - It is also considered *infectious* as almost all calculations where one
+/// of the operands is NaN will also result in NaN. The explanations on this
+/// page only explicitly document behavior on NaN operands if this default
+/// is deviated from.
+/// - Lastly, there are multiple bit patterns that are considered NaN.
+/// Rust does not currently guarantee that the bit patterns of NaN are
+/// preserved over arithmetic operations, and they are not guaranteed to be
+/// portable or even fully deterministic! This means that there may be some
+/// surprising results upon inspecting the bit patterns,
+/// as the same calculations might produce NaNs with different bit patterns.
///
/// For more information on floating point numbers, see [Wikipedia][wikipedia].
///
/// For the mutable counterpart see [`as_mut`].
///
/// [`as_uninit_ref`]: #method.as_uninit_ref-1
- /// [`as_mut`]: #method.as_mut
+ /// [`as_mut`]: #method.as_mut-1
///
/// # Safety
///
use crate::ptr::Unique;
use crate::slice::{self, SliceIndex};
-/// `*mut T` but non-zero and covariant.
+/// `*mut T` but non-zero and [covariant].
///
/// This is often the correct thing to use when building data structures using
/// raw pointers, but is ultimately more dangerous to use because of its additional
/// it is your responsibility to ensure that `as_mut` is never called, and `as_ptr`
/// is never used for mutation.
///
+/// [covariant]: https://doc.rust-lang.org/reference/subtyping.html
/// [`PhantomData`]: crate::marker::PhantomData
/// [`UnsafeCell<T>`]: crate::cell::UnsafeCell
#[stable(feature = "nonnull", since = "1.25.0")]
}
}
- #[doc(hidden)]
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
// SAFETY: since the caller guarantees that `i` is in bounds,
// which means that `i` cannot overflow an `isize`, and the
}
}
- #[doc(hidden)]
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
let start = idx * self.chunk_size;
// SAFETY: the caller guarantees that `i` is in bounds,
}
}
- #[doc(hidden)]
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
let start = idx * self.chunk_size;
// SAFETY: see comments for `Chunks::__iterator_get_unchecked`.
self.next_back()
}
- #[doc(hidden)]
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
let start = idx * self.chunk_size;
// SAFETY: mostly identical to `Chunks::__iterator_get_unchecked`.
self.next_back()
}
- #[doc(hidden)]
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
let start = idx * self.chunk_size;
// SAFETY: see comments for `ChunksMut::__iterator_get_unchecked`.
self.iter.last()
}
- #[doc(hidden)]
unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> &'a [T; N] {
// SAFETY: The safety guarantees of `__iterator_get_unchecked` are
// transferred to the caller.
self.iter.last()
}
- #[doc(hidden)]
unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> &'a mut [T; N] {
// SAFETY: The safety guarantees of `__iterator_get_unchecked` are transferred to
// the caller.
}
}
- #[doc(hidden)]
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
let end = self.v.len() - idx * self.chunk_size;
let start = match end.checked_sub(self.chunk_size) {
}
}
- #[doc(hidden)]
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
let end = self.v.len() - idx * self.chunk_size;
let start = match end.checked_sub(self.chunk_size) {
self.next_back()
}
- #[doc(hidden)]
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
let end = self.v.len() - idx * self.chunk_size;
let start = end - self.chunk_size;
self.next_back()
}
- #[doc(hidden)]
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
let end = self.v.len() - idx * self.chunk_size;
let start = end - self.chunk_size;
None
}
- #[doc(hidden)]
#[inline]
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
// SAFETY: the caller must guarantee that `i` is in bounds of
}
#[inline]
- #[doc(hidden)]
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> u8 {
// SAFETY: the caller must uphold the safety contract
// for `Iterator::__iterator_get_unchecked`.
///
/// [`lines_any`]: str::lines_any
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "1.4.0", reason = "use lines()/Lines instead now")]
+#[deprecated(since = "1.4.0", note = "use lines()/Lines instead now")]
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[derive(Clone, Debug)]
#[allow(deprecated)]
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_deprecated(since = "1.29.0", reason = "use `get_unchecked(begin..end)` instead")]
+ #[deprecated(since = "1.29.0", note = "use `get_unchecked(begin..end)` instead")]
#[must_use]
#[inline]
pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str {
/// * `begin` and `end` must be byte positions within the string slice.
/// * `begin` and `end` must lie on UTF-8 sequence boundaries.
#[stable(feature = "str_slice_mut", since = "1.5.0")]
- #[rustc_deprecated(since = "1.29.0", reason = "use `get_unchecked_mut(begin..end)` instead")]
+ #[deprecated(since = "1.29.0", note = "use `get_unchecked_mut(begin..end)` instead")]
#[inline]
pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str {
// SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`;
/// An iterator over the lines of a string.
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_deprecated(since = "1.4.0", reason = "use lines() instead now")]
+ #[deprecated(since = "1.4.0", note = "use lines() instead now")]
#[inline]
#[allow(deprecated)]
pub fn lines_any(&self) -> LinesAny<'_> {
without modifying the original"]
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_deprecated(
- since = "1.33.0",
- reason = "superseded by `trim_start`",
- suggestion = "trim_start"
- )]
+ #[deprecated(since = "1.33.0", note = "superseded by `trim_start`", suggestion = "trim_start")]
pub fn trim_left(&self) -> &str {
self.trim_start()
}
without modifying the original"]
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_deprecated(
- since = "1.33.0",
- reason = "superseded by `trim_end`",
- suggestion = "trim_end"
- )]
+ #[deprecated(since = "1.33.0", note = "superseded by `trim_end`", suggestion = "trim_end")]
pub fn trim_right(&self) -> &str {
self.trim_end()
}
/// assert_eq!("12foo1bar12".trim_left_matches(x), "foo1bar12");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_deprecated(
+ #[deprecated(
since = "1.33.0",
- reason = "superseded by `trim_start_matches`",
+ note = "superseded by `trim_start_matches`",
suggestion = "trim_start_matches"
)]
pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
/// assert_eq!("1fooX".trim_right_matches(|c| c == '1' || c == 'X'), "1foo");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_deprecated(
+ #[deprecated(
since = "1.33.0",
- reason = "superseded by `trim_end_matches`",
+ note = "superseded by `trim_end_matches`",
suggestion = "trim_end_matches"
)]
pub fn trim_right_matches<'a, P>(&'a self, pat: P) -> &'a str
/// loads and stores of pointers. Its size depends on the target pointer's size.
#[cfg(target_has_atomic_load_store = "ptr")]
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "AtomicPtr")]
#[cfg_attr(target_pointer_width = "16", repr(C, align(2)))]
#[cfg_attr(target_pointer_width = "32", repr(C, align(4)))]
#[cfg_attr(target_pointer_width = "64", repr(C, align(8)))]
/// An [`AtomicBool`] initialized to `false`.
#[cfg(target_has_atomic_load_store = "8")]
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
+#[deprecated(
since = "1.34.0",
- reason = "the `new` function is now preferred",
+ note = "the `new` function is now preferred",
suggestion = "AtomicBool::new(false)"
)]
pub const ATOMIC_BOOL_INIT: AtomicBool = AtomicBool::new(false);
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_deprecated(
+ #[deprecated(
since = "1.50.0",
- reason = "Use `compare_exchange` or `compare_exchange_weak` instead"
+ note = "Use `compare_exchange` or `compare_exchange_weak` instead"
)]
#[cfg(target_has_atomic = "8")]
pub fn compare_and_swap(&self, current: bool, new: bool, order: Ordering) -> bool {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_deprecated(
+ #[deprecated(
since = "1.50.0",
- reason = "Use `compare_exchange` or `compare_exchange_weak` instead"
+ note = "Use `compare_exchange` or `compare_exchange_weak` instead"
)]
#[cfg(target_has_atomic = "ptr")]
pub fn compare_and_swap(&self, current: *mut T, new: *mut T, order: Ordering) -> *mut T {
$stable_nand:meta,
$const_stable:meta,
$stable_init_const:meta,
+ $diagnostic_item:meta,
$s_int_type:literal,
$extra_feature:expr,
$min_fn:ident, $max_fn:ident,
///
/// [module-level documentation]: crate::sync::atomic
#[$stable]
+ #[$diagnostic_item]
#[repr(C, align($align))]
pub struct $atomic_type {
v: UnsafeCell<$int_type>,
/// An atomic integer initialized to `0`.
#[$stable_init_const]
- #[rustc_deprecated(
+ #[deprecated(
since = "1.34.0",
- reason = "the `new` function is now preferred",
+ note = "the `new` function is now preferred",
suggestion = $atomic_new,
)]
pub const $atomic_init: $atomic_type = $atomic_type::new(0);
/// ```
#[inline]
#[$stable]
- #[rustc_deprecated(
+ #[deprecated(
since = "1.50.0",
- reason = "Use `compare_exchange` or `compare_exchange_weak` instead")
+ note = "Use `compare_exchange` or `compare_exchange_weak` instead")
]
#[$cfg_cas]
pub fn compare_and_swap(&self,
stable(feature = "integer_atomics_stable", since = "1.34.0"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
unstable(feature = "integer_atomics", issue = "32976"),
+ cfg_attr(not(test), rustc_diagnostic_item = "AtomicI8"),
"i8",
"",
atomic_min, atomic_max,
stable(feature = "integer_atomics_stable", since = "1.34.0"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
unstable(feature = "integer_atomics", issue = "32976"),
+ cfg_attr(not(test), rustc_diagnostic_item = "AtomicU8"),
"u8",
"",
atomic_umin, atomic_umax,
stable(feature = "integer_atomics_stable", since = "1.34.0"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
unstable(feature = "integer_atomics", issue = "32976"),
+ cfg_attr(not(test), rustc_diagnostic_item = "AtomicI16"),
"i16",
"",
atomic_min, atomic_max,
stable(feature = "integer_atomics_stable", since = "1.34.0"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
unstable(feature = "integer_atomics", issue = "32976"),
+ cfg_attr(not(test), rustc_diagnostic_item = "AtomicU16"),
"u16",
"",
atomic_umin, atomic_umax,
stable(feature = "integer_atomics_stable", since = "1.34.0"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
unstable(feature = "integer_atomics", issue = "32976"),
+ cfg_attr(not(test), rustc_diagnostic_item = "AtomicI32"),
"i32",
"",
atomic_min, atomic_max,
stable(feature = "integer_atomics_stable", since = "1.34.0"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
unstable(feature = "integer_atomics", issue = "32976"),
+ cfg_attr(not(test), rustc_diagnostic_item = "AtomicU32"),
"u32",
"",
atomic_umin, atomic_umax,
stable(feature = "integer_atomics_stable", since = "1.34.0"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
unstable(feature = "integer_atomics", issue = "32976"),
+ cfg_attr(not(test), rustc_diagnostic_item = "AtomicI64"),
"i64",
"",
atomic_min, atomic_max,
stable(feature = "integer_atomics_stable", since = "1.34.0"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
unstable(feature = "integer_atomics", issue = "32976"),
+ cfg_attr(not(test), rustc_diagnostic_item = "AtomicU64"),
"u64",
"",
atomic_umin, atomic_umax,
unstable(feature = "integer_atomics", issue = "32976"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
unstable(feature = "integer_atomics", issue = "32976"),
+ cfg_attr(not(test), rustc_diagnostic_item = "AtomicI128"),
"i128",
"#![feature(integer_atomics)]\n\n",
atomic_min, atomic_max,
unstable(feature = "integer_atomics", issue = "32976"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
unstable(feature = "integer_atomics", issue = "32976"),
+ cfg_attr(not(test), rustc_diagnostic_item = "AtomicU128"),
"u128",
"#![feature(integer_atomics)]\n\n",
atomic_umin, atomic_umax,
stable(feature = "atomic_nand", since = "1.27.0"),
rustc_const_stable(feature = "const_ptr_sized_atomics", since = "1.24.0"),
stable(feature = "rust1", since = "1.0.0"),
+ cfg_attr(not(test), rustc_diagnostic_item = "AtomicIsize"),
"isize",
"",
atomic_min, atomic_max,
stable(feature = "atomic_nand", since = "1.27.0"),
rustc_const_stable(feature = "const_ptr_sized_atomics", since = "1.24.0"),
stable(feature = "rust1", since = "1.0.0"),
+ cfg_attr(not(test), rustc_diagnostic_item = "AtomicUsize"),
"usize",
"",
atomic_umin, atomic_umax,
/// [`hint::spin_loop`]: crate::hint::spin_loop
#[inline]
#[stable(feature = "spin_loop_hint", since = "1.24.0")]
-#[rustc_deprecated(since = "1.51.0", reason = "use hint::spin_loop instead")]
+#[deprecated(since = "1.51.0", note = "use hint::spin_loop instead")]
pub fn spin_loop_hint() {
spin_loop()
}
///
/// [combining character]: https://en.wikipedia.org/wiki/Combining_character
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")]
+#[deprecated(since = "1.26.0", note = "use inherent methods instead")]
pub trait AsciiExt {
/// Container type for copied ASCII characters.
#[stable(feature = "rust1", since = "1.0.0")]
use crate::fmt::{self, Debug};
#[allow(deprecated)]
use crate::hash::{BuildHasher, Hash, Hasher, SipHasher13};
-use crate::iter::{FromIterator, FusedIterator};
+use crate::iter::FusedIterator;
use crate::ops::Index;
use crate::sys;
use crate::collections::TryReserveError;
use crate::fmt;
use crate::hash::{BuildHasher, Hash};
-use crate::iter::{Chain, FromIterator, FusedIterator};
+use crate::iter::{Chain, FusedIterator};
use crate::ops::{BitAnd, BitOr, BitXor, Sub};
use super::map::{map_try_reserve_error, RandomState};
#[stable(feature = "rust1", since = "1.0.0")]
// FIXME(#82080) The deprecation here is only theoretical, and does not actually produce a warning.
-#[rustc_deprecated(reason = "moved to `std::ops::Bound`", since = "1.26.0")]
+#[deprecated(note = "moved to `std::ops::Bound`", since = "1.26.0")]
#[doc(hidden)]
pub use crate::ops::Bound;
/// None => println!("Impossible to get your home dir!"),
/// }
/// ```
-#[rustc_deprecated(
+#[deprecated(
since = "1.29.0",
- reason = "This function's behavior is unexpected and probably not what you want. \
- Consider using a crate from crates.io instead."
+ note = "This function's behavior is unexpected and probably not what you want. \
+ Consider using a crate from crates.io instead."
)]
#[must_use]
#[stable(feature = "env", since = "1.0.0")]
///
/// # Security
///
-/// The output of this function should not be used in anything that might have
-/// security implications. For example:
+/// The output of this function should not be trusted for anything
+/// that might have security implications. Basically, if users can run
+/// the executable, they can change the output arbitrarily.
///
-/// ```
-/// fn main() {
-/// println!("{:?}", std::env::current_exe());
-/// }
-/// ```
-///
-/// On Linux systems, if this is compiled as `foo`:
+/// As an example, you can easily introduce a race condition. It goes
+/// like this:
///
-/// ```bash
-/// $ rustc foo.rs
-/// $ ./foo
-/// Ok("/home/alex/foo")
-/// ```
+/// 1. You get the path to the current executable using `current_exe()`, and
+/// store it in a variable.
+/// 2. Time passes. A malicious actor removes the current executable, and
+/// replaces it with a malicious one.
+/// 3. You then use the stored path to re-execute the current
+/// executable.
///
-/// And you make a hard link of the program:
-///
-/// ```bash
-/// $ ln foo bar
-/// ```
-///
-/// When you run it, you won’t get the path of the original executable, you’ll
-/// get the path of the hard link:
-///
-/// ```bash
-/// $ ./bar
-/// Ok("/home/alex/bar")
-/// ```
+/// You expected to safely execute the current executable, but you're
+/// instead executing something completely different. The code you
+/// just executed run with your privileges.
///
/// This sort of behavior has been known to [lead to privilege escalation] when
/// used incorrectly.
/// high-level module to provide its own errors while also revealing some of the
/// implementation for debugging via `source` chains.
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "Error")]
pub trait Error: Debug + Display {
/// The lower-level source of this error, if any.
///
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_deprecated(since = "1.42.0", reason = "use the Display impl or to_string()")]
+ #[deprecated(since = "1.42.0", note = "use the Display impl or to_string()")]
fn description(&self) -> &str {
"description() is deprecated; use Display"
}
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_deprecated(
+ #[deprecated(
since = "1.33.0",
- reason = "replaced by Error::source, which can support downcasting"
+ note = "replaced by Error::source, which can support downcasting"
)]
#[allow(missing_docs)]
fn cause(&self) -> Option<&dyn Error> {
#[cfg(not(test))]
impl f32 {
- /// Returns the largest integer less than or equal to a number.
+ /// Returns the largest integer less than or equal to `self`.
///
/// # Examples
///
unsafe { intrinsics::floorf32(self) }
}
- /// Returns the smallest integer greater than or equal to a number.
+ /// Returns the smallest integer greater than or equal to `self`.
///
/// # Examples
///
unsafe { intrinsics::ceilf32(self) }
}
- /// Returns the nearest integer to a number. Round half-way cases away from
+ /// Returns the nearest integer to `self`. Round half-way cases away from
/// `0.0`.
///
/// # Examples
unsafe { intrinsics::roundf32(self) }
}
- /// Returns the integer part of a number.
+ /// Returns the integer part of `self`.
+ /// This means that non-integer numbers are always truncated towards zero.
///
/// # Examples
///
unsafe { intrinsics::truncf32(self) }
}
- /// Returns the fractional part of a number.
+ /// Returns the fractional part of `self`.
///
/// # Examples
///
self - self.trunc()
}
- /// Computes the absolute value of `self`. Returns `NAN` if the
- /// number is `NAN`.
+ /// Computes the absolute value of `self`.
///
/// # Examples
///
///
/// - `1.0` if the number is positive, `+0.0` or `INFINITY`
/// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
- /// - `NAN` if the number is `NAN`
+ /// - NaN if the number is NaN
///
/// # Examples
///
/// `sign`.
///
/// Equal to `self` if the sign of `self` and `sign` are the same, otherwise
- /// equal to `-self`. If `self` is a `NAN`, then a `NAN` with the sign of
- /// `sign` is returned.
+ /// equal to `-self`. If `self` is a NaN, then a NaN with the sign bit of
+ /// `sign` is returned. Note, however, that conserving the sign bit on NaN
+ /// across arithmetical operations is not generally guaranteed.
+ /// See [explanation of NaN as a special value](primitive@f32) for more info.
///
/// # Examples
///
/// Raises a number to an integer power.
///
- /// Using this function is generally faster than using `powf`
+ /// Using this function is generally faster than using `powf`.
+ /// It might have a different sequence of rounding operations than `powf`,
+ /// so the results are not guaranteed to agree.
///
/// # Examples
///
#[must_use = "method returns a new number and does not mutate the original value"]
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- #[rustc_deprecated(
+ #[deprecated(
since = "1.10.0",
- reason = "you probably meant `(self - other).abs()`: \
- this operation is `(self - other).max(0.0)` \
- except that `abs_sub` also propagates NaNs (also \
- known as `fdimf` in C). If you truly need the positive \
- difference, consider using that expression or the C function \
- `fdimf`, depending on how you wish to handle NaN (please consider \
- filing an issue describing your use-case too)."
+ note = "you probably meant `(self - other).abs()`: \
+ this operation is `(self - other).max(0.0)` \
+ except that `abs_sub` also propagates NaNs (also \
+ known as `fdimf` in C). If you truly need the positive \
+ difference, consider using that expression or the C function \
+ `fdimf`, depending on how you wish to handle NaN (please consider \
+ filing an issue describing your use-case too)."
)]
pub fn abs_sub(self, other: f32) -> f32 {
unsafe { cmath::fdimf(self, other) }
#[cfg(not(test))]
impl f64 {
- /// Returns the largest integer less than or equal to a number.
+ /// Returns the largest integer less than or equal to `self`.
///
/// # Examples
///
unsafe { intrinsics::floorf64(self) }
}
- /// Returns the smallest integer greater than or equal to a number.
+ /// Returns the smallest integer greater than or equal to `self`.
///
/// # Examples
///
unsafe { intrinsics::ceilf64(self) }
}
- /// Returns the nearest integer to a number. Round half-way cases away from
+ /// Returns the nearest integer to `self`. Round half-way cases away from
/// `0.0`.
///
/// # Examples
unsafe { intrinsics::roundf64(self) }
}
- /// Returns the integer part of a number.
+ /// Returns the integer part of `self`.
+ /// This means that non-integer numbers are always truncated towards zero.
///
/// # Examples
///
unsafe { intrinsics::truncf64(self) }
}
- /// Returns the fractional part of a number.
+ /// Returns the fractional part of `self`.
///
/// # Examples
///
self - self.trunc()
}
- /// Computes the absolute value of `self`. Returns `NAN` if the
- /// number is `NAN`.
+ /// Computes the absolute value of `self`.
///
/// # Examples
///
///
/// - `1.0` if the number is positive, `+0.0` or `INFINITY`
/// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
- /// - `NAN` if the number is `NAN`
+ /// - NaN if the number is NaN
///
/// # Examples
///
/// `sign`.
///
/// Equal to `self` if the sign of `self` and `sign` are the same, otherwise
- /// equal to `-self`. If `self` is a `NAN`, then a `NAN` with the sign of
- /// `sign` is returned.
+ /// equal to `-self`. If `self` is a NaN, then a NaN with the sign bit of
+ /// `sign` is returned. Note, however, that conserving the sign bit on NaN
+ /// across arithmetical operations is not generally guaranteed.
+ /// See [explanation of NaN as a special value](primitive@f32) for more info.
///
/// # Examples
///
/// Raises a number to an integer power.
///
- /// Using this function is generally faster than using `powf`
+ /// Using this function is generally faster than using `powf`.
+ /// It might have a different sequence of rounding operations than `powf`,
+ /// so the results are not guaranteed to agree.
///
/// # Examples
///
#[must_use = "method returns a new number and does not mutate the original value"]
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- #[rustc_deprecated(
+ #[deprecated(
since = "1.10.0",
- reason = "you probably meant `(self - other).abs()`: \
- this operation is `(self - other).max(0.0)` \
- except that `abs_sub` also propagates NaNs (also \
- known as `fdim` in C). If you truly need the positive \
- difference, consider using that expression or the C function \
- `fdim`, depending on how you wish to handle NaN (please consider \
- filing an issue describing your use-case too)."
+ note = "you probably meant `(self - other).abs()`: \
+ this operation is `(self - other).max(0.0)` \
+ except that `abs_sub` also propagates NaNs (also \
+ known as `fdim` in C). If you truly need the positive \
+ difference, consider using that expression or the C function \
+ `fdim`, depending on how you wish to handle NaN (please consider \
+ filing an issue describing your use-case too)."
)]
pub fn abs_sub(self, other: f64) -> f64 {
unsafe { cmath::fdim(self, other) }
use crate::collections::TryReserveError;
use crate::fmt;
use crate::hash::{Hash, Hasher};
-use crate::iter::{Extend, FromIterator};
+use crate::iter::Extend;
use crate::ops;
use crate::rc::Rc;
use crate::str::FromStr;
}
}
-#[unstable(feature = "slice_concat_ext", issue = "27747")]
-impl<S: Borrow<OsStr>> alloc::slice::Join<&OsStr> for [S] {
- type Output = OsString;
-
- fn join(slice: &Self, sep: &OsStr) -> OsString {
- let Some(first) = slice.first() else {
- return OsString::new();
- };
- let first = first.borrow().to_owned();
- slice[1..].iter().fold(first, |mut a, b| {
- a.push(sep);
- a.push(b.borrow());
- a
- })
- }
-}
-
#[stable(feature = "rust1", since = "1.0.0")]
impl Borrow<OsStr> for OsString {
#[inline]
assert!(os_string.capacity() >= 33)
}
-#[test]
-fn test_os_string_join() {
- let strings = [OsStr::new("hello"), OsStr::new("dear"), OsStr::new("world")];
- assert_eq!("hello", strings[..1].join(OsStr::new(" ")));
- assert_eq!("hello dear world", strings.join(OsStr::new(" ")));
- assert_eq!("hellodearworld", strings.join(OsStr::new("")));
- assert_eq!("hello.\n dear.\n world", strings.join(OsStr::new(".\n ")));
-
- assert_eq!("dear world", strings[1..].join(&OsString::from(" ")));
-
- let strings_abc = [OsString::from("a"), OsString::from("b"), OsString::from("c")];
- assert_eq!("a b c", strings_abc.join(OsStr::new(" ")));
-}
-
#[test]
fn test_os_string_default() {
let os_string: OsString = Default::default();
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
+#[deprecated(
since = "1.1.0",
- reason = "replaced with std::os::unix::fs::symlink and \
- std::os::windows::fs::{symlink_file, symlink_dir}"
+ note = "replaced with std::os::unix::fs::symlink and \
+ std::os::windows::fs::{symlink_file, symlink_dir}"
)]
pub fn soft_link<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
fs_imp::symlink(original.as_ref(), link.as_ref())
/// Ok(())
/// }
/// ```
+#[doc(alias = "realpath")]
+#[doc(alias = "GetFinalPathNameByHandle")]
#[stable(feature = "fs_canonicalize", since = "1.5.0")]
pub fn canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
fs_imp::canonicalize(path.as_ref())
use crate::cmp;
use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, ReadBuf, SeekFrom};
-use core::convert::TryInto;
-
/// A `Cursor` wraps an in-memory buffer and provides it with a
/// [`Seek`] implementation.
///
mod tests;
use crate::cmp;
-use crate::convert::TryInto;
use crate::fmt;
use crate::mem::replace;
use crate::ops::{Deref, DerefMut};
#![feature(intra_doc_pointers)]
#![feature(lang_items)]
#![feature(let_chains)]
-#![feature(let_else)]
#![feature(linkage)]
#![feature(min_specialization)]
#![feature(must_not_suspend)]
#![feature(toowned_clone_into)]
#![feature(try_reserve_kind)]
#![feature(vec_into_raw_parts)]
-#![feature(slice_concat_trait)]
//
// Library features (unwind):
#![feature(panic_unwind)]
// to import the prelude implicitly when building crates that depend on std.
#[prelude_import]
#[allow(unused)]
-use prelude::v1::*;
+use prelude::rust_2021::*;
// Access to Bencher, etc.
#[cfg(test)]
mod tests;
use crate::cmp::Ordering;
-use crate::convert::TryInto;
use crate::fmt;
use crate::hash;
use crate::io::{self, Write};
#[cfg(test)]
mod tests;
-use crate::convert::TryInto as _;
use crate::error::Error;
use crate::fmt;
use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
}
#[stable(feature = "net2_mutators", since = "1.9.0")]
- #[rustc_deprecated(
- since = "1.16.0",
- reason = "this option can only be set before the socket is bound"
- )]
+ #[deprecated(since = "1.16.0", note = "this option can only be set before the socket is bound")]
#[allow(missing_docs)]
pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
self.0.set_only_v6(only_v6)
}
#[stable(feature = "net2_mutators", since = "1.9.0")]
- #[rustc_deprecated(
- since = "1.16.0",
- reason = "this option can only be set before the socket is bound"
- )]
+ #[deprecated(since = "1.16.0", note = "this option can only be set before the socket is bound")]
#[allow(missing_docs)]
pub fn only_v6(&self) -> io::Result<bool> {
self.0.only_v6()
/// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
/// cross-Unix abstractions contained within the raw stat.
#[stable(feature = "metadata_ext", since = "1.1.0")]
- #[rustc_deprecated(
+ #[deprecated(
since = "1.8.0",
- reason = "deprecated in favor of the accessor \
- methods of this trait"
+ note = "deprecated in favor of the accessor \
+ methods of this trait"
)]
#[allow(deprecated)]
fn as_raw_stat(&self) -> &raw::stat;
//! Android-specific raw type definitions
#![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
+#![deprecated(
since = "1.8.0",
- reason = "these type aliases are no longer supported by \
- the standard library, the `libc` crate on \
- crates.io should be used instead for the correct \
- definitions"
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
)]
#![allow(deprecated)]
/// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
/// cross-Unix abstractions contained within the raw stat.
#[stable(feature = "metadata_ext", since = "1.1.0")]
- #[rustc_deprecated(
+ #[deprecated(
since = "1.8.0",
- reason = "deprecated in favor of the accessor \
- methods of this trait"
+ note = "deprecated in favor of the accessor \
+ methods of this trait"
)]
#[allow(deprecated)]
fn as_raw_stat(&self) -> &raw::stat;
//! Dragonfly-specific raw type definitions
#![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
+#![deprecated(
since = "1.8.0",
- reason = "these type aliases are no longer supported by \
- the standard library, the `libc` crate on \
- crates.io should be used instead for the correct \
- definitions"
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
)]
#![allow(deprecated)]
/// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
/// cross-Unix abstractions contained within the raw stat.
#[stable(feature = "metadata_ext", since = "1.1.0")]
- #[rustc_deprecated(
+ #[deprecated(
since = "1.8.0",
- reason = "deprecated in favor of the accessor \
- methods of this trait"
+ note = "deprecated in favor of the accessor \
+ methods of this trait"
)]
#[allow(deprecated)]
fn as_raw_stat(&self) -> &raw::stat;
//! except using the musl-specific stat64 structure in liblibc.
#![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
+#![deprecated(
since = "1.8.0",
- reason = "these type aliases are no longer supported by \
- the standard library, the `libc` crate on \
- crates.io should be used instead for the correct \
- definitions"
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
)]
#![allow(deprecated)]
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
#[stable(feature = "metadata_ext", since = "1.1.0")]
- #[rustc_deprecated(
+ #[deprecated(
since = "1.8.0",
- reason = "deprecated in favor of the accessor \
- methods of this trait"
+ note = "deprecated in favor of the accessor \
+ methods of this trait"
)]
#[allow(deprecated)]
fn as_raw_stat(&self) -> &raw::stat;
//! Raw type definitions for the ESP-IDF framework.
#![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
+#![deprecated(
since = "1.8.0",
- reason = "these type aliases are no longer supported by \
- the standard library, the `libc` crate on \
- crates.io should be used instead for the correct \
- definitions"
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
)]
use crate::os::raw::c_long;
/// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
/// cross-Unix abstractions contained within the raw stat.
#[stable(feature = "metadata_ext", since = "1.1.0")]
- #[rustc_deprecated(
+ #[deprecated(
since = "1.8.0",
- reason = "deprecated in favor of the accessor \
- methods of this trait"
+ note = "deprecated in favor of the accessor \
+ methods of this trait"
)]
#[allow(deprecated)]
fn as_raw_stat(&self) -> &raw::stat;
//! FreeBSD-specific raw type definitions
#![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
+#![deprecated(
since = "1.8.0",
- reason = "these type aliases are no longer supported by \
- the standard library, the `libc` crate on \
- crates.io should be used instead for the correct \
- definitions"
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
)]
#![allow(deprecated)]
//! Fuchsia-specific raw type definitions
#![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
+#![deprecated(
since = "1.8.0",
- reason = "these type aliases are no longer supported by \
- the standard library, the `libc` crate on \
- crates.io should be used instead for the correct \
- definitions"
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
)]
#![allow(deprecated)]
/// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
/// cross-Unix abstractions contained within the raw stat.
#[stable(feature = "metadata_ext", since = "1.1.0")]
- #[rustc_deprecated(
+ #[deprecated(
since = "1.8.0",
- reason = "deprecated in favor of the accessor \
- methods of this trait"
+ note = "deprecated in favor of the accessor \
+ methods of this trait"
)]
#[allow(deprecated)]
fn as_raw_stat(&self) -> &raw::stat;
//! Haiku-specific raw type definitions
#![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
+#![deprecated(
since = "1.53.0",
- reason = "these type aliases are no longer supported by \
- the standard library, the `libc` crate on \
- crates.io should be used instead for the correct \
- definitions"
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
)]
#![allow(deprecated)]
/// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
/// cross-Unix abstractions contained within the raw stat.
#[stable(feature = "metadata_ext", since = "1.1.0")]
- #[rustc_deprecated(
+ #[deprecated(
since = "1.8.0",
- reason = "deprecated in favor of the accessor methods of this trait"
+ note = "deprecated in favor of the accessor methods of this trait"
)]
#[allow(deprecated)]
fn as_raw_stat(&self) -> &raw::stat;
//! illumos-specific raw type definitions
#![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
+#![deprecated(
since = "1.8.0",
- reason = "these type aliases are no longer supported by the standard library, the `libc` \
+ note = "these type aliases are no longer supported by the standard library, the `libc` \
crate on crates.io should be used instead for the correct definitions"
)]
#![allow(deprecated)]
/// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
/// cross-Unix abstractions contained within the raw stat.
#[stable(feature = "metadata_ext", since = "1.1.0")]
- #[rustc_deprecated(
+ #[deprecated(
since = "1.8.0",
- reason = "deprecated in favor of the accessor \
- methods of this trait"
+ note = "deprecated in favor of the accessor \
+ methods of this trait"
)]
#[allow(deprecated)]
fn as_raw_stat(&self) -> &raw::stat;
//! iOS-specific raw type definitions
#![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
+#![deprecated(
since = "1.8.0",
- reason = "these type aliases are no longer supported by \
- the standard library, the `libc` crate on \
- crates.io should be used instead for the correct \
- definitions"
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
)]
#![allow(deprecated)]
/// }
/// ```
#[stable(feature = "metadata_ext", since = "1.1.0")]
- #[rustc_deprecated(since = "1.8.0", reason = "other methods of this trait are now preferred")]
+ #[deprecated(since = "1.8.0", note = "other methods of this trait are now preferred")]
#[allow(deprecated)]
fn as_raw_stat(&self) -> &raw::stat;
//! L4Re-specific raw type definitions.
#![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
+#![deprecated(
since = "1.8.0",
- reason = "these type aliases are no longer supported by \
- the standard library, the `libc` crate on \
- crates.io should be used instead for the correct \
- definitions"
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
)]
#![allow(deprecated)]
/// }
/// ```
#[stable(feature = "metadata_ext", since = "1.1.0")]
- #[rustc_deprecated(since = "1.8.0", reason = "other methods of this trait are now preferred")]
+ #[deprecated(since = "1.8.0", note = "other methods of this trait are now preferred")]
#[allow(deprecated)]
fn as_raw_stat(&self) -> &raw::stat;
self.as_inner().as_inner().st_size as u64
}
fn st_atime(&self) -> i64 {
- self.as_inner().as_inner().st_atime as i64
+ let file_attr = self.as_inner();
+ #[cfg(all(target_env = "gnu", target_pointer_width = "32"))]
+ if let Some(atime) = file_attr.stx_atime() {
+ return atime.tv_sec;
+ }
+ file_attr.as_inner().st_atime as i64
}
fn st_atime_nsec(&self) -> i64 {
self.as_inner().as_inner().st_atime_nsec as i64
}
fn st_mtime(&self) -> i64 {
- self.as_inner().as_inner().st_mtime as i64
+ let file_attr = self.as_inner();
+ #[cfg(all(target_env = "gnu", target_pointer_width = "32"))]
+ if let Some(mtime) = file_attr.stx_mtime() {
+ return mtime.tv_sec;
+ }
+ file_attr.as_inner().st_mtime as i64
}
fn st_mtime_nsec(&self) -> i64 {
self.as_inner().as_inner().st_mtime_nsec as i64
}
fn st_ctime(&self) -> i64 {
- self.as_inner().as_inner().st_ctime as i64
+ let file_attr = self.as_inner();
+ #[cfg(all(target_env = "gnu", target_pointer_width = "32"))]
+ if let Some(ctime) = file_attr.stx_ctime() {
+ return ctime.tv_sec;
+ }
+ file_attr.as_inner().st_ctime as i64
}
fn st_ctime_nsec(&self) -> i64 {
self.as_inner().as_inner().st_ctime_nsec as i64
//! Linux-specific raw type definitions.
#![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
+#![deprecated(
since = "1.8.0",
- reason = "these type aliases are no longer supported by \
- the standard library, the `libc` crate on \
- crates.io should be used instead for the correct \
- definitions"
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
)]
#![allow(deprecated)]
/// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
/// cross-Unix abstractions contained within the raw stat.
#[stable(feature = "metadata_ext", since = "1.1.0")]
- #[rustc_deprecated(
+ #[deprecated(
since = "1.8.0",
- reason = "deprecated in favor of the accessor \
- methods of this trait"
+ note = "deprecated in favor of the accessor \
+ methods of this trait"
)]
#[allow(deprecated)]
fn as_raw_stat(&self) -> &raw::stat;
//! macOS-specific raw type definitions
#![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
+#![deprecated(
since = "1.8.0",
- reason = "these type aliases are no longer supported by \
- the standard library, the `libc` crate on \
- crates.io should be used instead for the correct \
- definitions"
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
)]
#![allow(deprecated)]
/// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
/// cross-Unix abstractions contained within the raw stat.
#[stable(feature = "metadata_ext", since = "1.1.0")]
- #[rustc_deprecated(
+ #[deprecated(
since = "1.8.0",
- reason = "deprecated in favor of the accessor \
- methods of this trait"
+ note = "deprecated in favor of the accessor \
+ methods of this trait"
)]
#[allow(deprecated)]
fn as_raw_stat(&self) -> &raw::stat;
//! NetBSD-specific raw type definitions
#![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
+#![deprecated(
since = "1.8.0",
- reason = "these type aliases are no longer supported by \
- the standard library, the `libc` crate on \
- crates.io should be used instead for the correct \
- definitions"
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
)]
#![allow(deprecated)]
/// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
/// cross-Unix abstractions contained within the raw stat.
#[stable(feature = "metadata_ext", since = "1.1.0")]
- #[rustc_deprecated(
+ #[deprecated(
since = "1.8.0",
- reason = "deprecated in favor of the accessor \
- methods of this trait"
+ note = "deprecated in favor of the accessor \
+ methods of this trait"
)]
#[allow(deprecated)]
fn as_raw_stat(&self) -> &raw::stat;
//! OpenBSD-specific raw type definitions
#![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
+#![deprecated(
since = "1.8.0",
- reason = "these type aliases are no longer supported by \
- the standard library, the `libc` crate on \
- crates.io should be used instead for the correct \
- definitions"
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
)]
#![allow(deprecated)]
/// }
/// ```
#[stable(feature = "metadata_ext", since = "1.1.0")]
- #[rustc_deprecated(
+ #[deprecated(
since = "1.8.0",
- reason = "deprecated in favor of the accessor \
- methods of this trait"
+ note = "deprecated in favor of the accessor \
+ methods of this trait"
)]
#[allow(deprecated)]
fn as_raw_stat(&self) -> &raw::stat;
//! Redox-specific raw type definitions
#![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
+#![deprecated(
since = "1.8.0",
- reason = "these type aliases are no longer supported by \
- the standard library, the `libc` crate on \
- crates.io should be used instead for the correct \
- definitions"
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
)]
#![allow(deprecated)]
/// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
/// cross-Unix abstractions contained within the raw stat.
#[stable(feature = "metadata_ext", since = "1.1.0")]
- #[rustc_deprecated(
+ #[deprecated(
since = "1.8.0",
- reason = "deprecated in favor of the accessor \
- methods of this trait"
+ note = "deprecated in favor of the accessor \
+ methods of this trait"
)]
#[allow(deprecated)]
fn as_raw_stat(&self) -> &raw::stat;
//! Solaris-specific raw type definitions
#![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
+#![deprecated(
since = "1.8.0",
- reason = "these type aliases are no longer supported by \
- the standard library, the `libc` crate on \
- crates.io should be used instead for the correct \
- definitions"
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
)]
#![allow(deprecated)]
use super::{sockaddr_un, SocketAddr};
-use crate::convert::TryFrom;
use crate::io::{self, IoSlice, IoSliceMut};
use crate::marker::PhantomData;
use crate::mem::{size_of, zeroed};
target_os = "netbsd",
target_os = "openbsd",
))]
-use crate::iter::FromIterator;
#[cfg(any(
target_os = "android",
target_os = "dragonfly",
///
/// [`pre_exec`]: CommandExt::pre_exec
#[stable(feature = "process_exec", since = "1.15.0")]
- #[rustc_deprecated(since = "1.37.0", reason = "should be unsafe, use `pre_exec` instead")]
+ #[deprecated(since = "1.37.0", note = "should be unsafe, use `pre_exec` instead")]
fn before_exec<F>(&mut self, f: F) -> &mut process::Command
where
F: FnMut() -> io::Result<()> + Send + Sync + 'static,
//! Unix-specific primitives available on all unix platforms.
#![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
+#![deprecated(
since = "1.8.0",
- reason = "these type aliases are no longer supported by \
- the standard library, the `libc` crate on \
- crates.io should be used instead for the correct \
- definitions"
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
)]
#![allow(deprecated)]
#![unstable(feature = "io_safety", issue = "87074")]
use super::raw::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
-use crate::convert::TryFrom;
use crate::fmt;
use crate::fs;
use crate::io;
self
}
}
+
+#[unstable(feature = "windows_process_extensions_main_thread_handle", issue = "96723")]
+pub trait ChildExt: Sealed {
+ /// Extracts the main thread raw handle, without taking ownership
+ #[unstable(feature = "windows_process_extensions_main_thread_handle", issue = "96723")]
+ fn main_thread_handle(&self) -> BorrowedHandle<'_>;
+}
+
+#[unstable(feature = "windows_process_extensions_main_thread_handle", issue = "96723")]
+impl ChildExt for process::Child {
+ fn main_thread_handle(&self) -> BorrowedHandle<'_> {
+ self.handle.main_thread_handle()
+ }
+}
if self.has_root() {
return false;
}
- let mut iter = self.path[self.prefix_len()..].iter();
+ let mut iter = self.path[self.prefix_remaining()..].iter();
match (iter.next(), iter.next()) {
(Some(&b'.'), None) => true,
(Some(&b'.'), Some(&b)) => self.is_sep_byte(b),
/// like `1.0 / 0.0`.
/// - [NaN (not a number)](#associatedconstant.NAN): this value results from
/// calculations like `(-1.0).sqrt()`. NaN has some potentially unexpected
-/// behavior: it is unequal to any float, including itself! It is also neither
-/// smaller nor greater than any float, making it impossible to sort. Lastly,
-/// it is considered infectious as almost all calculations where one of the
-/// operands is NaN will also result in NaN.
+/// behavior:
+/// - It is unequal to any float, including itself! This is the reason `f32`
+/// doesn't implement the `Eq` trait.
+/// - It is also neither smaller nor greater than any float, making it
+/// impossible to sort by the default comparison operation, which is the
+/// reason `f32` doesn't implement the `Ord` trait.
+/// - It is also considered *infectious* as almost all calculations where one
+/// of the operands is NaN will also result in NaN. The explanations on this
+/// page only explicitly document behavior on NaN operands if this default
+/// is deviated from.
+/// - Lastly, there are multiple bit patterns that are considered NaN.
+/// Rust does not currently guarantee that the bit patterns of NaN are
+/// preserved over arithmetic operations, and they are not guaranteed to be
+/// portable or even fully deterministic! This means that there may be some
+/// surprising results upon inspecting the bit patterns,
+/// as the same calculations might produce NaNs with different bit patterns.
///
/// For more information on floating point numbers, see [Wikipedia][wikipedia].
///
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_deprecated(since = "1.6.0", reason = "replaced by `std::sync::Condvar::wait_timeout`")]
+ #[deprecated(since = "1.6.0", note = "replaced by `std::sync::Condvar::wait_timeout`")]
pub fn wait_timeout_ms<'a, T>(
&self,
guard: MutexGuard<'a, T>,
points can cause deadlocks, delays, \
and cause Futures to not implement `Send`"]
#[stable(feature = "rust1", since = "1.0.0")]
+#[clippy::has_significant_drop]
pub struct MutexGuard<'a, T: ?Sized + 'a> {
lock: &'a Mutex<T>,
poison: poison::Guard,
/// static START: Once = ONCE_INIT;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
+#[deprecated(
since = "1.38.0",
- reason = "the `new` function is now preferred",
+ note = "the `new` function is now preferred",
suggestion = "Once::new()"
)]
pub const ONCE_INIT: Once = Once::new();
points can cause deadlocks, delays, \
and cause Futures to not implement `Send`"]
#[stable(feature = "rust1", since = "1.0.0")]
+#[clippy::has_significant_drop]
pub struct RwLockReadGuard<'a, T: ?Sized + 'a> {
lock: &'a RwLock<T>,
}
points can cause deadlocks, delays, \
and cause Future's to not implement `Send`"]
#[stable(feature = "rust1", since = "1.0.0")]
+#[clippy::has_significant_drop]
pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> {
lock: &'a RwLock<T>,
poison: poison::Guard,
-use crate::convert::TryFrom;
use crate::fmt;
use crate::io::{self, ErrorKind, IoSlice, IoSliceMut};
use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
#![allow(dead_code)]
use crate::cmp::Ordering;
-use crate::convert::TryInto;
use crate::sys::hermit::abi;
use crate::sys::hermit::abi::timespec;
use crate::sys::hermit::abi::{CLOCK_MONOTONIC, CLOCK_REALTIME, NSEC_PER_SEC};
use super::abi;
use crate::{
cell::UnsafeCell,
- convert::TryFrom,
mem::MaybeUninit,
sync::atomic::{AtomicBool, AtomicUsize, Ordering},
};
};
use crate::{
cell::UnsafeCell,
- convert::TryFrom,
ffi::CStr,
hint, io,
mem::ManuallyDrop,
use super::{abi, error::expect_success};
-use crate::{convert::TryInto, mem::MaybeUninit, time::Duration};
+use crate::{mem::MaybeUninit, time::Duration};
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct Instant(abi::SYSTIM);
use crate::cmp;
-use crate::convert::TryFrom;
use crate::io::{Error as IoError, ErrorKind, IoSlice, IoSliceMut, Result as IoResult};
use crate::sys::rand::rdrand64;
use crate::time::{Duration, Instant};
-use crate::convert::TryFrom;
use crate::error;
use crate::fmt;
use crate::io::{self, IoSlice, IoSliceMut};
use super::{abi, error::expect_success};
-use crate::{convert::TryInto, mem::MaybeUninit, time::Duration};
+use crate::{mem::MaybeUninit, time::Duration};
pub use super::itron::time::Instant;
// This is needed to check if btime is supported by the filesystem.
stx_mask: u32,
stx_btime: libc::statx_timestamp,
+ // With statx, we can overcome 32-bit `time_t` too.
+ #[cfg(target_pointer_width = "32")]
+ stx_atime: libc::statx_timestamp,
+ #[cfg(target_pointer_width = "32")]
+ stx_ctime: libc::statx_timestamp,
+ #[cfg(target_pointer_width = "32")]
+ stx_mtime: libc::statx_timestamp,
+
}
- // We prefer `statx` on Linux if available, which contains file creation time.
- // Default `stat64` contains no creation time.
+ // We prefer `statx` on Linux if available, which contains file creation time,
+ // as well as 64-bit timestamps of all kinds.
+ // Default `stat64` contains no creation time and may have 32-bit `time_t`.
unsafe fn try_statx(
fd: c_int,
path: *const c_char,
let extra = StatxExtraFields {
stx_mask: buf.stx_mask,
stx_btime: buf.stx_btime,
+ // Store full times to avoid 32-bit `time_t` truncation.
+ #[cfg(target_pointer_width = "32")]
+ stx_atime: buf.stx_atime,
+ #[cfg(target_pointer_width = "32")]
+ stx_ctime: buf.stx_ctime,
+ #[cfg(target_pointer_width = "32")]
+ stx_mtime: buf.stx_mtime,
};
Some(Ok(FileAttr { stat, statx_extra_fields: Some(extra) }))
fn from_stat64(stat: stat64) -> Self {
Self { stat, statx_extra_fields: None }
}
+
+ #[cfg(target_pointer_width = "32")]
+ pub fn stx_mtime(&self) -> Option<&libc::statx_timestamp> {
+ if let Some(ext) = &self.statx_extra_fields {
+ if (ext.stx_mask & libc::STATX_MTIME) != 0 {
+ return Some(&ext.stx_mtime);
+ }
+ }
+ None
+ }
+
+ #[cfg(target_pointer_width = "32")]
+ pub fn stx_atime(&self) -> Option<&libc::statx_timestamp> {
+ if let Some(ext) = &self.statx_extra_fields {
+ if (ext.stx_mask & libc::STATX_ATIME) != 0 {
+ return Some(&ext.stx_atime);
+ }
+ }
+ None
+ }
+
+ #[cfg(target_pointer_width = "32")]
+ pub fn stx_ctime(&self) -> Option<&libc::statx_timestamp> {
+ if let Some(ext) = &self.statx_extra_fields {
+ if (ext.stx_mask & libc::STATX_CTIME) != 0 {
+ return Some(&ext.stx_ctime);
+ }
+ }
+ None
+ }
}
} else {
impl FileAttr {
#[cfg(target_os = "netbsd")]
impl FileAttr {
pub fn modified(&self) -> io::Result<SystemTime> {
- Ok(SystemTime::from(libc::timespec {
- tv_sec: self.stat.st_mtime as libc::time_t,
- tv_nsec: self.stat.st_mtimensec as libc::c_long,
- }))
+ Ok(SystemTime::new(self.stat.st_mtime as i64, self.stat.st_mtimensec as i64))
}
pub fn accessed(&self) -> io::Result<SystemTime> {
- Ok(SystemTime::from(libc::timespec {
- tv_sec: self.stat.st_atime as libc::time_t,
- tv_nsec: self.stat.st_atimensec as libc::c_long,
- }))
+ Ok(SystemTime::new(self.stat.st_atime as i64, self.stat.st_atimensec as i64))
}
pub fn created(&self) -> io::Result<SystemTime> {
- Ok(SystemTime::from(libc::timespec {
- tv_sec: self.stat.st_birthtime as libc::time_t,
- tv_nsec: self.stat.st_birthtimensec as libc::c_long,
- }))
+ Ok(SystemTime::new(self.stat.st_birthtime as i64, self.stat.st_birthtimensec as i64))
}
}
impl FileAttr {
#[cfg(all(not(target_os = "vxworks"), not(target_os = "espidf")))]
pub fn modified(&self) -> io::Result<SystemTime> {
- Ok(SystemTime::from(libc::timespec {
- tv_sec: self.stat.st_mtime as libc::time_t,
- tv_nsec: self.stat.st_mtime_nsec as _,
- }))
+ #[cfg(target_pointer_width = "32")]
+ cfg_has_statx! {
+ if let Some(mtime) = self.stx_mtime() {
+ return Ok(SystemTime::new(mtime.tv_sec, mtime.tv_nsec as i64));
+ }
+ }
+
+ Ok(SystemTime::new(self.stat.st_mtime as i64, self.stat.st_mtime_nsec as i64))
}
#[cfg(any(target_os = "vxworks", target_os = "espidf"))]
pub fn modified(&self) -> io::Result<SystemTime> {
- Ok(SystemTime::from(libc::timespec {
- tv_sec: self.stat.st_mtime as libc::time_t,
- tv_nsec: 0,
- }))
+ Ok(SystemTime::new(self.stat.st_mtime as i64, 0))
}
#[cfg(all(not(target_os = "vxworks"), not(target_os = "espidf")))]
pub fn accessed(&self) -> io::Result<SystemTime> {
- Ok(SystemTime::from(libc::timespec {
- tv_sec: self.stat.st_atime as libc::time_t,
- tv_nsec: self.stat.st_atime_nsec as _,
- }))
+ #[cfg(target_pointer_width = "32")]
+ cfg_has_statx! {
+ if let Some(atime) = self.stx_atime() {
+ return Ok(SystemTime::new(atime.tv_sec, atime.tv_nsec as i64));
+ }
+ }
+
+ Ok(SystemTime::new(self.stat.st_atime as i64, self.stat.st_atime_nsec as i64))
}
#[cfg(any(target_os = "vxworks", target_os = "espidf"))]
pub fn accessed(&self) -> io::Result<SystemTime> {
- Ok(SystemTime::from(libc::timespec {
- tv_sec: self.stat.st_atime as libc::time_t,
- tv_nsec: 0,
- }))
+ Ok(SystemTime::new(self.stat.st_atime as i64, 0))
}
#[cfg(any(
target_os = "ios"
))]
pub fn created(&self) -> io::Result<SystemTime> {
- Ok(SystemTime::from(libc::timespec {
- tv_sec: self.stat.st_birthtime as libc::time_t,
- tv_nsec: self.stat.st_birthtime_nsec as libc::c_long,
- }))
+ Ok(SystemTime::new(self.stat.st_birthtime as i64, self.stat.st_birthtime_nsec as i64))
}
#[cfg(not(any(
cfg_has_statx! {
if let Some(ext) = &self.statx_extra_fields {
return if (ext.stx_mask & libc::STATX_BTIME) != 0 {
- Ok(SystemTime::from(libc::timespec {
- tv_sec: ext.stx_btime.tv_sec as libc::time_t,
- tv_nsec: ext.stx_btime.tv_nsec as _,
- }))
+ Ok(SystemTime::new(ext.stx_btime.tv_sec, ext.stx_btime.tv_nsec as i64))
} else {
Err(io::const_io_error!(
io::ErrorKind::Uncategorized,
}
pub fn truncate(&self, size: u64) -> io::Result<()> {
- use crate::convert::TryInto;
let size: off64_t =
size.try_into().map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
cvt_r(|| unsafe { ftruncate64(self.as_raw_fd(), size) }).map(drop)
// Calculate the timeout as an absolute timespec.
//
// Overflows are rounded up to an infinite timeout (None).
- let timespec =
- timeout.and_then(|d| Some(Timespec::now(libc::CLOCK_MONOTONIC).checked_add_duration(&d)?));
+ let timespec = timeout
+ .and_then(|d| Some(Timespec::now(libc::CLOCK_MONOTONIC).checked_add_duration(&d)?))
+ .and_then(|t| t.to_timespec());
loop {
// No need to wait if the value already changed.
// identical. It supports absolute timeouts through a flag
// in the _umtx_time struct.
let umtx_timeout = timespec.map(|t| libc::_umtx_time {
- _timeout: t.t,
+ _timeout: t,
_flags: libc::UMTX_ABSTIME,
_clockid: libc::CLOCK_MONOTONIC as u32,
});
futex as *const AtomicU32,
libc::FUTEX_WAIT_BITSET | libc::FUTEX_PRIVATE_FLAG,
expected,
- timespec.as_ref().map_or(null(), |t| &t.t as *const libc::timespec),
+ timespec.as_ref().map_or(null(), |t| t as *const libc::timespec),
null::<u32>(), // This argument is unused for FUTEX_WAIT_BITSET.
!0u32, // A full bitmask, to make it behave like a regular FUTEX_WAIT.
)
#[cfg(target_os = "openbsd")]
pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool {
- use crate::convert::TryInto;
use crate::ptr::{null, null_mut};
let timespec = timeout.and_then(|d| {
Some(libc::timespec {
#[cfg(target_os = "dragonfly")]
pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool {
- use crate::convert::TryFrom;
-
// A timeout of 0 means infinite.
// We round smaller timeouts up to 1 millisecond.
// Overflows are rounded up to an infinite timeout.
//! * complexity
use crate::cmp::min;
-use crate::convert::TryInto;
use crate::fs::{File, Metadata};
use crate::io::copy::generic_copy;
use crate::io::{
pub mod net {
#![allow(warnings)]
- use crate::convert::TryFrom;
use crate::fmt;
use crate::io::{self, IoSlice, IoSliceMut};
use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
-use crate::convert::{TryFrom, TryInto};
use crate::fmt;
use crate::io;
use crate::mem;
-use crate::convert::{TryFrom, TryInto};
use crate::fmt;
use crate::io::{self, Error, ErrorKind};
use crate::mem;
-use crate::convert::{TryFrom, TryInto};
use crate::fmt;
use crate::io;
use crate::io::ErrorKind;
-use crate::convert::{TryFrom, TryInto};
use crate::fmt;
use crate::io::{self, Error, ErrorKind};
use crate::num::NonZeroI32;
#![allow(non_camel_case_types, unused)]
-use crate::convert::TryInto;
use crate::io;
use crate::mem::MaybeUninit;
use crate::os::raw::c_char;
(Timespec::now(libc::CLOCK_MONOTONIC), dur)
};
- let timeout = now.checked_add_duration(&dur).map(|t| t.t).unwrap_or(TIMESPEC_MAX);
+ let timeout =
+ now.checked_add_duration(&dur).and_then(|t| t.to_timespec()).unwrap_or(TIMESPEC_MAX);
let r = libc::pthread_cond_timedwait(cond, lock, &timeout);
debug_assert!(r == libc::ETIMEDOUT || r == 0);
}
-use crate::cmp::Ordering;
+use crate::fmt;
use crate::time::Duration;
-use core::hash::{Hash, Hasher};
-
-pub use self::inner::{Instant, SystemTime, UNIX_EPOCH};
-use crate::convert::TryInto;
+pub use self::inner::Instant;
const NSEC_PER_SEC: u64 = 1_000_000_000;
+pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct SystemTime {
+ pub(in crate::sys::unix) t: Timespec,
+}
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(in crate::sys::unix) struct Timespec {
- pub t: libc::timespec,
+ tv_sec: i64,
+ tv_nsec: i64,
+}
+
+impl SystemTime {
+ pub fn new(tv_sec: i64, tv_nsec: i64) -> SystemTime {
+ SystemTime { t: Timespec::new(tv_sec, tv_nsec) }
+ }
+
+ pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
+ self.t.sub_timespec(&other.t)
+ }
+
+ pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+ Some(SystemTime { t: self.t.checked_add_duration(other)? })
+ }
+
+ pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+ Some(SystemTime { t: self.t.checked_sub_duration(other)? })
+ }
+}
+
+impl From<libc::timespec> for SystemTime {
+ fn from(t: libc::timespec) -> SystemTime {
+ SystemTime { t: Timespec::from(t) }
+ }
+}
+
+impl fmt::Debug for SystemTime {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("SystemTime")
+ .field("tv_sec", &self.t.tv_sec)
+ .field("tv_nsec", &self.t.tv_nsec)
+ .finish()
+ }
}
impl Timespec {
const fn zero() -> Timespec {
- Timespec { t: libc::timespec { tv_sec: 0, tv_nsec: 0 } }
+ Timespec { tv_sec: 0, tv_nsec: 0 }
+ }
+
+ fn new(tv_sec: i64, tv_nsec: i64) -> Timespec {
+ Timespec { tv_sec, tv_nsec }
}
pub fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
// NOTE(eddyb) two aspects of this `if`-`else` are required for LLVM
// to optimize it into a branchless form (see also #75545):
//
- // 1. `self.t.tv_sec - other.t.tv_sec` shows up as a common expression
+ // 1. `self.tv_sec - other.tv_sec` shows up as a common expression
// in both branches, i.e. the `else` must have its `- 1`
// subtraction after the common one, not interleaved with it
- // (it used to be `self.t.tv_sec - 1 - other.t.tv_sec`)
+ // (it used to be `self.tv_sec - 1 - other.tv_sec`)
//
// 2. the `Duration::new` call (or any other additional complexity)
// is outside of the `if`-`else`, not duplicated in both branches
//
// Ideally this code could be rearranged such that it more
// directly expresses the lower-cost behavior we want from it.
- let (secs, nsec) = if self.t.tv_nsec >= other.t.tv_nsec {
- ((self.t.tv_sec - other.t.tv_sec) as u64, (self.t.tv_nsec - other.t.tv_nsec) as u32)
+ let (secs, nsec) = if self.tv_nsec >= other.tv_nsec {
+ ((self.tv_sec - other.tv_sec) as u64, (self.tv_nsec - other.tv_nsec) as u32)
} else {
(
- (self.t.tv_sec - other.t.tv_sec - 1) as u64,
- self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) - other.t.tv_nsec as u32,
+ (self.tv_sec - other.tv_sec - 1) as u64,
+ self.tv_nsec as u32 + (NSEC_PER_SEC as u32) - other.tv_nsec as u32,
)
};
pub fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
let mut secs = other
.as_secs()
- .try_into() // <- target type would be `libc::time_t`
+ .try_into() // <- target type would be `i64`
.ok()
- .and_then(|secs| self.t.tv_sec.checked_add(secs))?;
+ .and_then(|secs| self.tv_sec.checked_add(secs))?;
// Nano calculations can't overflow because nanos are <1B which fit
// in a u32.
- let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32;
+ let mut nsec = other.subsec_nanos() + self.tv_nsec as u32;
if nsec >= NSEC_PER_SEC as u32 {
nsec -= NSEC_PER_SEC as u32;
secs = secs.checked_add(1)?;
}
- Some(Timespec { t: libc::timespec { tv_sec: secs, tv_nsec: nsec as _ } })
+ Some(Timespec::new(secs, nsec as i64))
}
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
let mut secs = other
.as_secs()
- .try_into() // <- target type would be `libc::time_t`
+ .try_into() // <- target type would be `i64`
.ok()
- .and_then(|secs| self.t.tv_sec.checked_sub(secs))?;
+ .and_then(|secs| self.tv_sec.checked_sub(secs))?;
// Similar to above, nanos can't overflow.
- let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32;
+ let mut nsec = self.tv_nsec as i32 - other.subsec_nanos() as i32;
if nsec < 0 {
nsec += NSEC_PER_SEC as i32;
secs = secs.checked_sub(1)?;
}
- Some(Timespec { t: libc::timespec { tv_sec: secs, tv_nsec: nsec as _ } })
- }
-}
-
-impl PartialEq for Timespec {
- fn eq(&self, other: &Timespec) -> bool {
- self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec
- }
-}
-
-impl Eq for Timespec {}
-
-impl PartialOrd for Timespec {
- fn partial_cmp(&self, other: &Timespec) -> Option<Ordering> {
- Some(self.cmp(other))
+ Some(Timespec::new(secs, nsec as i64))
}
-}
-impl Ord for Timespec {
- fn cmp(&self, other: &Timespec) -> Ordering {
- let me = (self.t.tv_sec, self.t.tv_nsec);
- let other = (other.t.tv_sec, other.t.tv_nsec);
- me.cmp(&other)
+ pub fn to_timespec(&self) -> Option<libc::timespec> {
+ Some(libc::timespec {
+ tv_sec: self.tv_sec.try_into().ok()?,
+ tv_nsec: self.tv_nsec.try_into().ok()?,
+ })
}
}
-impl Hash for Timespec {
- fn hash<H: Hasher>(&self, state: &mut H) {
- self.t.tv_sec.hash(state);
- self.t.tv_nsec.hash(state);
+impl From<libc::timespec> for Timespec {
+ fn from(t: libc::timespec) -> Timespec {
+ Timespec::new(t.tv_sec as i64, t.tv_nsec as i64)
}
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
mod inner {
- use crate::fmt;
use crate::sync::atomic::{AtomicU64, Ordering};
use crate::sys::cvt;
use crate::sys_common::mul_div_u64;
use crate::time::Duration;
- use super::Timespec;
- use super::NSEC_PER_SEC;
+ use super::{SystemTime, Timespec, NSEC_PER_SEC};
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct Instant {
t: u64,
}
- #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
- pub struct SystemTime {
- pub(in crate::sys::unix) t: Timespec,
- }
-
- pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };
-
#[repr(C)]
#[derive(Copy, Clone)]
struct mach_timebase_info {
cvt(unsafe { libc::gettimeofday(&mut s, ptr::null_mut()) }).unwrap();
return SystemTime::from(s);
}
+ }
- pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
- self.t.sub_timespec(&other.t)
- }
-
- pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
- Some(SystemTime { t: self.t.checked_add_duration(other)? })
- }
-
- pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
- Some(SystemTime { t: self.t.checked_sub_duration(other)? })
+ impl From<libc::timeval> for Timespec {
+ fn from(t: libc::timeval) -> Timespec {
+ Timespec::new(t.tv_sec as i64, 1000 * t.tv_usec as i64)
}
}
impl From<libc::timeval> for SystemTime {
fn from(t: libc::timeval) -> SystemTime {
- SystemTime::from(libc::timespec {
- tv_sec: t.tv_sec,
- tv_nsec: (t.tv_usec * 1000) as libc::c_long,
- })
- }
- }
-
- impl From<libc::timespec> for SystemTime {
- fn from(t: libc::timespec) -> SystemTime {
- SystemTime { t: Timespec { t } }
- }
- }
-
- impl fmt::Debug for SystemTime {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("SystemTime")
- .field("tv_sec", &self.t.t.tv_sec)
- .field("tv_nsec", &self.t.t.tv_nsec)
- .finish()
+ SystemTime { t: Timespec::from(t) }
}
}
use crate::sys::cvt;
use crate::time::Duration;
- use super::Timespec;
+ use super::{SystemTime, Timespec};
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Instant {
t: Timespec,
}
- #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
- pub struct SystemTime {
- pub(in crate::sys::unix) t: Timespec,
- }
-
- pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };
-
impl Instant {
pub fn now() -> Instant {
Instant { t: Timespec::now(libc::CLOCK_MONOTONIC) }
impl fmt::Debug for Instant {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Instant")
- .field("tv_sec", &self.t.t.tv_sec)
- .field("tv_nsec", &self.t.t.tv_nsec)
+ .field("tv_sec", &self.t.tv_sec)
+ .field("tv_nsec", &self.t.tv_nsec)
.finish()
}
}
pub fn now() -> SystemTime {
SystemTime { t: Timespec::now(libc::CLOCK_REALTIME) }
}
-
- pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
- self.t.sub_timespec(&other.t)
- }
-
- pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
- Some(SystemTime { t: self.t.checked_add_duration(other)? })
- }
-
- pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
- Some(SystemTime { t: self.t.checked_sub_duration(other)? })
- }
- }
-
- impl From<libc::timespec> for SystemTime {
- fn from(t: libc::timespec) -> SystemTime {
- SystemTime { t: Timespec { t } }
- }
- }
-
- impl fmt::Debug for SystemTime {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("SystemTime")
- .field("tv_sec", &self.t.t.tv_sec)
- .field("tv_nsec", &self.t.t.tv_nsec)
- .finish()
- }
}
#[cfg(not(any(target_os = "dragonfly", target_os = "espidf")))]
impl Timespec {
pub fn now(clock: clock_t) -> Timespec {
+ // Try to use 64-bit time in preparation for Y2038.
+ #[cfg(all(target_os = "linux", target_env = "gnu", target_pointer_width = "32"))]
+ {
+ use crate::sys::weak::weak;
+
+ // __clock_gettime64 was added to 32-bit arches in glibc 2.34,
+ // and it handles both vDSO calls and ENOSYS fallbacks itself.
+ weak!(fn __clock_gettime64(libc::clockid_t, *mut __timespec64) -> libc::c_int);
+
+ #[repr(C)]
+ struct __timespec64 {
+ tv_sec: i64,
+ #[cfg(target_endian = "big")]
+ _padding: i32,
+ tv_nsec: i32,
+ #[cfg(target_endian = "little")]
+ _padding: i32,
+ }
+
+ if let Some(clock_gettime64) = __clock_gettime64.get() {
+ let mut t = MaybeUninit::uninit();
+ cvt(unsafe { clock_gettime64(clock, t.as_mut_ptr()) }).unwrap();
+ let t = unsafe { t.assume_init() };
+ return Timespec { tv_sec: t.tv_sec, tv_nsec: t.tv_nsec as i64 };
+ }
+ }
+
let mut t = MaybeUninit::uninit();
cvt(unsafe { libc::clock_gettime(clock, t.as_mut_ptr()) }).unwrap();
- Timespec { t: unsafe { t.assume_init() } }
+ Timespec::from(unsafe { t.assume_init() })
}
}
}
-use crate::convert::TryFrom;
use crate::fmt;
use crate::io::{self, IoSlice, IoSliceMut};
use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
use super::err2io;
use super::fd::WasiFd;
-use crate::convert::TryFrom;
use crate::fmt;
use crate::io::{self, IoSlice, IoSliceMut};
use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
use crate::arch::wasm32;
-use crate::convert::TryInto;
use crate::sync::atomic::AtomicU32;
use crate::time::Duration;
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};
}
}
+#[repr(transparent)]
pub struct Slice {
pub inner: Wtf8,
}
assert_eq!(prefix, parse_prefix(r"/\?\C:\windows\system32\notepad.exe"));
assert_eq!(prefix, parse_prefix(r"\\?/C:\windows\system32\notepad.exe"));
}
+
+// See #93586 for more infomation.
+#[test]
+fn test_windows_prefix_components() {
+ use crate::path::Path;
+
+ let path = Path::new("C:");
+ let mut components = path.components();
+ let drive = components.next().expect("drive is expected here");
+ assert_eq!(drive.as_os_str(), OsStr::new("C:"));
+ assert_eq!(components.as_path(), Path::new(""));
+}
use crate::cmp;
use crate::collections::BTreeMap;
-use crate::convert::{TryFrom, TryInto};
use crate::env;
use crate::env::consts::{EXE_EXTENSION, EXE_SUFFIX};
use crate::ffi::{OsStr, OsString};
use crate::mem;
use crate::num::NonZeroI32;
use crate::os::windows::ffi::{OsStrExt, OsStringExt};
-use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle};
+use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle};
use crate::path::{Path, PathBuf};
use crate::ptr;
use crate::sys::args::{self, Arg};
))
}?;
- // We close the thread handle because we don't care about keeping
- // the thread id valid, and we aren't keeping the thread handle
- // around to be able to close it later.
unsafe {
- drop(Handle::from_raw_handle(pi.hThread));
-
- Ok((Process { handle: Handle::from_raw_handle(pi.hProcess) }, pipes))
+ Ok((
+ Process {
+ handle: Handle::from_raw_handle(pi.hProcess),
+ main_thread_handle: Handle::from_raw_handle(pi.hThread),
+ },
+ pipes,
+ ))
}
}
}
/// for the process to terminate.
pub struct Process {
handle: Handle,
+ main_thread_handle: Handle,
}
impl Process {
unsafe { c::GetProcessId(self.handle.as_raw_handle()) as u32 }
}
+ pub fn main_thread_handle(&self) -> BorrowedHandle<'_> {
+ self.main_thread_handle.as_handle()
+ }
+
pub fn wait(&mut self) -> io::Result<ExitStatus> {
unsafe {
let res = c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE);
);
}
+#[test]
+fn test_thread_handle() {
+ use crate::os::windows::io::BorrowedHandle;
+ use crate::os::windows::process::{ChildExt, CommandExt};
+ const CREATE_SUSPENDED: u32 = 0x00000004;
+
+ let p = Command::new("cmd").args(&["/C", "exit 0"]).creation_flags(CREATE_SUSPENDED).spawn();
+ assert!(p.is_ok());
+ let mut p = p.unwrap();
+
+ extern "system" {
+ fn ResumeThread(_: BorrowedHandle<'_>) -> u32;
+ }
+ unsafe {
+ ResumeThread(p.main_thread_handle());
+ }
+
+ crate::thread::sleep(crate::time::Duration::from_millis(100));
+
+ let res = p.try_wait();
+ assert!(res.is_ok());
+ assert!(res.unwrap().is_some());
+ assert!(p.try_wait().unwrap().unwrap().success());
+}
+
#[test]
fn test_make_command_line() {
fn test_wrapper(prog: &str, args: &[&str], force_quotes: bool) -> String {
-use crate::convert::TryInto;
use crate::ffi::CStr;
use crate::io;
use crate::num::NonZeroUsize;
// [3]: https://docs.microsoft.com/en-us/archive/msdn-magazine/2012/november/windows-with-c-the-evolution-of-synchronization-in-windows-and-c
// [4]: Windows Internals, Part 1, ISBN 9780735671300
-use crate::convert::TryFrom;
use crate::pin::Pin;
use crate::ptr;
use crate::sync::atomic::{
use crate::cmp::Ordering;
-use crate::convert::TryInto;
use crate::fmt;
use crate::mem;
use crate::sys::c;
mod tests;
use crate::cmp;
-use crate::convert::{TryFrom, TryInto};
use crate::ffi::CString;
use crate::fmt;
use crate::io::{self, ErrorKind, IoSlice, IoSliceMut};
use crate::collections::TryReserveError;
use crate::fmt;
use crate::hash::{Hash, Hasher};
-use crate::iter::{FromIterator, FusedIterator};
+use crate::iter::FusedIterator;
use crate::mem;
use crate::ops;
use crate::rc::Rc;
/// thread::sleep_ms(2000);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "1.6.0", reason = "replaced by `std::thread::sleep`")]
+#[deprecated(since = "1.6.0", note = "replaced by `std::thread::sleep`")]
pub fn sleep_ms(ms: u32) {
sleep(Duration::from_millis(ms as u64))
}
///
/// See the [park documentation][`park`] for more detail.
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "1.6.0", reason = "replaced by `std::thread::park_timeout`")]
+#[deprecated(since = "1.6.0", note = "replaced by `std::thread::park_timeout`")]
pub fn park_timeout_ms(ms: u32) {
park_timeout(Duration::from_millis(ms as u64))
}
"library/backtrace",
"library/stdarch"
]
+ # If build.vendor is set in config.toml, we must update rust-analyzer also.
+ # Otherwise, the bootstrap will fail (#96456).
+ if self.use_vendored_sources:
+ submodules.append("src/tools/rust-analyzer")
filtered_submodules = []
submodules_names = []
for module in submodules:
native::Lld,
native::CrtBeginEnd
),
- Kind::Check => describe!(
+ Kind::Check | Kind::Clippy | Kind::Fix => describe!(
check::Std,
check::Rustc,
check::Rustdoc,
),
Kind::Run => describe!(run::ExpandYamlAnchors, run::BuildManifest, run::BumpStage0),
// These commands either don't use paths, or they're special-cased in Build::build()
- Kind::Clean | Kind::Clippy | Kind::Fix | Kind::Format | Kind::Setup => vec![],
+ Kind::Clean | Kind::Format | Kind::Setup => vec![],
}
}
rustflags.arg("-Zunstable-options");
}
- // #[cfg(not(bootstrap)]
+ // FIXME(Urgau): This a hack as it shouldn't be gated on stage 0 but until `rustc_llvm`
+ // is made to work with `--check-cfg` which is currently not easly possible until cargo
+ // get some support for setting `--check-cfg` within build script, it's the least invasive
+ // hack that still let's us have cfg checking for the vast majority of the codebase.
if stage != 0 {
- // Enable cfg checking of cargo features
- // FIXME: De-comment this when cargo beta get support for it
- // cargo.arg("-Zcheck-cfg-features");
+ // Enable cfg checking of cargo features for everything but std.
+ //
+ // Note: `std`, `alloc` and `core` imports some dependencies by #[path] (like
+ // backtrace, core_simd, std_float, ...), those dependencies have their own features
+ // but cargo isn't involved in the #[path] and so cannot pass the complete list of
+ // features, so for that reason we don't enable checking of features for std.
+ if mode != Mode::Std {
+ cargo.arg("-Zcheck-cfg-features");
+ }
- // Enable cfg checking of rustc well-known names
+ // Enable cfg checking of well known names/values
rustflags
.arg("-Zunstable-options")
// Enable checking of well known names
# These defaults are meant for contributors to the compiler who modify codegen or LLVM
+[build]
+# Contributors working on the compiler will probably expect compiler docs to be generated.
+compiler-docs = true
+
[llvm]
# This enables debug-assertions in LLVM,
# catching logic errors in codegen much earlier in the process.
# These defaults are meant for contributors to the compiler who do not modify codegen or LLVM
+[build]
+# Contributors working on the compiler will probably expect compiler docs to be generated.
+compiler-docs = true
+
[rust]
# This enables `RUSTC_LOG=debug`, avoiding confusing situations
# where adding `debug!()` appears to do nothing.
[build]
# Document with the in-tree rustdoc by default, since `download-rustc` makes it quick to compile.
doc-stage = 2
+# Contributors working on tools will probably expect compiler docs to be generated, so they can figure out how to use the API.
+compiler-docs = true
[llvm]
# Will download LLVM from CI if available on your platform.
/// This avoids contributors checking in a submodule change by accident.
pub fn maybe_update_submodules(&self) {
// WARNING: keep this in sync with the submodules hard-coded in bootstrap.py
- const BOOTSTRAP_SUBMODULES: &[&str] = &[
+ let mut bootstrap_submodules: Vec<&str> = vec![
"src/tools/rust-installer",
"src/tools/cargo",
"src/tools/rls",
"library/backtrace",
"library/stdarch",
];
+ // As in bootstrap.py, we include `rust-analyzer` if `build.vendor` was set in
+ // `config.toml`.
+ if self.config.vendor {
+ bootstrap_submodules.push("src/tools/rust-analyzer");
+ }
// Avoid running git when there isn't a git checkout.
if !self.config.submodules(&self.rust_info) {
return;
// Sample output: `submodule.src/rust-installer.path src/tools/rust-installer`
let submodule = Path::new(line.splitn(2, ' ').nth(1).unwrap());
// avoid updating submodules twice
- if !BOOTSTRAP_SUBMODULES.iter().any(|&p| Path::new(p) == submodule)
+ if !bootstrap_submodules.iter().any(|&p| Path::new(p) == submodule)
&& channel::GitInfo::new(false, submodule).is_git()
{
self.update_submodule(submodule);
let dst = dstdir.join(src.file_name().unwrap());
self.verbose_than(1, &format!("Install {:?} to {:?}", src, dst));
t!(fs::create_dir_all(dstdir));
- drop(fs::remove_file(&dst));
{
if !src.exists() {
panic!("Error: File \"{}\" not found!", src.display());
}
- let metadata = t!(src.symlink_metadata());
- if let Err(e) = fs::copy(&src, &dst) {
- panic!("failed to copy `{}` to `{}`: {}", src.display(), dst.display(), e)
- }
- t!(fs::set_permissions(&dst, metadata.permissions()));
- let atime = FileTime::from_last_access_time(&metadata);
- let mtime = FileTime::from_last_modification_time(&metadata);
- t!(filetime::set_file_times(&dst, atime, mtime));
+ self.copy(src, &dst);
}
+ // NOTE: when using hard-links, this will also update the permissions on the original file.
+ // We never use permissions that are more restrictive than the original, so this shouldn't cause any issues.
chmod(&dst, perms);
}
src/tools/cargo \
src/tools/cargotest \
$(BOOTSTRAP_ARGS)
-check-bootstrap:
- $(Q)$(CFG_PYTHON) $(CFG_SRC_DIR)src/bootstrap/bootstrap_test.py
dist:
$(Q)$(BOOTSTRAP) dist $(BOOTSTRAP_ARGS)
distcheck:
.any(|build_llvm_ourselves| build_llvm_ourselves);
let need_cmake = building_llvm || build.config.any_sanitizers_enabled();
if need_cmake {
- cmd_finder.must_have("cmake");
+ if cmd_finder.maybe_have("cmake").is_none() {
+ eprintln!(
+ "
+Couldn't find required command: cmake
+
+You should install cmake, or set `download-ci-llvm = true` in the
+`[llvm]` section section of `config.toml` to download LLVM rather
+than building it.
+"
+ );
+ std::process::exit(1);
+ }
}
build.config.python = build
&[],
);
- // clippy tests need to know about the stage sysroot
- cargo.env("SYSROOT", builder.sysroot(compiler));
cargo.env("RUSTC_TEST_SUITE", builder.rustc(compiler));
cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler));
let host_libs = builder.stage_out(compiler, Mode::ToolRustc).join(builder.cargo_dir());
/// Tests the build system itself.
fn run(self, builder: &Builder<'_>) {
+ let mut check_bootstrap = Command::new(&builder.python());
+ check_bootstrap.arg("bootstrap_test.py").current_dir(builder.src.join("src/bootstrap/"));
+ try_run(builder, &mut check_bootstrap);
+
let mut cmd = Command::new(&builder.initial_cargo);
cmd.arg("test")
.current_dir(builder.src.join("src/bootstrap"))
}
}
+ // clippy tests need to know about the stage sysroot. Set them consistently while building to
+ // avoid rebuilding when running tests.
+ cargo.env("SYSROOT", builder.sysroot(compiler));
+
// if tools are using lzma we want to force the build script to build its
// own copy
cargo.env("LZMA_API_STATIC", "1");
retry make prepare
-make check-bootstrap
-
# Display the CPU and memory information. This helps us know why the CI timing
# is fluctuating.
if isMacOS; then
- `symbols` - same as `debuginfo`, but the rest of the symbol table section is
stripped as well if the linker supports it.
+## symbol-mangling-version
+
+This option controls the [name mangling] format for encoding Rust item names
+for the purpose of generating object code and linking.
+
+Supported values for this option are:
+
+* `v0` — The "v0" mangling scheme. The specific format is not specified at
+ this time.
+
+The default if not specified will use a compiler-chosen default which may
+change in the future.
+
+[name mangling]: https://en.wikipedia.org/wiki/Name_mangling
+
## target-cpu
This instructs `rustc` to generate code specifically for a particular processor.
argument](#option-emit), and as soon as the artifact is available on the
filesystem a notification will be emitted.
+- `future-incompat` - includes a JSON message that contains a report if the
+ crate contains any code that may fail to compile in the future.
+
Note that it is invalid to combine the `--json` argument with the
[`--color`](#option-color) argument, and it is required to combine `--json`
with `--error-format=json`.
}
```
+## Future-incompatible reports
+
+If the [`--json=future-incompat`][option-json] flag is used, then a separate
+JSON structure will be emitted if the crate may stop compiling in the future.
+This contains diagnostic information about the particular warnings that may be
+turned into a hard error in the future. This will include the diagnostic
+information, even if the diagnostics have been suppressed (such as with an
+`#[allow]` attribute or the `--cap-lints` option).
+
+```javascript
+{
+ /* An array of objects describing a warning that will become a hard error
+ in the future.
+ */
+ "future_incompat_report":
+ [
+ {
+ /* A diagnostic structure as defined in
+ https://doc.rust-lang.org/rustc/json.html#diagnostics
+ */
+ "diagnostic": {...},
+ }
+ ]
+}
+```
+
[option-emit]: command-line-arguments.md#option-emit
[option-error-format]: command-line-arguments.md#option-error-format
[option-json]: command-line-arguments.md#option-json
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_hir::PredicateOrigin;
use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
use rustc_middle::middle::resolve_lifetime as rl;
use rustc_middle::ty::fold::TypeFolder;
let bounds = if let Some(generics) = generics {
generics
.bounds_for_param(did)
- .filter(|bp| !bp.in_where_clause)
+ .filter(|bp| bp.origin != PredicateOrigin::WhereClause)
.flat_map(|bp| bp.bounds)
.filter_map(|x| x.clean(cx))
.collect()
rustc_lint::builtin::RENAMED_AND_REMOVED_LINTS.name.to_string(),
rustc_lint::builtin::UNKNOWN_LINTS.name.to_string(),
rustc_lint::builtin::UNEXPECTED_CFGS.name.to_string(),
+ // this lint is needed to support `#[expect]` attributes
+ rustc_lint::builtin::UNFULFILLED_LINT_EXPECTATIONS.name.to_string(),
];
lints_to_show.extend(crate::lint::RUSTDOC_LINTS.iter().map(|lint| lint.name.to_string()));
}
}
+ tcx.sess.time("check_lint_expectations", || tcx.check_expectations(Some(sym::rustdoc)));
+
if tcx.sess.diagnostic().has_errors_or_lint_errors().is_some() {
rustc_errors::FatalError.raise();
}
if let Some(depr @ Deprecation { note, since, is_since_rustc_version: _, suggestion: _ }) =
item.deprecation(cx.tcx())
{
- // We display deprecation messages for #[deprecated] and #[rustc_deprecated]
- // but only display the future-deprecation messages for #[rustc_deprecated].
+ // We display deprecation messages for #[deprecated], but only display
+ // the future-deprecation messages for rustc versions.
let mut message = if let Some(since) = since {
let since = since.as_str();
if !stability::deprecation_in_effect(&depr) {
"error",
"always"
],
+ "quotes": [
+ "error",
+ "double"
+ ],
+ "linebreak-style": [
+ "error",
+ "unix"
+ ],
+ "no-trailing-spaces": "error",
"no-var": ["error"],
"prefer-const": ["error"],
"prefer-arrow-callback": ["error"],
(function() {
function loadScript(url) {
- const script = document.createElement('script');
+ const script = document.createElement("script");
script.src = url;
document.head.append(script);
}
searchState.input.blur();
},
showResults: search => {
- if (search === null || typeof search === 'undefined') {
+ if (search === null || typeof search === "undefined") {
search = searchState.outputElement();
}
switchDisplayedElement(search);
loadSearch();
});
- if (search_input.value !== '') {
+ if (search_input.value !== "") {
loadSearch();
}
onEachLazy(document.getElementsByClassName("notable-traits"), e => {
e.onclick = function() {
- this.getElementsByClassName('notable-traits-tooltiptext')[0]
+ this.getElementsByClassName("notable-traits-tooltiptext")[0]
.classList.toggle("force-tooltip");
};
});
const path = [];
onEach(parent.childNodes, child => {
- if (child.tagName === 'A') {
+ if (child.tagName === "A") {
path.push(child.textContent);
}
});
- const el = document.createElement('textarea');
- el.value = path.join('::');
- el.setAttribute('readonly', '');
+ const el = document.createElement("textarea");
+ el.value = path.join("::");
+ el.setAttribute("readonly", "");
// To not make it appear on the screen.
- el.style.position = 'absolute';
- el.style.left = '-9999px';
+ el.style.position = "absolute";
+ el.style.left = "-9999px";
document.body.appendChild(el);
el.select();
- document.execCommand('copy');
+ document.execCommand("copy");
document.body.removeChild(el);
// There is always one children, but multiple childNodes.
- but.children[0].style.display = 'none';
+ but.children[0].style.display = "none";
let tmp;
if (but.childNodes.length < 2) {
- tmp = document.createTextNode('✓');
+ tmp = document.createTextNode("✓");
but.appendChild(tmp);
} else {
onEachLazy(but.childNodes, e => {
return true;
}
});
- tmp.textContent = '✓';
+ tmp.textContent = "✓";
}
if (reset_button_timeout !== null) {
}
function reset_button() {
- tmp.textContent = '';
+ tmp.textContent = "";
reset_button_timeout = null;
but.children[0].style.display = "";
}
// Scroll code block to the given code location
function scrollToLoc(elt, loc) {
- const lines = elt.querySelector('.line-numbers');
+ const lines = elt.querySelector(".line-numbers");
let scrollOffset;
// If the block is greater than the size of the viewer,
function updateScrapedExample(example) {
const locs = JSON.parse(example.attributes.getNamedItem("data-locs").textContent);
let locIndex = 0;
- const highlights = Array.prototype.slice.call(example.querySelectorAll('.highlight'));
- const link = example.querySelector('.scraped-example-title a');
+ const highlights = Array.prototype.slice.call(example.querySelectorAll(".highlight"));
+ const link = example.querySelector(".scraped-example-title a");
if (locs.length > 1) {
// Toggle through list of examples in a given file
const onChangeLoc = changeIndex => {
- removeClass(highlights[locIndex], 'focus');
+ removeClass(highlights[locIndex], "focus");
changeIndex();
scrollToLoc(example, locs[locIndex][0]);
- addClass(highlights[locIndex], 'focus');
+ addClass(highlights[locIndex], "focus");
const url = locs[locIndex][1];
const title = locs[locIndex][2];
link.innerHTML = title;
};
- example.querySelector('.prev')
- .addEventListener('click', () => {
+ example.querySelector(".prev")
+ .addEventListener("click", () => {
onChangeLoc(() => {
locIndex = (locIndex - 1 + locs.length) % locs.length;
});
});
- example.querySelector('.next')
- .addEventListener('click', () => {
+ example.querySelector("next")
+ .addEventListener("click", () => {
onChangeLoc(() => {
locIndex = (locIndex + 1) % locs.length;
});
});
}
- const expandButton = example.querySelector('.expand');
+ const expandButton = example.querySelector(".expand");
if (expandButton) {
- expandButton.addEventListener('click', () => {
+ expandButton.addEventListener("click", () => {
if (hasClass(example, "expanded")) {
removeClass(example, "expanded");
scrollToLoc(example, locs[0][0]);
scrollToLoc(example, locs[0][0]);
}
- const firstExamples = document.querySelectorAll('.scraped-example-list > .scraped-example');
+ const firstExamples = document.querySelectorAll(".scraped-example-list > .scraped-example");
onEachLazy(firstExamples, updateScrapedExample);
- onEachLazy(document.querySelectorAll('.more-examples-toggle'), toggle => {
+ onEachLazy(document.querySelectorAll(".more-examples-toggle"), toggle => {
// Allow users to click the left border of the <details> section to close it,
// since the section can be large and finding the [+] button is annoying.
- onEachLazy(toggle.querySelectorAll('.toggle-line, .hide-more'), button => {
- button.addEventListener('click', () => {
+ onEachLazy(toggle.querySelectorAll(".toggle-line, .hide-more"), button => {
+ button.addEventListener("click", () => {
toggle.open = false;
});
});
- const moreExamples = toggle.querySelectorAll('.scraped-example');
- toggle.querySelector('summary').addEventListener('click', () => {
+ const moreExamples = toggle.querySelectorAll(".scraped-example");
+ toggle.querySelector("summary").addEventListener("click", () => {
// Wrapping in setTimeout ensures the update happens after the elements are actually
// visible. This is necessary since updateScrapedExample calls scrollToLoc which
// depends on offsetHeight, a property that requires an element to be visible to
* @return {boolean}
*/
function isPathStart(parserState) {
- return parserState.userQuery.slice(parserState.pos, parserState.pos + 2) == '::';
+ return parserState.userQuery.slice(parserState.pos, parserState.pos + 2) == "::";
}
/**
* @return {boolean}
*/
function isReturnArrow(parserState) {
- return parserState.userQuery.slice(parserState.pos, parserState.pos + 2) == '->';
+ return parserState.userQuery.slice(parserState.pos, parserState.pos + 2) == "->";
}
/**
*/
function isIdentCharacter(c) {
return (
- c === '_' ||
- (c >= '0' && c <= '9') ||
- (c >= 'a' && c <= 'z') ||
- (c >= 'A' && c <= 'Z'));
+ c === "_" ||
+ (c >= "0" && c <= "9") ||
+ (c >= "a" && c <= "z") ||
+ (c >= "A" && c <= "Z"));
}
/**
* @return {QueryElement} - The newly created `QueryElement`.
*/
function createQueryElement(query, parserState, name, generics, isInGenerics) {
- if (name === '*' || (name.length === 0 && generics.length === 0)) {
+ if (name === "*" || (name.length === 0 && generics.length === 0)) {
return;
}
if (query.literalSearch && parserState.totalElems - parserState.genericsElems > 0) {
return parsedQuery.literalSearch ? MAX_LEV_DISTANCE + 1 : lev;
}
- function checkPath(contains, lastElem, ty) {
+ function checkPath(contains, ty) {
if (contains.length === 0) {
return 0;
}
}
if (elem.fullPath.length > 1) {
- lev = checkPath(elem.pathWithoutLast, elem.pathLast, row);
+ lev = checkPath(elem.pathWithoutLast, row);
if (lev > MAX_LEV_DISTANCE || (parsedQuery.literalSearch && lev !== 0)) {
return;
} else if (lev > 0) {
}
}
lev = levenshtein(searchWord, elem.pathLast);
- lev += lev_add;
if (lev > 0 && elem.pathLast.length > 2 && searchWord.indexOf(elem.pathLast) > -1)
{
if (elem.pathLast.length < 6) {
lev = 0;
}
}
+ lev += lev_add;
if (lev > MAX_LEV_DISTANCE) {
return;
} else if (index !== -1 && elem.fullPath.length < 2) {
let crates = "";
if (window.ALL_CRATES.length > 1) {
- crates = ` in <select id="crate-search"><option value="All crates">All crates</option>`;
+ crates = " in <select id=\"crate-search\"><option value=\"All crates\">" +
+ "All crates</option>";
for (const c of window.ALL_CRATES) {
crates += `<option value="${c}" ${c == filterCrates && "selected"}>${c}</option>`;
}
- crates += `</select>`;
+ crates += "</select>";
}
let typeFilter = "";
typeFilter = " (type: " + escape(itemTypes[results.query.typeFilter]) + ")";
}
- let output = `<div id="search-settings">` +
+ let output = "<div id=\"search-settings\">" +
`<h1 class="search-results-title">Results for ${escape(results.query.userQuery)}` +
`${typeFilter}</h1> in ${crates} </div>`;
if (results.query.error !== null) {
output += `<h3>Query parser error: "${results.query.error}".</h3>`;
- output += '<div id="titles">' +
+ output += "<div id=\"titles\">" +
makeTabHeader(0, "In Names", ret_others[1]) +
"</div>";
currentTab = 0;
} else if (results.query.foundElems <= 1 && results.query.returned.length === 0) {
- output += `<div id="titles">` +
+ output += "<div id=\"titles\">" +
makeTabHeader(0, "In Names", ret_others[1]) +
makeTabHeader(1, "In Parameters", ret_in_args[1]) +
makeTabHeader(2, "In Return Types", ret_returned[1]) +
results.query.elems.length === 0 ? "In Function Return Types" :
results.query.returned.length === 0 ? "In Function Parameters" :
"In Function Signatures";
- output += '<div id="titles">' +
+ output += "<div id=\"titles\">" +
makeTabHeader(0, signatureTabTitle, ret_others[1]) +
"</div>";
currentTab = 0;
let output = "";
for (const setting of settings) {
- output += `<div class="setting-line">`;
+ output += "<div class=\"setting-line\">";
const js_data_name = setting["js_name"];
const setting_name = setting["name"];
if (isSettingsPage) {
innerHTML +=
- `<a id="back" href="javascript:void(0)" onclick="history.back();">Back</a>`;
+ "<a id=\"back\" href=\"javascript:void(0)\" onclick=\"history.back();\">Back</a>";
} else {
- innerHTML +=
- `<a id="back" href="javascript:void(0)" onclick="switchDisplayedElement(null);">\
- Back</a>`;
+ innerHTML += "<a id=\"back\" href=\"javascript:void(0)\" " +
+ "onclick=\"switchDisplayedElement(null);\">Back</a>";
}
innerHTML += `</span>
</div>
if (settingsDataset !== null) {
// See the comment for `default_settings.into_iter()` etc. in
// `Options::from_matches` in `librustdoc/config.rs`.
- const def = settingsDataset[settingName.replace(/-/g,'_')];
+ const def = settingsDataset[settingName.replace(/-/g,"_")];
if (def !== undefined) {
return def;
}
// fallback to the CSS computed value
return () => {
const cssTheme = getComputedStyle(document.documentElement)
- .getPropertyValue('content');
+ .getPropertyValue("content");
switchTheme(
window.currentTheme,
-Subproject commit fc10370ef7d91babf512c10505f8f2176bc8519d
+Subproject commit 593484fc1596707406b0b0b45b97feb08d2a1bfc
A(i32),
B(i32),
}
-// CHECK: %"Enum4::A" = type { [1 x i32], i32 }
+// No Aggregate type, and hence nothing in LLVM IR.
pub enum Enum64 {
A(Align64),
--- /dev/null
+const QUERY = 'hashset::insert';
+
+const EXPECTED = {
+ 'others': [
+ // ensure hashset::insert comes first
+ { 'path': 'std::collections::hash_set::HashSet', 'name': 'insert' },
+ { 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert' },
+ { 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert_with' },
+ { 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert_owned' },
+ { 'path': 'std::collections::hash_map::HashMap', 'name': 'insert' },
+ ],
+};
--- /dev/null
+// exact-check
+
+const QUERY = 'b::ccccccc';
+
+const EXPECTED = {
+ 'others': [
+ // `ccccccc` is an exact match for all three of these.
+ // However `b` is a closer match for `bb` than for any
+ // of the others, so it ought to go first.
+ { 'path': 'path_ordering::bb', 'name': 'Ccccccc' },
+ { 'path': 'path_ordering::aa', 'name': 'Ccccccc' },
+ { 'path': 'path_ordering::dd', 'name': 'Ccccccc' },
+ ],
+};
--- /dev/null
+pub mod dd {
+ pub struct Ccccccc;
+}
+pub mod aa {
+ pub struct Ccccccc;
+}
+pub mod bb {
+ pub struct Ccccccc;
+}
--- /dev/null
+// check-pass
+#![feature(lint_reasons)]
+
+//! This file tests the `#[expect]` attribute implementation for tool lints. The same
+//! file is used to test clippy and rustdoc. Any changes to this file should be synced
+//! to the other test files as well.
+//!
+//! Expectations:
+//! * rustc: only rustc lint expectations are emitted
+//! * clippy: rustc and Clippy's expectations are emitted
+//! * rustdoc: only rustdoc lint expectations are emitted
+//!
+//! This test can't cover every lint from Clippy, rustdoc and potentially other
+//! tools that will be developed. This therefore only tests a small subset of lints
+
+#![expect(rustdoc::missing_crate_level_docs)]
+//~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+//~| NOTE `#[warn(unfulfilled_lint_expectations)]` on by default
+
+mod rustc_ok {
+ //! See <https://doc.rust-lang.org/rustc/lints/index.html>
+
+ #[expect(dead_code)]
+ pub fn rustc_lints() {
+ let x = 42.0;
+
+ #[expect(illegal_floating_point_literal_pattern)]
+ match x {
+ 5.0 => {}
+ 6.0 => {}
+ _ => {}
+ }
+ }
+}
+
+mod rustc_warn {
+ //! See <https://doc.rust-lang.org/rustc/lints/index.html>
+
+ #[expect(dead_code)]
+ pub fn rustc_lints() {
+ let x = 42;
+
+ #[expect(illegal_floating_point_literal_pattern)]
+ match x {
+ 5 => {}
+ 6 => {}
+ _ => {}
+ }
+ }
+}
+
+pub mod rustdoc_ok {
+ //! See <https://doc.rust-lang.org/rustdoc/lints.html>
+
+ #[expect(rustdoc::broken_intra_doc_links)]
+ /// I want to link to [`Nonexistent`] but it doesn't exist!
+ pub fn foo() {}
+
+ #[expect(rustdoc::invalid_html_tags)]
+ /// <h1>
+ pub fn bar() {}
+
+ #[expect(rustdoc::bare_urls)]
+ /// http://example.org
+ pub fn baz() {}
+}
+
+pub mod rustdoc_warn {
+ //! See <https://doc.rust-lang.org/rustdoc/lints.html>
+
+ #[expect(rustdoc::broken_intra_doc_links)]
+ //~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+ /// I want to link to [`bar`] but it doesn't exist!
+ pub fn foo() {}
+
+ #[expect(rustdoc::invalid_html_tags)]
+ //~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+ /// <h1></h1>
+ pub fn bar() {}
+
+ #[expect(rustdoc::bare_urls)]
+ //~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+ /// <http://example.org>
+ pub fn baz() {}
+}
+
+mod clippy_ok {
+ //! See <https://rust-lang.github.io/rust-clippy/master/index.html>
+
+ #[expect(clippy::almost_swapped)]
+ fn foo() {
+ let mut a = 0;
+ let mut b = 9;
+ a = b;
+ b = a;
+ }
+
+ #[expect(clippy::bytes_nth)]
+ fn bar() {
+ let _ = "Hello".bytes().nth(3);
+ }
+
+ #[expect(clippy::if_same_then_else)]
+ fn baz() {
+ let _ = if true {
+ 42
+ } else {
+ 42
+ };
+ }
+
+ #[expect(clippy::logic_bug)]
+ fn burger() {
+ let a = false;
+ let b = true;
+
+ if a && b || a {}
+ }
+}
+
+mod clippy_warn {
+ //! See <https://rust-lang.github.io/rust-clippy/master/index.html>
+
+ #[expect(clippy::almost_swapped)]
+ fn foo() {
+ let mut a = 0;
+ let mut b = 9;
+ a = b;
+ }
+
+ #[expect(clippy::bytes_nth)]
+ fn bar() {
+ let _ = "Hello".as_bytes().get(3);
+ }
+
+ #[expect(clippy::if_same_then_else)]
+ fn baz() {
+ let _ = if true {
+ 33
+ } else {
+ 42
+ };
+ }
+
+ #[expect(clippy::logic_bug)]
+ fn burger() {
+ let a = false;
+ let b = true;
+ let c = false;
+
+ if a && b || c {}
+ }
+}
+
+fn main() {
+ rustc_warn::rustc_lints();
+}
--- /dev/null
+warning: this lint expectation is unfulfilled
+ --> $DIR/expect-tool-lint-rfc-2383.rs:16:11
+ |
+LL | #![expect(rustdoc::missing_crate_level_docs)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(unfulfilled_lint_expectations)]` on by default
+
+warning: this lint expectation is unfulfilled
+ --> $DIR/expect-tool-lint-rfc-2383.rs:71:14
+ |
+LL | #[expect(rustdoc::broken_intra_doc_links)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: this lint expectation is unfulfilled
+ --> $DIR/expect-tool-lint-rfc-2383.rs:76:14
+ |
+LL | #[expect(rustdoc::invalid_html_tags)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: this lint expectation is unfulfilled
+ --> $DIR/expect-tool-lint-rfc-2383.rs:81:14
+ |
+LL | #[expect(rustdoc::bare_urls)]
+ | ^^^^^^^^^^^^^^^^^^
+
+warning: 4 warnings emitted
+
--- /dev/null
+#![feature(staged_api)]
+#![stable(feature = "deprecated-future-staged-api", since = "1.0.0")]
+
+// @has deprecated_future_staged_api/index.html '//*[@class="stab deprecated"]' \
+// 'Deprecation planned'
+// @has deprecated_future_staged_api/struct.S1.html '//*[@class="stab deprecated"]' \
+// 'Deprecating in 99.99.99: effectively never'
+#[deprecated(since = "99.99.99", note = "effectively never")]
+#[stable(feature = "deprecated-future-staged-api", since = "1.0.0")]
+pub struct S1;
+
+// @has deprecated_future_staged_api/index.html '//*[@class="stab deprecated"]' \
+// 'Deprecation planned'
+// @has deprecated_future_staged_api/struct.S2.html '//*[@class="stab deprecated"]' \
+// 'Deprecating in a future Rust version: literally never'
+#[deprecated(since = "TBD", note = "literally never")]
+#[stable(feature = "deprecated-future-staged-api", since = "1.0.0")]
+pub struct S2;
#![feature(staged_api)]
-
#![stable(feature = "rust1", since = "1.0.0")]
/// docs for my_macro
#[unstable(feature = "macro_test", issue = "none")]
-#[rustc_deprecated(since = "1.2.3", reason = "text")]
+#[deprecated(since = "1.2.3", note = "text")]
#[macro_export]
macro_rules! my_macro {
- () => ()
+ () => {};
}
// build-aux-docs
#![feature(macro_test)]
-
#![crate_name = "foo"]
extern crate macros;
// @has - '//*[@class="docblock"]' 'docs for my_macro'
// @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.2.3: text'
// @has - '//*[@class="stab unstable"]' 'macro_test'
-// @has - '//a/@href' '../src/macros/macros.rs.html#9-11'
+// @has - '//a/@href' '../src/macros/macros.rs.html#8-10'
pub use macros::my_macro;
// @matches issue_32374/struct.T.html '//*[@class="stab unstable"]' \
// '🔬 This is a nightly-only experimental API. \(test\s#32374\)$'
/// Docs
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
#[unstable(feature = "test", issue = "32374")]
pub struct T;
// '👎 Deprecated since 1.0.0: deprecated'
// @has issue_32374/struct.U.html '//*[@class="stab unstable"]' \
// '🔬 This is a nightly-only experimental API. (test #32374)'
-#[rustc_deprecated(since = "1.0.0", reason = "deprecated")]
+#[deprecated(since = "1.0.0", note = "deprecated")]
#[unstable(feature = "test", issue = "32374", reason = "unstable")]
pub struct U;
+++ /dev/null
-#![feature(staged_api)]
-
-#![stable(feature = "rustc_deprecated-future-test", since = "1.0.0")]
-
-// @has rustc_deprecated_future/index.html '//*[@class="stab deprecated"]' \
-// 'Deprecation planned'
-// @has rustc_deprecated_future/struct.S1.html '//*[@class="stab deprecated"]' \
-// 'Deprecating in 99.99.99: effectively never'
-#[rustc_deprecated(since = "99.99.99", reason = "effectively never")]
-#[stable(feature = "rustc_deprecated-future-test", since = "1.0.0")]
-pub struct S1;
-
-// @has rustc_deprecated_future/index.html '//*[@class="stab deprecated"]' \
-// 'Deprecation planned'
-// @has rustc_deprecated_future/struct.S2.html '//*[@class="stab deprecated"]' \
-// 'Deprecating in a future Rust version: literally never'
-#[rustc_deprecated(since = "TBD", reason = "literally never")]
-#[stable(feature = "rustc_deprecated-future-test", since = "1.0.0")]
-pub struct S2;
missing(); //~ ERROR this function takes
swapped("", 1); //~ ERROR arguments to this function are incorrect
permuted(Y {}, Z {}, X {}); //~ ERROR arguments to this function are incorrect
+
+ let closure = |x| x;
+ closure(); //~ ERROR this function takes
}
LL | permuted(X {}, Y {}, Z {});
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
-error: aborting due to 5 previous errors
+error[E0057]: this function takes 1 argument but 0 arguments were supplied
+ --> $DIR/basic.rs:27:5
+ |
+LL | closure();
+ | ^^^^^^^-- an argument is missing
+ |
+note: closure defined here
+ --> $DIR/basic.rs:26:19
+ |
+LL | let closure = |x| x;
+ | ^^^
+help: provide the argument
+ |
+LL | closure({_});
+ | ~~~~~~~~~~~~
+
+error: aborting due to 6 previous errors
-Some errors have detailed explanations: E0061, E0308.
-For more information about an error, try `rustc --explain E0061`.
+Some errors have detailed explanations: E0057, E0061, E0308.
+For more information about an error, try `rustc --explain E0057`.
|
LL | type Item = T;
| ^
- = note: expected enum `Option<T>`
- found type `T`
+ = note: expected enum `Option<T>`
+ found type parameter `T`
note: required by a bound in `is_iterator_of`
--> $DIR/associated-types-issue-20346.rs:15:34
|
| ^^^ lifetime mismatch
|
= note: expected reference `&'a ()`
- found type `&()`
+ found reference `&()`
note: the lifetime requirement is introduced here
--> $DIR/higher-ranked-projection.rs:15:33
|
| |
| arguments to this function are incorrect
|
+note: while checking the return type of the `async fn`
+ --> $DIR/generator-desc.rs:5:16
+ |
+LL | async fn one() {}
+ | ^ checked the `Output` of this `async fn`, expected opaque type
note: while checking the return type of the `async fn`
--> $DIR/generator-desc.rs:6:16
|
LL | async fn two() {}
| ^ checked the `Output` of this `async fn`, found opaque type
- = note: expected type `impl Future<Output = ()>` (opaque type at <$DIR/generator-desc.rs:5:16>)
- found opaque type `impl Future<Output = ()>` (opaque type at <$DIR/generator-desc.rs:6:16>)
+ = note: expected opaque type `impl Future<Output = ()>` (opaque type at <$DIR/generator-desc.rs:5:16>)
+ found opaque type `impl Future<Output = ()>` (opaque type at <$DIR/generator-desc.rs:6:16>)
= help: consider `await`ing on both `Future`s
= note: distinct uses of `impl Trait` result in different opaque types
note: function defined here
--> $DIR/generator-desc.rs:14:26
|
LL | fun((async || {})(), (async || {})());
- | --- ^^^^^^^^^^^^^^^ expected `async` closure body, found a different `async` closure body
- | |
+ | --- -- ^^^^^^^^^^^^^^^ expected `async` closure body, found a different `async` closure body
+ | | |
+ | | the expected `async` closure body
| arguments to this function are incorrect
|
::: $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
+ | -------------------------------
+ | |
+ | the expected opaque type
+ | the found opaque type
|
- = note: expected type `impl Future<Output = ()>` (`async` closure body)
- found opaque type `impl Future<Output = ()>` (`async` closure body)
+ = note: expected opaque type `impl Future<Output = ()>` (`async` closure body)
+ found opaque type `impl Future<Output = ()>` (`async` closure body)
note: function defined here
--> $DIR/generator-desc.rs:8:4
|
LL | fn fun<F: Future<Output = ()>>(f1: F, f2: F) {}
| ^^^ ----- -----
-help: consider `await`ing on the `Future`
- |
-LL | fun((async || {})(), (async || {})().await);
- | ++++++
error: aborting due to 3 previous errors
LL | | };
| |_____- `if` and `else` have incompatible types
|
- = note: expected type `impl Future<Output = ()>`
- found unit type `()`
+note: while checking the return type of the `async fn`
+ --> $DIR/suggest-missing-await.rs:18:18
+ |
+LL | async fn dummy() {}
+ | ^ checked the `Output` of this `async fn`, expected opaque type
+ = note: expected opaque type `impl Future<Output = ()>`
+ found unit type `()`
help: consider `await`ing on the `Future`
|
LL | dummy().await
--- /dev/null
+// Regression test: issue had to do with "givens" in region inference,
+// which were not being considered during the contraction phase.
+
+// run-fail
+// error-pattern:explicit panic
+// ignore-emscripten no processes
+
+struct Parser<'i: 't, 't>(&'i u8, &'t u8);
+
+impl<'i, 't> Parser<'i, 't> {
+ fn parse_nested_block<F, T>(&mut self, parse: F) -> Result<T, ()>
+ where for<'tt> F: FnOnce(&mut Parser<'i, 'tt>) -> T
+ {
+ panic!()
+ }
+
+ fn expect_exhausted(&mut self) -> Result<(), ()> {
+ Ok(())
+ }
+}
+
+fn main() {
+ let x = 0u8;
+ Parser(&x, &x).parse_nested_block(|input| input.expect_exhausted()).unwrap();
+}
+++ /dev/null
-error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
- --> $DIR/suggest-local-var-imm-and-mut.rs:12:22
- |
-LL | self.foo(self.bar());
- | ---------^^^^^^^^^^-
- | | | |
- | | | mutable borrow occurs here
- | | immutable borrow later used by call
- | immutable borrow occurs here
-
-error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
- --> $DIR/suggest-local-var-imm-and-mut.rs:24:29
- |
-LL | Self::foo(self, Self::bar(self));
- | --------- ---- ^^^^^^^^^^^^^^^ mutable borrow occurs here
- | | |
- | | immutable borrow occurs here
- | immutable borrow later used by call
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0502`.
LL | | };
| |_____- `match` arms have incompatible types
|
- = note: expected type `fn(i32, i32) -> i32 {add}`
- found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:9:16: 9:43]`
+ = note: expected fn item `fn(i32, i32) -> i32 {add}`
+ found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:9:16: 9:43]`
error[E0308]: `match` arms have incompatible types
--> $DIR/closure_cap_coerce_many_fail.rs:18:16
LL | let _ = match "+" {
| _____________-
LL | | "+" => |a, b| (a + b) as i32,
- | | --------------------- this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:17:16: 17:37]`
+ | | ---------------------
+ | | |
+ | | the expected closure
+ | | this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:17:16: 17:37]`
LL | | "-" => |a, b| (a - b + cap) as i32,
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure
LL | | _ => unimplemented!(),
LL | | };
| |_____- `match` arms have incompatible types
|
- = note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:17:16: 17:37]`
- found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:18:16: 18:43]`
+ = note: expected closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:17:16: 17:37]`
+ found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:18:16: 18:43]`
= note: no two closures, even if identical, have the same type
= help: consider boxing your closure and/or using it as a trait object
LL | let _ = match "+" {
| _____________-
LL | | "+" => |a, b| (a + b + cap) as i32,
- | | --------------------------- this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:43]`
+ | | ---------------------------
+ | | |
+ | | the expected closure
+ | | this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:43]`
LL | | "-" => |a, b| (a - b) as i32,
| | ^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure
LL | | _ => unimplemented!(),
LL | | };
| |_____- `match` arms have incompatible types
|
- = note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:43]`
- found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:27:16: 27:37]`
+ = note: expected closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:43]`
+ found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:27:16: 27:37]`
= note: no two closures, even if identical, have the same type
= help: consider boxing your closure and/or using it as a trait object
LL | let _ = match "+" {
| _____________-
LL | | "+" => |a, b| (a + b + cap) as i32,
- | | --------------------------- this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:43]`
+ | | ---------------------------
+ | | |
+ | | the expected closure
+ | | this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:43]`
LL | | "-" => |a, b| (a - b + cap) as i32,
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure
LL | | _ => unimplemented!(),
LL | | };
| |_____- `match` arms have incompatible types
|
- = note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:43]`
- found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:35:16: 35:43]`
+ = note: expected closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:43]`
+ found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:35:16: 35:43]`
= note: no two closures, even if identical, have the same type
= help: consider boxing your closure and/or using it as a trait object
--- /dev/null
+// Creating a stack closure which references a box and then
+// transferring ownership of the box before invoking the stack
+// closure results in a crash.
+
+#![feature(box_syntax)]
+
+fn twice(x: Box<usize>) -> usize {
+ *x * 2
+}
+
+fn invoke<F>(f: F) where F: FnOnce() -> usize {
+ f();
+}
+
+fn main() {
+ let x : Box<usize> = box 9;
+ let sq = || { *x * *x };
+
+ twice(x); //~ ERROR: cannot move out of
+ invoke(sq);
+}
--- /dev/null
+error[E0505]: cannot move out of `x` because it is borrowed
+ --> $DIR/issue-6801.rs:19:13
+ |
+LL | let sq = || { *x * *x };
+ | -- -- borrow occurs due to use in closure
+ | |
+ | borrow of `x` occurs here
+LL |
+LL | twice(x);
+ | ^ move out of `x` occurs here
+LL | invoke(sq);
+ | -- borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0505`.
LL | /* *mut $0 is coerced to Box<dyn Error> here */ Box::<_ /* ! */>::new(x)
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()`
|
- = help: the following other types implement trait `std::error::Error`:
- !
- &'a T
- AccessError
- AddrParseError
- Arc<T>
- BorrowError
- BorrowMutError
- Box<T>
- and 45 others
= note: required for the cast to the object type `dyn std::error::Error`
error[E0277]: the trait bound `(): std::error::Error` is not satisfied
LL | /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()`
|
- = help: the following other types implement trait `std::error::Error`:
- !
- &'a T
- AccessError
- AddrParseError
- Arc<T>
- BorrowError
- BorrowMutError
- Box<T>
- and 45 others
= note: required for the cast to the object type `(dyn std::error::Error + 'static)`
error: aborting due to 2 previous errors
LL | /* *mut $0 is coerced to Box<dyn Error> here */ Box::<_ /* ! */>::new(x)
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()`
|
- = help: the following other types implement trait `std::error::Error`:
- !
- &'a T
- AccessError
- AddrParseError
- Arc<T>
- BorrowError
- BorrowMutError
- Box<T>
- and 43 others
= note: required for the cast to the object type `dyn std::error::Error`
error[E0277]: the trait bound `(): std::error::Error` is not satisfied
LL | /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()`
|
- = help: the following other types implement trait `std::error::Error`:
- !
- &'a T
- AccessError
- AddrParseError
- Arc<T>
- BorrowError
- BorrowMutError
- Box<T>
- and 43 others
= note: required for the cast to the object type `(dyn std::error::Error + 'static)`
error: aborting due to 2 previous errors
| |
| arguments to this function are incorrect
|
- = note: expected type `&mut {integer}`
- found reference `&{integer}`
+ = note: expected mutable reference `&mut {integer}`
+ found reference `&{integer}`
note: function defined here
--> $DIR/coerce-reborrow-multi-arg-fail.rs:1:4
|
+++ /dev/null
-error[E0308]: arguments to this function are incorrect
- --> $DIR/const-argument-cross-crate-mismatch.rs:7:41
- |
-LL | let _ = const_generic_lib::function(const_generic_lib::Struct([0u8, 1u8]));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^----------^
- | |
- | expected `[u8; 3]`, found `[u8; 2]`
- |
-help: provide an argument of the correct type
- |
-LL | let _ = const_generic_lib::function(({[u8; 3]}));
- | ^^^^^^^^^^^
-
-error[E0308]: arguments to this function are incorrect
- --> $DIR/const-argument-cross-crate-mismatch.rs:9:39
- |
-LL | let _: const_generic_lib::Alias = const_generic_lib::Struct([0u8, 1u8, 2u8]);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^---------------^
- | |
- | expected `[u8; 2]`, found `[u8; 3]`
- |
-help: provide an argument of the correct type
- |
-LL | let _: const_generic_lib::Alias = ({[u8; 2]});
- | ^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
-// [full] run-pass
+// [full] check-pass
// revisions: full min
// regression test for #78180
--- /dev/null
+trait Trait {
+ fn foo<U>() {}
+}
+impl Trait for () {
+ fn foo<const M: u64>() {}
+ //~^ error: method `foo` has an incompatible generic parameter for trait
+}
+
+trait Other {
+ fn bar<const M: u8>() {}
+}
+impl Other for () {
+ fn bar<T>() {}
+ //~^ error: method `bar` has an incompatible generic parameter for trait
+}
+
+trait Uwu {
+ fn baz<const N: u32>() {}
+}
+impl Uwu for () {
+ fn baz<const N: i32>() {}
+ //~^ error: method `baz` has an incompatible generic parameter for trait
+}
+
+trait Aaaaaa {
+ fn bbbb<const N: u32, T>() {}
+}
+impl Aaaaaa for () {
+ fn bbbb<T, const N: u32>() {}
+ //~^ error: method `bbbb` has an incompatible generic parameter for trait
+}
+
+trait Names {
+ fn abcd<T, const N: u32>() {}
+}
+impl Names for () {
+ fn abcd<const N: u32, T>() {}
+ //~^ error: method `abcd` has an incompatible generic parameter for trait
+}
+
+fn main() {}
--- /dev/null
+error[E0053]: method `foo` has an incompatible generic parameter for trait `Trait`
+ --> $DIR/mismatched_ty_const_in_trait_impl.rs:5:12
+ |
+LL | trait Trait {
+ | -----
+LL | fn foo<U>() {}
+ | - expected type parameter
+LL | }
+LL | impl Trait for () {
+ | -----------------
+LL | fn foo<const M: u64>() {}
+ | ^^^^^^^^^^^^ found const parameter of type `u64`
+
+error[E0053]: method `bar` has an incompatible generic parameter for trait `Other`
+ --> $DIR/mismatched_ty_const_in_trait_impl.rs:13:12
+ |
+LL | trait Other {
+ | -----
+LL | fn bar<const M: u8>() {}
+ | ----------- expected const parameter of type `u8`
+LL | }
+LL | impl Other for () {
+ | -----------------
+LL | fn bar<T>() {}
+ | ^ found type parameter
+
+error[E0053]: method `baz` has an incompatible generic parameter for trait `Uwu`
+ --> $DIR/mismatched_ty_const_in_trait_impl.rs:21:12
+ |
+LL | trait Uwu {
+ | ---
+LL | fn baz<const N: u32>() {}
+ | ------------ expected const parameter of type `u32`
+LL | }
+LL | impl Uwu for () {
+ | ---------------
+LL | fn baz<const N: i32>() {}
+ | ^^^^^^^^^^^^ found const parameter of type `i32`
+
+error[E0053]: method `bbbb` has an incompatible generic parameter for trait `Aaaaaa`
+ --> $DIR/mismatched_ty_const_in_trait_impl.rs:29:13
+ |
+LL | trait Aaaaaa {
+ | ------
+LL | fn bbbb<const N: u32, T>() {}
+ | ------------ expected const parameter of type `u32`
+LL | }
+LL | impl Aaaaaa for () {
+ | ------------------
+LL | fn bbbb<T, const N: u32>() {}
+ | ^ found type parameter
+
+error[E0053]: method `abcd` has an incompatible generic parameter for trait `Names`
+ --> $DIR/mismatched_ty_const_in_trait_impl.rs:37:13
+ |
+LL | trait Names {
+ | -----
+LL | fn abcd<T, const N: u32>() {}
+ | - expected type parameter
+LL | }
+LL | impl Names for () {
+ | -----------------
+LL | fn abcd<const N: u32, T>() {}
+ | ^^^^^^^^^^^^ found const parameter of type `u32`
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0053`.
--- /dev/null
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+trait MyTrait<T> {}
+
+fn bug<'a, T>() -> &'static dyn MyTrait<[(); { |x: &'a u32| { x }; 4 }]> {
+ //~^ ERROR overly complex generic constant
+ todo!()
+}
+
+fn main() {}
--- /dev/null
+error: overly complex generic constant
+ --> $DIR/issue-77357.rs:6:46
+ |
+LL | fn bug<'a, T>() -> &'static dyn MyTrait<[(); { |x: &'a u32| { x }; 4 }]> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ blocks are not supported in generic constant
+ |
+ = help: consider moving this anonymous constant into a `const` function
+ = note: this operation may be supported in the future
+
+error: aborting due to previous error
+
+++ /dev/null
-#![feature(generic_const_exprs)]
-#![allow(incomplete_features)]
-
-trait MyTrait<T> {}
-
-fn bug<'a, T>() -> &'static dyn MyTrait<[(); { |x: &'a u32| { x }; 4 }]> {
- //~^ ERROR overly complex generic constant
- todo!()
-}
-
-fn main() {}
+++ /dev/null
-error: overly complex generic constant
- --> $DIR/issue-775377.rs:6:46
- |
-LL | fn bug<'a, T>() -> &'static dyn MyTrait<[(); { |x: &'a u32| { x }; 4 }]> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ blocks are not supported in generic constant
- |
- = help: consider moving this anonymous constant into a `const` function
- = note: this operation may be supported in the future
-
-error: aborting due to previous error
-
// Regression test for the ICE described in #86820.
-#![allow(unused,dead_code)]
+#![allow(unused, dead_code)]
use std::ops::BitAnd;
const C: fn() = || is_set();
}
trait Bits {
- fn bit<const I : u8>(self) -> bool;
- //~^ NOTE: the const parameter `I` has type `usize`, but the declaration in trait `Bits::bit` has type `u8`
+ fn bit<const I: u8>(self) -> bool;
}
impl Bits for u8 {
- fn bit<const I : usize>(self) -> bool {
- //~^ ERROR: method `bit` has an incompatible const parameter type for trait [E0053]
+ fn bit<const I: usize>(self) -> bool {
+ //~^ ERROR: method `bit` has an incompatible generic parameter for trait `Bits` [E0053]
let i = 1 << I;
let mask = u8::from(i);
mask & self == mask
-error[E0053]: method `bit` has an incompatible const parameter type for trait
- --> $DIR/issue-86820.rs:17:12
+error[E0053]: method `bit` has an incompatible generic parameter for trait `Bits`
+ --> $DIR/issue-86820.rs:16:12
|
-LL | fn bit<const I : usize>(self) -> bool {
- | ^^^^^^^^^^^^^^^
- |
-note: the const parameter `I` has type `usize`, but the declaration in trait `Bits::bit` has type `u8`
- --> $DIR/issue-86820.rs:12:12
- |
-LL | fn bit<const I : u8>(self) -> bool;
- | ^^^^^^^^^^^^
+LL | trait Bits {
+ | ----
+LL | fn bit<const I: u8>(self) -> bool;
+ | ----------- expected const parameter of type `u8`
+...
+LL | impl Bits for u8 {
+ | ----------------
+LL | fn bit<const I: usize>(self) -> bool {
+ | ^^^^^^^^^^^^^^ found const parameter of type `usize`
error: aborting due to previous error
--- /dev/null
+// check-pass
+
+struct A<const M: u32> {}
+
+struct B<const M: u32> {}
+
+impl<const M: u32> B<M> {
+ const M: u32 = M;
+}
+
+struct C<const M: u32> {
+ a: A<{ B::<1>::M }>,
+}
+
+fn main() {}
+++ /dev/null
-error[E0601]: `main` function not found in crate `continue_after_missing_main`
- --> $DIR/continue-after-missing-main.rs:30:2
- |
-LL | }
- | ^ consider adding a `main` function to `$DIR/continue-after-missing-main.rs`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0601`.
+++ /dev/null
-#![allow(dead_code)]
-
-struct Tableau<'a, MP> {
- provider: &'a MP,
-}
-
-impl<'adapted_matrix_provider, 'original_data, MP>
- Tableau<'adapted_matrix_provider, AdaptedMatrixProvider<'original_data, MP>>
-{
- fn provider(&self) -> &'adapted_matrix_provider AdaptedMatrixProvider</*'original_data,*/ MP> {
- self.provider
- }
-}
-
-struct AdaptedMatrixProvider<'a, T> {
- original_problem: &'a T,
-}
-
-impl<'a, T> AdaptedMatrixProvider<'a, T> {
- fn clone_with_extra_bound(&self) -> Self {
- AdaptedMatrixProvider { original_problem: self.original_problem }
- }
-}
-
-fn create_and_solve_subproblems<'data_provider, 'original_data, MP>(
- tableau: Tableau<'data_provider, AdaptedMatrixProvider<'original_data, MP>>,
-) {
- let _: AdaptedMatrixProvider<'original_data, MP> = tableau.provider().clone_with_extra_bound();
- //~^ ERROR lifetime mismatch
-} //~ ERROR `main` function not found in crate
+++ /dev/null
-error[E0601]: `main` function not found in crate `continue_after_missing_main`
- --> $DIR/continue-after-missing-main.rs:30:2
- |
-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 | tableau: Tableau<'data_provider, AdaptedMatrixProvider<'original_data, MP>>,
- | ------------------------------------------------------------------ these two types are declared with different lifetimes...
-LL | ) {
-LL | let _: AdaptedMatrixProvider<'original_data, MP> = tableau.provider().clone_with_extra_bound();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...but data from `tableau` flows into `tableau` here
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0601, E0623.
-For more information about an error, try `rustc --explain E0601`.
pub fn deprecated_future() {}
fn test() {
- deprecated_future(); // ok; deprecated_in_future only applies to rustc_deprecated
+ deprecated_future(); // ok; deprecated_in_future only applies with `#![feature(staged_api)]`
//~^ WARNING use of deprecated function `deprecated_future`: text [deprecated]
}
warning: use of deprecated function `deprecated_future`: text
--> $DIR/deprecation-in-future.rs:9:5
|
-LL | deprecated_future(); // ok; deprecated_in_future only applies to rustc_deprecated
+LL | deprecated_future(); // ok; deprecated_in_future only applies with `#![feature(staged_api)]`
| ^^^^^^^^^^^^^^^^^
|
= note: `#[warn(deprecated)]` on by default
<Foo>::trait_deprecated_text(&foo); //~ ERROR use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
<Foo as Trait>::trait_deprecated_text(&foo); //~ ERROR use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
- // Future deprecations are only permitted for rustc_deprecated.
+ // Future deprecations are only permitted with `#![feature(staged_api)]`
deprecated_future(); //~ ERROR use of deprecated function
deprecated_future_text(); //~ ERROR use of deprecated function
}
#[deprecated(since = "a", note = "b")]
-#[deprecated(since = "a", note = "b")] //~ ERROR multiple deprecated attributes
+#[deprecated(since = "a", note = "b")] //~ ERROR multiple `deprecated` attributes
fn multiple1() { }
#[deprecated(since = "a", since = "b", note = "c")] //~ ERROR multiple 'since' items
+error: multiple `deprecated` attributes
+ --> $DIR/deprecation-sanity.rs:27:1
+ |
+LL | #[deprecated(since = "a", note = "b")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+ |
+note: attribute also specified here
+ --> $DIR/deprecation-sanity.rs:26:1
+ |
+LL | #[deprecated(since = "a", note = "b")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
error[E0541]: unknown meta item 'reason'
--> $DIR/deprecation-sanity.rs:4:43
|
LL | #[deprecated("test")]
| ^^^^^^
-error[E0550]: multiple deprecated attributes
- --> $DIR/deprecation-sanity.rs:27:1
- |
-LL | #[deprecated(since = "a", note = "b")]
- | -------------------------------------- first deprecation attribute
-LL | #[deprecated(since = "a", note = "b")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ repeated deprecation attribute
-
error[E0538]: multiple 'since' items
--> $DIR/deprecation-sanity.rs:30:27
|
error: aborting due to 10 previous errors
-Some errors have detailed explanations: E0538, E0541, E0550, E0551, E0565.
+Some errors have detailed explanations: E0538, E0541, E0551, E0565.
For more information about an error, try `rustc --explain E0538`.
--- /dev/null
+// compile-flags: --crate-type=lib
+
+#![feature(staged_api)]
+#![stable(since = "1.0.0", feature = "rust1")]
+
+#[rustc_deprecated( //~ ERROR `#[rustc_deprecated]` has been removed
+ //~^ HELP use `#[deprecated]` instead
+ since = "1.100.0",
+ reason = "text" //~ ERROR `reason` has been renamed
+ //~^ HELP use `note` instead
+)]
+#[stable(feature = "rust1", since = "1.0.0")]
+fn foo() {}
--- /dev/null
+error: `#[rustc_deprecated]` has been removed
+ --> $DIR/rustc_deprecated.rs:6:1
+ |
+LL | / #[rustc_deprecated(
+LL | |
+LL | | since = "1.100.0",
+LL | | reason = "text"
+LL | |
+LL | | )]
+ | |__^
+ |
+ = help: use `#[deprecated]` instead
+
+error: `reason` has been renamed
+ --> $DIR/rustc_deprecated.rs:9:5
+ |
+LL | reason = "text"
+ | ^^^^^^^^^^^^^^^ help: use `note` instead: `note = "text"`
+
+error: aborting due to 2 previous errors
+
| |
| expected reference, found tuple
|
- = note: expected type `&({integer}, {integer})`
- found tuple `(_, _)`
+ = note: expected reference `&({integer}, {integer})`
+ found tuple `(_, _)`
error: aborting due to previous error
| |
| expected a tuple with 2 elements, found one with 3 elements
|
- = note: expected type `({integer}, {integer})`
- found tuple `(_, _, _)`
+ = note: expected tuple `({integer}, {integer})`
+ found tuple `(_, _, _)`
error[E0070]: invalid left-hand side of assignment
--> $DIR/tuple_destructure_fail.rs:7:13
| |
| expected a tuple with 2 elements, found one with 1 element
|
- = note: expected type `({integer}, {integer})`
- found tuple `(_,)`
+ = note: expected tuple `({integer}, {integer})`
+ found tuple `(_,)`
error: aborting due to 4 previous errors
LL | let a = f();
| ^-- an argument is missing
|
+note: closure defined here
+ --> $DIR/E0057.rs:2:13
+ |
+LL | let f = |x| x * 3;
+ | ^^^
help: provide the argument
|
LL | let a = f({_});
LL | let c = f(2, 3);
| ^ - argument unexpected
|
+note: closure defined here
+ --> $DIR/E0057.rs:2:13
+ |
+LL | let f = |x| x * 3;
+ | ^^^
help: remove the extra argument
|
LL | let c = f(2);
+++ /dev/null
-error[E0502]: cannot borrow `*a` as mutable because it is also borrowed as immutable
- --> $DIR/E0502.rs:4:5
- |
-LL | let ref y = a;
- | ----- immutable borrow occurs here
-LL | bar(a);
- | ^^^^^^ mutable borrow occurs here
-LL | y.use_ref();
- | ----------- immutable borrow later used here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0502`.
+++ /dev/null
-fn wants_uniq(x: String) { }
-fn wants_slice(x: &str) { }
-
-fn has_uniq(x: String) {
- wants_uniq(x);
- wants_slice(&*x);
-}
-
-fn has_slice(x: &str) {
- wants_uniq(x); //~ ERROR mismatched types
- wants_slice(x);
-}
-
-fn main() {
-}
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/estr-subtyping.rs:10:15
- |
-LL | wants_uniq(x);
- | ---------- ^- help: try using a conversion method: `.to_string()`
- | | |
- | | expected struct `String`, found `&str`
- | arguments to this function are incorrect
- |
-note: function defined here
- --> $DIR/estr-subtyping.rs:1:4
- |
-LL | fn wants_uniq(x: String) { }
- | ^^^^^^^^^^ ---------
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
fn main() {
eq(foo::<u8>, bar::<u8>);
//~^ ERROR mismatched types
- //~| expected type `fn(_) -> _ {foo::<u8>}`
+ //~| expected fn item `fn(_) -> _ {foo::<u8>}`
//~| found fn item `fn(_) -> _ {bar::<u8>}`
//~| expected fn item, found a different fn item
//~| different `fn` items always have unique types, even if their signatures are the same
eq(bar::<String>, bar::<Vec<u8>>);
//~^ ERROR mismatched types
- //~| expected type `fn(_) -> _ {bar::<String>}`
//~| found fn item `fn(_) -> _ {bar::<Vec<u8>>}`
//~| expected struct `String`, found struct `Vec`
//~| different `fn` items always have unique types, even if their signatures are the same
eq(foo::<u8>, bar::<u8> as fn(isize) -> isize);
//~^ ERROR mismatched types
- //~| expected type `fn(_) -> _ {foo::<u8>}`
//~| found fn pointer `fn(_) -> _`
//~| expected fn item, found fn pointer
//~| change the expected type to be function pointer
| |
| arguments to this function are incorrect
|
- = note: expected type `fn(_) -> _ {foo::<u8>}`
- found fn item `fn(_) -> _ {bar::<u8>}`
+ = note: expected fn item `fn(_) -> _ {foo::<u8>}`
+ found fn item `fn(_) -> _ {bar::<u8>}`
= note: different `fn` items always have unique types, even if their signatures are the same
= help: change the expected type to be function pointer `fn(isize) -> isize`
= help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `foo::<u8> as fn(isize) -> isize`
| |
| arguments to this function are incorrect
|
- = note: expected type `fn(_) -> _ {foo::<u8>}`
- found fn item `fn(_) -> _ {foo::<i8>}`
+ = note: expected fn item `fn(_) -> _ {foo::<u8>}`
+ found fn item `fn(_) -> _ {foo::<i8>}`
= note: different `fn` items always have unique types, even if their signatures are the same
= help: change the expected type to be function pointer `fn(isize) -> isize`
= help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `foo::<u8> as fn(isize) -> isize`
| |
| arguments to this function are incorrect
|
- = note: expected type `fn(_) -> _ {bar::<String>}`
- found fn item `fn(_) -> _ {bar::<Vec<u8>>}`
+ = note: expected fn item `fn(_) -> _ {bar::<String>}`
+ found fn item `fn(_) -> _ {bar::<Vec<u8>>}`
= note: different `fn` items always have unique types, even if their signatures are the same
= help: change the expected type to be function pointer `fn(isize) -> isize`
= help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `bar::<String> as fn(isize) -> isize`
| ^^ ---- ----
error[E0308]: mismatched types
- --> $DIR/fn-item-type.rs:39:26
+ --> $DIR/fn-item-type.rs:38:26
|
LL | eq(<u8 as Foo>::foo, <u16 as Foo>::foo);
| -- ^^^^^^^^^^^^^^^^^ expected `u8`, found `u16`
| |
| arguments to this function are incorrect
|
- = note: expected type `fn() {<u8 as Foo>::foo}`
- found fn item `fn() {<u16 as Foo>::foo}`
+ = note: expected fn item `fn() {<u8 as Foo>::foo}`
+ found fn item `fn() {<u16 as Foo>::foo}`
= note: different `fn` items always have unique types, even if their signatures are the same
= help: change the expected type to be function pointer `fn()`
= help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `<u8 as Foo>::foo as fn()`
| ^^ ---- ----
error[E0308]: mismatched types
- --> $DIR/fn-item-type.rs:46:19
+ --> $DIR/fn-item-type.rs:45:19
|
LL | eq(foo::<u8>, bar::<u8> as fn(isize) -> isize);
| -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn item, found fn pointer
| |
| arguments to this function are incorrect
|
- = note: expected type `fn(_) -> _ {foo::<u8>}`
+ = note: expected fn item `fn(_) -> _ {foo::<u8>}`
found fn pointer `fn(_) -> _`
= help: change the expected type to be function pointer `fn(isize) -> isize`
= help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `foo::<u8> as fn(isize) -> isize`
LL | 5
| ^ expected enum `Result`, found integer
|
- = note: expected type `Result<{integer}, _>`
+ = note: expected enum `Result<{integer}, _>`
found type `{integer}`
note: return type inferred to be `Result<{integer}, _>` here
--> $DIR/type-mismatch-signature-deduction.rs:9:20
--- /dev/null
+#![feature(generic_associated_types)]
+
+trait Trait {
+ type Foo<const N: u8>;
+}
+
+impl Trait for () {
+ type Foo<const N: u64> = u32;
+ //~^ error: type `Foo` has an incompatible generic parameter for trait
+}
+
+fn main() {}
--- /dev/null
+error[E0053]: type `Foo` has an incompatible generic parameter for trait `Trait`
+ --> $DIR/const_params_have_right_type.rs:8:14
+ |
+LL | trait Trait {
+ | -----
+LL | type Foo<const N: u8>;
+ | ----------- expected const parameter of type `u8`
+...
+LL | impl Trait for () {
+ | -----------------
+LL | type Foo<const N: u64> = u32;
+ | ^^^^^^^^^^^^ found const parameter of type `u64`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0053`.
|
LL | fn bar<T>(_: T) {}
| ^^^ ----
+help: you can convert a `usize` to an `isize` and panic if the converted value doesn't fit
+ |
+LL | bar::<isize>(i.try_into().unwrap()); // i should not be re-coerced back to an isize
+ | ++++++++++++++++++++
error: aborting due to 2 previous errors
|
LL | fn foo(_s: i16) { }
| ^^^ -------
+help: you can convert an `isize` to an `i16` and panic if the converted value doesn't fit
+ |
+LL | foo((1*(1 as isize)).try_into().unwrap());
+ | + +++++++++++++++++++++
error[E0308]: mismatched types
--> $DIR/issue-13359.rs:10:9
|
LL | fn bar(_s: u32) { }
| ^^^ -------
+help: you can convert a `usize` to a `u32` and panic if the converted value doesn't fit
+ |
+LL | bar((1*(1 as usize)).try_into().unwrap());
+ | + +++++++++++++++++++++
error: aborting due to 2 previous errors
+++ /dev/null
-// run-pass
-// ignore-emscripten no processes
-// ignore-sgx no processes
-
-use std::env;
-use std::process::Command;
-use std::io::{self, Write};
-
-fn main() {
- let mut args = env::args();
- if args.len() > 1 {
- let mut out = io::stdout();
- out.write(&['a' as u8; 128 * 1024]).unwrap();
- } else {
- let out = Command::new(&args.next().unwrap()).arg("child").output();
- let out = out.unwrap();
- assert!(out.status.success());
- }
-}
+++ /dev/null
-// Regression test: issue had to do with "givens" in region inference,
-// which were not being considered during the contraction phase.
-
-// run-fail
-// error-pattern:explicit panic
-// ignore-emscripten no processes
-
-struct Parser<'i: 't, 't>(&'i u8, &'t u8);
-
-impl<'i, 't> Parser<'i, 't> {
- fn parse_nested_block<F, T>(&mut self, parse: F) -> Result<T, ()>
- where for<'tt> F: FnOnce(&mut Parser<'i, 'tt>) -> T
- {
- panic!()
- }
-
- fn expect_exhausted(&mut self) -> Result<(), ()> {
- Ok(())
- }
-}
-
-fn main() {
- let x = 0u8;
- Parser(&x, &x).parse_nested_block(|input| input.expect_exhausted()).unwrap();
-}
+++ /dev/null
-#[macro_export]
-macro_rules! foo { ($i:ident) => {} }
-
-#[macro_export]
-macro_rules! foo { () => {} } //~ ERROR the name `foo` is defined multiple times
-
-fn main() {}
+++ /dev/null
-error[E0428]: the name `foo` is defined multiple times
- --> $DIR/issue-38715.rs:5:1
- |
-LL | macro_rules! foo { ($i:ident) => {} }
- | ---------------- previous definition of the macro `foo` here
-...
-LL | macro_rules! foo { () => {} }
- | ^^^^^^^^^^^^^^^^ `foo` redefined here
- |
- = note: `foo` must be defined only once in the macro namespace of this module
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0428`.
+++ /dev/null
-fn flatten<'a, 'b, T>(x: &'a &'b T) -> &'a T {
- x
-}
-
-fn main() {
- let mut x = "original";
- let y = &x;
- let z = &y;
- let w = flatten(z);
- x = "modified";
- //~^ ERROR cannot assign to `x` because it is borrowed [E0506]
- println!("{}", w); // prints "modified"
-}
+++ /dev/null
-error[E0506]: cannot assign to `x` because it is borrowed
- --> $DIR/issue-48803.rs:10:5
- |
-LL | let y = &x;
- | -- borrow of `x` occurs here
-...
-LL | x = "modified";
- | ^^^^^^^^^^^^^^ assignment to borrowed `x` occurs here
-LL |
-LL | println!("{}", w); // prints "modified"
- | - borrow later used here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0506`.
+++ /dev/null
-error: lifetime may not live long enough
- --> $DIR/issue-52533-1.rs:9:18
- |
-LL | gimme(|x, y| y)
- | - - ^ closure was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
- | | |
- | | has type `&Foo<'_, '1, u32>`
- | has type `&Foo<'_, '2, u32>`
-
-error: aborting due to previous error
-
+++ /dev/null
-#![allow(warnings)]
-
-struct Foo<'a, 'b, T: 'a + 'b> { x: &'a T, y: &'b T }
-
-fn gimme(_: impl for<'a, 'b, 'c> FnOnce(&'a Foo<'a, 'b, u32>,
- &'a Foo<'a, 'c, u32>) -> &'a Foo<'a, 'b, u32>) { }
-
-fn main() {
- gimme(|x, y| y)
- //~^ ERROR mismatched types [E0308]
-}
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/issue-52533-1.rs:9:18
- |
-LL | gimme(|x, y| y)
- | ^ lifetime mismatch
- |
- = note: expected reference `&Foo<'_, '_, u32>`
- found reference `&Foo<'_, '_, u32>`
-note: the anonymous lifetime #3 defined here...
- --> $DIR/issue-52533-1.rs:9:11
- |
-LL | gimme(|x, y| y)
- | ^^^^^^^^
-note: ...does not necessarily outlive the anonymous lifetime #2 defined here
- --> $DIR/issue-52533-1.rs:9:11
- |
-LL | gimme(|x, y| y)
- | ^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
+++ /dev/null
-// Creating a stack closure which references a box and then
-// transferring ownership of the box before invoking the stack
-// closure results in a crash.
-
-#![feature(box_syntax)]
-
-fn twice(x: Box<usize>) -> usize {
- *x * 2
-}
-
-fn invoke<F>(f: F) where F: FnOnce() -> usize {
- f();
-}
-
-fn main() {
- let x : Box<usize> = box 9;
- let sq = || { *x * *x };
-
- twice(x); //~ ERROR: cannot move out of
- invoke(sq);
-}
+++ /dev/null
-error[E0505]: cannot move out of `x` because it is borrowed
- --> $DIR/issue-6801.rs:19:13
- |
-LL | let sq = || { *x * *x };
- | -- -- borrow occurs due to use in closure
- | |
- | borrow of `x` occurs here
-LL |
-LL | twice(x);
- | ^ move out of `x` occurs here
-LL | invoke(sq);
- | -- borrow later used here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0505`.
variants: Single {
index: 0,
},
- abi: Aggregate {
- sized: true,
- },
+ abi: ScalarPair(
+ Initialized {
+ value: Int(
+ I32,
+ false,
+ ),
+ valid_range: 0..=1,
+ },
+ Initialized {
+ value: Int(
+ I32,
+ true,
+ ),
+ valid_range: 0..=4294967295,
+ },
+ ),
largest_niche: None,
align: AbiAndPrefAlign {
abi: Align(4 bytes),
variants: Single {
index: 1,
},
- abi: Aggregate {
- sized: true,
- },
+ abi: ScalarPair(
+ Initialized {
+ value: Int(
+ I32,
+ false,
+ ),
+ valid_range: 0..=1,
+ },
+ Initialized {
+ value: Int(
+ I32,
+ true,
+ ),
+ valid_range: 0..=4294967295,
+ },
+ ),
largest_niche: None,
align: AbiAndPrefAlign {
abi: Align(4 bytes),
variants: Single {
index: 0,
},
- abi: Aggregate {
- sized: true,
- },
+ abi: ScalarPair(
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=1,
+ },
+ Union {
+ value: Int(
+ I8,
+ false,
+ ),
+ },
+ ),
largest_niche: None,
align: AbiAndPrefAlign {
abi: Align(1 bytes),
variants: Single {
index: 0,
},
- abi: Aggregate {
- sized: true,
- },
+ abi: ScalarPair(
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=1,
+ },
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=255,
+ },
+ ),
largest_niche: None,
align: AbiAndPrefAlign {
abi: Align(1 bytes),
variants: Single {
index: 1,
},
- abi: Aggregate {
- sized: true,
- },
+ abi: ScalarPair(
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=1,
+ },
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=255,
+ },
+ ),
largest_niche: None,
align: AbiAndPrefAlign {
abi: Align(1 bytes),
variants: Single {
index: 0,
},
- abi: Aggregate {
- sized: true,
- },
+ abi: ScalarPair(
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=1,
+ },
+ Union {
+ value: Int(
+ I8,
+ false,
+ ),
+ },
+ ),
largest_niche: None,
align: AbiAndPrefAlign {
abi: Align(1 bytes),
variants: Single {
index: 1,
},
- abi: Aggregate {
- sized: true,
- },
+ abi: ScalarPair(
+ Initialized {
+ value: Int(
+ I8,
+ false,
+ ),
+ valid_range: 0..=1,
+ },
+ Union {
+ value: Int(
+ I8,
+ false,
+ ),
+ },
+ ),
largest_niche: None,
align: AbiAndPrefAlign {
abi: Align(1 bytes),
| ^^^^^^^^^^^ expected `!`, found enum `Option`
|
= note: expected type `!`
- found type `Option<{integer}>`
+ found enum `Option<{integer}>`
= help: try adding a diverging expression, such as `return` or `panic!(..)`
= help: ...or use `match` instead of `let...else`
LL | | };
| |_____^ expected `!`, found `()`
|
- = note: expected type `!`
- found type `()`
+ = note: expected type `!`
+ found unit type `()`
= help: try adding a diverging expression, such as `return` or `panic!(..)`
= help: ...or use `match` instead of `let...else`
| |_____^ expected `!`, found enum `Option`
|
= note: expected type `!`
- found type `Option<{integer}>`
+ found enum `Option<{integer}>`
= help: try adding a diverging expression, such as `return` or `panic!(..)`
= help: ...or use `match` instead of `let...else`
--- /dev/null
+// check-pass
+#![feature(lint_reasons)]
+
+//! This file tests the `#[expect]` attribute implementation for tool lints. The same
+//! file is used to test clippy and rustdoc. Any changes to this file should be synced
+//! to the other test files.
+//!
+//! Expectations:
+//! * rustc: only rustc lint expectations are emitted
+//! * clippy: rustc and Clippy's expectations are emitted
+//! * rustdoc: only rustdoc lint expectations are emitted
+//!
+//! This test can't cover every lint from Clippy, rustdoc and potentially other
+//! tools that will be developed. This therefore only tests a small subset of lints
+
+#![expect(rustdoc::missing_crate_level_docs)]
+
+mod rustc_ok {
+ //! See <https://doc.rust-lang.org/rustc/lints/index.html>
+
+ #[expect(dead_code)]
+ pub fn rustc_lints() {
+ let x = 42.0;
+
+ #[expect(illegal_floating_point_literal_pattern)]
+ match x {
+ 5.0 => {}
+ 6.0 => {}
+ _ => {}
+ }
+ }
+}
+
+mod rustc_warn {
+ //! See <https://doc.rust-lang.org/rustc/lints/index.html>
+
+ #[expect(dead_code)]
+ //~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+ //~| NOTE `#[warn(unfulfilled_lint_expectations)]` on by default
+ pub fn rustc_lints() {
+ let x = 42;
+
+ #[expect(illegal_floating_point_literal_pattern)]
+ //~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+ match x {
+ 5 => {}
+ 6 => {}
+ _ => {}
+ }
+ }
+}
+
+pub mod rustdoc_ok {
+ //! See <https://doc.rust-lang.org/rustdoc/lints.html>
+
+ #[expect(rustdoc::broken_intra_doc_links)]
+ /// I want to link to [`Nonexistent`] but it doesn't exist!
+ pub fn foo() {}
+
+ #[expect(rustdoc::invalid_html_tags)]
+ /// <h1>
+ pub fn bar() {}
+
+ #[expect(rustdoc::bare_urls)]
+ /// http://example.org
+ pub fn baz() {}
+}
+
+pub mod rustdoc_warn {
+ //! See <https://doc.rust-lang.org/rustdoc/lints.html>
+
+ #[expect(rustdoc::broken_intra_doc_links)]
+ /// I want to link to [`bar`] but it doesn't exist!
+ pub fn foo() {}
+
+ #[expect(rustdoc::invalid_html_tags)]
+ /// <h1></h1>
+ pub fn bar() {}
+
+ #[expect(rustdoc::bare_urls)]
+ /// <http://example.org>
+ pub fn baz() {}
+}
+
+mod clippy_ok {
+ //! See <https://rust-lang.github.io/rust-clippy/master/index.html>
+
+ #[expect(clippy::almost_swapped)]
+ fn foo() {
+ let mut a = 0;
+ let mut b = 9;
+ a = b;
+ b = a;
+ }
+
+ #[expect(clippy::bytes_nth)]
+ fn bar() {
+ let _ = "Hello".bytes().nth(3);
+ }
+
+ #[expect(clippy::if_same_then_else)]
+ fn baz() {
+ let _ = if true {
+ 42
+ } else {
+ 42
+ };
+ }
+
+ #[expect(clippy::logic_bug)]
+ fn burger() {
+ let a = false;
+ let b = true;
+
+ if a && b || a {}
+ }
+}
+
+mod clippy_warn {
+ //! See <https://rust-lang.github.io/rust-clippy/master/index.html>
+
+ #[expect(clippy::almost_swapped)]
+ fn foo() {
+ let mut a = 0;
+ let mut b = 9;
+ a = b;
+ }
+
+ #[expect(clippy::bytes_nth)]
+ fn bar() {
+ let _ = "Hello".as_bytes().get(3);
+ }
+
+ #[expect(clippy::if_same_then_else)]
+ fn baz() {
+ let _ = if true {
+ 33
+ } else {
+ 42
+ };
+ }
+
+ #[expect(clippy::logic_bug)]
+ fn burger() {
+ let a = false;
+ let b = true;
+ let c = false;
+
+ if a && b || c {}
+ }
+}
+
+fn main() {
+ rustc_warn::rustc_lints();
+}
--- /dev/null
+warning: this lint expectation is unfulfilled
+ --> $DIR/expect_tool_lint_rfc_2383.rs:37:14
+ |
+LL | #[expect(dead_code)]
+ | ^^^^^^^^^
+ |
+ = note: `#[warn(unfulfilled_lint_expectations)]` on by default
+
+warning: this lint expectation is unfulfilled
+ --> $DIR/expect_tool_lint_rfc_2383.rs:43:18
+ |
+LL | #[expect(illegal_floating_point_literal_pattern)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: 2 warnings emitted
+
--- /dev/null
+// This ensures that ICEs like rust#94953 don't happen
+// check-pass
+// compile-flags: -Z unpretty=expanded
+
+#![feature(lint_reasons)]
+
+// This `expect` will create an expectation with an unstable expectation id
+#[expect(while_true)]
+fn create_early_lint_pass_expectation() {
+ // `while_true` is an early lint
+ while true {}
+}
+
+fn main() {
+ create_early_lint_pass_expectation();
+}
--- /dev/null
+#![feature(prelude_import)]
+#![no_std]
+// This ensures that ICEs like rust#94953 don't happen
+// check-pass
+// compile-flags: -Z unpretty=expanded
+
+#![feature(lint_reasons)]
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
+#[macro_use]
+extern crate std;
+
+// This `expect` will create an expectation with an unstable expectation id
+#[expect(while_true)]
+fn create_early_lint_pass_expectation() {
+ // `while_true` is an early lint
+ while true {}
+}
+
+fn main() { create_early_lint_pass_expectation(); }
--- /dev/null
+#![deny(unused_attributes)]
+#![crate_type = "lib"]
+// run-rustfix
+
+pub trait Trait {
+ type It;
+ const IT: ();
+ fn it0();
+ fn it1();
+ fn it2();
+}
+
+pub struct Implementor;
+
+impl Trait for Implementor {
+
+ type It = ();
+ //~^^ ERROR `#[doc(hidden)]` is ignored
+ //~| WARNING this was previously accepted
+
+
+ const IT: () = ();
+ //~^^ ERROR `#[doc(hidden)]` is ignored
+ //~| WARNING this was previously accepted
+
+ #[doc(alias = "aka")]
+ fn it0() {}
+ //~^^ ERROR `#[doc(hidden)]` is ignored
+ //~| WARNING this was previously accepted
+
+ #[doc(alias = "this", )]
+ fn it1() {}
+ //~^^ ERROR `#[doc(hidden)]` is ignored
+ //~| WARNING this was previously accepted
+
+ #[doc()]
+ fn it2() {}
+ //~^^ ERROR `#[doc(hidden)]` is ignored
+ //~| WARNING this was previously accepted
+ //~| ERROR `#[doc(hidden)]` is ignored
+ //~| WARNING this was previously accepted
+}
--- /dev/null
+#![deny(unused_attributes)]
+#![crate_type = "lib"]
+// run-rustfix
+
+pub trait Trait {
+ type It;
+ const IT: ();
+ fn it0();
+ fn it1();
+ fn it2();
+}
+
+pub struct Implementor;
+
+impl Trait for Implementor {
+ #[doc(hidden)]
+ type It = ();
+ //~^^ ERROR `#[doc(hidden)]` is ignored
+ //~| WARNING this was previously accepted
+
+ #[doc(hidden)]
+ const IT: () = ();
+ //~^^ ERROR `#[doc(hidden)]` is ignored
+ //~| WARNING this was previously accepted
+
+ #[doc(hidden, alias = "aka")]
+ fn it0() {}
+ //~^^ ERROR `#[doc(hidden)]` is ignored
+ //~| WARNING this was previously accepted
+
+ #[doc(alias = "this", hidden,)]
+ fn it1() {}
+ //~^^ ERROR `#[doc(hidden)]` is ignored
+ //~| WARNING this was previously accepted
+
+ #[doc(hidden, hidden)]
+ fn it2() {}
+ //~^^ ERROR `#[doc(hidden)]` is ignored
+ //~| WARNING this was previously accepted
+ //~| ERROR `#[doc(hidden)]` is ignored
+ //~| WARNING this was previously accepted
+}
--- /dev/null
+error: `#[doc(hidden)]` is ignored on trait impl items
+ --> $DIR/unused-attr-doc-hidden.rs:16:5
+ |
+LL | #[doc(hidden)]
+ | ^^^^^^^^^^^^^^ help: remove this attribute
+ |
+note: the lint level is defined here
+ --> $DIR/unused-attr-doc-hidden.rs:1:9
+ |
+LL | #![deny(unused_attributes)]
+ | ^^^^^^^^^^^^^^^^^
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: whether the impl item is `doc(hidden)` or not entirely depends on the corresponding trait item
+
+error: `#[doc(hidden)]` is ignored on trait impl items
+ --> $DIR/unused-attr-doc-hidden.rs:21:5
+ |
+LL | #[doc(hidden)]
+ | ^^^^^^^^^^^^^^ help: remove this attribute
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: whether the impl item is `doc(hidden)` or not entirely depends on the corresponding trait item
+
+error: `#[doc(hidden)]` is ignored on trait impl items
+ --> $DIR/unused-attr-doc-hidden.rs:26:11
+ |
+LL | #[doc(hidden, alias = "aka")]
+ | ^^^^^^--
+ | |
+ | help: remove this attribute
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: whether the impl item is `doc(hidden)` or not entirely depends on the corresponding trait item
+
+error: `#[doc(hidden)]` is ignored on trait impl items
+ --> $DIR/unused-attr-doc-hidden.rs:31:27
+ |
+LL | #[doc(alias = "this", hidden,)]
+ | ^^^^^^-
+ | |
+ | help: remove this attribute
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: whether the impl item is `doc(hidden)` or not entirely depends on the corresponding trait item
+
+error: `#[doc(hidden)]` is ignored on trait impl items
+ --> $DIR/unused-attr-doc-hidden.rs:36:11
+ |
+LL | #[doc(hidden, hidden)]
+ | ^^^^^^--
+ | |
+ | help: remove this attribute
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: whether the impl item is `doc(hidden)` or not entirely depends on the corresponding trait item
+
+error: `#[doc(hidden)]` is ignored on trait impl items
+ --> $DIR/unused-attr-doc-hidden.rs:36:19
+ |
+LL | #[doc(hidden, hidden)]
+ | ^^^^^^ help: remove this attribute
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: whether the impl item is `doc(hidden)` or not entirely depends on the corresponding trait item
+
+error: aborting due to 6 previous errors
+
--- /dev/null
+#[macro_export]
+macro_rules! foo { ($i:ident) => {} }
+
+#[macro_export]
+macro_rules! foo { () => {} } //~ ERROR the name `foo` is defined multiple times
+
+fn main() {}
--- /dev/null
+error[E0428]: the name `foo` is defined multiple times
+ --> $DIR/issue-38715.rs:5:1
+ |
+LL | macro_rules! foo { ($i:ident) => {} }
+ | ---------------- previous definition of the macro `foo` here
+...
+LL | macro_rules! foo { () => {} }
+ | ^^^^^^^^^^^^^^^^ `foo` redefined here
+ |
+ = note: `foo` must be defined only once in the macro namespace of this module
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0428`.
LL | fn write(fildes: i32, buf: *const i8, nbyte: u64) -> i64;
| ^^^^^
= note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: you can convert a `usize` to a `u64` and panic if the converted value doesn't fit
+ |
+LL | ($arr.len() * size_of($arr[0])).try_into().unwrap());
+ | + +++++++++++++++++++++
error[E0605]: non-primitive cast: `{integer}` as `()`
--> $DIR/issue-26480.rs:22:19
--- /dev/null
+error[E0601]: `main` function not found in crate `continue_after_missing_main`
+ --> $DIR/continue-after-missing-main.rs:30:2
+ |
+LL | }
+ | ^ consider adding a `main` function to `$DIR/continue-after-missing-main.rs`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0601`.
--- /dev/null
+#![allow(dead_code)]
+
+struct Tableau<'a, MP> {
+ provider: &'a MP,
+}
+
+impl<'adapted_matrix_provider, 'original_data, MP>
+ Tableau<'adapted_matrix_provider, AdaptedMatrixProvider<'original_data, MP>>
+{
+ fn provider(&self) -> &'adapted_matrix_provider AdaptedMatrixProvider</*'original_data,*/ MP> {
+ self.provider
+ }
+}
+
+struct AdaptedMatrixProvider<'a, T> {
+ original_problem: &'a T,
+}
+
+impl<'a, T> AdaptedMatrixProvider<'a, T> {
+ fn clone_with_extra_bound(&self) -> Self {
+ AdaptedMatrixProvider { original_problem: self.original_problem }
+ }
+}
+
+fn create_and_solve_subproblems<'data_provider, 'original_data, MP>(
+ tableau: Tableau<'data_provider, AdaptedMatrixProvider<'original_data, MP>>,
+) {
+ let _: AdaptedMatrixProvider<'original_data, MP> = tableau.provider().clone_with_extra_bound();
+ //~^ ERROR lifetime mismatch
+} //~ ERROR `main` function not found in crate
--- /dev/null
+error[E0601]: `main` function not found in crate `continue_after_missing_main`
+ --> $DIR/continue-after-missing-main.rs:30:2
+ |
+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 | tableau: Tableau<'data_provider, AdaptedMatrixProvider<'original_data, MP>>,
+ | ------------------------------------------------------------------ these two types are declared with different lifetimes...
+LL | ) {
+LL | let _: AdaptedMatrixProvider<'original_data, MP> = tableau.provider().clone_with_extra_bound();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...but data from `tableau` flows into `tableau` here
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0601, E0623.
+For more information about an error, try `rustc --explain E0601`.
--- /dev/null
+fn flatten<'a, 'b, T>(x: &'a &'b T) -> &'a T {
+ x
+}
+
+fn main() {
+ let mut x = "original";
+ let y = &x;
+ let z = &y;
+ let w = flatten(z);
+ x = "modified";
+ //~^ ERROR cannot assign to `x` because it is borrowed [E0506]
+ println!("{}", w); // prints "modified"
+}
--- /dev/null
+error[E0506]: cannot assign to `x` because it is borrowed
+ --> $DIR/issue-48803.rs:10:5
+ |
+LL | let y = &x;
+ | -- borrow of `x` occurs here
+...
+LL | x = "modified";
+ | ^^^^^^^^^^^^^^ assignment to borrowed `x` occurs here
+LL |
+LL | println!("{}", w); // prints "modified"
+ | - borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0506`.
--- /dev/null
+error: lifetime may not live long enough
+ --> $DIR/issue-52533-1.rs:9:18
+ |
+LL | gimme(|x, y| y)
+ | - - ^ closure was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ | | |
+ | | has type `&Foo<'_, '1, u32>`
+ | has type `&Foo<'_, '2, u32>`
+
+error: aborting due to previous error
+
--- /dev/null
+#![allow(warnings)]
+
+struct Foo<'a, 'b, T: 'a + 'b> { x: &'a T, y: &'b T }
+
+fn gimme(_: impl for<'a, 'b, 'c> FnOnce(&'a Foo<'a, 'b, u32>,
+ &'a Foo<'a, 'c, u32>) -> &'a Foo<'a, 'b, u32>) { }
+
+fn main() {
+ gimme(|x, y| y)
+ //~^ ERROR mismatched types [E0308]
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-52533-1.rs:9:18
+ |
+LL | gimme(|x, y| y)
+ | ^ lifetime mismatch
+ |
+ = note: expected reference `&Foo<'_, '_, u32>`
+ found reference `&Foo<'_, '_, u32>`
+note: the anonymous lifetime #3 defined here...
+ --> $DIR/issue-52533-1.rs:9:11
+ |
+LL | gimme(|x, y| y)
+ | ^^^^^^^^
+note: ...does not necessarily outlive the anonymous lifetime #2 defined here
+ --> $DIR/issue-52533-1.rs:9:11
+ |
+LL | gimme(|x, y| y)
+ | ^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
| first introduced with type `{integer}` here
|
= note: expected type `{integer}`
- found type `E<{integer}>`
+ found enum `E<{integer}>`
= note: a binding must have the same type in all alternatives
error: aborting due to 15 previous errors
| | types differ in mutability
| first introduced with type `&&u8` here
|
- = note: expected type `&&u8`
- found type `&mut &mut u8`
+ = note: expected reference `&&u8`
+ found mutable reference `&mut &mut u8`
= note: a binding must have the same type in all alternatives
error[E0308]: mismatched types
| | types differ in mutability
| first introduced with type `&{integer}` here
|
- = note: expected type `&{integer}`
- found type `&mut _`
+ = note: expected reference `&{integer}`
+ found mutable reference `&mut _`
= note: a binding must have the same type in all alternatives
error: aborting due to 9 previous errors
| | |
| | expected integer, found floating-point number
| this is of type `u8`
+ |
+ = note: expected type `u8`
+ found type `{float}`
error[E0029]: only `char` and numeric types are allowed in range patterns
--> $DIR/recover-range-pats.rs:33:12
| | |
| | expected integer, found floating-point number
| this is of type `u8`
+ |
+ = note: expected type `u8`
+ found type `{float}`
error[E0029]: only `char` and numeric types are allowed in range patterns
--> $DIR/recover-range-pats.rs:54:12
| | |
| | expected integer, found floating-point number
| this is of type `u8`
+ |
+ = note: expected type `u8`
+ found type `{float}`
error[E0029]: only `char` and numeric types are allowed in range patterns
--> $DIR/recover-range-pats.rs:73:12
--- /dev/null
+// run-pass
+// ignore-emscripten no processes
+// ignore-sgx no processes
+
+use std::env;
+use std::process::Command;
+use std::io::{self, Write};
+
+fn main() {
+ let mut args = env::args();
+ if args.len() > 1 {
+ let mut out = io::stdout();
+ out.write(&['a' as u8; 128 * 1024]).unwrap();
+ } else {
+ let out = Command::new(&args.next().unwrap()).arg("child").output();
+ let out = out.unwrap();
+ assert!(out.status.success());
+ }
+}
LL | std::intrinsics::unlikely,
| ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot coerce intrinsics to function pointers
|
- = note: expected type `extern "rust-intrinsic" fn(_) -> _ {likely}`
- found fn item `extern "rust-intrinsic" fn(_) -> _ {unlikely}`
+ = note: expected fn item `extern "rust-intrinsic" fn(_) -> _ {likely}`
+ found fn item `extern "rust-intrinsic" fn(_) -> _ {unlikely}`
error: aborting due to 3 previous errors
| |
| first introduced with type `&mut isize` here
|
- = note: expected type `&mut isize`
- found type `&isize`
+ = note: expected mutable reference `&mut isize`
+ found reference `&isize`
= note: in the same arm, a binding must have the same type in all alternatives
error: aborting due to 6 previous errors
LL | "abc" => true,
| ^^^^^ expected `&str`, found `str`
|
- = note: expected type `&&str`
- found reference `&'static str`
+ = note: expected reference `&&str`
+ found reference `&'static str`
error[E0308]: mismatched types
--> $DIR/lit.rs:16:9
LL | b"abc" => true,
| ^^^^^^ expected `&[u8]`, found array `[u8; 3]`
|
- = note: expected type `&&[u8]`
- found reference `&'static [u8; 3]`
+ = note: expected reference `&&[u8]`
+ found reference `&'static [u8; 3]`
error: aborting due to 2 previous errors
--- /dev/null
+pub fn foo() {}
+
+#[macro_export]
+macro_rules! gimme_a {
+ ($($mac:tt)*) => { $($mac)* { 'a } }
+}
--- /dev/null
+// edition:2018
+// aux-build:edition-lint-infer-outlives-macro.rs
+
+// Test that the lint does not fire if the where predicate
+// is from the local crate, but all the bounds are from an
+// external macro.
+
+#![deny(explicit_outlives_requirements)]
+
+#[macro_use]
+extern crate edition_lint_infer_outlives_macro;
+
+macro_rules! make_foo {
+ ($a:tt) => {
+ struct Foo<$a, 'b> where 'b: $a {
+ foo: &$a &'b (),
+ }
+ }
+}
+
+gimme_a! {make_foo!}
+
+struct Bar<'a, 'b: 'a> {
+ //~^ ERROR: outlives requirements can be inferred
+ bar: &'a &'b (),
+}
+
+fn main() {}
--- /dev/null
+error: outlives requirements can be inferred
+ --> $DIR/edition-lint-infer-outlives-macro.rs:23:18
+ |
+LL | struct Bar<'a, 'b: 'a> {
+ | ^^^^ help: remove this bound
+ |
+note: the lint level is defined here
+ --> $DIR/edition-lint-infer-outlives-macro.rs:8:9
+ |
+LL | #![deny(explicit_outlives_requirements)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+++ /dev/null
-fn main() {
- let f = |x| x * 3;
- let a = f(); //~ ERROR E0057
- let b = f(4);
- let c = f(2, 3); //~ ERROR E0057
-}
+++ /dev/null
-error[E0057]: this function takes 1 argument but 0 arguments were supplied
- --> $DIR/E0057.rs:3:13
- |
-LL | let a = f();
- | ^-- an argument is missing
- |
-help: provide the argument
- |
-LL | let a = f({_});
- | ~~~~~~
-
-error[E0057]: this function takes 1 argument but 2 arguments were supplied
- --> $DIR/E0057.rs:5:13
- |
-LL | let c = f(2, 3);
- | ^ - argument unexpected
- |
-help: remove the extra argument
- |
-LL | let c = f(2);
- | ~~~~
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0057`.
#[stable(feature = "a", since = "b")] //~ ERROR invalid stability version found
#[deprecated(since = "b", note = "text")]
-#[deprecated(since = "b", note = "text")] //~ ERROR multiple deprecated attributes
+#[deprecated(since = "b", note = "text")] //~ ERROR multiple `deprecated` attributes
#[rustc_const_unstable(feature = "c", issue = "none")]
#[rustc_const_unstable(feature = "d", issue = "none")] //~ ERROR multiple stability levels
pub const fn multiple4() { }
+error: multiple `deprecated` attributes
+ --> $DIR/stability-attribute-sanity.rs:62:1
+ |
+LL | #[deprecated(since = "b", note = "text")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+ |
+note: attribute also specified here
+ --> $DIR/stability-attribute-sanity.rs:61:1
+ |
+LL | #[deprecated(since = "b", note = "text")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
error[E0541]: unknown meta item 'reason'
--> $DIR/stability-attribute-sanity.rs:8:42
|
LL | #[stable(feature = "a", since = "b")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error[E0550]: multiple deprecated attributes
- --> $DIR/stability-attribute-sanity.rs:62:1
- |
-LL | #[deprecated(since = "b", note = "text")]
- | ----------------------------------------- first deprecation attribute
-LL | #[deprecated(since = "b", note = "text")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ repeated deprecation attribute
-
error[E0544]: multiple stability levels
--> $DIR/stability-attribute-sanity.rs:64:1
|
error: aborting due to 20 previous errors
-Some errors have detailed explanations: E0539, E0541, E0542, E0543, E0544, E0546, E0547, E0549, E0550.
+Some errors have detailed explanations: E0539, E0541, E0542, E0543, E0544, E0546, E0547, E0549.
For more information about an error, try `rustc --explain E0539`.
|
LL | pub async fn answer_str(&self, _s: &str) -> Test {
| ^^^^ checked the `Output` of this `async fn`, found opaque type
- = note: expected type `()`
- found opaque type `impl Future<Output = Test>`
+ = note: expected unit type `()`
+ found opaque type `impl Future<Output = Test>`
error: aborting due to previous error
--- /dev/null
+// edition:2018
+
+async fn f() {
+ m::f1().await; //~ ERROR `()` is not a future
+ m::f2().await; //~ ERROR `()` is not a future
+ m::f3().await; //~ ERROR `()` is not a future
+}
+
+mod m {
+ pub fn f1() {}
+
+ pub(crate) fn f2() {}
+
+ pub
+ fn
+ f3() {}
+}
+
+fn main() {}
--- /dev/null
+error[E0277]: `()` is not a future
+ --> $DIR/issue-96555.rs:4:12
+ |
+LL | m::f1().await;
+ | -------^^^^^^ `()` is not a future
+ | |
+ | this call returns `()`
+ |
+ = help: the trait `Future` is not implemented for `()`
+ = note: () must be a future or must implement `IntoFuture` to be awaited
+ = note: required because of the requirements on the impl of `IntoFuture` for `()`
+help: remove the `.await`
+ |
+LL - m::f1().await;
+LL + m::f1();
+ |
+help: alternatively, consider making `fn f1` asynchronous
+ |
+LL | pub async fn f1() {}
+ | +++++
+
+error[E0277]: `()` is not a future
+ --> $DIR/issue-96555.rs:5:12
+ |
+LL | m::f2().await;
+ | -------^^^^^^ `()` is not a future
+ | |
+ | this call returns `()`
+ |
+ = help: the trait `Future` is not implemented for `()`
+ = note: () must be a future or must implement `IntoFuture` to be awaited
+ = note: required because of the requirements on the impl of `IntoFuture` for `()`
+help: remove the `.await`
+ |
+LL - m::f2().await;
+LL + m::f2();
+ |
+help: alternatively, consider making `fn f2` asynchronous
+ |
+LL | pub(crate) async fn f2() {}
+ | +++++
+
+error[E0277]: `()` is not a future
+ --> $DIR/issue-96555.rs:6:12
+ |
+LL | m::f3().await;
+ | -------^^^^^^ `()` is not a future
+ | |
+ | this call returns `()`
+ |
+ = help: the trait `Future` is not implemented for `()`
+ = note: () must be a future or must implement `IntoFuture` to be awaited
+ = note: required because of the requirements on the impl of `IntoFuture` for `()`
+help: remove the `.await`
+ |
+LL - m::f3().await;
+LL + m::f3();
+ |
+help: alternatively, consider making `fn f3` asynchronous
+ |
+LL | pub async
+ | +++++
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
async fn async_dummy() {} //~ NOTE checked the `Output` of this `async fn`, found opaque type
//~| NOTE while checking the return type of the `async fn`
//~| NOTE in this expansion of desugaring of `async` block or function
+//~| NOTE checked the `Output` of this `async fn`, expected opaque type
+//~| NOTE while checking the return type of the `async fn`
+//~| NOTE in this expansion of desugaring of `async` block or function
async fn async_dummy2() {} //~ NOTE checked the `Output` of this `async fn`, found opaque type
//~| NOTE checked the `Output` of this `async fn`, found opaque type
//~| NOTE while checking the return type of the `async fn`
}
false => async_dummy(), //~ ERROR `match` arms have incompatible types
//~^ NOTE expected `()`, found opaque type
- //~| NOTE expected type `()`
+ //~| NOTE expected unit type `()`
//~| HELP consider `await`ing on the `Future`
};
}
}
false => async_dummy2(), //~ ERROR `match` arms have incompatible types
//~^ NOTE expected `()`, found opaque type
- //~| NOTE expected type `()`
+ //~| NOTE expected unit type `()`
//~| HELP consider `await`ing on the `Future`
};
}
//~| HELP consider `await`ing on both `Future`s
false => async_dummy2(), //~ ERROR `match` arms have incompatible types
//~^ NOTE expected opaque type, found a different opaque type
- //~| NOTE expected type `impl Future<Output = ()>`
+ //~| NOTE expected opaque type `impl Future<Output = ()>`
//~| NOTE distinct uses of `impl Trait` result in different opaque types
};
}
error[E0308]: `match` arms have incompatible types
- --> $DIR/match-prev-arm-needing-semi.rs:32:18
+ --> $DIR/match-prev-arm-needing-semi.rs:35:18
|
LL | let _ = match true {
| _____________-
|
LL | async fn async_dummy() {}
| ^ checked the `Output` of this `async fn`, found opaque type
- = note: expected type `()`
- found opaque type `impl Future<Output = ()>`
+ = note: expected unit type `()`
+ found opaque type `impl Future<Output = ()>`
help: consider `await`ing on the `Future`
|
LL | false => async_dummy().await,
|
error[E0308]: `match` arms have incompatible types
- --> $DIR/match-prev-arm-needing-semi.rs:45:18
+ --> $DIR/match-prev-arm-needing-semi.rs:48:18
|
LL | let _ = match true {
| _____________-
| |_____- `match` arms have incompatible types
|
note: while checking the return type of the `async fn`
- --> $DIR/match-prev-arm-needing-semi.rs:19:25
+ --> $DIR/match-prev-arm-needing-semi.rs:22:25
|
LL | async fn async_dummy2() {}
| ^ checked the `Output` of this `async fn`, found opaque type
- = note: expected type `()`
- found opaque type `impl Future<Output = ()>`
+ = note: expected unit type `()`
+ found opaque type `impl Future<Output = ()>`
help: consider `await`ing on the `Future`
|
LL | false => async_dummy2().await,
|
error[E0308]: `match` arms have incompatible types
- --> $DIR/match-prev-arm-needing-semi.rs:56:18
+ --> $DIR/match-prev-arm-needing-semi.rs:59:18
|
LL | let _ = match true {
| _____________-
| |_____- `match` arms have incompatible types
|
note: while checking the return type of the `async fn`
- --> $DIR/match-prev-arm-needing-semi.rs:19:25
+ --> $DIR/match-prev-arm-needing-semi.rs:16:24
+ |
+LL | async fn async_dummy() {}
+ | ^ checked the `Output` of this `async fn`, expected opaque type
+note: while checking the return type of the `async fn`
+ --> $DIR/match-prev-arm-needing-semi.rs:22:25
|
LL | async fn async_dummy2() {}
| ^ checked the `Output` of this `async fn`, found opaque type
- = note: expected type `impl Future<Output = ()>` (opaque type at <$DIR/match-prev-arm-needing-semi.rs:16:24>)
- found opaque type `impl Future<Output = ()>` (opaque type at <$DIR/match-prev-arm-needing-semi.rs:19:25>)
+ = note: expected opaque type `impl Future<Output = ()>` (opaque type at <$DIR/match-prev-arm-needing-semi.rs:16:24>)
+ found opaque type `impl Future<Output = ()>` (opaque type at <$DIR/match-prev-arm-needing-semi.rs:22:25>)
= note: distinct uses of `impl Trait` result in different opaque types
help: consider `await`ing on both `Future`s
|
LL | | };
| |_____- `match` arms have incompatible types
|
- = note: expected type `Box<Baz>`
- found struct `Box<Bar>`
+ = note: expected struct `Box<Baz>`
+ found struct `Box<Bar>`
note: you might have meant to return the `match` expression
--> $DIR/match-with-different-arm-types-as-stmt-instead-of-expr.rs:27:6
|
error[E0308]: `if` and `else` have incompatible types
--> $DIR/opaque-type-error.rs:20:9
|
+LL | fn thing_one() -> impl Future<Output = Result<(), ()>> {
+ | ------------------------------------ the expected opaque type
+...
LL | fn thing_two() -> impl Future<Output = Result<(), ()>> {
| ------------------------------------ the found opaque type
...
LL | | }.await
| |_____- `if` and `else` have incompatible types
|
- = note: expected type `impl Future<Output = Result<(), ()>>` (opaque type at <$DIR/opaque-type-error.rs:8:19>)
- found opaque type `impl Future<Output = Result<(), ()>>` (opaque type at <$DIR/opaque-type-error.rs:12:19>)
+ = note: expected opaque type `impl Future<Output = Result<(), ()>>` (opaque type at <$DIR/opaque-type-error.rs:8:19>)
+ found opaque type `impl Future<Output = Result<(), ()>>` (opaque type at <$DIR/opaque-type-error.rs:12:19>)
= note: distinct uses of `impl Trait` result in different opaque types
help: consider `await`ing on both `Future`s
|
error[E0224]: at least one trait is required for an object type
--> $DIR/only-maybe-bound.rs:13:12
|
+LL | trait _1 = _0;
+ | -------------- this alias does not contain a trait
+...
LL | type _T0 = dyn _1;
| ^^^^^^
error[E0224]: at least one trait is required for an object type
--> $DIR/only-maybe-bound.rs:19:12
|
+LL | trait _2 = _1 + _1;
+ | ------------------- this alias does not contain a trait
+LL |
LL | type _T1 = dyn _2;
| ^^^^^^
| |
| arguments to this function are incorrect
|
- = note: expected type `F`
- found struct `Class<P>`
+ = note: expected type parameter `F`
+ found struct `Class<P>`
note: associated function defined here
--> $DIR/issue-52893.rs:11:8
|
impl<T> WithType for T {
type Ctx = dyn Alias<T>;
-//~^ ERROR the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time
+ //~^ ERROR at least one trait is required for an object type [E0224]
}
fn main() {}
-error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time
+error[E0224]: at least one trait is required for an object type
--> $DIR/issue-65673.rs:9:16
|
+LL | trait Alias<T> = where T: Trait;
+ | -------------------------------- this alias does not contain a trait
+...
LL | type Ctx = dyn Alias<T>;
- | ^^^^^^^^^^^^ doesn't have a size known at compile-time
- |
- = help: the trait `Sized` is not implemented for `(dyn Trait + 'static)`
-note: required by a bound in `WithType::Ctx`
- --> $DIR/issue-65673.rs:4:5
- |
-LL | type Ctx;
- | ^^^^^^^^^ required by this bound in `WithType::Ctx`
+ | ^^^^^^^^^^^^
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0224`.
--- /dev/null
+// check-pass
+
+#![feature(trait_alias)]
+
+pub trait State = Clone + Send + Sync + PartialOrd + PartialEq + std::fmt::Display;
+pub trait RandState<S: State> = FnMut() -> S + Send;
+
+pub trait Evaluator {
+ type State;
+}
+
+pub struct Evolver<E: Evaluator> {
+ rand_state: Box<dyn RandState<E::State>>,
+}
+
+fn main() {}
--- /dev/null
+// check-pass
+
+pub trait Sequence<Item, Subsequence: Sequence<Item, Subsequence>> {}
+
+pub trait NodeWalk<Graph: GraphBase, NodeSubwalk: NodeWalk<Graph, NodeSubwalk>>:
+ Sequence<Graph::NodeIndex, NodeSubwalk>
+{
+}
+
+pub trait GraphBase {
+ type NodeIndex;
+}
+
+pub trait WalkableGraph: GraphBase {}
+
+fn main() {}
LL | | });
| |_____- argument unexpected
|
+note: closure defined here
+ --> $DIR/wrong_argument_ice-4.rs:2:6
+ |
+LL | (|| {})(|| {
+ | ^^
help: remove the extra argument
|
LL | (|| {})();
--- /dev/null
+#![feature(type_alias_impl_trait)]
+
+// edition:2018
+
+use std::future::Future;
+
+pub trait Service<Request> {
+ type Future: Future<Output = ()>;
+ fn call(&mut self, req: Request) -> Self::Future;
+}
+
+// NOTE: the pub(crate) here is critical
+pub(crate) fn new() -> () {}
+
+pub struct A;
+impl Service<()> for A {
+ type Future = impl Future<Output = ()>;
+ fn call(&mut self, _: ()) -> Self::Future {
+ async { new() }
+ }
+}
--- /dev/null
+// aux-build:collect_hidden_types.rs
+use collect_hidden_types::Service;
+use std::future::Future;
+use std::pin::Pin;
+use std::task::Context;
+
+// build-pass
+
+// edition:2018
+
+extern crate collect_hidden_types;
+
+fn broken(mut a: collect_hidden_types::A, cx: &mut Context<'_>) {
+ let mut fut = a.call(());
+ let _ = unsafe { Pin::new_unchecked(&mut fut) }.poll(cx);
+}
+
+pub async fn meeb(cx: &mut Context<'_>) {
+ broken(collect_hidden_types::A, cx);
+}
+
+fn main() {}
--- /dev/null
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+
+fn main() {
+ type T = impl Copy;
+ let foo: T = (1u32, 2u32);
+ let x: (_, _) = foo;
+ println!("{:?}", x);
+}
--- /dev/null
+// known-bug
+// failure-status: 101
+// compile-flags: --edition=2021 --crate-type=lib
+// rustc-env:RUST_BACKTRACE=0
+
+// normalize-stderr-test "thread 'rustc' panicked.*" -> "thread 'rustc' panicked"
+// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> ""
+// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> ""
+// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> ""
+// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
+// normalize-stderr-test "note: compiler flags.*\n\n" -> ""
+// normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
+// normalize-stderr-test "#.*\n" -> ""
+// normalize-stderr-test ".*delayed.*\n" -> ""
+
+// tracked in https://github.com/rust-lang/rust/issues/96572
+
+#![feature(type_alias_impl_trait)]
+
+fn main() {
+ type T = impl Copy;
+ let foo: T = (1u32, 2u32);
+ let (a, b): (u32, u32) = foo;
+}
--- /dev/null
+error: internal compiler error: no errors encountered even though `delay_span_bug` issued
+
+error: internal compiler error: broken MIR in DefId(0:3 ~ cross_inference_pattern_bug[646d]::main) ((_1.0: u32)): can't project out of PlaceTy { ty: main::T, variant_index: None }
+ --> $DIR/cross_inference_pattern_bug.rs:23:10
+ |
+LL | let (a, b): (u32, u32) = foo;
+ | ^
+ |
+
+error: internal compiler error: TyKind::Error constructed but no error reported
+ |
+
+error: internal compiler error: TyKind::Error constructed but no error reported
+ |
+
+error: internal compiler error: broken MIR in DefId(0:3 ~ cross_inference_pattern_bug[646d]::main) ((_1.1: u32)): can't project out of PlaceTy { ty: main::T, variant_index: None }
+ --> $DIR/cross_inference_pattern_bug.rs:23:13
+ |
+LL | let (a, b): (u32, u32) = foo;
+ | ^
+ |
+
+error: internal compiler error: TyKind::Error constructed but no error reported
+ |
+
+error: internal compiler error: TyKind::Error constructed but no error reported
+ |
+
+thread 'rustc' panicked
+
+query stack during panic:
+end of query stack
--- /dev/null
+// known-bug
+// compile-flags: --edition=2021 --crate-type=lib
+// rustc-env:RUST_BACKTRACE=0
+
+// tracked in https://github.com/rust-lang/rust/issues/96572
+
+#![feature(type_alias_impl_trait)]
+
+fn main() {
+ type T = impl Copy; // error: unconstrained opaque type
+ let foo: T = (1u32, 2u32);
+ let (a, b) = foo; // removing this line makes the code compile
+}
--- /dev/null
+error: unconstrained opaque type
+ --> $DIR/cross_inference_pattern_bug_no_type.rs:10:14
+ |
+LL | type T = impl Copy; // error: unconstrained opaque type
+ | ^^^^^^^^^
+ |
+ = note: `T` must be used in combination with a concrete type within the same module
+
+error: aborting due to previous error
+
--- /dev/null
+// check-pass
+
+fn foo(b: bool) -> impl Copy {
+ if b {
+ return (5,6)
+ }
+ let x: (_, _) = foo(true);
+ println!("{:?}", x);
+ (1u32, 2u32)
+}
+
+fn main() {
+ foo(false);
+}
fn main() {
Some.nonexistent_method(); //~ ERROR: no method named `nonexistent_method` found
+ Some.nonexistent_field; //~ ERROR: no field `nonexistent_field`
}
LL | (Some)(_).nonexistent_method();
| + ++++
-error: aborting due to previous error
+error[E0609]: no field `nonexistent_field` on type `fn(_) -> Option<_> {Option::<_>::Some}`
+ --> $DIR/issue-96738.rs:3:10
+ |
+LL | Some.nonexistent_field;
+ | ---- ^^^^^^^^^^^^^^^^^
+ | |
+ | this is the constructor of an enum variant
+ |
+help: call the constructor
+ |
+LL | (Some)(_).nonexistent_field;
+ | + ++++
+
+error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0599`.
+Some errors have detailed explanations: E0599, E0609.
+For more information about an error, try `rustc --explain E0599`.
| |
| arguments to this function are incorrect
|
+note: closure defined here
+ --> $DIR/unboxed-closures-type-mismatch.rs:4:17
+ |
+LL | let mut f = |x: isize, y: isize| -> isize { x + y };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: change the type of the numeric literal from `usize` to `isize`
|
LL | let z = f(1_isize, 2);
|
LL | / if a % 2 == 0 {
LL | | move || println!("{a}")
- | | ----------------------- expected because of this
+ | | -----------------------
+ | | |
+ | | the expected closure
+ | | expected because of this
LL | | } else {
LL | | Box::new(move || println!("{}", b))
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected closure, found struct `Box`
LL | | }
| |_____- `if` and `else` have incompatible types
|
- = note: expected type `[closure@$DIR/box-instead-of-dyn-fn.rs:8:9: 8:32]`
- found struct `Box<[closure@$DIR/box-instead-of-dyn-fn.rs:10:18: 10:43]>`
+ = note: expected closure `[closure@$DIR/box-instead-of-dyn-fn.rs:8:9: 8:32]`
+ found struct `Box<[closure@$DIR/box-instead-of-dyn-fn.rs:10:18: 10:43]>`
error[E0746]: return type cannot have an unboxed trait object
--> $DIR/box-instead-of-dyn-fn.rs:5:56
LL | | }
| |_____- `match` arms have incompatible types
|
- = note: expected type `&S`
- found reference `&R`
+ = note: expected reference `&S`
+ found reference `&R`
error[E0038]: the trait `Trait` cannot be made into an object
--> $DIR/wf-unsafe-trait-obj-match.rs:26:21
[`skip_while_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#skip_while_next
[`slow_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#slow_vector_initialization
[`stable_sort_primitive`]: https://rust-lang.github.io/rust-clippy/master/index.html#stable_sort_primitive
+[`significant_drop_in_scrutinee`]: https://rust-lang.github.io/rust-clippy/master/index.html#significant_drop_in_scrutinee
[`str_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#str_to_string
[`string_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add
[`string_add_assign`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add_assign
size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT,
slow_vector_initialization::SLOW_VECTOR_INITIALIZATION,
stable_sort_primitive::STABLE_SORT_PRIMITIVE,
+ significant_drop_in_scrutinee::SIGNIFICANT_DROP_IN_SCRUTINEE,
strings::STRING_ADD,
strings::STRING_ADD_ASSIGN,
strings::STRING_FROM_UTF8_AS_BYTES,
LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),
LintId::of(redundant_pub_crate::REDUNDANT_PUB_CRATE),
LintId::of(regex::TRIVIAL_REGEX),
+ LintId::of(significant_drop_in_scrutinee::SIGNIFICANT_DROP_IN_SCRUTINEE),
LintId::of(strings::STRING_LIT_AS_BYTES),
LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
LintId::of(trailing_empty_array::TRAILING_EMPTY_ARRAY),
- LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
- LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS),
LintId::of(transmute::TRANSMUTE_UNDEFINED_REPR),
LintId::of(transmute::USELESS_TRANSMUTE),
LintId::of(use_self::USE_SELF),
LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE),
LintId::of(strings::STRING_ADD_ASSIGN),
+ LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
+ LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS),
LintId::of(transmute::TRANSMUTE_PTR_TO_PTR),
LintId::of(types::LINKEDLIST),
LintId::of(types::OPTION_OPTION),
mod semicolon_if_nothing_returned;
mod serde_api;
mod shadow;
+mod significant_drop_in_scrutinee;
mod single_char_lifetime_names;
mod single_component_path_imports;
mod size_of_in_element_count;
store.register_late_pass(move || Box::new(manual_bits::ManualBits::new(msrv)));
store.register_late_pass(|| Box::new(default_union_representation::DefaultUnionRepresentation));
store.register_late_pass(|| Box::new(only_used_in_recursion::OnlyUsedInRecursion));
+ store.register_late_pass(|| Box::new(significant_drop_in_scrutinee::SignificantDropInScrutinee));
store.register_late_pass(|| Box::new(dbg_macro::DbgMacro));
let cargo_ignore_publish = conf.cargo_ignore_publish;
store.register_late_pass(move || {
use rustc_hir::FnRetTy::Return;
use rustc_hir::{
BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl, ImplItem,
- ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, ParamName, PolyTraitRef, TraitBoundModifier,
- TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
+ ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, ParamName, PolyTraitRef, PredicateOrigin,
+ TraitBoundModifier, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter as middle_nested_filter;
.filter(|param| matches!(param.kind, GenericParamKind::Type { .. }));
for typ in types {
for pred in generics.bounds_for_param(cx.tcx.hir().local_def_id(typ.hir_id)) {
- if pred.in_where_clause {
+ if pred.origin == PredicateOrigin::WhereClause {
// has_where_lifetimes checked that this predicate contains no lifetime.
continue;
}
--- /dev/null
+use crate::FxHashSet;
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::get_attr;
+use clippy_utils::source::{indent_of, snippet};
+use rustc_errors::{Applicability, Diagnostic};
+use rustc_hir::intravisit::{walk_expr, Visitor};
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::ty::subst::GenericArgKind;
+use rustc_middle::ty::{Ty, TypeAndMut};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::Span;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Check for temporaries returned from function calls in a match scrutinee that have the
+ /// `clippy::has_significant_drop` attribute.
+ ///
+ /// ### Why is this bad?
+ /// The `clippy::has_significant_drop` attribute can be added to types whose Drop impls have
+ /// an important side-effect, such as unlocking a mutex, making it important for users to be
+ /// able to accurately understand their lifetimes. When a temporary is returned in a function
+ /// call in a match scrutinee, its lifetime lasts until the end of the match block, which may
+ /// be surprising.
+ ///
+ /// For `Mutex`es this can lead to a deadlock. This happens when the match scrutinee uses a
+ /// function call that returns a `MutexGuard` and then tries to lock again in one of the match
+ /// arms. In that case the `MutexGuard` in the scrutinee will not be dropped until the end of
+ /// the match block and thus will not unlock.
+ ///
+ /// ### Example
+ /// ```rust
+ /// # use std::sync::Mutex;
+ ///
+ /// # struct State {}
+ ///
+ /// # impl State {
+ /// # fn foo(&self) -> bool {
+ /// # true
+ /// # }
+ ///
+ /// # fn bar(&self) {}
+ /// # }
+ ///
+ ///
+ /// let mutex = Mutex::new(State {});
+ ///
+ /// match mutex.lock().unwrap().foo() {
+ /// true => {
+ /// mutex.lock().unwrap().bar(); // Deadlock!
+ /// }
+ /// false => {}
+ /// };
+ ///
+ /// println!("All done!");
+ ///
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// # use std::sync::Mutex;
+ ///
+ /// # struct State {}
+ ///
+ /// # impl State {
+ /// # fn foo(&self) -> bool {
+ /// # true
+ /// # }
+ ///
+ /// # fn bar(&self) {}
+ /// # }
+ ///
+ /// let mutex = Mutex::new(State {});
+ ///
+ /// let is_foo = mutex.lock().unwrap().foo();
+ /// match is_foo {
+ /// true => {
+ /// mutex.lock().unwrap().bar();
+ /// }
+ /// false => {}
+ /// };
+ ///
+ /// println!("All done!");
+ /// ```
+ #[clippy::version = "1.60.0"]
+ pub SIGNIFICANT_DROP_IN_SCRUTINEE,
+ nursery,
+ "warns when a temporary of a type with a drop with a significant side-effect might have a surprising lifetime"
+}
+
+declare_lint_pass!(SignificantDropInScrutinee => [SIGNIFICANT_DROP_IN_SCRUTINEE]);
+
+impl<'tcx> LateLintPass<'tcx> for SignificantDropInScrutinee {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+ if let Some(suggestions) = has_significant_drop_in_scrutinee(cx, expr) {
+ for found in suggestions {
+ span_lint_and_then(
+ cx,
+ SIGNIFICANT_DROP_IN_SCRUTINEE,
+ found.found_span,
+ "temporary with significant drop in match scrutinee",
+ |diag| set_diagnostic(diag, cx, expr, found),
+ )
+ }
+ }
+ }
+}
+
+fn set_diagnostic<'tcx>(diag: &mut Diagnostic, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, found: FoundSigDrop) {
+ if found.lint_suggestion == LintSuggestion::MoveAndClone {
+ // If our suggestion is to move and clone, then we want to leave it to the user to
+ // decide how to address this lint, since it may be that cloning is inappropriate.
+ // Therefore, we won't to emit a suggestion.
+ return;
+ }
+
+ let original = snippet(cx, found.found_span, "..");
+ let trailing_indent = " ".repeat(indent_of(cx, found.found_span).unwrap_or(0));
+
+ let replacement = if found.lint_suggestion == LintSuggestion::MoveAndDerefToCopy {
+ format!("let value = *{};\n{}", original, trailing_indent)
+ } else if found.is_unit_return_val {
+ // If the return value of the expression to be moved is unit, then we don't need to
+ // capture the result in a temporary -- we can just replace it completely with `()`.
+ format!("{};\n{}", original, trailing_indent)
+ } else {
+ format!("let value = {};\n{}", original, trailing_indent)
+ };
+
+ let suggestion_message = if found.lint_suggestion == LintSuggestion::MoveOnly {
+ "try moving the temporary above the match"
+ } else {
+ "try moving the temporary above the match and create a copy"
+ };
+
+ let scrutinee_replacement = if found.is_unit_return_val {
+ "()".to_owned()
+ } else {
+ "value".to_owned()
+ };
+
+ diag.multipart_suggestion(
+ suggestion_message,
+ vec![
+ (expr.span.shrink_to_lo(), replacement),
+ (found.found_span, scrutinee_replacement),
+ ],
+ Applicability::MaybeIncorrect,
+ );
+}
+
+/// If the expression is an ExprKind::Match, check if the scrutinee has a significant drop that may
+/// have a surprising lifetime.
+fn has_significant_drop_in_scrutinee<'tcx, 'a>(
+ cx: &'a LateContext<'tcx>,
+ expr: &'tcx Expr<'tcx>,
+) -> Option<Vec<FoundSigDrop>> {
+ let mut helper = SigDropHelper::new(cx);
+ match expr.kind {
+ ExprKind::Match(match_expr, _, _) => helper.find_sig_drop(match_expr),
+ _ => None,
+ }
+}
+
+struct SigDropHelper<'a, 'tcx> {
+ cx: &'a LateContext<'tcx>,
+ is_chain_end: bool,
+ seen_types: FxHashSet<Ty<'tcx>>,
+ has_significant_drop: bool,
+ current_sig_drop: Option<FoundSigDrop>,
+ sig_drop_spans: Option<Vec<FoundSigDrop>>,
+ special_handling_for_binary_op: bool,
+}
+
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+enum LintSuggestion {
+ MoveOnly,
+ MoveAndDerefToCopy,
+ MoveAndClone,
+}
+
+#[derive(Clone, Copy)]
+struct FoundSigDrop {
+ found_span: Span,
+ is_unit_return_val: bool,
+ lint_suggestion: LintSuggestion,
+}
+
+impl<'a, 'tcx> SigDropHelper<'a, 'tcx> {
+ fn new(cx: &'a LateContext<'tcx>) -> SigDropHelper<'a, 'tcx> {
+ SigDropHelper {
+ cx,
+ is_chain_end: true,
+ seen_types: FxHashSet::default(),
+ has_significant_drop: false,
+ current_sig_drop: None,
+ sig_drop_spans: None,
+ special_handling_for_binary_op: false,
+ }
+ }
+
+ fn find_sig_drop(&mut self, match_expr: &'tcx Expr<'_>) -> Option<Vec<FoundSigDrop>> {
+ self.visit_expr(match_expr);
+
+ // If sig drop spans is empty but we found a significant drop, it means that we didn't find
+ // a type that was trivially copyable as we moved up the chain after finding a significant
+ // drop, so move the entire scrutinee.
+ if self.has_significant_drop && self.sig_drop_spans.is_none() {
+ self.try_setting_current_suggestion(match_expr, true);
+ self.move_current_suggestion();
+ }
+
+ self.sig_drop_spans.take()
+ }
+
+ /// This will try to set the current suggestion (so it can be moved into the suggestions vec
+ /// later). If allow_move_and_clone is false, the suggestion *won't* be set -- this gives us
+ /// an opportunity to look for another type in the chain that will be trivially copyable.
+ /// However, if we are at the the end of the chain, we want to accept whatever is there. (The
+ /// suggestion won't actually be output, but the diagnostic message will be output, so the user
+ /// can determine the best way to handle the lint.)
+ fn try_setting_current_suggestion(&mut self, expr: &'tcx Expr<'_>, allow_move_and_clone: bool) {
+ if self.current_sig_drop.is_some() {
+ return;
+ }
+ let ty = self.get_type(expr);
+ if ty.is_ref() {
+ // We checked that the type was ref, so builtin_deref will return Some TypeAndMut,
+ // but let's avoid any chance of an ICE
+ if let Some(TypeAndMut { ty, .. }) = ty.builtin_deref(true) {
+ if ty.is_trivially_pure_clone_copy() {
+ self.current_sig_drop.replace(FoundSigDrop {
+ found_span: expr.span,
+ is_unit_return_val: false,
+ lint_suggestion: LintSuggestion::MoveAndDerefToCopy,
+ });
+ } else if allow_move_and_clone {
+ self.current_sig_drop.replace(FoundSigDrop {
+ found_span: expr.span,
+ is_unit_return_val: false,
+ lint_suggestion: LintSuggestion::MoveAndClone,
+ });
+ }
+ }
+ } else if ty.is_trivially_pure_clone_copy() {
+ self.current_sig_drop.replace(FoundSigDrop {
+ found_span: expr.span,
+ is_unit_return_val: false,
+ lint_suggestion: LintSuggestion::MoveOnly,
+ });
+ }
+ }
+
+ fn move_current_suggestion(&mut self) {
+ if let Some(current) = self.current_sig_drop.take() {
+ self.sig_drop_spans.get_or_insert_with(Vec::new).push(current);
+ }
+ }
+
+ fn get_type(&self, ex: &'tcx Expr<'_>) -> Ty<'tcx> {
+ self.cx.typeck_results().expr_ty(ex)
+ }
+
+ fn has_seen_type(&mut self, ty: Ty<'tcx>) -> bool {
+ !self.seen_types.insert(ty)
+ }
+
+ fn visit_exprs_for_binary_ops(
+ &mut self,
+ left: &'tcx Expr<'_>,
+ right: &'tcx Expr<'_>,
+ is_unit_return_val: bool,
+ span: Span,
+ ) {
+ self.special_handling_for_binary_op = true;
+ self.visit_expr(left);
+ self.visit_expr(right);
+
+ // If either side had a significant drop, suggest moving the entire scrutinee to avoid
+ // unnecessary copies and to simplify cases where both sides have significant drops.
+ if self.has_significant_drop {
+ self.current_sig_drop.replace(FoundSigDrop {
+ found_span: span,
+ is_unit_return_val,
+ lint_suggestion: LintSuggestion::MoveOnly,
+ });
+ }
+
+ self.special_handling_for_binary_op = false;
+ }
+
+ fn has_sig_drop_attr(&mut self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+ if let Some(adt) = ty.ty_adt_def() {
+ if get_attr(cx.sess(), cx.tcx.get_attrs(adt.did()), "has_significant_drop").count() > 0 {
+ return true;
+ }
+ }
+
+ match ty.kind() {
+ rustc_middle::ty::Adt(a, b) => {
+ for f in a.all_fields() {
+ let ty = f.ty(cx.tcx, b);
+ if !self.has_seen_type(ty) && self.has_sig_drop_attr(cx, ty) {
+ return true;
+ }
+ }
+
+ for generic_arg in b.iter() {
+ if let GenericArgKind::Type(ty) = generic_arg.unpack() {
+ if self.has_sig_drop_attr(cx, ty) {
+ return true;
+ }
+ }
+ }
+ false
+ },
+ rustc_middle::ty::Array(ty, _) => self.has_sig_drop_attr(cx, *ty),
+ rustc_middle::ty::RawPtr(TypeAndMut { ty, .. }) => self.has_sig_drop_attr(cx, *ty),
+ rustc_middle::ty::Ref(_, ty, _) => self.has_sig_drop_attr(cx, *ty),
+ rustc_middle::ty::Slice(ty) => self.has_sig_drop_attr(cx, *ty),
+ _ => false,
+ }
+ }
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> {
+ fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
+ if !self.is_chain_end && self.has_sig_drop_attr(self.cx, self.get_type(ex)) {
+ self.has_significant_drop = true;
+ return;
+ }
+ self.is_chain_end = false;
+
+ match ex.kind {
+ ExprKind::MethodCall(_, [ref expr, ..], _) => {
+ self.visit_expr(expr)
+ }
+ ExprKind::Binary(_, left, right) => {
+ self.visit_exprs_for_binary_ops(left, right, false, ex.span);
+ }
+ ExprKind::Assign(left, right, _) => {
+ self.visit_exprs_for_binary_ops(left, right, true, ex.span);
+ }
+ ExprKind::AssignOp(_, left, right) => {
+ self.visit_exprs_for_binary_ops(left, right, true, ex.span);
+ }
+ ExprKind::Tup(exprs) => {
+ for expr in exprs {
+ self.visit_expr(expr);
+ if self.has_significant_drop {
+ // We may have not have set current_sig_drop if all the suggestions were
+ // MoveAndClone, so add this tuple item's full expression in that case.
+ if self.current_sig_drop.is_none() {
+ self.try_setting_current_suggestion(expr, true);
+ }
+
+ // Now we are guaranteed to have something, so add it to the final vec.
+ self.move_current_suggestion();
+ }
+ // Reset `has_significant_drop` after each tuple expression so we can look for
+ // additional cases.
+ self.has_significant_drop = false;
+ }
+ if self.sig_drop_spans.is_some() {
+ self.has_significant_drop = true;
+ }
+ }
+ ExprKind::Box(..) |
+ ExprKind::Array(..) |
+ ExprKind::Call(..) |
+ ExprKind::Unary(..) |
+ ExprKind::If(..) |
+ ExprKind::Match(..) |
+ ExprKind::Field(..) |
+ ExprKind::Index(..) |
+ ExprKind::Ret(..) |
+ ExprKind::Repeat(..) |
+ ExprKind::Yield(..) |
+ ExprKind::MethodCall(..) => walk_expr(self, ex),
+ ExprKind::AddrOf(_, _, _) |
+ ExprKind::Block(_, _) |
+ ExprKind::Break(_, _) |
+ ExprKind::Cast(_, _) |
+ // Don't want to check the closure itself, only invocation, which is covered by MethodCall
+ ExprKind::Closure(_, _, _, _, _) |
+ ExprKind::ConstBlock(_) |
+ ExprKind::Continue(_) |
+ ExprKind::DropTemps(_) |
+ ExprKind::Err |
+ ExprKind::InlineAsm(_) |
+ ExprKind::Let(_) |
+ ExprKind::Lit(_) |
+ ExprKind::Loop(_, _, _, _) |
+ ExprKind::Path(_) |
+ ExprKind::Struct(_, _, _) |
+ ExprKind::Type(_, _) => {
+ return;
+ }
+ }
+
+ // Once a significant temporary has been found, we need to go back up at least 1 level to
+ // find the span to extract for replacement, so the temporary gets dropped. However, for
+ // binary ops, we want to move the whole scrutinee so we avoid unnecessary copies and to
+ // simplify cases where both sides have significant drops.
+ if self.has_significant_drop && !self.special_handling_for_binary_op {
+ self.try_setting_current_suggestion(ex, false);
+ }
+ }
+}
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::{
- GenericBound, Generics, Item, ItemKind, Node, Path, PathSegment, QPath, TraitItem, Ty, TyKind, WherePredicate,
+ GenericBound, Generics, Item, ItemKind, Node, Path, PathSegment, PredicateOrigin, QPath, TraitItem, Ty, TyKind,
+ WherePredicate,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
/// ```
#[clippy::version = "1.38.0"]
pub TYPE_REPETITION_IN_BOUNDS,
- nursery,
+ pedantic,
"Types are repeated unnecessary in trait bounds use `+` instead of using `T: _, T: _`"
}
/// ```
#[clippy::version = "1.47.0"]
pub TRAIT_DUPLICATION_IN_BOUNDS,
- nursery,
+ pedantic,
"Check if the same trait bounds are specified twice during a function declaration"
}
for predicate in item.generics.predicates {
if_chain! {
if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate;
+ if bound_predicate.origin != PredicateOrigin::ImplTrait;
if !bound_predicate.span.from_expansion();
if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind;
if let Some(PathSegment {
for bound in gen.predicates {
if_chain! {
if let WherePredicate::BoundPredicate(ref p) = bound;
+ if p.origin != PredicateOrigin::ImplTrait;
if p.bounds.len() as u64 <= self.max_trait_bounds;
if !p.span.from_expansion();
if let Some(ref v) = map.insert(
for predicate in gen.predicates {
if_chain! {
if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate;
+ if bound_predicate.origin != PredicateOrigin::ImplTrait;
if !bound_predicate.span.from_expansion();
if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind;
if let Some(segment) = segments.first();
("cyclomatic_complexity", DeprecationStatus::Replaced("cognitive_complexity")),
("dump", DeprecationStatus::None),
("msrv", DeprecationStatus::None),
+ ("has_significant_drop", DeprecationStatus::None),
];
pub struct LimitStack {
--- /dev/null
+// check-pass
+#![feature(lint_reasons)]
+//! This file tests the `#[expect]` attribute implementation for tool lints. The same
+//! file is used to test clippy and rustdoc. Any changes to this file should be synced
+//! to the other test files as well.
+//!
+//! Expectations:
+//! * rustc: only rustc lint expectations are emitted
+//! * clippy: rustc and Clippy's expectations are emitted
+//! * rustdoc: only rustdoc lint expectations are emitted
+//!
+//! This test can't cover every lint from Clippy, rustdoc and potentially other
+//! tools that will be developed. This therefore only tests a small subset of lints
+#![expect(rustdoc::missing_crate_level_docs)]
+
+mod rustc_ok {
+ //! See <https://doc.rust-lang.org/rustc/lints/index.html>
+
+ #[expect(dead_code)]
+ pub fn rustc_lints() {
+ let x = 42.0;
+
+ #[expect(illegal_floating_point_literal_pattern)]
+ match x {
+ 5.0 => {}
+ 6.0 => {}
+ _ => {}
+ }
+ }
+}
+
+mod rustc_warn {
+ //! See <https://doc.rust-lang.org/rustc/lints/index.html>
+
+ #[expect(dead_code)]
+ pub fn rustc_lints() {
+ let x = 42;
+
+ #[expect(illegal_floating_point_literal_pattern)]
+ match x {
+ 5 => {}
+ 6 => {}
+ _ => {}
+ }
+ }
+}
+
+pub mod rustdoc_ok {
+ //! See <https://doc.rust-lang.org/rustdoc/lints.html>
+
+ #[expect(rustdoc::broken_intra_doc_links)]
+ /// I want to link to [`Nonexistent`] but it doesn't exist!
+ pub fn foo() {}
+
+ #[expect(rustdoc::invalid_html_tags)]
+ /// <h1>
+ pub fn bar() {}
+
+ #[expect(rustdoc::bare_urls)]
+ /// http://example.org
+ pub fn baz() {}
+}
+
+pub mod rustdoc_warn {
+ //! See <https://doc.rust-lang.org/rustdoc/lints.html>
+
+ #[expect(rustdoc::broken_intra_doc_links)]
+ /// I want to link to [`bar`] but it doesn't exist!
+ pub fn foo() {}
+
+ #[expect(rustdoc::invalid_html_tags)]
+ /// <h1></h1>
+ pub fn bar() {}
+
+ #[expect(rustdoc::bare_urls)]
+ /// <http://example.org>
+ pub fn baz() {}
+}
+
+mod clippy_ok {
+ //! See <https://rust-lang.github.io/rust-clippy/master/index.html>
+
+ #[expect(clippy::almost_swapped)]
+ fn foo() {
+ let mut a = 0;
+ let mut b = 9;
+ a = b;
+ b = a;
+ }
+
+ #[expect(clippy::bytes_nth)]
+ fn bar() {
+ let _ = "Hello".bytes().nth(3);
+ }
+
+ #[expect(clippy::if_same_then_else)]
+ fn baz() {
+ let _ = if true { 42 } else { 42 };
+ }
+
+ #[expect(clippy::logic_bug)]
+ fn burger() {
+ let a = false;
+ let b = true;
+
+ if a && b || a {}
+ }
+}
+
+mod clippy_warn {
+ //! See <https://rust-lang.github.io/rust-clippy/master/index.html>
+
+ #[expect(clippy::almost_swapped)]
+ fn foo() {
+ let mut a = 0;
+ let mut b = 9;
+ a = b;
+ }
+
+ #[expect(clippy::bytes_nth)]
+ fn bar() {
+ let _ = "Hello".as_bytes().get(3);
+ }
+
+ #[expect(clippy::if_same_then_else)]
+ fn baz() {
+ let _ = if true { 33 } else { 42 };
+ }
+
+ #[expect(clippy::logic_bug)]
+ fn burger() {
+ let a = false;
+ let b = true;
+ let c = false;
+
+ if a && b || c {}
+ }
+}
+
+fn main() {
+ rustc_warn::rustc_lints();
+}
--- /dev/null
+error: this lint expectation is unfulfilled
+ --> $DIR/expect_tool_lint_rfc_2383.rs:35:14
+ |
+LL | #[expect(dead_code)]
+ | ^^^^^^^^^
+ |
+ = note: `-D unfulfilled-lint-expectations` implied by `-D warnings`
+
+error: this lint expectation is unfulfilled
+ --> $DIR/expect_tool_lint_rfc_2383.rs:39:18
+ |
+LL | #[expect(illegal_floating_point_literal_pattern)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this lint expectation is unfulfilled
+ --> $DIR/expect_tool_lint_rfc_2383.rs:113:14
+ |
+LL | #[expect(clippy::almost_swapped)]
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error: this lint expectation is unfulfilled
+ --> $DIR/expect_tool_lint_rfc_2383.rs:120:14
+ |
+LL | #[expect(clippy::bytes_nth)]
+ | ^^^^^^^^^^^^^^^^^
+
+error: this lint expectation is unfulfilled
+ --> $DIR/expect_tool_lint_rfc_2383.rs:125:14
+ |
+LL | #[expect(clippy::if_same_then_else)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this lint expectation is unfulfilled
+ --> $DIR/expect_tool_lint_rfc_2383.rs:130:14
+ |
+LL | #[expect(clippy::logic_bug)]
+ | ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
+
--- /dev/null
+// FIXME: Ideally these suggestions would be fixed via rustfix. Blocked by rust-lang/rust#53934
+// // run-rustfix
+
+#![warn(clippy::significant_drop_in_scrutinee)]
+#![allow(clippy::single_match)]
+#![allow(clippy::match_single_binding)]
+#![allow(unused_assignments)]
+#![allow(dead_code)]
+
+use std::ops::Deref;
+use std::sync::atomic::{AtomicU64, Ordering};
+use std::sync::{Mutex, MutexGuard};
+
+struct State {}
+
+impl State {
+ fn foo(&self) -> bool {
+ true
+ }
+
+ fn bar(&self) {}
+}
+
+fn should_not_trigger_lint_with_mutex_guard_outside_match() {
+ let mutex = Mutex::new(State {});
+
+ // Should not trigger lint because the temporary should drop at the `;` on line before the match
+ let is_foo = mutex.lock().unwrap().foo();
+ match is_foo {
+ true => {
+ mutex.lock().unwrap().bar();
+ }
+ false => {}
+ };
+}
+
+fn should_not_trigger_lint_with_mutex_guard_when_taking_ownership_in_match() {
+ let mutex = Mutex::new(State {});
+
+ // Should not trigger lint because the scrutinee is explicitly returning the MutexGuard,
+ // so its lifetime should not be surprising.
+ match mutex.lock() {
+ Ok(guard) => {
+ guard.foo();
+ mutex.lock().unwrap().bar();
+ }
+ _ => {}
+ };
+}
+
+fn should_trigger_lint_with_mutex_guard_in_match_scrutinee() {
+ let mutex = Mutex::new(State {});
+
+ // Should trigger lint because the lifetime of the temporary MutexGuard is surprising because it
+ // is preserved until the end of the match, but there is no clear indication that this is the
+ // case.
+ match mutex.lock().unwrap().foo() {
+ true => {
+ mutex.lock().unwrap().bar();
+ }
+ false => {}
+ };
+}
+
+fn should_not_trigger_lint_for_insignificant_drop() {
+ // Should not trigger lint because there are no temporaries whose drops have a significant
+ // side effect.
+ match 1u64.to_string().is_empty() {
+ true => {
+ println!("It was empty")
+ }
+ false => {
+ println!("It was not empty")
+ }
+ }
+}
+
+struct StateWithMutex {
+ m: Mutex<u64>,
+}
+
+struct MutexGuardWrapper<'a> {
+ mg: MutexGuard<'a, u64>,
+}
+
+impl<'a> MutexGuardWrapper<'a> {
+ fn get_the_value(&self) -> u64 {
+ *self.mg.deref()
+ }
+}
+
+struct MutexGuardWrapperWrapper<'a> {
+ mg: MutexGuardWrapper<'a>,
+}
+
+impl<'a> MutexGuardWrapperWrapper<'a> {
+ fn get_the_value(&self) -> u64 {
+ *self.mg.mg.deref()
+ }
+}
+
+impl StateWithMutex {
+ fn lock_m(&self) -> MutexGuardWrapper<'_> {
+ MutexGuardWrapper {
+ mg: self.m.lock().unwrap(),
+ }
+ }
+
+ fn lock_m_m(&self) -> MutexGuardWrapperWrapper<'_> {
+ MutexGuardWrapperWrapper {
+ mg: MutexGuardWrapper {
+ mg: self.m.lock().unwrap(),
+ },
+ }
+ }
+
+ fn foo(&self) -> bool {
+ true
+ }
+
+ fn bar(&self) {}
+}
+
+fn should_trigger_lint_with_wrapped_mutex() {
+ let s = StateWithMutex { m: Mutex::new(1) };
+
+ // Should trigger lint because a temporary contains a type with a significant drop and its
+ // lifetime is not obvious. Additionally, it is not obvious from looking at the scrutinee that
+ // the temporary contains such a type, making it potentially even more surprising.
+ match s.lock_m().get_the_value() {
+ 1 => {
+ println!("Got 1. Is it still 1?");
+ println!("{}", s.lock_m().get_the_value());
+ }
+ 2 => {
+ println!("Got 2. Is it still 2?");
+ println!("{}", s.lock_m().get_the_value());
+ }
+ _ => {}
+ }
+ println!("All done!");
+}
+
+fn should_trigger_lint_with_double_wrapped_mutex() {
+ let s = StateWithMutex { m: Mutex::new(1) };
+
+ // Should trigger lint because a temporary contains a type which further contains a type with a
+ // significant drop and its lifetime is not obvious. Additionally, it is not obvious from
+ // looking at the scrutinee that the temporary contains such a type, making it potentially even
+ // more surprising.
+ match s.lock_m_m().get_the_value() {
+ 1 => {
+ println!("Got 1. Is it still 1?");
+ println!("{}", s.lock_m().get_the_value());
+ }
+ 2 => {
+ println!("Got 2. Is it still 2?");
+ println!("{}", s.lock_m().get_the_value());
+ }
+ _ => {}
+ }
+ println!("All done!");
+}
+
+struct Counter {
+ i: AtomicU64,
+}
+
+#[clippy::has_significant_drop]
+struct CounterWrapper<'a> {
+ counter: &'a Counter,
+}
+
+impl<'a> CounterWrapper<'a> {
+ fn new(counter: &Counter) -> CounterWrapper {
+ counter.i.fetch_add(1, Ordering::Relaxed);
+ CounterWrapper { counter }
+ }
+}
+
+impl<'a> Drop for CounterWrapper<'a> {
+ fn drop(&mut self) {
+ self.counter.i.fetch_sub(1, Ordering::Relaxed);
+ }
+}
+
+impl Counter {
+ fn temp_increment(&self) -> Vec<CounterWrapper> {
+ vec![CounterWrapper::new(self), CounterWrapper::new(self)]
+ }
+}
+
+fn should_trigger_lint_for_vec() {
+ let counter = Counter { i: AtomicU64::new(0) };
+
+ // Should trigger lint because the temporary in the scrutinee returns a collection of types
+ // which have significant drops. The types with significant drops are also non-obvious when
+ // reading the expression in the scrutinee.
+ match counter.temp_increment().len() {
+ 2 => {
+ let current_count = counter.i.load(Ordering::Relaxed);
+ println!("Current count {}", current_count);
+ assert_eq!(current_count, 0);
+ }
+ 1 => {}
+ 3 => {}
+ _ => {}
+ };
+}
+
+struct StateWithField {
+ s: String,
+}
+
+// Should trigger lint only on the type in the tuple which is created using a temporary
+// with a significant drop. Additionally, this test ensures that the format of the tuple
+// is preserved correctly in the suggestion.
+fn should_trigger_lint_for_tuple_in_scrutinee() {
+ let mutex1 = Mutex::new(StateWithField { s: "one".to_owned() });
+
+ {
+ match (mutex1.lock().unwrap().s.len(), true) {
+ (3, _) => {
+ println!("started");
+ mutex1.lock().unwrap().s.len();
+ println!("done");
+ }
+ (_, _) => {}
+ };
+
+ match (true, mutex1.lock().unwrap().s.len(), true) {
+ (_, 3, _) => {
+ println!("started");
+ mutex1.lock().unwrap().s.len();
+ println!("done");
+ }
+ (_, _, _) => {}
+ };
+
+ let mutex2 = Mutex::new(StateWithField { s: "two".to_owned() });
+ match (mutex1.lock().unwrap().s.len(), true, mutex2.lock().unwrap().s.len()) {
+ (3, _, 3) => {
+ println!("started");
+ mutex1.lock().unwrap().s.len();
+ mutex2.lock().unwrap().s.len();
+ println!("done");
+ }
+ (_, _, _) => {}
+ };
+
+ let mutex3 = Mutex::new(StateWithField { s: "three".to_owned() });
+ match mutex3.lock().unwrap().s.as_str() {
+ "three" => {
+ println!("started");
+ mutex1.lock().unwrap().s.len();
+ mutex2.lock().unwrap().s.len();
+ println!("done");
+ }
+ _ => {}
+ };
+
+
+ match (true, mutex3.lock().unwrap().s.as_str()) {
+ (_, "three") => {
+ println!("started");
+ mutex1.lock().unwrap().s.len();
+ mutex2.lock().unwrap().s.len();
+ println!("done");
+ }
+ (_, _) => {}
+ };
+ }
+}
+
+// Should trigger lint when either side of a binary operation creates a temporary with a
+// significant drop.
+// To avoid potential unnecessary copies or creating references that would trigger the significant
+// drop problem, the lint recommends moving the entire binary operation.
+fn should_trigger_lint_for_accessing_field_in_mutex_in_one_side_of_binary_op() {
+ let mutex = Mutex::new(StateWithField { s: "state".to_owned() });
+
+ match mutex.lock().unwrap().s.len() > 1 {
+ true => {
+ mutex.lock().unwrap().s.len();
+ }
+ false => {}
+ };
+
+ match 1 < mutex.lock().unwrap().s.len() {
+ true => {
+ mutex.lock().unwrap().s.len();
+ }
+ false => {}
+ };
+}
+
+// Should trigger lint when both sides of a binary operation creates a temporary with a
+// significant drop.
+// To avoid potential unnecessary copies or creating references that would trigger the significant
+// drop problem, the lint recommends moving the entire binary operation.
+fn should_trigger_lint_for_accessing_fields_in_mutex_in_both_sides_of_binary_op() {
+ let mutex1 = Mutex::new(StateWithField { s: "state".to_owned() });
+ let mutex2 = Mutex::new(StateWithField { s: "statewithfield".to_owned() });
+
+ match mutex1.lock().unwrap().s.len() < mutex2.lock().unwrap().s.len() {
+ true => {
+ println!("{} < {}", mutex1.lock().unwrap().s.len(), mutex2.lock().unwrap().s.len());
+ }
+ false => {}
+ };
+
+ match mutex1.lock().unwrap().s.len() >= mutex2.lock().unwrap().s.len() {
+ true => {
+ println!("{} >= {}", mutex1.lock().unwrap().s.len(), mutex2.lock().unwrap().s.len());
+ }
+ false => {}
+ };
+}
+
+fn should_not_trigger_lint_for_closure_in_scrutinee() {
+ let mutex1 = Mutex::new(StateWithField { s: "one".to_owned() });
+
+ let get_mutex_guard = || mutex1.lock().unwrap().s.len();
+
+ // Should not trigger lint because the temporary with a significant drop will be dropped
+ // at the end of the closure, so the MutexGuard will be unlocked and not have a potentially
+ // surprising lifetime.
+ match get_mutex_guard() > 1 {
+ true => {
+ mutex1.lock().unwrap().s.len();
+ }
+ false => {}
+ };
+}
+
+fn should_trigger_lint_for_return_from_closure_in_scrutinee() {
+ let mutex1 = Mutex::new(StateWithField { s: "one".to_owned() });
+
+ let get_mutex_guard = || mutex1.lock().unwrap();
+
+ // Should trigger lint because the temporary with a significant drop is returned from the
+ // closure but not used directly in any match arms, so it has a potentially surprising lifetime.
+ match get_mutex_guard().s.len() > 1 {
+ true => {
+ mutex1.lock().unwrap().s.len();
+ }
+ false => {}
+ };
+}
+
+fn should_trigger_lint_for_return_from_match_in_scrutinee() {
+ let mutex1 = Mutex::new(StateWithField { s: "one".to_owned() });
+ let mutex2 = Mutex::new(StateWithField { s: "two".to_owned() });
+
+ let i = 100;
+
+ // Should trigger lint because the nested match within the scrutinee returns a temporary with a
+ // significant drop is but not used directly in any match arms, so it has a potentially
+ // surprising lifetime.
+ match match i { 100 => mutex1.lock().unwrap(), _ => mutex2.lock().unwrap() }.s.len() > 1 {
+ true => {
+ mutex1.lock().unwrap().s.len();
+ }
+ false => {
+ println!("nothing to do here");
+ }
+ };
+}
+
+fn should_trigger_lint_for_return_from_if_in_scrutinee() {
+ let mutex1 = Mutex::new(StateWithField { s: "one".to_owned() });
+ let mutex2 = Mutex::new(StateWithField { s: "two".to_owned() });
+
+ let i = 100;
+
+ // Should trigger lint because the nested if-expression within the scrutinee returns a temporary
+ // with a significant drop is but not used directly in any match arms, so it has a potentially
+ // surprising lifetime.
+ match if i > 1 { mutex1.lock().unwrap() } else { mutex2.lock().unwrap() }.s.len() > 1 {
+ true => {
+ mutex1.lock().unwrap().s.len();
+ }
+ false => {}
+ };
+}
+
+fn should_not_trigger_lint_for_if_in_scrutinee() {
+ let mutex = Mutex::new(StateWithField { s: "state".to_owned() });
+
+ let i = 100;
+
+ // Should not trigger the lint because the temporary with a significant drop *is* dropped within
+ // the body of the if-expression nested within the match scrutinee, and therefore does not have
+ // a potentially surprising lifetime.
+ match if i > 1 { mutex.lock().unwrap().s.len() > 1 } else { false } {
+ true => {
+ mutex.lock().unwrap().s.len();
+ }
+ false => {}
+ };
+}
+
+struct StateWithBoxedMutexGuard {
+ u: Mutex<u64>,
+}
+
+impl StateWithBoxedMutexGuard {
+ fn new() -> StateWithBoxedMutexGuard {
+ StateWithBoxedMutexGuard { u: Mutex::new(42) }
+ }
+ fn lock(&self) -> Box<MutexGuard<u64>> {
+ Box::new(self.u.lock().unwrap())
+ }
+}
+
+fn should_trigger_lint_for_boxed_mutex_guard() {
+ let s = StateWithBoxedMutexGuard::new();
+
+ // Should trigger lint because a temporary Box holding a type with a significant drop in a match
+ // scrutinee may have a potentially surprising lifetime.
+ match s.lock().deref().deref() {
+ 0 | 1 => println!("Value was less than 2"),
+ _ => println!("Value is {}", s.lock().deref()),
+ };
+}
+
+struct StateStringWithBoxedMutexGuard {
+ s: Mutex<String>,
+}
+
+impl StateStringWithBoxedMutexGuard {
+ fn new() -> StateStringWithBoxedMutexGuard {
+ StateStringWithBoxedMutexGuard { s: Mutex::new("A String".to_owned()) }
+ }
+ fn lock(&self) -> Box<MutexGuard<String>> {
+ Box::new(self.s.lock().unwrap())
+ }
+}
+
+fn should_trigger_lint_for_boxed_mutex_guard_holding_string() {
+ let s = StateStringWithBoxedMutexGuard::new();
+
+ let matcher = String::from("A String");
+
+ // Should trigger lint because a temporary Box holding a type with a significant drop in a match
+ // scrutinee may have a potentially surprising lifetime.
+ match s.lock().deref().deref() {
+ matcher => println!("Value is {}", s.lock().deref()),
+ _ => println!("Value was not a match"),
+ };
+}
+
+
+struct StateWithIntField {
+ i: u64,
+}
+
+// Should trigger lint when either side of an assign expression contains a temporary with a
+// significant drop, because the temporary's lifetime will be extended to the end of the match.
+// To avoid potential unnecessary copies or creating references that would trigger the significant
+// drop problem, the lint recommends moving the entire binary operation.
+fn should_trigger_lint_in_assign_expr() {
+ let mutex = Mutex::new(StateWithIntField { i: 10 });
+
+ let mut i = 100;
+
+ match mutex.lock().unwrap().i = i {
+ _ => {
+ println!("{}", mutex.lock().unwrap().i);
+ }
+ };
+
+ match i = mutex.lock().unwrap().i {
+ _ => {
+ println!("{}", mutex.lock().unwrap().i);
+ }
+ };
+
+ match mutex.lock().unwrap().i += 1 {
+ _ => {
+ println!("{}", mutex.lock().unwrap().i);
+ }
+ };
+
+ match i += mutex.lock().unwrap().i {
+ _ => {
+ println!("{}", mutex.lock().unwrap().i);
+ }
+ };
+}
+
+#[derive(Debug)]
+enum RecursiveEnum {
+ Foo(Option<Box<RecursiveEnum>>)
+}
+
+#[derive(Debug)]
+enum GenericRecursiveEnum<T> {
+ Foo(T, Option<Box<GenericRecursiveEnum<T>>>)
+}
+
+fn should_not_cause_stack_overflow() {
+ // Test that when a type recursively contains itself, a stack overflow does not occur when
+ // checking sub-types for significant drops.
+ let f = RecursiveEnum::Foo(Some(Box::new(RecursiveEnum::Foo(None))));
+ match f {
+ RecursiveEnum::Foo(Some(f)) => {
+ println!("{:?}", f)
+ }
+ RecursiveEnum::Foo(f) => {
+ println!("{:?}", f)
+ }
+ }
+
+ let f = GenericRecursiveEnum::Foo(1u64, Some(Box::new(GenericRecursiveEnum::Foo(2u64, None))));
+ match f {
+ GenericRecursiveEnum::Foo(i, Some(f)) => {
+ println!("{} {:?}", i, f)
+ }
+ GenericRecursiveEnum::Foo(i, f) => {
+ println!("{} {:?}", i, f)
+ }
+ }
+}
+
+fn main() {}
--- /dev/null
+error: temporary with significant drop in match scrutinee
+ --> $DIR/significant_drop_in_scrutinee.rs:57:11
+ |
+LL | match mutex.lock().unwrap().foo() {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::significant-drop-in-scrutinee` implied by `-D warnings`
+help: try moving the temporary above the match
+ |
+LL ~ let value = mutex.lock().unwrap().foo();
+LL ~ match value {
+ |
+
+error: temporary with significant drop in match scrutinee
+ --> $DIR/significant_drop_in_scrutinee.rs:130:11
+ |
+LL | match s.lock_m().get_the_value() {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try moving the temporary above the match
+ |
+LL ~ let value = s.lock_m().get_the_value();
+LL ~ match value {
+ |
+
+error: temporary with significant drop in match scrutinee
+ --> $DIR/significant_drop_in_scrutinee.rs:151:11
+ |
+LL | match s.lock_m_m().get_the_value() {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try moving the temporary above the match
+ |
+LL ~ let value = s.lock_m_m().get_the_value();
+LL ~ match value {
+ |
+
+error: temporary with significant drop in match scrutinee
+ --> $DIR/significant_drop_in_scrutinee.rs:199:11
+ |
+LL | match counter.temp_increment().len() {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try moving the temporary above the match
+ |
+LL ~ let value = counter.temp_increment().len();
+LL ~ match value {
+ |
+
+error: temporary with significant drop in match scrutinee
+ --> $DIR/significant_drop_in_scrutinee.rs:222:16
+ |
+LL | match (mutex1.lock().unwrap().s.len(), true) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try moving the temporary above the match
+ |
+LL ~ let value = mutex1.lock().unwrap().s.len();
+LL ~ match (value, true) {
+ |
+
+error: temporary with significant drop in match scrutinee
+ --> $DIR/significant_drop_in_scrutinee.rs:231:22
+ |
+LL | match (true, mutex1.lock().unwrap().s.len(), true) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try moving the temporary above the match
+ |
+LL ~ let value = mutex1.lock().unwrap().s.len();
+LL ~ match (true, value, true) {
+ |
+
+error: temporary with significant drop in match scrutinee
+ --> $DIR/significant_drop_in_scrutinee.rs:241:16
+ |
+LL | match (mutex1.lock().unwrap().s.len(), true, mutex2.lock().unwrap().s.len()) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try moving the temporary above the match
+ |
+LL ~ let value = mutex1.lock().unwrap().s.len();
+LL ~ match (value, true, mutex2.lock().unwrap().s.len()) {
+ |
+
+error: temporary with significant drop in match scrutinee
+ --> $DIR/significant_drop_in_scrutinee.rs:241:54
+ |
+LL | match (mutex1.lock().unwrap().s.len(), true, mutex2.lock().unwrap().s.len()) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try moving the temporary above the match
+ |
+LL ~ let value = mutex2.lock().unwrap().s.len();
+LL ~ match (mutex1.lock().unwrap().s.len(), true, value) {
+ |
+
+error: temporary with significant drop in match scrutinee
+ --> $DIR/significant_drop_in_scrutinee.rs:252:15
+ |
+LL | match mutex3.lock().unwrap().s.as_str() {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: temporary with significant drop in match scrutinee
+ --> $DIR/significant_drop_in_scrutinee.rs:263:22
+ |
+LL | match (true, mutex3.lock().unwrap().s.as_str()) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: temporary with significant drop in match scrutinee
+ --> $DIR/significant_drop_in_scrutinee.rs:282:11
+ |
+LL | match mutex.lock().unwrap().s.len() > 1 {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try moving the temporary above the match
+ |
+LL ~ let value = mutex.lock().unwrap().s.len() > 1;
+LL ~ match value {
+ |
+
+error: temporary with significant drop in match scrutinee
+ --> $DIR/significant_drop_in_scrutinee.rs:289:11
+ |
+LL | match 1 < mutex.lock().unwrap().s.len() {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try moving the temporary above the match
+ |
+LL ~ let value = 1 < mutex.lock().unwrap().s.len();
+LL ~ match value {
+ |
+
+error: temporary with significant drop in match scrutinee
+ --> $DIR/significant_drop_in_scrutinee.rs:305:11
+ |
+LL | match mutex1.lock().unwrap().s.len() < mutex2.lock().unwrap().s.len() {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try moving the temporary above the match
+ |
+LL ~ let value = mutex1.lock().unwrap().s.len() < mutex2.lock().unwrap().s.len();
+LL ~ match value {
+ |
+
+error: temporary with significant drop in match scrutinee
+ --> $DIR/significant_drop_in_scrutinee.rs:312:11
+ |
+LL | match mutex1.lock().unwrap().s.len() >= mutex2.lock().unwrap().s.len() {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try moving the temporary above the match
+ |
+LL ~ let value = mutex1.lock().unwrap().s.len() >= mutex2.lock().unwrap().s.len();
+LL ~ match value {
+ |
+
+error: temporary with significant drop in match scrutinee
+ --> $DIR/significant_drop_in_scrutinee.rs:343:11
+ |
+LL | match get_mutex_guard().s.len() > 1 {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try moving the temporary above the match
+ |
+LL ~ let value = get_mutex_guard().s.len() > 1;
+LL ~ match value {
+ |
+
+error: temporary with significant drop in match scrutinee
+ --> $DIR/significant_drop_in_scrutinee.rs:360:11
+ |
+LL | match match i { 100 => mutex1.lock().unwrap(), _ => mutex2.lock().unwrap() }.s.len() > 1 {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try moving the temporary above the match
+ |
+LL ~ let value = match i { 100 => mutex1.lock().unwrap(), _ => mutex2.lock().unwrap() }.s.len() > 1;
+LL ~ match value {
+ |
+
+error: temporary with significant drop in match scrutinee
+ --> $DIR/significant_drop_in_scrutinee.rs:379:11
+ |
+LL | match if i > 1 { mutex1.lock().unwrap() } else { mutex2.lock().unwrap() }.s.len() > 1 {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try moving the temporary above the match
+ |
+LL ~ let value = if i > 1 { mutex1.lock().unwrap() } else { mutex2.lock().unwrap() }.s.len() > 1;
+LL ~ match value {
+ |
+
+error: temporary with significant drop in match scrutinee
+ --> $DIR/significant_drop_in_scrutinee.rs:421:11
+ |
+LL | match s.lock().deref().deref() {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try moving the temporary above the match and create a copy
+ |
+LL ~ let value = *s.lock().deref().deref();
+LL ~ match value {
+ |
+
+error: temporary with significant drop in match scrutinee
+ --> $DIR/significant_drop_in_scrutinee.rs:447:11
+ |
+LL | match s.lock().deref().deref() {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: temporary with significant drop in match scrutinee
+ --> $DIR/significant_drop_in_scrutinee.rs:467:11
+ |
+LL | match mutex.lock().unwrap().i = i {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try moving the temporary above the match
+ |
+LL ~ mutex.lock().unwrap().i = i;
+LL ~ match () {
+ |
+
+error: temporary with significant drop in match scrutinee
+ --> $DIR/significant_drop_in_scrutinee.rs:473:11
+ |
+LL | match i = mutex.lock().unwrap().i {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try moving the temporary above the match
+ |
+LL ~ i = mutex.lock().unwrap().i;
+LL ~ match () {
+ |
+
+error: temporary with significant drop in match scrutinee
+ --> $DIR/significant_drop_in_scrutinee.rs:479:11
+ |
+LL | match mutex.lock().unwrap().i += 1 {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try moving the temporary above the match
+ |
+LL ~ mutex.lock().unwrap().i += 1;
+LL ~ match () {
+ |
+
+error: temporary with significant drop in match scrutinee
+ --> $DIR/significant_drop_in_scrutinee.rs:485:11
+ |
+LL | match i += mutex.lock().unwrap().i {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: try moving the temporary above the match
+ |
+LL ~ i += mutex.lock().unwrap().i;
+LL ~ match () {
+ |
+
+error: aborting due to 23 previous errors
+
|
= help: consider removing this trait bound
-error: this trait bound is already specified in the where clause
- --> $DIR/trait_duplication_in_bounds.rs:99:23
- |
-LL | fn impl_trait(_: impl AsRef<str>, _: impl AsRef<str>) {}
- | ^^^^^^^^^^
- |
- = help: consider removing this trait bound
-
-error: aborting due to 9 previous errors
+error: aborting due to 8 previous errors
|
= help: consider combining the bounds: `Self: Clone + Copy + Default + Ord`
-error: this type has already been used as a bound predicate
- --> $DIR/type_repetition_in_bounds.rs:83:43
- |
-LL | fn impl_trait(_: impl AsRef<str>, _: impl AsRef<str>) {}
- | ^^^^^^^^^^
- |
- = help: consider combining the bounds: `impl AsRef<str>: AsRef<str> + AsRef<str>`
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
const ENTRY_LIMIT: usize = 1000;
// FIXME: The following limits should be reduced eventually.
-const ROOT_ENTRY_LIMIT: usize = 977;
-const ISSUES_ENTRY_LIMIT: usize = 2278;
+const ROOT_ENTRY_LIMIT: usize = 974;
+const ISSUES_ENTRY_LIMIT: usize = 2248;
fn check_entries(path: &Path, bad: &mut bool) {
let dirs = walkdir::WalkDir::new(&path.join("test/ui"))