Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit a8ebfb5

Browse files
authoredOct 1, 2019
Rollup merge of rust-lang#64648 - alexreg:rush-parsing, r=Mark-Simulacrum
REPL, part 1: Added interpreter mode to compiler interface, interpreter parsing functionality Summary: * Adds "interpreter mode" to compiler interface. This will be used later in several places, including diagnostics. * Adds "interpreter tag" to `ast::Local`s to track info like whether they came from a previous eval session or have been moved. * Added interface for injecting a pre-parsed "user body" into the parsing pipeline. cf. `TyCtxt::get_interp_user_fn`, `expr.rs` * Moved `Steal` data structure to `rustc_data_structures` crate since a) it was already used outside of `rustc::ty` crate, b) it's now used even a little more outside there. * Made a few more things `pub` (as little as possible), so the interpreter can use them. If you want the big picture of where this is going in terms of compiler changes (probably 2/3 more PRs needed), take a look at my [personal branch](https://github.com/alexreg/rust/tree/rush). I will also be publishing the REPL repo itself soon. Also, sorry for the lack of commits; I basically just carved this out of an even bigger squashed commit after much, much hacking! (It might be a tad heavy on cosmetic stuff too, for the same reason. If it's okay, then great, otherwise I can try to revert certain areas that people really don't want.) Maybe @Centril / @Zoxc for review? Not wholly sure. CC @nikomatsakis @mw @eddyb
2 parents 7607459 + 7062164 commit a8ebfb5

File tree

31 files changed

+335
-114
lines changed

31 files changed

+335
-114
lines changed
 

‎src/librustc/arena.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ macro_rules! arena_types {
2323
[] generics: rustc::ty::Generics,
2424
[] trait_def: rustc::ty::TraitDef,
2525
[] adt_def: rustc::ty::AdtDef,
26-
[] steal_mir: rustc::ty::steal::Steal<rustc::mir::Body<$tcx>>,
26+
[] steal_mir: rustc_data_structures::steal::Steal<rustc::mir::Body<$tcx>>,
2727
[] mir: rustc::mir::Body<$tcx>,
28-
[] steal_promoted: rustc::ty::steal::Steal<
28+
[] steal_promoted: rustc_data_structures::steal::Steal<
2929
rustc_index::vec::IndexVec<
3030
rustc::mir::Promoted,
3131
rustc::mir::Body<$tcx>

‎src/librustc/hir/lowering.rs

+2
Original file line numberDiff line numberDiff line change
@@ -2079,6 +2079,7 @@ impl<'a> LoweringContext<'a> {
20792079
span: l.span,
20802080
attrs: l.attrs.clone(),
20812081
source: hir::LocalSource::Normal,
2082+
interp_tag: l.interp_tag.clone(),
20822083
}, ids)
20832084
}
20842085

@@ -3048,6 +3049,7 @@ impl<'a> LoweringContext<'a> {
30483049
source,
30493050
span,
30503051
ty: None,
3052+
interp_tag: None,
30513053
};
30523054
self.stmt(span, hir::StmtKind::Local(P(local)))
30533055
}

‎src/librustc/hir/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1273,6 +1273,8 @@ pub struct Local {
12731273
/// Can be `ForLoopDesugar` if the `let` statement is part of a `for` loop
12741274
/// desugaring. Otherwise will be `Normal`.
12751275
pub source: LocalSource,
1276+
/// See comment on `syntax::ast::Local`.
1277+
pub interp_tag: Option<ast::LocalInterpTag>,
12761278
}
12771279

12781280
/// Represents a single arm of a `match` expression, e.g.

‎src/librustc/ich/impls_hir.rs

+11
Original file line numberDiff line numberDiff line change
@@ -392,3 +392,14 @@ impl<'hir> HashStable<StableHashingContext<'hir>> for attr::OptimizeAttr {
392392
mem::discriminant(self).hash_stable(hcx, hasher);
393393
}
394394
}
395+
396+
impl_stable_hash_for!(enum ast::LocalInterpState {
397+
Uninitialized,
398+
Set,
399+
Moved,
400+
});
401+
402+
impl_stable_hash_for!(struct ast::LocalInterpTag {
403+
id,
404+
state,
405+
});

‎src/librustc/ich/impls_ty.rs

+5-13
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
//! This module contains `HashStable` implementations for various data types
2-
//! from rustc::ty in no particular order.
2+
//! from `rustc::ty` in no particular order.
33
44
use crate::ich::{Fingerprint, StableHashingContext, NodeIdHashingMode};
5+
use crate::middle::region;
6+
use crate::mir;
7+
use crate::ty;
8+
59
use rustc_data_structures::fx::FxHashMap;
610
use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey, StableHasher};
711
use std::cell::RefCell;
812
use std::mem;
9-
use crate::middle::region;
10-
use crate::ty;
11-
use crate::mir;
1213

1314
impl<'a, 'tcx, T> HashStable<StableHashingContext<'a>> for &'tcx ty::List<T>
1415
where
@@ -197,15 +198,6 @@ impl<'a> HashStable<StableHashingContext<'a>> for ty::FloatVid {
197198
}
198199
}
199200

200-
impl<'a, T> HashStable<StableHashingContext<'a>> for ty::steal::Steal<T>
201-
where
202-
T: HashStable<StableHashingContext<'a>>,
203-
{
204-
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
205-
self.borrow().hash_stable(hcx, hasher);
206-
}
207-
}
208-
209201
impl<'a> HashStable<StableHashingContext<'a>>
210202
for crate::middle::privacy::AccessLevels {
211203
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {

‎src/librustc/query/mod.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -1120,8 +1120,7 @@ rustc_queries! {
11201120
}
11211121

11221122
// Get an estimate of the size of an InstanceDef based on its MIR for CGU partitioning.
1123-
query instance_def_size_estimate(def: ty::InstanceDef<'tcx>)
1124-
-> usize {
1123+
query instance_def_size_estimate(def: ty::InstanceDef<'tcx>) -> usize {
11251124
no_force
11261125
desc { |tcx| "estimating size for `{}`", tcx.def_path_str(def.def_id()) }
11271126
}
@@ -1130,5 +1129,10 @@ rustc_queries! {
11301129
eval_always
11311130
desc { "looking up enabled feature gates" }
11321131
}
1132+
1133+
query interp_user_fn(_: CrateNum) -> DefId {
1134+
eval_always
1135+
desc { "locating interpreter user fn in HIR" }
1136+
}
11331137
}
11341138
}

‎src/librustc/session/config.rs

+3
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,7 @@ top_level_options!(
391391
// can influence whether overflow checks are done or not.
392392
debug_assertions: bool [TRACKED],
393393
debuginfo: DebugInfo [TRACKED],
394+
interp_mode: bool [TRACKED],
394395
lint_opts: Vec<(String, lint::Level)> [TRACKED],
395396
lint_cap: Option<lint::Level> [TRACKED],
396397
describe_lints: bool [UNTRACKED],
@@ -599,6 +600,7 @@ impl Default for Options {
599600
crate_types: Vec::new(),
600601
optimize: OptLevel::No,
601602
debuginfo: DebugInfo::None,
603+
interp_mode: false,
602604
lint_opts: Vec::new(),
603605
lint_cap: None,
604606
describe_lints: false,
@@ -2467,6 +2469,7 @@ pub fn build_session_options_and_crate_config(
24672469
crate_types,
24682470
optimize: opt_level,
24692471
debuginfo,
2472+
interp_mode: false,
24702473
lint_opts,
24712474
lint_cap,
24722475
describe_lints,

‎src/librustc/ty/context.rs

+44-2
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ use crate::ty::{InferConst, ParamConst};
3838
use crate::ty::GenericParamDefKind;
3939
use crate::ty::layout::{LayoutDetails, TargetDataLayout, VariantIdx};
4040
use crate::ty::query;
41-
use crate::ty::steal::Steal;
4241
use crate::ty::subst::{UserSubsts, GenericArgKind};
4342
use crate::ty::{BoundVar, BindingMode};
4443
use crate::ty::CanonicalPolyFnSig;
@@ -49,12 +48,13 @@ use crate::util::nodemap::{FxHashMap, FxHashSet};
4948
use errors::DiagnosticBuilder;
5049
use arena::SyncDroplessArena;
5150
use smallvec::SmallVec;
51+
use rustc_index::vec::{Idx, IndexVec};
5252
use rustc_data_structures::stable_hasher::{
5353
HashStable, StableHasher, StableVec, hash_stable_hashmap,
5454
};
55-
use rustc_index::vec::{Idx, IndexVec};
5655
use rustc_data_structures::sharded::ShardedHashMap;
5756
use rustc_data_structures::sync::{Lrc, Lock, WorkerLocal};
57+
use rustc_data_structures::steal::Steal;
5858
use std::any::Any;
5959
use std::borrow::Borrow;
6060
use std::cmp::Ordering;
@@ -2894,6 +2894,44 @@ fn ptr_eq<T, U>(t: *const T, u: *const U) -> bool {
28942894
t as *const () == u as *const ()
28952895
}
28962896

2897+
/// In interpreter mode, locates the `DefId` of the user fn (a closure marked by an attribute named
2898+
/// `rustc_interp_user_fn`) by visiting the local crate's HIR.
2899+
fn find_interp_user_fn(tcx: TyCtxt<'_>) -> DefId {
2900+
use hir::intravisit::{self, Visitor, NestedVisitorMap};
2901+
2902+
struct InterpUserFnVisitor<'tcx> {
2903+
tcx: TyCtxt<'tcx>,
2904+
def_id: Option<DefId>,
2905+
}
2906+
2907+
impl<'tcx> Visitor<'tcx> for InterpUserFnVisitor<'tcx> {
2908+
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
2909+
NestedVisitorMap::OnlyBodies(&self.tcx.hir())
2910+
}
2911+
2912+
fn visit_expr(&mut self, ex: &'tcx hir::Expr) {
2913+
if syntax::attr::contains_name(&ex.attrs, sym::rustc_interp_user_fn) {
2914+
self.def_id = Some(self.tcx.hir().local_def_id(ex.hir_id));
2915+
return;
2916+
}
2917+
2918+
intravisit::walk_expr(self, ex);
2919+
}
2920+
}
2921+
2922+
let mut visitor = InterpUserFnVisitor {
2923+
tcx,
2924+
def_id: None,
2925+
};
2926+
tcx.hir().krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
2927+
visitor.def_id
2928+
.unwrap_or_else(|| tcx.sess.fatal(&format!(
2929+
"could not find interpreter user fn in HIR; it should be a closure expression \
2930+
marked with the `#[{}]` attribute",
2931+
sym::rustc_interp_user_fn
2932+
)))
2933+
}
2934+
28972935
pub fn provide(providers: &mut ty::query::Providers<'_>) {
28982936
providers.in_scope_traits_map = |tcx, id| tcx.gcx.trait_map.get(&id);
28992937
providers.module_exports = |tcx, id| tcx.gcx.export_map.get(&id).map(|v| &v[..]);
@@ -2971,4 +3009,8 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
29713009
assert_eq!(cnum, LOCAL_CRATE);
29723010
attr::contains_name(tcx.hir().krate_attrs(), sym::compiler_builtins)
29733011
};
3012+
providers.interp_user_fn = |tcx, cnum| {
3013+
assert_eq!(cnum, LOCAL_CRATE);
3014+
find_interp_user_fn(tcx)
3015+
};
29743016
}

‎src/librustc/ty/mod.rs

-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,6 @@ pub mod outlives;
105105
pub mod print;
106106
pub mod query;
107107
pub mod relate;
108-
pub mod steal;
109108
pub mod subst;
110109
pub mod trait_def;
111110
pub mod walk;

‎src/librustc/ty/query/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use crate::traits::query::outlives_bounds::OutlivesBound;
3434
use crate::traits::specialization_graph;
3535
use crate::traits::Clauses;
3636
use crate::ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt, AdtSizedConstraint};
37-
use crate::ty::steal::Steal;
37+
use rustc_data_structures::steal::Steal;
3838
use crate::ty::util::NeedsDrop;
3939
use crate::ty::subst::SubstsRef;
4040
use crate::util::nodemap::{DefIdSet, DefIdMap, ItemLocalSet};

‎src/librustc_data_structures/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ pub use ena::unify;
9494
pub mod vec_linked_list;
9595
pub mod work_queue;
9696
pub mod fingerprint;
97+
pub mod steal;
9798

9899
pub struct OnDrop<F: Fn()>(pub F);
99100

‎src/librustc/ty/steal.rs ‎src/librustc_data_structures/steal.rs

+13-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
use rustc_data_structures::sync::{RwLock, ReadGuard, MappedReadGuard};
1+
use crate::stable_hasher::{StableHasher, HashStable};
2+
use crate::sync::{RwLock, ReadGuard, MappedReadGuard};
23

34
/// The `Steal` struct is intended to used as the value for a query.
4-
/// Specifically, we sometimes have queries (*cough* MIR *cough*)
5+
/// Specifically, we sometimes have queries (in particular, for MIR)
56
/// where we create a large, complex value that we want to iteratively
67
/// update (e.g., optimize). We could clone the value for each
78
/// optimization, but that'd be expensive. And yet we don't just want
@@ -26,21 +27,28 @@ pub struct Steal<T> {
2627

2728
impl<T> Steal<T> {
2829
pub fn new(value: T) -> Self {
29-
Steal {
30+
Self {
3031
value: RwLock::new(Some(value))
3132
}
3233
}
3334

3435
pub fn borrow(&self) -> MappedReadGuard<'_, T> {
3536
ReadGuard::map(self.value.borrow(), |opt| match *opt {
36-
None => bug!("attempted to read from stolen value"),
37+
None => panic!("attempted to read from stolen value"),
3738
Some(ref v) => v
3839
})
3940
}
4041

4142
pub fn steal(&self) -> T {
42-
let value_ref = &mut *self.value.try_write().expect("stealing value which is locked");
43+
let value_ref = &mut *self.value.try_write()
44+
.expect("stealing value that is locked");
4345
let value = value_ref.take();
4446
value.expect("attempt to read from stolen value")
4547
}
4648
}
49+
50+
impl<T: HashStable<CTX>, CTX> HashStable<CTX> for Steal<T> {
51+
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
52+
self.borrow().hash_stable(hcx, hasher);
53+
}
54+
}

‎src/librustc_interface/interface.rs

+28-11
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@ use rustc::session::{DiagnosticOutput, Session};
99
use rustc::util::common::ErrorReported;
1010
use rustc_codegen_utils::codegen_backend::CodegenBackend;
1111
use rustc_data_structures::OnDrop;
12+
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1213
use rustc_data_structures::sync::Lrc;
13-
use rustc_data_structures::fx::{FxHashSet, FxHashMap};
14+
use rustc_data_structures::steal::Steal;
1415
use rustc_metadata::cstore::CStore;
1516
use std::path::PathBuf;
1617
use std::result;
1718
use std::sync::{Arc, Mutex};
1819
use syntax;
20+
use syntax::parse::parser::InterpUserFn;
1921
use syntax::source_map::{FileLoader, SourceMap};
2022
use syntax_pos::edition;
2123

@@ -35,9 +37,19 @@ pub struct Compiler {
3537
pub(crate) queries: Queries,
3638
pub(crate) cstore: Lrc<CStore>,
3739
pub(crate) crate_name: Option<String>,
40+
/// In interpreter mode, the user fn to use when parsing.
41+
pub(crate) interp_user_fn: Option<Steal<InterpUserFn>>,
3842
}
3943

4044
impl Compiler {
45+
pub fn set_interp_user_fn(
46+
&mut self,
47+
interp_user_fn: Option<InterpUserFn>,
48+
) -> &mut Self {
49+
self.interp_user_fn = interp_user_fn.map(|user_fn| Steal::new(user_fn));
50+
self
51+
}
52+
4153
pub fn session(&self) -> &Lrc<Session> {
4254
&self.sess
4355
}
@@ -61,12 +73,12 @@ impl Compiler {
6173
}
6274
}
6375

64-
/// The compiler configuration
76+
/// The compiler configuration.
6577
pub struct Config {
66-
/// Command line options
78+
/// The command-line options.
6779
pub opts: config::Options,
6880

69-
/// cfg! configuration in addition to the default ones
81+
/// `cfg!` configuration in addition to the default ones.
7082
pub crate_cfg: FxHashSet<(String, Option<String>)>,
7183

7284
pub input: Input,
@@ -76,17 +88,14 @@ pub struct Config {
7688
pub file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
7789
pub diagnostic_output: DiagnosticOutput,
7890

79-
/// Set to capture stderr output during compiler execution
91+
/// `Some` to capture stderr output during compiler execution.
8092
pub stderr: Option<Arc<Mutex<Vec<u8>>>>,
8193

8294
pub crate_name: Option<String>,
8395
pub lint_caps: FxHashMap<lint::LintId, lint::Level>,
8496
}
8597

86-
pub fn run_compiler_in_existing_thread_pool<F, R>(config: Config, f: F) -> R
87-
where
88-
F: FnOnce(&Compiler) -> R,
89-
{
98+
pub fn create_compiler(config: Config) -> Compiler {
9099
let (sess, codegen_backend, source_map) = util::create_session(
91100
config.opts,
92101
config.crate_cfg,
@@ -98,7 +107,7 @@ where
98107

99108
let cstore = Lrc::new(CStore::new(codegen_backend.metadata_loader()));
100109

101-
let compiler = Compiler {
110+
Compiler {
102111
sess,
103112
codegen_backend,
104113
source_map,
@@ -109,7 +118,15 @@ where
109118
output_file: config.output_file,
110119
queries: Default::default(),
111120
crate_name: config.crate_name,
112-
};
121+
interp_user_fn: None,
122+
}
123+
}
124+
125+
pub fn run_compiler_in_existing_thread_pool<R>(
126+
config: Config,
127+
f: impl FnOnce(&Compiler) -> R,
128+
) -> R {
129+
let compiler = create_compiler(config);
113130

114131
let _sess_abort_error = OnDrop(|| {
115132
compiler.sess.diagnostic().print_error_count(&util::diagnostics_registry());

‎src/librustc_interface/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ mod proc_macro_decls;
1919
mod profile;
2020

2121
pub use interface::{run_compiler, Config};
22+
pub use passes::BoxedGlobalCtxt;

‎src/librustc_interface/passes.rs

+39-29
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use rustc::lint;
1111
use rustc::middle::{self, reachable, resolve_lifetime, stability};
1212
use rustc::middle::cstore::CrateStore;
1313
use rustc::ty::{self, AllArenas, Resolutions, TyCtxt, GlobalCtxt};
14-
use rustc::ty::steal::Steal;
14+
use rustc_data_structures::steal::Steal;
1515
use rustc::traits;
1616
use rustc::util::common::{time, ErrorReported};
1717
use rustc::session::Session;
@@ -38,6 +38,7 @@ use syntax::early_buffered_lints::BufferedEarlyLint;
3838
use syntax::ext::base::{NamedSyntaxExtension, ExtCtxt};
3939
use syntax::mut_visit::MutVisitor;
4040
use syntax::parse::{self, PResult};
41+
use syntax::parse::parser::InterpUserFn;
4142
use syntax::util::node_count::NodeCounter;
4243
use syntax::symbol::Symbol;
4344
use syntax_pos::FileName;
@@ -56,16 +57,28 @@ use std::path::PathBuf;
5657
use std::cell::RefCell;
5758
use std::rc::Rc;
5859

59-
pub fn parse<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> {
60+
pub fn parse<'a>(
61+
sess: &'a Session,
62+
input: &Input,
63+
interp_user_fn: Option<InterpUserFn>,
64+
) -> PResult<'a, ast::Crate> {
6065
sess.diagnostic()
6166
.set_continue_after_error(sess.opts.debugging_opts.continue_parse_after_error);
6267
sess.profiler(|p| p.start_activity("parsing"));
6368
let krate = time(sess, "parsing", || match *input {
64-
Input::File(ref file) => parse::parse_crate_from_file(file, &sess.parse_sess),
69+
Input::File(ref file) => parse::parse_crate_from_file(
70+
file,
71+
&sess.parse_sess,
72+
),
6573
Input::Str {
6674
ref input,
6775
ref name,
68-
} => parse::parse_crate_from_source_str(name.clone(), input.clone(), &sess.parse_sess),
76+
} => parse::parse_crate_from_source_str(
77+
name.clone(),
78+
input.clone(),
79+
&sess.parse_sess,
80+
interp_user_fn,
81+
),
6982
})?;
7083
sess.profiler(|p| p.end_activity("parsing"));
7184

@@ -112,7 +125,7 @@ declare_box_region_type!(
112125
/// harness if one is to be provided, injection of a dependency on the
113126
/// standard library and prelude, and name resolution.
114127
///
115-
/// Returns `None` if we're aborting after handling -W help.
128+
/// Returns `None` if we're aborting after handling `-W help`.
116129
pub fn configure_and_expand(
117130
sess: Lrc<Session>,
118131
cstore: Lrc<CStore>,
@@ -236,7 +249,7 @@ pub fn register_plugins<'a>(
236249
sess.edition(),
237250
&sess.opts.debugging_opts.allow_features,
238251
);
239-
// these need to be set "early" so that expansion sees `quote` if enabled.
252+
// These need to be set "early" so that expansion sees `quote` if enabled.
240253
sess.init_features(features);
241254

242255
let crate_types = util::collect_crate_types(sess, &krate.attrs);
@@ -354,13 +367,13 @@ fn configure_and_expand_inner<'a>(
354367
&mut krate, &mut resolver, plugin_info.syntax_exts, sess.edition()
355368
);
356369

357-
// Expand all macros
370+
// Expand all macros.
358371
sess.profiler(|p| p.start_activity("macro expansion"));
359372
krate = time(sess, "expansion", || {
360-
// Windows dlls do not have rpaths, so they don't know how to find their
373+
// Windows DLLs do not have rpaths, so they don't know how to find their
361374
// dependencies. It's up to us to tell the system where to find all the
362-
// dependent dlls. Note that this uses cfg!(windows) as opposed to
363-
// targ_cfg because syntax extensions are always loaded for the host
375+
// dependent DLLs. Note that this uses `cfg!(windows)` as opposed to
376+
// `targ_cfg` because syntax extensions are always loaded for the host
364377
// compiler, not for the target.
365378
//
366379
// This is somewhat of an inherently racy operation, however, as
@@ -389,7 +402,7 @@ fn configure_and_expand_inner<'a>(
389402
);
390403
}
391404

392-
// Create the config for macro expansion
405+
// Create the config for macro expansion.
393406
let features = sess.features_untracked();
394407
let cfg = syntax::ext::expand::ExpansionConfig {
395408
features: Some(&features),
@@ -406,7 +419,7 @@ fn configure_and_expand_inner<'a>(
406419
ecx.monotonic_expander().expand_crate(krate)
407420
});
408421

409-
// The rest is error reporting
422+
// The rest is error reporting.
410423

411424
time(sess, "check unused macros", || {
412425
ecx.check_unused_macros();
@@ -447,7 +460,7 @@ fn configure_and_expand_inner<'a>(
447460
});
448461

449462
// If we're actually rustdoc then there's no need to actually compile
450-
// anything, so switch everything to just looping
463+
// anything, so switch everything to just looping.
451464
if sess.opts.actually_rustdoc {
452465
util::ReplaceBodyWithLoop::new(sess).visit_crate(&mut krate);
453466
}
@@ -582,7 +595,7 @@ fn generated_output_paths(
582595
out_filenames.push(p);
583596
},
584597
OutputType::DepInfo if sess.opts.debugging_opts.dep_info_omit_d_target => {
585-
// Don't add the dep-info output when omitting it from dep-info targets
598+
// Don't add the dep-info output when omitting it from dep-info targets.
586599
}
587600
_ => {
588601
out_filenames.push(file);
@@ -640,15 +653,15 @@ fn escape_dep_filename(filename: &FileName) -> String {
640653

641654
fn write_out_deps(compiler: &Compiler, outputs: &OutputFilenames, out_filenames: &[PathBuf]) {
642655
let sess = &compiler.sess;
643-
// Write out dependency rules to the dep-info file if requested
656+
// Write out dependency rules to the dep-info file if requested.
644657
if !sess.opts.output_types.contains_key(&OutputType::DepInfo) {
645658
return;
646659
}
647660
let deps_filename = outputs.path(OutputType::DepInfo);
648661

649662
let result = (|| -> io::Result<()> {
650663
// Build a list of files used to compile the output and
651-
// write Makefile-compatible dependency rules
664+
// write Makefile-compatible dependency rules.
652665
let mut files: Vec<String> = sess.source_map()
653666
.files()
654667
.iter()
@@ -680,7 +693,7 @@ fn write_out_deps(compiler: &Compiler, outputs: &OutputFilenames, out_filenames:
680693

681694
// Emit a fake target for each input file to the compilation. This
682695
// prevents `make` from spitting out an error if a file is later
683-
// deleted. For more info see #28735
696+
// deleted. For more info see #28735.
684697
for path in files {
685698
writeln!(file, "{}:", path)?;
686699
}
@@ -710,7 +723,7 @@ pub fn prepare_outputs(
710723
krate: &ast::Crate,
711724
crate_name: &str
712725
) -> Result<OutputFilenames> {
713-
// FIXME: rustdoc passes &[] instead of &krate.attrs here
726+
// FIXME: rustdoc passes `&[]` instead of `&krate.attrs` here.
714727
let outputs = util::build_output_filenames(
715728
&compiler.input,
716729
&compiler.output_dir,
@@ -731,16 +744,15 @@ pub fn prepare_outputs(
731744
if sess.opts.will_create_output_file() {
732745
if output_contains_path(&output_paths, input_path) {
733746
sess.err(&format!(
734-
"the input file \"{}\" would be overwritten by the generated \
735-
executable",
747+
"the input file \"{}\" would be overwritten by the generated executable",
736748
input_path.display()
737749
));
738750
return Err(ErrorReported);
739751
}
740752
if let Some(dir_path) = output_conflicts_with_dir(&output_paths) {
741753
sess.err(&format!(
742754
"the generated executable for the input file \"{}\" conflicts with the \
743-
existing directory \"{}\"",
755+
existing directory \"{}\"",
744756
input_path.display(),
745757
dir_path.display()
746758
));
@@ -857,14 +869,14 @@ pub fn create_global_ctxt(
857869
hir_map,
858870
query_result_on_disk_cache,
859871
&crate_name,
860-
&outputs
872+
&outputs,
861873
);
862874

863875
global_ctxt = Some(gcx);
864876
let gcx = global_ctxt.as_ref().unwrap();
865877

866878
ty::tls::enter_global(gcx, |tcx| {
867-
// Do some initialization of the DepGraph that can only be done with the
879+
// Do some initialization of the `DepGraph` that can only be done with the
868880
// tcx available.
869881
time(tcx.sess, "dep graph tcx init", || rustc_incremental::dep_graph_tcx_init(tcx));
870882
});
@@ -911,7 +923,7 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> {
911923
});
912924
});
913925

914-
// passes are timed inside typeck
926+
// Passes are timed inside typeck.
915927
typeck::check_crate(tcx)?;
916928

917929
time(sess, "misc checking 2", || {
@@ -925,12 +937,11 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> {
925937
}, {
926938
time(sess, "liveness checking + intrinsic checking", || {
927939
par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| {
928-
// this must run before MIR dump, because
940+
// This must run before MIR dump, because
929941
// "not all control paths return a value" is reported here.
930942
//
931-
// maybe move the check to a MIR pass?
943+
// FIXME: maybe move the check to a MIR pass?
932944
let local_def_id = tcx.hir().local_def_id(module);
933-
934945
tcx.ensure().check_mod_liveness(local_def_id);
935946
tcx.ensure().check_mod_intrinsics(local_def_id);
936947
});
@@ -1055,8 +1066,7 @@ fn encode_and_write_metadata(
10551066
(metadata, need_metadata_module)
10561067
}
10571068

1058-
/// Runs the codegen backend, after which the AST and analysis can
1059-
/// be discarded.
1069+
/// Runs the codegen backend, after which the AST and analysis can be discarded.
10601070
pub fn start_codegen<'tcx>(
10611071
codegen_backend: &dyn CodegenBackend,
10621072
tcx: TyCtxt<'tcx>,

‎src/librustc_interface/queries.rs

+20-11
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,16 @@ use rustc::session::config::{OutputFilenames, OutputType};
66
use rustc::util::common::{time, ErrorReported};
77
use rustc::hir;
88
use rustc::hir::def_id::LOCAL_CRATE;
9-
use rustc::ty::steal::Steal;
9+
use rustc_data_structures::steal::Steal;
1010
use rustc::dep_graph::DepGraph;
11+
use syntax::{self, ast};
12+
1113
use std::cell::{Ref, RefMut, RefCell};
1214
use std::rc::Rc;
1315
use std::any::Any;
1416
use std::mem;
15-
use syntax::{self, ast};
1617

17-
/// Represent the result of a query.
18+
/// Represents the result of a query.
1819
/// This result can be stolen with the `take` method and returned with the `give` method.
1920
pub struct Query<T> {
2021
result: RefCell<Option<Result<T>>>,
@@ -46,14 +47,14 @@ impl<T> Query<T> {
4647
*result = Some(Ok(value));
4748
}
4849

49-
/// Borrows the query result using the RefCell. Panics if the result is stolen.
50+
/// Borrows the query result using the `RefCell`. Panics if the result is stolen.
5051
pub fn peek(&self) -> Ref<'_, T> {
5152
Ref::map(self.result.borrow(), |r| {
5253
r.as_ref().unwrap().as_ref().expect("missing query result")
5354
})
5455
}
5556

56-
/// Mutably borrows the query result using the RefCell. Panics if the result is stolen.
57+
/// Mutably borrows the query result using the `RefCell`. Panics if the result is stolen.
5758
pub fn peek_mut(&self) -> RefMut<'_, T> {
5859
RefMut::map(self.result.borrow_mut(), |r| {
5960
r.as_mut().unwrap().as_mut().expect("missing query result")
@@ -97,11 +98,18 @@ impl Compiler {
9798

9899
pub fn parse(&self) -> Result<&Query<ast::Crate>> {
99100
self.queries.parse.compute(|| {
100-
passes::parse(self.session(), &self.input).map_err(
101+
passes::parse(
102+
self.session(),
103+
&self.input,
104+
// This is only run once, so the steal here is fine (unfortunately, the current
105+
// architechture of rustc_interface is not great at exposing the nature of these
106+
// queries as "linear").
107+
self.interp_user_fn.as_ref().map(|s| s.steal()),
108+
).map_err(
101109
|mut parse_error| {
102110
parse_error.emit();
103111
ErrorReported
104-
},
112+
}
105113
)
106114
})
107115
}
@@ -221,7 +229,8 @@ impl Compiler {
221229
expansion.defs.steal(),
222230
expansion.resolutions.steal(),
223231
outputs,
224-
&crate_name))
232+
&crate_name,
233+
))
225234
})
226235
}
227236

@@ -231,7 +240,7 @@ impl Compiler {
231240
self.global_ctxt()?.peek_mut().enter(|tcx| {
232241
tcx.analysis(LOCAL_CRATE).ok();
233242

234-
// Don't do code generation if there were any errors
243+
// Don't do code generation if there were any errors.
235244
self.session().compile_status()?;
236245

237246
Ok(passes::start_codegen(
@@ -276,12 +285,12 @@ impl Compiler {
276285

277286
self.global_ctxt()?;
278287

279-
// Drop AST after creating GlobalCtxt to free memory.
288+
// Drop AST after creating `GlobalCtxt` to free memory.
280289
mem::drop(self.expansion()?.take());
281290

282291
self.ongoing_codegen()?;
283292

284-
// Drop GlobalCtxt after starting codegen to free memory.
293+
// Drop `GlobalCtxt` after starting codegen to free memory.
285294
mem::drop(self.global_ctxt()?.take());
286295

287296
self.link().map(|_| ())

‎src/librustc_mir/transform/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
use crate::{build, shim};
2+
23
use rustc_index::vec::IndexVec;
4+
use rustc_data_structures::steal::Steal;
35
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
46
use rustc::mir::{Body, MirPhase, Promoted};
57
use rustc::ty::{TyCtxt, InstanceDef};
68
use rustc::ty::query::Providers;
7-
use rustc::ty::steal::Steal;
89
use rustc::hir;
910
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
1011
use rustc::util::nodemap::DefIdSet;

‎src/libsyntax/ast.rs

+23-1
Original file line numberDiff line numberDiff line change
@@ -905,7 +905,27 @@ pub enum MacStmtStyle {
905905
NoBraces,
906906
}
907907

908-
/// Local represents a `let` statement, e.g., `let <pat>:<ty> = <expr>;`.
908+
/// The interpreter state of a `Local`.
909+
#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)]
910+
pub enum LocalInterpState {
911+
/// The local was not uninitialized in any previous evaluation session.
912+
Uninitialized,
913+
/// The local was set to a value in a previous evaluation session.
914+
Set,
915+
/// The local was moved during a previous evaluation session.
916+
Moved,
917+
}
918+
919+
/// Extra information about a `Local` for the interpreter.
920+
#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
921+
pub struct LocalInterpTag {
922+
/// The ID of this local, for use by the interpreter.
923+
pub id: usize,
924+
/// The state of the local.
925+
pub state: LocalInterpState,
926+
}
927+
928+
/// Represents a `let` statement, e.g., `let <pat>:<ty> = <expr>;`.
909929
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
910930
pub struct Local {
911931
pub id: NodeId,
@@ -915,6 +935,8 @@ pub struct Local {
915935
pub init: Option<P<Expr>>,
916936
pub span: Span,
917937
pub attrs: ThinVec<Attribute>,
938+
/// In interpreter mode, extra information about the local.
939+
pub interp_tag: Option<LocalInterpTag>,
918940
}
919941

920942
/// An arm of a 'match'.

‎src/libsyntax/ext/build.rs

+2
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ impl<'a> ExtCtxt<'a> {
190190
id: ast::DUMMY_NODE_ID,
191191
span: sp,
192192
attrs: ThinVec::new(),
193+
interp_tag: None,
193194
});
194195
ast::Stmt {
195196
id: ast::DUMMY_NODE_ID,
@@ -207,6 +208,7 @@ impl<'a> ExtCtxt<'a> {
207208
id: ast::DUMMY_NODE_ID,
208209
span,
209210
attrs: ThinVec::new(),
211+
interp_tag: None,
210212
});
211213
ast::Stmt {
212214
id: ast::DUMMY_NODE_ID,

‎src/libsyntax/feature_gate/builtin_attrs.rs

+16-11
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
337337
gated!(allow_internal_unsafe, Normal, template!(Word), EXPLAIN_ALLOW_INTERNAL_UNSAFE),
338338

339339
// ==========================================================================
340-
// Internal attributes: Type system related:
340+
// Internal attributes: Type system:
341341
// ==========================================================================
342342

343343
gated!(fundamental, Whitelisted, template!(Word), experimental!(fundamental)),
@@ -352,7 +352,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
352352
),
353353

354354
// ==========================================================================
355-
// Internal attributes: Runtime related:
355+
// Internal attributes: Runtime:
356356
// ==========================================================================
357357

358358
rustc_attr!(rustc_allocator, Whitelisted, template!(Word), IMPL_DETAIL),
@@ -389,7 +389,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
389389
),
390390

391391
// ==========================================================================
392-
// Internal attributes, Linkage:
392+
// Internal attributes: Linkage:
393393
// ==========================================================================
394394

395395
gated!(
@@ -399,7 +399,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
399399
rustc_attr!(rustc_std_internal_symbol, Whitelisted, template!(Word), INTERAL_UNSTABLE),
400400

401401
// ==========================================================================
402-
// Internal attributes, Macro related:
402+
// Internal attributes: Macros:
403403
// ==========================================================================
404404

405405
rustc_attr!(rustc_builtin_macro, Whitelisted, template!(Word), IMPL_DETAIL),
@@ -411,7 +411,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
411411
),
412412

413413
// ==========================================================================
414-
// Internal attributes, Diagnostics related:
414+
// Internal attributes: Diagnostics:
415415
// ==========================================================================
416416

417417
gated!(
@@ -427,15 +427,15 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
427427
rustc_attr!(rustc_conversion_suggestion, Whitelisted, template!(Word), INTERAL_UNSTABLE),
428428

429429
// ==========================================================================
430-
// Internal attributes, Const related:
430+
// Internal attributes: Const:
431431
// ==========================================================================
432432

433433
rustc_attr!(rustc_promotable, Whitelisted, template!(Word), IMPL_DETAIL),
434434
rustc_attr!(rustc_allow_const_fn_ptr, Whitelisted, template!(Word), IMPL_DETAIL),
435435
rustc_attr!(rustc_args_required_const, Whitelisted, template!(List: "N"), INTERAL_UNSTABLE),
436436

437437
// ==========================================================================
438-
// Internal attributes, Layout related:
438+
// Internal attributes: Layout related:
439439
// ==========================================================================
440440

441441
rustc_attr!(
@@ -455,7 +455,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
455455
),
456456

457457
// ==========================================================================
458-
// Internal attributes, Misc:
458+
// Internal attributes: Miscellaneous:
459459
// ==========================================================================
460460
gated!(
461461
lang, Normal, template!(NameValueStr: "name"), lang_items,
@@ -489,7 +489,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
489489
),
490490
gated!(
491491
rustc_paren_sugar, Normal, template!(Word), unboxed_closures,
492-
"unboxed_closures are still evolving",
492+
"the `unboxed_closures` feature is still evolving",
493493
),
494494
rustc_attr!(
495495
rustc_inherit_overflow_checks, Whitelisted, template!(Word),
@@ -505,9 +505,14 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
505505
rustc_test_marker, Normal, template!(Word),
506506
"the `#[rustc_test_marker]` attribute is used internally to track tests",
507507
),
508+
rustc_attr!(
509+
// Used by interpreters:
510+
rustc_interp_user_fn, Normal, template!(Word),
511+
"`#[rustc_interp_user_fn]` is for use by interpreters only"
512+
),
508513

509514
// ==========================================================================
510-
// Internal attributes, Testing:
515+
// Internal attributes: Testing:
511516
// ==========================================================================
512517

513518
rustc_attr!(TEST, rustc_outlives, Normal, template!(Word)),
@@ -545,7 +550,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
545550
rustc_attr!(TEST, rustc_dump_program_clauses, Whitelisted, template!(Word)),
546551
rustc_attr!(TEST, rustc_dump_env_program_clauses, Whitelisted, template!(Word)),
547552
rustc_attr!(TEST, rustc_object_lifetime_default, Whitelisted, template!(Word)),
548-
rustc_attr!(TEST, rustc_dummy, Normal, template!(Word /* doesn't matter*/)),
553+
rustc_attr!(TEST, rustc_dummy, Normal, template!(Word /* doesn't matter */)),
549554
gated!(
550555
omit_gdb_pretty_printer_section, Whitelisted, template!(Word),
551556
"the `#[omit_gdb_pretty_printer_section]` attribute is just used for the Rust test suite",

‎src/libsyntax/mut_visit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,7 @@ pub fn noop_visit_parenthesized_parameter_data<T: MutVisitor>(args: &mut Parenth
540540
}
541541

542542
pub fn noop_visit_local<T: MutVisitor>(local: &mut P<Local>, vis: &mut T) {
543-
let Local { id, pat, ty, init, span, attrs } = local.deref_mut();
543+
let Local { id, pat, ty, init, span, attrs, interp_tag: _ } = local.deref_mut();
544544
vis.visit_id(id);
545545
vis.visit_pat(pat);
546546
visit_opt(ty, |ty| vis.visit_ty(ty));

‎src/libsyntax/parse/diagnostics.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1087,7 +1087,9 @@ impl<'a> Parser<'a> {
10871087
/// statement. This is something of a best-effort heuristic.
10881088
///
10891089
/// We terminate when we find an unmatched `}` (without consuming it).
1090-
crate fn recover_stmt(&mut self) {
1090+
//
1091+
// NOTE: needs to be `pub` for interpreter.
1092+
pub fn recover_stmt(&mut self) {
10911093
self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore)
10921094
}
10931095

‎src/libsyntax/parse/mod.rs

+28-13
Original file line numberDiff line numberDiff line change
@@ -170,25 +170,40 @@ pub enum DirectoryOwnership {
170170
// uses a HOF to parse anything, and <source> includes file and
171171
// `source_str`.
172172

173-
pub fn parse_crate_from_file<'a>(input: &Path, sess: &'a ParseSess) -> PResult<'a, ast::Crate> {
174-
let mut parser = new_parser_from_file(sess, input);
175-
parser.parse_crate_mod()
173+
pub fn parse_crate_from_file<'a>(
174+
input: &Path,
175+
sess: &'a ParseSess,
176+
) -> PResult<'a, ast::Crate> {
177+
new_parser_from_file(sess, input)
178+
.parse_crate_mod()
176179
}
177180

178-
pub fn parse_crate_attrs_from_file<'a>(input: &Path, sess: &'a ParseSess)
179-
-> PResult<'a, Vec<ast::Attribute>> {
180-
let mut parser = new_parser_from_file(sess, input);
181-
parser.parse_inner_attributes()
181+
pub fn parse_crate_attrs_from_file<'a>(
182+
input: &Path,
183+
sess: &'a ParseSess,
184+
) -> PResult<'a, Vec<ast::Attribute>> {
185+
new_parser_from_file(sess, input)
186+
.parse_inner_attributes()
182187
}
183188

184-
pub fn parse_crate_from_source_str(name: FileName, source: String, sess: &ParseSess)
185-
-> PResult<'_, ast::Crate> {
186-
new_parser_from_source_str(sess, name, source).parse_crate_mod()
189+
pub fn parse_crate_from_source_str<'a>(
190+
name: FileName,
191+
source: String,
192+
sess: &'a ParseSess,
193+
interp_user_fn: Option<parser::InterpUserFn>,
194+
) -> PResult<'a, ast::Crate> {
195+
new_parser_from_source_str(sess, name, source)
196+
.set_interp_user_fn(interp_user_fn)
197+
.parse_crate_mod()
187198
}
188199

189-
pub fn parse_crate_attrs_from_source_str(name: FileName, source: String, sess: &ParseSess)
190-
-> PResult<'_, Vec<ast::Attribute>> {
191-
new_parser_from_source_str(sess, name, source).parse_inner_attributes()
200+
pub fn parse_crate_attrs_from_source_str<'a>(
201+
name: FileName,
202+
source: String,
203+
sess: &'a ParseSess,
204+
) -> PResult<'a, Vec<ast::Attribute>> {
205+
new_parser_from_source_str(sess, name, source)
206+
.parse_inner_attributes()
192207
}
193208

194209
pub fn parse_stream_from_source_str(

‎src/libsyntax/parse/parser.rs

+17
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,15 @@ enum PrevTokenKind {
107107

108108
// NOTE: `Ident`s are handled by `common.rs`.
109109

110+
/// In interpreter mode, information about the user fn (where the user-input code goes).
111+
#[derive(Clone)]
112+
pub struct InterpUserFn {
113+
/// The placeholder name. The parser looks for this as a single ident within a block.
114+
pub placeholder: Symbol,
115+
/// The body to insert in place of the placeholder ident.
116+
pub body: Option<P<ast::Block>>,
117+
}
118+
110119
#[derive(Clone)]
111120
pub struct Parser<'a> {
112121
pub sess: &'a ParseSess,
@@ -151,6 +160,8 @@ pub struct Parser<'a> {
151160
crate last_type_ascription: Option<(Span, bool /* likely path typo */)>,
152161
/// If present, this `Parser` is not parsing Rust code but rather a macro call.
153162
crate subparser_name: Option<&'static str>,
163+
/// In interpreter mode, the user fn to use.
164+
pub interp_user_fn: Option<InterpUserFn>,
154165
}
155166

156167
impl<'a> Drop for Parser<'a> {
@@ -368,6 +379,7 @@ impl<'a> Parser<'a> {
368379
last_unexpected_token_span: None,
369380
last_type_ascription: None,
370381
subparser_name,
382+
interp_user_fn: None,
371383
};
372384

373385
parser.token = parser.next_tok();
@@ -387,6 +399,11 @@ impl<'a> Parser<'a> {
387399
parser
388400
}
389401

402+
pub fn set_interp_user_fn(&mut self, interp_user_fn: Option<InterpUserFn>) -> &mut Self {
403+
self.interp_user_fn = interp_user_fn;
404+
self
405+
}
406+
390407
fn next_tok(&mut self) -> Token {
391408
let mut next = if self.desugar_doc_comments {
392409
self.token_cursor.next_desugared()

‎src/libsyntax/parse/parser/expr.rs

+38-6
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use super::{
55
use super::pat::{GateOr, PARAM_EXPECTED};
66

77
use crate::ast::{
8-
self, DUMMY_NODE_ID, Attribute, AttrStyle, Ident, CaptureBy, BlockCheckMode,
8+
self, DUMMY_NODE_ID, Attribute, AttrStyle, Ident, CaptureBy, Block, BlockCheckMode,
99
Expr, ExprKind, RangeLimits, Label, Movability, IsAsync, Arm, Ty, TyKind,
1010
FunctionRetTy, Param, FnDecl, BinOpKind, BinOp, UnOp, Mac, AnonConst, Field,
1111
};
@@ -631,13 +631,13 @@ impl<'a> Parser<'a> {
631631
let mut e = e0;
632632
let mut hi;
633633
loop {
634-
// expr?
634+
// `expr?`
635635
while self.eat(&token::Question) {
636636
let hi = self.prev_span;
637637
e = self.mk_expr(lo.to(hi), ExprKind::Try(e), ThinVec::new());
638638
}
639639

640-
// expr.f
640+
// `expr.f`
641641
if self.eat(&token::Dot) {
642642
match self.token.kind {
643643
token::Ident(..) => {
@@ -691,7 +691,7 @@ impl<'a> Parser<'a> {
691691
}
692692
if self.expr_is_complete(&e) { break; }
693693
match self.token.kind {
694-
// expr(...)
694+
// `expr(...)`
695695
token::OpenDelim(token::Paren) => {
696696
let seq = self.parse_paren_expr_seq().map(|es| {
697697
let nd = self.mk_call(e, es);
@@ -701,7 +701,7 @@ impl<'a> Parser<'a> {
701701
e = self.recover_seq_parse_error(token::Paren, lo, seq);
702702
}
703703

704-
// expr[...]
704+
// `expr[...]`
705705
// Could be either an index expression or a slicing expression.
706706
token::OpenDelim(token::Bracket) => {
707707
self.bump();
@@ -1100,10 +1100,42 @@ impl<'a> Parser<'a> {
11001100
let mut attrs = outer_attrs;
11011101
attrs.extend(self.parse_inner_attributes()?);
11021102

1103-
let blk = self.parse_block_tail(lo, blk_mode)?;
1103+
let blk = if let Some(interp_blk) = self.parse_interp_user_fn_block()? {
1104+
interp_blk
1105+
} else {
1106+
self.parse_block_tail(lo, blk_mode)?
1107+
};
11041108
Ok(self.mk_expr(blk.span, ExprKind::Block(blk, opt_label), attrs))
11051109
}
11061110

1111+
/// In interpreter mode, parses the placeholder for the user fn body as the user-provided
1112+
/// block (not from the source).
1113+
/// Outside of interpreter mode, simply returns `Ok(None)`.
1114+
fn parse_interp_user_fn_block(&mut self) -> PResult<'a, Option<P<Block>>> {
1115+
if let Some(placeholder) = self.interp_user_fn.as_ref().map(|f| f.placeholder) {
1116+
if let token::Ident(name, _) = self.token.kind {
1117+
if name == placeholder {
1118+
// We are in interpreter mode, and have found the block to use as the
1119+
// "user fn" body. Insert the given body for the user fn instead of
1120+
// parsing one.
1121+
1122+
self.bump();
1123+
self.expect(&token::CloseDelim(token::Brace))?;
1124+
1125+
let blk = self.interp_user_fn.as_mut().and_then(|f| f.body.take())
1126+
.ok_or_else(|| {
1127+
self.diagnostic().struct_span_err(self.token.span, &format!(
1128+
"encountered interpreter user fn placeholder `{}` more than once",
1129+
placeholder
1130+
))
1131+
})?;
1132+
return Ok(Some(blk));
1133+
}
1134+
}
1135+
}
1136+
Ok(None)
1137+
}
1138+
11071139
/// Parses a closure expression (e.g., `move |args| expr`).
11081140
fn parse_closure_expr(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
11091141
let lo = self.token.span;

‎src/libsyntax/parse/parser/stmt.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ impl<'a> Parser<'a> {
275275
id: DUMMY_NODE_ID,
276276
span: lo.to(hi),
277277
attrs,
278+
interp_tag: None,
278279
}))
279280
}
280281

@@ -422,7 +423,9 @@ impl<'a> Parser<'a> {
422423
}
423424

424425
/// Parses a statement, including the trailing semicolon.
425-
crate fn parse_full_stmt(&mut self, macro_legacy_warnings: bool) -> PResult<'a, Option<Stmt>> {
426+
//
427+
// NOTE: needs to be `pub` for interpreter.
428+
pub fn parse_full_stmt(&mut self, macro_legacy_warnings: bool) -> PResult<'a, Option<Stmt>> {
426429
// Skip looking for a trailing semicolon when we have an interpolated statement.
427430
maybe_whole!(self, NtStmt, |x| Some(x));
428431

‎src/libsyntax_ext/deriving/debug.rs

+1
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ fn stmt_let_undescore(cx: &mut ExtCtxt<'_>, sp: Span, expr: P<ast::Expr>) -> ast
128128
id: ast::DUMMY_NODE_ID,
129129
span: sp,
130130
attrs: ThinVec::new(),
131+
interp_tag: None,
131132
});
132133
ast::Stmt {
133134
id: ast::DUMMY_NODE_ID,

‎src/libsyntax_pos/span_encoding.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ const LEN_TAG: u16 = 0b1000_0000_0000_0000;
6868
const MAX_LEN: u32 = 0b0111_1111_1111_1111;
6969
const MAX_CTXT: u32 = 0b1111_1111_1111_1111;
7070

71-
/// Dummy span, both position and length are zero, syntax context is zero as well.
71+
/// Dummy span: both position and length are zero; syntax context is zero (empty) as well.
7272
pub const DUMMY_SP: Span = Span { base_or_index: 0, len_or_tag: 0, ctxt_or_zero: 0 };
7373

7474
impl Span {

‎src/libsyntax_pos/symbol.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ symbols! {
101101
}
102102

103103
// Symbols that can be referred to with syntax_pos::sym::*. The symbol is
104-
// the stringified identifier unless otherwise specified (e.g.
104+
// the stringified identifier unless otherwise specified (e.g.,
105105
// `proc_dash_macro` represents "proc-macro").
106106
//
107107
// As well as the symbols listed, there are symbols for the the strings
@@ -581,6 +581,7 @@ symbols! {
581581
rustc_expected_cgu_reuse,
582582
rustc_if_this_changed,
583583
rustc_inherit_overflow_checks,
584+
rustc_interp_user_fn,
584585
rustc_layout,
585586
rustc_layout_scalar_valid_range_end,
586587
rustc_layout_scalar_valid_range_start,

‎src/test/ui/interp-user-fn.rs

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#![feature(stmt_expr_attributes)]
2+
3+
fn main() {
4+
let user_body = #[rustc_interp_user_fn] || {};
5+
//~^ ERROR `#[rustc_interp_user_fn]` is for use by interpreters only [E0658]
6+
user_body();
7+
}

‎src/test/ui/interp-user-fn.stderr

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0658]: `#[rustc_interp_user_fn]` is for use by interpreters only
2+
--> $DIR/interp-user-fn.rs:4:21
3+
|
4+
LL | let user_body = #[rustc_interp_user_fn] || {};
5+
| ^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: for more information, see https://github.com/rust-lang/rust/issues/29642
8+
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0658`.

0 commit comments

Comments
 (0)
Please sign in to comment.