Refactor macro resolution errors + add derive macro suggestions

This commit is contained in:
Josh Driver 2017-02-06 22:14:38 +10:30
parent 05a7f25cc4
commit 2d91e7aab8
27 changed files with 300 additions and 123 deletions

View File

@ -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(|| {

View File

@ -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,
}
}

View File

@ -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?"));
}

View File

@ -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)
}
}

View File

@ -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.

View File

@ -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
}

View File

@ -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
}

View File

@ -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()
}

View File

@ -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()
}

View 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() {}

View File

@ -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() {}

View File

@ -14,5 +14,6 @@
extern crate two_macros;
pub fn main() {
macro_two!(); //~ ERROR macro undefined
macro_two!();
//~^ ERROR cannot find macro
}

View File

@ -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!(""); }

View File

@ -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

View 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
}

View File

@ -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
}

View File

@ -10,6 +10,9 @@
fn main() {}
struct Type;
impl Type {
undef!(); //~ ERROR macro undefined: `undef`
undef!();
//~^ ERROR cannot find macro `undef!` in this scope
}

View File

@ -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`
}

View File

@ -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 {

View File

@ -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!`?
}

View File

@ -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
}

View File

@ -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
}

View File

@ -14,5 +14,6 @@
extern crate two_macros;
pub fn main() {
macro_two!(); //~ ERROR macro undefined
macro_two!();
//~^ ERROR cannot find macro
}

View File

@ -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?
}

View File

@ -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

View File

@ -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
}

View File

@ -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`
}