mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-28 20:16:58 +03:00
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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 ¶ms.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 ¶ms.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
@@ -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))
|
||||
}};
|
||||
}
|
||||
|
||||
|
||||
@@ -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] /
|
||||
|
||||
@@ -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::*;
|
||||
|
||||
@@ -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"))]
|
||||
|
||||
@@ -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"))]
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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::*;
|
||||
@@ -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;
|
||||
|
||||
@@ -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,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::*;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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' },
|
||||
],
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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,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,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 `//`
|
||||
}
|
||||
|
||||
@@ -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,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 `//`
|
||||
;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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() {}
|
||||
@@ -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`.
|
||||
Reference in New Issue
Block a user