Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions compiler/rustc_ast_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ ast_passes_coroutine_and_c_variadic = functions cannot be both `{$coroutine_kind
.const = `{$coroutine_kind}` because of this
.variadic = C-variadic because of this

ast_passes_deprecated_where_clause_location = where clause not allowed here
.note = see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information

ast_passes_equality_in_where = equality constraints are not yet supported in `where` clauses
.label = not supported
.suggestion = if `{$ident}` is an associated type you're trying to set, use the associated type binding syntax
Expand Down Expand Up @@ -237,6 +240,8 @@ ast_passes_missing_unsafe_on_extern_lint = extern blocks should be unsafe
ast_passes_module_nonascii = trying to load file for module `{$name}` with non-ascii identifier name
.help = consider using the `#[path]` attribute to specify filesystem path

ast_passes_move_leading_ty_alias_where_clause = move it to the end of the type declaration

ast_passes_negative_bound_not_supported =
negative bounds are not supported

Expand All @@ -259,6 +264,7 @@ ast_passes_out_of_order_params = {$param_ord} parameters must be declared prior

ast_passes_pattern_in_bodiless = patterns aren't allowed in functions without bodies
.label = pattern not allowed in function without body
.remove_mut_sugg = remove `mut` from the parameter

ast_passes_pattern_in_fn_pointer = patterns aren't allowed in function pointer types

Expand All @@ -270,6 +276,8 @@ ast_passes_precise_capturing_duplicated = duplicate `use<...>` precise capturing

ast_passes_precise_capturing_not_allowed_here = `use<...>` precise capturing syntax not allowed in {$loc}

ast_passes_remove_leading_ty_alias_where_clause = remove this `where`

ast_passes_static_without_body =
free static item without body
.suggestion = provide a definition for the static
Expand Down Expand Up @@ -322,6 +330,10 @@ ast_passes_unsafe_negative_impl = negative impls cannot be unsafe
ast_passes_unsafe_static =
static items cannot be declared with `unsafe` safety qualifier outside of `extern` block

ast_passes_unused_visibilities = visibility qualifiers have no effect on `const _` declarations
.note = `const _` does not declare a name, so there is nothing for the qualifier to apply to
.suggestion = remove the qualifier

ast_passes_visibility_not_permitted =
visibility qualifiers are not permitted here
.enum_variant = enum variants and their fields always share the visibility of the enum they are in
Expand All @@ -336,5 +348,3 @@ ast_passes_where_clause_after_type_alias = where clauses are not allowed after t

ast_passes_where_clause_before_type_alias = where clauses are not allowed before the type for type aliases
.note = see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
.remove_suggestion = remove this `where`
.move_suggestion = move it to the end of the type declaration
58 changes: 22 additions & 36 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ use rustc_data_structures::fx::FxIndexMap;
use rustc_errors::{DiagCtxtHandle, LintBuffer};
use rustc_feature::Features;
use rustc_session::Session;
use rustc_session::lint::BuiltinLintDiag;
use rustc_session::lint::builtin::{
DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, MISSING_UNSAFE_ON_EXTERN,
PATTERNS_IN_FNS_WITHOUT_BODY, UNUSED_VISIBILITIES,
Expand Down Expand Up @@ -166,13 +165,13 @@ impl<'a> AstValidator<'a> {
state.print_where_predicate(p);
}

errors::WhereClauseBeforeTypeAliasSugg::Move {
errors::ModifyLeadingTyAliasWhereClause::Move {
left: span,
snippet: state.s.eof(),
right: ty_alias.after_where_clause.span.shrink_to_hi(),
}
} else {
errors::WhereClauseBeforeTypeAliasSugg::Remove { span }
errors::ModifyLeadingTyAliasWhereClause::Remove { span }
};

Err(errors::WhereClauseBeforeTypeAlias { span, sugg })
Expand Down Expand Up @@ -230,14 +229,12 @@ impl<'a> AstValidator<'a> {
});
}

fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>)) {
for Param { pat, .. } in &decl.inputs {
match pat.kind {
PatKind::Missing | PatKind::Ident(BindingMode::NONE, _, None) | PatKind::Wild => {}
PatKind::Ident(BindingMode::MUT, ident, None) => {
report_err(pat.span, Some(ident), true)
}
_ => report_err(pat.span, None, false),
PatKind::Ident(BindingMode::MUT, ident, None) => report_err(pat.span, Some(ident)),
_ => report_err(pat.span, None),
}
}
}
Expand Down Expand Up @@ -929,7 +926,7 @@ impl<'a> AstValidator<'a> {
TyKind::FnPtr(bfty) => {
self.check_fn_ptr_safety(bfty.decl_span, bfty.safety);
self.check_fn_decl(&bfty.decl, SelfSemantic::No);
Self::check_decl_no_pat(&bfty.decl, |span, _, _| {
Self::check_decl_no_pat(&bfty.decl, |span, _| {
self.dcx().emit_err(errors::PatternFnPointer { span });
});
if let Extern::Implicit(extern_span) = bfty.ext {
Expand Down Expand Up @@ -1360,7 +1357,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
UNUSED_VISIBILITIES,
item.id,
item.vis.span,
BuiltinLintDiag::UnusedVisibility(item.vis.span),
errors::UnusedVisibility { span: item.vis.span },
)
}

Expand Down Expand Up @@ -1646,25 +1643,20 @@ impl<'a> Visitor<'a> for AstValidator<'a> {

// Functions without bodies cannot have patterns.
if let FnKind::Fn(ctxt, _, Fn { body: None, sig, .. }) = fk {
Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
if let Some(ident) = ident {
self.lint_buffer.buffer_lint(
PATTERNS_IN_FNS_WITHOUT_BODY,
id,
span,
BuiltinLintDiag::PatternsInFnsWithoutBody {
span,
ident,
is_foreign: matches!(ctxt, FnCtxt::Foreign),
},
)
}
} else {
match ctxt {
FnCtxt::Foreign => self.dcx().emit_err(errors::PatternInForeign { span }),
_ => self.dcx().emit_err(errors::PatternInBodiless { span }),
};
Self::check_decl_no_pat(&sig.decl, |span, mut_ident| match ctxt {
FnCtxt::Assoc(_) if let Some(mut_ident) = mut_ident => {
self.lint_buffer.buffer_lint(
PATTERNS_IN_FNS_WITHOUT_BODY,
id,
span,
errors::PatternInBodilessLint { removal: span.until(mut_ident.span) },
);
}
FnCtxt::Foreign => {
self.dcx().emit_err(errors::PatternInForeign { span });
}
_ => {
self.dcx().emit_err(errors::PatternInBodiless { span });
}
});
}
Expand Down Expand Up @@ -1728,17 +1720,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
if let AssocItemKind::Type(ty_alias) = &item.kind
&& let Err(err) = self.check_type_alias_where_clause_location(ty_alias)
{
let sugg = match err.sugg {
errors::WhereClauseBeforeTypeAliasSugg::Remove { .. } => None,
errors::WhereClauseBeforeTypeAliasSugg::Move { snippet, right, .. } => {
Some((right, snippet))
}
};
self.lint_buffer.buffer_lint(
DEPRECATED_WHERE_CLAUSE_LOCATION,
item.id,
err.span,
BuiltinLintDiag::DeprecatedWhereclauseLocation(err.span, sugg),
errors::DeprecatedWhereClauseLocation { sugg: err.sugg },
);
}

Expand Down
37 changes: 31 additions & 6 deletions compiler/rustc_ast_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -575,18 +575,30 @@ pub(crate) struct WhereClauseBeforeTypeAlias {
#[primary_span]
pub span: Span,
#[subdiagnostic]
pub sugg: WhereClauseBeforeTypeAliasSugg,
pub sugg: ModifyLeadingTyAliasWhereClause,
}

#[derive(LintDiagnostic)]
#[diag(ast_passes_deprecated_where_clause_location)]
#[note]
pub(crate) struct DeprecatedWhereClauseLocation {
#[subdiagnostic]
pub sugg: ModifyLeadingTyAliasWhereClause,
}

#[derive(Subdiagnostic)]
pub(crate) enum WhereClauseBeforeTypeAliasSugg {
#[suggestion(ast_passes_remove_suggestion, applicability = "machine-applicable", code = "")]
pub(crate) enum ModifyLeadingTyAliasWhereClause {
#[suggestion(
ast_passes_remove_leading_ty_alias_where_clause,
applicability = "machine-applicable",
code = ""
)]
Remove {
#[primary_span]
span: Span,
},
#[multipart_suggestion(
ast_passes_move_suggestion,
ast_passes_move_leading_ty_alias_where_clause,
applicability = "machine-applicable",
style = "verbose"
)]
Expand Down Expand Up @@ -743,7 +755,6 @@ pub(crate) struct CVariadicNotSupported<'a> {

#[derive(Diagnostic)]
#[diag(ast_passes_pattern_in_foreign, code = E0130)]
// FIXME: deduplicate with rustc_lint (`BuiltinLintDiag::PatternsInFnsWithoutBody`)
pub(crate) struct PatternInForeign {
#[primary_span]
#[label]
Expand All @@ -752,13 +763,19 @@ pub(crate) struct PatternInForeign {

#[derive(Diagnostic)]
#[diag(ast_passes_pattern_in_bodiless, code = E0642)]
// FIXME: deduplicate with rustc_lint (`BuiltinLintDiag::PatternsInFnsWithoutBody`)
pub(crate) struct PatternInBodiless {
#[primary_span]
#[label]
pub span: Span,
}

#[derive(LintDiagnostic)]
#[diag(ast_passes_pattern_in_bodiless)]
pub(crate) struct PatternInBodilessLint {
#[suggestion(ast_passes_remove_mut_sugg, code = "", applicability = "machine-applicable")]
pub removal: Span,
}

#[derive(Diagnostic)]
#[diag(ast_passes_equality_in_where)]
#[note]
Expand Down Expand Up @@ -990,3 +1007,11 @@ pub(crate) struct AbiX86Interrupt {
pub spans: Vec<Span>,
pub param_count: usize,
}

#[derive(LintDiagnostic)]
#[diag(ast_passes_unused_visibilities)]
#[note]
pub(crate) struct UnusedVisibility {
#[suggestion(style = "short", code = "", applicability = "machine-applicable")]
pub span: Span,
}
5 changes: 5 additions & 0 deletions compiler/rustc_builtin_macros/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,11 @@ builtin_macros_naked_functions_testing_attribute =
.label = function marked with testing attribute here
.naked_attribute = `#[unsafe(naked)]` is incompatible with testing attributes

builtin_macros_named_argument_used_positionally = named argument `{$named_arg_name}` is not used by name
.label_named_arg = this named argument is referred to by position in formatting string
.label_position_arg = this formatting argument uses named argument `{$named_arg_name}` by position
.suggestion = use the named argument by name to avoid ambiguity

builtin_macros_no_default_variant = `#[derive(Default)]` on enum with no `#[default]`
.label = this enum needs a unit variant marked with `#[default]`
.suggestion = make this unit variant default by placing `#[default]` on it
Expand Down
38 changes: 36 additions & 2 deletions compiler/rustc_builtin_macros/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use rustc_errors::codes::*;
use rustc_errors::{
Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan, SingleLabelManySpans,
Subdiagnostic,
Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, LintDiagnostic,
MultiSpan, SingleLabelManySpans, Subdiagnostic,
};
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_span::{Ident, Span, Symbol};

use crate::fluent_generated as fluent;

#[derive(LintDiagnostic)]
#[diag(builtin_macros_avoid_intel_syntax)]
pub(crate) struct AvoidIntelSyntax;
Expand Down Expand Up @@ -1058,3 +1060,35 @@ pub(crate) struct EiiMacroExpectedMaxOneArgument {
pub span: Span,
pub name: String,
}

pub(crate) struct NamedArgumentUsedPositionally {
pub position_sp_to_replace: Option<Span>,
pub position_sp_for_msg: Option<Span>,
pub named_arg_sp: Span,
pub named_arg_name: Symbol,
pub is_formatting_arg: bool,
}

impl<'a> LintDiagnostic<'a, ()> for NamedArgumentUsedPositionally {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be derived if we did the $ pushing eagerly (might impact perf, unlikely tho).

fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) {
diag.primary_message(fluent::builtin_macros_named_argument_used_positionally);
diag.span_label(self.named_arg_sp, fluent::builtin_macros_label_named_arg);
if let Some(span) = self.position_sp_for_msg {
diag.span_label(span, fluent::builtin_macros_label_position_arg);
}
diag.arg("named_arg_name", self.named_arg_name);

if let Some(positional_arg_to_replace) = self.position_sp_to_replace {
let mut name = self.named_arg_name.to_string();
if self.is_formatting_arg {
name.push('$')
};
diag.span_suggestion_verbose(
positional_arg_to_replace,
fluent::builtin_macros_suggestion,
name,
Applicability::MaybeIncorrect,
);
}
}
}
6 changes: 3 additions & 3 deletions compiler/rustc_builtin_macros/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ use rustc_errors::{
pluralize,
};
use rustc_expand::base::*;
use rustc_lint_defs::LintId;
use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY;
use rustc_lint_defs::{BuiltinLintDiag, LintId};
use rustc_parse::exp;
use rustc_parse_format as parse;
use rustc_span::{BytePos, ErrorGuaranteed, Ident, InnerSpan, Span, Symbol};
Expand Down Expand Up @@ -589,11 +589,11 @@ fn make_format_args(
span: Some(arg_name.span.into()),
node_id: rustc_ast::CRATE_NODE_ID,
lint_id: LintId::of(NAMED_ARGUMENTS_USED_POSITIONALLY),
diagnostic: BuiltinLintDiag::NamedArgumentUsedPositionally {
diagnostic: errors::NamedArgumentUsedPositionally {
position_sp_to_replace,
position_sp_for_msg,
named_arg_sp: arg_name.span,
named_arg_name: arg_name.name.to_string(),
named_arg_name: arg_name.name,
is_formatting_arg: matches!(used_as, Width | Precision),
}
.into(),
Expand Down
Loading
Loading