From dc2e444e506c31e8f4a4331c7f6264ca6c107bb6 Mon Sep 17 00:00:00 2001 From: Joseph Crail Date: Wed, 4 Feb 2015 23:00:02 -0500 Subject: Fix for misspelled comments. The spelling corrections were made in both documentation comments and regular comments. --- src/libsyntax/feature_gate.rs | 2 +- src/libsyntax/parse/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index d7a51e1149f..435713d99d1 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -109,7 +109,7 @@ static KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[ // int and uint are now deprecated ("int_uint", "1.0.0", Active), - // macro reexport needs more discusion and stabilization + // macro reexport needs more discussion and stabilization ("macro_reexport", "1.0.0", Active), // These are used to test this portion of the compiler, they don't actually diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index eecd7d87185..d8a5ef04852 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -560,7 +560,7 @@ fn filtered_float_lit(data: token::InternedString, suffix: Option<&str>, } pub fn float_lit(s: &str, suffix: Option<&str>, sd: &SpanHandler, sp: Span) -> ast::Lit_ { debug!("float_lit: {:?}, {:?}", s, suffix); - // FIXME #2252: bounds checking float literals is defered until trans + // FIXME #2252: bounds checking float literals is deferred until trans let s = s.chars().filter(|&c| c != '_').collect::(); let data = token::intern_and_get_ident(&*s); filtered_float_lit(data, suffix, sd, sp) -- cgit 1.4.1-3-g733a5 From 456d23e73ee5d8c22b67336061ed7b457742d7ff Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 2 Feb 2015 20:25:42 -0800 Subject: Add a lint for writing `#[feature]` for stable features, warn by default. The 'stable_features' lint helps people progress from unstable to stable Rust by telling them when they no longer need a `feature` attribute because upstream Rust has declared it stable. This compares to the existing 'unstable_features', which is used to implement feature staging, and triggers on *any* use of `#[feature]`. --- src/librustc/lint/builtin.rs | 7 ++++ src/librustc/middle/stability.rs | 53 +++++++++++++++++++++--------- src/librustc_driver/driver.rs | 4 +-- src/libsyntax/feature_gate.rs | 15 ++++++--- src/test/compile-fail/gated-bad-feature.rs | 1 - src/test/compile-fail/stable-features.rs | 20 +++++++++++ 6 files changed, 77 insertions(+), 23 deletions(-) create mode 100644 src/test/compile-fail/stable-features.rs (limited to 'src/libsyntax') diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 53054f462c8..685922cea11 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -2018,6 +2018,12 @@ declare_lint! { "unused or unknown features found in crate-level #[feature] directives" } +declare_lint! { + pub STABLE_FEATURES, + Warn, + "stable features found in #[feature] directive" +} + declare_lint! { pub UNKNOWN_CRATE_TYPES, Deny, @@ -2060,6 +2066,7 @@ impl LintPass for HardwiredLints { UNREACHABLE_CODE, WARNINGS, UNUSED_FEATURES, + STABLE_FEATURES, UNKNOWN_CRATE_TYPES, VARIANT_SIZE_DIFFERENCES, FAT_PTR_TRANSMUTES diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 3304bd4ae29..a005ae9c222 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -201,8 +201,9 @@ impl Index { /// Cross-references the feature names of unstable APIs with enabled /// features and possibly prints errors. Returns a list of all /// features used. -pub fn check_unstable_api_usage(tcx: &ty::ctxt) -> FnvHashSet { - let ref active_lib_features = tcx.sess.features.borrow().lib_features; +pub fn check_unstable_api_usage(tcx: &ty::ctxt) + -> FnvHashMap { + let ref active_lib_features = tcx.sess.features.borrow().declared_lib_features; // Put the active features into a map for quick lookup let active_features = active_lib_features.iter().map(|&(ref s, _)| s.clone()).collect(); @@ -210,7 +211,7 @@ pub fn check_unstable_api_usage(tcx: &ty::ctxt) -> FnvHashSet { let mut checker = Checker { tcx: tcx, active_features: active_features, - used_features: FnvHashSet() + used_features: FnvHashMap() }; let krate = tcx.map.krate(); @@ -223,7 +224,7 @@ pub fn check_unstable_api_usage(tcx: &ty::ctxt) -> FnvHashSet { struct Checker<'a, 'tcx: 'a> { tcx: &'a ty::ctxt<'tcx>, active_features: FnvHashSet, - used_features: FnvHashSet + used_features: FnvHashMap } impl<'a, 'tcx> Checker<'a, 'tcx> { @@ -234,7 +235,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { match *stab { Some(Stability { level: attr::Unstable, ref feature, ref reason, .. }) => { - self.used_features.insert(feature.clone()); + self.used_features.insert(feature.clone(), attr::Unstable); if !self.active_features.contains(feature) { let msg = match *reason { @@ -247,7 +248,9 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { feature.get(), span, &msg[]); } } - Some(..) => { + Some(Stability { level, ref feature, .. }) => { + self.used_features.insert(feature.clone(), level); + // Stable APIs are always ok to call and deprecated APIs are // handled by a lint. } @@ -433,17 +436,37 @@ pub fn lookup(tcx: &ty::ctxt, id: DefId) -> Option { /// Given the list of enabled features that were not language features (i.e. that /// were expected to be library features), and the list of features used from /// libraries, identify activated features that don't exist and error about them. -pub fn check_unused_features(sess: &Session, - used_lib_features: &FnvHashSet) { - let ref lib_features = sess.features.borrow().lib_features; - let mut active_lib_features: FnvHashMap - = lib_features.clone().into_iter().collect(); - - for used_feature in used_lib_features { - active_lib_features.remove(used_feature); +pub fn check_unused_or_stable_features(sess: &Session, + lib_features_used: &FnvHashMap) { + let ref declared_lib_features = sess.features.borrow().declared_lib_features; + let mut remaining_lib_features: FnvHashMap + = declared_lib_features.clone().into_iter().collect(); + + let stable_msg = "this feature is stable. attribute no longer needed"; + + for &span in sess.features.borrow().declared_stable_lang_features.iter() { + sess.add_lint(lint::builtin::STABLE_FEATURES, + ast::CRATE_NODE_ID, + span, + stable_msg.to_string()); + } + + for (used_lib_feature, level) in lib_features_used.iter() { + match remaining_lib_features.remove(used_lib_feature) { + Some(span) => { + if *level == attr::Stable { + sess.add_lint(lint::builtin::STABLE_FEATURES, + ast::CRATE_NODE_ID, + span, + stable_msg.to_string()); + } + } + None => ( /* used but undeclared, handled during the previous ast visit */ ) + } } - for (_, &span) in &active_lib_features { + for (_, &span) in remaining_lib_features.iter() { sess.add_lint(lint::builtin::UNUSED_FEATURES, ast::CRATE_NODE_ID, span, diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 8ede037594a..8c89f66f7a1 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -668,8 +668,8 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session, time(time_passes, "stability checking", (), |_| stability::check_unstable_api_usage(&ty_cx)); - time(time_passes, "unused feature checking", (), |_| - stability::check_unused_features( + time(time_passes, "unused lib feature checking", (), |_| + stability::check_unused_or_stable_features( &ty_cx.sess, lib_features_used)); time(time_passes, "lint checking", (), |_| diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index d7a51e1149f..59cdb15296a 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -149,7 +149,10 @@ pub struct Features { pub old_orphan_check: bool, pub simd_ffi: bool, pub unmarked_api: bool, - pub lib_features: Vec<(InternedString, Span)> + /// spans of #![feature] attrs for stable language features. for error reporting + pub declared_stable_lang_features: Vec, + /// #![feature] attrs for non-language (library) features + pub declared_lib_features: Vec<(InternedString, Span)> } impl Features { @@ -162,7 +165,8 @@ impl Features { old_orphan_check: false, simd_ffi: false, unmarked_api: false, - lib_features: Vec::new() + declared_stable_lang_features: Vec::new(), + declared_lib_features: Vec::new() } } } @@ -511,6 +515,7 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::C cm: cm, }; + let mut accepted_features = Vec::new(); let mut unknown_features = Vec::new(); for attr in &krate.attrs { @@ -550,8 +555,7 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::C span_handler.span_err(mi.span, "feature has been removed"); } Some(&(_, _, Accepted)) => { - span_handler.span_warn(mi.span, "feature has been added to Rust, \ - directive not necessary"); + accepted_features.push(mi.span); } None => { unknown_features.push((name, mi.span)); @@ -572,7 +576,8 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::C old_orphan_check: cx.has_feature("old_orphan_check"), simd_ffi: cx.has_feature("simd_ffi"), unmarked_api: cx.has_feature("unmarked_api"), - lib_features: unknown_features + declared_stable_lang_features: accepted_features, + declared_lib_features: unknown_features } } diff --git a/src/test/compile-fail/gated-bad-feature.rs b/src/test/compile-fail/gated-bad-feature.rs index 39cd3e3b86a..5baafd41531 100644 --- a/src/test/compile-fail/gated-bad-feature.rs +++ b/src/test/compile-fail/gated-bad-feature.rs @@ -20,4 +20,3 @@ #![feature = "foo"] //~ ERROR: malformed feature #![feature(test_removed_feature)] //~ ERROR: feature has been removed -#![feature(test_accepted_feature)] //~ WARNING: feature has been added diff --git a/src/test/compile-fail/stable-features.rs b/src/test/compile-fail/stable-features.rs new file mode 100644 index 00000000000..30eb4112c3f --- /dev/null +++ b/src/test/compile-fail/stable-features.rs @@ -0,0 +1,20 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Testing that the stable_features lint catches use of stable +// language and lib features. + +#![deny(stable_features)] +#![feature(test_accepted_feature)] //~ ERROR this feature is stable +#![feature(rust1)] //~ ERROR this feature is stable + +fn main() { + let _foo: Vec<()> = Vec::new(); +} -- cgit 1.4.1-3-g733a5 From fa9d2230a65689289f64c897ad30c83251762320 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 5 Feb 2015 16:02:22 +0100 Subject: make codemap more robust in face of ill-formed spans. This can be considered partial work on #8256. The main observable change: macro expansion sometimes results in spans where `lo > hi`; so for now, when we have such a span, do not attempt to return a snippet result. (Longer term, we might think about whether we could still present a snippet for the cases where this arises, e.g. perhaps by showing the whole macro as the snippet, assuming that is the sole cause of such spans; or by somehow looking up the closest AST node that holds both `lo` and `hi`, and showing that.) As a drive-by, revised the API to return a `Result` rather than an `Option`, with better information-packed error value that should help us (and maybe also our users) identify the causes of such problems in the future. Ideally the call-sites that really want an actual snippet would be updated to catch the newly added `Err` case and print something meaningful about it, but that is not part of this PR. --- src/librustc_trans/save/span_utils.rs | 4 +-- src/librustc_trans/trans/debuginfo.rs | 2 +- src/librustdoc/clean/mod.rs | 4 +-- src/libsyntax/codemap.rs | 54 +++++++++++++++++++++++++++++------ src/libsyntax/parse/mod.rs | 4 +-- 5 files changed, 53 insertions(+), 15 deletions(-) (limited to 'src/libsyntax') diff --git a/src/librustc_trans/save/span_utils.rs b/src/librustc_trans/save/span_utils.rs index beec8071a72..a724cdc0229 100644 --- a/src/librustc_trans/save/span_utils.rs +++ b/src/librustc_trans/save/span_utils.rs @@ -69,8 +69,8 @@ impl<'a> SpanUtils<'a> { pub fn snippet(&self, span: Span) -> String { match self.sess.codemap().span_to_snippet(span) { - Some(s) => s, - None => String::new(), + Ok(s) => s, + Err(_) => String::new(), } } diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index 1e788351172..4d4a2bf4854 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -1094,7 +1094,7 @@ pub fn get_cleanup_debug_loc_for_ast_node<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // bodies), in which case we also just want to return the span of the // whole expression. let code_snippet = cx.sess().codemap().span_to_snippet(node_span); - if let Some(code_snippet) = code_snippet { + if let Ok(code_snippet) = code_snippet { let bytes = code_snippet.as_bytes(); if bytes.len() > 0 && &bytes[bytes.len()-1..] == b"}" { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 248ce99ff9b..611251d4cfa 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2301,8 +2301,8 @@ impl ToSource for syntax::codemap::Span { fn to_src(&self, cx: &DocContext) -> String { debug!("converting span {:?} to snippet", self.clean(cx)); let sn = match cx.sess().codemap().span_to_snippet(*self) { - Some(x) => x.to_string(), - None => "".to_string() + Ok(x) => x.to_string(), + Err(_) => "".to_string() }; debug!("got snippet {}", sn); sn diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 00857d10f43..3231342cb50 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -437,18 +437,35 @@ impl CodeMap { FileLines {file: lo.file, lines: lines} } - pub fn span_to_snippet(&self, sp: Span) -> Option { + pub fn span_to_snippet(&self, sp: Span) -> Result { + if sp.lo > sp.hi { + return Err(SpanSnippetError::IllFormedSpan(sp)); + } + let begin = self.lookup_byte_offset(sp.lo); let end = self.lookup_byte_offset(sp.hi); - // FIXME #8256: this used to be an assert but whatever precondition - // it's testing isn't true for all spans in the AST, so to allow the - // caller to not have to panic (and it can't catch it since the CodeMap - // isn't sendable), return None if begin.fm.start_pos != end.fm.start_pos { - None + return Err(SpanSnippetError::DistinctSources(DistinctSources { + begin: (begin.fm.name.clone(), + begin.fm.start_pos), + end: (end.fm.name.clone(), + end.fm.start_pos) + })); } else { - Some((&begin.fm.src[begin.pos.to_usize()..end.pos.to_usize()]).to_string()) + let start = begin.pos.to_usize(); + let limit = end.pos.to_usize(); + if start > limit || limit > begin.fm.src.len() { + return Err(SpanSnippetError::MalformedForCodemap( + MalformedCodemapPositions { + name: begin.fm.name.clone(), + source_len: begin.fm.src.len(), + begin_pos: begin.pos, + end_pos: end.pos, + })); + } + + return Ok((&begin.fm.src[start..limit]).to_string()) } } @@ -622,6 +639,27 @@ impl CodeMap { } } +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum SpanSnippetError { + IllFormedSpan(Span), + DistinctSources(DistinctSources), + MalformedForCodemap(MalformedCodemapPositions), +} + +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct DistinctSources { + begin: (String, BytePos), + end: (String, BytePos) +} + +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct MalformedCodemapPositions { + name: String, + source_len: usize, + begin_pos: BytePos, + end_pos: BytePos +} + #[cfg(test)] mod test { use super::*; @@ -773,7 +811,7 @@ mod test { let span = Span {lo: BytePos(12), hi: BytePos(23), expn_id: NO_EXPANSION}; let snippet = cm.span_to_snippet(span); - assert_eq!(snippet, Some("second line".to_string())); + assert_eq!(snippet, Ok("second line".to_string())); } #[test] diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 6ff5c77f507..9e9ec08da03 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -1233,8 +1233,8 @@ mod test { let span = tts.iter().rev().next().unwrap().get_span(); match sess.span_diagnostic.cm.span_to_snippet(span) { - Some(s) => assert_eq!(&s[], "{ body }"), - None => panic!("could not get snippet"), + Ok(s) => assert_eq!(&s[], "{ body }"), + Err(_) => panic!("could not get snippet"), } } } -- cgit 1.4.1-3-g733a5 From 1589dcf944939cf0ca5e74b737c874f43bdbdc83 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 6 Feb 2015 16:24:13 +0200 Subject: Remove word syntax from obsolete syntax messages The word is repeated twice in the message like error: obsolete syntax: `:`, `&mut:`, or `&:` syntax This removes the word syntax that appears in messages after the second colon (:). --- src/libsyntax/parse/obsolete.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs index 60de6c909b7..1df2e762ee7 100644 --- a/src/libsyntax/parse/obsolete.rs +++ b/src/libsyntax/parse/obsolete.rs @@ -63,15 +63,15 @@ impl<'a> ParserObsoleteMethods for parser::Parser<'a> { "use a `move ||` expression instead", ), ObsoleteSyntax::ClosureType => ( - "`|usize| -> bool` closure type syntax", + "`|usize| -> bool` closure type", "use unboxed closures instead, no type annotation needed" ), ObsoleteSyntax::ClosureKind => ( - "`:`, `&mut:`, or `&:` syntax", + "`:`, `&mut:`, or `&:`", "rely on inference instead" ), ObsoleteSyntax::Sized => ( - "`Sized? T` syntax for removing the `Sized` bound", + "`Sized? T` for removing the `Sized` bound", "write `T: ?Sized` instead" ), }; -- cgit 1.4.1-3-g733a5