1
Fork 0

resolve: Centralize some error reporting for unexpected macro resolutions

This commit is contained in:
Vadim Petrochenkov 2020-11-19 01:49:20 +03:00
parent 69894ce9ac
commit 68f94e94ed
14 changed files with 278 additions and 253 deletions

View file

@ -12,24 +12,24 @@ use rustc_ast_pretty::pprust;
use rustc_attr::StabilityLevel;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::ptr_key::PtrKey;
use rustc_data_structures::sync::Lrc;
use rustc_errors::struct_span_err;
use rustc_expand::base::{Indeterminate, InvocationRes, ResolverExpand, SyntaxExtension};
use rustc_expand::compile_declarative_macro;
use rustc_expand::expand::{AstFragment, AstFragmentKind, Invocation, InvocationKind};
use rustc_expand::expand::{AstFragment, Invocation, InvocationKind};
use rustc_feature::is_builtin_attr_name;
use rustc_hir::def::{self, DefKind, NonMacroAttrKind};
use rustc_hir::def_id;
use rustc_middle::middle::stability;
use rustc_middle::ty;
use rustc_session::lint::builtin::UNUSED_MACROS;
use rustc_session::parse::feature_err;
use rustc_session::Session;
use rustc_span::edition::Edition;
use rustc_span::hygiene::{self, ExpnData, ExpnId, ExpnKind};
use rustc_span::hygiene::{AstPass, MacroKind};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
use rustc_data_structures::sync::Lrc;
use rustc_span::hygiene::{AstPass, MacroKind};
use std::cell::Cell;
use std::{mem, ptr};
@ -241,15 +241,20 @@ impl<'a> ResolverExpand for Resolver<'a> {
}
};
let (path, kind, derives, after_derive) = match invoc.kind {
let (path, kind, inner_attr, derives, after_derive) = match invoc.kind {
InvocationKind::Attr { ref attr, ref derives, after_derive, .. } => (
&attr.get_normal_item().path,
MacroKind::Attr,
attr.style == ast::AttrStyle::Inner,
self.arenas.alloc_ast_paths(derives),
after_derive,
),
InvocationKind::Bang { ref mac, .. } => (&mac.path, MacroKind::Bang, &[][..], false),
InvocationKind::Derive { ref path, .. } => (path, MacroKind::Derive, &[][..], false),
InvocationKind::Bang { ref mac, .. } => {
(&mac.path, MacroKind::Bang, false, &[][..], false)
}
InvocationKind::Derive { ref path, .. } => {
(path, MacroKind::Derive, false, &[][..], false)
}
InvocationKind::DeriveContainer { ref derives, .. } => {
// Block expansion of the container until we resolve all derives in it.
// This is required for two reasons:
@ -299,8 +304,17 @@ impl<'a> ResolverExpand for Resolver<'a> {
// Derives are not included when `invocations` are collected, so we have to add them here.
let parent_scope = &ParentScope { derives, ..parent_scope };
let require_inert = !invoc.fragment_kind.supports_macro_expansion();
let node_id = self.lint_node_id(eager_expansion_root);
let (ext, res) = self.smart_resolve_macro_path(path, kind, parent_scope, node_id, force)?;
let (ext, res) = self.smart_resolve_macro_path(
path,
kind,
require_inert,
inner_attr,
parent_scope,
node_id,
force,
)?;
let span = invoc.span();
invoc_id.set_expn_data(ext.expn_data(
@ -318,29 +332,6 @@ impl<'a> ResolverExpand for Resolver<'a> {
self.definitions.add_parent_module_of_macro_def(invoc_id, normal_module_def_id);
}
match invoc.fragment_kind {
AstFragmentKind::Arms
| AstFragmentKind::Fields
| AstFragmentKind::FieldPats
| AstFragmentKind::GenericParams
| AstFragmentKind::Params
| AstFragmentKind::StructFields
| AstFragmentKind::Variants => {
if let Res::Def(..) = res {
self.session.span_err(
span,
&format!(
"expected an inert attribute, found {} {}",
res.article(),
res.descr()
),
);
return Ok(InvocationRes::Single(self.dummy_ext(kind)));
}
}
_ => {}
}
Ok(InvocationRes::Single(ext))
}
@ -403,10 +394,14 @@ impl<'a> ResolverExpand for Resolver<'a> {
impl<'a> Resolver<'a> {
/// Resolve macro path with error reporting and recovery.
/// Uses dummy syntax extensions for unresolved macros or macros with unexpected resolutions
/// for better error recovery.
fn smart_resolve_macro_path(
&mut self,
path: &ast::Path,
kind: MacroKind,
require_inert: bool,
inner_attr: bool,
parent_scope: &ParentScope<'a>,
node_id: NodeId,
force: bool,
@ -414,7 +409,6 @@ impl<'a> Resolver<'a> {
let (ext, res) = match self.resolve_macro_path(path, Some(kind), parent_scope, true, force)
{
Ok((Some(ext), res)) => (ext, res),
// Use dummy syntax extensions for unresolved macros for better recovery.
Ok((None, res)) => (self.dummy_ext(kind), res),
Err(Determinacy::Determined) => (self.dummy_ext(kind), Res::Err),
Err(Determinacy::Undetermined) => return Err(Indeterminate),
@ -451,19 +445,43 @@ impl<'a> Resolver<'a> {
self.check_stability_and_deprecation(&ext, path, node_id);
Ok(if ext.macro_kind() != kind {
let expected = kind.descr_expected();
let unexpected_res = if ext.macro_kind() != kind {
Some((kind.article(), kind.descr_expected()))
} else if require_inert && matches!(res, Res::Def(..)) {
Some(("a", "non-macro attribute"))
} else {
None
};
if let Some((article, expected)) = unexpected_res {
let path_str = pprust::path_to_string(path);
let msg = format!("expected {}, found {} `{}`", expected, res.descr(), path_str);
self.session
.struct_span_err(path.span, &msg)
.span_label(path.span, format!("not {} {}", kind.article(), expected))
.span_label(path.span, format!("not {} {}", article, expected))
.emit();
// Use dummy syntax extensions for unexpected macro kinds for better recovery.
(self.dummy_ext(kind), Res::Err)
} else {
(ext, res)
})
return Ok((self.dummy_ext(kind), Res::Err));
}
// We are trying to avoid reporting this error if other related errors were reported.
if inner_attr
&& !self.session.features_untracked().custom_inner_attributes
&& path != &sym::test
&& res != Res::Err
{
feature_err(
&self.session.parse_sess,
sym::custom_inner_attributes,
path.span,
match res {
Res::Def(..) => "inner macro attributes are unstable",
Res::NonMacroAttr(..) => "custom inner attributes are unstable",
_ => unreachable!(),
},
)
.emit();
}
Ok((ext, res))
}
pub fn resolve_macro_path(