mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-30 02:33:55 +00:00
Auto merge of #31065 - nrc:ident-correct, r=pnkfelix
This PR adds some minor error correction to the parser - if there is a missing ident, we recover and carry on. It also makes compilation more robust so that non-fatal errors (which is still most of them, unfortunately) in parsing do not cause us to abort compilation. The effect is that a program with a missing or incorrect ident can get all the way to type checking.
This commit is contained in:
commit
faf6d1e873
@ -267,24 +267,28 @@ impl InlinedItem {
|
||||
|
||||
// FIXME: find a better place for this?
|
||||
pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option<Span>) {
|
||||
let say = |s: &str| {
|
||||
match (sp, sess) {
|
||||
(_, None) => panic!("{}", s),
|
||||
(Some(sp), Some(sess)) => sess.span_err(sp, s),
|
||||
(None, Some(sess)) => sess.err(s),
|
||||
let mut err_count = 0;
|
||||
{
|
||||
let mut say = |s: &str| {
|
||||
match (sp, sess) {
|
||||
(_, None) => panic!("{}", s),
|
||||
(Some(sp), Some(sess)) => sess.span_err(sp, s),
|
||||
(None, Some(sess)) => sess.err(s),
|
||||
}
|
||||
err_count += 1;
|
||||
};
|
||||
if s.is_empty() {
|
||||
say("crate name must not be empty");
|
||||
}
|
||||
for c in s.chars() {
|
||||
if c.is_alphanumeric() { continue }
|
||||
if c == '_' { continue }
|
||||
say(&format!("invalid character `{}` in crate name: `{}`", c, s));
|
||||
}
|
||||
};
|
||||
if s.is_empty() {
|
||||
say("crate name must not be empty");
|
||||
}
|
||||
for c in s.chars() {
|
||||
if c.is_alphanumeric() { continue }
|
||||
if c == '_' { continue }
|
||||
say(&format!("invalid character `{}` in crate name: `{}`", c, s));
|
||||
}
|
||||
match sess {
|
||||
Some(sess) => sess.abort_if_errors(),
|
||||
None => {}
|
||||
|
||||
if err_count > 0 {
|
||||
sess.unwrap().abort_if_errors();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -239,7 +239,6 @@ pub fn collect_language_items(session: &Session,
|
||||
collector.collect(krate);
|
||||
let LanguageItemCollector { mut items, .. } = collector;
|
||||
weak_lang_items::check_crate(krate, session, &mut items);
|
||||
session.abort_if_errors();
|
||||
items
|
||||
}
|
||||
|
||||
|
@ -176,14 +176,15 @@ impl Session {
|
||||
pub fn abort_if_errors(&self) {
|
||||
self.diagnostic().abort_if_errors();
|
||||
}
|
||||
pub fn abort_if_new_errors<F>(&self, mut f: F)
|
||||
where F: FnMut()
|
||||
pub fn abort_if_new_errors<F, T>(&self, f: F) -> T
|
||||
where F: FnOnce() -> T
|
||||
{
|
||||
let count = self.err_count();
|
||||
f();
|
||||
let result = f();
|
||||
if self.err_count() > count {
|
||||
self.abort_if_errors();
|
||||
}
|
||||
result
|
||||
}
|
||||
pub fn span_warn(&self, sp: Span, msg: &str) {
|
||||
self.diagnostic().span_warn(sp, msg)
|
||||
|
@ -69,8 +69,8 @@ pub fn compile_input(sess: Session,
|
||||
let state = $make_state;
|
||||
(control.$point.callback)(state);
|
||||
|
||||
$tsess.abort_if_errors();
|
||||
if control.$point.stop == Compilation::Stop {
|
||||
$tsess.abort_if_errors();
|
||||
return;
|
||||
}
|
||||
})}
|
||||
@ -470,7 +470,11 @@ pub fn phase_2_configure_and_expand(sess: &Session,
|
||||
|
||||
let mut feature_gated_cfgs = vec![];
|
||||
krate = time(time_passes, "configuration 1", || {
|
||||
syntax::config::strip_unconfigured_items(sess.diagnostic(), krate, &mut feature_gated_cfgs)
|
||||
sess.abort_if_new_errors(|| {
|
||||
syntax::config::strip_unconfigured_items(sess.diagnostic(),
|
||||
krate,
|
||||
&mut feature_gated_cfgs)
|
||||
})
|
||||
});
|
||||
|
||||
*sess.crate_types.borrow_mut() = collect_crate_types(sess, &krate.attrs);
|
||||
@ -481,13 +485,15 @@ pub fn phase_2_configure_and_expand(sess: &Session,
|
||||
});
|
||||
|
||||
time(time_passes, "gated macro checking", || {
|
||||
let features = syntax::feature_gate::check_crate_macros(sess.codemap(),
|
||||
&sess.parse_sess.span_diagnostic,
|
||||
&krate);
|
||||
sess.abort_if_new_errors(|| {
|
||||
let features =
|
||||
syntax::feature_gate::check_crate_macros(sess.codemap(),
|
||||
&sess.parse_sess.span_diagnostic,
|
||||
&krate);
|
||||
|
||||
// these need to be set "early" so that expansion sees `quote` if enabled.
|
||||
*sess.features.borrow_mut() = features;
|
||||
sess.abort_if_errors();
|
||||
// these need to be set "early" so that expansion sees `quote` if enabled.
|
||||
*sess.features.borrow_mut() = features;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -525,7 +531,7 @@ pub fn phase_2_configure_and_expand(sess: &Session,
|
||||
let Registry { syntax_exts, early_lint_passes, late_lint_passes, lint_groups,
|
||||
llvm_passes, attributes, .. } = registry;
|
||||
|
||||
{
|
||||
sess.abort_if_new_errors(|| {
|
||||
let mut ls = sess.lint_store.borrow_mut();
|
||||
for pass in early_lint_passes {
|
||||
ls.register_early_pass(Some(sess), true, pass);
|
||||
@ -540,17 +546,14 @@ pub fn phase_2_configure_and_expand(sess: &Session,
|
||||
|
||||
*sess.plugin_llvm_passes.borrow_mut() = llvm_passes;
|
||||
*sess.plugin_attributes.borrow_mut() = attributes.clone();
|
||||
}
|
||||
});
|
||||
|
||||
// Lint plugins are registered; now we can process command line flags.
|
||||
if sess.opts.describe_lints {
|
||||
super::describe_lints(&*sess.lint_store.borrow(), true);
|
||||
return None;
|
||||
}
|
||||
sess.lint_store.borrow_mut().process_command_line(sess);
|
||||
|
||||
// Abort if there are errors from lint processing or a plugin registrar.
|
||||
sess.abort_if_errors();
|
||||
sess.abort_if_new_errors(|| sess.lint_store.borrow_mut().process_command_line(sess));
|
||||
|
||||
krate = time(time_passes, "expansion", || {
|
||||
// Windows dlls do not have rpaths, so they don't know how to find their
|
||||
@ -594,29 +597,36 @@ pub fn phase_2_configure_and_expand(sess: &Session,
|
||||
// much as possible (e.g. help the programmer avoid platform
|
||||
// specific differences)
|
||||
time(time_passes, "complete gated feature checking 1", || {
|
||||
let features = syntax::feature_gate::check_crate(sess.codemap(),
|
||||
&sess.parse_sess.span_diagnostic,
|
||||
&krate,
|
||||
&attributes,
|
||||
sess.opts.unstable_features);
|
||||
*sess.features.borrow_mut() = features;
|
||||
sess.abort_if_errors();
|
||||
sess.abort_if_new_errors(|| {
|
||||
let features = syntax::feature_gate::check_crate(sess.codemap(),
|
||||
&sess.parse_sess.span_diagnostic,
|
||||
&krate,
|
||||
&attributes,
|
||||
sess.opts.unstable_features);
|
||||
*sess.features.borrow_mut() = features;
|
||||
});
|
||||
});
|
||||
|
||||
// JBC: make CFG processing part of expansion to avoid this problem:
|
||||
|
||||
// strip again, in case expansion added anything with a #[cfg].
|
||||
krate = time(time_passes, "configuration 2", || {
|
||||
syntax::config::strip_unconfigured_items(sess.diagnostic(), krate, &mut feature_gated_cfgs)
|
||||
});
|
||||
krate = sess.abort_if_new_errors(|| {
|
||||
let krate = time(time_passes, "configuration 2", || {
|
||||
syntax::config::strip_unconfigured_items(sess.diagnostic(),
|
||||
krate,
|
||||
&mut feature_gated_cfgs)
|
||||
});
|
||||
|
||||
time(time_passes, "gated configuration checking", || {
|
||||
let features = sess.features.borrow();
|
||||
feature_gated_cfgs.sort();
|
||||
feature_gated_cfgs.dedup();
|
||||
for cfg in &feature_gated_cfgs {
|
||||
cfg.check_and_emit(sess.diagnostic(), &features, sess.codemap());
|
||||
}
|
||||
time(time_passes, "gated configuration checking", || {
|
||||
let features = sess.features.borrow();
|
||||
feature_gated_cfgs.sort();
|
||||
feature_gated_cfgs.dedup();
|
||||
for cfg in &feature_gated_cfgs {
|
||||
cfg.check_and_emit(sess.diagnostic(), &features, sess.codemap());
|
||||
}
|
||||
});
|
||||
|
||||
krate
|
||||
});
|
||||
|
||||
krate = time(time_passes, "maybe building test harness", || {
|
||||
@ -639,13 +649,14 @@ pub fn phase_2_configure_and_expand(sess: &Session,
|
||||
// later, to make sure we've got everything (e.g. configuration
|
||||
// can insert new attributes via `cfg_attr`)
|
||||
time(time_passes, "complete gated feature checking 2", || {
|
||||
let features = syntax::feature_gate::check_crate(sess.codemap(),
|
||||
&sess.parse_sess.span_diagnostic,
|
||||
&krate,
|
||||
&attributes,
|
||||
sess.opts.unstable_features);
|
||||
*sess.features.borrow_mut() = features;
|
||||
sess.abort_if_errors();
|
||||
sess.abort_if_new_errors(|| {
|
||||
let features = syntax::feature_gate::check_crate(sess.codemap(),
|
||||
&sess.parse_sess.span_diagnostic,
|
||||
&krate,
|
||||
&attributes,
|
||||
sess.opts.unstable_features);
|
||||
*sess.features.borrow_mut() = features;
|
||||
});
|
||||
});
|
||||
|
||||
time(time_passes,
|
||||
@ -711,9 +722,11 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
|
||||
"external crate/lib resolution",
|
||||
|| LocalCrateReader::new(sess, cstore, &hir_map).read_crates(krate));
|
||||
|
||||
let lang_items = time(time_passes,
|
||||
"language item collection",
|
||||
|| middle::lang_items::collect_language_items(&sess, &hir_map));
|
||||
let lang_items = time(time_passes, "language item collection", || {
|
||||
sess.abort_if_new_errors(|| {
|
||||
middle::lang_items::collect_language_items(&sess, &hir_map)
|
||||
})
|
||||
});
|
||||
|
||||
let resolve::CrateMap {
|
||||
def_map,
|
||||
|
@ -258,15 +258,14 @@ impl<'a> CrateReader<'a> {
|
||||
metadata: &MetadataBlob) {
|
||||
let crate_rustc_version = decoder::crate_rustc_version(metadata.as_slice());
|
||||
if crate_rustc_version != Some(rustc_version()) {
|
||||
span_err!(self.sess, span, E0514,
|
||||
"the crate `{}` has been compiled with {}, which is \
|
||||
incompatible with this version of rustc",
|
||||
name,
|
||||
crate_rustc_version
|
||||
.as_ref().map(|s|&**s)
|
||||
.unwrap_or("an old version of rustc")
|
||||
span_fatal!(self.sess, span, E0514,
|
||||
"the crate `{}` has been compiled with {}, which is \
|
||||
incompatible with this version of rustc",
|
||||
name,
|
||||
crate_rustc_version
|
||||
.as_ref().map(|s|&**s)
|
||||
.unwrap_or("an old version of rustc")
|
||||
);
|
||||
self.sess.abort_if_errors();
|
||||
}
|
||||
}
|
||||
|
||||
@ -511,7 +510,6 @@ impl<'a> CrateReader<'a> {
|
||||
}
|
||||
};
|
||||
let span = mk_sp(lo, p.last_span.hi);
|
||||
p.abort_if_errors();
|
||||
|
||||
// Mark the attrs as used
|
||||
for attr in &attrs {
|
||||
@ -554,8 +552,7 @@ impl<'a> CrateReader<'a> {
|
||||
name,
|
||||
config::host_triple(),
|
||||
self.sess.opts.target_triple);
|
||||
span_err!(self.sess, span, E0456, "{}", &message[..]);
|
||||
self.sess.abort_if_errors();
|
||||
span_fatal!(self.sess, span, E0456, "{}", &message[..]);
|
||||
}
|
||||
|
||||
let registrar =
|
||||
|
@ -18,8 +18,9 @@ use syntax::visit::{self, Visitor, FnKind};
|
||||
use syntax::codemap::Span;
|
||||
|
||||
pub fn check_crate(sess: &Session, krate: &ast::Crate) {
|
||||
visit::walk_crate(&mut CheckConstFn{ sess: sess }, krate);
|
||||
sess.abort_if_errors();
|
||||
sess.abort_if_new_errors(|| {
|
||||
visit::walk_crate(&mut CheckConstFn{ sess: sess }, krate);
|
||||
});
|
||||
}
|
||||
|
||||
struct CheckConstFn<'a> {
|
||||
|
@ -3037,6 +3037,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
check_ribs: bool,
|
||||
record_used: bool)
|
||||
-> Option<LocalDef> {
|
||||
if identifier.name == special_idents::invalid.name {
|
||||
return Some(LocalDef::from_def(Def::Err));
|
||||
}
|
||||
|
||||
// First, check to see whether the name is a primitive type.
|
||||
if namespace == TypeNS {
|
||||
if let Some(&prim_ty) = self.primitive_type_table
|
||||
@ -4019,10 +4023,8 @@ pub fn create_resolver<'a, 'tcx>(session: &'a Session,
|
||||
resolver.callback = callback;
|
||||
|
||||
build_reduced_graph::build_reduced_graph(&mut resolver, krate);
|
||||
session.abort_if_errors();
|
||||
|
||||
resolve_imports::resolve_imports(&mut resolver);
|
||||
session.abort_if_errors();
|
||||
|
||||
resolver
|
||||
}
|
||||
|
@ -121,7 +121,7 @@ use syntax::attr;
|
||||
use syntax::attr::AttrMetaMethods;
|
||||
use syntax::codemap::{self, Span, Spanned};
|
||||
use syntax::errors::DiagnosticBuilder;
|
||||
use syntax::parse::token::{self, InternedString};
|
||||
use syntax::parse::token::{self, InternedString, special_idents};
|
||||
use syntax::ptr::P;
|
||||
use syntax::util::lev_distance::find_best_match_for_name;
|
||||
|
||||
@ -2839,8 +2839,10 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
method_ty
|
||||
}
|
||||
Err(error) => {
|
||||
method::report_error(fcx, method_name.span, expr_t,
|
||||
method_name.node, Some(rcvr), error);
|
||||
if method_name.node != special_idents::invalid.name {
|
||||
method::report_error(fcx, method_name.span, expr_t,
|
||||
method_name.node, Some(rcvr), error);
|
||||
}
|
||||
fcx.write_error(expr.id);
|
||||
fcx.tcx().types.err
|
||||
}
|
||||
@ -2938,6 +2940,11 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
None => {}
|
||||
}
|
||||
|
||||
if field.node == special_idents::invalid.name {
|
||||
fcx.write_error(expr.id);
|
||||
return;
|
||||
}
|
||||
|
||||
if method::exists(fcx, field.span, field.node, expr_t, expr.id) {
|
||||
fcx.type_error_struct(field.span,
|
||||
|actual| {
|
||||
@ -3788,8 +3795,9 @@ pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, 'tcx>,
|
||||
Some((Some(ty), slice::ref_slice(item_segment), def))
|
||||
}
|
||||
Err(error) => {
|
||||
method::report_error(fcx, span, ty,
|
||||
item_name, None, error);
|
||||
if item_name != special_idents::invalid.name {
|
||||
method::report_error(fcx, span, ty, item_name, None, error);
|
||||
}
|
||||
fcx.write_error(node_id);
|
||||
None
|
||||
}
|
||||
@ -4221,7 +4229,9 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
|
||||
}
|
||||
// Check for unrepresentable discriminant values
|
||||
match hint {
|
||||
attr::ReprAny | attr::ReprExtern => (),
|
||||
attr::ReprAny | attr::ReprExtern => {
|
||||
disr_vals.push(current_disr_val);
|
||||
}
|
||||
attr::ReprInt(sp, ity) => {
|
||||
if !disr_in_range(ccx, ity, current_disr_val) {
|
||||
let mut err = struct_span_err!(ccx.tcx.sess, v.span, E0082,
|
||||
@ -4231,14 +4241,9 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
attr::ReprSimd => {
|
||||
ccx.tcx.sess.bug("range_to_inttype: found ReprSimd on an enum");
|
||||
}
|
||||
attr::ReprPacked => {
|
||||
ccx.tcx.sess.bug("range_to_inttype: found ReprPacked on an enum");
|
||||
}
|
||||
// Error reported elsewhere.
|
||||
attr::ReprSimd | attr::ReprPacked => {}
|
||||
}
|
||||
disr_vals.push(current_disr_val);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -555,6 +555,9 @@ impl Handler {
|
||||
pub enum Level {
|
||||
Bug,
|
||||
Fatal,
|
||||
// An error which while not immediately fatal, should stop the compiler
|
||||
// progressing beyond the current phase.
|
||||
PhaseFatal,
|
||||
Error,
|
||||
Warning,
|
||||
Note,
|
||||
@ -573,7 +576,7 @@ impl fmt::Display for Level {
|
||||
impl Level {
|
||||
fn color(self) -> term::color::Color {
|
||||
match self {
|
||||
Bug | Fatal | Error => term::color::BRIGHT_RED,
|
||||
Bug | Fatal | PhaseFatal | Error => term::color::BRIGHT_RED,
|
||||
Warning => term::color::BRIGHT_YELLOW,
|
||||
Note => term::color::BRIGHT_GREEN,
|
||||
Help => term::color::BRIGHT_CYAN,
|
||||
@ -584,7 +587,7 @@ impl Level {
|
||||
fn to_str(self) -> &'static str {
|
||||
match self {
|
||||
Bug => "error: internal compiler error",
|
||||
Fatal | Error => "error",
|
||||
Fatal | PhaseFatal | Error => "error",
|
||||
Warning => "warning",
|
||||
Note => "note",
|
||||
Help => "help",
|
||||
|
@ -1304,9 +1304,14 @@ pub fn expand_crate(mut cx: ExtCtxt,
|
||||
expander.cx.syntax_env.insert(name, extension);
|
||||
}
|
||||
|
||||
let err_count = cx.parse_sess.span_diagnostic.err_count();
|
||||
let mut ret = expander.fold_crate(c);
|
||||
ret.exported_macros = expander.cx.exported_macros.clone();
|
||||
cx.parse_sess.span_diagnostic.abort_if_errors();
|
||||
|
||||
if cx.parse_sess.span_diagnostic.err_count() > err_count {
|
||||
cx.parse_sess.span_diagnostic.abort_if_errors();
|
||||
}
|
||||
|
||||
ret
|
||||
};
|
||||
return (ret, cx.syntax_env.names);
|
||||
|
@ -98,7 +98,7 @@ pub fn parse_crate_from_source_str(name: String,
|
||||
cfg,
|
||||
name,
|
||||
source);
|
||||
maybe_aborted(panictry!(p.parse_crate_mod()),p)
|
||||
panictry!(p.parse_crate_mod())
|
||||
}
|
||||
|
||||
pub fn parse_crate_attrs_from_source_str(name: String,
|
||||
@ -110,7 +110,7 @@ pub fn parse_crate_attrs_from_source_str(name: String,
|
||||
cfg,
|
||||
name,
|
||||
source);
|
||||
maybe_aborted(panictry!(p.parse_inner_attributes()), p)
|
||||
panictry!(p.parse_inner_attributes())
|
||||
}
|
||||
|
||||
pub fn parse_expr_from_source_str(name: String,
|
||||
@ -119,7 +119,7 @@ pub fn parse_expr_from_source_str(name: String,
|
||||
sess: &ParseSess)
|
||||
-> P<ast::Expr> {
|
||||
let mut p = new_parser_from_source_str(sess, cfg, name, source);
|
||||
maybe_aborted(panictry!(p.parse_expr()), p)
|
||||
panictry!(p.parse_expr())
|
||||
}
|
||||
|
||||
pub fn parse_item_from_source_str(name: String,
|
||||
@ -128,7 +128,7 @@ pub fn parse_item_from_source_str(name: String,
|
||||
sess: &ParseSess)
|
||||
-> Option<P<ast::Item>> {
|
||||
let mut p = new_parser_from_source_str(sess, cfg, name, source);
|
||||
maybe_aborted(panictry!(p.parse_item()), p)
|
||||
panictry!(p.parse_item())
|
||||
}
|
||||
|
||||
pub fn parse_meta_from_source_str(name: String,
|
||||
@ -137,7 +137,7 @@ pub fn parse_meta_from_source_str(name: String,
|
||||
sess: &ParseSess)
|
||||
-> P<ast::MetaItem> {
|
||||
let mut p = new_parser_from_source_str(sess, cfg, name, source);
|
||||
maybe_aborted(panictry!(p.parse_meta_item()), p)
|
||||
panictry!(p.parse_meta_item())
|
||||
}
|
||||
|
||||
pub fn parse_stmt_from_source_str(name: String,
|
||||
@ -151,7 +151,7 @@ pub fn parse_stmt_from_source_str(name: String,
|
||||
name,
|
||||
source
|
||||
);
|
||||
maybe_aborted(panictry!(p.parse_stmt()), p)
|
||||
panictry!(p.parse_stmt())
|
||||
}
|
||||
|
||||
// Warning: This parses with quote_depth > 0, which is not the default.
|
||||
@ -168,7 +168,7 @@ pub fn parse_tts_from_source_str(name: String,
|
||||
);
|
||||
p.quote_depth += 1;
|
||||
// right now this is re-creating the token trees from ... token trees.
|
||||
maybe_aborted(panictry!(p.parse_all_token_trees()),p)
|
||||
panictry!(p.parse_all_token_trees())
|
||||
}
|
||||
|
||||
// Create a new parser from a source string
|
||||
@ -265,16 +265,10 @@ pub fn tts_to_parser<'a>(sess: &'a ParseSess,
|
||||
p
|
||||
}
|
||||
|
||||
/// Abort if necessary
|
||||
pub fn maybe_aborted<T>(result: T, p: Parser) -> T {
|
||||
p.abort_if_errors();
|
||||
result
|
||||
}
|
||||
|
||||
fn abort_if_errors<'a, T>(result: PResult<'a, T>, p: &Parser) -> T {
|
||||
match result {
|
||||
Ok(c) => {
|
||||
p.abort_if_errors();
|
||||
c
|
||||
}
|
||||
Err(mut e) => {
|
||||
|
@ -2355,6 +2355,59 @@ impl<'a> Parser<'a> {
|
||||
)
|
||||
}
|
||||
|
||||
// Assuming we have just parsed `.foo` (i.e., a dot and an ident), continue
|
||||
// parsing into an expression.
|
||||
fn parse_dot_suffix(&mut self,
|
||||
ident: Ident,
|
||||
ident_span: Span,
|
||||
self_value: P<Expr>)
|
||||
-> PResult<'a, P<Expr>> {
|
||||
let (_, tys, bindings) = if self.eat(&token::ModSep) {
|
||||
try!(self.expect_lt());
|
||||
try!(self.parse_generic_values_after_lt())
|
||||
} else {
|
||||
(Vec::new(), Vec::new(), Vec::new())
|
||||
};
|
||||
|
||||
if !bindings.is_empty() {
|
||||
let last_span = self.last_span;
|
||||
self.span_err(last_span, "type bindings are only permitted on trait paths");
|
||||
}
|
||||
|
||||
let lo = self_value.span.lo;
|
||||
|
||||
Ok(match self.token {
|
||||
// expr.f() method call.
|
||||
token::OpenDelim(token::Paren) => {
|
||||
let mut es = try!(self.parse_unspanned_seq(
|
||||
&token::OpenDelim(token::Paren),
|
||||
&token::CloseDelim(token::Paren),
|
||||
seq_sep_trailing_allowed(token::Comma),
|
||||
|p| Ok(try!(p.parse_expr()))
|
||||
));
|
||||
let hi = self.last_span.hi;
|
||||
|
||||
es.insert(0, self_value);
|
||||
let id = spanned(ident_span.lo, ident_span.hi, ident);
|
||||
let nd = self.mk_method_call(id, tys, es);
|
||||
self.mk_expr(lo, hi, nd, None)
|
||||
}
|
||||
// Field access.
|
||||
_ => {
|
||||
if !tys.is_empty() {
|
||||
let last_span = self.last_span;
|
||||
self.span_err(last_span,
|
||||
"field expressions may not \
|
||||
have type parameters");
|
||||
}
|
||||
|
||||
let id = spanned(ident_span.lo, ident_span.hi, ident);
|
||||
let field = self.mk_field(self_value, id);
|
||||
self.mk_expr(lo, ident_span.hi, field, None)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_dot_or_call_expr_with_(&mut self, e0: P<Expr>) -> PResult<'a, P<Expr>> {
|
||||
let mut e = e0;
|
||||
let lo = e.span.lo;
|
||||
@ -2364,50 +2417,11 @@ impl<'a> Parser<'a> {
|
||||
if self.eat(&token::Dot) {
|
||||
match self.token {
|
||||
token::Ident(i, _) => {
|
||||
let dot = self.last_span.hi;
|
||||
let dot_pos = self.last_span.hi;
|
||||
hi = self.span.hi;
|
||||
self.bump();
|
||||
let (_, tys, bindings) = if self.eat(&token::ModSep) {
|
||||
try!(self.expect_lt());
|
||||
try!(self.parse_generic_values_after_lt())
|
||||
} else {
|
||||
(Vec::new(), Vec::new(), Vec::new())
|
||||
};
|
||||
|
||||
if !bindings.is_empty() {
|
||||
let last_span = self.last_span;
|
||||
self.span_err(last_span, "type bindings are only permitted on trait paths");
|
||||
}
|
||||
|
||||
// expr.f() method call
|
||||
match self.token {
|
||||
token::OpenDelim(token::Paren) => {
|
||||
let mut es = try!(self.parse_unspanned_seq(
|
||||
&token::OpenDelim(token::Paren),
|
||||
&token::CloseDelim(token::Paren),
|
||||
seq_sep_trailing_allowed(token::Comma),
|
||||
|p| Ok(try!(p.parse_expr()))
|
||||
));
|
||||
hi = self.last_span.hi;
|
||||
|
||||
es.insert(0, e);
|
||||
let id = spanned(dot, hi, i);
|
||||
let nd = self.mk_method_call(id, tys, es);
|
||||
e = self.mk_expr(lo, hi, nd, None);
|
||||
}
|
||||
_ => {
|
||||
if !tys.is_empty() {
|
||||
let last_span = self.last_span;
|
||||
self.span_err(last_span,
|
||||
"field expressions may not \
|
||||
have type parameters");
|
||||
}
|
||||
|
||||
let id = spanned(dot, hi, i);
|
||||
let field = self.mk_field(e, id);
|
||||
e = self.mk_expr(lo, hi, field, None);
|
||||
}
|
||||
}
|
||||
e = try!(self.parse_dot_suffix(i, mk_sp(dot_pos, hi), e));
|
||||
}
|
||||
token::Literal(token::Integer(n), suf) => {
|
||||
let sp = self.span;
|
||||
@ -2452,7 +2466,16 @@ impl<'a> Parser<'a> {
|
||||
self.abort_if_errors();
|
||||
|
||||
}
|
||||
_ => return self.unexpected()
|
||||
_ => {
|
||||
// FIXME Could factor this out into non_fatal_unexpected or something.
|
||||
let actual = self.this_token_to_string();
|
||||
self.span_err(self.span, &format!("unexpected token: `{}`", actual));
|
||||
|
||||
let dot_pos = self.last_span.hi;
|
||||
e = try!(self.parse_dot_suffix(special_idents::invalid,
|
||||
mk_sp(dot_pos, dot_pos),
|
||||
e));
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -8,6 +8,8 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(stmt_expr_attributes)]
|
||||
|
||||
fn main() {
|
||||
let _ = #[cfg(unset)] ();
|
||||
//~^ ERROR removing an expression is not supported in this position
|
||||
|
@ -20,5 +20,5 @@ mod foo {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _ = foo::X;
|
||||
let _ = foo::X; //~ ERROR unresolved name `foo::X`
|
||||
}
|
||||
|
@ -16,3 +16,4 @@ mod spam {
|
||||
}
|
||||
|
||||
fn main() { ham(); eggs(); }
|
||||
//~^ ERROR unresolved name `eggs`
|
||||
|
@ -16,4 +16,4 @@ use zed::baz;
|
||||
mod zed {
|
||||
pub fn bar() { println!("bar"); }
|
||||
}
|
||||
fn main(args: Vec<String>) { bar(); }
|
||||
fn main() { bar(); }
|
||||
|
@ -16,4 +16,5 @@ mod baz {}
|
||||
mod zed {
|
||||
pub fn bar() { println!("bar3"); }
|
||||
}
|
||||
fn main(args: Vec<String>) { bar(); }
|
||||
fn main() { bar(); }
|
||||
//~^ ERROR unresolved name `bar`
|
||||
|
@ -8,9 +8,8 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![no_std]
|
||||
#![feature(macro_reexport)]
|
||||
|
||||
#[macro_reexport] //~ ERROR bad macro reexport
|
||||
extern crate std;
|
||||
|
||||
fn main() { }
|
||||
|
@ -8,9 +8,8 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![no_std]
|
||||
#![feature(macro_reexport)]
|
||||
|
||||
#[macro_reexport="foo"] //~ ERROR bad macro reexport
|
||||
extern crate std;
|
||||
|
||||
fn main() { }
|
||||
|
@ -8,9 +8,8 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![no_std]
|
||||
#![feature(macro_reexport)]
|
||||
|
||||
#[macro_reexport(foo="bar")] //~ ERROR bad macro reexport
|
||||
extern crate std;
|
||||
|
||||
fn main() { }
|
||||
|
@ -10,6 +10,8 @@
|
||||
|
||||
// aux-build:two_macros.rs
|
||||
|
||||
#![feature(macro_reexport)]
|
||||
|
||||
#[macro_use(macro_two)]
|
||||
#[macro_reexport(no_way)] //~ ERROR reexported macro not found
|
||||
extern crate two_macros;
|
||||
|
@ -8,8 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![no_std]
|
||||
|
||||
#[macro_use(foo(bar))] //~ ERROR bad macro import
|
||||
extern crate std;
|
||||
|
||||
fn main() {
|
||||
}
|
||||
|
@ -8,8 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![no_std]
|
||||
|
||||
#[macro_use(foo="bar")] //~ ERROR bad macro import
|
||||
extern crate std;
|
||||
|
||||
fn main() {
|
||||
}
|
||||
|
19
src/test/compile-fail/parse-error-correct.rs
Normal file
19
src/test/compile-fail/parse-error-correct.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test that the parser is error correcting missing idents. Despite a parsing
|
||||
// error (or two), we still run type checking (and don't get extra errors there).
|
||||
|
||||
fn main() {
|
||||
let y = 42;
|
||||
let x = y.; //~ ERROR unexpected token
|
||||
let x = y.(); //~ ERROR unexpected token
|
||||
let x = y.foo; //~ ERROR no field
|
||||
}
|
@ -28,6 +28,7 @@ fn test1() {
|
||||
use bar::gpriv;
|
||||
//~^ ERROR unresolved import `bar::gpriv`. There is no `gpriv` in `bar`
|
||||
gpriv();
|
||||
//~^ ERROR unresolved name `gpriv`
|
||||
}
|
||||
|
||||
#[start] fn main(_: isize, _: *const *const u8) -> isize { 3 }
|
||||
|
@ -29,6 +29,7 @@ pub fn main() {
|
||||
//~^ ERROR expected identifier, found keyword `Self`
|
||||
Self!() => (),
|
||||
//~^ ERROR expected identifier, found keyword `Self`
|
||||
//~^^ ERROR macro undefined: 'Self!'
|
||||
Foo { x: Self } => (),
|
||||
//~^ ERROR expected identifier, found keyword `Self`
|
||||
Foo { Self } => (),
|
||||
|
@ -14,6 +14,7 @@ use foo::bar::{
|
||||
Bar,
|
||||
self
|
||||
//~^ NOTE another `self` import appears here
|
||||
//~^^ ERROR a module named `bar` has already been imported in this module
|
||||
};
|
||||
|
||||
use {self};
|
||||
|
Loading…
Reference in New Issue
Block a user