Skip to content

Commit

Permalink
Auto merge of #62467 - Centril:rollup-083tn7t, r=Centril
Browse files Browse the repository at this point in the history
Rollup of 4 pull requests

Successful merges:

 - #61883 (`non_ascii_idents` lint (part of RFC 2457))
 - #62042 (Support stability and deprecation checking for all macros)
 - #62213 (rustdoc: set cfg(doctest) when collecting doctests)
 - #62286 (Check if the archive has already been added to avoid duplicates)

Failed merges:

r? @ghost
  • Loading branch information
bors committed Jul 7, 2019
2 parents dd2e804 + a2500db commit 9210359
Show file tree
Hide file tree
Showing 66 changed files with 679 additions and 438 deletions.
30 changes: 30 additions & 0 deletions src/doc/rustdoc/src/unstable-features.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,36 @@ pub struct BigX;
Then, when looking for it through the `rustdoc` search, if you enter "x" or
"big", search will show the `BigX` struct first.

### Include items only when collecting doctests

Rustdoc's [documentation tests] can do some things that regular unit tests can't, so it can
sometimes be useful to extend your doctests with samples that wouldn't otherwise need to be in
documentation. To this end, Rustdoc allows you to have certain items only appear when it's
collecting doctests, so you can utilize doctest functionality without forcing the test to appear in
docs, or to find an arbitrary private item to include it on.

If you add `#![feature(cfg_doctest)]` to your crate, Rustdoc will set `cfg(doctest)` when collecting
doctests. Note that they will still link against only the public items of your crate; if you need to
test private items, unit tests are still the way to go.

In this example, we're adding doctests that we know won't compile, to verify that our struct can
only take in valid data:

```rust
#![feature(cfg_doctest)]

/// We have a struct here. Remember it doesn't accept negative numbers!
pub struct MyStruct(usize);

/// ```compile_fail
/// let x = my_crate::MyStruct(-5);
/// ```
#[cfg(doctest)]
pub struct MyStructOnlyTakesUsize;
```

[documentation tests]: documentation-tests.html

## Unstable command-line arguments

These features are enabled by passing a command-line flag to Rustdoc, but the flags in question are
Expand Down
5 changes: 5 additions & 0 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ pub struct LoweringContext<'a> {
impl_items: BTreeMap<hir::ImplItemId, hir::ImplItem>,
bodies: BTreeMap<hir::BodyId, hir::Body>,
exported_macros: Vec<hir::MacroDef>,
non_exported_macro_attrs: Vec<ast::Attribute>,

trait_impls: BTreeMap<DefId, Vec<hir::HirId>>,

Expand Down Expand Up @@ -252,6 +253,7 @@ pub fn lower_crate(
trait_impls: BTreeMap::new(),
modules: BTreeMap::new(),
exported_macros: Vec::new(),
non_exported_macro_attrs: Vec::new(),
catch_scopes: Vec::new(),
loop_scopes: Vec::new(),
is_in_loop_condition: false,
Expand Down Expand Up @@ -662,6 +664,7 @@ impl<'a> LoweringContext<'a> {
attrs,
span: c.span,
exported_macros: hir::HirVec::from(self.exported_macros),
non_exported_macro_attrs: hir::HirVec::from(self.non_exported_macro_attrs),
items: self.items,
trait_items: self.trait_items,
impl_items: self.impl_items,
Expand Down Expand Up @@ -4022,6 +4025,8 @@ impl<'a> LoweringContext<'a> {
body,
legacy: def.legacy,
});
} else {
self.non_exported_macro_attrs.extend(attrs.into_iter());
}
return None;
}
Expand Down
1 change: 1 addition & 0 deletions src/librustc/hir/map/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
span,
// These fields are handled separately:
exported_macros: _,
non_exported_macro_attrs: _,
items: _,
trait_items: _,
impl_items: _,
Expand Down
2 changes: 2 additions & 0 deletions src/librustc/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,8 @@ pub struct Crate {
pub attrs: HirVec<Attribute>,
pub span: Span,
pub exported_macros: HirVec<MacroDef>,
// Attributes from non-exported macros, kept only for collecting the library feature list.
pub non_exported_macro_attrs: HirVec<Attribute>,

// N.B., we use a BTreeMap here so that `visit_all_items` iterates
// over the ids in increasing order. In principle it should not
Expand Down
5 changes: 5 additions & 0 deletions src/librustc/lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
//! lints are all available in `rustc_lint::builtin`.

use crate::lint::{LintPass, LateLintPass, LintArray};
use crate::middle::stability;
use crate::session::Session;
use errors::{Applicability, DiagnosticBuilder};
use syntax::ast;
use syntax::source_map::Span;
use syntax::symbol::Symbol;

declare_lint! {
pub EXCEEDING_BITSHIFTS,
Expand Down Expand Up @@ -461,6 +463,7 @@ pub enum BuiltinLintDiagnostics {
UnusedImports(String, Vec<(Span, String)>),
NestedImplTrait { outer_impl_trait_span: Span, inner_impl_trait_span: Span },
RedundantImport(Vec<(Span, bool)>, ast::Ident),
DeprecatedMacro(Option<Symbol>, Span),
}

pub(crate) fn add_elided_lifetime_in_path_suggestion(
Expand Down Expand Up @@ -586,6 +589,8 @@ impl BuiltinLintDiagnostics {
);
}
}
BuiltinLintDiagnostics::DeprecatedMacro(suggestion, span) =>
stability::deprecation_suggestion(db, suggestion, span),
}
}
}
Expand Down
6 changes: 5 additions & 1 deletion src/librustc/middle/lib_features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@ impl Visitor<'tcx> for LibFeatureCollector<'tcx> {

pub fn collect(tcx: TyCtxt<'_>) -> LibFeatures {
let mut collector = LibFeatureCollector::new(tcx);
intravisit::walk_crate(&mut collector, tcx.hir().krate());
let krate = tcx.hir().krate();
for attr in &krate.non_exported_macro_attrs {
collector.visit_attribute(attr);
}
intravisit::walk_crate(&mut collector, krate);
collector.lib_features
}
208 changes: 117 additions & 91 deletions src/librustc/middle/stability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,21 @@
pub use self::StabilityLevel::*;

use crate::lint::{self, Lint, in_derive_expansion};
use crate::lint::builtin::BuiltinLintDiagnostics;
use crate::hir::{self, Item, Generics, StructField, Variant, HirId};
use crate::hir::def::{Res, DefKind};
use crate::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, LOCAL_CRATE};
use crate::hir::intravisit::{self, Visitor, NestedVisitorMap};
use crate::ty::query::Providers;
use crate::middle::privacy::AccessLevels;
use crate::session::{DiagnosticMessageId, Session};
use errors::DiagnosticBuilder;
use syntax::symbol::{Symbol, sym};
use syntax_pos::{Span, MultiSpan};
use syntax::ast::Attribute;
use syntax::ast::{Attribute, CRATE_NODE_ID};
use syntax::errors::Applicability;
use syntax::feature_gate::{GateIssue, emit_feature_err};
use syntax::attr::{self, Stability, Deprecation};
use syntax::attr::{self, Stability, Deprecation, RustcDeprecation};
use crate::ty::{self, TyCtxt};
use crate::util::nodemap::{FxHashSet, FxHashMap};

Expand Down Expand Up @@ -477,6 +479,36 @@ pub fn provide(providers: &mut Providers<'_>) {
};
}

pub fn report_unstable(
sess: &Session, feature: Symbol, reason: Option<Symbol>, issue: u32, span: Span
) {
let msg = match reason {
Some(r) => format!("use of unstable library feature '{}': {}", feature, r),
None => format!("use of unstable library feature '{}'", &feature)
};

let msp: MultiSpan = span.into();
let cm = &sess.parse_sess.source_map();
let span_key = msp.primary_span().and_then(|sp: Span|
if !sp.is_dummy() {
let file = cm.lookup_char_pos(sp.lo()).file;
if file.name.is_macros() {
None
} else {
Some(span)
}
} else {
None
}
);

let error_id = (DiagnosticMessageId::StabilityId(issue), span_key, msg.clone());
let fresh = sess.one_time_diagnostics.borrow_mut().insert(error_id);
if fresh {
emit_feature_err(&sess.parse_sess, feature, span, GateIssue::Library(Some(issue)), &msg);
}
}

/// Checks whether an item marked with `deprecated(since="X")` is currently
/// deprecated (i.e., whether X is not greater than the current rustc version).
pub fn deprecation_in_effect(since: &str) -> bool {
Expand All @@ -501,6 +533,79 @@ pub fn deprecation_in_effect(since: &str) -> bool {
}
}

pub fn deprecation_suggestion(
diag: &mut DiagnosticBuilder<'_>, suggestion: Option<Symbol>, span: Span
) {
if let Some(suggestion) = suggestion {
diag.span_suggestion(
span,
"replace the use of the deprecated item",
suggestion.to_string(),
Applicability::MachineApplicable,
);
}
}

fn deprecation_message_common(message: String, reason: Option<Symbol>) -> String {
match reason {
Some(reason) => format!("{}: {}", message, reason),
None => message,
}
}

pub fn deprecation_message(depr: &Deprecation, path: &str) -> (String, &'static Lint) {
let message = format!("use of deprecated item '{}'", path);
(deprecation_message_common(message, depr.note), lint::builtin::DEPRECATED)
}

pub fn rustc_deprecation_message(depr: &RustcDeprecation, path: &str) -> (String, &'static Lint) {
let (message, lint) = if deprecation_in_effect(&depr.since.as_str()) {
(format!("use of deprecated item '{}'", path), lint::builtin::DEPRECATED)
} else {
(format!("use of item '{}' that will be deprecated in future version {}", path, depr.since),
lint::builtin::DEPRECATED_IN_FUTURE)
};
(deprecation_message_common(message, Some(depr.reason)), lint)
}

pub fn early_report_deprecation(
sess: &Session,
message: &str,
suggestion: Option<Symbol>,
lint: &'static Lint,
span: Span,
) {
if in_derive_expansion(span) {
return;
}

let diag = BuiltinLintDiagnostics::DeprecatedMacro(suggestion, span);
sess.buffer_lint_with_diagnostic(lint, CRATE_NODE_ID, span, message, diag);
}

fn late_report_deprecation(
tcx: TyCtxt<'_>,
message: &str,
suggestion: Option<Symbol>,
lint: &'static Lint,
span: Span,
def_id: DefId,
hir_id: HirId,
) {
if in_derive_expansion(span) {
return;
}

let mut diag = tcx.struct_span_lint_hir(lint, hir_id, span, message);
if let hir::Node::Expr(_) = tcx.hir().get(hir_id) {
deprecation_suggestion(&mut diag, suggestion, span);
}
diag.emit();
if hir_id == hir::DUMMY_HIR_ID {
span_bug!(span, "emitted a {} lint with dummy HIR id: {:?}", lint.name, def_id);
}
}

struct Checker<'tcx> {
tcx: TyCtxt<'tcx>,
}
Expand Down Expand Up @@ -563,38 +668,6 @@ impl<'tcx> TyCtxt<'tcx> {
/// deprecated. If the item is indeed deprecated, we will emit a deprecation lint attached to
/// `id`.
pub fn eval_stability(self, def_id: DefId, id: Option<HirId>, span: Span) -> EvalResult {
let lint_deprecated = |def_id: DefId,
id: HirId,
note: Option<Symbol>,
suggestion: Option<Symbol>,
message: &str,
lint: &'static Lint| {
if in_derive_expansion(span) {
return;
}
let msg = if let Some(note) = note {
format!("{}: {}", message, note)
} else {
format!("{}", message)
};

let mut diag = self.struct_span_lint_hir(lint, id, span, &msg);
if let Some(suggestion) = suggestion {
if let hir::Node::Expr(_) = self.hir().get(id) {
diag.span_suggestion(
span,
"replace the use of the deprecated item",
suggestion.to_string(),
Applicability::MachineApplicable,
);
}
}
diag.emit();
if id == hir::DUMMY_HIR_ID {
span_bug!(span, "emitted a {} lint with dummy HIR id: {:?}", lint.name, def_id);
}
};

// Deprecated attributes apply in-crate and cross-crate.
if let Some(id) = id {
if let Some(depr_entry) = self.lookup_deprecation_entry(def_id) {
Expand All @@ -604,14 +677,9 @@ impl<'tcx> TyCtxt<'tcx> {
.map_or(false, |parent_depr| parent_depr.same_origin(&depr_entry));

if !skip {
let path = self.def_path_str(def_id);
let message = format!("use of deprecated item '{}'", path);
lint_deprecated(def_id,
id,
depr_entry.attr.note,
None,
&message,
lint::builtin::DEPRECATED);
let (message, lint) =
deprecation_message(&depr_entry.attr, &self.def_path_str(def_id));
late_report_deprecation(self, &message, None, lint, span, def_id, id);
}
};
}
Expand All @@ -631,27 +699,11 @@ impl<'tcx> TyCtxt<'tcx> {
if let Some(id) = id {
if let Some(stability) = stability {
if let Some(depr) = &stability.rustc_depr {
let path = self.def_path_str(def_id);
if deprecation_in_effect(&depr.since.as_str()) {
let message = format!("use of deprecated item '{}'", path);
lint_deprecated(def_id,
id,
Some(depr.reason),
depr.suggestion,
&message,
lint::builtin::DEPRECATED);
} else {
let message = format!("use of item '{}' \
that will be deprecated in future version {}",
path,
depr.since);
lint_deprecated(def_id,
id,
Some(depr.reason),
depr.suggestion,
&message,
lint::builtin::DEPRECATED_IN_FUTURE);
}
let (message, lint) =
rustc_deprecation_message(depr, &self.def_path_str(def_id));
late_report_deprecation(
self, &message, depr.suggestion, lint, span, def_id, id
);
}
}
}
Expand Down Expand Up @@ -715,34 +767,8 @@ impl<'tcx> TyCtxt<'tcx> {
pub fn check_stability(self, def_id: DefId, id: Option<HirId>, span: Span) {
match self.eval_stability(def_id, id, span) {
EvalResult::Allow => {}
EvalResult::Deny { feature, reason, issue } => {
let msg = match reason {
Some(r) => format!("use of unstable library feature '{}': {}", feature, r),
None => format!("use of unstable library feature '{}'", &feature)
};

let msp: MultiSpan = span.into();
let cm = &self.sess.parse_sess.source_map();
let span_key = msp.primary_span().and_then(|sp: Span|
if !sp.is_dummy() {
let file = cm.lookup_char_pos(sp.lo()).file;
if file.name.is_macros() {
None
} else {
Some(span)
}
} else {
None
}
);

let error_id = (DiagnosticMessageId::StabilityId(issue), span_key, msg.clone());
let fresh = self.sess.one_time_diagnostics.borrow_mut().insert(error_id);
if fresh {
emit_feature_err(&self.sess.parse_sess, feature, span,
GateIssue::Library(Some(issue)), &msg);
}
}
EvalResult::Deny { feature, reason, issue } =>
report_unstable(self.sess, feature, reason, issue, span),
EvalResult::Unmarked => {
// The API could be uncallable for other reasons, for example when a private module
// was referenced.
Expand Down
Loading

0 comments on commit 9210359

Please sign in to comment.