Serialize additional data for procedural macros

Split off from #62855

This PR deerializes the declaration `Span` and attributes for all
procedural macros from their underlying function definitions.
This allows Rustdoc to properly render doc comments
and source links when inlining procedural macros across crates
This commit is contained in:
Aaron Hill 2019-08-04 16:41:01 -04:00
parent ac60ca0643
commit 64f867ae3e
No known key found for this signature in database
GPG Key ID: B4087E510E98B164
17 changed files with 240 additions and 210 deletions

View File

@ -468,6 +468,14 @@ pub enum ProcMacro {
} }
impl ProcMacro { impl ProcMacro {
pub fn name(&self) -> &'static str {
match self {
ProcMacro::CustomDerive { trait_name, .. } => trait_name,
ProcMacro::Attr { name, .. } => name,
ProcMacro::Bang { name, ..} => name
}
}
pub const fn custom_derive( pub const fn custom_derive(
trait_name: &'static str, trait_name: &'static str,
attributes: &'static [&'static str], attributes: &'static [&'static str],

View File

@ -1,5 +1,4 @@
use crate::ty::{self, TyCtxt}; use crate::ty::{self, TyCtxt};
use crate::hir::map::definitions::FIRST_FREE_DEF_INDEX;
use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_vec::Idx;
use std::fmt; use std::fmt;
use std::u32; use std::u32;
@ -102,31 +101,6 @@ newtype_index! {
} }
} }
impl DefIndex {
// Proc macros from a proc-macro crate have a kind of virtual DefIndex. This
// function maps the index of the macro within the crate (which is also the
// index of the macro in the CrateMetadata::proc_macros array) to the
// corresponding DefIndex.
pub fn from_proc_macro_index(proc_macro_index: usize) -> DefIndex {
// DefIndex for proc macros start from FIRST_FREE_DEF_INDEX,
// because the first FIRST_FREE_DEF_INDEX indexes are reserved
// for internal use.
let def_index = DefIndex::from(
proc_macro_index.checked_add(FIRST_FREE_DEF_INDEX)
.expect("integer overflow adding `proc_macro_index`"));
assert!(def_index != CRATE_DEF_INDEX);
def_index
}
// This function is the reverse of from_proc_macro_index() above.
pub fn to_proc_macro_index(self: DefIndex) -> usize {
self.index().checked_sub(FIRST_FREE_DEF_INDEX)
.unwrap_or_else(|| {
bug!("using local index {:?} as proc-macro index", self)
})
}
}
impl rustc_serialize::UseSpecializedEncodable for DefIndex {} impl rustc_serialize::UseSpecializedEncodable for DefIndex {}
impl rustc_serialize::UseSpecializedDecodable for DefIndex {} impl rustc_serialize::UseSpecializedDecodable for DefIndex {}

View File

@ -411,10 +411,6 @@ impl Definitions {
} }
/// Adds a root definition (no parent) and a few other reserved definitions. /// Adds a root definition (no parent) and a few other reserved definitions.
///
/// After the initial definitions are created the first `FIRST_FREE_DEF_INDEX` indexes
/// are taken, so the "user" indexes will be allocated starting with `FIRST_FREE_DEF_INDEX`
/// in ascending order.
pub fn create_root_def(&mut self, pub fn create_root_def(&mut self,
crate_name: &str, crate_name: &str,
crate_disambiguator: CrateDisambiguator) crate_disambiguator: CrateDisambiguator)
@ -589,19 +585,6 @@ impl DefPathData {
} }
} }
/// Evaluates to the number of tokens passed to it.
///
/// Logarithmic counting: every one or two recursive expansions, the number of
/// tokens to count is divided by two, instead of being reduced by one.
/// Therefore, the recursion depth is the binary logarithm of the number of
/// tokens to count, and the expanded tree is likewise very small.
macro_rules! count {
() => (0usize);
($one:tt) => (1usize);
($($pairs:tt $_p:tt)*) => (count!($($pairs)*) << 1usize);
($odd:tt $($rest:tt)*) => (count!($($rest)*) | 1usize);
}
// We define the GlobalMetaDataKind enum with this macro because we want to // We define the GlobalMetaDataKind enum with this macro because we want to
// make sure that we exhaustively iterate over all variants when registering // make sure that we exhaustively iterate over all variants when registering
// the corresponding DefIndices in the DefTable. // the corresponding DefIndices in the DefTable.
@ -614,8 +597,6 @@ macro_rules! define_global_metadata_kind {
$($variant),* $($variant),*
} }
pub const FIRST_FREE_DEF_INDEX: usize = 1 + count!($($variant)*);
impl GlobalMetaDataKind { impl GlobalMetaDataKind {
fn allocate_def_indices(definitions: &mut Definitions) { fn allocate_def_indices(definitions: &mut Definitions) {
$({ $({

View File

@ -2,8 +2,7 @@
use crate::cstore::{self, CStore, CrateSource, MetadataBlob}; use crate::cstore::{self, CStore, CrateSource, MetadataBlob};
use crate::locator::{self, CratePaths}; use crate::locator::{self, CratePaths};
use crate::decoder::proc_macro_def_path_table; use crate::schema::{CrateRoot};
use crate::schema::CrateRoot;
use rustc_data_structures::sync::{Lrc, RwLock, Lock}; use rustc_data_structures::sync::{Lrc, RwLock, Lock};
use rustc::hir::def_id::CrateNum; use rustc::hir::def_id::CrateNum;
@ -26,11 +25,11 @@ use std::{cmp, fs};
use syntax::ast; use syntax::ast;
use syntax::attr; use syntax::attr;
use syntax::ext::allocator::{global_allocator_spans, AllocatorKind}; use syntax::ext::allocator::{global_allocator_spans, AllocatorKind};
use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind};
use syntax::symbol::{Symbol, sym}; use syntax::symbol::{Symbol, sym};
use syntax::{span_err, span_fatal}; use syntax::{span_err, span_fatal};
use syntax_pos::{Span, DUMMY_SP}; use syntax_pos::{Span, DUMMY_SP};
use log::{debug, info, log_enabled}; use log::{debug, info, log_enabled};
use proc_macro::bridge::client::ProcMacro;
pub struct Library { pub struct Library {
pub dylib: Option<(PathBuf, PathKind)>, pub dylib: Option<(PathBuf, PathKind)>,
@ -230,24 +229,13 @@ impl<'a> CrateLoader<'a> {
let dependencies: Vec<CrateNum> = cnum_map.iter().cloned().collect(); let dependencies: Vec<CrateNum> = cnum_map.iter().cloned().collect();
let proc_macros = crate_root.proc_macro_decls_static.map(|_| { let raw_proc_macros = crate_root.proc_macro_data.map(|_| {
if self.sess.opts.debugging_opts.dual_proc_macros { if self.sess.opts.debugging_opts.dual_proc_macros {
let host_lib = host_lib.unwrap(); let host_lib = host_lib.as_ref().unwrap();
self.load_derive_macros( self.dlsym_proc_macros(host_lib.dylib.as_ref().map(|p| p.0.clone()),
&host_lib.metadata.get_root(), &host_lib.metadata.get_root(), span)
host_lib.dylib.map(|p| p.0),
span
)
} else { } else {
self.load_derive_macros(&crate_root, dylib.clone().map(|p| p.0), span) self.dlsym_proc_macros(dylib.clone().map(|p| p.0), &crate_root, span)
}
});
let def_path_table = record_time(&self.sess.perf_stats.decode_def_path_tables_time, || {
if let Some(proc_macros) = &proc_macros {
proc_macro_def_path_table(&crate_root, proc_macros)
} else {
crate_root.def_path_table.decode((&metadata, self.sess))
} }
}); });
@ -260,13 +248,16 @@ impl<'a> CrateLoader<'a> {
.map(|trait_impls| (trait_impls.trait_id, trait_impls.impls)) .map(|trait_impls| (trait_impls.trait_id, trait_impls.impls))
.collect(); .collect();
let def_path_table = record_time(&self.sess.perf_stats.decode_def_path_tables_time, || {
crate_root.def_path_table.decode((&metadata, self.sess))
});
let cmeta = cstore::CrateMetadata { let cmeta = cstore::CrateMetadata {
name: crate_root.name, name: crate_root.name,
imported_name: ident, imported_name: ident,
extern_crate: Lock::new(None), extern_crate: Lock::new(None),
def_path_table: Lrc::new(def_path_table), def_path_table: Lrc::new(def_path_table),
trait_impls, trait_impls,
proc_macros,
root: crate_root, root: crate_root,
blob: metadata, blob: metadata,
cnum_map, cnum_map,
@ -280,7 +271,10 @@ impl<'a> CrateLoader<'a> {
rlib, rlib,
rmeta, rmeta,
}, },
private_dep private_dep,
span,
host_lib,
raw_proc_macros
}; };
let cmeta = Lrc::new(cmeta); let cmeta = Lrc::new(cmeta);
@ -389,7 +383,7 @@ impl<'a> CrateLoader<'a> {
match result { match result {
(LoadResult::Previous(cnum), None) => { (LoadResult::Previous(cnum), None) => {
let data = self.cstore.get_crate_data(cnum); let data = self.cstore.get_crate_data(cnum);
if data.root.proc_macro_decls_static.is_some() { if data.root.proc_macro_data.is_some() {
dep_kind = DepKind::UnexportedMacrosOnly; dep_kind = DepKind::UnexportedMacrosOnly;
} }
data.dep_kind.with_lock(|data_dep_kind| { data.dep_kind.with_lock(|data_dep_kind| {
@ -482,7 +476,7 @@ impl<'a> CrateLoader<'a> {
dep_kind: DepKind) dep_kind: DepKind)
-> cstore::CrateNumMap { -> cstore::CrateNumMap {
debug!("resolving deps of external crate"); debug!("resolving deps of external crate");
if crate_root.proc_macro_decls_static.is_some() { if crate_root.proc_macro_data.is_some() {
return cstore::CrateNumMap::new(); return cstore::CrateNumMap::new();
} }
@ -574,19 +568,13 @@ impl<'a> CrateLoader<'a> {
} }
} }
/// Loads custom derive macros. fn dlsym_proc_macros(&self,
/// dylib: Option<PathBuf>,
/// Note that this is intentionally similar to how we load plugins today, root: &CrateRoot<'_>,
/// but also intentionally separate. Plugins are likely always going to be span: Span
/// implemented as dynamic libraries, but we have a possible future where ) -> &'static [ProcMacro] {
/// custom derive (and other macro-1.1 style features) are implemented via use std::env;
/// executables and custom IPC.
fn load_derive_macros(&mut self, root: &CrateRoot<'_>, dylib: Option<PathBuf>, span: Span)
-> Vec<(ast::Name, Lrc<SyntaxExtension>)> {
use std::{env, mem};
use crate::dynamic_lib::DynamicLibrary; use crate::dynamic_lib::DynamicLibrary;
use proc_macro::bridge::client::ProcMacro;
use syntax::ext::proc_macro::{BangProcMacro, AttrProcMacro, ProcMacroDerive};
let path = match dylib { let path = match dylib {
Some(dylib) => dylib, Some(dylib) => dylib,
@ -608,38 +596,11 @@ impl<'a> CrateLoader<'a> {
*(sym as *const &[ProcMacro]) *(sym as *const &[ProcMacro])
}; };
let extensions = decls.iter().map(|&decl| {
let (name, kind, helper_attrs) = match decl {
ProcMacro::CustomDerive { trait_name, attributes, client } => {
let helper_attrs =
attributes.iter().cloned().map(Symbol::intern).collect::<Vec<_>>();
(
trait_name,
SyntaxExtensionKind::Derive(Box::new(ProcMacroDerive {
client, attrs: helper_attrs.clone()
})),
helper_attrs,
)
}
ProcMacro::Attr { name, client } => (
name, SyntaxExtensionKind::Attr(Box::new(AttrProcMacro { client })), Vec::new()
),
ProcMacro::Bang { name, client } => (
name, SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client })), Vec::new()
)
};
(Symbol::intern(name), Lrc::new(SyntaxExtension {
helper_attrs,
..SyntaxExtension::default(kind, root.edition)
}))
}).collect();
// Intentionally leak the dynamic library. We can't ever unload it // Intentionally leak the dynamic library. We can't ever unload it
// since the library can make things that will live arbitrarily long. // since the library can make things that will live arbitrarily long.
mem::forget(lib); std::mem::forget(lib);
extensions decls
} }
/// Look for a plugin registrar. Returns library path, crate /// Look for a plugin registrar. Returns library path, crate

View File

@ -28,6 +28,9 @@ pub use crate::cstore_impl::{provide, provide_extern};
pub type CrateNumMap = IndexVec<CrateNum, CrateNum>; pub type CrateNumMap = IndexVec<CrateNum, CrateNum>;
pub use rustc_data_structures::sync::MetadataRef; pub use rustc_data_structures::sync::MetadataRef;
use crate::creader::Library;
use syntax_pos::Span;
use proc_macro::bridge::client::ProcMacro;
pub struct MetadataBlob(pub MetadataRef); pub struct MetadataBlob(pub MetadataRef);
@ -82,11 +85,19 @@ pub struct CrateMetadata {
pub dep_kind: Lock<DepKind>, pub dep_kind: Lock<DepKind>,
pub source: CrateSource, pub source: CrateSource,
pub proc_macros: Option<Vec<(ast::Name, Lrc<SyntaxExtension>)>>,
/// Whether or not this crate should be consider a private dependency /// Whether or not this crate should be consider a private dependency
/// for purposes of the 'exported_private_dependencies' lint /// for purposes of the 'exported_private_dependencies' lint
pub private_dep: bool pub private_dep: bool,
pub host_lib: Option<Library>,
pub span: Span,
pub raw_proc_macros: Option<&'static [ProcMacro]>,
}
pub struct FullProcMacro {
pub name: ast::Name,
pub ext: Lrc<SyntaxExtension>
} }
pub struct CStore { pub struct CStore {

View File

@ -426,8 +426,8 @@ impl cstore::CStore {
pub fn load_macro_untracked(&self, id: DefId, sess: &Session) -> LoadedMacro { pub fn load_macro_untracked(&self, id: DefId, sess: &Session) -> LoadedMacro {
let data = self.get_crate_data(id.krate); let data = self.get_crate_data(id.krate);
if let Some(ref proc_macros) = data.proc_macros { if data.is_proc_macro_crate() {
return LoadedMacro::ProcMacro(proc_macros[id.index.to_proc_macro_index()].1.clone()); return LoadedMacro::ProcMacro(data.get_proc_macro(id.index, sess).ext);
} else if data.name == sym::proc_macro && data.item_name(id.index) == sym::quote { } else if data.name == sym::proc_macro && data.item_name(id.index) == sym::quote {
let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote); let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote);
let kind = SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client })); let kind = SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client }));
@ -439,7 +439,8 @@ impl cstore::CStore {
} }
let def = data.get_macro(id.index); let def = data.get_macro(id.index);
let macro_full_name = data.def_path(id.index).to_string_friendly(|_| data.imported_name); let macro_full_name = data.def_path(id.index)
.to_string_friendly(|_| data.imported_name);
let source_name = FileName::Macros(macro_full_name); let source_name = FileName::Macros(macro_full_name);
let source_file = sess.parse_sess.source_map().new_source_file(source_name, def.body); let source_file = sess.parse_sess.source_map().new_source_file(source_name, def.body);

View File

@ -1,16 +1,15 @@
// Decoding metadata from a single crate's metadata // Decoding metadata from a single crate's metadata
use crate::cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary, ForeignModule}; use crate::cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary, ForeignModule, FullProcMacro};
use crate::schema::*; use crate::schema::*;
use rustc_data_structures::sync::{Lrc, ReadGuard}; use rustc_data_structures::sync::{Lrc, ReadGuard};
use rustc::hir::map::{DefKey, DefPath, DefPathData, DefPathHash, Definitions}; use rustc::hir::map::{DefKey, DefPath, DefPathData, DefPathHash};
use rustc::hir; use rustc::hir;
use rustc::middle::cstore::LinkagePreference; use rustc::middle::cstore::LinkagePreference;
use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
use rustc::hir::def::{self, Res, DefKind, CtorOf, CtorKind}; use rustc::hir::def::{self, Res, DefKind, CtorOf, CtorKind};
use rustc::hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc::hir::map::definitions::DefPathTable;
use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fingerprint::Fingerprint;
use rustc::middle::lang_items; use rustc::middle::lang_items;
use rustc::mir::{self, interpret}; use rustc::mir::{self, interpret};
@ -30,10 +29,11 @@ use syntax::attr;
use syntax::ast::{self, Ident}; use syntax::ast::{self, Ident};
use syntax::source_map; use syntax::source_map;
use syntax::symbol::{Symbol, sym}; use syntax::symbol::{Symbol, sym};
use syntax::ext::base::{MacroKind, SyntaxExtension}; use syntax::ext::base::{MacroKind, SyntaxExtensionKind, SyntaxExtension};
use syntax::ext::hygiene::ExpnId; use syntax_pos::{self, Span, BytePos, Pos, DUMMY_SP, symbol::{InternedString}};
use syntax_pos::{self, Span, BytePos, Pos, DUMMY_SP};
use log::debug; use log::debug;
use proc_macro::bridge::client::ProcMacro;
use syntax::ext::proc_macro::{AttrProcMacro, ProcMacroDerive, BangProcMacro};
pub struct DecodeContext<'a, 'tcx> { pub struct DecodeContext<'a, 'tcx> {
opaque: opaque::Decoder<'a>, opaque: opaque::Decoder<'a>,
@ -138,7 +138,7 @@ impl<'a: 'x, 'tcx: 'x, 'x, T: Decodable> LazySeq<T> {
pub fn decode<M: Metadata<'a, 'tcx>>( pub fn decode<M: Metadata<'a, 'tcx>>(
self, self,
meta: M, meta: M,
) -> impl Iterator<Item = T> + Captures<'a> + Captures<'tcx> + 'x { ) -> impl ExactSizeIterator<Item = T> + Captures<'a> + Captures<'tcx> + 'x {
let mut dcx = meta.decoder(self.position); let mut dcx = meta.decoder(self.position);
dcx.lazy_state = LazyState::NodeStart(self.position); dcx.lazy_state = LazyState::NodeStart(self.position);
(0..self.len).map(move |_| T::decode(&mut dcx).unwrap()) (0..self.len).map(move |_| T::decode(&mut dcx).unwrap())
@ -434,46 +434,16 @@ impl<'tcx> EntryKind<'tcx> {
} }
} }
/// Creates the "fake" DefPathTable for a given proc macro crate.
///
/// The DefPathTable is as follows:
///
/// CRATE_ROOT (DefIndex 0:0)
/// |- GlobalMetaDataKind data (DefIndex 1:0 .. DefIndex 1:N)
/// |- proc macro #0 (DefIndex 1:N)
/// |- proc macro #1 (DefIndex 1:N+1)
/// \- ...
crate fn proc_macro_def_path_table(crate_root: &CrateRoot<'_>,
proc_macros: &[(ast::Name, Lrc<SyntaxExtension>)])
-> DefPathTable
{
let mut definitions = Definitions::default();
let name = crate_root.name.as_str();
let disambiguator = crate_root.disambiguator;
debug!("creating proc macro def path table for {:?}/{:?}", name, disambiguator);
let crate_root = definitions.create_root_def(&name, disambiguator);
for (index, (name, _)) in proc_macros.iter().enumerate() {
let def_index = definitions.create_def_with_parent(
crate_root,
ast::DUMMY_NODE_ID,
DefPathData::MacroNs(name.as_interned_str()),
ExpnId::root(),
DUMMY_SP);
debug!("definition for {:?} is {:?}", name, def_index);
assert_eq!(def_index, DefIndex::from_proc_macro_index(index));
}
definitions.def_path_table().clone()
}
impl<'a, 'tcx> CrateMetadata { impl<'a, 'tcx> CrateMetadata {
pub fn is_proc_macro_crate(&self) -> bool {
self.root.proc_macro_decls_static.is_some()
}
fn is_proc_macro(&self, id: DefIndex) -> bool { fn is_proc_macro(&self, id: DefIndex) -> bool {
self.proc_macros.is_some() && id != CRATE_DEF_INDEX self.is_proc_macro_crate() &&
self.root.proc_macro_data.unwrap().decode(self).find(|x| *x == id).is_some()
} }
fn maybe_entry(&self, item_id: DefIndex) -> Option<Lazy<Entry<'tcx>>> { fn maybe_entry(&self, item_id: DefIndex) -> Option<Lazy<Entry<'tcx>>> {
assert!(!self.is_proc_macro(item_id));
self.root.entries_index.lookup(self.blob.raw_bytes(), item_id) self.root.entries_index.lookup(self.blob.raw_bytes(), item_id)
} }
@ -496,13 +466,24 @@ impl<'a, 'tcx> CrateMetadata {
} }
} }
fn raw_proc_macro(&self, id: DefIndex) -> &ProcMacro {
// DefIndex's in root.proc_macro_data have a one-to-one correspondence
// with items in 'raw_proc_macros'
let pos = self.root.proc_macro_data.unwrap().decode(self).position(|i| i == id).unwrap();
&self.raw_proc_macros.unwrap()[pos]
}
pub fn item_name(&self, item_index: DefIndex) -> Symbol { pub fn item_name(&self, item_index: DefIndex) -> Symbol {
if !self.is_proc_macro(item_index) {
self.def_key(item_index) self.def_key(item_index)
.disambiguated_data .disambiguated_data
.data .data
.get_opt_name() .get_opt_name()
.expect("no name in item_name") .expect("no name in item_name")
.as_symbol() .as_symbol()
} else {
Symbol::intern(self.raw_proc_macro(item_index).name())
}
} }
pub fn def_kind(&self, index: DefIndex) -> Option<DefKind> { pub fn def_kind(&self, index: DefIndex) -> Option<DefKind> {
@ -510,15 +491,64 @@ impl<'a, 'tcx> CrateMetadata {
self.entry(index).kind.def_kind() self.entry(index).kind.def_kind()
} else { } else {
Some(DefKind::Macro( Some(DefKind::Macro(
self.proc_macros.as_ref().unwrap()[index.to_proc_macro_index()].1.macro_kind() macro_kind(self.raw_proc_macro(index))
)) ))
} }
} }
pub fn get_span(&self, index: DefIndex, sess: &Session) -> Span { pub fn get_span(&self, index: DefIndex, sess: &Session) -> Span {
match self.is_proc_macro(index) { self.entry(index).span.decode((self, sess))
true => DUMMY_SP, }
false => self.entry(index).span.decode((self, sess)),
pub fn get_proc_macro(&self, id: DefIndex, sess: &Session) -> FullProcMacro {
if sess.opts.debugging_opts.dual_proc_macros {
let host_lib = self.host_lib.as_ref().unwrap();
self.load_proc_macro(
&host_lib.metadata.get_root(),
id,
sess
)
} else {
self.load_proc_macro(&self.root, id, sess)
}
}
fn load_proc_macro(&self, root: &CrateRoot<'_>,
id: DefIndex,
sess: &Session)
-> FullProcMacro {
let raw_macro = self.raw_proc_macro(id);
let (name, kind, helper_attrs) = match *raw_macro {
ProcMacro::CustomDerive { trait_name, attributes, client } => {
let helper_attrs =
attributes.iter().cloned().map(Symbol::intern).collect::<Vec<_>>();
(
trait_name,
SyntaxExtensionKind::Derive(Box::new(ProcMacroDerive {
client, attrs: helper_attrs.clone()
})),
helper_attrs,
)
}
ProcMacro::Attr { name, client } => (
name, SyntaxExtensionKind::Attr(Box::new(AttrProcMacro { client })), Vec::new()
),
ProcMacro::Bang { name, client } => (
name, SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client })), Vec::new()
)
};
let span = self.get_span(id, sess);
FullProcMacro {
name: Symbol::intern(name),
ext: Lrc::new(SyntaxExtension {
span,
helper_attrs,
..SyntaxExtension::default(kind, root.edition)
})
} }
} }
@ -715,7 +745,7 @@ impl<'a, 'tcx> CrateMetadata {
/// Iterates over the language items in the given crate. /// Iterates over the language items in the given crate.
pub fn get_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, usize)] { pub fn get_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, usize)] {
if self.proc_macros.is_some() { if self.is_proc_macro_crate() {
// Proc macro crates do not export any lang-items to the target. // Proc macro crates do not export any lang-items to the target.
&[] &[]
} else { } else {
@ -730,18 +760,18 @@ impl<'a, 'tcx> CrateMetadata {
pub fn each_child_of_item<F>(&self, id: DefIndex, mut callback: F, sess: &Session) pub fn each_child_of_item<F>(&self, id: DefIndex, mut callback: F, sess: &Session)
where F: FnMut(def::Export<hir::HirId>) where F: FnMut(def::Export<hir::HirId>)
{ {
if let Some(ref proc_macros) = self.proc_macros { if let Some(proc_macros_ids) = self.root.proc_macro_data.map(|d| d.decode(self)) {
/* If we are loading as a proc macro, we want to return the view of this crate /* If we are loading as a proc macro, we want to return the view of this crate
* as a proc macro crate, not as a Rust crate. See `proc_macro_def_path_table` * as a proc macro crate.
* for the DefPathTable we are corresponding to.
*/ */
if id == CRATE_DEF_INDEX { if id == CRATE_DEF_INDEX {
for (id, &(name, ref ext)) in proc_macros.iter().enumerate() { for def_index in proc_macros_ids {
let raw_macro = self.raw_proc_macro(def_index);
let res = Res::Def( let res = Res::Def(
DefKind::Macro(ext.macro_kind()), DefKind::Macro(macro_kind(raw_macro)),
self.local_def_id(DefIndex::from_proc_macro_index(id)), self.local_def_id(def_index),
); );
let ident = Ident::with_dummy_span(name); let ident = Ident::from_str(raw_macro.name());
callback(def::Export { callback(def::Export {
ident: ident, ident: ident,
res: res, res: res,
@ -952,11 +982,8 @@ impl<'a, 'tcx> CrateMetadata {
} }
} }
pub fn get_item_attrs(&self, node_id: DefIndex, sess: &Session) -> Lrc<[ast::Attribute]> {
if self.is_proc_macro(node_id) {
return Lrc::new([]);
}
pub fn get_item_attrs(&self, node_id: DefIndex, sess: &Session) -> Lrc<[ast::Attribute]> {
// The attributes for a tuple struct/variant are attached to the definition, not the ctor; // The attributes for a tuple struct/variant are attached to the definition, not the ctor;
// we assume that someone passing in a tuple struct ctor is actually wanting to // we assume that someone passing in a tuple struct ctor is actually wanting to
// look at the definition // look at the definition
@ -1014,7 +1041,7 @@ impl<'a, 'tcx> CrateMetadata {
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
filter: Option<DefId>, filter: Option<DefId>,
) -> &'tcx [DefId] { ) -> &'tcx [DefId] {
if self.proc_macros.is_some() { if self.is_proc_macro_crate() {
// proc-macro crates export no trait impls. // proc-macro crates export no trait impls.
return &[] return &[]
} }
@ -1058,7 +1085,7 @@ impl<'a, 'tcx> CrateMetadata {
pub fn get_native_libraries(&self, sess: &Session) -> Vec<NativeLibrary> { pub fn get_native_libraries(&self, sess: &Session) -> Vec<NativeLibrary> {
if self.proc_macros.is_some() { if self.is_proc_macro_crate() {
// Proc macro crates do not have any *target* native libraries. // Proc macro crates do not have any *target* native libraries.
vec![] vec![]
} else { } else {
@ -1067,7 +1094,7 @@ impl<'a, 'tcx> CrateMetadata {
} }
pub fn get_foreign_modules(&self, tcx: TyCtxt<'tcx>) -> &'tcx [ForeignModule] { pub fn get_foreign_modules(&self, tcx: TyCtxt<'tcx>) -> &'tcx [ForeignModule] {
if self.proc_macros.is_some() { if self.is_proc_macro_crate() {
// Proc macro crates do not have any *target* foreign modules. // Proc macro crates do not have any *target* foreign modules.
&[] &[]
} else { } else {
@ -1090,7 +1117,7 @@ impl<'a, 'tcx> CrateMetadata {
} }
pub fn get_missing_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [lang_items::LangItem] { pub fn get_missing_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [lang_items::LangItem] {
if self.proc_macros.is_some() { if self.is_proc_macro_crate() {
// Proc macro crates do not depend on any target weak lang-items. // Proc macro crates do not depend on any target weak lang-items.
&[] &[]
} else { } else {
@ -1114,7 +1141,7 @@ impl<'a, 'tcx> CrateMetadata {
&self, &self,
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
) -> Vec<(ExportedSymbol<'tcx>, SymbolExportLevel)> { ) -> Vec<(ExportedSymbol<'tcx>, SymbolExportLevel)> {
if self.proc_macros.is_some() { if self.is_proc_macro_crate() {
// If this crate is a custom derive crate, then we're not even going to // If this crate is a custom derive crate, then we're not even going to
// link those in so we skip those crates. // link those in so we skip those crates.
vec![] vec![]
@ -1183,13 +1210,18 @@ impl<'a, 'tcx> CrateMetadata {
#[inline] #[inline]
pub fn def_key(&self, index: DefIndex) -> DefKey { pub fn def_key(&self, index: DefIndex) -> DefKey {
self.def_path_table.def_key(index) let mut key = self.def_path_table.def_key(index);
if self.is_proc_macro(index) {
let name = self.raw_proc_macro(index).name();
key.disambiguated_data.data = DefPathData::MacroNs(InternedString::intern(name));
}
key
} }
// Returns the path leading to the thing with this `id`. // Returns the path leading to the thing with this `id`.
pub fn def_path(&self, id: DefIndex) -> DefPath { pub fn def_path(&self, id: DefIndex) -> DefPath {
debug!("def_path(cnum={:?}, id={:?})", self.cnum, id); debug!("def_path(cnum={:?}, id={:?})", self.cnum, id);
DefPath::make(self.cnum, id, |parent| self.def_path_table.def_key(parent)) DefPath::make(self.cnum, id, |parent| self.def_key(parent))
} }
#[inline] #[inline]
@ -1302,3 +1334,13 @@ impl<'a, 'tcx> CrateMetadata {
self.source_map_import_info.borrow() self.source_map_import_info.borrow()
} }
} }
// Cannot be implemented on 'ProcMacro', as libproc_macro
// does not depend on libsyntax
fn macro_kind(raw: &ProcMacro) -> MacroKind {
match raw {
ProcMacro::CustomDerive { .. } => MacroKind::Derive,
ProcMacro::Attr { .. } => MacroKind::Attr,
ProcMacro::Bang { .. } => MacroKind::Bang
}
}

View File

@ -30,6 +30,7 @@ use rustc_data_structures::sync::Lrc;
use std::u32; use std::u32;
use syntax::ast; use syntax::ast;
use syntax::attr; use syntax::attr;
use syntax::ext::proc_macro::is_proc_macro_attr;
use syntax::source_map::Spanned; use syntax::source_map::Spanned;
use syntax::symbol::{kw, sym}; use syntax::symbol::{kw, sym};
use syntax_pos::{self, FileName, SourceFile, Span}; use syntax_pos::{self, FileName, SourceFile, Span};
@ -376,6 +377,8 @@ impl<'tcx> EncodeContext<'tcx> {
} }
fn encode_crate_root(&mut self) -> Lazy<CrateRoot<'tcx>> { fn encode_crate_root(&mut self) -> Lazy<CrateRoot<'tcx>> {
let is_proc_macro = self.tcx.sess.crate_types.borrow().contains(&CrateType::ProcMacro);
let mut i = self.position(); let mut i = self.position();
let crate_deps = self.encode_crate_deps(); let crate_deps = self.encode_crate_deps();
@ -456,16 +459,23 @@ impl<'tcx> EncodeContext<'tcx> {
self.lazy_seq(interpret_alloc_index) self.lazy_seq(interpret_alloc_index)
}; };
i = self.position(); i = self.position();
let entries_index = self.entries_index.write_index(&mut self.opaque); let entries_index = self.entries_index.write_index(&mut self.opaque);
let entries_index_bytes = self.position() - i; let entries_index_bytes = self.position() - i;
// Encode the proc macro data
i = self.position();
let proc_macro_data = self.encode_proc_macros();
let proc_macro_data_bytes = self.position() - i;
let attrs = tcx.hir().krate_attrs(); let attrs = tcx.hir().krate_attrs();
let is_proc_macro = tcx.sess.crate_types.borrow().contains(&CrateType::ProcMacro);
let has_default_lib_allocator = attr::contains_name(&attrs, sym::default_lib_allocator); let has_default_lib_allocator = attr::contains_name(&attrs, sym::default_lib_allocator);
let has_global_allocator = *tcx.sess.has_global_allocator.get(); let has_global_allocator = *tcx.sess.has_global_allocator.get();
let has_panic_handler = *tcx.sess.has_panic_handler.try_get().unwrap_or(&false); let has_panic_handler = *tcx.sess.has_panic_handler.try_get().unwrap_or(&false);
let root = self.lazy(&CrateRoot { let root = self.lazy(&CrateRoot {
name: tcx.crate_name(LOCAL_CRATE), name: tcx.crate_name(LOCAL_CRATE),
extra_filename: tcx.sess.opts.cg.extra_filename.clone(), extra_filename: tcx.sess.opts.cg.extra_filename.clone(),
@ -484,6 +494,7 @@ impl<'tcx> EncodeContext<'tcx> {
} else { } else {
None None
}, },
proc_macro_data,
proc_macro_stability: if is_proc_macro { proc_macro_stability: if is_proc_macro {
tcx.lookup_stability(DefId::local(CRATE_DEF_INDEX)).map(|stab| stab.clone()) tcx.lookup_stability(DefId::local(CRATE_DEF_INDEX)).map(|stab| stab.clone())
} else { } else {
@ -532,6 +543,7 @@ impl<'tcx> EncodeContext<'tcx> {
println!(" impl bytes: {}", impl_bytes); println!(" impl bytes: {}", impl_bytes);
println!(" exp. symbols bytes: {}", exported_symbols_bytes); println!(" exp. symbols bytes: {}", exported_symbols_bytes);
println!(" def-path table bytes: {}", def_path_table_bytes); println!(" def-path table bytes: {}", def_path_table_bytes);
println!(" proc-macro-data-bytes: {}", proc_macro_data_bytes);
println!(" item bytes: {}", item_bytes); println!(" item bytes: {}", item_bytes);
println!(" entries index bytes: {}", entries_index_bytes); println!(" entries index bytes: {}", entries_index_bytes);
println!(" zero bytes: {}", zero_bytes); println!(" zero bytes: {}", zero_bytes);
@ -1463,6 +1475,22 @@ impl EncodeContext<'tcx> {
self.lazy_seq(foreign_modules.iter().cloned()) self.lazy_seq(foreign_modules.iter().cloned())
} }
fn encode_proc_macros(&mut self) -> Option<LazySeq<DefIndex>> {
let is_proc_macro = self.tcx.sess.crate_types.borrow().contains(&CrateType::ProcMacro);
if is_proc_macro {
let proc_macros: Vec<_> = self.tcx.hir().krate().items.values().filter_map(|item| {
if item.attrs.iter().any(|attr| is_proc_macro_attr(attr)) {
Some(item.hir_id.owner)
} else {
None
}
}).collect();
Some(self.lazy_seq(proc_macros))
} else {
None
}
}
fn encode_crate_deps(&mut self) -> LazySeq<CrateDep> { fn encode_crate_deps(&mut self) -> LazySeq<CrateDep> {
let crates = self.tcx.crates(); let crates = self.tcx.crates();

View File

@ -716,7 +716,9 @@ impl<'a> Context<'a> {
let root = metadata.get_root(); let root = metadata.get_root();
if let Some(is_proc_macro) = self.is_proc_macro { if let Some(is_proc_macro) = self.is_proc_macro {
if root.proc_macro_decls_static.is_some() != is_proc_macro { if root.proc_macro_data.is_some() != is_proc_macro {
info!("Rejecting via proc macro: expected {} got {}",
is_proc_macro, root.proc_macro_data.is_some());
return None; return None;
} }
} }

View File

@ -182,6 +182,10 @@ pub struct CrateRoot<'tcx> {
pub entries_index: LazySeq<index::Index<'tcx>>, pub entries_index: LazySeq<index::Index<'tcx>>,
/// The DefIndex's of any proc macros delcared by
/// this crate
pub proc_macro_data: Option<LazySeq<DefIndex>>,
pub compiler_builtins: bool, pub compiler_builtins: bool,
pub needs_allocator: bool, pub needs_allocator: bool,
pub needs_panic_runtime: bool, pub needs_panic_runtime: bool,

View File

@ -18,7 +18,10 @@ error: `$x:expr` may be followed by `$y:tt`, which is not allowed for `expr` fra
--> $DIR/same-sequence-span.rs:20:1 --> $DIR/same-sequence-span.rs:20:1
| |
LL | proc_macro_sequence::make_foo!(); LL | proc_macro_sequence::make_foo!();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not allowed after `expr` fragments | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| not allowed after `expr` fragments
| in this macro invocation
| |
= note: allowed there are: `=>`, `,` or `;` = note: allowed there are: `=>`, `,` or `;`
@ -26,7 +29,10 @@ error: `$x:expr` may be followed by `=`, which is not allowed for `expr` fragmen
--> $DIR/same-sequence-span.rs:20:1 --> $DIR/same-sequence-span.rs:20:1
| |
LL | proc_macro_sequence::make_foo!(); LL | proc_macro_sequence::make_foo!();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not allowed after `expr` fragments | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| not allowed after `expr` fragments
| in this macro invocation
| |
= note: allowed there are: `=>`, `,` or `;` = note: allowed there are: `=>`, `,` or `;`

View File

@ -2,13 +2,19 @@ error[E0412]: cannot find type `FromOutside` in this scope
--> $DIR/generate-mod.rs:9:1 --> $DIR/generate-mod.rs:9:1
| |
LL | generate_mod::check!(); LL | generate_mod::check!();
| ^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope | ^^^^^^^^^^^^^^^^^^^^^^^
| |
| not found in this scope
| in this macro invocation
error[E0412]: cannot find type `Outer` in this scope error[E0412]: cannot find type `Outer` in this scope
--> $DIR/generate-mod.rs:9:1 --> $DIR/generate-mod.rs:9:1
| |
LL | generate_mod::check!(); LL | generate_mod::check!();
| ^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope | ^^^^^^^^^^^^^^^^^^^^^^^
| |
| not found in this scope
| in this macro invocation
error[E0412]: cannot find type `FromOutside` in this scope error[E0412]: cannot find type `FromOutside` in this scope
--> $DIR/generate-mod.rs:12:1 --> $DIR/generate-mod.rs:12:1

View File

@ -2,7 +2,10 @@ error: unexpected close delimiter: `)`
--> $DIR/invalid-punct-ident-4.rs:6:1 --> $DIR/invalid-punct-ident-4.rs:6:1
| |
LL | lexer_failure!(); LL | lexer_failure!();
| ^^^^^^^^^^^^^^^^^ unexpected close delimiter | ^^^^^^^^^^^^^^^^^
| |
| unexpected close delimiter
| in this macro invocation
error: proc macro panicked error: proc macro panicked
--> $DIR/invalid-punct-ident-4.rs:6:1 --> $DIR/invalid-punct-ident-4.rs:6:1

View File

@ -2,7 +2,10 @@ error[E0425]: cannot find value `foobar2` in this scope
--> $DIR/lints_in_proc_macros.rs:12:5 --> $DIR/lints_in_proc_macros.rs:12:5
| |
LL | bang_proc_macro2!(); LL | bang_proc_macro2!();
| ^^^^^^^^^^^^^^^^^^^^ help: a local variable with a similar name exists: `foobar` | ^^^^^^^^^^^^^^^^^^^^
| |
| help: a local variable with a similar name exists: `foobar`
| in this macro invocation
error: aborting due to previous error error: aborting due to previous error

View File

@ -2,7 +2,7 @@ error: hello to you, too!
--> $DIR/multispan.rs:14:5 --> $DIR/multispan.rs:14:5
| |
LL | hello!(hi); LL | hello!(hi);
| ^^^^^^^^^^^ | ^^^^^^^^^^^ in this macro invocation
| |
note: found these 'hi's note: found these 'hi's
--> $DIR/multispan.rs:14:12 --> $DIR/multispan.rs:14:12
@ -14,7 +14,7 @@ error: hello to you, too!
--> $DIR/multispan.rs:17:5 --> $DIR/multispan.rs:17:5
| |
LL | hello!(hi hi); LL | hello!(hi hi);
| ^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^ in this macro invocation
| |
note: found these 'hi's note: found these 'hi's
--> $DIR/multispan.rs:17:12 --> $DIR/multispan.rs:17:12
@ -26,7 +26,7 @@ error: hello to you, too!
--> $DIR/multispan.rs:20:5 --> $DIR/multispan.rs:20:5
| |
LL | hello!(hi hi hi); LL | hello!(hi hi hi);
| ^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^ in this macro invocation
| |
note: found these 'hi's note: found these 'hi's
--> $DIR/multispan.rs:20:12 --> $DIR/multispan.rs:20:12
@ -38,7 +38,7 @@ error: hello to you, too!
--> $DIR/multispan.rs:23:5 --> $DIR/multispan.rs:23:5
| |
LL | hello!(hi hey hi yo hi beep beep hi hi); LL | hello!(hi hey hi yo hi beep beep hi hi);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in this macro invocation
| |
note: found these 'hi's note: found these 'hi's
--> $DIR/multispan.rs:23:12 --> $DIR/multispan.rs:23:12
@ -50,7 +50,7 @@ error: hello to you, too!
--> $DIR/multispan.rs:24:5 --> $DIR/multispan.rs:24:5
| |
LL | hello!(hi there, hi how are you? hi... hi.); LL | hello!(hi there, hi how are you? hi... hi.);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in this macro invocation
| |
note: found these 'hi's note: found these 'hi's
--> $DIR/multispan.rs:24:12 --> $DIR/multispan.rs:24:12
@ -62,7 +62,7 @@ error: hello to you, too!
--> $DIR/multispan.rs:25:5 --> $DIR/multispan.rs:25:5
| |
LL | hello!(whoah. hi di hi di ho); LL | hello!(whoah. hi di hi di ho);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in this macro invocation
| |
note: found these 'hi's note: found these 'hi's
--> $DIR/multispan.rs:25:19 --> $DIR/multispan.rs:25:19
@ -74,7 +74,7 @@ error: hello to you, too!
--> $DIR/multispan.rs:26:5 --> $DIR/multispan.rs:26:5
| |
LL | hello!(hi good hi and good bye); LL | hello!(hi good hi and good bye);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in this macro invocation
| |
note: found these 'hi's note: found these 'hi's
--> $DIR/multispan.rs:26:12 --> $DIR/multispan.rs:26:12

View File

@ -2,7 +2,7 @@ error: found 'hi's
--> $DIR/subspan.rs:11:1 --> $DIR/subspan.rs:11:1
| |
LL | subspan!("hi"); LL | subspan!("hi");
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^ in this macro invocation
| |
note: here note: here
--> $DIR/subspan.rs:11:11 --> $DIR/subspan.rs:11:11
@ -14,7 +14,7 @@ error: found 'hi's
--> $DIR/subspan.rs:14:1 --> $DIR/subspan.rs:14:1
| |
LL | subspan!("hihi"); LL | subspan!("hihi");
| ^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^ in this macro invocation
| |
note: here note: here
--> $DIR/subspan.rs:14:11 --> $DIR/subspan.rs:14:11
@ -26,7 +26,7 @@ error: found 'hi's
--> $DIR/subspan.rs:17:1 --> $DIR/subspan.rs:17:1
| |
LL | subspan!("hihihi"); LL | subspan!("hihihi");
| ^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^ in this macro invocation
| |
note: here note: here
--> $DIR/subspan.rs:17:11 --> $DIR/subspan.rs:17:11
@ -38,7 +38,7 @@ error: found 'hi's
--> $DIR/subspan.rs:20:1 --> $DIR/subspan.rs:20:1
| |
LL | subspan!("why I hide? hi!"); LL | subspan!("why I hide? hi!");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in this macro invocation
| |
note: here note: here
--> $DIR/subspan.rs:20:17 --> $DIR/subspan.rs:20:17
@ -50,7 +50,7 @@ error: found 'hi's
--> $DIR/subspan.rs:21:1 --> $DIR/subspan.rs:21:1
| |
LL | subspan!("hey, hi, hidy, hidy, hi hi"); LL | subspan!("hey, hi, hidy, hidy, hi hi");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in this macro invocation
| |
note: here note: here
--> $DIR/subspan.rs:21:16 --> $DIR/subspan.rs:21:16
@ -62,7 +62,7 @@ error: found 'hi's
--> $DIR/subspan.rs:22:1 --> $DIR/subspan.rs:22:1
| |
LL | subspan!("this is a hi, and this is another hi"); LL | subspan!("this is a hi, and this is another hi");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in this macro invocation
| |
note: here note: here
--> $DIR/subspan.rs:22:12 --> $DIR/subspan.rs:22:12
@ -74,7 +74,7 @@ error: found 'hi's
--> $DIR/subspan.rs:23:1 --> $DIR/subspan.rs:23:1
| |
LL | subspan!("how are you this evening"); LL | subspan!("how are you this evening");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in this macro invocation
| |
note: here note: here
--> $DIR/subspan.rs:23:24 --> $DIR/subspan.rs:23:24
@ -86,7 +86,7 @@ error: found 'hi's
--> $DIR/subspan.rs:24:1 --> $DIR/subspan.rs:24:1
| |
LL | subspan!("this is highly eradic"); LL | subspan!("this is highly eradic");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in this macro invocation
| |
note: here note: here
--> $DIR/subspan.rs:24:12 --> $DIR/subspan.rs:24:12

View File

@ -2,7 +2,7 @@ error: found 2 equal signs, need exactly 3
--> $DIR/three-equals.rs:15:5 --> $DIR/three-equals.rs:15:5
| |
LL | three_equals!(==); LL | three_equals!(==);
| ^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^ in this macro invocation
| |
= help: input must be: `===` = help: input must be: `===`