Skip to content
Permalink
Browse files

resolve: Divide macro path resolution into speculative and error repo…

…rting parts

Also move macro stability checking closer to other checks performed on obtained resolutions.
Tighten the stability spans as well, it is an error to *refer* to and unstable entity in any way, not only "call" it.
  • Loading branch information...
petrochenkov committed Jul 3, 2019
1 parent 8bc187d commit f92394209455bf14594f279249c2e592809180cd
@@ -755,11 +755,7 @@ impl<'a> Resolver<'a> {
}
}

pub fn get_macro(&mut self, res: Res) -> Lrc<SyntaxExtension> {
self.opt_get_macro(res).expect("expected `DefKind::Macro` or `Res::NonMacroAttr`")
}

crate fn opt_get_macro(&mut self, res: Res) -> Option<Lrc<SyntaxExtension>> {
pub fn get_macro(&mut self, res: Res) -> Option<Lrc<SyntaxExtension>> {
let def_id = match res {
Res::Def(DefKind::Macro(..), def_id) => def_id,
Res::NonMacroAttr(attr_kind) =>
@@ -229,13 +229,10 @@ impl<'a> base::Resolver for Resolver<'a> {
};

let parent_scope = self.invoc_parent_scope(invoc_id, derives_in_scope);
let (res, ext) = self.resolve_macro_to_res(path, kind, &parent_scope, true, force)?;
let (ext, res) = self.smart_resolve_macro_path(path, kind, &parent_scope, true, force)?;

let span = invoc.span();
let descr = fast_print_path(path);
invoc.expansion_data.mark.set_expn_info(ext.expn_info(span, descr));

self.check_stability_and_deprecation(&ext, descr, span);
invoc.expansion_data.mark.set_expn_info(ext.expn_info(span, fast_print_path(path)));

if let Res::Def(_, def_id) = res {
if after_derive {
@@ -275,47 +272,42 @@ impl<'a> Resolver<'a> {
}
}

fn resolve_macro_to_res(
/// Resolve macro path with error reporting and recovery.
fn smart_resolve_macro_path(
&mut self,
path: &ast::Path,
kind: MacroKind,
parent_scope: &ParentScope<'a>,
trace: bool,
force: bool,
) -> Result<(Res, Lrc<SyntaxExtension>), Indeterminate> {
let res = self.resolve_macro_to_res_inner(path, kind, parent_scope, trace, force);
) -> Result<(Lrc<SyntaxExtension>, Res), Indeterminate> {
let (ext, res) = match self.resolve_macro_path(path, kind, parent_scope, trace, 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),
};

// Report errors and enforce feature gates for the resolved macro.
let features = self.session.features_untracked();
if res != Err(Determinacy::Undetermined) {
// Do not report duplicated errors on every undetermined resolution.
for segment in &path.segments {
if let Some(args) = &segment.args {
self.session.span_err(args.span(), "generic arguments in macro path");
}
if kind == MacroKind::Attr && !features.rustc_attrs &&
segment.ident.as_str().starts_with("rustc") {
let msg = "attributes starting with `rustc` are \
reserved for use by the `rustc` compiler";
emit_feature_err(
&self.session.parse_sess,
sym::rustc_attrs,
segment.ident.span,
GateIssue::Language,
msg,
);
}
for segment in &path.segments {
if let Some(args) = &segment.args {
self.session.span_err(args.span(), "generic arguments in macro path");
}
}

let res = match res {
Err(Determinacy::Undetermined) => return Err(Indeterminate),
Ok(Res::Err) | Err(Determinacy::Determined) => {
// Return dummy syntax extensions for unresolved macros for better recovery.
return Ok((Res::Err, self.dummy_ext(kind)));
if kind == MacroKind::Attr && !features.rustc_attrs &&
segment.ident.as_str().starts_with("rustc") {
let msg =
"attributes starting with `rustc` are reserved for use by the `rustc` compiler";
emit_feature_err(
&self.session.parse_sess,
sym::rustc_attrs,
segment.ident.span,
GateIssue::Language,
msg,
);
}
Ok(res) => res,
};
}

match res {
Res::Def(DefKind::Macro(_), def_id) => {
@@ -345,20 +337,22 @@ impl<'a> Resolver<'a> {
}
}
}
Res::Err => {}
_ => panic!("expected `DefKind::Macro` or `Res::NonMacroAttr`"),
};

let ext = self.get_macro(res);
self.check_stability_and_deprecation(&ext, path);

Ok(if ext.macro_kind() != kind {
let expected = if kind == MacroKind::Attr { "attribute" } else { kind.descr() };
let msg = format!("expected {}, found {} `{}`", expected, res.descr(), path);
self.session.struct_span_err(path.span, &msg)
.span_label(path.span, format!("not {} {}", kind.article(), expected))
.emit();
// Return dummy syntax extensions for unexpected macro kinds for better recovery.
(Res::Err, self.dummy_ext(kind))
// Use dummy syntax extensions for unexpected macro kinds for better recovery.
(self.dummy_ext(kind), Res::Err)
} else {
(res, ext)
(ext, res)
})
}

@@ -416,14 +410,14 @@ impl<'a> Resolver<'a> {
err.emit();
}

pub fn resolve_macro_to_res_inner(
pub fn resolve_macro_path(
&mut self,
path: &ast::Path,
kind: MacroKind,
parent_scope: &ParentScope<'a>,
trace: bool,
force: bool,
) -> Result<Res, Determinacy> {
) -> Result<(Option<Lrc<SyntaxExtension>>, Res), Determinacy> {
let path_span = path.span;
let mut path = Segment::from_path(path);

@@ -435,7 +429,7 @@ impl<'a> Resolver<'a> {
path.insert(0, Segment::from_ident(root));
}

if path.len() > 1 {
let res = if path.len() > 1 {
let res = match self.resolve_path(&path, Some(MacroNS), parent_scope,
false, path_span, CrateLint::No) {
PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
@@ -471,7 +465,9 @@ impl<'a> Resolver<'a> {
let res = binding.map(|binding| binding.res());
self.prohibit_imported_non_macro_attrs(binding.ok(), res.ok(), path_span);
res
}
};

res.map(|res| (self.get_macro(res), res))
}

// Resolve an identifier in lexical scope.
@@ -600,16 +596,18 @@ impl<'a> Resolver<'a> {
let mut result = Err(Determinacy::Determined);
for derive in &parent_scope.derives {
let parent_scope = ParentScope { derives: Vec::new(), ..*parent_scope };
match self.resolve_macro_to_res(derive, MacroKind::Derive,
&parent_scope, true, force) {
Ok((_, ext)) => if ext.helper_attrs.contains(&ident.name) {
match self.resolve_macro_path(derive, MacroKind::Derive,
&parent_scope, true, force) {
Ok((Some(ext), _)) => if ext.helper_attrs.contains(&ident.name) {
let binding = (Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
ty::Visibility::Public, derive.span, Mark::root())
.to_name_binding(self.arenas);
result = Ok((binding, Flags::empty()));
break;
}
Err(Indeterminate) => result = Err(Determinacy::Undetermined),
Ok(_) | Err(Determinacy::Determined) => {}
Err(Determinacy::Undetermined) =>
result = Err(Determinacy::Undetermined),
}
}
result
@@ -1004,7 +1002,8 @@ impl<'a> Resolver<'a> {
}
}

fn check_stability_and_deprecation(&self, ext: &SyntaxExtension, descr: Symbol, span: Span) {
fn check_stability_and_deprecation(&self, ext: &SyntaxExtension, path: &ast::Path) {
let span = path.span;
if let Some(stability) = &ext.stability {
if let StabilityLevel::Unstable { reason, issue } = stability.level {
let feature = stability.feature;
@@ -1013,14 +1012,14 @@ impl<'a> Resolver<'a> {
}
}
if let Some(depr) = &stability.rustc_depr {
let (message, lint) = stability::rustc_deprecation_message(depr, &descr.as_str());
let (message, lint) = stability::rustc_deprecation_message(depr, &path.to_string());
stability::early_report_deprecation(
self.session, &message, depr.suggestion, lint, span
);
}
}
if let Some(depr) = &ext.deprecation {
let (message, lint) = stability::deprecation_message(depr, &descr.as_str());
let (message, lint) = stability::deprecation_message(depr, &path.to_string());
stability::early_report_deprecation(self.session, &message, None, lint, span);
}
}
@@ -1101,7 +1100,7 @@ impl<'a> Resolver<'a> {
// Reserve some names that are not quite covered by the general check
// performed on `Resolver::builtin_attrs`.
if ident.name == sym::cfg || ident.name == sym::cfg_attr || ident.name == sym::derive {
let macro_kind = self.opt_get_macro(res).map(|ext| ext.macro_kind());
let macro_kind = self.get_macro(res).map(|ext| ext.macro_kind());
if macro_kind.is_some() && sub_namespace_match(macro_kind, Some(MacroKind::Attr)) {
self.session.span_err(
ident.span, &format!("name `{}` is reserved in attribute namespace", ident)
@@ -429,10 +429,10 @@ fn macro_resolve(cx: &DocContext<'_>, path_str: &str) -> Option<Res> {
let segment = ast::PathSegment::from_ident(Ident::from_str(path_str));
let path = ast::Path { segments: vec![segment], span: DUMMY_SP };
cx.enter_resolver(|resolver| {
if let Ok(res @ Res::Def(DefKind::Macro(_), _)) = resolver.resolve_macro_to_res_inner(
if let Ok((Some(ext), res)) = resolver.resolve_macro_path(
&path, MacroKind::Bang, &resolver.dummy_parent_scope(), false, false
) {
if let SyntaxExtensionKind::LegacyBang { .. } = resolver.get_macro(res).kind {
if let SyntaxExtensionKind::LegacyBang { .. } = ext.kind {
return Some(res.map_id(|_| panic!("unexpected id")));
}
}
@@ -2,7 +2,7 @@ error[E0658]: use of unstable library feature 'asm': inline assembly is not stab
--> $DIR/feature-gate-asm.rs:3:9
|
LL | asm!("");
| ^^^^^^^^^
| ^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/29722
= help: add `#![feature(asm)]` to the crate attributes to enable
@@ -2,7 +2,7 @@ error[E0658]: use of unstable library feature 'asm': inline assembly is not stab
--> $DIR/feature-gate-asm2.rs:5:26
|
LL | println!("{:?}", asm!(""));
| ^^^^^^^^
| ^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/29722
= help: add `#![feature(asm)]` to the crate attributes to enable
@@ -2,7 +2,7 @@ error[E0658]: use of unstable library feature 'concat_idents': `concat_idents` i
--> $DIR/feature-gate-concat_idents.rs:5:13
|
LL | let a = concat_idents!(X, Y_1);
| ^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/29599
= help: add `#![feature(concat_idents)]` to the crate attributes to enable
@@ -11,7 +11,7 @@ error[E0658]: use of unstable library feature 'concat_idents': `concat_idents` i
--> $DIR/feature-gate-concat_idents.rs:6:13
|
LL | let b = concat_idents!(X, Y_2);
| ^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/29599
= help: add `#![feature(concat_idents)]` to the crate attributes to enable
@@ -2,7 +2,7 @@ error[E0658]: use of unstable library feature 'concat_idents': `concat_idents` i
--> $DIR/feature-gate-concat_idents2.rs:4:5
|
LL | concat_idents!(a, b);
| ^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/29599
= help: add `#![feature(concat_idents)]` to the crate attributes to enable
@@ -2,7 +2,7 @@ error[E0658]: use of unstable library feature 'concat_idents': `concat_idents` i
--> $DIR/feature-gate-concat_idents3.rs:7:20
|
LL | assert_eq!(10, concat_idents!(X, Y_1));
| ^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/29599
= help: add `#![feature(concat_idents)]` to the crate attributes to enable
@@ -11,7 +11,7 @@ error[E0658]: use of unstable library feature 'concat_idents': `concat_idents` i
--> $DIR/feature-gate-concat_idents3.rs:8:20
|
LL | assert_eq!(20, concat_idents!(X, Y_2));
| ^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/29599
= help: add `#![feature(concat_idents)]` to the crate attributes to enable
@@ -2,7 +2,7 @@ error[E0658]: use of unstable library feature 'format_args_nl': `format_args_nl`
--> $DIR/feature-gate-format_args_nl.rs:2:5
|
LL | format_args_nl!("");
| ^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^
|
= help: add `#![feature(format_args_nl)]` to the crate attributes to enable

@@ -2,7 +2,7 @@ error[E0658]: use of unstable library feature 'global_asm': `global_asm!` is not
--> $DIR/feature-gate-global_asm.rs:1:1
|
LL | global_asm!("");
| ^^^^^^^^^^^^^^^^
| ^^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/35119
= help: add `#![feature(global_asm)]` to the crate attributes to enable
@@ -2,7 +2,7 @@ error[E0658]: use of unstable library feature 'log_syntax': `log_syntax!` is not
--> $DIR/feature-gate-log_syntax.rs:2:5
|
LL | log_syntax!()
| ^^^^^^^^^^^^^
| ^^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/29598
= help: add `#![feature(log_syntax)]` to the crate attributes to enable
@@ -2,7 +2,7 @@ error[E0658]: use of unstable library feature 'log_syntax': `log_syntax!` is not
--> $DIR/feature-gate-log_syntax2.rs:4:22
|
LL | println!("{:?}", log_syntax!());
| ^^^^^^^^^^^^^
| ^^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/29598
= help: add `#![feature(log_syntax)]` to the crate attributes to enable
@@ -2,7 +2,7 @@ error[E0658]: use of unstable library feature 'trace_macros': `trace_macros` is
--> $DIR/feature-gate-trace_macros.rs:2:5
|
LL | trace_macros!(true);
| ^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/29598
= help: add `#![feature(trace_macros)]` to the crate attributes to enable
@@ -2,13 +2,13 @@ warning: use of deprecated item 'local_deprecated': local deprecation note
--> $DIR/macro-deprecation.rs:11:5
|
LL | local_deprecated!();
| ^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^
|
= note: #[warn(deprecated)] on by default

warning: use of deprecated item 'deprecated_macro': deprecation note
--> $DIR/macro-deprecation.rs:12:5
|
LL | deprecated_macro!();
| ^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^

0 comments on commit f923942

Please sign in to comment.
You can’t perform that action at this time.