Skip to content

Define queries using a proc macro #56462

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 19, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 18 additions & 7 deletions src/librustc/dep_graph/dep_node.rs
Original file line number Diff line number Diff line change
@@ -423,7 +423,7 @@ impl DefId {
}
}

define_dep_nodes!( <'tcx>
rustc_dep_node_append!([define_dep_nodes!][ <'tcx>
// We use this for most things when incr. comp. is turned off.
[] Null,

@@ -492,9 +492,6 @@ define_dep_nodes!( <'tcx>
// table in the tcx (or elsewhere) maps to one of these
// nodes.
[] AssociatedItems(DefId),
[] TypeOfItem(DefId),
[] GenericsOfItem(DefId),
[] PredicatesOfItem(DefId),
[] ExplicitPredicatesOfItem(DefId),
[] PredicatesDefinedOnItem(DefId),
[] InferredOutlivesOf(DefId),
@@ -570,7 +567,6 @@ define_dep_nodes!( <'tcx>
[] FnArgNames(DefId),
[] RenderedConst(DefId),
[] DylibDepFormats(CrateNum),
[] IsPanicRuntime(CrateNum),
[] IsCompilerBuiltins(CrateNum),
[] HasGlobalAllocator(CrateNum),
[] HasPanicHandler(CrateNum),
@@ -588,7 +584,6 @@ define_dep_nodes!( <'tcx>
[] CheckTraitItemWellFormed(DefId),
[] CheckImplItemWellFormed(DefId),
[] ReachableNonGenerics(CrateNum),
[] NativeLibraries(CrateNum),
[] EntryFn(CrateNum),
[] PluginRegistrarFn(CrateNum),
[] ProcMacroDeclsStatic(CrateNum),
@@ -679,7 +674,23 @@ define_dep_nodes!( <'tcx>

[] UpstreamMonomorphizations(CrateNum),
[] UpstreamMonomorphizationsFor(DefId),
);
]);

pub trait RecoverKey<'tcx>: Sized {
fn recover(tcx: TyCtxt<'_, 'tcx, 'tcx>, dep_node: &DepNode) -> Option<Self>;
}

impl RecoverKey<'tcx> for CrateNum {
fn recover(tcx: TyCtxt<'_, 'tcx, 'tcx>, dep_node: &DepNode) -> Option<Self> {
dep_node.extract_def_id(tcx).map(|id| id.krate)
}
}

impl RecoverKey<'tcx> for DefId {
fn recover(tcx: TyCtxt<'_, 'tcx, 'tcx>, dep_node: &DepNode) -> Option<Self> {
dep_node.extract_def_id(tcx)
}
}

trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug {
const CAN_RECONSTRUCT_QUERY_KEY: bool;
2 changes: 1 addition & 1 deletion src/librustc/dep_graph/mod.rs
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ mod serialized;
pub mod cgu_reuse_tracker;

pub use self::dep_tracking_map::{DepTrackingMap, DepTrackingMapConfig};
pub use self::dep_node::{DepNode, DepKind, DepConstructor, WorkProductId, label_strs};
pub use self::dep_node::{DepNode, DepKind, DepConstructor, WorkProductId, RecoverKey, label_strs};
pub use self::graph::{DepGraph, WorkProduct, DepNodeIndex, DepNodeColor, TaskDeps, hash_result};
pub use self::graph::WorkProductFileKind;
pub use self::prev::PreviousDepGraph;
6 changes: 6 additions & 0 deletions src/librustc/lib.rs
Original file line number Diff line number Diff line change
@@ -60,6 +60,8 @@
#![feature(test)]
#![feature(in_band_lifetimes)]
#![feature(crate_visibility_modifier)]
#![feature(proc_macro_hygiene)]
#![feature(log_syntax)]

#![recursion_limit="512"]

@@ -69,6 +71,7 @@ extern crate getopts;
#[macro_use] extern crate scoped_tls;
#[cfg(windows)]
extern crate libc;
#[macro_use] extern crate rustc_macros;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW wherever possible it'd be great to stop using #[macro_use] for new macro-based code

#[macro_use] extern crate rustc_data_structures;

#[macro_use] extern crate log;
@@ -96,6 +99,9 @@ mod macros;
// registered before they are used.
pub mod diagnostics;

#[macro_use]
pub mod query;

pub mod cfg;
pub mod dep_graph;
pub mod hir;
66 changes: 66 additions & 0 deletions src/librustc/query/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use crate::ty::query::QueryDescription;
use crate::ty::query::queries;
use crate::ty::TyCtxt;
use crate::ty;
use crate::hir::def_id::CrateNum;
use crate::dep_graph::SerializedDepNodeIndex;
use std::borrow::Cow;

// Each of these queries corresponds to a function pointer field in the
// `Providers` struct for requesting a value of that type, and a method
// on `tcx: TyCtxt` (and `tcx.at(span)`) for doing that request in a way
// which memoizes and does dep-graph tracking, wrapping around the actual
// `Providers` that the driver creates (using several `rustc_*` crates).
//
// The result type of each query must implement `Clone`, and additionally
// `ty::query::values::Value`, which produces an appropriate placeholder
// (error) value if the query resulted in a query cycle.
// Queries marked with `fatal_cycle` do not need the latter implementation,
// as they will raise an fatal error on query cycles instead.
rustc_queries! {
Other {
/// Records the type of every item.
query type_of(key: DefId) -> Ty<'tcx> {
cache { key.is_local() }
}

/// Maps from the `DefId` of an item (trait/struct/enum/fn) to its
/// associated generics.
query generics_of(key: DefId) -> &'tcx ty::Generics {
cache { key.is_local() }
load_cached(tcx, id) {
let generics: Option<ty::Generics> = tcx.queries.on_disk_cache
.try_load_query_result(tcx, id);
generics.map(|x| tcx.alloc_generics(x))
}
}

/// Maps from the `DefId` of an item (trait/struct/enum/fn) to the
/// predicates (where-clauses) that must be proven true in order
/// to reference it. This is almost always the "predicates query"
/// that you want.
///
/// `predicates_of` builds on `predicates_defined_on` -- in fact,
/// it is almost always the same as that query, except for the
/// case of traits. For traits, `predicates_of` contains
/// an additional `Self: Trait<...>` predicate that users don't
/// actually write. This reflects the fact that to invoke the
/// trait (e.g., via `Default::default`) you must supply types
/// that actually implement the trait. (However, this extra
/// predicate gets in the way of some checks, which are intended
/// to operate over only the actual where-clauses written by the
/// user.)
query predicates_of(_: DefId) -> Lrc<ty::GenericPredicates<'tcx>> {}

query native_libraries(_: CrateNum) -> Lrc<Vec<NativeLibrary>> {
desc { "looking up the native libraries of a linked crate" }
}
}

Codegen {
query is_panic_runtime(_: CrateNum) -> bool {
fatal_cycle
desc { "checking if the crate is_panic_runtime" }
}
}
}
32 changes: 2 additions & 30 deletions src/librustc/ty/query/config.rs
Original file line number Diff line number Diff line change
@@ -34,7 +34,7 @@ pub trait QueryConfig<'tcx> {
type Value: Clone;
}

pub(super) trait QueryAccessors<'tcx>: QueryConfig<'tcx> {
pub(crate) trait QueryAccessors<'tcx>: QueryConfig<'tcx> {
fn query(key: Self::Key) -> Query<'tcx>;

// Don't use this method to access query results, instead use the methods on TyCtxt
@@ -53,7 +53,7 @@ pub(super) trait QueryAccessors<'tcx>: QueryConfig<'tcx> {
fn handle_cycle_error(tcx: TyCtxt<'_, 'tcx, '_>, error: CycleError<'tcx>) -> Self::Value;
}

pub(super) trait QueryDescription<'tcx>: QueryAccessors<'tcx> {
pub(crate) trait QueryDescription<'tcx>: QueryAccessors<'tcx> {
fn describe(tcx: TyCtxt<'_, '_, '_>, key: Self::Key) -> Cow<'static, str>;

#[inline]
@@ -587,12 +587,6 @@ impl<'tcx> QueryDescription<'tcx> for queries::dylib_dependency_formats<'tcx> {
}
}

impl<'tcx> QueryDescription<'tcx> for queries::is_panic_runtime<'tcx> {
fn describe(_: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> {
"checking if the crate is_panic_runtime".into()
}
}

impl<'tcx> QueryDescription<'tcx> for queries::is_compiler_builtins<'tcx> {
fn describe(_: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> {
"checking if the crate is_compiler_builtins".into()
@@ -671,12 +665,6 @@ impl<'tcx> QueryDescription<'tcx> for queries::reachable_non_generics<'tcx> {
}
}

impl<'tcx> QueryDescription<'tcx> for queries::native_libraries<'tcx> {
fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> {
"looking up the native libraries of a linked crate".into()
}
}

impl<'tcx> QueryDescription<'tcx> for queries::foreign_modules<'tcx> {
fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> {
"looking up the foreign modules of a linked crate".into()
@@ -949,21 +937,6 @@ impl<'tcx> QueryDescription<'tcx> for queries::instance_def_size_estimate<'tcx>
}
}

impl<'tcx> QueryDescription<'tcx> for queries::generics_of<'tcx> {
#[inline]
fn cache_on_disk(_: TyCtxt<'_, 'tcx, 'tcx>, def_id: Self::Key) -> bool {
def_id.is_local()
}

fn try_load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
id: SerializedDepNodeIndex)
-> Option<Self::Value> {
let generics: Option<ty::Generics> = tcx.queries.on_disk_cache
.try_load_query_result(tcx, id);
generics.map(|x| tcx.alloc_generics(x))
}
}

impl<'tcx> QueryDescription<'tcx> for queries::program_clauses_for<'tcx> {
fn describe(_tcx: TyCtxt<'_, '_, '_>, _: DefId) -> Cow<'static, str> {
"generating chalk-style clauses".into()
@@ -1027,7 +1000,6 @@ impl_disk_cacheable_query!(borrowck, |_, def_id| def_id.is_local());
impl_disk_cacheable_query!(mir_const_qualif, |_, def_id| def_id.is_local());
impl_disk_cacheable_query!(check_match, |_, def_id| def_id.is_local());
impl_disk_cacheable_query!(def_symbol_name, |_, _| true);
impl_disk_cacheable_query!(type_of, |_, def_id| def_id.is_local());
impl_disk_cacheable_query!(predicates_of, |_, def_id| def_id.is_local());
impl_disk_cacheable_query!(used_trait_imports, |_, def_id| def_id.is_local());
impl_disk_cacheable_query!(codegen_fn_attrs, |_, _| true);
37 changes: 6 additions & 31 deletions src/librustc/ty/query/mod.rs
Original file line number Diff line number Diff line change
@@ -80,13 +80,14 @@ mod values;
use self::values::Value;

mod config;
pub(crate) use self::config::QueryDescription;
pub use self::config::QueryConfig;
use self::config::{QueryAccessors, QueryDescription};
use self::config::QueryAccessors;

mod on_disk_cache;
pub use self::on_disk_cache::OnDiskCache;

// Each of these quries corresponds to a function pointer field in the
// Each of these queries corresponds to a function pointer field in the
// `Providers` struct for requesting a value of that type, and a method
// on `tcx: TyCtxt` (and `tcx.at(span)`) for doing that request in a way
// which memoizes and does dep-graph tracking, wrapping around the actual
@@ -97,35 +98,12 @@ pub use self::on_disk_cache::OnDiskCache;
// (error) value if the query resulted in a query cycle.
// Queries marked with `fatal_cycle` do not need the latter implementation,
// as they will raise an fatal error on query cycles instead.
define_queries! { <'tcx>

rustc_query_append! { [define_queries!][ <'tcx>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is mind-bending, but cool!

Other {
/// Run analysis passes on the crate
[] fn analysis: Analysis(CrateNum) -> Result<(), ErrorReported>,

/// Records the type of every item.
[] fn type_of: TypeOfItem(DefId) -> Ty<'tcx>,

/// Maps from the `DefId` of an item (trait/struct/enum/fn) to its
/// associated generics.
[] fn generics_of: GenericsOfItem(DefId) -> &'tcx ty::Generics,

/// Maps from the `DefId` of an item (trait/struct/enum/fn) to the
/// predicates (where-clauses) that must be proven true in order
/// to reference it. This is almost always the "predicates query"
/// that you want.
///
/// `predicates_of` builds on `predicates_defined_on` -- in fact,
/// it is almost always the same as that query, except for the
/// case of traits. For traits, `predicates_of` contains
/// an additional `Self: Trait<...>` predicate that users don't
/// actually write. This reflects the fact that to invoke the
/// trait (e.g., via `Default::default`) you must supply types
/// that actually implement the trait. (However, this extra
/// predicate gets in the way of some checks, which are intended
/// to operate over only the actual where-clauses written by the
/// user.)
[] fn predicates_of: PredicatesOfItem(DefId) -> Lrc<ty::GenericPredicates<'tcx>>,

/// Maps from the `DefId` of an item (trait/struct/enum/fn) to the
/// predicates (where-clauses) directly defined on it. This is
/// equal to the `explicit_predicates_of` predicates plus the
@@ -446,7 +424,6 @@ define_queries! { <'tcx>
},

Codegen {
[fatal_cycle] fn is_panic_runtime: IsPanicRuntime(CrateNum) -> bool,
[fatal_cycle] fn is_compiler_builtins: IsCompilerBuiltins(CrateNum) -> bool,
[fatal_cycle] fn has_global_allocator: HasGlobalAllocator(CrateNum) -> bool,
[fatal_cycle] fn has_panic_handler: HasPanicHandler(CrateNum) -> bool,
@@ -504,8 +481,6 @@ define_queries! { <'tcx>
},

Other {
[] fn native_libraries: NativeLibraries(CrateNum) -> Lrc<Vec<NativeLibrary>>,

[] fn foreign_modules: ForeignModules(CrateNum) -> Lrc<Vec<ForeignModule>>,

/// Identifies the entry-point (e.g., the `main` function) for a given
@@ -752,7 +727,7 @@ define_queries! { <'tcx>
[] fn wasm_import_module_map: WasmImportModuleMap(CrateNum)
-> Lrc<FxHashMap<DefId, String>>,
},
}
]}

//////////////////////////////////////////////////////////////////////
// These functions are little shims used to find the dep-node for a
38 changes: 22 additions & 16 deletions src/librustc/ty/query/plumbing.rs
Original file line number Diff line number Diff line change
@@ -1131,10 +1131,12 @@ macro_rules! define_provider_struct {
/// then `force_from_dep_node()` should not fail for it. Otherwise, you can just
/// add it to the "We don't have enough information to reconstruct..." group in
/// the match below.
pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
dep_node: &DepNode)
-> bool {
pub fn force_from_dep_node<'tcx>(
tcx: TyCtxt<'_, 'tcx, 'tcx>,
dep_node: &DepNode
) -> bool {
use crate::hir::def_id::LOCAL_CRATE;
use crate::dep_graph::RecoverKey;

// We must avoid ever having to call force_from_dep_node() for a
// DepNode::CodegenUnit:
@@ -1171,17 +1173,26 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
() => { (def_id!()).krate }
};

macro_rules! force {
($query:ident, $key:expr) => {
macro_rules! force_ex {
($tcx:expr, $query:ident, $key:expr) => {
{
tcx.force_query::<crate::ty::query::queries::$query<'_>>($key, DUMMY_SP, *dep_node);
$tcx.force_query::<crate::ty::query::queries::$query<'_>>(
$key,
DUMMY_SP,
*dep_node
);
}
}
};

macro_rules! force {
($query:ident, $key:expr) => { force_ex!(tcx, $query, $key) }
};

// FIXME(#45015): We should try move this boilerplate code into a macro
// somehow.
match dep_node.kind {

rustc_dep_node_force!([dep_node, tcx]
// These are inputs that are expected to be pre-allocated and that
// should therefore always be red or green already
DepKind::AllLocalTraitImpls |
@@ -1274,9 +1285,6 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
DepKind::MirKeys => { force!(mir_keys, LOCAL_CRATE); }
DepKind::CrateVariances => { force!(crate_variances, LOCAL_CRATE); }
DepKind::AssociatedItems => { force!(associated_item, def_id!()); }
DepKind::TypeOfItem => { force!(type_of, def_id!()); }
DepKind::GenericsOfItem => { force!(generics_of, def_id!()); }
DepKind::PredicatesOfItem => { force!(predicates_of, def_id!()); }
DepKind::PredicatesDefinedOnItem => { force!(predicates_defined_on, def_id!()); }
DepKind::ExplicitPredicatesOfItem => { force!(explicit_predicates_of, def_id!()); }
DepKind::InferredOutlivesOf => { force!(inferred_outlives_of, def_id!()); }
@@ -1332,7 +1340,6 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
DepKind::FnArgNames => { force!(fn_arg_names, def_id!()); }
DepKind::RenderedConst => { force!(rendered_const, def_id!()); }
DepKind::DylibDepFormats => { force!(dylib_dependency_formats, krate!()); }
DepKind::IsPanicRuntime => { force!(is_panic_runtime, krate!()); }
DepKind::IsCompilerBuiltins => { force!(is_compiler_builtins, krate!()); }
DepKind::HasGlobalAllocator => { force!(has_global_allocator, krate!()); }
DepKind::HasPanicHandler => { force!(has_panic_handler, krate!()); }
@@ -1349,7 +1356,6 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
DepKind::CheckTraitItemWellFormed => { force!(check_trait_item_well_formed, def_id!()); }
DepKind::CheckImplItemWellFormed => { force!(check_impl_item_well_formed, def_id!()); }
DepKind::ReachableNonGenerics => { force!(reachable_non_generics, krate!()); }
DepKind::NativeLibraries => { force!(native_libraries, krate!()); }
DepKind::EntryFn => { force!(entry_fn, krate!()); }
DepKind::PluginRegistrarFn => { force!(plugin_registrar_fn, krate!()); }
DepKind::ProcMacroDeclsStatic => { force!(proc_macro_decls_static, krate!()); }
@@ -1432,7 +1438,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
DepKind::BackendOptimizationLevel => {
force!(backend_optimization_level, krate!());
}
}
);

true
}
@@ -1493,9 +1499,9 @@ impl_load_from_cache!(
SymbolName => def_symbol_name,
ConstIsRvaluePromotableToStatic => const_is_rvalue_promotable_to_static,
CheckMatch => check_match,
TypeOfItem => type_of,
GenericsOfItem => generics_of,
PredicatesOfItem => predicates_of,
type_of => type_of,
generics_of => generics_of,
predicates_of => predicates_of,
UsedTraitImports => used_trait_imports,
CodegenFnAttrs => codegen_fn_attrs,
SpecializationGraph => specialization_graph_of,
22 changes: 11 additions & 11 deletions src/librustc_incremental/persist/dirty_clean.rs
Original file line number Diff line number Diff line change
@@ -36,16 +36,16 @@ const CFG: &str = "cfg";

/// For typedef, constants, and statics
const BASE_CONST: &[&str] = &[
label_strs::TypeOfItem,
label_strs::type_of,
];

/// DepNodes for functions + methods
const BASE_FN: &[&str] = &[
// Callers will depend on the signature of these items, so we better test
label_strs::FnSignature,
label_strs::GenericsOfItem,
label_strs::PredicatesOfItem,
label_strs::TypeOfItem,
label_strs::generics_of,
label_strs::predicates_of,
label_strs::type_of,

// And a big part of compilation (that we eventually want to cache) is type inference
// information:
@@ -62,7 +62,7 @@ const BASE_HIR: &[&str] = &[
/// `impl` implementation of struct/trait
const BASE_IMPL: &[&str] = &[
label_strs::AssociatedItemDefIds,
label_strs::GenericsOfItem,
label_strs::generics_of,
label_strs::ImplTraitRef,
];

@@ -78,17 +78,17 @@ const BASE_MIR: &[&str] = &[
/// Note that changing the type of a field does not change the type of the struct or enum, but
/// adding/removing fields or changing a fields name or visibility does.
const BASE_STRUCT: &[&str] = &[
label_strs::GenericsOfItem,
label_strs::PredicatesOfItem,
label_strs::TypeOfItem,
label_strs::generics_of,
label_strs::predicates_of,
label_strs::type_of,
];

/// Trait definition `DepNode`s.
const BASE_TRAIT_DEF: &[&str] = &[
label_strs::AssociatedItemDefIds,
label_strs::GenericsOfItem,
label_strs::generics_of,
label_strs::ObjectSafety,
label_strs::PredicatesOfItem,
label_strs::predicates_of,
label_strs::SpecializationGraph,
label_strs::TraitDefOfItem,
label_strs::TraitImpls,
@@ -179,7 +179,7 @@ const LABELS_TRAIT: &[&[&str]] = &[
// Fields are kind of separate from their containers, as they can change independently from
// them. We should at least check
//
// TypeOfItem for these.
// type_of for these.

type Labels = FxHashSet<String>;

10 changes: 10 additions & 0 deletions src/librustc_macros/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
#![feature(proc_macro_hygiene)]
#![deny(rust_2018_idioms)]

extern crate proc_macro;

use synstructure::decl_derive;

use proc_macro::TokenStream;

mod hash_stable;
mod query;

#[proc_macro]
pub fn rustc_queries(input: TokenStream) -> TokenStream {
query::rustc_queries(input)
}

decl_derive!([HashStable, attributes(stable_hasher)] => hash_stable::hash_stable_derive);
394 changes: 394 additions & 0 deletions src/librustc_macros/src/query.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,394 @@
use proc_macro::TokenStream;
use syn::{
Token, Ident, Type, Attribute, ReturnType, Expr, Block, Error,
braced, parenthesized, parse_macro_input,
};
use syn::spanned::Spanned;
use syn::parse::{Result, Parse, ParseStream};
use syn::punctuated::Punctuated;
use syn;
use quote::quote;

#[allow(non_camel_case_types)]
mod kw {
syn::custom_keyword!(query);
}

/// Ident or a wildcard `_`.
struct IdentOrWild(Ident);

impl Parse for IdentOrWild {
fn parse(input: ParseStream<'_>) -> Result<Self> {
Ok(if input.peek(Token![_]) {
let underscore = input.parse::<Token![_]>()?;
IdentOrWild(Ident::new("_", underscore.span()))
} else {
IdentOrWild(input.parse()?)
})
}
}

/// A modifier for a query
enum QueryModifier {
/// The description of the query.
Desc(Option<Ident>, Punctuated<Expr, Token![,]>),

/// Cache the query to disk if the `Expr` returns true.
Cache(Option<Ident>, Expr),

/// Custom code to load the query from disk.
LoadCached(Ident, Ident, Block),

/// A cycle error for this query aborting the compilation with a fatal error.
FatalCycle,
}

impl Parse for QueryModifier {
fn parse(input: ParseStream<'_>) -> Result<Self> {
let modifier: Ident = input.parse()?;
if modifier == "desc" {
// Parse a description modifier like:
// `desc { |tcx| "foo {}", tcx.item_path(key) }`
let attr_content;
braced!(attr_content in input);
let tcx = if attr_content.peek(Token![|]) {
attr_content.parse::<Token![|]>()?;
let tcx = attr_content.parse()?;
attr_content.parse::<Token![|]>()?;
Some(tcx)
} else {
None
};
let desc = attr_content.parse_terminated(Expr::parse)?;
Ok(QueryModifier::Desc(tcx, desc))
} else if modifier == "cache" {
// Parse a cache modifier like:
// `cache { |tcx| key.is_local() }`
let attr_content;
braced!(attr_content in input);
let tcx = if attr_content.peek(Token![|]) {
attr_content.parse::<Token![|]>()?;
let tcx = attr_content.parse()?;
attr_content.parse::<Token![|]>()?;
Some(tcx)
} else {
None
};
let expr = attr_content.parse()?;
Ok(QueryModifier::Cache(tcx, expr))
} else if modifier == "load_cached" {
// Parse a load_cached modifier like:
// `load_cached(tcx, id) { tcx.queries.on_disk_cache.try_load_query_result(tcx, id) }`
let args;
parenthesized!(args in input);
let tcx = args.parse()?;
args.parse::<Token![,]>()?;
let id = args.parse()?;
let block = input.parse()?;
Ok(QueryModifier::LoadCached(tcx, id, block))
} else if modifier == "fatal_cycle" {
Ok(QueryModifier::FatalCycle)
} else {
Err(Error::new(modifier.span(), "unknown query modifier"))
}
}
}

/// Ensures only doc comment attributes are used
fn check_attributes(attrs: Vec<Attribute>) -> Result<()> {
for attr in attrs {
if !attr.path.is_ident("doc") {
return Err(Error::new(attr.span(), "attributes not supported on queries"));
}
}
Ok(())
}

/// A compiler query. `query ... { ... }`
struct Query {
modifiers: List<QueryModifier>,
name: Ident,
key: IdentOrWild,
arg: Type,
result: ReturnType,
}

impl Parse for Query {
fn parse(input: ParseStream<'_>) -> Result<Self> {
check_attributes(input.call(Attribute::parse_outer)?)?;

// Parse the query declaration. Like `query type_of(key: DefId) -> Ty<'tcx>`
input.parse::<kw::query>()?;
let name: Ident = input.parse()?;
let arg_content;
parenthesized!(arg_content in input);
let key = arg_content.parse()?;
arg_content.parse::<Token![:]>()?;
let arg = arg_content.parse()?;
let result = input.parse()?;

// Parse the query modifiers
let content;
braced!(content in input);
let modifiers = content.parse()?;

Ok(Query {
modifiers,
name,
key,
arg,
result,
})
}
}

/// A type used to greedily parse another type until the input is empty.
struct List<T>(Vec<T>);

impl<T: Parse> Parse for List<T> {
fn parse(input: ParseStream<'_>) -> Result<Self> {
let mut list = Vec::new();
while !input.is_empty() {
list.push(input.parse()?);
}
Ok(List(list))
}
}

/// A named group containing queries.
struct Group {
name: Ident,
queries: List<Query>,
}

impl Parse for Group {
fn parse(input: ParseStream<'_>) -> Result<Self> {
let name: Ident = input.parse()?;
let content;
braced!(content in input);
Ok(Group {
name,
queries: content.parse()?,
})
}
}

struct QueryModifiers {
/// The description of the query.
desc: Option<(Option<Ident>, Punctuated<Expr, Token![,]>)>,

/// Cache the query to disk if the `Expr` returns true.
cache: Option<(Option<Ident>, Expr)>,

/// Custom code to load the query from disk.
load_cached: Option<(Ident, Ident, Block)>,

/// A cycle error for this query aborting the compilation with a fatal error.
fatal_cycle: bool,
}

/// Process query modifiers into a struct, erroring on duplicates
fn process_modifiers(query: &mut Query) -> QueryModifiers {
let mut load_cached = None;
let mut cache = None;
let mut desc = None;
let mut fatal_cycle = false;
for modifier in query.modifiers.0.drain(..) {
match modifier {
QueryModifier::LoadCached(tcx, id, block) => {
if load_cached.is_some() {
panic!("duplicate modifier `load_cached` for query `{}`", query.name);
}
load_cached = Some((tcx, id, block));
}
QueryModifier::Cache(tcx, expr) => {
if cache.is_some() {
panic!("duplicate modifier `cache` for query `{}`", query.name);
}
cache = Some((tcx, expr));
}
QueryModifier::Desc(tcx, list) => {
if desc.is_some() {
panic!("duplicate modifier `desc` for query `{}`", query.name);
}
desc = Some((tcx, list));
}
QueryModifier::FatalCycle => {
if fatal_cycle {
panic!("duplicate modifier `fatal_cycle` for query `{}`", query.name);
}
fatal_cycle = true;
}
}
}
QueryModifiers {
load_cached,
cache,
desc,
fatal_cycle,
}
}

/// Add the impl of QueryDescription for the query to `impls` if one is requested
fn add_query_description_impl(
query: &Query,
modifiers: QueryModifiers,
impls: &mut proc_macro2::TokenStream
) {
let name = &query.name;
let arg = &query.arg;
let key = &query.key.0;

// Find out if we should cache the query on disk
let cache = modifiers.cache.as_ref().map(|(tcx, expr)| {
let try_load_from_disk = if let Some((tcx, id, block)) = modifiers.load_cached.as_ref() {
// Use custom code to load the query from disk
quote! {
#[inline]
fn try_load_from_disk(
#tcx: TyCtxt<'_, 'tcx, 'tcx>,
#id: SerializedDepNodeIndex
) -> Option<Self::Value> {
#block
}
}
} else {
// Use the default code to load the query from disk
quote! {
#[inline]
fn try_load_from_disk(
tcx: TyCtxt<'_, 'tcx, 'tcx>,
id: SerializedDepNodeIndex
) -> Option<Self::Value> {
tcx.queries.on_disk_cache.try_load_query_result(tcx, id)
}
}
};

let tcx = tcx.as_ref().map(|t| quote! { #t }).unwrap_or(quote! { _ });
quote! {
#[inline]
fn cache_on_disk(#tcx: TyCtxt<'_, 'tcx, 'tcx>, #key: Self::Key) -> bool {
#expr
}

#try_load_from_disk
}
});

if cache.is_none() && modifiers.load_cached.is_some() {
panic!("load_cached modifier on query `{}` without a cache modifier", name);
}

let desc = modifiers.desc.as_ref().map(|(tcx, desc)| {
let tcx = tcx.as_ref().map(|t| quote! { #t }).unwrap_or(quote! { _ });
quote! {
fn describe(
#tcx: TyCtxt<'_, '_, '_>,
#key: #arg,
) -> Cow<'static, str> {
format!(#desc).into()
}
}
});

if desc.is_some() || cache.is_some() {
let cache = cache.unwrap_or(quote! {});
let desc = desc.unwrap_or(quote! {});

impls.extend(quote! {
impl<'tcx> QueryDescription<'tcx> for queries::#name<'tcx> {
#desc
#cache
}
});
}
}

pub fn rustc_queries(input: TokenStream) -> TokenStream {
let groups = parse_macro_input!(input as List<Group>);

let mut query_stream = quote! {};
let mut query_description_stream = quote! {};
let mut dep_node_def_stream = quote! {};
let mut dep_node_force_stream = quote! {};

for group in groups.0 {
let mut group_stream = quote! {};
for mut query in group.queries.0 {
let modifiers = process_modifiers(&mut query);
let name = &query.name;
let arg = &query.arg;
let result_full = &query.result;
let result = match query.result {
ReturnType::Default => quote! { -> () },
_ => quote! { #result_full },
};

// Pass on the fatal_cycle modifier
let fatal_cycle = if modifiers.fatal_cycle {
quote! { fatal_cycle }
} else {
quote! {}
};

// Add the query to the group
group_stream.extend(quote! {
[#fatal_cycle] fn #name: #name(#arg) #result,
});

add_query_description_impl(&query, modifiers, &mut query_description_stream);

// Create a dep node for the query
dep_node_def_stream.extend(quote! {
[] #name(#arg),
});

// Add a match arm to force the query given the dep node
dep_node_force_stream.extend(quote! {
DepKind::#name => {
if let Some(key) = RecoverKey::recover($tcx, $dep_node) {
force_ex!($tcx, #name, key);
} else {
return false;
}
}
});
}
let name = &group.name;
query_stream.extend(quote! {
#name { #group_stream },
});
}
TokenStream::from(quote! {
macro_rules! rustc_query_append {
([$($macro:tt)*][$($other:tt)*]) => {
$($macro)* {
$($other)*

#query_stream

}
}
}
macro_rules! rustc_dep_node_append {
([$($macro:tt)*][$($other:tt)*]) => {
$($macro)*(
$($other)*

#dep_node_def_stream
);
}
}
macro_rules! rustc_dep_node_force {
([$dep_node:expr, $tcx:expr] $($other:tt)*) => {
match $dep_node.kind {
$($other)*

#dep_node_force_stream
}
}
}
#query_description_stream
})
}
8 changes: 4 additions & 4 deletions src/test/incremental/hashes/consts.rs
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@ pub const CONST_VISIBILITY: u8 = 0;
const CONST_CHANGE_TYPE_1: i32 = 0;

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")]
#[rustc_clean(cfg="cfail3")]
const CONST_CHANGE_TYPE_1: u32 = 0;

@@ -39,7 +39,7 @@ const CONST_CHANGE_TYPE_1: u32 = 0;
const CONST_CHANGE_TYPE_2: Option<u32> = None;

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")]
#[rustc_clean(cfg="cfail3")]
const CONST_CHANGE_TYPE_2: Option<u64> = None;

@@ -99,11 +99,11 @@ mod const_change_type_indirectly {
#[cfg(not(cfail1))]
use super::ReferencedType2 as Type;

#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")]
#[rustc_clean(cfg="cfail3")]
const CONST_CHANGE_TYPE_INDIRECTLY_1: Type = Type;

#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")]
#[rustc_clean(cfg="cfail3")]
const CONST_CHANGE_TYPE_INDIRECTLY_2: Option<Type> = None;
}
46 changes: 23 additions & 23 deletions src/test/incremental/hashes/enum_defs.rs
Original file line number Diff line number Diff line change
@@ -42,7 +42,7 @@ enum EnumChangeNameCStyleVariant {
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumChangeNameCStyleVariant {
Variant1,
@@ -59,7 +59,7 @@ enum EnumChangeNameTupleStyleVariant {
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumChangeNameTupleStyleVariant {
Variant1,
@@ -76,7 +76,7 @@ enum EnumChangeNameStructStyleVariant {
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumChangeNameStructStyleVariant {
Variant1,
@@ -109,7 +109,7 @@ enum EnumChangeValueCStyleVariant1 {
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumChangeValueCStyleVariant1 {
Variant1,
@@ -125,7 +125,7 @@ enum EnumAddCStyleVariant {
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumAddCStyleVariant {
Variant1,
@@ -142,7 +142,7 @@ enum EnumRemoveCStyleVariant {
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumRemoveCStyleVariant {
Variant1,
@@ -157,7 +157,7 @@ enum EnumAddTupleStyleVariant {
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumAddTupleStyleVariant {
Variant1,
@@ -174,7 +174,7 @@ enum EnumRemoveTupleStyleVariant {
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumRemoveTupleStyleVariant {
Variant1,
@@ -189,7 +189,7 @@ enum EnumAddStructStyleVariant {
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumAddStructStyleVariant {
Variant1,
@@ -206,7 +206,7 @@ enum EnumRemoveStructStyleVariant {
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumRemoveStructStyleVariant {
Variant1,
@@ -257,7 +257,7 @@ enum EnumChangeFieldNameStructStyleVariant {
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumChangeFieldNameStructStyleVariant {
Variant1 { a: u32, c: u32 },
@@ -289,7 +289,7 @@ enum EnumChangeFieldOrderStructStyleVariant {
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumChangeFieldOrderStructStyleVariant {
Variant1 { b: f32, a: u32 },
@@ -304,7 +304,7 @@ enum EnumAddFieldTupleStyleVariant {
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumAddFieldTupleStyleVariant {
Variant1(u32, u32, u32),
@@ -319,7 +319,7 @@ enum EnumAddFieldStructStyleVariant {
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumAddFieldStructStyleVariant {
Variant1 { a: u32, b: u32, c: u32 },
@@ -353,7 +353,7 @@ enum EnumAddReprC {
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")]
#[rustc_clean(cfg="cfail3")]
#[repr(C)]
enum EnumAddReprC {
@@ -402,7 +402,7 @@ enum EnumChangeNameOfLifetimeParameter<'a> {
}

#[cfg(not(cfail1))]
#[rustc_dirty(cfg="cfail2", except="PredicatesOfItem")]
#[rustc_dirty(cfg="cfail2", except="predicates_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumChangeNameOfLifetimeParameter<'b> {
Variant1(&'b u32),
@@ -418,7 +418,7 @@ enum EnumAddLifetimeParameter<'a> {
}

#[cfg(not(cfail1))]
#[rustc_dirty(cfg="cfail2", except="PredicatesOfItem")]
#[rustc_dirty(cfg="cfail2", except="predicates_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumAddLifetimeParameter<'a, 'b> {
Variant1(&'a u32),
@@ -435,7 +435,7 @@ enum EnumAddLifetimeParameterBound<'a, 'b> {
}

#[cfg(not(cfail1))]
#[rustc_dirty(cfg="cfail2", except="GenericsOfItem,TypeOfItem")]
#[rustc_dirty(cfg="cfail2", except="generics_of,type_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumAddLifetimeParameterBound<'a, 'b: 'a> {
Variant1(&'a u32),
@@ -450,7 +450,7 @@ enum EnumAddLifetimeBoundToParameter<'a, T> {
}

#[cfg(not(cfail1))]
#[rustc_dirty(cfg="cfail2", except="TypeOfItem")]
#[rustc_dirty(cfg="cfail2", except="type_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumAddLifetimeBoundToParameter<'a, T: 'a> {
Variant1(T),
@@ -482,7 +482,7 @@ enum EnumAddLifetimeParameterBoundWhere<'a, 'b> {
}

#[cfg(not(cfail1))]
#[rustc_dirty(cfg="cfail2", except="GenericsOfItem,TypeOfItem")]
#[rustc_dirty(cfg="cfail2", except="generics_of,type_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumAddLifetimeParameterBoundWhere<'a, 'b> where 'b: 'a {
Variant1(&'a u32),
@@ -499,7 +499,7 @@ enum EnumAddLifetimeBoundToParameterWhere<'a, T> {
}

#[cfg(not(cfail1))]
#[rustc_dirty(cfg="cfail2", except="TypeOfItem")]
#[rustc_dirty(cfg="cfail2", except="type_of")]
#[rustc_clean(cfg="cfail3")]
enum EnumAddLifetimeBoundToParameterWhere<'a, T> where T: 'a {
Variant1(T),
@@ -618,7 +618,7 @@ mod change_trait_bound_indirectly {
#[cfg(not(cfail1))]
use super::ReferencedTrait2 as Trait;

#[rustc_clean(cfg="cfail2", except="Hir,HirBody,PredicatesOfItem")]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,predicates_of")]
#[rustc_clean(cfg="cfail3")]
enum Enum<T: Trait> {
Variant1(T)
@@ -634,7 +634,7 @@ mod change_trait_bound_indirectly_where {
#[cfg(not(cfail1))]
use super::ReferencedTrait2 as Trait;

#[rustc_clean(cfg="cfail2", except="Hir,HirBody,PredicatesOfItem")]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,predicates_of")]
#[rustc_clean(cfg="cfail3")]
enum Enum<T> where T: Trait {
Variant1(T)
20 changes: 10 additions & 10 deletions src/test/incremental/hashes/function_interfaces.rs
Original file line number Diff line number Diff line change
@@ -117,7 +117,7 @@ pub fn type_parameter() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2",
except = "Hir, HirBody, GenericsOfItem, TypeOfItem, PredicatesOfItem")]
except = "Hir, HirBody, generics_of, type_of, predicates_of")]
#[rustc_clean(cfg = "cfail3")]
pub fn type_parameter<T>() {}

@@ -128,7 +128,7 @@ pub fn type_parameter<T>() {}
pub fn lifetime_parameter() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, GenericsOfItem")]
#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, generics_of")]
#[rustc_clean(cfg = "cfail3")]
pub fn lifetime_parameter<'a>() {}

@@ -139,7 +139,7 @@ pub fn lifetime_parameter<'a>() {}
pub fn trait_bound<T>() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, PredicatesOfItem")]
#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, predicates_of")]
#[rustc_clean(cfg = "cfail3")]
pub fn trait_bound<T: Eq>() {}

@@ -150,7 +150,7 @@ pub fn trait_bound<T: Eq>() {}
pub fn builtin_bound<T>() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, PredicatesOfItem")]
#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, predicates_of")]
#[rustc_clean(cfg = "cfail3")]
pub fn builtin_bound<T: Send>() {}

@@ -162,7 +162,7 @@ pub fn lifetime_bound<'a, T>() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2",
except = "Hir, HirBody, GenericsOfItem, TypeOfItem, PredicatesOfItem")]
except = "Hir, HirBody, generics_of, type_of, predicates_of")]
#[rustc_clean(cfg = "cfail3")]
pub fn lifetime_bound<'a, T: 'a>() {}

@@ -173,7 +173,7 @@ pub fn lifetime_bound<'a, T: 'a>() {}
pub fn second_trait_bound<T: Eq>() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, PredicatesOfItem")]
#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, predicates_of")]
#[rustc_clean(cfg = "cfail3")]
pub fn second_trait_bound<T: Eq + Clone>() {}

@@ -184,7 +184,7 @@ pub fn second_trait_bound<T: Eq + Clone>() {}
pub fn second_builtin_bound<T: Send>() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, PredicatesOfItem")]
#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, predicates_of")]
#[rustc_clean(cfg = "cfail3")]
pub fn second_builtin_bound<T: Send + Sized>() {}

@@ -196,7 +196,7 @@ pub fn second_lifetime_bound<'a, 'b, T: 'a>() {}

#[cfg(not(cfail1))]
#[rustc_clean(cfg = "cfail2",
except = "Hir, HirBody, GenericsOfItem, TypeOfItem, PredicatesOfItem")]
except = "Hir, HirBody, generics_of, type_of, predicates_of")]
#[rustc_clean(cfg = "cfail3")]
pub fn second_lifetime_bound<'a, 'b, T: 'a + 'b>() {}

@@ -326,7 +326,7 @@ pub mod change_trait_bound_indirectly {
#[cfg(not(cfail1))]
use super::ReferencedTrait2 as Trait;

#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, PredicatesOfItem")]
#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, predicates_of")]
#[rustc_clean(cfg = "cfail3")]
pub fn indirect_trait_bound<T: Trait>(p: T) {}
}
@@ -340,7 +340,7 @@ pub mod change_trait_bound_indirectly_in_where_clause {
#[cfg(not(cfail1))]
use super::ReferencedTrait2 as Trait;

#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, PredicatesOfItem")]
#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, predicates_of")]
#[rustc_clean(cfg = "cfail3")]
pub fn indirect_trait_bound_where<T>(p: T)
where
16 changes: 8 additions & 8 deletions src/test/incremental/hashes/inherent_impls.rs
Original file line number Diff line number Diff line change
@@ -97,7 +97,7 @@ impl Foo {
#[rustc_clean(cfg="cfail2", except="Hir,HirBody")]
#[rustc_clean(cfg="cfail3")]
impl Foo {
#[rustc_dirty(cfg="cfail2", except="TypeOfItem,PredicatesOfItem")]
#[rustc_dirty(cfg="cfail2", except="type_of,predicates_of")]
#[rustc_clean(cfg="cfail3")]
pub fn method_selfness(&self) { }
}
@@ -334,7 +334,7 @@ impl Foo {
// appear dirty, that might be the cause. -nmatsakis
#[rustc_clean(
cfg="cfail2",
except="Hir,HirBody,GenericsOfItem,PredicatesOfItem,TypeOfItem",
except="Hir,HirBody,generics_of,predicates_of,type_of",
)]
#[rustc_clean(cfg="cfail3")]
pub fn add_type_parameter_to_method<T>(&self) { }
@@ -354,7 +354,7 @@ impl Foo {
impl Foo {
#[rustc_clean(
cfg="cfail2",
except="Hir,HirBody,GenericsOfItem,PredicatesOfItem,TypeOfItem,TypeckTables"
except="Hir,HirBody,generics_of,predicates_of,type_of,TypeckTables"
)]
#[rustc_clean(cfg="cfail3")]
pub fn add_lifetime_bound_to_lifetime_param_of_method<'a, 'b: 'a>(&self) { }
@@ -381,8 +381,8 @@ impl Foo {
// generics before the body, then the `HirId` for things in the
// body will be affected. So if you start to see `TypeckTables`
// appear dirty, that might be the cause. -nmatsakis
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,GenericsOfItem,PredicatesOfItem,\
TypeOfItem")]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,generics_of,predicates_of,\
type_of")]
#[rustc_clean(cfg="cfail3")]
pub fn add_lifetime_bound_to_type_param_of_method<'a, T: 'a>(&self) { }
}
@@ -408,7 +408,7 @@ impl Foo {
// generics before the body, then the `HirId` for things in the
// body will be affected. So if you start to see `TypeckTables`
// appear dirty, that might be the cause. -nmatsakis
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,PredicatesOfItem")]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,predicates_of")]
#[rustc_clean(cfg="cfail3")]
pub fn add_trait_bound_to_type_param_of_method<T: Clone>(&self) { }
}
@@ -442,12 +442,12 @@ impl Bar<u32> {
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,GenericsOfItem")]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,generics_of")]
#[rustc_clean(cfg="cfail3")]
impl<T> Bar<T> {
#[rustc_clean(
cfg="cfail2",
except="GenericsOfItem,FnSignature,TypeckTables,TypeOfItem,MirOptimized,MirBuilt"
except="generics_of,FnSignature,TypeckTables,type_of,MirOptimized,MirBuilt"
)]
#[rustc_clean(cfg="cfail3")]
pub fn add_type_parameter_to_impl(&self) { }
8 changes: 4 additions & 4 deletions src/test/incremental/hashes/statics.rs
Original file line number Diff line number Diff line change
@@ -74,7 +74,7 @@ static STATIC_THREAD_LOCAL: u8 = 0;
static STATIC_CHANGE_TYPE_1: i16 = 0;

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")]
#[rustc_clean(cfg="cfail3")]
static STATIC_CHANGE_TYPE_1: u64 = 0;

@@ -84,7 +84,7 @@ static STATIC_CHANGE_TYPE_1: u64 = 0;
static STATIC_CHANGE_TYPE_2: Option<i8> = None;

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")]
#[rustc_clean(cfg="cfail3")]
static STATIC_CHANGE_TYPE_2: Option<u16> = None;

@@ -144,11 +144,11 @@ mod static_change_type_indirectly {
#[cfg(not(cfail1))]
use super::ReferencedType2 as Type;

#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")]
#[rustc_clean(cfg="cfail3")]
static STATIC_CHANGE_TYPE_INDIRECTLY_1: Type = Type;

#[rustc_clean(cfg="cfail2", except="Hir,HirBody,TypeOfItem")]
#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")]
#[rustc_clean(cfg="cfail3")]
static STATIC_CHANGE_TYPE_INDIRECTLY_2: Option<Type> = None;
}
252 changes: 126 additions & 126 deletions src/test/incremental/hashes/struct_defs.rs

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions src/test/ui/dep-graph/dep-graph-struct-signature.rs
Original file line number Diff line number Diff line change
@@ -24,7 +24,7 @@ struct WontChange {
mod signatures {
use WillChange;

#[rustc_then_this_would_need(TypeOfItem)] //~ ERROR no path
#[rustc_then_this_would_need(type_of)] //~ ERROR no path
#[rustc_then_this_would_need(AssociatedItems)] //~ ERROR no path
#[rustc_then_this_would_need(TraitDefOfItem)] //~ ERROR no path
trait Bar {
@@ -42,36 +42,36 @@ mod signatures {
WillChange { x: x, y: y }
}

#[rustc_then_this_would_need(TypeOfItem)] //~ ERROR OK
#[rustc_then_this_would_need(type_of)] //~ ERROR OK
impl WillChange {
#[rustc_then_this_would_need(FnSignature)] //~ ERROR OK
#[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK
fn new(x: u32, y: u32) -> WillChange { loop { } }
}

#[rustc_then_this_would_need(TypeOfItem)] //~ ERROR OK
#[rustc_then_this_would_need(type_of)] //~ ERROR OK
impl WillChange {
#[rustc_then_this_would_need(FnSignature)] //~ ERROR OK
#[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK
fn method(&self, x: u32) { }
}

struct WillChanges {
#[rustc_then_this_would_need(TypeOfItem)] //~ ERROR OK
#[rustc_then_this_would_need(type_of)] //~ ERROR OK
x: WillChange,
#[rustc_then_this_would_need(TypeOfItem)] //~ ERROR OK
#[rustc_then_this_would_need(type_of)] //~ ERROR OK
y: WillChange
}

// The fields change, not the type itself.
#[rustc_then_this_would_need(TypeOfItem)] //~ ERROR no path
#[rustc_then_this_would_need(type_of)] //~ ERROR no path
fn indirect(x: WillChanges) { }
}

mod invalid_signatures {
use WontChange;

#[rustc_then_this_would_need(TypeOfItem)] //~ ERROR no path
#[rustc_then_this_would_need(type_of)] //~ ERROR no path
trait A {
#[rustc_then_this_would_need(FnSignature)] //~ ERROR no path
fn do_something_else_twice(x: WontChange);
34 changes: 17 additions & 17 deletions src/test/ui/dep-graph/dep-graph-struct-signature.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error: no path from `WillChange` to `TypeOfItem`
error: no path from `WillChange` to `type_of`
--> $DIR/dep-graph-struct-signature.rs:27:5
|
LL | #[rustc_then_this_would_need(TypeOfItem)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: no path from `WillChange` to `AssociatedItems`
--> $DIR/dep-graph-struct-signature.rs:28:5
@@ -43,38 +43,38 @@ LL | #[rustc_then_this_would_need(TypeckTables)]
error: OK
--> $DIR/dep-graph-struct-signature.rs:45:5
|
LL | #[rustc_then_this_would_need(TypeOfItem)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: OK
--> $DIR/dep-graph-struct-signature.rs:52:5
|
LL | #[rustc_then_this_would_need(TypeOfItem)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: OK
--> $DIR/dep-graph-struct-signature.rs:60:9
|
LL | #[rustc_then_this_would_need(TypeOfItem)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: OK
--> $DIR/dep-graph-struct-signature.rs:62:9
|
LL | #[rustc_then_this_would_need(TypeOfItem)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: no path from `WillChange` to `TypeOfItem`
error: no path from `WillChange` to `type_of`
--> $DIR/dep-graph-struct-signature.rs:67:5
|
LL | #[rustc_then_this_would_need(TypeOfItem)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: no path from `WillChange` to `TypeOfItem`
error: no path from `WillChange` to `type_of`
--> $DIR/dep-graph-struct-signature.rs:74:5
|
LL | #[rustc_then_this_would_need(TypeOfItem)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: no path from `WillChange` to `FnSignature`
--> $DIR/dep-graph-struct-signature.rs:80:5
14 changes: 7 additions & 7 deletions src/test/ui/dep-graph/dep-graph-type-alias.rs
Original file line number Diff line number Diff line change
@@ -14,38 +14,38 @@ type TypeAlias = u32;

// The type alias directly affects the type of the field,
// not the enclosing struct:
#[rustc_then_this_would_need(TypeOfItem)] //~ ERROR no path
#[rustc_then_this_would_need(type_of)] //~ ERROR no path
struct Struct {
#[rustc_then_this_would_need(TypeOfItem)] //~ ERROR OK
#[rustc_then_this_would_need(type_of)] //~ ERROR OK
x: TypeAlias,
y: u32
}

#[rustc_then_this_would_need(TypeOfItem)] //~ ERROR no path
#[rustc_then_this_would_need(type_of)] //~ ERROR no path
enum Enum {
Variant1 {
#[rustc_then_this_would_need(TypeOfItem)] //~ ERROR OK
#[rustc_then_this_would_need(type_of)] //~ ERROR OK
t: TypeAlias
},
Variant2(i32)
}

#[rustc_then_this_would_need(TypeOfItem)] //~ ERROR no path
#[rustc_then_this_would_need(type_of)] //~ ERROR no path
trait Trait {
#[rustc_then_this_would_need(FnSignature)] //~ ERROR OK
fn method(&self, _: TypeAlias);
}

struct SomeType;

#[rustc_then_this_would_need(TypeOfItem)] //~ ERROR no path
#[rustc_then_this_would_need(type_of)] //~ ERROR no path
impl SomeType {
#[rustc_then_this_would_need(FnSignature)] //~ ERROR OK
#[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK
fn method(&self, _: TypeAlias) {}
}

#[rustc_then_this_would_need(TypeOfItem)] //~ ERROR OK
#[rustc_then_this_would_need(type_of)] //~ ERROR OK
type TypeAlias2 = TypeAlias;

#[rustc_then_this_would_need(FnSignature)] //~ ERROR OK
36 changes: 18 additions & 18 deletions src/test/ui/dep-graph/dep-graph-type-alias.stderr
Original file line number Diff line number Diff line change
@@ -1,44 +1,44 @@
error: no path from `TypeAlias` to `TypeOfItem`
error: no path from `TypeAlias` to `type_of`
--> $DIR/dep-graph-type-alias.rs:17:1
|
LL | #[rustc_then_this_would_need(TypeOfItem)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: OK
--> $DIR/dep-graph-type-alias.rs:19:5
|
LL | #[rustc_then_this_would_need(TypeOfItem)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: no path from `TypeAlias` to `TypeOfItem`
error: no path from `TypeAlias` to `type_of`
--> $DIR/dep-graph-type-alias.rs:24:1
|
LL | #[rustc_then_this_would_need(TypeOfItem)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: OK
--> $DIR/dep-graph-type-alias.rs:27:9
|
LL | #[rustc_then_this_would_need(TypeOfItem)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: no path from `TypeAlias` to `TypeOfItem`
error: no path from `TypeAlias` to `type_of`
--> $DIR/dep-graph-type-alias.rs:33:1
|
LL | #[rustc_then_this_would_need(TypeOfItem)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: no path from `TypeAlias` to `TypeOfItem`
error: no path from `TypeAlias` to `type_of`
--> $DIR/dep-graph-type-alias.rs:41:1
|
LL | #[rustc_then_this_would_need(TypeOfItem)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: OK
--> $DIR/dep-graph-type-alias.rs:48:1
|
LL | #[rustc_then_this_would_need(TypeOfItem)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: OK
--> $DIR/dep-graph-type-alias.rs:51:1