}
macro_rules! contains_anon_attr {
- ($($attr:ident),*) => ({$(is_anon_attr!($attr) | )* false});
+ ($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_anon_attr!($attr) | )* false});
}
macro_rules! contains_eval_always_attr {
- ($($attr:ident),*) => ({$(is_eval_always_attr!($attr) | )* false});
+ ($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_eval_always_attr!($attr) | )* false});
}
macro_rules! define_dep_nodes {
(<$tcx:tt>
$(
- [$($attr:ident),* ]
+ [$($attrs:tt)*]
$variant:ident $(( $tuple_arg_ty:ty $(,)? ))*
$({ $($struct_arg_name:ident : $struct_arg_ty:ty),* })*
,)*
match *self {
$(
DepKind :: $variant => {
- if contains_anon_attr!($($attr),*) {
+ if contains_anon_attr!($($attrs)*) {
return false;
}
pub fn is_anon(&self) -> bool {
match *self {
$(
- DepKind :: $variant => { contains_anon_attr!($($attr),*) }
+ DepKind :: $variant => { contains_anon_attr!($($attrs)*) }
)*
}
}
pub fn is_eval_always(&self) -> bool {
match *self {
$(
- DepKind :: $variant => { contains_eval_always_attr!($($attr), *) }
+ DepKind :: $variant => { contains_eval_always_attr!($($attrs)*) }
)*
}
}
$tcx.report_cycle($error).emit();
Value::from_cycle_error($tcx)
}};
- ([fatal_cycle$(, $modifiers:ident)*][$tcx:expr, $error:expr]) => {{
+ ([fatal_cycle $($rest:tt)*][$tcx:expr, $error:expr]) => {{
$tcx.report_cycle($error).emit();
$tcx.sess.abort_if_errors();
unreachable!()
}};
- ([cycle_delay_bug$(, $modifiers:ident)*][$tcx:expr, $error:expr]) => {{
+ ([cycle_delay_bug $($rest:tt)*][$tcx:expr, $error:expr]) => {{
$tcx.report_cycle($error).delay_as_bug();
Value::from_cycle_error($tcx)
}};
- ([$other:ident$(, $modifiers:ident)*][$($args:tt)*]) => {
- handle_cycle_error!([$($modifiers),*][$($args)*])
+ ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*][$($args:tt)*]) => {
+ handle_cycle_error!([$($($modifiers)*)*][$($args)*])
};
}
([]) => {{
false
}};
- ([anon$(, $modifiers:ident)*]) => {{
+ ([anon $($rest:tt)*]) => {{
true
}};
- ([$other:ident$(, $modifiers:ident)*]) => {
- is_anon!([$($modifiers),*])
+ ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*]) => {
+ is_anon!([$($($modifiers)*)*])
};
}
([]) => {{
false
}};
- ([eval_always$(, $modifiers:ident)*]) => {{
+ ([eval_always $($rest:tt)*]) => {{
true
}};
- ([$other:ident$(, $modifiers:ident)*]) => {
- is_eval_always!([$($modifiers),*])
+ ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*]) => {
+ is_eval_always!([$($($modifiers)*)*])
+ };
+}
+
+macro_rules! query_storage {
+ ([][$K:ty, $V:ty]) => {
+ <<$K as Key>::CacheSelector as CacheSelector<$K, $V>>::Cache
+ };
+ ([storage($ty:ty) $($rest:tt)*][$K:ty, $V:ty]) => {
+ $ty
+ };
+ ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*][$($args:tt)*]) => {
+ query_storage!([$($($modifiers)*)*][$($args)*])
};
}
([][$hcx:expr, $result:expr]) => {{
dep_graph::hash_result($hcx, &$result)
}};
- ([no_hash$(, $modifiers:ident)*][$hcx:expr, $result:expr]) => {{
+ ([no_hash $($rest:tt)*][$hcx:expr, $result:expr]) => {{
None
}};
- ([$other:ident$(, $modifiers:ident)*][$($args:tt)*]) => {
- hash_result!([$($modifiers),*][$($args)*])
+ ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*][$($args:tt)*]) => {
+ hash_result!([$($($modifiers)*)*][$($args)*])
};
}
const ANON: bool = is_anon!([$($modifiers)*]);
const EVAL_ALWAYS: bool = is_eval_always!([$($modifiers)*]);
- type Cache = <<$K as Key>::CacheSelector as CacheSelector<$K, $V>>::Cache;
+ type Cache = query_storage!([$($modifiers)*][$K, $V]);
#[inline(always)]
fn query(key: Self::Key) -> Query<'tcx> {
/// The description of the query.
Desc(Option<Ident>, Punctuated<Expr, Token![,]>),
+ /// Use this type for the in-memory cache.
+ Storage(Type),
+
/// Cache the query to disk if the `Expr` returns true.
Cache(Option<(IdentOrWild, IdentOrWild)>, Block),
let id = args.parse()?;
let block = input.parse()?;
Ok(QueryModifier::LoadCached(tcx, id, block))
+ } else if modifier == "storage" {
+ let ty = input.parse()?;
+ Ok(QueryModifier::Storage(ty))
} else if modifier == "fatal_cycle" {
Ok(QueryModifier::FatalCycle)
} else if modifier == "cycle_delay_bug" {
/// The description of the query.
desc: Option<(Option<Ident>, Punctuated<Expr, Token![,]>)>,
+ /// Use this type for the in-memory cache.
+ storage: Option<Type>,
+
/// Cache the query to disk if the `Block` returns true.
cache: Option<(Option<(IdentOrWild, IdentOrWild)>, Block)>,
/// Process query modifiers into a struct, erroring on duplicates
fn process_modifiers(query: &mut Query) -> QueryModifiers {
let mut load_cached = None;
+ let mut storage = None;
let mut cache = None;
let mut desc = None;
let mut fatal_cycle = false;
}
load_cached = Some((tcx, id, block));
}
+ QueryModifier::Storage(ty) => {
+ if storage.is_some() {
+ panic!("duplicate modifier `storage` for query `{}`", query.name);
+ }
+ storage = Some(ty);
+ }
QueryModifier::Cache(args, expr) => {
if cache.is_some() {
panic!("duplicate modifier `cache` for query `{}`", query.name);
}
QueryModifiers {
load_cached,
+ storage,
cache,
desc,
fatal_cycle,
if modifiers.fatal_cycle {
attributes.push(quote! { fatal_cycle });
};
+ // Pass on the storage modifier
+ if let Some(ref ty) = modifiers.storage {
+ attributes.push(quote! { storage(#ty) });
+ };
// Pass on the cycle_delay_bug modifier
if modifiers.cycle_delay_bug {
attributes.push(quote! { cycle_delay_bug });