Auto merge of #102450 - JohnTitor:rollup-ahleg93, r=JohnTitor

Rollup of 8 pull requests

Successful merges:

 - #98368 (Make `std::os::fd` public.)
 - #102085 (Code refactoring smart_resolve_report_errors)
 - #102351 (Improve E0585 help)
 - #102368 (Add a niche to `Duration`, unix `SystemTime`, and non-apple `Instant`)
 - #102393 (Add regression test for issue 94923)
 - #102399 (Account for use of index-based lifetime names in print of binder)
 - #102416 (remove FIXME, improve documentation)
 - #102433 (env::temp_dir: fix a typo)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors
2022-09-29 05:12:30 +00:00
39 changed files with 597 additions and 395 deletions
@@ -245,7 +245,7 @@ parser_assignment_else_not_allowed = <assignment> ... else {"{"} ... {"}"} is no
parser_expected_statement_after_outer_attr = expected statement after outer attribute
parser_doc_comment_does_not_document_anything = found a documentation comment that doesn't document anything
.help = doc comments must come before what they document, maybe a comment was intended with `//`?
.help = doc comments must come before what they document, if a comment was intended use `//`
.suggestion = missing comma here
parser_const_let_mutually_exclusive = `const` and `let` are mutually exclusive
+10 -4
View File
@@ -2173,10 +2173,16 @@ fn name_by_region_index(
let mut region_index = self.region_index;
let mut next_name = |this: &Self| {
let name = name_by_region_index(region_index, &mut available_names, num_available);
debug!(?name);
region_index += 1;
assert!(!this.used_region_names.contains(&name));
let mut name;
loop {
name = name_by_region_index(region_index, &mut available_names, num_available);
region_index += 1;
if !this.used_region_names.contains(&name) {
break;
}
}
name
};
+2 -2
View File
@@ -760,8 +760,8 @@ fn recover_doc_comment_before_brace(&mut self) -> bool {
)
.span_label(self.token.span, "this doc comment doesn't document anything")
.help(
"doc comments must come before what they document, maybe a \
comment was intended with `//`?",
"doc comments must come before what they document, if a comment was \
intended use `//`",
)
.emit();
self.bump();
+372 -253
View File
@@ -130,6 +130,16 @@ pub(super) enum LifetimeElisionCandidate {
Missing(MissingLifetime),
}
/// Only used for diagnostics.
struct BaseError {
msg: String,
fallback_label: String,
span: Span,
span_label: Option<(Span, &'static str)>,
could_be_expr: bool,
suggestion: Option<(Span, &'static str, String)>,
}
impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
fn def_span(&self, def_id: DefId) -> Option<Span> {
match def_id.krate {
@@ -138,35 +148,18 @@ fn def_span(&self, def_id: DefId) -> Option<Span> {
}
}
/// Handles error reporting for `smart_resolve_path_fragment` function.
/// Creates base error and amends it with one short label and possibly some longer helps/notes.
pub(crate) fn smart_resolve_report_errors(
fn make_base_error(
&mut self,
path: &[Segment],
span: Span,
source: PathSource<'_>,
res: Option<Res>,
) -> (DiagnosticBuilder<'a, ErrorGuaranteed>, Vec<ImportSuggestion>) {
let ident_span = path.last().map_or(span, |ident| ident.ident.span);
let ns = source.namespace();
let is_expected = &|res| source.is_expected(res);
let is_enum_variant = &|res| matches!(res, Res::Def(DefKind::Variant, _));
debug!(?res, ?source);
) -> BaseError {
// Make the base error.
struct BaseError<'a> {
msg: String,
fallback_label: String,
span: Span,
span_label: Option<(Span, &'a str)>,
could_be_expr: bool,
suggestion: Option<(Span, &'a str, String)>,
}
let mut expected = source.descr_expected();
let path_str = Segment::names_to_string(path);
let item_str = path.last().unwrap().ident;
let base_error = if let Some(res) = res {
if let Some(res) = res {
BaseError {
msg: format!("expected {}, found {} `{}`", expected, res.descr(), path_str),
fallback_label: format!("not a {expected}"),
@@ -277,8 +270,20 @@ struct BaseError<'a> {
could_be_expr: false,
suggestion,
}
};
}
}
/// Handles error reporting for `smart_resolve_path_fragment` function.
/// Creates base error and amends it with one short label and possibly some longer helps/notes.
pub(crate) fn smart_resolve_report_errors(
&mut self,
path: &[Segment],
span: Span,
source: PathSource<'_>,
res: Option<Res>,
) -> (DiagnosticBuilder<'a, ErrorGuaranteed>, Vec<ImportSuggestion>) {
debug!(?res, ?source);
let base_error = self.make_base_error(path, span, source, res);
let code = source.error_code(res.is_some());
let mut err =
self.r.session.struct_span_err_with_code(base_error.span, &base_error.msg, code);
@@ -289,41 +294,79 @@ struct BaseError<'a> {
err.span_label(span, label);
}
if let Some(sugg) = base_error.suggestion {
err.span_suggestion_verbose(sugg.0, sugg.1, sugg.2, Applicability::MaybeIncorrect);
if let Some(ref sugg) = base_error.suggestion {
err.span_suggestion_verbose(sugg.0, sugg.1, &sugg.2, Applicability::MaybeIncorrect);
}
if let Some(span) = self.diagnostic_metadata.current_block_could_be_bare_struct_literal {
err.multipart_suggestion(
"you might have meant to write a `struct` literal",
vec![
(span.shrink_to_lo(), "{ SomeStruct ".to_string()),
(span.shrink_to_hi(), "}".to_string()),
],
Applicability::HasPlaceholders,
);
self.suggest_bare_struct_literal(&mut err);
self.suggest_pattern_match_with_let(&mut err, source, span);
self.suggest_self_or_self_ref(&mut err, path, span);
self.detect_assoct_type_constraint_meant_as_path(&mut err, &base_error);
if self.suggest_self_ty(&mut err, source, path, span)
|| self.suggest_self_value(&mut err, source, path, span)
{
return (err, Vec::new());
}
match (source, self.diagnostic_metadata.in_if_condition) {
(
PathSource::Expr(_),
Some(Expr { span: expr_span, kind: ExprKind::Assign(lhs, _, _), .. }),
) => {
// Icky heuristic so we don't suggest:
// `if (i + 2) = 2` => `if let (i + 2) = 2` (approximately pattern)
// `if 2 = i` => `if let 2 = i` (lhs needs to contain error span)
if lhs.is_approximately_pattern() && lhs.span.contains(span) {
err.span_suggestion_verbose(
expr_span.shrink_to_lo(),
"you might have meant to use pattern matching",
"let ",
Applicability::MaybeIncorrect,
);
let (found, candidates) =
self.try_lookup_name_relaxed(&mut err, source, path, span, res, &base_error);
if found {
return (err, candidates);
}
if !self.type_ascription_suggestion(&mut err, base_error.span) {
let mut fallback =
self.suggest_trait_and_bounds(&mut err, source, res, span, &base_error);
fallback |= self.suggest_typo(&mut err, source, path, span, &base_error);
if fallback {
// Fallback label.
err.span_label(base_error.span, &base_error.fallback_label);
}
}
self.err_code_special_cases(&mut err, source, path, span);
(err, candidates)
}
fn detect_assoct_type_constraint_meant_as_path(
&self,
err: &mut Diagnostic,
base_error: &BaseError,
) {
let Some(ty) = self.diagnostic_metadata.current_type_path else { return; };
let TyKind::Path(_, path) = &ty.kind else { return; };
for segment in &path.segments {
let Some(params) = &segment.args else { continue; };
let ast::GenericArgs::AngleBracketed(ref params) = params.deref() else { continue; };
for param in &params.args {
let ast::AngleBracketedArg::Constraint(constraint) = param else { continue; };
let ast::AssocConstraintKind::Bound { bounds } = &constraint.kind else {
continue;
};
for bound in bounds {
let ast::GenericBound::Trait(trait_ref, ast::TraitBoundModifier::None)
= bound else
{
continue;
};
if base_error.span == trait_ref.span {
err.span_suggestion_verbose(
constraint.ident.span.between(trait_ref.span),
"you might have meant to write a path instead of an associated type bound",
"::",
Applicability::MachineApplicable,
);
}
}
}
_ => {}
}
}
fn suggest_self_or_self_ref(&mut self, err: &mut Diagnostic, path: &[Segment], span: Span) {
let is_assoc_fn = self.self_type_is_available();
let Some(path_last_segment) = path.last() else { return };
let item_str = path_last_segment.ident;
// Emit help message for fake-self from other languages (e.g., `this` in Javascript).
if ["this", "my"].contains(&item_str.as_str()) && is_assoc_fn {
err.span_suggestion_short(
@@ -358,96 +401,25 @@ struct BaseError<'a> {
}
}
}
}
self.detect_assoct_type_constraint_meant_as_path(base_error.span, &mut err);
// Emit special messages for unresolved `Self` and `self`.
if is_self_type(path, ns) {
err.code(rustc_errors::error_code!(E0411));
err.span_label(
span,
"`Self` is only available in impls, traits, and type definitions".to_string(),
);
if let Some(item_kind) = self.diagnostic_metadata.current_item {
err.span_label(
item_kind.ident.span,
format!(
"`Self` not allowed in {} {}",
item_kind.kind.article(),
item_kind.kind.descr()
),
);
}
return (err, Vec::new());
}
if is_self_value(path, ns) {
debug!("smart_resolve_path_fragment: E0424, source={:?}", source);
err.code(rustc_errors::error_code!(E0424));
err.span_label(span, match source {
PathSource::Pat => "`self` value is a keyword and may not be bound to variables or shadowed",
_ => "`self` value is a keyword only available in methods with a `self` parameter",
});
if let Some((fn_kind, span)) = &self.diagnostic_metadata.current_function {
// The current function has a `self' parameter, but we were unable to resolve
// a reference to `self`. This can only happen if the `self` identifier we
// are resolving came from a different hygiene context.
if fn_kind.decl().inputs.get(0).map_or(false, |p| p.is_self()) {
err.span_label(*span, "this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters");
} else {
let doesnt = if is_assoc_fn {
let (span, sugg) = fn_kind
.decl()
.inputs
.get(0)
.map(|p| (p.span.shrink_to_lo(), "&self, "))
.unwrap_or_else(|| {
// Try to look for the "(" after the function name, if possible.
// This avoids placing the suggestion into the visibility specifier.
let span = fn_kind
.ident()
.map_or(*span, |ident| span.with_lo(ident.span.hi()));
(
self.r
.session
.source_map()
.span_through_char(span, '(')
.shrink_to_hi(),
"&self",
)
});
err.span_suggestion_verbose(
span,
"add a `self` receiver parameter to make the associated `fn` a method",
sugg,
Applicability::MaybeIncorrect,
);
"doesn't"
} else {
"can't"
};
if let Some(ident) = fn_kind.ident() {
err.span_label(
ident.span,
&format!("this function {} have a `self` parameter", doesnt),
);
}
}
} else if let Some(item_kind) = self.diagnostic_metadata.current_item {
err.span_label(
item_kind.ident.span,
format!(
"`self` not allowed in {} {}",
item_kind.kind.article(),
item_kind.kind.descr()
),
);
}
return (err, Vec::new());
}
fn try_lookup_name_relaxed(
&mut self,
err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
source: PathSource<'_>,
path: &[Segment],
span: Span,
res: Option<Res>,
base_error: &BaseError,
) -> (bool, Vec<ImportSuggestion>) {
// Try to lookup name in more relaxed fashion for better error reporting.
let ident = path.last().unwrap().ident;
let is_expected = &|res| source.is_expected(res);
let ns = source.namespace();
let is_enum_variant = &|res| matches!(res, Res::Def(DefKind::Variant, _));
let path_str = Segment::names_to_string(path);
let ident_span = path.last().map_or(span, |ident| ident.ident.span);
let mut candidates = self
.r
.lookup_import_candidates(ident, ns, &self.parent_scope, is_expected)
@@ -494,7 +466,7 @@ struct BaseError<'a> {
{
// Already reported this issue on the lhs of the type ascription.
err.delay_as_bug();
return (err, candidates);
return (true, candidates);
}
}
@@ -522,8 +494,9 @@ struct BaseError<'a> {
);
}
}
// Try Levenshtein algorithm.
let typo_sugg = self.lookup_typo_candidate(path, ns, is_expected);
let typo_sugg = self.lookup_typo_candidate(path, source.namespace(), is_expected);
if path.len() == 1 && self.self_type_is_available() {
if let Some(candidate) = self.lookup_assoc_candidate(ident, ns, is_expected) {
let self_is_available = self.self_value_is_available(path[0].ident.span);
@@ -560,8 +533,8 @@ struct BaseError<'a> {
);
}
}
self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span);
return (err, candidates);
self.r.add_typo_suggestion(err, typo_sugg, ident_span);
return (true, candidates);
}
// If the first argument in call is `self` suggest calling a method.
@@ -579,14 +552,14 @@ struct BaseError<'a> {
format!("self.{path_str}({args_snippet})"),
Applicability::MachineApplicable,
);
return (err, candidates);
return (true, candidates);
}
}
// Try context-dependent help if relaxed lookup didn't work.
if let Some(res) = res {
if self.smart_resolve_context_dependent_help(
&mut err,
err,
span,
source,
res,
@@ -594,106 +567,135 @@ struct BaseError<'a> {
&base_error.fallback_label,
) {
// We do this to avoid losing a secondary span when we override the main error span.
self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span);
return (err, candidates);
self.r.add_typo_suggestion(err, typo_sugg, ident_span);
return (true, candidates);
}
}
return (false, candidates);
}
fn suggest_trait_and_bounds(
&mut self,
err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
source: PathSource<'_>,
res: Option<Res>,
span: Span,
base_error: &BaseError,
) -> bool {
let is_macro =
base_error.span.from_expansion() && base_error.span.desugaring_kind().is_none();
if !self.type_ascription_suggestion(&mut err, base_error.span) {
let mut fallback = false;
if let (
PathSource::Trait(AliasPossibility::Maybe),
Some(Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)),
false,
) = (source, res, is_macro)
{
if let Some(bounds @ [_, .., _]) = self.diagnostic_metadata.current_trait_object {
fallback = true;
let spans: Vec<Span> = bounds
.iter()
.map(|bound| bound.span())
.filter(|&sp| sp != base_error.span)
.collect();
let mut fallback = false;
let start_span = bounds[0].span();
// `end_span` is the end of the poly trait ref (Foo + 'baz + Bar><)
let end_span = bounds.last().unwrap().span();
// `last_bound_span` is the last bound of the poly trait ref (Foo + >'baz< + Bar)
let last_bound_span = spans.last().cloned().unwrap();
let mut multi_span: MultiSpan = spans.clone().into();
for sp in spans {
let msg = if sp == last_bound_span {
format!(
"...because of {these} bound{s}",
these = pluralize!("this", bounds.len() - 1),
s = pluralize!(bounds.len() - 1),
)
} else {
String::new()
};
multi_span.push_span_label(sp, msg);
}
multi_span
.push_span_label(base_error.span, "expected this type to be a trait...");
err.span_help(
multi_span,
"`+` is used to constrain a \"trait object\" type with lifetimes or \
auto-traits; structs and enums can't be bound in that way",
);
if bounds.iter().all(|bound| match bound {
ast::GenericBound::Outlives(_) => true,
ast::GenericBound::Trait(tr, _) => tr.span == base_error.span,
}) {
let mut sugg = vec![];
if base_error.span != start_span {
sugg.push((start_span.until(base_error.span), String::new()));
}
if base_error.span != end_span {
sugg.push((base_error.span.shrink_to_hi().to(end_span), String::new()));
}
err.multipart_suggestion(
"if you meant to use a type and not a trait here, remove the bounds",
sugg,
Applicability::MaybeIncorrect,
);
}
}
}
fallback |= self.restrict_assoc_type_in_where_clause(span, &mut err);
if !self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span) {
if let (
PathSource::Trait(AliasPossibility::Maybe),
Some(Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)),
false,
) = (source, res, is_macro)
{
if let Some(bounds @ [_, .., _]) = self.diagnostic_metadata.current_trait_object {
fallback = true;
match self.diagnostic_metadata.current_let_binding {
Some((pat_sp, Some(ty_sp), None))
if ty_sp.contains(base_error.span) && base_error.could_be_expr =>
{
err.span_suggestion_short(
pat_sp.between(ty_sp),
"use `=` if you meant to assign",
" = ",
Applicability::MaybeIncorrect,
);
}
_ => {}
}
let spans: Vec<Span> = bounds
.iter()
.map(|bound| bound.span())
.filter(|&sp| sp != base_error.span)
.collect();
// If the trait has a single item (which wasn't matched by Levenshtein), suggest it
let suggestion = self.get_single_associated_item(&path, &source, is_expected);
self.r.add_typo_suggestion(&mut err, suggestion, ident_span);
}
if fallback {
// Fallback label.
err.span_label(base_error.span, base_error.fallback_label);
let start_span = bounds[0].span();
// `end_span` is the end of the poly trait ref (Foo + 'baz + Bar><)
let end_span = bounds.last().unwrap().span();
// `last_bound_span` is the last bound of the poly trait ref (Foo + >'baz< + Bar)
let last_bound_span = spans.last().cloned().unwrap();
let mut multi_span: MultiSpan = spans.clone().into();
for sp in spans {
let msg = if sp == last_bound_span {
format!(
"...because of {these} bound{s}",
these = pluralize!("this", bounds.len() - 1),
s = pluralize!(bounds.len() - 1),
)
} else {
String::new()
};
multi_span.push_span_label(sp, msg);
}
multi_span.push_span_label(base_error.span, "expected this type to be a trait...");
err.span_help(
multi_span,
"`+` is used to constrain a \"trait object\" type with lifetimes or \
auto-traits; structs and enums can't be bound in that way",
);
if bounds.iter().all(|bound| match bound {
ast::GenericBound::Outlives(_) => true,
ast::GenericBound::Trait(tr, _) => tr.span == base_error.span,
}) {
let mut sugg = vec![];
if base_error.span != start_span {
sugg.push((start_span.until(base_error.span), String::new()));
}
if base_error.span != end_span {
sugg.push((base_error.span.shrink_to_hi().to(end_span), String::new()));
}
err.multipart_suggestion(
"if you meant to use a type and not a trait here, remove the bounds",
sugg,
Applicability::MaybeIncorrect,
);
}
}
}
fallback |= self.restrict_assoc_type_in_where_clause(span, err);
fallback
}
fn suggest_typo(
&mut self,
err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
source: PathSource<'_>,
path: &[Segment],
span: Span,
base_error: &BaseError,
) -> bool {
let is_expected = &|res| source.is_expected(res);
let ident_span = path.last().map_or(span, |ident| ident.ident.span);
let typo_sugg = self.lookup_typo_candidate(path, source.namespace(), is_expected);
let mut fallback = false;
if !self.r.add_typo_suggestion(err, typo_sugg, ident_span) {
fallback = true;
match self.diagnostic_metadata.current_let_binding {
Some((pat_sp, Some(ty_sp), None))
if ty_sp.contains(base_error.span) && base_error.could_be_expr =>
{
err.span_suggestion_short(
pat_sp.between(ty_sp),
"use `=` if you meant to assign",
" = ",
Applicability::MaybeIncorrect,
);
}
_ => {}
}
// If the trait has a single item (which wasn't matched by Levenshtein), suggest it
let suggestion = self.get_single_associated_item(&path, &source, is_expected);
self.r.add_typo_suggestion(err, suggestion, ident_span);
}
fallback
}
fn err_code_special_cases(
&mut self,
err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
source: PathSource<'_>,
path: &[Segment],
span: Span,
) {
if let Some(err_code) = &err.code {
if err_code == &rustc_errors::error_code!(E0425) {
for label_rib in &self.label_ribs {
for (label_ident, node_id) in &label_rib.bindings {
let ident = path.last().unwrap().ident;
if format!("'{}", ident) == label_ident.to_string() {
err.span_label(label_ident.span, "a label with a similar name exists");
if let PathSource::Expr(Some(Expr {
@@ -724,38 +726,116 @@ struct BaseError<'a> {
}
}
}
(err, candidates)
}
fn detect_assoct_type_constraint_meant_as_path(&self, base_span: Span, err: &mut Diagnostic) {
let Some(ty) = self.diagnostic_metadata.current_type_path else { return; };
let TyKind::Path(_, path) = &ty.kind else { return; };
for segment in &path.segments {
let Some(params) = &segment.args else { continue; };
let ast::GenericArgs::AngleBracketed(ref params) = params.deref() else { continue; };
for param in &params.args {
let ast::AngleBracketedArg::Constraint(constraint) = param else { continue; };
let ast::AssocConstraintKind::Bound { bounds } = &constraint.kind else {
continue;
/// Emit special messages for unresolved `Self` and `self`.
fn suggest_self_ty(
&mut self,
err: &mut Diagnostic,
source: PathSource<'_>,
path: &[Segment],
span: Span,
) -> bool {
if !is_self_type(path, source.namespace()) {
return false;
}
err.code(rustc_errors::error_code!(E0411));
err.span_label(
span,
"`Self` is only available in impls, traits, and type definitions".to_string(),
);
if let Some(item_kind) = self.diagnostic_metadata.current_item {
err.span_label(
item_kind.ident.span,
format!(
"`Self` not allowed in {} {}",
item_kind.kind.article(),
item_kind.kind.descr()
),
);
}
true
}
fn suggest_self_value(
&mut self,
err: &mut Diagnostic,
source: PathSource<'_>,
path: &[Segment],
span: Span,
) -> bool {
if !is_self_value(path, source.namespace()) {
return false;
}
debug!("smart_resolve_path_fragment: E0424, source={:?}", source);
err.code(rustc_errors::error_code!(E0424));
err.span_label(
span,
match source {
PathSource::Pat => {
"`self` value is a keyword and may not be bound to variables or shadowed"
}
_ => "`self` value is a keyword only available in methods with a `self` parameter",
},
);
let is_assoc_fn = self.self_type_is_available();
if let Some((fn_kind, span)) = &self.diagnostic_metadata.current_function {
// The current function has a `self' parameter, but we were unable to resolve
// a reference to `self`. This can only happen if the `self` identifier we
// are resolving came from a different hygiene context.
if fn_kind.decl().inputs.get(0).map_or(false, |p| p.is_self()) {
err.span_label(*span, "this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters");
} else {
let doesnt = if is_assoc_fn {
let (span, sugg) = fn_kind
.decl()
.inputs
.get(0)
.map(|p| (p.span.shrink_to_lo(), "&self, "))
.unwrap_or_else(|| {
// Try to look for the "(" after the function name, if possible.
// This avoids placing the suggestion into the visibility specifier.
let span = fn_kind
.ident()
.map_or(*span, |ident| span.with_lo(ident.span.hi()));
(
self.r
.session
.source_map()
.span_through_char(span, '(')
.shrink_to_hi(),
"&self",
)
});
err.span_suggestion_verbose(
span,
"add a `self` receiver parameter to make the associated `fn` a method",
sugg,
Applicability::MaybeIncorrect,
);
"doesn't"
} else {
"can't"
};
for bound in bounds {
let ast::GenericBound::Trait(trait_ref, ast::TraitBoundModifier::None)
= bound else
{
continue;
};
if base_span == trait_ref.span {
err.span_suggestion_verbose(
constraint.ident.span.between(trait_ref.span),
"you might have meant to write a path instead of an associated type bound",
"::",
Applicability::MachineApplicable,
);
}
if let Some(ident) = fn_kind.ident() {
err.span_label(
ident.span,
&format!("this function {} have a `self` parameter", doesnt),
);
}
}
} else if let Some(item_kind) = self.diagnostic_metadata.current_item {
err.span_label(
item_kind.ident.span,
format!(
"`self` not allowed in {} {}",
item_kind.kind.article(),
item_kind.kind.descr()
),
);
}
true
}
fn suggest_swapping_misplaced_self_ty_and_trait(
@@ -787,6 +867,45 @@ fn suggest_swapping_misplaced_self_ty_and_trait(
}
}
fn suggest_bare_struct_literal(&mut self, err: &mut Diagnostic) {
if let Some(span) = self.diagnostic_metadata.current_block_could_be_bare_struct_literal {
err.multipart_suggestion(
"you might have meant to write a `struct` literal",
vec![
(span.shrink_to_lo(), "{ SomeStruct ".to_string()),
(span.shrink_to_hi(), "}".to_string()),
],
Applicability::HasPlaceholders,
);
}
}
fn suggest_pattern_match_with_let(
&mut self,
err: &mut Diagnostic,
source: PathSource<'_>,
span: Span,
) {
if let PathSource::Expr(_) = source &&
let Some(Expr {
span: expr_span,
kind: ExprKind::Assign(lhs, _, _),
..
}) = self.diagnostic_metadata.in_if_condition {
// Icky heuristic so we don't suggest:
// `if (i + 2) = 2` => `if let (i + 2) = 2` (approximately pattern)
// `if 2 = i` => `if let 2 = i` (lhs needs to contain error span)
if lhs.is_approximately_pattern() && lhs.span.contains(span) {
err.span_suggestion_verbose(
expr_span.shrink_to_lo(),
"you might have meant to use pattern matching",
"let ",
Applicability::MaybeIncorrect,
);
}
}
}
fn get_single_associated_item(
&mut self,
path: &[Segment],
@@ -1737,12 +1737,12 @@ fn candidate_should_be_dropped_in_favor_of(
(&ImplCandidate(other_def), &ImplCandidate(victim_def)) => {
// See if we can toss out `victim` based on specialization.
// This requires us to know *for sure* that the `other` impl applies
// i.e., `EvaluatedToOk`.
// While this requires us to know *for sure* that the `other` impl applies
// we still use modulo regions here.
//
// FIXME(@lcnr): Using `modulo_regions` here seems kind of scary
// to me but is required for `std` to compile, so I didn't change it
// for now.
// This is fine as specialization currently assumes that specializing
// impls have to be always applicable, meaning that the only allowed
// region constraints may be constraints also present on the default impl.
let tcx = self.tcx();
if other.evaluation.must_apply_modulo_regions() {
if tcx.specializes((other_def, victim_def)) {
+52 -46
View File
@@ -29,6 +29,20 @@
const MILLIS_PER_SEC: u64 = 1_000;
const MICROS_PER_SEC: u64 = 1_000_000;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
#[rustc_layout_scalar_valid_range_start(0)]
#[rustc_layout_scalar_valid_range_end(999_999_999)]
struct Nanoseconds(u32);
impl Default for Nanoseconds {
#[inline]
fn default() -> Self {
// SAFETY: 0 is within the valid range
unsafe { Nanoseconds(0) }
}
}
/// A `Duration` type to represent a span of time, typically used for system
/// timeouts.
///
@@ -71,7 +85,7 @@
#[cfg_attr(not(test), rustc_diagnostic_item = "Duration")]
pub struct Duration {
secs: u64,
nanos: u32, // Always 0 <= nanos < NANOS_PER_SEC
nanos: Nanoseconds, // Always 0 <= nanos < NANOS_PER_SEC
}
impl Duration {
@@ -188,7 +202,8 @@ pub const fn new(secs: u64, nanos: u32) -> Duration {
None => panic!("overflow in Duration::new"),
};
let nanos = nanos % NANOS_PER_SEC;
Duration { secs, nanos }
// SAFETY: nanos % NANOS_PER_SEC < NANOS_PER_SEC, therefore nanos is within the valid range
Duration { secs, nanos: unsafe { Nanoseconds(nanos) } }
}
/// Creates a new `Duration` from the specified number of whole seconds.
@@ -208,7 +223,7 @@ pub const fn new(secs: u64, nanos: u32) -> Duration {
#[inline]
#[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]
pub const fn from_secs(secs: u64) -> Duration {
Duration { secs, nanos: 0 }
Duration::new(secs, 0)
}
/// Creates a new `Duration` from the specified number of milliseconds.
@@ -228,10 +243,7 @@ pub const fn from_secs(secs: u64) -> Duration {
#[inline]
#[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]
pub const fn from_millis(millis: u64) -> Duration {
Duration {
secs: millis / MILLIS_PER_SEC,
nanos: ((millis % MILLIS_PER_SEC) as u32) * NANOS_PER_MILLI,
}
Duration::new(millis / MILLIS_PER_SEC, ((millis % MILLIS_PER_SEC) as u32) * NANOS_PER_MILLI)
}
/// Creates a new `Duration` from the specified number of microseconds.
@@ -251,10 +263,7 @@ pub const fn from_millis(millis: u64) -> Duration {
#[inline]
#[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]
pub const fn from_micros(micros: u64) -> Duration {
Duration {
secs: micros / MICROS_PER_SEC,
nanos: ((micros % MICROS_PER_SEC) as u32) * NANOS_PER_MICRO,
}
Duration::new(micros / MICROS_PER_SEC, ((micros % MICROS_PER_SEC) as u32) * NANOS_PER_MICRO)
}
/// Creates a new `Duration` from the specified number of nanoseconds.
@@ -274,10 +283,7 @@ pub const fn from_micros(micros: u64) -> Duration {
#[inline]
#[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]
pub const fn from_nanos(nanos: u64) -> Duration {
Duration {
secs: nanos / (NANOS_PER_SEC as u64),
nanos: (nanos % (NANOS_PER_SEC as u64)) as u32,
}
Duration::new(nanos / (NANOS_PER_SEC as u64), (nanos % (NANOS_PER_SEC as u64)) as u32)
}
/// Returns true if this `Duration` spans no time.
@@ -301,7 +307,7 @@ pub const fn from_nanos(nanos: u64) -> Duration {
#[rustc_const_stable(feature = "duration_zero", since = "1.53.0")]
#[inline]
pub const fn is_zero(&self) -> bool {
self.secs == 0 && self.nanos == 0
self.secs == 0 && self.nanos.0 == 0
}
/// Returns the number of _whole_ seconds contained by this `Duration`.
@@ -352,7 +358,7 @@ pub const fn as_secs(&self) -> u64 {
#[must_use]
#[inline]
pub const fn subsec_millis(&self) -> u32 {
self.nanos / NANOS_PER_MILLI
self.nanos.0 / NANOS_PER_MILLI
}
/// Returns the fractional part of this `Duration`, in whole microseconds.
@@ -375,7 +381,7 @@ pub const fn subsec_millis(&self) -> u32 {
#[must_use]
#[inline]
pub const fn subsec_micros(&self) -> u32 {
self.nanos / NANOS_PER_MICRO
self.nanos.0 / NANOS_PER_MICRO
}
/// Returns the fractional part of this `Duration`, in nanoseconds.
@@ -398,7 +404,7 @@ pub const fn subsec_micros(&self) -> u32 {
#[must_use]
#[inline]
pub const fn subsec_nanos(&self) -> u32 {
self.nanos
self.nanos.0
}
/// Returns the total number of whole milliseconds contained by this `Duration`.
@@ -416,7 +422,7 @@ pub const fn subsec_nanos(&self) -> u32 {
#[must_use]
#[inline]
pub const fn as_millis(&self) -> u128 {
self.secs as u128 * MILLIS_PER_SEC as u128 + (self.nanos / NANOS_PER_MILLI) as u128
self.secs as u128 * MILLIS_PER_SEC as u128 + (self.nanos.0 / NANOS_PER_MILLI) as u128
}
/// Returns the total number of whole microseconds contained by this `Duration`.
@@ -434,7 +440,7 @@ pub const fn as_millis(&self) -> u128 {
#[must_use]
#[inline]
pub const fn as_micros(&self) -> u128 {
self.secs as u128 * MICROS_PER_SEC as u128 + (self.nanos / NANOS_PER_MICRO) as u128
self.secs as u128 * MICROS_PER_SEC as u128 + (self.nanos.0 / NANOS_PER_MICRO) as u128
}
/// Returns the total number of nanoseconds contained by this `Duration`.
@@ -452,7 +458,7 @@ pub const fn as_micros(&self) -> u128 {
#[must_use]
#[inline]
pub const fn as_nanos(&self) -> u128 {
self.secs as u128 * NANOS_PER_SEC as u128 + self.nanos as u128
self.secs as u128 * NANOS_PER_SEC as u128 + self.nanos.0 as u128
}
/// Checked `Duration` addition. Computes `self + other`, returning [`None`]
@@ -475,7 +481,7 @@ pub const fn as_nanos(&self) -> u128 {
#[rustc_const_stable(feature = "duration_consts_2", since = "1.58.0")]
pub const fn checked_add(self, rhs: Duration) -> Option<Duration> {
if let Some(mut secs) = self.secs.checked_add(rhs.secs) {
let mut nanos = self.nanos + rhs.nanos;
let mut nanos = self.nanos.0 + rhs.nanos.0;
if nanos >= NANOS_PER_SEC {
nanos -= NANOS_PER_SEC;
if let Some(new_secs) = secs.checked_add(1) {
@@ -485,7 +491,7 @@ pub const fn checked_add(self, rhs: Duration) -> Option<Duration> {
}
}
debug_assert!(nanos < NANOS_PER_SEC);
Some(Duration { secs, nanos })
Some(Duration::new(secs, nanos))
} else {
None
}
@@ -535,16 +541,16 @@ pub const fn saturating_add(self, rhs: Duration) -> Duration {
#[rustc_const_stable(feature = "duration_consts_2", since = "1.58.0")]
pub const fn checked_sub(self, rhs: Duration) -> Option<Duration> {
if let Some(mut secs) = self.secs.checked_sub(rhs.secs) {
let nanos = if self.nanos >= rhs.nanos {
self.nanos - rhs.nanos
let nanos = if self.nanos.0 >= rhs.nanos.0 {
self.nanos.0 - rhs.nanos.0
} else if let Some(sub_secs) = secs.checked_sub(1) {
secs = sub_secs;
self.nanos + NANOS_PER_SEC - rhs.nanos
self.nanos.0 + NANOS_PER_SEC - rhs.nanos.0
} else {
return None;
};
debug_assert!(nanos < NANOS_PER_SEC);
Some(Duration { secs, nanos })
Some(Duration::new(secs, nanos))
} else {
None
}
@@ -593,13 +599,13 @@ pub const fn saturating_sub(self, rhs: Duration) -> Duration {
#[rustc_const_stable(feature = "duration_consts_2", since = "1.58.0")]
pub const fn checked_mul(self, rhs: u32) -> Option<Duration> {
// Multiply nanoseconds as u64, because it cannot overflow that way.
let total_nanos = self.nanos as u64 * rhs as u64;
let total_nanos = self.nanos.0 as u64 * rhs as u64;
let extra_secs = total_nanos / (NANOS_PER_SEC as u64);
let nanos = (total_nanos % (NANOS_PER_SEC as u64)) as u32;
if let Some(s) = self.secs.checked_mul(rhs as u64) {
if let Some(secs) = s.checked_add(extra_secs) {
debug_assert!(nanos < NANOS_PER_SEC);
return Some(Duration { secs, nanos });
return Some(Duration::new(secs, nanos));
}
}
None
@@ -653,9 +659,9 @@ pub const fn checked_div(self, rhs: u32) -> Option<Duration> {
let secs = self.secs / (rhs as u64);
let carry = self.secs - secs * (rhs as u64);
let extra_nanos = carry * (NANOS_PER_SEC as u64) / (rhs as u64);
let nanos = self.nanos / rhs + (extra_nanos as u32);
let nanos = self.nanos.0 / rhs + (extra_nanos as u32);
debug_assert!(nanos < NANOS_PER_SEC);
Some(Duration { secs, nanos })
Some(Duration::new(secs, nanos))
} else {
None
}
@@ -677,7 +683,7 @@ pub const fn checked_div(self, rhs: u32) -> Option<Duration> {
#[inline]
#[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")]
pub const fn as_secs_f64(&self) -> f64 {
(self.secs as f64) + (self.nanos as f64) / (NANOS_PER_SEC as f64)
(self.secs as f64) + (self.nanos.0 as f64) / (NANOS_PER_SEC as f64)
}
/// Returns the number of seconds contained by this `Duration` as `f32`.
@@ -696,7 +702,7 @@ pub const fn as_secs_f64(&self) -> f64 {
#[inline]
#[rustc_const_unstable(feature = "duration_consts_float", issue = "72440")]
pub const fn as_secs_f32(&self) -> f32 {
(self.secs as f32) + (self.nanos as f32) / (NANOS_PER_SEC as f32)
(self.secs as f32) + (self.nanos.0 as f32) / (NANOS_PER_SEC as f32)
}
/// Creates a new `Duration` from the specified number of seconds represented
@@ -987,13 +993,13 @@ macro_rules! sum_durations {
for entry in $iter {
total_secs =
total_secs.checked_add(entry.secs).expect("overflow in iter::sum over durations");
total_nanos = match total_nanos.checked_add(entry.nanos as u64) {
total_nanos = match total_nanos.checked_add(entry.nanos.0 as u64) {
Some(n) => n,
None => {
total_secs = total_secs
.checked_add(total_nanos / NANOS_PER_SEC as u64)
.expect("overflow in iter::sum over durations");
(total_nanos % NANOS_PER_SEC as u64) + entry.nanos as u64
(total_nanos % NANOS_PER_SEC as u64) + entry.nanos.0 as u64
}
};
}
@@ -1001,7 +1007,7 @@ macro_rules! sum_durations {
.checked_add(total_nanos / NANOS_PER_SEC as u64)
.expect("overflow in iter::sum over durations");
total_nanos = total_nanos % NANOS_PER_SEC as u64;
Duration { secs: total_secs, nanos: total_nanos as u32 }
Duration::new(total_secs, total_nanos as u32)
}};
}
@@ -1166,27 +1172,27 @@ fn fmt_decimal(
let prefix = if f.sign_plus() { "+" } else { "" };
if self.secs > 0 {
fmt_decimal(f, self.secs, self.nanos, NANOS_PER_SEC / 10, prefix, "s")
} else if self.nanos >= NANOS_PER_MILLI {
fmt_decimal(f, self.secs, self.nanos.0, NANOS_PER_SEC / 10, prefix, "s")
} else if self.nanos.0 >= NANOS_PER_MILLI {
fmt_decimal(
f,
(self.nanos / NANOS_PER_MILLI) as u64,
self.nanos % NANOS_PER_MILLI,
(self.nanos.0 / NANOS_PER_MILLI) as u64,
self.nanos.0 % NANOS_PER_MILLI,
NANOS_PER_MILLI / 10,
prefix,
"ms",
)
} else if self.nanos >= NANOS_PER_MICRO {
} else if self.nanos.0 >= NANOS_PER_MICRO {
fmt_decimal(
f,
(self.nanos / NANOS_PER_MICRO) as u64,
self.nanos % NANOS_PER_MICRO,
(self.nanos.0 / NANOS_PER_MICRO) as u64,
self.nanos.0 % NANOS_PER_MICRO,
NANOS_PER_MICRO / 10,
prefix,
"µs",
)
} else {
fmt_decimal(f, self.nanos as u64, 0, 1, prefix, "ns")
fmt_decimal(f, self.nanos.0 as u64, 0, 1, prefix, "ns")
}
}
}
@@ -1317,7 +1323,7 @@ macro_rules! try_from_secs {
return Err(FromFloatSecsError { kind: FromFloatSecsErrorKind::OverflowOrNan });
};
Ok(Duration { secs, nanos })
Ok(Duration::new(secs, nanos))
}};
}
+1 -1
View File
@@ -603,7 +603,7 @@ pub fn home_dir() -> Option<PathBuf> {
/// # Platform-specific behavior
///
/// On Unix, returns the value of the `TMPDIR` environment variable if it is
/// set, otherwise for non-Android it returns `/tmp`. If Android, since there
/// set, otherwise for non-Android it returns `/tmp`. On Android, since there
/// is no global temporary folder (it is usually allocated per-app), it returns
/// `/data/local/tmp`.
/// On Windows, the behavior is equivalent to that of [`GetTempPath2`][GetTempPath2] /
+11 -2
View File
@@ -1,16 +1,25 @@
//! Owned and borrowed Unix-like file descriptors.
//!
//! This module is supported on Unix platforms and WASI, which both use a
//! similar file descriptor system for referencing OS resources.
#![stable(feature = "io_safety", since = "1.63.0")]
#![deny(unsafe_op_in_unsafe_fn)]
// `RawFd`, `AsRawFd`, etc.
pub mod raw;
mod raw;
// `OwnedFd`, `AsFd`, etc.
pub mod owned;
mod owned;
// Implementations for `AsRawFd` etc. for network types.
mod net;
#[cfg(test)]
mod tests;
// Export the types and traits for the public API.
#[unstable(feature = "os_fd", issue = "98699")]
pub use owned::*;
#[unstable(feature = "os_fd", issue = "98699")]
pub use raw::*;
+2 -4
View File
@@ -206,10 +206,8 @@ pub trait AsFd {
/// ```rust,no_run
/// use std::fs::File;
/// # use std::io;
/// # #[cfg(target_os = "wasi")]
/// # use std::os::wasi::io::{AsFd, BorrowedFd};
/// # #[cfg(unix)]
/// # use std::os::unix::io::{AsFd, BorrowedFd};
/// # #[cfg(any(unix, target_os = "wasi"))]
/// # use std::os::fd::{AsFd, BorrowedFd};
///
/// let mut f = File::open("foo.txt")?;
/// # #[cfg(any(unix, target_os = "wasi"))]
+6 -12
View File
@@ -42,10 +42,8 @@ pub trait AsRawFd {
/// ```no_run
/// use std::fs::File;
/// # use std::io;
/// #[cfg(unix)]
/// use std::os::unix::io::{AsRawFd, RawFd};
/// #[cfg(target_os = "wasi")]
/// use std::os::wasi::io::{AsRawFd, RawFd};
/// #[cfg(any(unix, target_os = "wasi"))]
/// use std::os::fd::{AsRawFd, RawFd};
///
/// let mut f = File::open("foo.txt")?;
/// // Note that `raw_fd` is only valid as long as `f` exists.
@@ -83,10 +81,8 @@ pub trait FromRawFd {
/// ```no_run
/// use std::fs::File;
/// # use std::io;
/// #[cfg(unix)]
/// use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd};
/// #[cfg(target_os = "wasi")]
/// use std::os::wasi::io::{FromRawFd, IntoRawFd, RawFd};
/// #[cfg(any(unix, target_os = "wasi"))]
/// use std::os::fd::{FromRawFd, IntoRawFd, RawFd};
///
/// let f = File::open("foo.txt")?;
/// # #[cfg(any(unix, target_os = "wasi"))]
@@ -121,10 +117,8 @@ pub trait IntoRawFd {
/// ```no_run
/// use std::fs::File;
/// # use std::io;
/// #[cfg(unix)]
/// use std::os::unix::io::{IntoRawFd, RawFd};
/// #[cfg(target_os = "wasi")]
/// use std::os::wasi::io::{IntoRawFd, RawFd};
/// #[cfg(any(unix, target_os = "wasi"))]
/// use std::os::fd::{IntoRawFd, RawFd};
///
/// let f = File::open("foo.txt")?;
/// #[cfg(any(unix, target_os = "wasi"))]
+1 -1
View File
@@ -147,7 +147,7 @@ pub mod windows {}
pub mod vxworks;
#[cfg(any(unix, target_os = "wasi", doc))]
mod fd;
pub mod fd;
#[cfg(any(target_os = "linux", target_os = "android", doc))]
mod net;
-8
View File
@@ -1,8 +0,0 @@
//! Owned and borrowed file descriptors.
// Tests for this module
#[cfg(test)]
mod tests;
#[stable(feature = "io_safety", since = "1.63.0")]
pub use crate::os::fd::owned::*;
+5 -6
View File
@@ -77,10 +77,9 @@
#![stable(feature = "rust1", since = "1.0.0")]
mod fd;
mod raw;
#[stable(feature = "io_safety", since = "1.63.0")]
pub use fd::*;
#[stable(feature = "rust1", since = "1.0.0")]
pub use raw::*;
pub use crate::os::fd::*;
// Tests for this module
#[cfg(test)]
mod tests;
-6
View File
@@ -1,6 +0,0 @@
//! Unix-specific extensions to general I/O primitives.
#![stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "rust1", since = "1.0.0")]
pub use crate::os::fd::raw::*;
+1 -7
View File
@@ -1,12 +1,6 @@
//! WASI-specific extensions to general I/O primitives.
#![deny(unsafe_op_in_unsafe_fn)]
#![unstable(feature = "wasi_ext", issue = "71213")]
mod fd;
mod raw;
#[unstable(feature = "wasi_ext", issue = "71213")]
pub use fd::*;
#[unstable(feature = "wasi_ext", issue = "71213")]
pub use raw::*;
pub use crate::os::fd::*;
+21 -13
View File
@@ -6,6 +6,12 @@
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)]
#[repr(transparent)]
#[rustc_layout_scalar_valid_range_start(0)]
#[rustc_layout_scalar_valid_range_end(999_999_999)]
struct Nanoseconds(u32);
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SystemTime {
pub(in crate::sys::unix) t: Timespec,
@@ -14,7 +20,7 @@ pub struct SystemTime {
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(in crate::sys::unix) struct Timespec {
tv_sec: i64,
tv_nsec: i64,
tv_nsec: Nanoseconds,
}
impl SystemTime {
@@ -46,18 +52,20 @@ 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)
.field("tv_nsec", &self.t.tv_nsec.0)
.finish()
}
}
impl Timespec {
pub const fn zero() -> Timespec {
Timespec { tv_sec: 0, tv_nsec: 0 }
Timespec::new(0, 0)
}
fn new(tv_sec: i64, tv_nsec: i64) -> Timespec {
Timespec { tv_sec, tv_nsec }
const fn new(tv_sec: i64, tv_nsec: i64) -> Timespec {
assert!(tv_nsec >= 0 && tv_nsec < NSEC_PER_SEC as i64);
// SAFETY: The assert above checks tv_nsec is within the valid range
Timespec { tv_sec, tv_nsec: unsafe { Nanoseconds(tv_nsec as u32) } }
}
pub fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
@@ -75,12 +83,12 @@ pub fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
//
// 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.tv_nsec >= other.tv_nsec {
((self.tv_sec - other.tv_sec) as u64, (self.tv_nsec - other.tv_nsec) as u32)
let (secs, nsec) = if self.tv_nsec.0 >= other.tv_nsec.0 {
((self.tv_sec - other.tv_sec) as u64, self.tv_nsec.0 - other.tv_nsec.0)
} else {
(
(self.tv_sec - other.tv_sec - 1) as u64,
self.tv_nsec as u32 + (NSEC_PER_SEC as u32) - other.tv_nsec as u32,
self.tv_nsec.0 + (NSEC_PER_SEC as u32) - other.tv_nsec.0,
)
};
@@ -102,7 +110,7 @@ pub fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
// Nano calculations can't overflow because nanos are <1B which fit
// in a u32.
let mut nsec = other.subsec_nanos() + self.tv_nsec as u32;
let mut nsec = other.subsec_nanos() + self.tv_nsec.0;
if nsec >= NSEC_PER_SEC as u32 {
nsec -= NSEC_PER_SEC as u32;
secs = secs.checked_add(1)?;
@@ -118,7 +126,7 @@ pub fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
.and_then(|secs| self.tv_sec.checked_sub(secs))?;
// Similar to above, nanos can't overflow.
let mut nsec = self.tv_nsec as i32 - other.subsec_nanos() as i32;
let mut nsec = self.tv_nsec.0 as i32 - other.subsec_nanos() as i32;
if nsec < 0 {
nsec += NSEC_PER_SEC as i32;
secs = secs.checked_sub(1)?;
@@ -130,7 +138,7 @@ pub fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
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()?,
tv_nsec: self.tv_nsec.0.try_into().ok()?,
})
}
}
@@ -293,7 +301,7 @@ impl fmt::Debug for Instant {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Instant")
.field("tv_sec", &self.t.tv_sec)
.field("tv_nsec", &self.t.tv_nsec)
.field("tv_nsec", &self.t.tv_nsec.0)
.finish()
}
}
@@ -334,7 +342,7 @@ struct __timespec64 {
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 };
return Timespec::new(t.tv_sec, t.tv_nsec as i64);
}
}
+2 -2
View File
@@ -154,10 +154,10 @@
</Type>
<Type Name="core::time::Duration">
<DisplayString>{secs,d}s {nanos,d}ns</DisplayString>
<DisplayString>{secs,d}s {nanos.__0,d}ns</DisplayString>
<Expand>
<Item Name="seconds">secs,d</Item>
<Item Name="nanoseconds">nanos,d</Item>
<Item Name="nanoseconds">nanos.__0,d</Item>
</Expand>
</Type>
</AutoVisualizer>
+3 -3
View File
@@ -6,9 +6,9 @@ const EXPECTED = {
'others': [
// Reproduction test for https://github.com/rust-lang/rust/issues/78724
// Validate that type alias methods get the correct path.
{ 'path': 'std::os::unix::io::AsRawFd', 'name': 'as_raw_fd' },
{ 'path': 'std::os::wasi::io::AsRawFd', 'name': 'as_raw_fd' },
{ 'path': 'std::os::fd::AsRawFd', 'name': 'as_raw_fd' },
{ 'path': 'std::os::fd::AsRawFd', 'name': 'as_raw_fd' },
{ 'path': 'std::os::linux::process::PidFd', 'name': 'as_raw_fd' },
{ 'path': 'std::os::unix::io::RawFd', 'name': 'as_raw_fd' },
{ 'path': 'std::os::fd::RawFd', 'name': 'as_raw_fd' },
],
};
+1 -1
View File
@@ -4,7 +4,7 @@ error[E0585]: found a documentation comment that doesn't document anything
LL | /// Hello! I'm useless...
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: doc comments must come before what they document, maybe a comment was intended with `//`?
= help: doc comments must come before what they document, if a comment was intended use `//`
error: aborting due to previous error
+49
View File
@@ -0,0 +1,49 @@
// run-pass
// regression test for issue #94923
// min-llvm-version: 15.0.0
// compile-flags: -C opt-level=3
fn f0<T>(mut x: usize) -> usize {
for _ in 0..1000 {
x *= 123;
x %= 99
}
x + 321 // function composition is not just longer iteration
}
fn f1<T>(x: usize) -> usize {
f0::<(i8, T)>(f0::<(u8, T)>(x))
}
fn f2<T>(x: usize) -> usize {
f1::<(i8, T)>(f1::<(u8, T)>(x))
}
fn f3<T>(x: usize) -> usize {
f2::<(i8, T)>(f2::<(u8, T)>(x))
}
fn f4<T>(x: usize) -> usize {
f3::<(i8, T)>(f3::<(u8, T)>(x))
}
fn f5<T>(x: usize) -> usize {
f4::<(i8, T)>(f4::<(u8, T)>(x))
}
fn f6<T>(x: usize) -> usize {
f5::<(i8, T)>(f5::<(u8, T)>(x))
}
fn f7<T>(x: usize) -> usize {
f6::<(i8, T)>(f6::<(u8, T)>(x))
}
fn f8<T>(x: usize) -> usize {
f7::<(i8, T)>(f7::<(u8, T)>(x))
}
fn main() {
let y = f8::<()>(1);
assert_eq!(y, 348);
}
+2 -2
View File
@@ -1,13 +1,13 @@
struct X {
a: u8 /** document a */,
//~^ ERROR found a documentation comment that doesn't document anything
//~| HELP maybe a comment was intended
//~| HELP if a comment was intended use `//`
}
struct Y {
a: u8 /// document a
//~^ ERROR found a documentation comment that doesn't document anything
//~| HELP maybe a comment was intended
//~| HELP if a comment was intended use `//`
}
fn main() {
@@ -4,7 +4,7 @@ error[E0585]: found a documentation comment that doesn't document anything
LL | a: u8 /** document a */,
| ^^^^^^^^^^^^^^^^^
|
= help: doc comments must come before what they document, maybe a comment was intended with `//`?
= help: doc comments must come before what they document, if a comment was intended use `//`
error[E0585]: found a documentation comment that doesn't document anything
--> $DIR/doc-after-struct-field.rs:8:11
@@ -12,7 +12,7 @@ error[E0585]: found a documentation comment that doesn't document anything
LL | a: u8 /// document a
| ^^^^^^^^^^^^^^
|
= help: doc comments must come before what they document, maybe a comment was intended with `//`?
= help: doc comments must come before what they document, if a comment was intended use `//`
error: aborting due to 2 previous errors
@@ -4,7 +4,7 @@ error[E0584]: found a documentation comment that doesn't document anything
LL | /// hi
| ^^^^^^ this doc comment doesn't document anything
|
= help: doc comments must come before what they document, maybe a comment was intended with `//`?
= help: doc comments must come before what they document, if a comment was intended use `//`
error: aborting due to previous error
+1 -1
View File
@@ -1,5 +1,5 @@
fn main() {
/// document
//~^ ERROR found a documentation comment that doesn't document anything
//~| HELP maybe a comment was intended
//~| HELP if a comment was intended use `//`
}
@@ -4,7 +4,7 @@ error[E0585]: found a documentation comment that doesn't document anything
LL | /// document
| ^^^^^^^^^^^^
|
= help: doc comments must come before what they document, maybe a comment was intended with `//`?
= help: doc comments must come before what they document, if a comment was intended use `//`
error: aborting due to previous error
+1 -1
View File
@@ -1,5 +1,5 @@
fn main() {
println!("Hi"); /// hi
//~^ ERROR found a documentation comment that doesn't document anything
//~| HELP maybe a comment was intended
//~| HELP if a comment was intended use `//`
}
+1 -1
View File
@@ -4,7 +4,7 @@ error[E0585]: found a documentation comment that doesn't document anything
LL | println!("Hi"); /// hi
| ^^^^^^
|
= help: doc comments must come before what they document, maybe a comment was intended with `//`?
= help: doc comments must come before what they document, if a comment was intended use `//`
error: aborting due to previous error
+1 -1
View File
@@ -1,6 +1,6 @@
fn main() {
/// hi
//~^ ERROR found a documentation comment that doesn't document anything
//~| HELP maybe a comment was intended
//~| HELP if a comment was intended use `//`
;
}
+1 -1
View File
@@ -4,7 +4,7 @@ error[E0585]: found a documentation comment that doesn't document anything
LL | /// hi
| ^^^^^^
|
= help: doc comments must come before what they document, maybe a comment was intended with `//`?
= help: doc comments must come before what they document, if a comment was intended use `//`
error: aborting due to previous error
@@ -2,7 +2,7 @@ struct X {
a: u8,
/// document
//~^ ERROR found a documentation comment that doesn't document anything
//~| HELP maybe a comment was intended
//~| HELP if a comment was intended use `//`
}
fn main() {
@@ -7,7 +7,7 @@ LL | a: u8,
LL | /// document
| ^^^^^^^^^^^^
|
= help: doc comments must come before what they document, maybe a comment was intended with `//`?
= help: doc comments must come before what they document, if a comment was intended use `//`
error: aborting due to previous error
@@ -1,7 +1,7 @@
struct X {
a: u8 /// document
//~^ ERROR found a documentation comment that doesn't document anything
//~| HELP maybe a comment was intended
//~| HELP if a comment was intended use `//`
}
fn main() {
@@ -4,7 +4,7 @@ error[E0585]: found a documentation comment that doesn't document anything
LL | a: u8 /// document
| ^^^^^^^^^^^^
|
= help: doc comments must come before what they document, maybe a comment was intended with `//`?
= help: doc comments must come before what they document, if a comment was intended use `//`
error: aborting due to previous error
@@ -4,7 +4,7 @@ error[E0584]: found a documentation comment that doesn't document anything
LL | /// empty doc
| ^^^^^^^^^^^^^ this doc comment doesn't document anything
|
= help: doc comments must come before what they document, maybe a comment was intended with `//`?
= help: doc comments must come before what they document, if a comment was intended use `//`
error: aborting due to previous error
@@ -4,7 +4,7 @@ error[E0585]: found a documentation comment that doesn't document anything
LL | /// comment
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: doc comments must come before what they document, maybe a comment was intended with `//`?
= help: doc comments must come before what they document, if a comment was intended use `//`
error: aborting due to previous error
+1 -1
View File
@@ -8,7 +8,7 @@ LL | x: u8
LL | /// The ID of the parent core
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: doc comments must come before what they document, maybe a comment was intended with `//`?
= help: doc comments must come before what they document, if a comment was intended use `//`
error: aborting due to previous error
+20
View File
@@ -0,0 +1,20 @@
use std::cell::Cell;
#[rustfmt::skip]
fn f(
f: for<'a, 'b, 'c, 'd, 'e, 'f, 'g,
'h, 'i, 'j, 'k, 'l, 'm, 'n,
'o, 'p, 'q, 'r, 's, 't, 'u,
'v, 'w, 'x, 'y, 'z, 'z0>
fn(Cell<(& i32, &'a i32, &'b i32, &'c i32, &'d i32,
&'e i32, &'f i32, &'g i32, &'h i32, &'i i32,
&'j i32, &'k i32, &'l i32, &'m i32, &'n i32,
&'o i32, &'p i32, &'q i32, &'r i32, &'s i32,
&'t i32, &'u i32, &'v i32, &'w i32, &'x i32,
&'y i32, &'z i32, &'z0 i32)>),
) -> i32 {
f
//~^ ERROR mismatched types
}
fn main() {}
+14
View File
@@ -0,0 +1,14 @@
error[E0308]: mismatched types
--> $DIR/issue-102374.rs:16:5
|
LL | ) -> i32 {
| --- expected `i32` because of return type
LL | f
| ^ expected `i32`, found fn pointer
|
= note: expected type `i32`
found fn pointer `for<'z1, 'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k, 'l, 'm, 'n, 'o, 'p, 'q, 'r, 's, 't, 'u, 'v, 'w, 'x, 'y, 'z, 'z0> fn(Cell<(&'z1 i32, &'a i32, &'b i32, &'c i32, &'d i32, &'e i32, &'f i32, &'g i32, &'h i32, &'i i32, &'j i32, &'k i32, &'l i32, &'m i32, &'n i32, &'o i32, &'p i32, &'q i32, &'r i32, &'s i32, &'t i32, &'u i32, &'v i32, &'w i32, &'x i32, &'y i32, &'z i32, &'z0 i32)>)`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.