mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 07:14:28 +00:00
Refactor macro resolution errors + add derive macro suggestions
This commit is contained in:
parent
05a7f25cc4
commit
2d91e7aab8
@ -726,6 +726,8 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
|
||||
});
|
||||
}
|
||||
|
||||
after_expand(&krate)?;
|
||||
|
||||
if sess.opts.debugging_opts.input_stats {
|
||||
println!("Post-expansion node count: {}", count_nodes(&krate));
|
||||
}
|
||||
@ -751,14 +753,14 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
|
||||
|| ast_validation::check_crate(sess, &krate));
|
||||
|
||||
time(time_passes, "name resolution", || -> CompileResult {
|
||||
// Since import resolution will eventually happen in expansion,
|
||||
// don't perform `after_expand` until after import resolution.
|
||||
after_expand(&krate)?;
|
||||
|
||||
resolver.resolve_crate(&krate);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
if resolver.found_unresolved_macro {
|
||||
sess.parse_sess.span_diagnostic.abort_if_errors();
|
||||
}
|
||||
|
||||
// Needs to go *after* expansion to be able to check the results of macro expansion.
|
||||
time(time_passes, "complete gated feature checking", || {
|
||||
sess.track_errors(|| {
|
||||
|
@ -51,6 +51,7 @@ use syntax::ext::hygiene::{Mark, SyntaxContext};
|
||||
use syntax::ast::{self, Name, NodeId, Ident, SpannedIdent, FloatTy, IntTy, UintTy};
|
||||
use syntax::ext::base::SyntaxExtension;
|
||||
use syntax::ext::base::Determinacy::{Determined, Undetermined};
|
||||
use syntax::ext::base::MacroKind;
|
||||
use syntax::symbol::{Symbol, keywords};
|
||||
use syntax::util::lev_distance::find_best_match_for_name;
|
||||
|
||||
@ -785,7 +786,7 @@ pub struct ModuleData<'a> {
|
||||
normal_ancestor_id: DefId,
|
||||
|
||||
resolutions: RefCell<FxHashMap<(Ident, Namespace), &'a RefCell<NameResolution<'a>>>>,
|
||||
legacy_macro_resolutions: RefCell<Vec<(Mark, Ident, Span)>>,
|
||||
legacy_macro_resolutions: RefCell<Vec<(Mark, Ident, Span, MacroKind)>>,
|
||||
macro_resolutions: RefCell<Vec<(Box<[Ident]>, Span)>>,
|
||||
|
||||
// Macro invocations that can expand into items in this module.
|
||||
@ -1117,6 +1118,7 @@ pub struct Resolver<'a> {
|
||||
macro_map: FxHashMap<DefId, Rc<SyntaxExtension>>,
|
||||
macro_exports: Vec<Export>,
|
||||
pub whitelisted_legacy_custom_derives: Vec<Name>,
|
||||
pub found_unresolved_macro: bool,
|
||||
|
||||
// Maps the `Mark` of an expansion to its containing module or block.
|
||||
invocations: FxHashMap<Mark, &'a InvocationData<'a>>,
|
||||
@ -1315,6 +1317,7 @@ impl<'a> Resolver<'a> {
|
||||
warned_proc_macros: FxHashSet(),
|
||||
potentially_unused_imports: Vec::new(),
|
||||
struct_constructors: DefIdMap(),
|
||||
found_unresolved_macro: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@ use syntax::attr;
|
||||
use syntax::errors::DiagnosticBuilder;
|
||||
use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator};
|
||||
use syntax::ext::base::{NormalTT, Resolver as SyntaxResolver, SyntaxExtension};
|
||||
use syntax::ext::base::MacroKind;
|
||||
use syntax::ext::expand::{Expansion, mark_tts};
|
||||
use syntax::ext::hygiene::Mark;
|
||||
use syntax::ext::tt::macro_rules;
|
||||
@ -236,8 +237,8 @@ impl<'a> base::Resolver for Resolver<'a> {
|
||||
None
|
||||
}
|
||||
|
||||
fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, force: bool)
|
||||
-> Result<Rc<SyntaxExtension>, Determinacy> {
|
||||
fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind,
|
||||
force: bool) -> Result<Rc<SyntaxExtension>, Determinacy> {
|
||||
let ast::Path { ref segments, span } = *path;
|
||||
if segments.iter().any(|segment| segment.parameters.is_some()) {
|
||||
let kind =
|
||||
@ -256,6 +257,7 @@ impl<'a> base::Resolver for Resolver<'a> {
|
||||
let msg = "non-ident macro paths are experimental";
|
||||
let feature = "use_extern_macros";
|
||||
emit_feature_err(&self.session.parse_sess, feature, span, GateIssue::Language, msg);
|
||||
self.found_unresolved_macro = true;
|
||||
return Err(Determinacy::Determined);
|
||||
}
|
||||
|
||||
@ -266,7 +268,10 @@ impl<'a> base::Resolver for Resolver<'a> {
|
||||
},
|
||||
PathResult::Module(..) => unreachable!(),
|
||||
PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined),
|
||||
_ => Err(Determinacy::Determined),
|
||||
_ => {
|
||||
self.found_unresolved_macro = true;
|
||||
Err(Determinacy::Determined)
|
||||
},
|
||||
};
|
||||
self.current_module.macro_resolutions.borrow_mut()
|
||||
.push((path.into_boxed_slice(), span));
|
||||
@ -279,40 +284,19 @@ impl<'a> base::Resolver for Resolver<'a> {
|
||||
Some(MacroBinding::Modern(binding)) => Ok(binding.get_macro(self)),
|
||||
None => match self.resolve_lexical_macro_path_segment(path[0], MacroNS, None) {
|
||||
Ok(binding) => Ok(binding.get_macro(self)),
|
||||
Err(Determinacy::Undetermined) if !force => return Err(Determinacy::Undetermined),
|
||||
_ => {
|
||||
let msg = format!("macro undefined: `{}`", name);
|
||||
let mut err = self.session.struct_span_err(span, &msg);
|
||||
self.suggest_macro_name(&name.as_str(), &mut err);
|
||||
err.emit();
|
||||
return Err(Determinacy::Determined);
|
||||
},
|
||||
Err(Determinacy::Undetermined) if !force =>
|
||||
return Err(Determinacy::Undetermined),
|
||||
Err(_) => {
|
||||
self.found_unresolved_macro = true;
|
||||
Err(Determinacy::Determined)
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
if self.use_extern_macros {
|
||||
self.current_module.legacy_macro_resolutions.borrow_mut().push((scope, path[0], span));
|
||||
}
|
||||
result
|
||||
}
|
||||
self.current_module.legacy_macro_resolutions.borrow_mut()
|
||||
.push((scope, path[0], span, kind));
|
||||
|
||||
fn resolve_derive_macro(&mut self, scope: Mark, path: &ast::Path, force: bool)
|
||||
-> Result<Rc<SyntaxExtension>, Determinacy> {
|
||||
let ast::Path { span, .. } = *path;
|
||||
match self.resolve_macro(scope, path, false) {
|
||||
Ok(ext) => match *ext {
|
||||
SyntaxExtension::BuiltinDerive(..) |
|
||||
SyntaxExtension::ProcMacroDerive(..) => Ok(ext),
|
||||
_ => Err(Determinacy::Determined),
|
||||
},
|
||||
Err(Determinacy::Undetermined) if force => {
|
||||
let msg = format!("cannot find derive macro `{}` in this scope", path);
|
||||
let mut err = self.session.struct_span_err(span, &msg);
|
||||
err.emit();
|
||||
Err(Determinacy::Determined)
|
||||
},
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
@ -438,37 +422,74 @@ impl<'a> Resolver<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
for &(mark, ident, span) in module.legacy_macro_resolutions.borrow().iter() {
|
||||
for &(mark, ident, span, kind) in module.legacy_macro_resolutions.borrow().iter() {
|
||||
let legacy_scope = &self.invocations[&mark].legacy_scope;
|
||||
let legacy_resolution = self.resolve_legacy_scope(legacy_scope, ident.name, true);
|
||||
let resolution = self.resolve_lexical_macro_path_segment(ident, MacroNS, Some(span));
|
||||
let (legacy_resolution, resolution) = match (legacy_resolution, resolution) {
|
||||
(Some(legacy_resolution), Ok(resolution)) => (legacy_resolution, resolution),
|
||||
match (legacy_resolution, resolution) {
|
||||
(Some(legacy_resolution), Ok(resolution)) => {
|
||||
let (legacy_span, participle) = match legacy_resolution {
|
||||
MacroBinding::Modern(binding)
|
||||
if binding.def() == resolution.def() => continue,
|
||||
MacroBinding::Modern(binding) => (binding.span, "imported"),
|
||||
MacroBinding::Legacy(binding) => (binding.span, "defined"),
|
||||
};
|
||||
let msg1 = format!("`{}` could refer to the macro {} here", ident, participle);
|
||||
let msg2 = format!("`{}` could also refer to the macro imported here", ident);
|
||||
self.session.struct_span_err(span, &format!("`{}` is ambiguous", ident))
|
||||
.span_note(legacy_span, &msg1)
|
||||
.span_note(resolution.span, &msg2)
|
||||
.emit();
|
||||
},
|
||||
(Some(MacroBinding::Modern(binding)), Err(_)) => {
|
||||
self.record_use(ident, MacroNS, binding, span);
|
||||
self.err_if_macro_use_proc_macro(ident.name, span, binding);
|
||||
continue
|
||||
},
|
||||
_ => continue,
|
||||
(None, Err(_)) => {
|
||||
let msg = match kind {
|
||||
MacroKind::Bang =>
|
||||
format!("cannot find macro `{}!` in this scope", ident),
|
||||
MacroKind::Attr =>
|
||||
format!("cannot find attribute macro `{}` in this scope", ident),
|
||||
MacroKind::Derive =>
|
||||
format!("cannot find derive macro `{}` in this scope", ident),
|
||||
};
|
||||
let mut err = self.session.struct_span_err(span, &msg);
|
||||
self.suggest_macro_name(&ident.name.as_str(), kind, &mut err);
|
||||
err.emit();
|
||||
},
|
||||
_ => {},
|
||||
};
|
||||
let (legacy_span, participle) = match legacy_resolution {
|
||||
MacroBinding::Modern(binding) if binding.def() == resolution.def() => continue,
|
||||
MacroBinding::Modern(binding) => (binding.span, "imported"),
|
||||
MacroBinding::Legacy(binding) => (binding.span, "defined"),
|
||||
};
|
||||
let msg1 = format!("`{}` could refer to the macro {} here", ident, participle);
|
||||
let msg2 = format!("`{}` could also refer to the macro imported here", ident);
|
||||
self.session.struct_span_err(span, &format!("`{}` is ambiguous", ident))
|
||||
.span_note(legacy_span, &msg1)
|
||||
.span_note(resolution.span, &msg2)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
fn suggest_macro_name(&mut self, name: &str, err: &mut DiagnosticBuilder<'a>) {
|
||||
if let Some(suggestion) = find_best_match_for_name(self.macro_names.iter(), name, None) {
|
||||
fn suggest_macro_name(&mut self, name: &str, kind: MacroKind,
|
||||
err: &mut DiagnosticBuilder<'a>) {
|
||||
let suggestion = match kind {
|
||||
MacroKind::Bang =>
|
||||
find_best_match_for_name(self.macro_names.iter(), name, None),
|
||||
MacroKind::Attr |
|
||||
MacroKind::Derive => {
|
||||
// Find a suggestion from the legacy namespace.
|
||||
// FIXME: get_macro needs an &mut Resolver, can we do it without cloning?
|
||||
let builtin_macros = self.builtin_macros.clone();
|
||||
let names = builtin_macros.iter().filter_map(|(name, binding)| {
|
||||
if binding.get_macro(self).kind() == kind {
|
||||
Some(name)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
find_best_match_for_name(names, name, None)
|
||||
}
|
||||
};
|
||||
if let Some(suggestion) = suggestion {
|
||||
if suggestion != name {
|
||||
err.help(&format!("did you mean `{}!`?", suggestion));
|
||||
if let MacroKind::Bang = kind {
|
||||
err.help(&format!("did you mean `{}!`?", suggestion));
|
||||
} else {
|
||||
err.help(&format!("did you mean `{}`?", suggestion));
|
||||
}
|
||||
} else {
|
||||
err.help(&format!("have you added the `#[macro_use]` on the module/import?"));
|
||||
}
|
||||
|
@ -474,6 +474,17 @@ impl MacResult for DummyResult {
|
||||
pub type BuiltinDeriveFn =
|
||||
for<'cx> fn(&'cx mut ExtCtxt, Span, &MetaItem, &Annotatable, &mut FnMut(Annotatable));
|
||||
|
||||
/// Represents different kinds of macro invocations that can be resolved.
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub enum MacroKind {
|
||||
/// A bang macro - foo!()
|
||||
Bang,
|
||||
/// An attribute macro - #[foo]
|
||||
Attr,
|
||||
/// A derive attribute macro - #[derive(Foo)]
|
||||
Derive,
|
||||
}
|
||||
|
||||
/// An enum representing the different kinds of syntax extensions.
|
||||
pub enum SyntaxExtension {
|
||||
/// A syntax extension that is attached to an item and creates new items
|
||||
@ -520,6 +531,25 @@ pub enum SyntaxExtension {
|
||||
BuiltinDerive(BuiltinDeriveFn),
|
||||
}
|
||||
|
||||
impl SyntaxExtension {
|
||||
/// Return which kind of macro calls this syntax extension.
|
||||
pub fn kind(&self) -> MacroKind {
|
||||
match *self {
|
||||
SyntaxExtension::NormalTT(..) |
|
||||
SyntaxExtension::IdentTT(..) |
|
||||
SyntaxExtension::ProcMacro(..) =>
|
||||
MacroKind::Bang,
|
||||
SyntaxExtension::MultiDecorator(..) |
|
||||
SyntaxExtension::MultiModifier(..) |
|
||||
SyntaxExtension::AttrProcMacro(..) =>
|
||||
MacroKind::Attr,
|
||||
SyntaxExtension::ProcMacroDerive(..) |
|
||||
SyntaxExtension::BuiltinDerive(..) =>
|
||||
MacroKind::Derive,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type NamedSyntaxExtension = (Name, SyntaxExtension);
|
||||
|
||||
pub trait Resolver {
|
||||
@ -535,10 +565,8 @@ pub trait Resolver {
|
||||
fn resolve_imports(&mut self);
|
||||
// Resolves attribute and derive legacy macros from `#![plugin(..)]`.
|
||||
fn find_legacy_attr_invoc(&mut self, attrs: &mut Vec<Attribute>) -> Option<Attribute>;
|
||||
fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, force: bool)
|
||||
-> Result<Rc<SyntaxExtension>, Determinacy>;
|
||||
fn resolve_derive_macro(&mut self, scope: Mark, path: &ast::Path, force: bool)
|
||||
-> Result<Rc<SyntaxExtension>, Determinacy>;
|
||||
fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind,
|
||||
force: bool) -> Result<Rc<SyntaxExtension>, Determinacy>;
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
@ -561,12 +589,8 @@ impl Resolver for DummyResolver {
|
||||
|
||||
fn resolve_imports(&mut self) {}
|
||||
fn find_legacy_attr_invoc(&mut self, _attrs: &mut Vec<Attribute>) -> Option<Attribute> { None }
|
||||
fn resolve_macro(&mut self, _scope: Mark, _path: &ast::Path, _force: bool)
|
||||
-> Result<Rc<SyntaxExtension>, Determinacy> {
|
||||
Err(Determinacy::Determined)
|
||||
}
|
||||
fn resolve_derive_macro(&mut self, _scope: Mark, _path: &ast::Path, _force: bool)
|
||||
-> Result<Rc<SyntaxExtension>, Determinacy> {
|
||||
fn resolve_macro(&mut self, _scope: Mark, _path: &ast::Path, _kind: MacroKind,
|
||||
_force: bool) -> Result<Rc<SyntaxExtension>, Determinacy> {
|
||||
Err(Determinacy::Determined)
|
||||
}
|
||||
}
|
||||
|
@ -282,8 +282,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||
let mark = Mark::fresh();
|
||||
derives.push(mark);
|
||||
let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name));
|
||||
let item = match self.cx.resolver
|
||||
.resolve_macro(Mark::root(), &path, false) {
|
||||
let item = match self.cx.resolver.resolve_macro(
|
||||
Mark::root(), &path, MacroKind::Derive, false) {
|
||||
Ok(ext) => match *ext {
|
||||
SyntaxExtension::BuiltinDerive(..) => item_with_markers.clone(),
|
||||
_ => item.clone(),
|
||||
@ -369,12 +369,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||
-> Result<Option<Rc<SyntaxExtension>>, Determinacy> {
|
||||
let (attr, traits, item) = match invoc.kind {
|
||||
InvocationKind::Bang { ref mac, .. } => {
|
||||
return self.cx.resolver.resolve_macro(scope, &mac.node.path, force).map(Some);
|
||||
return self.cx.resolver.resolve_macro(scope, &mac.node.path,
|
||||
MacroKind::Bang, force).map(Some);
|
||||
}
|
||||
InvocationKind::Attr { attr: None, .. } => return Ok(None),
|
||||
InvocationKind::Derive { name, span, .. } => {
|
||||
let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name));
|
||||
return self.cx.resolver.resolve_derive_macro(scope, &path, force).map(Some);
|
||||
return self.cx.resolver.resolve_macro(scope, &path,
|
||||
MacroKind::Derive, force).map(Some)
|
||||
}
|
||||
InvocationKind::Attr { ref mut attr, ref traits, ref mut item } => (attr, traits, item),
|
||||
};
|
||||
@ -385,7 +387,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||
};
|
||||
|
||||
let mut determined = true;
|
||||
match self.cx.resolver.resolve_macro(scope, &path, force) {
|
||||
match self.cx.resolver.resolve_macro(scope, &path, MacroKind::Attr, force) {
|
||||
Ok(ext) => return Ok(Some(ext)),
|
||||
Err(Determinacy::Undetermined) => determined = false,
|
||||
Err(Determinacy::Determined) if force => return Err(Determinacy::Determined),
|
||||
@ -394,7 +396,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||
|
||||
for &(name, span) in traits {
|
||||
let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name));
|
||||
match self.cx.resolver.resolve_macro(scope, &path, force) {
|
||||
match self.cx.resolver.resolve_macro(scope, &path, MacroKind::Derive, force) {
|
||||
Ok(ext) => if let SyntaxExtension::ProcMacroDerive(_, ref inert_attrs) = *ext {
|
||||
if inert_attrs.contains(&attr_name) {
|
||||
// FIXME(jseyfried) Avoid `mem::replace` here.
|
||||
|
@ -25,32 +25,45 @@ extern crate syntax;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::parse;
|
||||
use syntax_pos::Span;
|
||||
|
||||
struct ParseSess;
|
||||
|
||||
impl ParseSess {
|
||||
fn cfg(&self) -> ast::CrateConfig { loop { } }
|
||||
fn parse_sess<'a>(&'a self) -> &'a parse::ParseSess { loop { } }
|
||||
fn call_site(&self) -> Span { loop { } }
|
||||
fn call_site(&self) -> () { loop { } }
|
||||
fn ident_of(&self, st: &str) -> ast::Ident { loop { } }
|
||||
fn name_of(&self, st: &str) -> ast::Name { loop { } }
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let ecx = &ParseSess;
|
||||
let x = quote_tokens!(ecx, 3); //~ ERROR macro undefined: `quote_tokens`
|
||||
let x = quote_expr!(ecx, 3); //~ ERROR macro undefined: `quote_expr`
|
||||
let x = quote_ty!(ecx, 3); //~ ERROR macro undefined: `quote_ty`
|
||||
let x = quote_method!(ecx, 3); //~ ERROR macro undefined: `quote_method`
|
||||
let x = quote_item!(ecx, 3); //~ ERROR macro undefined: `quote_item`
|
||||
let x = quote_pat!(ecx, 3); //~ ERROR macro undefined: `quote_pat`
|
||||
let x = quote_arm!(ecx, 3); //~ ERROR macro undefined: `quote_arm`
|
||||
let x = quote_stmt!(ecx, 3); //~ ERROR macro undefined: `quote_stmt`
|
||||
let x = quote_matcher!(ecx, 3); //~ ERROR macro undefined: `quote_matcher`
|
||||
let x = quote_attr!(ecx, 3); //~ ERROR macro undefined: `quote_attr`
|
||||
let x = quote_arg!(ecx, 3); //~ ERROR macro undefined: `quote_arg`
|
||||
let x = quote_block!(ecx, 3); //~ ERROR macro undefined: `quote_block`
|
||||
let x = quote_meta_item!(ecx, 3); //~ ERROR macro undefined: `quote_meta_item`
|
||||
let x = quote_path!(ecx, 3); //~ ERROR macro undefined: `quote_path`
|
||||
let x = quote_tokens!(ecx, 3);
|
||||
//~^ ERROR cannot find macro `quote_tokens!` in this scope
|
||||
let x = quote_expr!(ecx, 3);
|
||||
//~^ ERROR cannot find macro `quote_expr!` in this scope
|
||||
let x = quote_ty!(ecx, 3);
|
||||
//~^ ERROR cannot find macro `quote_ty!` in this scope
|
||||
let x = quote_method!(ecx, 3);
|
||||
//~^ ERROR cannot find macro `quote_method!` in this scope
|
||||
let x = quote_item!(ecx, 3);
|
||||
//~^ ERROR cannot find macro `quote_item!` in this scope
|
||||
let x = quote_pat!(ecx, 3);
|
||||
//~^ ERROR cannot find macro `quote_pat!` in this scope
|
||||
let x = quote_arm!(ecx, 3);
|
||||
//~^ ERROR cannot find macro `quote_arm!` in this scope
|
||||
let x = quote_stmt!(ecx, 3);
|
||||
//~^ ERROR cannot find macro `quote_stmt!` in this scope
|
||||
let x = quote_matcher!(ecx, 3);
|
||||
//~^ ERROR cannot find macro `quote_matcher!` in this scope
|
||||
let x = quote_attr!(ecx, 3);
|
||||
//~^ ERROR cannot find macro `quote_attr!` in this scope
|
||||
let x = quote_arg!(ecx, 3);
|
||||
//~^ ERROR cannot find macro `quote_arg!` in this scope
|
||||
let x = quote_block!(ecx, 3);
|
||||
//~^ ERROR cannot find macro `quote_block!` in this scope
|
||||
let x = quote_meta_item!(ecx, 3);
|
||||
//~^ ERROR cannot find macro `quote_meta_item!` in this scope
|
||||
let x = quote_path!(ecx, 3);
|
||||
//~^ ERROR cannot find macro `quote_path!` in this scope
|
||||
}
|
||||
|
@ -14,5 +14,6 @@
|
||||
extern crate macro_crate_test;
|
||||
|
||||
fn main() {
|
||||
assert_eq!(3, unexported_macro!()); //~ ERROR macro undefined: `unexported_macro`
|
||||
unexported_macro!();
|
||||
//~^ ERROR cannot find macro `unexported_macro!` in this scope
|
||||
}
|
||||
|
@ -0,0 +1,23 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// force-host
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![crate_type = "proc-macro"]
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
|
||||
#[proc_macro_derive(Clona)]
|
||||
pub fn derive_clonea(input: TokenStream) -> TokenStream {
|
||||
"".parse().unwrap()
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// force-host
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![crate_type = "proc-macro"]
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
|
||||
#[proc_macro_derive(FooWithLongName)]
|
||||
pub fn derive_foo(input: TokenStream) -> TokenStream {
|
||||
"".parse().unwrap()
|
||||
}
|
44
src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs
Normal file
44
src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:derive-foo.rs
|
||||
// aux-build:derive-clona.rs
|
||||
// aux-build:attr_proc_macro.rs
|
||||
|
||||
#![feature(proc_macro)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate derive_foo;
|
||||
#[macro_use]
|
||||
extern crate derive_clona;
|
||||
extern crate attr_proc_macro;
|
||||
|
||||
use attr_proc_macro::attr_proc_macro;
|
||||
|
||||
#[derive(FooWithLongNam)]
|
||||
//~^ ERROR cannot find derive macro `FooWithLongNam` in this scope
|
||||
//~^^ HELP did you mean `FooWithLongName`?
|
||||
struct Foo;
|
||||
|
||||
#[attr_proc_macra]
|
||||
//~^ ERROR cannot find attribute macro `attr_proc_macra` in this scope
|
||||
struct Bar;
|
||||
|
||||
#[derive(Dlone)]
|
||||
//~^ ERROR cannot find derive macro `Dlone` in this scope
|
||||
//~^^ HELP did you mean `Clone`?
|
||||
struct A;
|
||||
|
||||
#[derive(Dlona)]
|
||||
//~^ ERROR cannot find derive macro `Dlona` in this scope
|
||||
//~^^ HELP did you mean `Clona`?
|
||||
struct B;
|
||||
|
||||
fn main() {}
|
@ -8,7 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[derive(FromPrimitive)] //~ERROR cannot find derive macro `FromPrimitive` in this scope
|
||||
#[derive(FromPrimitive)] //~ ERROR cannot find derive macro `FromPrimitive` in this scope
|
||||
enum Foo {}
|
||||
|
||||
fn main() {}
|
||||
|
@ -14,5 +14,6 @@
|
||||
extern crate two_macros;
|
||||
|
||||
pub fn main() {
|
||||
macro_two!(); //~ ERROR macro undefined
|
||||
macro_two!();
|
||||
//~^ ERROR cannot find macro
|
||||
}
|
||||
|
@ -8,5 +8,5 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// error-pattern:macro undefined
|
||||
// error-pattern:cannot find macro
|
||||
fn main() { iamnotanextensionthatexists!(""); }
|
||||
|
@ -12,12 +12,12 @@
|
||||
// gate
|
||||
|
||||
__register_diagnostic!(E0001);
|
||||
//~^ ERROR macro undefined: `__register_diagnostic`
|
||||
//~^ ERROR cannot find macro `__register_diagnostic!` in this scope
|
||||
|
||||
fn main() {
|
||||
__diagnostic_used!(E0001);
|
||||
//~^ ERROR macro undefined: `__diagnostic_used`
|
||||
//~^ ERROR cannot find macro `__diagnostic_used!` in this scope
|
||||
}
|
||||
|
||||
__build_diagnostic_array!(DIAGNOSTICS);
|
||||
//~^ ERROR macro undefined: `__build_diagnostic_array`
|
||||
//~^ ERROR cannot find macro `__build_diagnostic_array!` in this scope
|
||||
|
14
src/test/compile-fail/issue-11692-1.rs
Normal file
14
src/test/compile-fail/issue-11692-1.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
fn main() {
|
||||
print!(test!());
|
||||
//~^ ERROR: format argument must be a string literal
|
||||
}
|
@ -9,10 +9,6 @@
|
||||
// except according to those terms.
|
||||
|
||||
fn main() {
|
||||
print!(test!());
|
||||
//~^ ERROR: macro undefined: `test`
|
||||
//~^^ ERROR: format argument must be a string literal
|
||||
|
||||
concat!(test!());
|
||||
//~^ ERROR: macro undefined: `test`
|
||||
//~^ ERROR cannot find macro `test!` in this scope
|
||||
}
|
@ -10,6 +10,9 @@
|
||||
|
||||
fn main() {}
|
||||
|
||||
struct Type;
|
||||
|
||||
impl Type {
|
||||
undef!(); //~ ERROR macro undefined: `undef`
|
||||
undef!();
|
||||
//~^ ERROR cannot find macro `undef!` in this scope
|
||||
}
|
||||
|
@ -16,5 +16,4 @@ fn main() {
|
||||
foo!(0); // Check that we report errors at macro definition, not expansion.
|
||||
|
||||
let _: cfg!(foo) = (); //~ ERROR non-type macro in type position
|
||||
derive!(); //~ ERROR macro undefined: `derive`
|
||||
}
|
||||
|
@ -12,14 +12,16 @@ mod macros_cant_escape_fns {
|
||||
fn f() {
|
||||
macro_rules! m { () => { 3 + 4 } }
|
||||
}
|
||||
fn g() -> i32 { m!() } //~ ERROR macro undefined
|
||||
fn g() -> i32 { m!() }
|
||||
//~^ ERROR cannot find macro
|
||||
}
|
||||
|
||||
mod macros_cant_escape_mods {
|
||||
mod f {
|
||||
macro_rules! m { () => { 3 + 4 } }
|
||||
}
|
||||
fn g() -> i32 { m!() } //~ ERROR macro undefined
|
||||
fn g() -> i32 { m!() }
|
||||
//~^ ERROR cannot find macro
|
||||
}
|
||||
|
||||
mod macros_can_escape_flattened_mods_test {
|
||||
|
@ -9,6 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
fn main() {
|
||||
printlx!("oh noes!"); //~ ERROR macro undefined
|
||||
//~^ HELP did you mean `println!`?
|
||||
printlx!("oh noes!");
|
||||
//~^ ERROR cannot find macro
|
||||
//~^^ HELP did you mean `println!`?
|
||||
}
|
||||
|
@ -15,5 +15,6 @@
|
||||
extern crate macro_non_reexport_2;
|
||||
|
||||
fn main() {
|
||||
assert_eq!(reexported!(), 3); //~ ERROR macro undefined
|
||||
assert_eq!(reexported!(), 3);
|
||||
//~^ ERROR cannot find macro `reexported!` in this scope
|
||||
}
|
||||
|
@ -17,5 +17,6 @@
|
||||
extern crate macro_reexport_1;
|
||||
|
||||
fn main() {
|
||||
assert_eq!(reexported!(), 3); //~ ERROR macro undefined
|
||||
assert_eq!(reexported!(), 3);
|
||||
//~^ ERROR cannot find macro
|
||||
}
|
||||
|
@ -14,5 +14,6 @@
|
||||
extern crate two_macros;
|
||||
|
||||
pub fn main() {
|
||||
macro_two!(); //~ ERROR macro undefined
|
||||
macro_two!();
|
||||
//~^ ERROR cannot find macro
|
||||
}
|
||||
|
@ -18,8 +18,10 @@ mod m {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
k!(); //~ ERROR macro undefined: `k`
|
||||
//~^ HELP did you mean `kl!`?
|
||||
kl!(); //~ ERROR macro undefined: `kl`
|
||||
//~^ HELP have you added the `#[macro_use]` on the module/import?
|
||||
k!();
|
||||
//~^ ERROR cannot find macro `k!` in this scope
|
||||
//~^^ HELP did you mean `kl!`?
|
||||
kl!();
|
||||
//~^ ERROR cannot find macro `kl!` in this scope
|
||||
//~^^ HELP have you added the `#[macro_use]` on the module/import?
|
||||
}
|
||||
|
@ -14,15 +14,10 @@
|
||||
#![feature(asm)]
|
||||
#![feature(trace_macros, concat_idents)]
|
||||
|
||||
#[derive(Zero)] //~ ERROR
|
||||
struct CantDeriveThis;
|
||||
|
||||
#[derive(Default)] //~ ERROR
|
||||
enum OrDeriveThis {}
|
||||
|
||||
fn main() {
|
||||
doesnt_exist!(); //~ ERROR
|
||||
|
||||
asm!(invalid); //~ ERROR
|
||||
|
||||
concat_idents!("not", "idents"); //~ ERROR
|
||||
|
@ -13,5 +13,6 @@
|
||||
extern crate two_macros;
|
||||
|
||||
pub fn main() {
|
||||
macro_two!(); //~ ERROR macro undefined
|
||||
macro_two!();
|
||||
//~^ ERROR cannot find macro `macro_two!` in this scope
|
||||
}
|
||||
|
@ -10,12 +10,16 @@
|
||||
|
||||
// compile-flags: -Z continue-parse-after-error
|
||||
|
||||
struct Self;
|
||||
//~^ ERROR expected identifier, found keyword `Self`
|
||||
mod foo {
|
||||
struct Self;
|
||||
//~^ ERROR expected identifier, found keyword `Self`
|
||||
}
|
||||
|
||||
struct Bar<'Self>;
|
||||
//~^ ERROR lifetimes cannot use keyword names
|
||||
|
||||
struct Foo;
|
||||
|
||||
pub fn main() {
|
||||
match 15 {
|
||||
ref Self => (),
|
||||
@ -25,7 +29,7 @@ pub fn main() {
|
||||
ref mut Self => (),
|
||||
//~^ ERROR expected identifier, found keyword `Self`
|
||||
Self!() => (),
|
||||
//~^ ERROR macro undefined: `Self`
|
||||
//~^ ERROR cannot find macro `Self!` in this scope
|
||||
Foo { Self } => (),
|
||||
//~^ ERROR expected identifier, found keyword `Self`
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user