Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate parts of rustc_expand to session diagnostics #104460

Merged
merged 1 commit into from
Dec 10, 2022
Merged
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
2 changes: 1 addition & 1 deletion compiler/rustc_builtin_macros/src/concat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub fn expand_concat(
sp: rustc_span::Span,
tts: TokenStream,
) -> Box<dyn base::MacResult + 'static> {
let Some(es) = base::get_exprs_from_tts(cx, sp, tts) else {
let Some(es) = base::get_exprs_from_tts(cx, tts) else {
return DummyResult::any(sp);
};
let mut accumulator = String::new();
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_builtin_macros/src/concat_bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ pub fn expand_concat_bytes(
sp: rustc_span::Span,
tts: TokenStream,
) -> Box<dyn base::MacResult + 'static> {
let Some(es) = base::get_exprs_from_tts(cx, sp, tts) else {
let Some(es) = base::get_exprs_from_tts(cx, tts) else {
return DummyResult::any(sp);
};
let mut accumulator = Vec::new();
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_builtin_macros/src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ pub fn expand_env<'cx>(
sp: Span,
tts: TokenStream,
) -> Box<dyn base::MacResult + 'cx> {
let mut exprs = match get_exprs_from_tts(cx, sp, tts) {
let mut exprs = match get_exprs_from_tts(cx, tts) {
Some(exprs) if exprs.is_empty() => {
cx.span_err(sp, "env! takes 1 or 2 arguments");
return DummyResult::any(sp);
Expand Down
107 changes: 107 additions & 0 deletions compiler/rustc_error_messages/locales/en-US/expand.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,110 @@ expand_var_still_repeating =
variable '{$ident}' is still repeating at this depth

expand_meta_var_dif_seq_matchers = {$msg}

expand_macro_const_stability =
macros cannot have const stability attributes
.label = invalid const stability attribute
.label2 = const stability attribute affects this macro

expand_macro_body_stability =
macros cannot have body stability attributes
.label = invalid body stability attribute
.label2 = body stability attribute affects this macro

expand_resolve_relative_path =
cannot resolve relative path in non-file source `{$path}`

expand_attr_no_arguments =
attribute must have either one or two arguments

expand_not_a_meta_item =
not a meta item

expand_only_one_word =
must only be one word

expand_cannot_be_name_of_macro =
`{$trait_ident}` cannot be a name of {$macro_type} macro

expand_arg_not_attributes =
second argument must be `attributes`

expand_attributes_wrong_form =
attribute must be of form: `attributes(foo, bar)`

expand_attribute_meta_item =
attribute must be a meta item, not a literal

expand_attribute_single_word =
attribute must only be a single word

expand_helper_attribute_name_invalid =
`{$name}` cannot be a name of derive helper attribute

expand_expected_comma_in_list =
expected token: `,`

expand_only_one_argument =
{$name} takes 1 argument

expand_takes_no_arguments =
{$name} takes no arguments

expand_feature_included_in_edition =
the feature `{$feature}` is included in the Rust {$edition} edition

expand_feature_removed =
feature has been removed
.label = feature has been removed
.reason = {$reason}

expand_feature_not_allowed =
the feature `{$name}` is not in the list of allowed features

expand_recursion_limit_reached =
recursion limit reached while expanding `{$descr}`
.help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`)

expand_malformed_feature_attribute =
malformed `feature` attribute input
.expected = expected just one word

expand_remove_expr_not_supported =
removing an expression is not supported in this position

expand_invalid_cfg_no_parens = `cfg` is not followed by parentheses
expand_invalid_cfg_no_predicate = `cfg` predicate is not specified
expand_invalid_cfg_multiple_predicates = multiple `cfg` predicates are specified
expand_invalid_cfg_predicate_literal = `cfg` predicate key cannot be a literal
expand_invalid_cfg_expected_syntax = expected syntax is

expand_wrong_fragment_kind =
non-{$kind} macro in {$kind} position: {$name}

expand_unsupported_key_value =
key-value macro attributes are not supported

expand_incomplete_parse =
macro expansion ignores token `{$token}` and any following
.label = caused by the macro expansion here
.note = the usage of `{$macro_path}!` is likely invalid in {$kind_name} context
.suggestion_add_semi = you might be missing a semicolon here

expand_remove_node_not_supported =
removing {$descr} is not supported in this position

expand_module_circular =
circular modules: {$modules}

expand_module_in_block =
cannot declare a non-inline module inside a block unless it has a path attribute
.note = maybe `use` the module `{$name}` instead of redeclaring it

expand_module_file_not_found =
file not found for module `{$name}`
.help = to create the module `{$name}`, create file "{$default_path}" or "{$secondary_path}"

expand_module_multiple_candidates =
file for module `{$name}` found at both "{$default_path}" and "{$secondary_path}"
.help = delete or rename one of them to remove the ambiguity
6 changes: 6 additions & 0 deletions compiler/rustc_errors/src/diagnostic_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,12 @@ impl IntoDiagnosticArg for ast::Path {
}
}

impl IntoDiagnosticArg for &ast::Path {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
DiagnosticArgValue::Str(Cow::Owned(pprust::path_to_string(self)))
}
}

impl IntoDiagnosticArg for ast::token::Token {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
DiagnosticArgValue::Str(pprust::token_to_string(&self))
Expand Down
90 changes: 39 additions & 51 deletions compiler/rustc_expand/src/base.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
#![deny(rustc::untranslatable_diagnostic)]

use crate::errors::{
ArgumentNotAttributes, AttrNoArguments, AttributeMetaItem, AttributeSingleWord,
AttributesWrongForm, CannotBeNameOfMacro, ExpectedCommaInList, HelperAttributeNameInvalid,
MacroBodyStability, MacroConstStability, NotAMetaItem, OnlyOneArgument, OnlyOneWord,
ResolveRelativePath, TakesNoArguments,
};
use crate::expand::{self, AstFragment, Invocation};
use crate::module::DirOwnership;

Expand Down Expand Up @@ -789,26 +797,16 @@ impl SyntaxExtension {
.unwrap_or_else(|| (None, helper_attrs));
let (stability, const_stability, body_stability) = attr::find_stability(&sess, attrs, span);
if let Some((_, sp)) = const_stability {
sess.parse_sess
.span_diagnostic
.struct_span_err(sp, "macros cannot have const stability attributes")
.span_label(sp, "invalid const stability attribute")
.span_label(
sess.source_map().guess_head_span(span),
"const stability attribute affects this macro",
)
.emit();
sess.emit_err(MacroConstStability {
span: sp,
head_span: sess.source_map().guess_head_span(span),
});
}
if let Some((_, sp)) = body_stability {
sess.parse_sess
.span_diagnostic
.struct_span_err(sp, "macros cannot have body stability attributes")
.span_label(sp, "invalid body stability attribute")
.span_label(
sess.source_map().guess_head_span(span),
"body stability attribute affects this macro",
)
.emit();
sess.emit_err(MacroBodyStability {
span: sp,
head_span: sess.source_map().guess_head_span(span),
});
}

SyntaxExtension {
Expand Down Expand Up @@ -1200,13 +1198,11 @@ pub fn resolve_path(
.expect("attempting to resolve a file path in an external file"),
FileName::DocTest(path, _) => path,
other => {
return Err(parse_sess.span_diagnostic.struct_span_err(
return Err(ResolveRelativePath {
span,
&format!(
"cannot resolve relative path in non-file source `{}`",
parse_sess.source_map().filename_for_diagnostics(&other)
),
));
path: parse_sess.source_map().filename_for_diagnostics(&other).to_string(),
}
.into_diagnostic(&parse_sess.span_diagnostic));
}
};
result.pop();
Expand All @@ -1222,6 +1218,8 @@ pub fn resolve_path(
/// The returned bool indicates whether an applicable suggestion has already been
/// added to the diagnostic to avoid emitting multiple suggestions. `Err(None)`
/// indicates that an ast error was encountered.
// FIXME(Nilstrieb) Make this function setup translatable
#[allow(rustc::untranslatable_diagnostic)]
pub fn expr_to_spanned_string<'a>(
cx: &'a mut ExtCtxt<'_>,
expr: P<ast::Expr>,
Expand Down Expand Up @@ -1280,9 +1278,9 @@ pub fn expr_to_string(
/// compilation should call
/// `cx.parse_sess.span_diagnostic.abort_if_errors()` (this should be
/// done as rarely as possible).
pub fn check_zero_tts(cx: &ExtCtxt<'_>, sp: Span, tts: TokenStream, name: &str) {
pub fn check_zero_tts(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream, name: &str) {
if !tts.is_empty() {
cx.span_err(sp, &format!("{} takes no arguments", name));
cx.emit_err(TakesNoArguments { span, name });
}
}

Expand All @@ -1304,31 +1302,27 @@ pub fn parse_expr(p: &mut parser::Parser<'_>) -> Option<P<ast::Expr>> {
/// expect exactly one string literal, or emit an error and return `None`.
pub fn get_single_str_from_tts(
cx: &mut ExtCtxt<'_>,
sp: Span,
span: Span,
tts: TokenStream,
name: &str,
) -> Option<Symbol> {
let mut p = cx.new_parser_from_tts(tts);
if p.token == token::Eof {
cx.span_err(sp, &format!("{} takes 1 argument", name));
cx.emit_err(OnlyOneArgument { span, name });
return None;
}
let ret = parse_expr(&mut p)?;
let _ = p.eat(&token::Comma);

if p.token != token::Eof {
cx.span_err(sp, &format!("{} takes 1 argument", name));
cx.emit_err(OnlyOneArgument { span, name });
}
expr_to_string(cx, ret, "argument must be a string literal").map(|(s, _)| s)
}

/// Extracts comma-separated expressions from `tts`.
/// On error, emit it, and return `None`.
pub fn get_exprs_from_tts(
cx: &mut ExtCtxt<'_>,
sp: Span,
tts: TokenStream,
) -> Option<Vec<P<ast::Expr>>> {
pub fn get_exprs_from_tts(cx: &mut ExtCtxt<'_>, tts: TokenStream) -> Option<Vec<P<ast::Expr>>> {
let mut p = cx.new_parser_from_tts(tts);
let mut es = Vec::new();
while p.token != token::Eof {
Expand All @@ -1343,7 +1337,7 @@ pub fn get_exprs_from_tts(
continue;
}
if p.token != token::Eof {
cx.span_err(sp, "expected token: `,`");
cx.emit_err(ExpectedCommaInList { span: p.token.span });
return None;
}
}
Expand All @@ -1353,64 +1347,58 @@ pub fn get_exprs_from_tts(
pub fn parse_macro_name_and_helper_attrs(
diag: &rustc_errors::Handler,
attr: &Attribute,
descr: &str,
macro_type: &str,
) -> Option<(Symbol, Vec<Symbol>)> {
// Once we've located the `#[proc_macro_derive]` attribute, verify
// that it's of the form `#[proc_macro_derive(Foo)]` or
// `#[proc_macro_derive(Foo, attributes(A, ..))]`
let list = attr.meta_item_list()?;
if list.len() != 1 && list.len() != 2 {
diag.span_err(attr.span, "attribute must have either one or two arguments");
diag.emit_err(AttrNoArguments { span: attr.span });
return None;
}
let Some(trait_attr) = list[0].meta_item() else {
diag.span_err(list[0].span(), "not a meta item");
diag.emit_err(NotAMetaItem {span: list[0].span()});
return None;
};
let trait_ident = match trait_attr.ident() {
Some(trait_ident) if trait_attr.is_word() => trait_ident,
_ => {
diag.span_err(trait_attr.span, "must only be one word");
diag.emit_err(OnlyOneWord { span: trait_attr.span });
return None;
}
};

if !trait_ident.name.can_be_raw() {
diag.span_err(
trait_attr.span,
&format!("`{}` cannot be a name of {} macro", trait_ident, descr),
);
diag.emit_err(CannotBeNameOfMacro { span: trait_attr.span, trait_ident, macro_type });
}

let attributes_attr = list.get(1);
let proc_attrs: Vec<_> = if let Some(attr) = attributes_attr {
if !attr.has_name(sym::attributes) {
diag.span_err(attr.span(), "second argument must be `attributes`");
diag.emit_err(ArgumentNotAttributes { span: attr.span() });
}
attr.meta_item_list()
.unwrap_or_else(|| {
diag.span_err(attr.span(), "attribute must be of form: `attributes(foo, bar)`");
diag.emit_err(AttributesWrongForm { span: attr.span() });
&[]
})
.iter()
.filter_map(|attr| {
let Some(attr) = attr.meta_item() else {
diag.span_err(attr.span(), "not a meta item");
diag.emit_err(AttributeMetaItem { span: attr.span() });
return None;
};

let ident = match attr.ident() {
Some(ident) if attr.is_word() => ident,
_ => {
diag.span_err(attr.span, "must only be one word");
diag.emit_err(AttributeSingleWord { span: attr.span });
return None;
}
};
if !ident.name.can_be_raw() {
diag.span_err(
attr.span,
&format!("`{}` cannot be a name of derive helper attribute", ident),
);
diag.emit_err(HelperAttributeNameInvalid { span: attr.span, name: ident });
}

Some(ident.name)
Expand Down
Loading