Auto merge of #100868 - Dylan-DPC:rollup-a1hfi1r, r=Dylan-DPC
Rollup of 5 pull requests Successful merges: - #93162 (Std module docs improvements) - #99386 (Add tests that check `Vec::retain` predicate execution order.) - #99915 (Recover keywords in trait bounds) - #100694 (Migrate rustc_ast_passes diagnostics to `SessionDiagnostic` and translatable messages (first part)) - #100757 (Catch overflow early) Failed merges: - #99917 (Move Error trait into core) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
ee8c31e64d
40 changed files with 957 additions and 342 deletions
|
@ -3595,6 +3595,7 @@ dependencies = [
|
|||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_macros",
|
||||
"rustc_parse",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
|
|
|
@ -11,6 +11,7 @@ rustc_attr = { path = "../rustc_attr" }
|
|||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
rustc_feature = { path = "../rustc_feature" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_parse = { path = "../rustc_parse" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
|
|
|
@ -13,7 +13,7 @@ use rustc_ast::walk_list;
|
|||
use rustc_ast::*;
|
||||
use rustc_ast_pretty::pprust::{self, State};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::{error_code, pluralize, struct_span_err, Applicability, Diagnostic};
|
||||
use rustc_errors::{error_code, fluent, pluralize, struct_span_err, Applicability};
|
||||
use rustc_parse::validate_attr;
|
||||
use rustc_session::lint::builtin::{
|
||||
DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY,
|
||||
|
@ -27,6 +27,8 @@ use rustc_target::spec::abi;
|
|||
use std::mem;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use crate::errors::*;
|
||||
|
||||
const MORE_EXTERN: &str =
|
||||
"for more information, visit https://doc.rust-lang.org/std/keyword.extern.html";
|
||||
|
||||
|
@ -117,23 +119,7 @@ impl<'a> AstValidator<'a> {
|
|||
|
||||
/// Emits an error banning the `let` expression provided in the given location.
|
||||
fn ban_let_expr(&self, expr: &'a Expr, forbidden_let_reason: ForbiddenLetReason) {
|
||||
let err = "`let` expressions are not supported here";
|
||||
let mut diag = self.session.struct_span_err(expr.span, err);
|
||||
diag.note("only supported directly in conditions of `if` and `while` expressions");
|
||||
match forbidden_let_reason {
|
||||
ForbiddenLetReason::GenericForbidden => {}
|
||||
ForbiddenLetReason::NotSupportedOr(span) => {
|
||||
diag.span_note(span, "`||` operators are not supported in let chain expressions");
|
||||
}
|
||||
ForbiddenLetReason::NotSupportedParentheses(span) => {
|
||||
diag.span_note(
|
||||
span,
|
||||
"`let`s wrapped in parentheses are not supported in a context with let \
|
||||
chains",
|
||||
);
|
||||
}
|
||||
}
|
||||
diag.emit();
|
||||
self.session.emit_err(ForbiddenLet { span: expr.span, reason: forbidden_let_reason });
|
||||
}
|
||||
|
||||
fn check_gat_where(
|
||||
|
@ -163,7 +149,7 @@ impl<'a> AstValidator<'a> {
|
|||
DEPRECATED_WHERE_CLAUSE_LOCATION,
|
||||
id,
|
||||
where_clauses.0.1,
|
||||
"where clause not allowed here",
|
||||
fluent::ast_passes::deprecated_where_clause_location,
|
||||
BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
|
||||
where_clauses.1.1.shrink_to_hi(),
|
||||
suggestion,
|
||||
|
@ -193,10 +179,7 @@ impl<'a> AstValidator<'a> {
|
|||
AssocConstraintKind::Equality { .. } => {}
|
||||
AssocConstraintKind::Bound { .. } => {
|
||||
if self.is_assoc_ty_bound_banned {
|
||||
self.err_handler().span_err(
|
||||
constraint.span,
|
||||
"associated type bounds are not allowed within structs, enums, or unions",
|
||||
);
|
||||
self.session.emit_err(ForbiddenAssocConstraint { span: constraint.span });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -268,31 +251,26 @@ impl<'a> AstValidator<'a> {
|
|||
fn check_lifetime(&self, ident: Ident) {
|
||||
let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty];
|
||||
if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
|
||||
self.err_handler().span_err(ident.span, "lifetimes cannot use keyword names");
|
||||
self.session.emit_err(KeywordLifetime { span: ident.span });
|
||||
}
|
||||
}
|
||||
|
||||
fn check_label(&self, ident: Ident) {
|
||||
if ident.without_first_quote().is_reserved() {
|
||||
self.err_handler()
|
||||
.span_err(ident.span, &format!("invalid label name `{}`", ident.name));
|
||||
self.session.emit_err(InvalidLabel { span: ident.span, name: ident.name });
|
||||
}
|
||||
}
|
||||
|
||||
fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) {
|
||||
fn invalid_visibility(&self, vis: &Visibility, note: Option<InvalidVisibilityNote>) {
|
||||
if let VisibilityKind::Inherited = vis.kind {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut err =
|
||||
struct_span_err!(self.session, vis.span, E0449, "unnecessary visibility qualifier");
|
||||
if vis.kind.is_pub() {
|
||||
err.span_label(vis.span, "`pub` not permitted here because it's implied");
|
||||
}
|
||||
if let Some(note) = note {
|
||||
err.note(note);
|
||||
}
|
||||
err.emit();
|
||||
self.session.emit_err(InvalidVisibility {
|
||||
span: vis.span,
|
||||
implied: if vis.kind.is_pub() { Some(vis.span) } else { None },
|
||||
note,
|
||||
});
|
||||
}
|
||||
|
||||
fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
|
||||
|
@ -309,29 +287,13 @@ impl<'a> AstValidator<'a> {
|
|||
|
||||
fn check_trait_fn_not_async(&self, fn_span: Span, asyncness: Async) {
|
||||
if let Async::Yes { span, .. } = asyncness {
|
||||
struct_span_err!(
|
||||
self.session,
|
||||
fn_span,
|
||||
E0706,
|
||||
"functions in traits cannot be declared `async`"
|
||||
)
|
||||
.span_label(span, "`async` because of this")
|
||||
.note("`async` trait functions are not currently supported")
|
||||
.note("consider using the `async-trait` crate: https://crates.io/crates/async-trait")
|
||||
.emit();
|
||||
self.session.emit_err(TraitFnAsync { fn_span, span });
|
||||
}
|
||||
}
|
||||
|
||||
fn check_trait_fn_not_const(&self, constness: Const) {
|
||||
if let Const::Yes(span) = constness {
|
||||
struct_span_err!(
|
||||
self.session,
|
||||
span,
|
||||
E0379,
|
||||
"functions in traits cannot be declared const"
|
||||
)
|
||||
.span_label(span, "functions in traits cannot be const")
|
||||
.emit();
|
||||
self.session.emit_err(TraitFnConst { span });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -344,8 +306,7 @@ impl<'a> AstValidator<'a> {
|
|||
GenericParamKind::Lifetime { .. } => {
|
||||
if !param.bounds.is_empty() {
|
||||
let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
|
||||
self.err_handler()
|
||||
.span_err(spans, "lifetime bounds cannot be used in this context");
|
||||
self.session.emit_err(ForbiddenLifetimeBound { spans });
|
||||
}
|
||||
None
|
||||
}
|
||||
|
@ -353,10 +314,7 @@ impl<'a> AstValidator<'a> {
|
|||
})
|
||||
.collect();
|
||||
if !non_lt_param_spans.is_empty() {
|
||||
self.err_handler().span_err(
|
||||
non_lt_param_spans,
|
||||
"only lifetime parameters can be used in this context",
|
||||
);
|
||||
self.session.emit_err(ForbiddenNonLifetimeParam { spans: non_lt_param_spans });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -373,10 +331,7 @@ impl<'a> AstValidator<'a> {
|
|||
let max_num_args: usize = u16::MAX.into();
|
||||
if fn_decl.inputs.len() > max_num_args {
|
||||
let Param { span, .. } = fn_decl.inputs[0];
|
||||
self.err_handler().span_fatal(
|
||||
span,
|
||||
&format!("function can not have more than {} arguments", max_num_args),
|
||||
);
|
||||
self.session.emit_fatal(FnParamTooMany { span, max_num_args });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -384,19 +339,13 @@ impl<'a> AstValidator<'a> {
|
|||
match &*fn_decl.inputs {
|
||||
[Param { ty, span, .. }] => {
|
||||
if let TyKind::CVarArgs = ty.kind {
|
||||
self.err_handler().span_err(
|
||||
*span,
|
||||
"C-variadic function must be declared with at least one named argument",
|
||||
);
|
||||
self.session.emit_err(FnParamCVarArgsOnly { span: *span });
|
||||
}
|
||||
}
|
||||
[ps @ .., _] => {
|
||||
for Param { ty, span, .. } in ps {
|
||||
if let TyKind::CVarArgs = ty.kind {
|
||||
self.err_handler().span_err(
|
||||
*span,
|
||||
"`...` must be the last argument of a C-variadic function",
|
||||
);
|
||||
self.session.emit_err(FnParamCVarArgsNotLast { span: *span });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -423,19 +372,9 @@ impl<'a> AstValidator<'a> {
|
|||
})
|
||||
.for_each(|attr| {
|
||||
if attr.is_doc_comment() {
|
||||
self.err_handler()
|
||||
.struct_span_err(
|
||||
attr.span,
|
||||
"documentation comments cannot be applied to function parameters",
|
||||
)
|
||||
.span_label(attr.span, "doc comments are not allowed here")
|
||||
.emit();
|
||||
self.session.emit_err(FnParamDocComment { span: attr.span });
|
||||
} else {
|
||||
self.err_handler().span_err(
|
||||
attr.span,
|
||||
"allow, cfg, cfg_attr, deny, expect, \
|
||||
forbid, and warn are the only allowed built-in attributes in function parameters",
|
||||
);
|
||||
self.session.emit_err(FnParamForbiddenAttr { span: attr.span });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -443,14 +382,7 @@ impl<'a> AstValidator<'a> {
|
|||
fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
|
||||
if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
|
||||
if param.is_self() {
|
||||
self.err_handler()
|
||||
.struct_span_err(
|
||||
param.span,
|
||||
"`self` parameter is only allowed in associated functions",
|
||||
)
|
||||
.span_label(param.span, "not semantically valid as function parameter")
|
||||
.note("associated functions are those in `impl` or `trait` definitions")
|
||||
.emit();
|
||||
self.session.emit_err(FnParamForbiddenSelf { span: param.span });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -458,47 +390,20 @@ impl<'a> AstValidator<'a> {
|
|||
fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
|
||||
if let Defaultness::Default(def_span) = defaultness {
|
||||
let span = self.session.source_map().guess_head_span(span);
|
||||
self.err_handler()
|
||||
.struct_span_err(span, "`default` is only allowed on items in trait impls")
|
||||
.span_label(def_span, "`default` because of this")
|
||||
.emit();
|
||||
self.session.emit_err(ForbiddenDefault { span, def_span });
|
||||
}
|
||||
}
|
||||
|
||||
fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) {
|
||||
self.error_item_without_body_with_help(sp, ctx, msg, sugg, |_| ());
|
||||
}
|
||||
|
||||
fn error_item_without_body_with_help(
|
||||
&self,
|
||||
sp: Span,
|
||||
ctx: &str,
|
||||
msg: &str,
|
||||
sugg: &str,
|
||||
help: impl FnOnce(&mut Diagnostic),
|
||||
) {
|
||||
/// If `sp` ends with a semicolon, returns it as a `Span`
|
||||
/// Otherwise, returns `sp.shrink_to_hi()`
|
||||
fn ending_semi_or_hi(&self, sp: Span) -> Span {
|
||||
let source_map = self.session.source_map();
|
||||
let end = source_map.end_point(sp);
|
||||
let replace_span = if source_map.span_to_snippet(end).map(|s| s == ";").unwrap_or(false) {
|
||||
|
||||
if source_map.span_to_snippet(end).map(|s| s == ";").unwrap_or(false) {
|
||||
end
|
||||
} else {
|
||||
sp.shrink_to_hi()
|
||||
};
|
||||
let mut err = self.err_handler().struct_span_err(sp, msg);
|
||||
err.span_suggestion(
|
||||
replace_span,
|
||||
&format!("provide a definition for the {}", ctx),
|
||||
sugg,
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
help(&mut err);
|
||||
err.emit();
|
||||
}
|
||||
|
||||
fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) {
|
||||
if body.is_none() {
|
||||
let msg = format!("associated {} in `impl` without body", ctx);
|
||||
self.error_item_without_body(sp, ctx, &msg, sugg);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1168,7 +1073,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
|
||||
self.invalid_visibility(
|
||||
&item.vis,
|
||||
Some("place qualifiers on individual impl items instead"),
|
||||
Some(InvalidVisibilityNote::IndividualImplItems),
|
||||
);
|
||||
if let Unsafe::Yes(span) = unsafety {
|
||||
error(span, "unsafe").code(error_code!(E0197)).emit();
|
||||
|
@ -1191,37 +1096,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
self.check_defaultness(item.span, defaultness);
|
||||
|
||||
if body.is_none() {
|
||||
let msg = "free function without a body";
|
||||
let ext = sig.header.ext;
|
||||
|
||||
let f = |e: &mut Diagnostic| {
|
||||
if let Extern::Implicit(start_span) | Extern::Explicit(_, start_span) = &ext
|
||||
{
|
||||
let start_suggestion = if let Extern::Explicit(abi, _) = ext {
|
||||
format!("extern \"{}\" {{", abi.symbol_unescaped)
|
||||
} else {
|
||||
"extern {".to_owned()
|
||||
};
|
||||
|
||||
let end_suggestion = " }".to_owned();
|
||||
let end_span = item.span.shrink_to_hi();
|
||||
|
||||
e
|
||||
.multipart_suggestion(
|
||||
"if you meant to declare an externally defined function, use an `extern` block",
|
||||
vec![(*start_span, start_suggestion), (end_span, end_suggestion)],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
self.error_item_without_body_with_help(
|
||||
item.span,
|
||||
"function",
|
||||
msg,
|
||||
" { <body> }",
|
||||
f,
|
||||
);
|
||||
self.session.emit_err(FnWithoutBody {
|
||||
span: item.span,
|
||||
replace_span: self.ending_semi_or_hi(item.span),
|
||||
extern_block_suggestion: match sig.header.ext {
|
||||
Extern::None => None,
|
||||
Extern::Implicit(start_span) => Some(ExternBlockSuggestion {
|
||||
start_span,
|
||||
end_span: item.span.shrink_to_hi(),
|
||||
abi: None,
|
||||
}),
|
||||
Extern::Explicit(abi, start_span) => Some(ExternBlockSuggestion {
|
||||
start_span,
|
||||
end_span: item.span.shrink_to_hi(),
|
||||
abi: Some(abi.symbol_unescaped),
|
||||
}),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
self.visit_vis(&item.vis);
|
||||
|
@ -1236,7 +1127,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
let old_item = mem::replace(&mut self.extern_mod, Some(item));
|
||||
self.invalid_visibility(
|
||||
&item.vis,
|
||||
Some("place qualifiers on individual foreign items instead"),
|
||||
Some(InvalidVisibilityNote::IndividualForeignItems),
|
||||
);
|
||||
if let Unsafe::Yes(span) = unsafety {
|
||||
self.err_handler().span_err(span, "extern block cannot be declared unsafe");
|
||||
|
@ -1327,12 +1218,16 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
}
|
||||
ItemKind::Const(def, .., None) => {
|
||||
self.check_defaultness(item.span, def);
|
||||
let msg = "free constant item without body";
|
||||
self.error_item_without_body(item.span, "constant", msg, " = <expr>;");
|
||||
self.session.emit_err(ConstWithoutBody {
|
||||
span: item.span,
|
||||
replace_span: self.ending_semi_or_hi(item.span),
|
||||
});
|
||||
}
|
||||
ItemKind::Static(.., None) => {
|
||||
let msg = "free static item without body";
|
||||
self.error_item_without_body(item.span, "static", msg, " = <expr>;");
|
||||
self.session.emit_err(StaticWithoutBody {
|
||||
span: item.span,
|
||||
replace_span: self.ending_semi_or_hi(item.span),
|
||||
});
|
||||
}
|
||||
ItemKind::TyAlias(box TyAlias {
|
||||
defaultness,
|
||||
|
@ -1343,8 +1238,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
}) => {
|
||||
self.check_defaultness(item.span, defaultness);
|
||||
if ty.is_none() {
|
||||
let msg = "free type alias without body";
|
||||
self.error_item_without_body(item.span, "type", msg, " = <type>;");
|
||||
self.session.emit_err(TyAliasWithoutBody {
|
||||
span: item.span,
|
||||
replace_span: self.ending_semi_or_hi(item.span),
|
||||
});
|
||||
}
|
||||
self.check_type_no_bounds(bounds, "this context");
|
||||
if where_clauses.1.0 {
|
||||
|
@ -1648,10 +1545,20 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
if ctxt == AssocCtxt::Impl {
|
||||
match &item.kind {
|
||||
AssocItemKind::Const(_, _, body) => {
|
||||
self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
|
||||
if body.is_none() {
|
||||
self.session.emit_err(AssocConstWithoutBody {
|
||||
span: item.span,
|
||||
replace_span: self.ending_semi_or_hi(item.span),
|
||||
});
|
||||
}
|
||||
}
|
||||
AssocItemKind::Fn(box Fn { body, .. }) => {
|
||||
self.check_impl_item_provided(item.span, body, "function", " { <body> }");
|
||||
if body.is_none() {
|
||||
self.session.emit_err(AssocFnWithoutBody {
|
||||
span: item.span,
|
||||
replace_span: self.ending_semi_or_hi(item.span),
|
||||
});
|
||||
}
|
||||
}
|
||||
AssocItemKind::TyAlias(box TyAlias {
|
||||
generics,
|
||||
|
@ -1661,7 +1568,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
ty,
|
||||
..
|
||||
}) => {
|
||||
self.check_impl_item_provided(item.span, ty, "type", " = <type>;");
|
||||
if ty.is_none() {
|
||||
self.session.emit_err(AssocTypeWithoutBody {
|
||||
span: item.span,
|
||||
replace_span: self.ending_semi_or_hi(item.span),
|
||||
});
|
||||
}
|
||||
self.check_type_no_bounds(bounds, "`impl`s");
|
||||
if ty.is_some() {
|
||||
self.check_gat_where(
|
||||
|
@ -1876,7 +1788,7 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) ->
|
|||
|
||||
/// Used to forbid `let` expressions in certain syntactic locations.
|
||||
#[derive(Clone, Copy)]
|
||||
enum ForbiddenLetReason {
|
||||
pub(crate) enum ForbiddenLetReason {
|
||||
/// `let` is not valid and the source environment is not important
|
||||
GenericForbidden,
|
||||
/// A let chain with the `||` operator
|
||||
|
|
248
compiler/rustc_ast_passes/src/errors.rs
Normal file
248
compiler/rustc_ast_passes/src/errors.rs
Normal file
|
@ -0,0 +1,248 @@
|
|||
//! Errors emitted by ast_passes.
|
||||
|
||||
use rustc_errors::{fluent, AddSubdiagnostic, Applicability, Diagnostic};
|
||||
use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
use crate::ast_validation::ForbiddenLetReason;
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::forbidden_let)]
|
||||
#[note]
|
||||
pub struct ForbiddenLet {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub(crate) reason: ForbiddenLetReason,
|
||||
}
|
||||
|
||||
impl AddSubdiagnostic for ForbiddenLetReason {
|
||||
fn add_to_diagnostic(self, diag: &mut Diagnostic) {
|
||||
match self {
|
||||
Self::GenericForbidden => {}
|
||||
Self::NotSupportedOr(span) => {
|
||||
diag.span_note(span, fluent::ast_passes::not_supported_or);
|
||||
}
|
||||
Self::NotSupportedParentheses(span) => {
|
||||
diag.span_note(span, fluent::ast_passes::not_supported_parentheses);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::forbidden_assoc_constraint)]
|
||||
pub struct ForbiddenAssocConstraint {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::keyword_lifetime)]
|
||||
pub struct KeywordLifetime {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::invalid_label)]
|
||||
pub struct InvalidLabel {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::invalid_visibility, code = "E0449")]
|
||||
pub struct InvalidVisibility {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[label(ast_passes::implied)]
|
||||
pub implied: Option<Span>,
|
||||
#[subdiagnostic]
|
||||
pub note: Option<InvalidVisibilityNote>,
|
||||
}
|
||||
|
||||
#[derive(SessionSubdiagnostic)]
|
||||
pub enum InvalidVisibilityNote {
|
||||
#[note(ast_passes::individual_impl_items)]
|
||||
IndividualImplItems,
|
||||
#[note(ast_passes::individual_foreign_items)]
|
||||
IndividualForeignItems,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::trait_fn_async, code = "E0706")]
|
||||
#[note]
|
||||
#[note(ast_passes::note2)]
|
||||
pub struct TraitFnAsync {
|
||||
#[primary_span]
|
||||
pub fn_span: Span,
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::trait_fn_const, code = "E0379")]
|
||||
pub struct TraitFnConst {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::forbidden_lifetime_bound)]
|
||||
pub struct ForbiddenLifetimeBound {
|
||||
#[primary_span]
|
||||
pub spans: Vec<Span>,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::forbidden_non_lifetime_param)]
|
||||
pub struct ForbiddenNonLifetimeParam {
|
||||
#[primary_span]
|
||||
pub spans: Vec<Span>,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::fn_param_too_many)]
|
||||
pub struct FnParamTooMany {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub max_num_args: usize,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::fn_param_c_var_args_only)]
|
||||
pub struct FnParamCVarArgsOnly {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::fn_param_c_var_args_not_last)]
|
||||
pub struct FnParamCVarArgsNotLast {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::fn_param_doc_comment)]
|
||||
pub struct FnParamDocComment {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::fn_param_forbidden_attr)]
|
||||
pub struct FnParamForbiddenAttr {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::fn_param_forbidden_self)]
|
||||
#[note]
|
||||
pub struct FnParamForbiddenSelf {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::forbidden_default)]
|
||||
pub struct ForbiddenDefault {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[label]
|
||||
pub def_span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::assoc_const_without_body)]
|
||||
pub struct AssocConstWithoutBody {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[suggestion(code = " = <expr>;", applicability = "has-placeholders")]
|
||||
pub replace_span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::assoc_fn_without_body)]
|
||||
pub struct AssocFnWithoutBody {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[suggestion(code = " {{ <body> }}", applicability = "has-placeholders")]
|
||||
pub replace_span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::assoc_type_without_body)]
|
||||
pub struct AssocTypeWithoutBody {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[suggestion(code = " = <type>;", applicability = "has-placeholders")]
|
||||
pub replace_span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::const_without_body)]
|
||||
pub struct ConstWithoutBody {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[suggestion(code = " = <expr>;", applicability = "has-placeholders")]
|
||||
pub replace_span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::static_without_body)]
|
||||
pub struct StaticWithoutBody {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[suggestion(code = " = <expr>;", applicability = "has-placeholders")]
|
||||
pub replace_span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::ty_alias_without_body)]
|
||||
pub struct TyAliasWithoutBody {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[suggestion(code = " = <type>;", applicability = "has-placeholders")]
|
||||
pub replace_span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[diag(ast_passes::fn_without_body)]
|
||||
pub struct FnWithoutBody {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[suggestion(code = " {{ <body> }}", applicability = "has-placeholders")]
|
||||
pub replace_span: Span,
|
||||
#[subdiagnostic]
|
||||
pub extern_block_suggestion: Option<ExternBlockSuggestion>,
|
||||
}
|
||||
|
||||
pub struct ExternBlockSuggestion {
|
||||
pub start_span: Span,
|
||||
pub end_span: Span,
|
||||
pub abi: Option<Symbol>,
|
||||
}
|
||||
|
||||
impl AddSubdiagnostic for ExternBlockSuggestion {
|
||||
fn add_to_diagnostic(self, diag: &mut Diagnostic) {
|
||||
let start_suggestion = if let Some(abi) = self.abi {
|
||||
format!("extern \"{}\" {{", abi)
|
||||
} else {
|
||||
"extern {".to_owned()
|
||||
};
|
||||
let end_suggestion = " }".to_owned();
|
||||
|
||||
diag.multipart_suggestion(
|
||||
fluent::ast_passes::extern_block_suggestion,
|
||||
vec![(self.start_span, start_suggestion), (self.end_span, end_suggestion)],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@
|
|||
#![recursion_limit = "256"]
|
||||
|
||||
pub mod ast_validation;
|
||||
mod errors;
|
||||
pub mod feature_gate;
|
||||
pub mod node_count;
|
||||
pub mod show_span;
|
||||
|
|
|
@ -1176,7 +1176,7 @@ fn create_lints_for_named_arguments_used_positionally(cx: &mut Context<'_, '_>)
|
|||
|
||||
cx.ecx.buffered_early_lint.push(BufferedEarlyLint {
|
||||
span: MultiSpan::from_span(named_arg.positional_named_arg_span),
|
||||
msg: msg.clone(),
|
||||
msg: msg.into(),
|
||||
node_id: ast::CRATE_NODE_ID,
|
||||
lint_id: LintId::of(&NAMED_ARGUMENTS_USED_POSITIONALLY),
|
||||
diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally {
|
||||
|
|
93
compiler/rustc_error_messages/locales/en-US/ast_passes.ftl
Normal file
93
compiler/rustc_error_messages/locales/en-US/ast_passes.ftl
Normal file
|
@ -0,0 +1,93 @@
|
|||
ast_passes_forbidden_let =
|
||||
`let` expressions are not supported here
|
||||
.note = only supported directly in conditions of `if` and `while` expressions
|
||||
.not_supported_or = `||` operators are not supported in let chain expressions
|
||||
.not_supported_parentheses = `let`s wrapped in parentheses are not supported in a context with let chains
|
||||
|
||||
ast_passes_deprecated_where_clause_location =
|
||||
where clause not allowed here
|
||||
|
||||
ast_passes_forbidden_assoc_constraint =
|
||||
associated type bounds are not allowed within structs, enums, or unions
|
||||
|
||||
ast_passes_keyword_lifetime =
|
||||
lifetimes cannot use keyword names
|
||||
|
||||
ast_passes_invalid_label =
|
||||
invalid label name `{$name}`
|
||||
|
||||
ast_passes_invalid_visibility =
|
||||
unnecessary visibility qualifier
|
||||
.implied = `pub` not permitted here because it's implied
|
||||
.individual_impl_items = place qualifiers on individual impl items instead
|
||||
.individual_foreign_items = place qualifiers on individual foreign items instead
|
||||
|
||||
ast_passes_trait_fn_async =
|
||||
functions in traits cannot be declared `async`
|
||||
.label = `async` because of this
|
||||
.note = `async` trait functions are not currently supported
|
||||
.note2 = consider using the `async-trait` crate: https://crates.io/crates/async-trait
|
||||
|
||||
ast_passes_trait_fn_const =
|
||||
functions in traits cannot be declared const
|
||||
.label = functions in traits cannot be const
|
||||
|
||||
ast_passes_forbidden_lifetime_bound =
|
||||
lifetime bounds cannot be used in this context
|
||||
|
||||
ast_passes_forbidden_non_lifetime_param =
|
||||
only lifetime parameters can be used in this context
|
||||
|
||||
ast_passes_fn_param_too_many =
|
||||
function can not have more than {$max_num_args} arguments
|
||||
|
||||
ast_passes_fn_param_c_var_args_only =
|
||||
C-variadic function must be declared with at least one named argument
|
||||
|
||||
ast_passes_fn_param_c_var_args_not_last =
|
||||
`...` must be the last argument of a C-variadic function
|
||||
|
||||
ast_passes_fn_param_doc_comment =
|
||||
documentation comments cannot be applied to function parameters
|
||||
.label = doc comments are not allowed here
|
||||
|
||||
ast_passes_fn_param_forbidden_attr =
|
||||
allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
|
||||
|
||||
ast_passes_fn_param_forbidden_self =
|
||||
`self` parameter is only allowed in associated functions
|
||||
.label = not semantically valid as function parameter
|
||||
.note = associated functions are those in `impl` or `trait` definitions
|
||||
|
||||
ast_passes_forbidden_default =
|
||||
`default` is only allowed on items in trait impls
|
||||
.label = `default` because of this
|
||||
|
||||
ast_passes_assoc_const_without_body =
|
||||
associated constant in `impl` without body
|
||||
.suggestion = provide a definition for the constant
|
||||
|
||||
ast_passes_assoc_fn_without_body =
|
||||
associated function in `impl` without body
|
||||
.suggestion = provide a definition for the function
|
||||
|
||||
ast_passes_assoc_type_without_body =
|
||||
associated type in `impl` without body
|
||||
.suggestion = provide a definition for the type
|
||||
|
||||
ast_passes_const_without_body =
|
||||
free constant item without body
|
||||
.suggestion = provide a definition for the constant
|
||||
|
||||
ast_passes_static_without_body =
|
||||
free static item without body
|
||||
.suggestion = provide a definition for the static
|
||||
|
||||
ast_passes_ty_alias_without_body =
|
||||
free type alias without body
|
||||
.suggestion = provide a definition for the type
|
||||
|
||||
ast_passes_fn_without_body =
|
||||
free function without a body
|
||||
.suggestion = provide a definition for the function
|
||||
.extern_block_suggestion = if you meant to declare an externally defined function, use an `extern` block
|
|
@ -32,6 +32,7 @@ pub use unic_langid::{langid, LanguageIdentifier};
|
|||
|
||||
// Generates `DEFAULT_LOCALE_RESOURCES` static and `fluent_generated` module.
|
||||
fluent_messages! {
|
||||
ast_passes => "../locales/en-US/ast_passes.ftl",
|
||||
borrowck => "../locales/en-US/borrowck.ftl",
|
||||
builtin_macros => "../locales/en-US/builtin_macros.ftl",
|
||||
const_eval => "../locales/en-US/const_eval.ftl",
|
||||
|
|
|
@ -45,7 +45,7 @@ impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> {
|
|||
lint_id.lint,
|
||||
Some(span),
|
||||
|lint| {
|
||||
lint.build(&msg).emit();
|
||||
lint.build(msg).emit();
|
||||
},
|
||||
diagnostic,
|
||||
);
|
||||
|
|
|
@ -9,7 +9,7 @@ pub use self::Level::*;
|
|||
use rustc_ast::node_id::{NodeId, NodeMap};
|
||||
use rustc_ast::{AttrId, Attribute};
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
|
||||
use rustc_error_messages::MultiSpan;
|
||||
use rustc_error_messages::{DiagnosticMessage, MultiSpan};
|
||||
use rustc_hir::HashStableContext;
|
||||
use rustc_hir::HirId;
|
||||
use rustc_span::edition::Edition;
|
||||
|
@ -491,7 +491,7 @@ pub struct BufferedEarlyLint {
|
|||
pub span: MultiSpan,
|
||||
|
||||
/// The lint message.
|
||||
pub msg: String,
|
||||
pub msg: DiagnosticMessage,
|
||||
|
||||
/// The `NodeId` of the AST node that generated the lint.
|
||||
pub node_id: NodeId,
|
||||
|
@ -520,11 +520,11 @@ impl LintBuffer {
|
|||
lint: &'static Lint,
|
||||
node_id: NodeId,
|
||||
span: MultiSpan,
|
||||
msg: &str,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
diagnostic: BuiltinLintDiagnostics,
|
||||
) {
|
||||
let lint_id = LintId::of(lint);
|
||||
let msg = msg.to_string();
|
||||
let msg = msg.into();
|
||||
self.add_early_lint(BufferedEarlyLint { lint_id, node_id, span, msg, diagnostic });
|
||||
}
|
||||
|
||||
|
@ -537,7 +537,7 @@ impl LintBuffer {
|
|||
lint: &'static Lint,
|
||||
id: NodeId,
|
||||
sp: impl Into<MultiSpan>,
|
||||
msg: &str,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
) {
|
||||
self.add_lint(lint, id, sp.into(), msg, BuiltinLintDiagnostics::Normal)
|
||||
}
|
||||
|
@ -547,7 +547,7 @@ impl LintBuffer {
|
|||
lint: &'static Lint,
|
||||
id: NodeId,
|
||||
sp: impl Into<MultiSpan>,
|
||||
msg: &str,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
diagnostic: BuiltinLintDiagnostics,
|
||||
) {
|
||||
self.add_lint(lint, id, sp.into(), msg, diagnostic)
|
||||
|
|
|
@ -235,35 +235,40 @@ pub(crate) trait HasFieldMap {
|
|||
// the referenced fields. Leaves `it` sitting on the closing brace of the format string, so
|
||||
// the next call to `it.next()` retrieves the next character.
|
||||
while let Some(c) = it.next() {
|
||||
if c == '{' && *it.peek().unwrap_or(&'\0') != '{' {
|
||||
let mut eat_argument = || -> Option<String> {
|
||||
let mut result = String::new();
|
||||
// Format specifiers look like:
|
||||
//
|
||||
// format := '{' [ argument ] [ ':' format_spec ] '}' .
|
||||
//
|
||||
// Therefore, we only need to eat until ':' or '}' to find the argument.
|
||||
while let Some(c) = it.next() {
|
||||
result.push(c);
|
||||
let next = *it.peek().unwrap_or(&'\0');
|
||||
if next == '}' {
|
||||
break;
|
||||
} else if next == ':' {
|
||||
// Eat the ':' character.
|
||||
assert_eq!(it.next().unwrap(), ':');
|
||||
break;
|
||||
}
|
||||
if c != '{' {
|
||||
continue;
|
||||
}
|
||||
if *it.peek().unwrap_or(&'\0') == '{' {
|
||||
assert_eq!(it.next().unwrap(), '{');
|
||||
continue;
|
||||
}
|
||||
let mut eat_argument = || -> Option<String> {
|
||||
let mut result = String::new();
|
||||
// Format specifiers look like:
|
||||
//
|
||||
// format := '{' [ argument ] [ ':' format_spec ] '}' .
|
||||
//
|
||||
// Therefore, we only need to eat until ':' or '}' to find the argument.
|
||||
while let Some(c) = it.next() {
|
||||
result.push(c);
|
||||
let next = *it.peek().unwrap_or(&'\0');
|
||||
if next == '}' {
|
||||
break;
|
||||
} else if next == ':' {
|
||||
// Eat the ':' character.
|
||||
assert_eq!(it.next().unwrap(), ':');
|
||||
break;
|
||||
}
|
||||
// Eat until (and including) the matching '}'
|
||||
while it.next()? != '}' {
|
||||
continue;
|
||||
}
|
||||
Some(result)
|
||||
};
|
||||
|
||||
if let Some(referenced_field) = eat_argument() {
|
||||
referenced_fields.insert(referenced_field);
|
||||
}
|
||||
// Eat until (and including) the matching '}'
|
||||
while it.next()? != '}' {
|
||||
continue;
|
||||
}
|
||||
Some(result)
|
||||
};
|
||||
|
||||
if let Some(referenced_field) = eat_argument() {
|
||||
referenced_fields.insert(referenced_field);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -640,7 +640,13 @@ impl<'a> Parser<'a> {
|
|||
let mut bounds = Vec::new();
|
||||
let mut negative_bounds = Vec::new();
|
||||
|
||||
while self.can_begin_bound() || self.token.is_keyword(kw::Dyn) {
|
||||
while self.can_begin_bound()
|
||||
// Continue even if we find a keyword.
|
||||
// This is necessary for error recover on, for example, `impl fn()`.
|
||||
//
|
||||
// The only keyword that can go after generic bounds is `where`, so stop if it's it.
|
||||
|| (self.token.is_reserved_ident() && !self.token.is_keyword(kw::Where))
|
||||
{
|
||||
if self.token.is_keyword(kw::Dyn) {
|
||||
// Account for `&dyn Trait + dyn Other`.
|
||||
self.struct_span_err(self.token.span, "invalid `dyn` keyword")
|
||||
|
@ -803,6 +809,20 @@ impl<'a> Parser<'a> {
|
|||
self.expect_keyword(kw::Const)?;
|
||||
let span = tilde.to(self.prev_token.span);
|
||||
self.sess.gated_spans.gate(sym::const_trait_impl, span);
|
||||
Some(span)
|
||||
} else if self.eat_keyword(kw::Const) {
|
||||
let span = self.prev_token.span;
|
||||
self.sess.gated_spans.gate(sym::const_trait_impl, span);
|
||||
|
||||
self.struct_span_err(span, "const bounds must start with `~`")
|
||||
.span_suggestion(
|
||||
span.shrink_to_lo(),
|
||||
"add `~`",
|
||||
"~",
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
|
||||
Some(span)
|
||||
} else {
|
||||
None
|
||||
|
|
|
@ -360,6 +360,17 @@ impl ParseSess {
|
|||
self.create_warning(warning).emit()
|
||||
}
|
||||
|
||||
pub fn create_fatal<'a>(
|
||||
&'a self,
|
||||
fatal: impl SessionDiagnostic<'a, !>,
|
||||
) -> DiagnosticBuilder<'a, !> {
|
||||
fatal.into_diagnostic(self)
|
||||
}
|
||||
|
||||
pub fn emit_fatal<'a>(&'a self, fatal: impl SessionDiagnostic<'a, !>) -> ! {
|
||||
self.create_fatal(fatal).emit()
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
pub fn struct_err(
|
||||
&self,
|
||||
|
@ -373,6 +384,11 @@ impl ParseSess {
|
|||
self.span_diagnostic.struct_warn(msg)
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> {
|
||||
self.span_diagnostic.struct_fatal(msg)
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
pub fn struct_diagnostic<G: EmissionGuarantee>(
|
||||
&self,
|
||||
|
|
|
@ -482,6 +482,15 @@ impl Session {
|
|||
pub fn emit_warning<'a>(&'a self, warning: impl SessionDiagnostic<'a, ()>) {
|
||||
self.parse_sess.emit_warning(warning)
|
||||
}
|
||||
pub fn create_fatal<'a>(
|
||||
&'a self,
|
||||
fatal: impl SessionDiagnostic<'a, !>,
|
||||
) -> DiagnosticBuilder<'a, !> {
|
||||
self.parse_sess.create_fatal(fatal)
|
||||
}
|
||||
pub fn emit_fatal<'a>(&'a self, fatal: impl SessionDiagnostic<'a, !>) -> ! {
|
||||
self.parse_sess.emit_fatal(fatal)
|
||||
}
|
||||
#[inline]
|
||||
pub fn err_count(&self) -> usize {
|
||||
self.diagnostic().err_count()
|
||||
|
|
|
@ -554,6 +554,18 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
|
|||
.flatten()
|
||||
.unwrap_or_else(|| ty::Term::Ty(ty.super_fold_with(self)))
|
||||
};
|
||||
// For cases like #95134 we would like to catch overflows early
|
||||
// otherwise they slip away away and cause ICE.
|
||||
let recursion_limit = self.tcx().recursion_limit();
|
||||
if !recursion_limit.value_within_limit(self.depth) {
|
||||
let obligation = Obligation::with_depth(
|
||||
self.cause.clone(),
|
||||
recursion_limit.0,
|
||||
self.param_env,
|
||||
ty,
|
||||
);
|
||||
self.selcx.infcx().report_overflow_error(&obligation, true);
|
||||
}
|
||||
debug!(
|
||||
?self.depth,
|
||||
?ty,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//! A pointer type for heap allocation.
|
||||
//! The `Box<T>` type for heap allocation.
|
||||
//!
|
||||
//! [`Box<T>`], casually referred to as a 'box', provides the simplest form of
|
||||
//! heap allocation in Rust. Boxes provide ownership for this allocation, and
|
||||
|
|
|
@ -1,82 +1,12 @@
|
|||
//! A dynamically-sized view into a contiguous sequence, `[T]`.
|
||||
//! Utilities for the slice primitive type.
|
||||
//!
|
||||
//! *[See also the slice primitive type](slice).*
|
||||
//!
|
||||
//! Slices are a view into a block of memory represented as a pointer and a
|
||||
//! length.
|
||||
//! Most of the structs in this module are iterator types which can only be created
|
||||
//! using a certain function. For example, `slice.iter()` yields an [`Iter`].
|
||||
//!
|
||||
//! ```
|
||||
//! // slicing a Vec
|
||||
//! let vec = vec![1, 2, 3];
|
||||
//! let int_slice = &vec[..];
|
||||
//! // coercing an array to a slice
|
||||
//! let str_slice: &[&str] = &["one", "two", "three"];
|
||||
//! ```
|
||||
//!
|
||||
//! Slices are either mutable or shared. The shared slice type is `&[T]`,
|
||||
//! while the mutable slice type is `&mut [T]`, where `T` represents the element
|
||||
//! type. For example, you can mutate the block of memory that a mutable slice
|
||||
//! points to:
|
||||
//!
|
||||
//! ```
|
||||
//! let x = &mut [1, 2, 3];
|
||||
//! x[1] = 7;
|
||||
//! assert_eq!(x, &[1, 7, 3]);
|
||||
//! ```
|
||||
//!
|
||||
//! Here are some of the things this module contains:
|
||||
//!
|
||||
//! ## Structs
|
||||
//!
|
||||
//! There are several structs that are useful for slices, such as [`Iter`], which
|
||||
//! represents iteration over a slice.
|
||||
//!
|
||||
//! ## Trait Implementations
|
||||
//!
|
||||
//! There are several implementations of common traits for slices. Some examples
|
||||
//! include:
|
||||
//!
|
||||
//! * [`Clone`]
|
||||
//! * [`Eq`], [`Ord`] - for slices whose element type are [`Eq`] or [`Ord`].
|
||||
//! * [`Hash`] - for slices whose element type is [`Hash`].
|
||||
//!
|
||||
//! ## Iteration
|
||||
//!
|
||||
//! The slices implement `IntoIterator`. The iterator yields references to the
|
||||
//! slice elements.
|
||||
//!
|
||||
//! ```
|
||||
//! let numbers = &[0, 1, 2];
|
||||
//! for n in numbers {
|
||||
//! println!("{n} is a number!");
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! The mutable slice yields mutable references to the elements:
|
||||
//!
|
||||
//! ```
|
||||
//! let mut scores = [7, 8, 9];
|
||||
//! for score in &mut scores[..] {
|
||||
//! *score += 1;
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! This iterator yields mutable references to the slice's elements, so while
|
||||
//! the element type of the slice is `i32`, the element type of the iterator is
|
||||
//! `&mut i32`.
|
||||
//!
|
||||
//! * [`.iter`] and [`.iter_mut`] are the explicit methods to return the default
|
||||
//! iterators.
|
||||
//! * Further methods that return iterators are [`.split`], [`.splitn`],
|
||||
//! [`.chunks`], [`.windows`] and more.
|
||||
//!
|
||||
//! [`Hash`]: core::hash::Hash
|
||||
//! [`.iter`]: slice::iter
|
||||
//! [`.iter_mut`]: slice::iter_mut
|
||||
//! [`.split`]: slice::split
|
||||
//! [`.splitn`]: slice::splitn
|
||||
//! [`.chunks`]: slice::chunks
|
||||
//! [`.windows`]: slice::windows
|
||||
//! A few functions are provided to create a slice from a value reference
|
||||
//! or from a raw pointer.
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
// Many of the usings in this module are only used in the test configuration.
|
||||
// It's cleaner to just turn off the unused_imports warning than to fix them.
|
||||
|
|
|
@ -1,26 +1,6 @@
|
|||
//! Unicode string slices.
|
||||
//! Utilities for the `str` primitive type.
|
||||
//!
|
||||
//! *[See also the `str` primitive type](str).*
|
||||
//!
|
||||
//! The `&str` type is one of the two main string types, the other being `String`.
|
||||
//! Unlike its `String` counterpart, its contents are borrowed.
|
||||
//!
|
||||
//! # Basic Usage
|
||||
//!
|
||||
//! A basic string declaration of `&str` type:
|
||||
//!
|
||||
//! ```
|
||||
//! let hello_world = "Hello, World!";
|
||||
//! ```
|
||||
//!
|
||||
//! Here we have declared a string literal, also known as a string slice.
|
||||
//! String literals have a static lifetime, which means the string `hello_world`
|
||||
//! is guaranteed to be valid for the duration of the entire program.
|
||||
//! We can explicitly specify `hello_world`'s lifetime as well:
|
||||
//!
|
||||
//! ```
|
||||
//! let hello_world: &'static str = "Hello, world!";
|
||||
//! ```
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
// Many of the usings in this module are only used in the test configuration.
|
||||
|
|
|
@ -293,6 +293,22 @@ fn test_retain() {
|
|||
assert_eq!(vec, [2, 4]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_retain_predicate_order() {
|
||||
for to_keep in [true, false] {
|
||||
let mut number_of_executions = 0;
|
||||
let mut vec = vec![1, 2, 3, 4];
|
||||
let mut next_expected = 1;
|
||||
vec.retain(|&x| {
|
||||
assert_eq!(next_expected, x);
|
||||
next_expected += 1;
|
||||
number_of_executions += 1;
|
||||
to_keep
|
||||
});
|
||||
assert_eq!(number_of_executions, 4);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_retain_pred_panic_with_hole() {
|
||||
let v = (0..5).map(Rc::new).collect::<Vec<_>>();
|
||||
|
@ -354,6 +370,35 @@ fn test_retain_drop_panic() {
|
|||
assert!(v.iter().all(|r| Rc::strong_count(r) == 1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_retain_maybeuninits() {
|
||||
// This test aimed to be run under miri.
|
||||
use core::mem::MaybeUninit;
|
||||
let mut vec: Vec<_> = [1i32, 2, 3, 4].map(|v| MaybeUninit::new(vec![v])).into();
|
||||
vec.retain(|x| {
|
||||
// SAFETY: Retain must visit every element of Vec in original order and exactly once.
|
||||
// Our values is initialized at creation of Vec.
|
||||
let v = unsafe { x.assume_init_ref()[0] };
|
||||
if v & 1 == 0 {
|
||||
return true;
|
||||
}
|
||||
// SAFETY: Value is initialized.
|
||||
// Value wouldn't be dropped by `Vec::retain`
|
||||
// because `MaybeUninit` doesn't drop content.
|
||||
drop(unsafe { x.assume_init_read() });
|
||||
false
|
||||
});
|
||||
let vec: Vec<i32> = vec
|
||||
.into_iter()
|
||||
.map(|x| unsafe {
|
||||
// SAFETY: All values dropped in retain predicate must be removed by `Vec::retain`.
|
||||
// Remaining values are initialized.
|
||||
x.assume_init()[0]
|
||||
})
|
||||
.collect();
|
||||
assert_eq!(vec, [2, 4]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dedup() {
|
||||
fn case(a: Vec<i32>, b: Vec<i32>) {
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
//! This module contains the `Any` trait, which enables dynamic typing
|
||||
//! of any `'static` type through runtime reflection. It also contains the
|
||||
//! `Provider` trait and accompanying API, which enable trait objects to provide
|
||||
//! data based on typed requests, an alternate form of runtime reflection.
|
||||
//! Utilities for dynamic typing or type reflection.
|
||||
//!
|
||||
//! # `Any` and `TypeId`
|
||||
//!
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//! Helper functions and types for fixed-length arrays.
|
||||
//! Utilities for the array primitive type.
|
||||
//!
|
||||
//! *[See also the array primitive type](array).*
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//! A module for working with borrowed data.
|
||||
//! Utilities for working with borrowed data.
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
//! A character type.
|
||||
//! Utilities for the `char` primitive type.
|
||||
//!
|
||||
//! *[See also the `char` primitive type](primitive@char).*
|
||||
//!
|
||||
//! The `char` type represents a single character. More specifically, since
|
||||
//! 'character' isn't a well-defined concept in Unicode, `char` is a '[Unicode
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! Functionality for ordering and comparison.
|
||||
//! Utilities for comparing and ordering values.
|
||||
//!
|
||||
//! This module contains various tools for ordering and comparing values. In
|
||||
//! This module contains various tools for comparing and ordering values. In
|
||||
//! summary:
|
||||
//!
|
||||
//! * [`Eq`] and [`PartialEq`] are traits that allow you to define total and
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//! The `Default` trait for types which may have meaningful default values.
|
||||
//! The `Default` trait for types with a default value.
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//! Constants specific to the `f32` single-precision floating point type.
|
||||
//! Constants for the `f32` single-precision floating point type.
|
||||
//!
|
||||
//! *[See also the `f32` primitive type][f32].*
|
||||
//!
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//! Constants specific to the `f64` double-precision floating point type.
|
||||
//! Constants for the `f64` double-precision floating point type.
|
||||
//!
|
||||
//! *[See also the `f64` primitive type][f64].*
|
||||
//!
|
||||
|
|
|
@ -801,11 +801,53 @@ mod prim_array {}
|
|||
/// assert_eq!(2 * pointer_size, std::mem::size_of::<Box<[u8]>>());
|
||||
/// assert_eq!(2 * pointer_size, std::mem::size_of::<Rc<[u8]>>());
|
||||
/// ```
|
||||
///
|
||||
/// ## Trait Implementations
|
||||
///
|
||||
/// Some traits are implemented for slices if the element type implements
|
||||
/// that trait. This includes [`Eq`], [`Hash`] and [`Ord`].
|
||||
///
|
||||
/// ## Iteration
|
||||
///
|
||||
/// The slices implement `IntoIterator`. The iterator yields references to the
|
||||
/// slice elements.
|
||||
///
|
||||
/// ```
|
||||
/// let numbers: &[i32] = &[0, 1, 2];
|
||||
/// for n in numbers {
|
||||
/// println!("{n} is a number!");
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The mutable slice yields mutable references to the elements:
|
||||
///
|
||||
/// ```
|
||||
/// let mut scores: &mut [i32] = &mut [7, 8, 9];
|
||||
/// for score in scores {
|
||||
/// *score += 1;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This iterator yields mutable references to the slice's elements, so while
|
||||
/// the element type of the slice is `i32`, the element type of the iterator is
|
||||
/// `&mut i32`.
|
||||
///
|
||||
/// * [`.iter`] and [`.iter_mut`] are the explicit methods to return the default
|
||||
/// iterators.
|
||||
/// * Further methods that return iterators are [`.split`], [`.splitn`],
|
||||
/// [`.chunks`], [`.windows`] and more.
|
||||
///
|
||||
/// [`Hash`]: core::hash::Hash
|
||||
/// [`.iter`]: slice::iter
|
||||
/// [`.iter_mut`]: slice::iter_mut
|
||||
/// [`.split`]: slice::split
|
||||
/// [`.splitn`]: slice::splitn
|
||||
/// [`.chunks`]: slice::chunks
|
||||
/// [`.windows`]: slice::windows
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
mod prim_slice {}
|
||||
|
||||
#[doc(primitive = "str")]
|
||||
//
|
||||
/// String slices.
|
||||
///
|
||||
/// *[See also the `std::str` module](crate::str).*
|
||||
|
@ -816,19 +858,22 @@ mod prim_slice {}
|
|||
///
|
||||
/// String slices are always valid UTF-8.
|
||||
///
|
||||
/// # Examples
|
||||
/// # Basic Usage
|
||||
///
|
||||
/// String literals are string slices:
|
||||
///
|
||||
/// ```
|
||||
/// let hello = "Hello, world!";
|
||||
///
|
||||
/// // with an explicit type annotation
|
||||
/// let hello: &'static str = "Hello, world!";
|
||||
/// let hello_world = "Hello, World!";
|
||||
/// ```
|
||||
///
|
||||
/// They are `'static` because they're stored directly in the final binary, and
|
||||
/// so will be valid for the `'static` duration.
|
||||
/// Here we have declared a string slice initialized with a string literal.
|
||||
/// String literals have a static lifetime, which means the string `hello_world`
|
||||
/// is guaranteed to be valid for the duration of the entire program.
|
||||
/// We can explicitly specify `hello_world`'s lifetime as well:
|
||||
///
|
||||
/// ```
|
||||
/// let hello_world: &'static str = "Hello, world!";
|
||||
/// ```
|
||||
///
|
||||
/// # Representation
|
||||
///
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//! Interfaces for working with Errors.
|
||||
//! The `Error` trait provides common functionality for errors.
|
||||
//!
|
||||
//! # Error Handling In Rust
|
||||
//!
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//! Constants specific to the `f32` single-precision floating point type.
|
||||
//! Constants for the `f32` single-precision floating point type.
|
||||
//!
|
||||
//! *[See also the `f32` primitive type](primitive@f32).*
|
||||
//!
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//! Constants specific to the `f64` double-precision floating point type.
|
||||
//! Constants for the `f64` double-precision floating point type.
|
||||
//!
|
||||
//! *[See also the `f64` primitive type](primitive@f64).*
|
||||
//!
|
||||
|
|
|
@ -801,11 +801,53 @@ mod prim_array {}
|
|||
/// assert_eq!(2 * pointer_size, std::mem::size_of::<Box<[u8]>>());
|
||||
/// assert_eq!(2 * pointer_size, std::mem::size_of::<Rc<[u8]>>());
|
||||
/// ```
|
||||
///
|
||||
/// ## Trait Implementations
|
||||
///
|
||||
/// Some traits are implemented for slices if the element type implements
|
||||
/// that trait. This includes [`Eq`], [`Hash`] and [`Ord`].
|
||||
///
|
||||
/// ## Iteration
|
||||
///
|
||||
/// The slices implement `IntoIterator`. The iterator yields references to the
|
||||
/// slice elements.
|
||||
///
|
||||
/// ```
|
||||
/// let numbers: &[i32] = &[0, 1, 2];
|
||||
/// for n in numbers {
|
||||
/// println!("{n} is a number!");
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The mutable slice yields mutable references to the elements:
|
||||
///
|
||||
/// ```
|
||||
/// let mut scores: &mut [i32] = &mut [7, 8, 9];
|
||||
/// for score in scores {
|
||||
/// *score += 1;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This iterator yields mutable references to the slice's elements, so while
|
||||
/// the element type of the slice is `i32`, the element type of the iterator is
|
||||
/// `&mut i32`.
|
||||
///
|
||||
/// * [`.iter`] and [`.iter_mut`] are the explicit methods to return the default
|
||||
/// iterators.
|
||||
/// * Further methods that return iterators are [`.split`], [`.splitn`],
|
||||
/// [`.chunks`], [`.windows`] and more.
|
||||
///
|
||||
/// [`Hash`]: core::hash::Hash
|
||||
/// [`.iter`]: slice::iter
|
||||
/// [`.iter_mut`]: slice::iter_mut
|
||||
/// [`.split`]: slice::split
|
||||
/// [`.splitn`]: slice::splitn
|
||||
/// [`.chunks`]: slice::chunks
|
||||
/// [`.windows`]: slice::windows
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
mod prim_slice {}
|
||||
|
||||
#[doc(primitive = "str")]
|
||||
//
|
||||
/// String slices.
|
||||
///
|
||||
/// *[See also the `std::str` module](crate::str).*
|
||||
|
@ -816,19 +858,22 @@ mod prim_slice {}
|
|||
///
|
||||
/// String slices are always valid UTF-8.
|
||||
///
|
||||
/// # Examples
|
||||
/// # Basic Usage
|
||||
///
|
||||
/// String literals are string slices:
|
||||
///
|
||||
/// ```
|
||||
/// let hello = "Hello, world!";
|
||||
///
|
||||
/// // with an explicit type annotation
|
||||
/// let hello: &'static str = "Hello, world!";
|
||||
/// let hello_world = "Hello, World!";
|
||||
/// ```
|
||||
///
|
||||
/// They are `'static` because they're stored directly in the final binary, and
|
||||
/// so will be valid for the `'static` duration.
|
||||
/// Here we have declared a string slice initialized with a string literal.
|
||||
/// String literals have a static lifetime, which means the string `hello_world`
|
||||
/// is guaranteed to be valid for the duration of the entire program.
|
||||
/// We can explicitly specify `hello_world`'s lifetime as well:
|
||||
///
|
||||
/// ```
|
||||
/// let hello_world: &'static str = "Hello, world!";
|
||||
/// ```
|
||||
///
|
||||
/// # Representation
|
||||
///
|
||||
|
|
|
@ -1,15 +1,10 @@
|
|||
error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<T as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: Sized`
|
||||
error[E0275]: overflow evaluating the requirement `<T as Next>::Next`
|
||||
--> $DIR/issue-23122-2.rs:10:17
|
||||
|
|
||||
LL | type Next = <GetNext<T::Next> as Next>::Next;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_23122_2`)
|
||||
note: required for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<T as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>` to implement `Next`
|
||||
--> $DIR/issue-23122-2.rs:9:15
|
||||
|
|
||||
LL | impl<T: Next> Next for GetNext<T> {
|
||||
| ^^^^ ^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
47
src/test/ui/parser/kw-in-trait-bounds.rs
Normal file
47
src/test/ui/parser/kw-in-trait-bounds.rs
Normal file
|
@ -0,0 +1,47 @@
|
|||
// edition:2018
|
||||
|
||||
fn _f<F: fn(), G>(_: impl fn(), _: &dyn fn())
|
||||
//~^ ERROR expected identifier, found keyword `fn`
|
||||
//~| ERROR expected identifier, found keyword `fn`
|
||||
//~| ERROR expected identifier, found keyword `fn`
|
||||
//~| ERROR cannot find trait `r#fn` in this scope
|
||||
//~| ERROR cannot find trait `r#fn` in this scope
|
||||
//~| ERROR cannot find trait `r#fn` in this scope
|
||||
//~| HELP a trait with a similar name exists
|
||||
//~| HELP a trait with a similar name exists
|
||||
//~| HELP a trait with a similar name exists
|
||||
//~| HELP escape `fn` to use it as an identifier
|
||||
//~| HELP escape `fn` to use it as an identifier
|
||||
//~| HELP escape `fn` to use it as an identifier
|
||||
where
|
||||
G: fn(),
|
||||
//~^ ERROR expected identifier, found keyword `fn`
|
||||
//~| ERROR cannot find trait `r#fn` in this scope
|
||||
//~| HELP a trait with a similar name exists
|
||||
//~| HELP escape `fn` to use it as an identifier
|
||||
{}
|
||||
|
||||
fn _g<A: struct, B>(_: impl struct, _: &dyn struct)
|
||||
//~^ ERROR expected identifier, found keyword `struct`
|
||||
//~| ERROR expected identifier, found keyword `struct`
|
||||
//~| ERROR expected identifier, found keyword `struct`
|
||||
//~| ERROR cannot find trait `r#struct` in this scope
|
||||
//~| ERROR cannot find trait `r#struct` in this scope
|
||||
//~| ERROR cannot find trait `r#struct` in this scope
|
||||
//~| HELP a trait with a similar name exists
|
||||
//~| HELP a trait with a similar name exists
|
||||
//~| HELP a trait with a similar name exists
|
||||
//~| HELP escape `struct` to use it as an identifier
|
||||
//~| HELP escape `struct` to use it as an identifier
|
||||
//~| HELP escape `struct` to use it as an identifier
|
||||
where
|
||||
B: struct,
|
||||
//~^ ERROR expected identifier, found keyword `struct`
|
||||
//~| ERROR cannot find trait `r#struct` in this scope
|
||||
//~| HELP a trait with a similar name exists
|
||||
//~| HELP escape `struct` to use it as an identifier
|
||||
{}
|
||||
|
||||
trait Struct {}
|
||||
|
||||
fn main() {}
|
171
src/test/ui/parser/kw-in-trait-bounds.stderr
Normal file
171
src/test/ui/parser/kw-in-trait-bounds.stderr
Normal file
|
@ -0,0 +1,171 @@
|
|||
error: expected identifier, found keyword `fn`
|
||||
--> $DIR/kw-in-trait-bounds.rs:3:10
|
||||
|
|
||||
LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn fn())
|
||||
| ^^ expected identifier, found keyword
|
||||
|
|
||||
help: escape `fn` to use it as an identifier
|
||||
|
|
||||
LL | fn _f<F: r#fn(), G>(_: impl fn(), _: &dyn fn())
|
||||
| ++
|
||||
|
||||
error: expected identifier, found keyword `fn`
|
||||
--> $DIR/kw-in-trait-bounds.rs:3:27
|
||||
|
|
||||
LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn fn())
|
||||
| ^^ expected identifier, found keyword
|
||||
|
|
||||
help: escape `fn` to use it as an identifier
|
||||
|
|
||||
LL | fn _f<F: fn(), G>(_: impl r#fn(), _: &dyn fn())
|
||||
| ++
|
||||
|
||||
error: expected identifier, found keyword `fn`
|
||||
--> $DIR/kw-in-trait-bounds.rs:3:41
|
||||
|
|
||||
LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn fn())
|
||||
| ^^ expected identifier, found keyword
|
||||
|
|
||||
help: escape `fn` to use it as an identifier
|
||||
|
|
||||
LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn r#fn())
|
||||
| ++
|
||||
|
||||
error: expected identifier, found keyword `fn`
|
||||
--> $DIR/kw-in-trait-bounds.rs:17:4
|
||||
|
|
||||
LL | G: fn(),
|
||||
| ^^ expected identifier, found keyword
|
||||
|
|
||||
help: escape `fn` to use it as an identifier
|
||||
|
|
||||
LL | G: r#fn(),
|
||||
| ++
|
||||
|
||||
error: expected identifier, found keyword `struct`
|
||||
--> $DIR/kw-in-trait-bounds.rs:24:10
|
||||
|
|
||||
LL | fn _g<A: struct, B>(_: impl struct, _: &dyn struct)
|
||||
| ^^^^^^ expected identifier, found keyword
|
||||
|
|
||||
help: escape `struct` to use it as an identifier
|
||||
|
|
||||
LL | fn _g<A: r#struct, B>(_: impl struct, _: &dyn struct)
|
||||
| ++
|
||||
|
||||
error: expected identifier, found keyword `struct`
|
||||
--> $DIR/kw-in-trait-bounds.rs:24:29
|
||||
|
|
||||
LL | fn _g<A: struct, B>(_: impl struct, _: &dyn struct)
|
||||
| ^^^^^^ expected identifier, found keyword
|
||||
|
|
||||
help: escape `struct` to use it as an identifier
|
||||
|
|
||||
LL | fn _g<A: struct, B>(_: impl r#struct, _: &dyn struct)
|
||||
| ++
|
||||
|
||||
error: expected identifier, found keyword `struct`
|
||||
--> $DIR/kw-in-trait-bounds.rs:24:45
|
||||
|
|
||||
LL | fn _g<A: struct, B>(_: impl struct, _: &dyn struct)
|
||||
| ^^^^^^ expected identifier, found keyword
|
||||
|
|
||||
help: escape `struct` to use it as an identifier
|
||||
|
|
||||
LL | fn _g<A: struct, B>(_: impl struct, _: &dyn r#struct)
|
||||
| ++
|
||||
|
||||
error: expected identifier, found keyword `struct`
|
||||
--> $DIR/kw-in-trait-bounds.rs:38:8
|
||||
|
|
||||
LL | B: struct,
|
||||
| ^^^^^^ expected identifier, found keyword
|
||||
|
|
||||
help: escape `struct` to use it as an identifier
|
||||
|
|
||||
LL | B: r#struct,
|
||||
| ++
|
||||
|
||||
error[E0405]: cannot find trait `r#fn` in this scope
|
||||
--> $DIR/kw-in-trait-bounds.rs:3:10
|
||||
|
|
||||
LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn fn())
|
||||
| ^^ help: a trait with a similar name exists (notice the capitalization): `Fn`
|
||||
|
|
||||
::: $SRC_DIR/core/src/ops/function.rs:LL:COL
|
||||
|
|
||||
LL | pub trait Fn<Args>: FnMut<Args> {
|
||||
| ------------------------------- similarly named trait `Fn` defined here
|
||||
|
||||
error[E0405]: cannot find trait `r#fn` in this scope
|
||||
--> $DIR/kw-in-trait-bounds.rs:17:4
|
||||
|
|
||||
LL | G: fn(),
|
||||
| ^^ help: a trait with a similar name exists (notice the capitalization): `Fn`
|
||||
|
|
||||
::: $SRC_DIR/core/src/ops/function.rs:LL:COL
|
||||
|
|
||||
LL | pub trait Fn<Args>: FnMut<Args> {
|
||||
| ------------------------------- similarly named trait `Fn` defined here
|
||||
|
||||
error[E0405]: cannot find trait `r#fn` in this scope
|
||||
--> $DIR/kw-in-trait-bounds.rs:3:27
|
||||
|
|
||||
LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn fn())
|
||||
| ^^ help: a trait with a similar name exists (notice the capitalization): `Fn`
|
||||
|
|
||||
::: $SRC_DIR/core/src/ops/function.rs:LL:COL
|
||||
|
|
||||
LL | pub trait Fn<Args>: FnMut<Args> {
|
||||
| ------------------------------- similarly named trait `Fn` defined here
|
||||
|
||||
error[E0405]: cannot find trait `r#fn` in this scope
|
||||
--> $DIR/kw-in-trait-bounds.rs:3:41
|
||||
|
|
||||
LL | fn _f<F: fn(), G>(_: impl fn(), _: &dyn fn())
|
||||
| ^^ help: a trait with a similar name exists (notice the capitalization): `Fn`
|
||||
|
|
||||
::: $SRC_DIR/core/src/ops/function.rs:LL:COL
|
||||
|
|
||||
LL | pub trait Fn<Args>: FnMut<Args> {
|
||||
| ------------------------------- similarly named trait `Fn` defined here
|
||||
|
||||
error[E0405]: cannot find trait `r#struct` in this scope
|
||||
--> $DIR/kw-in-trait-bounds.rs:24:10
|
||||
|
|
||||
LL | fn _g<A: struct, B>(_: impl struct, _: &dyn struct)
|
||||
| ^^^^^^ help: a trait with a similar name exists (notice the capitalization): `Struct`
|
||||
...
|
||||
LL | trait Struct {}
|
||||
| ------------ similarly named trait `Struct` defined here
|
||||
|
||||
error[E0405]: cannot find trait `r#struct` in this scope
|
||||
--> $DIR/kw-in-trait-bounds.rs:38:8
|
||||
|
|
||||
LL | B: struct,
|
||||
| ^^^^^^ help: a trait with a similar name exists (notice the capitalization): `Struct`
|
||||
...
|
||||
LL | trait Struct {}
|
||||
| ------------ similarly named trait `Struct` defined here
|
||||
|
||||
error[E0405]: cannot find trait `r#struct` in this scope
|
||||
--> $DIR/kw-in-trait-bounds.rs:24:29
|
||||
|
|
||||
LL | fn _g<A: struct, B>(_: impl struct, _: &dyn struct)
|
||||
| ^^^^^^ help: a trait with a similar name exists (notice the capitalization): `Struct`
|
||||
...
|
||||
LL | trait Struct {}
|
||||
| ------------ similarly named trait `Struct` defined here
|
||||
|
||||
error[E0405]: cannot find trait `r#struct` in this scope
|
||||
--> $DIR/kw-in-trait-bounds.rs:24:45
|
||||
|
|
||||
LL | fn _g<A: struct, B>(_: impl struct, _: &dyn struct)
|
||||
| ^^^^^^ help: a trait with a similar name exists (notice the capitalization): `Struct`
|
||||
...
|
||||
LL | trait Struct {}
|
||||
| ------------ similarly named trait `Struct` defined here
|
||||
|
||||
error: aborting due to 16 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0405`.
|
|
@ -9,9 +9,11 @@ LL | func(&mut iter.map(|x| x + 1))
|
|||
= note: `#[warn(unconditional_recursion)]` on by default
|
||||
= help: a `loop` may express intention better if this is on purpose
|
||||
|
||||
error[E0275]: overflow evaluating the requirement `Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut std::ops::Range<u8>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>: Iterator`
|
||||
error[E0275]: overflow evaluating the requirement `<std::ops::Range<u8> as Iterator>::Item`
|
||||
|
|
||||
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_83150`)
|
||||
= note: required for `Map<&mut std::ops::Range<u8>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>` to implement `Iterator`
|
||||
= note: 64 redundant requirements hidden
|
||||
= note: required for `&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut std::ops::Range<u8>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>` to implement `Iterator`
|
||||
|
||||
error: aborting due to previous error; 1 warning emitted
|
||||
|
|
28
src/test/ui/recursion/issue-95134.rs
Normal file
28
src/test/ui/recursion/issue-95134.rs
Normal file
|
@ -0,0 +1,28 @@
|
|||
// build-fail
|
||||
// compile-flags: -Copt-level=0
|
||||
//~^^ ERROR overflow evaluating the requirement
|
||||
|
||||
pub fn encode_num<Writer: ExampleWriter>(n: u32, mut writer: Writer) -> Result<(), Writer::Error> {
|
||||
if n > 15 {
|
||||
encode_num(n / 16, &mut writer)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub trait ExampleWriter {
|
||||
type Error;
|
||||
}
|
||||
|
||||
impl<'a, T: ExampleWriter> ExampleWriter for &'a mut T {
|
||||
type Error = T::Error;
|
||||
}
|
||||
|
||||
struct EmptyWriter;
|
||||
|
||||
impl ExampleWriter for EmptyWriter {
|
||||
type Error = ();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
encode_num(69, &mut EmptyWriter).unwrap();
|
||||
}
|
7
src/test/ui/recursion/issue-95134.stderr
Normal file
7
src/test/ui/recursion/issue-95134.stderr
Normal file
|
@ -0,0 +1,7 @@
|
|||
error[E0275]: overflow evaluating the requirement `<EmptyWriter as ExampleWriter>::Error`
|
||||
|
|
||||
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_95134`)
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0275`.
|
|
@ -3,4 +3,4 @@
|
|||
#![feature(const_trait_impl)]
|
||||
|
||||
struct S<T: const Tr>;
|
||||
//~^ ERROR expected one of `!`, `(`, `,`, `=`, `>`, `?`, `for`, `~`, lifetime, or path
|
||||
//~^ ERROR const bounds must start with `~`
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
error: expected one of `!`, `(`, `,`, `=`, `>`, `?`, `for`, `~`, lifetime, or path, found keyword `const`
|
||||
error: const bounds must start with `~`
|
||||
--> $DIR/without-tilde.rs:5:13
|
||||
|
|
||||
LL | struct S<T: const Tr>;
|
||||
| ^^^^^ expected one of 10 possible tokens
|
||||
| -^^^^
|
||||
| |
|
||||
| help: add `~`: `~`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue