Auto merge of #88824 - Manishearth:rollup-7bzk9h6, r=Manishearth

Rollup of 15 pull requests

Successful merges:

 - #85200 (Ignore derived Clone and Debug implementations during dead code analysis)
 - #86165 (Add proc_macro::Span::{before, after}.)
 - #87088 (Fix stray notes when the source code is not available)
 - #87441 (Emit suggestion when passing byte literal to format macro)
 - #88546 (Emit proper errors when on missing closure braces)
 - #88578 (fix(rustc): suggest `items` be borrowed in `for i in items[x..]`)
 - #88632 (Fix issues with Markdown summary options)
 - #88639 (rustdoc: Fix ICE with `doc(hidden)` on tuple variant fields)
 - #88667 (Tweak `write_fmt` doc.)
 - #88720 (Rustdoc coverage fields count)
 - #88732 (RustWrapper: avoid deleted unclear attribute methods)
 - #88742 (Fix table in docblocks)
 - #88776 (Workaround blink/chromium grid layout limitation of 1000 rows)
 - #88807 (Fix typo in docs for iterators)
 - #88812 (Fix typo `option` -> `options`.)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2021-09-11 03:30:55 +00:00
commit 22719efcc5
93 changed files with 976 additions and 212 deletions

View file

@ -218,7 +218,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
);
if self.fn_self_span_reported.insert(fn_span) {
err.span_note(
self_arg.span,
// Check whether the source is accessible
if self
.infcx
.tcx
.sess
.source_map()
.span_to_snippet(self_arg.span)
.is_ok()
{
self_arg.span
} else {
fn_call_span
},
"calling this operator moves the left-hand side",
);
}
@ -429,7 +441,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
deref_target_ty
));
err.span_note(deref_target, "deref defined here");
// Check first whether the source is accessible (issue #87060)
if self.infcx.tcx.sess.source_map().span_to_snippet(deref_target).is_ok() {
err.span_note(deref_target, "deref defined here");
}
}
if let Some((_, mut old_err)) =

View file

@ -510,7 +510,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
match expr_to_spanned_string(ecx, template_expr, msg) {
Ok(template_part) => template_part,
Err(err) => {
if let Some(mut err) = err {
if let Some((mut err, _)) = err {
err.emit();
}
return None;

View file

@ -964,17 +964,19 @@ pub fn expand_preparsed_format_args(
}
Ok(fmt) => fmt,
Err(err) => {
if let Some(mut err) = err {
if let Some((mut err, suggested)) = err {
let sugg_fmt = match args.len() {
0 => "{}".to_string(),
_ => format!("{}{{}}", "{} ".repeat(args.len())),
};
err.span_suggestion(
fmt_sp.shrink_to_lo(),
"you might be missing a string literal to format with",
format!("\"{}\", ", sugg_fmt),
Applicability::MaybeIncorrect,
);
if !suggested {
err.span_suggestion(
fmt_sp.shrink_to_lo(),
"you might be missing a string literal to format with",
format!("\"{}\", ", sugg_fmt),
Applicability::MaybeIncorrect,
);
}
err.emit();
}
return DummyResult::raw_expr(sp, true);

View file

@ -10,7 +10,7 @@ use rustc_ast::{self as ast, AstLike, Attribute, Item, NodeId, PatKind};
use rustc_attr::{self as attr, Deprecation, Stability};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::{self, Lrc};
use rustc_errors::{DiagnosticBuilder, ErrorReported};
use rustc_errors::{Applicability, DiagnosticBuilder, ErrorReported};
use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT;
use rustc_lint_defs::BuiltinLintDiagnostics;
use rustc_parse::{self, nt_to_tokenstream, parser, MACRO_ARGUMENTS};
@ -1136,13 +1136,15 @@ impl<'a> ExtCtxt<'a> {
}
/// Extracts a string literal from the macro expanded version of `expr`,
/// emitting `err_msg` if `expr` is not a string literal. This does not stop
/// compilation on error, merely emits a non-fatal error and returns `None`.
/// returning a diagnostic error of `err_msg` if `expr` is not a string literal.
/// The returned bool indicates whether an applicable suggestion has already been
/// added to the diagnostic to avoid emitting multiple suggestions. `Err(None)`
/// indicates that an ast error was encountered.
pub fn expr_to_spanned_string<'a>(
cx: &'a mut ExtCtxt<'_>,
expr: P<ast::Expr>,
err_msg: &str,
) -> Result<(Symbol, ast::StrStyle, Span), Option<DiagnosticBuilder<'a>>> {
) -> Result<(Symbol, ast::StrStyle, Span), Option<(DiagnosticBuilder<'a>, bool)>> {
// Perform eager expansion on the expression.
// We want to be able to handle e.g., `concat!("foo", "bar")`.
let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr();
@ -1150,14 +1152,27 @@ pub fn expr_to_spanned_string<'a>(
Err(match expr.kind {
ast::ExprKind::Lit(ref l) => match l.kind {
ast::LitKind::Str(s, style) => return Ok((s, style, expr.span)),
ast::LitKind::ByteStr(_) => {
let mut err = cx.struct_span_err(l.span, err_msg);
err.span_suggestion(
expr.span.shrink_to_lo(),
"consider removing the leading `b`",
String::new(),
Applicability::MaybeIncorrect,
);
Some((err, true))
}
ast::LitKind::Err(_) => None,
_ => Some(cx.struct_span_err(l.span, err_msg)),
_ => Some((cx.struct_span_err(l.span, err_msg), false)),
},
ast::ExprKind::Err => None,
_ => Some(cx.struct_span_err(expr.span, err_msg)),
_ => Some((cx.struct_span_err(expr.span, err_msg), false)),
})
}
/// Extracts a string literal from the macro expanded version of `expr`,
/// emitting `err_msg` if `expr` is not a string literal. This does not stop
/// compilation on error, merely emits a non-fatal error and returns `None`.
pub fn expr_to_string(
cx: &mut ExtCtxt<'_>,
expr: P<ast::Expr>,
@ -1165,7 +1180,7 @@ pub fn expr_to_string(
) -> Option<(Symbol, ast::StrStyle)> {
expr_to_spanned_string(cx, expr, err_msg)
.map_err(|err| {
err.map(|mut err| {
err.map(|(mut err, _)| {
err.emit();
})
})

View file

@ -758,6 +758,12 @@ impl server::Span for Rustc<'_> {
let loc = self.sess.source_map().lookup_char_pos(span.hi());
LineColumn { line: loc.line, column: loc.col.to_usize() }
}
fn before(&mut self, span: Self::Span) -> Self::Span {
span.shrink_to_lo()
}
fn after(&mut self, span: Self::Span) -> Self::Span {
span.shrink_to_hi()
}
fn join(&mut self, first: Self::Span, second: Self::Span) -> Option<Self::Span> {
let self_loc = self.sess.source_map().lookup_char_pos(first.lo());
let other_loc = self.sess.source_map().lookup_char_pos(second.lo());

View file

@ -16,7 +16,6 @@ macro_rules! declare_features {
since: $ver,
issue: to_nonzero($issue),
edition: None,
description: concat!($($doc,)*),
}
),+
];

View file

@ -37,7 +37,6 @@ macro_rules! declare_features {
since: $ver,
issue: to_nonzero($issue),
edition: $edition,
description: concat!($($doc,)*),
}
),+];

View file

@ -453,6 +453,9 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
),
// Enumerates "identity-like" conversion methods to suggest on type mismatch.
rustc_attr!(rustc_conversion_suggestion, Normal, template!(Word), INTERNAL_UNSTABLE),
// Prevents field reads in the marked trait or method to be considered
// during dead code analysis.
rustc_attr!(rustc_trivial_field_reads, Normal, template!(Word), INTERNAL_UNSTABLE),
// ==========================================================================
// Internal attributes, Const related:

View file

@ -51,7 +51,6 @@ pub struct Feature {
pub since: &'static str,
issue: Option<NonZeroU32>,
pub edition: Option<Edition>,
description: &'static str,
}
#[derive(Copy, Clone, Debug)]

View file

@ -16,7 +16,6 @@ macro_rules! declare_features {
since: $ver,
issue: to_nonzero($issue),
edition: None,
description: concat!($($doc,)*),
}
),+
];
@ -34,7 +33,6 @@ macro_rules! declare_features {
since: $ver,
issue: to_nonzero($issue),
edition: None,
description: concat!($($doc,)*),
}
),+
];

View file

@ -203,56 +203,57 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
report_fatal_error("bad AttributeKind");
}
template<typename T> static inline void AddAttribute(T *t, unsigned Index, Attribute Attr) {
#if LLVM_VERSION_LT(14, 0)
t->addAttribute(Index, Attr);
#else
t->addAttributeAtIndex(Index, Attr);
#endif
}
extern "C" void LLVMRustAddCallSiteAttribute(LLVMValueRef Instr, unsigned Index,
LLVMRustAttribute RustAttr) {
CallBase *Call = unwrap<CallBase>(Instr);
Attribute Attr = Attribute::get(Call->getContext(), fromRust(RustAttr));
Call->addAttribute(Index, Attr);
AddAttribute(Call, Index, Attr);
}
extern "C" void LLVMRustAddCallSiteAttrString(LLVMValueRef Instr, unsigned Index,
const char *Name) {
CallBase *Call = unwrap<CallBase>(Instr);
Attribute Attr = Attribute::get(Call->getContext(), Name);
Call->addAttribute(Index, Attr);
AddAttribute(Call, Index, Attr);
}
extern "C" void LLVMRustAddAlignmentCallSiteAttr(LLVMValueRef Instr,
unsigned Index,
uint32_t Bytes) {
CallBase *Call = unwrap<CallBase>(Instr);
AttrBuilder B;
B.addAlignmentAttr(Bytes);
Call->setAttributes(Call->getAttributes().addAttributes(
Call->getContext(), Index, B));
Attribute Attr = Attribute::getWithAlignment(Call->getContext(), Align(Bytes));
AddAttribute(Call, Index, Attr);
}
extern "C" void LLVMRustAddDereferenceableCallSiteAttr(LLVMValueRef Instr,
unsigned Index,
uint64_t Bytes) {
CallBase *Call = unwrap<CallBase>(Instr);
AttrBuilder B;
B.addDereferenceableAttr(Bytes);
Call->setAttributes(Call->getAttributes().addAttributes(
Call->getContext(), Index, B));
Attribute Attr = Attribute::getWithDereferenceableBytes(Call->getContext(), Bytes);
AddAttribute(Call, Index, Attr);
}
extern "C" void LLVMRustAddDereferenceableOrNullCallSiteAttr(LLVMValueRef Instr,
unsigned Index,
uint64_t Bytes) {
CallBase *Call = unwrap<CallBase>(Instr);
AttrBuilder B;
B.addDereferenceableOrNullAttr(Bytes);
Call->setAttributes(Call->getAttributes().addAttributes(
Call->getContext(), Index, B));
Attribute Attr = Attribute::getWithDereferenceableOrNullBytes(Call->getContext(), Bytes);
AddAttribute(Call, Index, Attr);
}
extern "C" void LLVMRustAddByValCallSiteAttr(LLVMValueRef Instr, unsigned Index,
LLVMTypeRef Ty) {
CallBase *Call = unwrap<CallBase>(Instr);
Attribute Attr = Attribute::getWithByValType(Call->getContext(), unwrap(Ty));
Call->addAttribute(Index, Attr);
AddAttribute(Call, Index, Attr);
}
extern "C" void LLVMRustAddStructRetCallSiteAttr(LLVMValueRef Instr, unsigned Index,
@ -263,28 +264,28 @@ extern "C" void LLVMRustAddStructRetCallSiteAttr(LLVMValueRef Instr, unsigned In
#else
Attribute Attr = Attribute::get(Call->getContext(), Attribute::StructRet);
#endif
Call->addAttribute(Index, Attr);
AddAttribute(Call, Index, Attr);
}
extern "C" void LLVMRustAddFunctionAttribute(LLVMValueRef Fn, unsigned Index,
LLVMRustAttribute RustAttr) {
Function *A = unwrap<Function>(Fn);
Attribute Attr = Attribute::get(A->getContext(), fromRust(RustAttr));
A->addAttribute(Index, Attr);
AddAttribute(A, Index, Attr);
}
extern "C" void LLVMRustAddAlignmentAttr(LLVMValueRef Fn,
unsigned Index,
uint32_t Bytes) {
Function *A = unwrap<Function>(Fn);
A->addAttribute(Index, Attribute::getWithAlignment(
AddAttribute(A, Index, Attribute::getWithAlignment(
A->getContext(), llvm::Align(Bytes)));
}
extern "C" void LLVMRustAddDereferenceableAttr(LLVMValueRef Fn, unsigned Index,
uint64_t Bytes) {
Function *A = unwrap<Function>(Fn);
A->addAttribute(Index, Attribute::getWithDereferenceableBytes(A->getContext(),
AddAttribute(A, Index, Attribute::getWithDereferenceableBytes(A->getContext(),
Bytes));
}
@ -292,7 +293,7 @@ extern "C" void LLVMRustAddDereferenceableOrNullAttr(LLVMValueRef Fn,
unsigned Index,
uint64_t Bytes) {
Function *A = unwrap<Function>(Fn);
A->addAttribute(Index, Attribute::getWithDereferenceableOrNullBytes(
AddAttribute(A, Index, Attribute::getWithDereferenceableOrNullBytes(
A->getContext(), Bytes));
}
@ -300,7 +301,7 @@ extern "C" void LLVMRustAddByValAttr(LLVMValueRef Fn, unsigned Index,
LLVMTypeRef Ty) {
Function *F = unwrap<Function>(Fn);
Attribute Attr = Attribute::getWithByValType(F->getContext(), unwrap(Ty));
F->addAttribute(Index, Attr);
AddAttribute(F, Index, Attr);
}
extern "C" void LLVMRustAddStructRetAttr(LLVMValueRef Fn, unsigned Index,
@ -311,7 +312,7 @@ extern "C" void LLVMRustAddStructRetAttr(LLVMValueRef Fn, unsigned Index,
#else
Attribute Attr = Attribute::get(F->getContext(), Attribute::StructRet);
#endif
F->addAttribute(Index, Attr);
AddAttribute(F, Index, Attr);
}
extern "C" void LLVMRustAddFunctionAttrStringValue(LLVMValueRef Fn,
@ -319,7 +320,7 @@ extern "C" void LLVMRustAddFunctionAttrStringValue(LLVMValueRef Fn,
const char *Name,
const char *Value) {
Function *F = unwrap<Function>(Fn);
F->addAttribute(Index, Attribute::get(
AddAttribute(F, Index, Attribute::get(
F->getContext(), StringRef(Name), StringRef(Value)));
}
@ -330,7 +331,12 @@ extern "C" void LLVMRustRemoveFunctionAttributes(LLVMValueRef Fn,
Attribute Attr = Attribute::get(F->getContext(), fromRust(RustAttr));
AttrBuilder B(Attr);
auto PAL = F->getAttributes();
auto PALNew = PAL.removeAttributes(F->getContext(), Index, B);
AttributeList PALNew;
#if LLVM_VERSION_LT(14, 0)
PALNew = PAL.removeAttributes(F->getContext(), Index, B);
#else
PALNew = PAL.removeAttributesAtIndex(F->getContext(), Index, B);
#endif
F->setAttributes(PALNew);
}

View file

@ -62,13 +62,6 @@ fn hash_body(
stable_hasher.finish()
}
/// Represents an entry and its parent `HirId`.
#[derive(Copy, Clone, Debug)]
pub struct Entry<'hir> {
parent: HirId,
node: Node<'hir>,
}
impl<'a, 'hir> NodeCollector<'a, 'hir> {
pub(super) fn root(
sess: &'a Session,

View file

@ -28,7 +28,6 @@ fn compute_ignored_attr_names() -> FxHashSet<Symbol> {
/// things (e.g., each `DefId`/`DefPath` is only hashed once).
#[derive(Clone)]
pub struct StableHashingContext<'a> {
sess: &'a Session,
definitions: &'a Definitions,
cstore: &'a dyn CrateStore,
pub(super) body_resolver: BodyResolver<'a>,
@ -78,7 +77,6 @@ impl<'a> StableHashingContext<'a> {
!always_ignore_spans && !sess.opts.debugging_opts.incremental_ignore_spans;
StableHashingContext {
sess,
body_resolver: BodyResolver(krate),
definitions,
cstore,

View file

@ -900,10 +900,7 @@ fn traverse_candidate<'pat, 'tcx: 'pat, C, T, I>(
struct Binding<'tcx> {
span: Span,
source: Place<'tcx>,
name: Symbol,
var_id: HirId,
var_ty: Ty<'tcx>,
mutability: Mutability,
binding_mode: BindingMode,
}

View file

@ -176,17 +176,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
Ok(())
}
PatKind::Binding { name, mutability, mode, var, ty, ref subpattern, is_primary: _ } => {
PatKind::Binding {
name: _,
mutability: _,
mode,
var,
ty: _,
ref subpattern,
is_primary: _,
} => {
if let Ok(place_resolved) =
match_pair.place.clone().try_upvars_resolved(self.tcx, self.typeck_results)
{
candidate.bindings.push(Binding {
name,
mutability,
span: match_pair.pattern.span,
source: place_resolved.into_place(self.tcx, self.typeck_results),
var_id: var,
var_ty: ty,
binding_mode: mode,
});
}

View file

@ -118,9 +118,6 @@ struct Scope {
/// the region span of this scope within source code.
region_scope: region::Scope,
/// the span of that region_scope
region_scope_span: Span,
/// set of places to drop when exiting this scope. This starts
/// out empty but grows as variables are declared during the
/// building process. This is a stack, so we always drop from the
@ -420,7 +417,6 @@ impl<'tcx> Scopes<'tcx> {
self.scopes.push(Scope {
source_scope: vis_scope,
region_scope: region_scope.0,
region_scope_span: region_scope.1.span,
drops: vec![],
moved_locals: vec![],
cached_unwind_block: None,

View file

@ -263,7 +263,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
}
if let Err(e) = result {
bug!("Error processing: {:?}: {:?}", self.mir_body.source.def_id(), e)
bug!("Error processing: {:?}: {:?}", self.mir_body.source.def_id(), e.message)
};
// Depending on current `debug_options()`, `alert_on_unused_expressions()` could panic, so

View file

@ -1,9 +1,12 @@
use super::pat::{RecoverColon, RecoverComma, PARAM_EXPECTED};
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
use super::{AttrWrapper, BlockMode, ForceCollect, Parser, PathStyle, Restrictions, TokenType};
use super::{
AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Restrictions, TokenType,
};
use super::{SemiColonMode, SeqSep, TokenExpectType, TrailingToken};
use crate::maybe_recover_from_interpolated_ty_qpath;
use ast::token::DelimToken;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Token, TokenKind};
use rustc_ast::tokenstream::Spacing;
@ -91,6 +94,8 @@ impl<'a> Parser<'a> {
/// Parses an expression.
#[inline]
pub fn parse_expr(&mut self) -> PResult<'a, P<Expr>> {
self.current_closure.take();
self.parse_expr_res(Restrictions::empty(), None)
}
@ -1736,7 +1741,7 @@ impl<'a> Parser<'a> {
let capture_clause = self.parse_capture_clause()?;
let decl = self.parse_fn_block_decl()?;
let decl_hi = self.prev_token.span;
let body = match decl.output {
let mut body = match decl.output {
FnRetTy::Default(_) => {
let restrictions = self.restrictions - Restrictions::STMT_EXPR;
self.parse_expr_res(restrictions, None)?
@ -1753,11 +1758,28 @@ impl<'a> Parser<'a> {
self.sess.gated_spans.gate(sym::async_closure, span);
}
Ok(self.mk_expr(
if self.token.kind == TokenKind::Semi && self.token_cursor.frame.delim == DelimToken::Paren
{
// It is likely that the closure body is a block but where the
// braces have been removed. We will recover and eat the next
// statements later in the parsing process.
body = self.mk_expr_err(body.span);
}
let body_span = body.span;
let closure = self.mk_expr(
lo.to(body.span),
ExprKind::Closure(capture_clause, asyncness, movability, decl, body, lo.to(decl_hi)),
attrs,
))
);
// Disable recovery for closure body
let spans =
ClosureSpans { whole_closure: closure.span, closing_pipe: decl_hi, body: body_span };
self.current_closure = Some(spans);
Ok(closure)
}
/// Parses an optional `move` prefix to a closure-like construct.

View file

@ -142,6 +142,17 @@ pub struct Parser<'a> {
/// If present, this `Parser` is not parsing Rust code but rather a macro call.
subparser_name: Option<&'static str>,
capture_state: CaptureState,
/// This allows us to recover when the user forget to add braces around
/// multiple statements in the closure body.
pub current_closure: Option<ClosureSpans>,
}
/// Stores span informations about a closure.
#[derive(Clone)]
pub struct ClosureSpans {
pub whole_closure: Span,
pub closing_pipe: Span,
pub body: Span,
}
/// Indicates a range of tokens that should be replaced by
@ -440,6 +451,7 @@ impl<'a> Parser<'a> {
replace_ranges: Vec::new(),
inner_attr_ranges: Default::default(),
},
current_closure: None,
};
// Make parser point to the first token.
@ -761,8 +773,11 @@ impl<'a> Parser<'a> {
first = false;
} else {
match self.expect(t) {
Ok(false) => {}
Ok(false) => {
self.current_closure.take();
}
Ok(true) => {
self.current_closure.take();
recovered = true;
break;
}
@ -770,10 +785,29 @@ impl<'a> Parser<'a> {
let sp = self.prev_token.span.shrink_to_hi();
let token_str = pprust::token_kind_to_string(t);
// Attempt to keep parsing if it was a similar separator.
if let Some(ref tokens) = t.similar_tokens() {
if tokens.contains(&self.token.kind) && !unclosed_delims {
self.bump();
match self.current_closure.take() {
Some(closure_spans) if self.token.kind == TokenKind::Semi => {
// Finding a semicolon instead of a comma
// after a closure body indicates that the
// closure body may be a block but the user
// forgot to put braces around its
// statements.
self.recover_missing_braces_around_closure_body(
closure_spans,
expect_err,
)?;
continue;
}
_ => {
// Attempt to keep parsing if it was a similar separator.
if let Some(ref tokens) = t.similar_tokens() {
if tokens.contains(&self.token.kind) && !unclosed_delims {
self.bump();
}
}
}
}
@ -839,6 +873,65 @@ impl<'a> Parser<'a> {
Ok((v, trailing, recovered))
}
fn recover_missing_braces_around_closure_body(
&mut self,
closure_spans: ClosureSpans,
mut expect_err: DiagnosticBuilder<'_>,
) -> PResult<'a, ()> {
let initial_semicolon = self.token.span;
while self.eat(&TokenKind::Semi) {
let _ = self.parse_stmt(ForceCollect::Yes)?;
}
expect_err.set_primary_message(
"closure bodies that contain statements must be surrounded by braces",
);
let preceding_pipe_span = closure_spans.closing_pipe;
let following_token_span = self.token.span;
let mut first_note = MultiSpan::from(vec![initial_semicolon]);
first_note.push_span_label(
initial_semicolon,
"this `;` turns the preceding closure into a statement".to_string(),
);
first_note.push_span_label(
closure_spans.body,
"this expression is a statement because of the trailing semicolon".to_string(),
);
expect_err.span_note(first_note, "statement found outside of a block");
let mut second_note = MultiSpan::from(vec![closure_spans.whole_closure]);
second_note.push_span_label(
closure_spans.whole_closure,
"this is the parsed closure...".to_string(),
);
second_note.push_span_label(
following_token_span,
"...but likely you meant the closure to end here".to_string(),
);
expect_err.span_note(second_note, "the closure body may be incorrectly delimited");
expect_err.set_span(vec![preceding_pipe_span, following_token_span]);
let opening_suggestion_str = " {".to_string();
let closing_suggestion_str = "}".to_string();
expect_err.multipart_suggestion(
"try adding braces",
vec![
(preceding_pipe_span.shrink_to_hi(), opening_suggestion_str),
(following_token_span.shrink_to_lo(), closing_suggestion_str),
],
Applicability::MaybeIncorrect,
);
expect_err.emit();
Ok(())
}
/// Parses a sequence, not including the closing delimiter. The function
/// `f` must consume tokens until reaching the next separator or
/// closing bracket.

View file

@ -239,7 +239,69 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
}
}
/// Automatically generated items marked with `rustc_trivial_field_reads`
/// will be ignored for the purposes of dead code analysis (see PR #85200
/// for discussion).
fn should_ignore_item(&self, def_id: DefId) -> bool {
if !self.tcx.has_attr(def_id, sym::automatically_derived)
&& !self
.tcx
.impl_of_method(def_id)
.map_or(false, |impl_id| self.tcx.has_attr(impl_id, sym::automatically_derived))
{
return false;
}
let has_attr = |def_id| self.tcx.has_attr(def_id, sym::rustc_trivial_field_reads);
if has_attr(def_id) {
return true;
}
if let Some(impl_of) = self.tcx.impl_of_method(def_id) {
if has_attr(impl_of) {
return true;
}
if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of) {
if has_attr(trait_of) {
return true;
}
if let Some(method_ident) = self.tcx.opt_item_name(def_id) {
if let Some(trait_method) = self
.tcx
.associated_items(trait_of)
.find_by_name_and_kind(self.tcx, method_ident, ty::AssocKind::Fn, trait_of)
{
if has_attr(trait_method.def_id) {
return true;
}
}
}
}
} else if let Some(trait_of) = self.tcx.trait_of_item(def_id) {
if has_attr(trait_of) {
return true;
}
}
return false;
}
fn visit_node(&mut self, node: Node<'tcx>) {
if let Some(item_def_id) = match node {
Node::Item(hir::Item { def_id, .. })
| Node::ForeignItem(hir::ForeignItem { def_id, .. })
| Node::TraitItem(hir::TraitItem { def_id, .. })
| Node::ImplItem(hir::ImplItem { def_id, .. }) => Some(def_id.to_def_id()),
_ => None,
} {
if self.should_ignore_item(item_def_id) {
return;
}
}
let had_repr_c = self.repr_has_repr_c;
let had_inherited_pub_visibility = self.inherited_pub_visibility;
let had_pub_visibility = self.pub_visibility;

View file

@ -1134,6 +1134,7 @@ symbols! {
rustc_synthetic,
rustc_test_marker,
rustc_then_this_would_need,
rustc_trivial_field_reads,
rustc_unsafe_specialization_marker,
rustc_variance,
rustdoc,

View file

@ -23,7 +23,7 @@ use rustc_middle::ty::{
use rustc_middle::ty::{TypeAndMut, TypeckResults};
use rustc_span::def_id::LOCAL_CRATE;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
use rustc_span::{BytePos, DesugaringKind, ExpnKind, ForLoopLoc, MultiSpan, Span, DUMMY_SP};
use rustc_target::spec::abi;
use std::fmt;
@ -680,7 +680,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
points_at_arg: bool,
has_custom_message: bool,
) -> bool {
if !points_at_arg {
let span = obligation.cause.span;
let points_at_for_iter = matches!(
span.ctxt().outer_expn_data().kind,
ExpnKind::Desugaring(DesugaringKind::ForLoop(ForLoopLoc::IntoIter))
);
if !points_at_arg && !points_at_for_iter {
return false;
}
@ -695,7 +701,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
never_suggest_borrow.push(self.tcx.get_diagnostic_item(sym::send_trait).unwrap());
let span = obligation.cause.span;
let param_env = obligation.param_env;
let trait_ref = trait_ref.skip_binder();
@ -754,7 +759,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
);
// This if is to prevent a special edge-case
if !span.from_expansion() {
if matches!(
span.ctxt().outer_expn_data().kind,
ExpnKind::Root
| ExpnKind::Desugaring(DesugaringKind::ForLoop(ForLoopLoc::IntoIter))
) {
// We don't want a borrowing suggestion on the fields in structs,
// ```
// struct Foo {

View file

@ -105,6 +105,7 @@
#[stable(feature = "rust1", since = "1.0.0")]
#[lang = "clone"]
#[rustc_diagnostic_item = "Clone"]
#[cfg_attr(not(bootstrap), rustc_trivial_field_reads)]
pub trait Clone: Sized {
/// Returns a copy of the value.
///

View file

@ -582,6 +582,7 @@ impl Display for Arguments<'_> {
)]
#[doc(alias = "{:?}")]
#[rustc_diagnostic_item = "debug_trait"]
#[cfg_attr(not(bootstrap), rustc_trivial_field_reads)]
pub trait Debug {
/// Formats the value using the given formatter.
///

View file

@ -653,6 +653,7 @@ mod debug_list {
fn test_formatting_parameters_are_forwarded() {
use std::collections::{BTreeMap, BTreeSet};
#[derive(Debug)]
#[allow(dead_code)]
struct Foo {
bar: u32,
baz: u32,

View file

@ -162,6 +162,8 @@ macro_rules! with_api {
fn source($self: $S::Span) -> $S::Span;
fn start($self: $S::Span) -> LineColumn;
fn end($self: $S::Span) -> LineColumn;
fn before($self: $S::Span) -> $S::Span;
fn after($self: $S::Span) -> $S::Span;
fn join($self: $S::Span, other: $S::Span) -> Option<$S::Span>;
fn resolved_at($self: $S::Span, at: $S::Span) -> $S::Span;
fn source_text($self: $S::Span) -> Option<String>;

View file

@ -357,6 +357,18 @@ impl Span {
self.0.end().add_1_to_column()
}
/// Creates an empty span pointing to directly before this span.
#[unstable(feature = "proc_macro_span_shrink", issue = "87552")]
pub fn before(&self) -> Span {
Span(self.0.before())
}
/// Creates an empty span pointing to directly after this span.
#[unstable(feature = "proc_macro_span_shrink", issue = "87552")]
pub fn after(&self) -> Span {
Span(self.0.after())
}
/// Creates a new span encompassing `self` and `other`.
///
/// Returns `None` if `self` and `other` are from different files.

View file

@ -239,7 +239,7 @@
//! Iterators also provide a series of *adapter* methods for performing common
//! threads to sequences. Among the adapters are functional favorites like `map`,
//! `fold`, `skip` and `take`. Of particular interest to collections is the
//! `rev` adapter, that reverses any iterator that supports this operation. Most
//! `rev` adapter, which reverses any iterator that supports this operation. Most
//! collections provide reversible iterators as the way to iterate over them in
//! reverse order.
//!

View file

@ -468,9 +468,6 @@ struct ProgrammableSink {
// Writes append to this slice
pub buffer: Vec<u8>,
// Flush sets this flag
pub flushed: bool,
// If true, writes will always be an error
pub always_write_error: bool,
@ -520,7 +517,6 @@ impl Write for ProgrammableSink {
if self.always_flush_error {
Err(io::Error::new(io::ErrorKind::Other, "test - always_flush_error"))
} else {
self.flushed = true;
Ok(())
}
}

View file

@ -1611,7 +1611,7 @@ pub trait Write {
/// encountered.
///
/// This method is primarily used to interface with the
/// [`format_args!()`] macro, but it is rare that this should
/// [`format_args!()`] macro, and it is rare that this should
/// explicitly be called. The [`write!()`] macro should be favored to
/// invoke this method instead.
///

View file

@ -16,6 +16,7 @@ use parser::compiled::{msys_terminfo, parse};
use searcher::get_dbpath_for_term;
/// A parsed terminfo database entry.
#[allow(unused)]
#[derive(Debug)]
pub(crate) struct TermInfo {
/// Names for the terminal

View file

@ -375,7 +375,7 @@ Any reuse of a named label, local or otherwise, can result in a assembler or lin
As a consequence, you should only use GNU assembler **numeric** [local labels] inside inline assembly code. Defining symbols in assembly code may lead to assembler and/or linker errors due to duplicate symbol definitions.
Moreover, on x86 when using the default intel syntax, due to [an llvm bug], you shouldn't use labels exclusively made of `0` and `1` digits, e.g. `0`, `11` or `101010`, as they may end up being interpreted as binary values. Using `option(att_syntax)` will avoid any ambiguity, but that affects the syntax of the _entire_ `asm!` block.
Moreover, on x86 when using the default intel syntax, due to [an llvm bug], you shouldn't use labels exclusively made of `0` and `1` digits, e.g. `0`, `11` or `101010`, as they may end up being interpreted as binary values. Using `options(att_syntax)` will avoid any ambiguity, but that affects the syntax of the _entire_ `asm!` block.
```rust,allow_fail
#![feature(asm)]

View file

@ -557,7 +557,6 @@ fn build_macro(
name: Symbol,
import_def_id: Option<DefId>,
) -> clean::ItemKind {
let imported_from = cx.tcx.crate_name(def_id.krate);
match CStore::from_tcx(cx.tcx).load_macro_untracked(def_id, cx.sess()) {
LoadedMacro::MacroDef(item_def, _) => {
if let ast::ItemKind::MacroDef(ref def) = item_def.kind {
@ -569,7 +568,6 @@ fn build_macro(
def_id,
cx.tcx.visibility(import_def_id.unwrap_or(def_id)),
),
imported_from: Some(imported_from),
})
} else {
unreachable!()

View file

@ -1859,7 +1859,6 @@ impl Clean<Vec<Item>> for (&hir::Item<'_>, Option<Symbol>) {
}
ItemKind::Macro(ref macro_def) => MacroItem(Macro {
source: display_macro_source(cx, name, &macro_def, def_id, &item.vis),
imported_from: None,
}),
ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref item_ids) => {
let items = item_ids

View file

@ -2202,7 +2202,6 @@ crate struct ImportSource {
#[derive(Clone, Debug)]
crate struct Macro {
crate source: String,
crate imported_from: Option<Symbol>,
}
#[derive(Clone, Debug)]

View file

@ -48,7 +48,7 @@ use pulldown_cmark::{
mod tests;
/// Options for rendering Markdown in the main body of documentation.
pub(crate) fn opts() -> Options {
pub(crate) fn main_body_opts() -> Options {
Options::ENABLE_TABLES
| Options::ENABLE_FOOTNOTES
| Options::ENABLE_STRIKETHROUGH
@ -56,9 +56,13 @@ pub(crate) fn opts() -> Options {
| Options::ENABLE_SMART_PUNCTUATION
}
/// A subset of [`opts()`] used for rendering summaries.
/// Options for rendering Markdown in summaries (e.g., in search results).
pub(crate) fn summary_opts() -> Options {
Options::ENABLE_STRIKETHROUGH | Options::ENABLE_SMART_PUNCTUATION | Options::ENABLE_TABLES
Options::ENABLE_TABLES
| Options::ENABLE_FOOTNOTES
| Options::ENABLE_STRIKETHROUGH
| Options::ENABLE_TASKLISTS
| Options::ENABLE_SMART_PUNCTUATION
}
/// When `to_string` is called, this struct will emit the HTML corresponding to
@ -441,6 +445,42 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for LinkReplacer<'a, I> {
}
}
/// Wrap HTML tables into `<div>` to prevent having the doc blocks width being too big.
struct TableWrapper<'a, I: Iterator<Item = Event<'a>>> {
inner: I,
stored_events: VecDeque<Event<'a>>,
}
impl<'a, I: Iterator<Item = Event<'a>>> TableWrapper<'a, I> {
fn new(iter: I) -> Self {
Self { inner: iter, stored_events: VecDeque::new() }
}
}
impl<'a, I: Iterator<Item = Event<'a>>> Iterator for TableWrapper<'a, I> {
type Item = Event<'a>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(first) = self.stored_events.pop_front() {
return Some(first);
}
let event = self.inner.next()?;
Some(match event {
Event::Start(Tag::Table(t)) => {
self.stored_events.push_back(Event::Start(Tag::Table(t)));
Event::Html(CowStr::Borrowed("<div>"))
}
Event::End(Tag::Table(t)) => {
self.stored_events.push_back(Event::Html(CowStr::Borrowed("</div>")));
Event::End(Tag::Table(t))
}
e => e,
})
}
}
type SpannedEvent<'a> = (Event<'a>, Range<usize>);
/// Make headings links with anchor IDs and build up TOC.
@ -981,7 +1021,7 @@ impl Markdown<'_> {
}
};
let p = Parser::new_with_broken_link_callback(md, opts(), Some(&mut replacer));
let p = Parser::new_with_broken_link_callback(md, main_body_opts(), Some(&mut replacer));
let p = p.into_offset_iter();
let mut s = String::with_capacity(md.len() * 3 / 2);
@ -989,6 +1029,7 @@ impl Markdown<'_> {
let p = HeadingLinks::new(p, None, &mut ids);
let p = Footnotes::new(p);
let p = LinkReplacer::new(p.map(|(ev, _)| ev), links);
let p = TableWrapper::new(p);
let p = CodeBlocks::new(p, codes, edition, playground);
html::push_html(&mut s, p);
@ -1000,7 +1041,7 @@ impl MarkdownWithToc<'_> {
crate fn into_string(self) -> String {
let MarkdownWithToc(md, mut ids, codes, edition, playground) = self;
let p = Parser::new_ext(md, opts()).into_offset_iter();
let p = Parser::new_ext(md, main_body_opts()).into_offset_iter();
let mut s = String::with_capacity(md.len() * 3 / 2);
@ -1009,7 +1050,8 @@ impl MarkdownWithToc<'_> {
{
let p = HeadingLinks::new(p, Some(&mut toc), &mut ids);
let p = Footnotes::new(p);
let p = CodeBlocks::new(p.map(|(ev, _)| ev), codes, edition, playground);
let p = TableWrapper::new(p.map(|(ev, _)| ev));
let p = CodeBlocks::new(p, codes, edition, playground);
html::push_html(&mut s, p);
}
@ -1025,7 +1067,7 @@ impl MarkdownHtml<'_> {
if md.is_empty() {
return String::new();
}
let p = Parser::new_ext(md, opts()).into_offset_iter();
let p = Parser::new_ext(md, main_body_opts()).into_offset_iter();
// Treat inline HTML as plain text.
let p = p.map(|event| match event.0 {
@ -1037,7 +1079,8 @@ impl MarkdownHtml<'_> {
let p = HeadingLinks::new(p, None, &mut ids);
let p = Footnotes::new(p);
let p = CodeBlocks::new(p.map(|(ev, _)| ev), codes, edition, playground);
let p = TableWrapper::new(p.map(|(ev, _)| ev));
let p = CodeBlocks::new(p, codes, edition, playground);
html::push_html(&mut s, p);
s
@ -1099,7 +1142,7 @@ fn markdown_summary_with_limit(
}
};
let p = Parser::new_with_broken_link_callback(md, opts(), Some(&mut replacer));
let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer));
let mut p = LinkReplacer::new(p, link_names);
let mut buf = HtmlWithLimit::new(length_limit);
@ -1246,7 +1289,8 @@ crate fn markdown_links(md: &str) -> Vec<MarkdownLink> {
});
None
};
let p = Parser::new_with_broken_link_callback(md, opts(), Some(&mut push)).into_offset_iter();
let p = Parser::new_with_broken_link_callback(md, main_body_opts(), Some(&mut push))
.into_offset_iter();
// There's no need to thread an IdMap through to here because
// the IDs generated aren't going to be emitted anywhere.
@ -1285,7 +1329,7 @@ crate fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec<RustCodeB
return code_blocks;
}
let mut p = Parser::new_ext(md, opts()).into_offset_iter();
let mut p = Parser::new_ext(md, main_body_opts()).into_offset_iter();
while let Some((event, offset)) = p.next() {
if let Event::Start(Tag::CodeBlock(syntax)) = event {

View file

@ -224,7 +224,6 @@ struct AllTypes {
opaque_tys: FxHashSet<ItemEntry>,
statics: FxHashSet<ItemEntry>,
constants: FxHashSet<ItemEntry>,
keywords: FxHashSet<ItemEntry>,
attributes: FxHashSet<ItemEntry>,
derives: FxHashSet<ItemEntry>,
trait_aliases: FxHashSet<ItemEntry>,
@ -245,7 +244,6 @@ impl AllTypes {
opaque_tys: new_set(100),
statics: new_set(100),
constants: new_set(100),
keywords: new_set(100),
attributes: new_set(100),
derives: new_set(100),
trait_aliases: new_set(100),

View file

@ -256,6 +256,10 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
debug!("{:?}", indices);
let mut curty = None;
// See: https://github.com/rust-lang/rust/issues/88545
let item_table_block_size = 900usize;
let mut item_table_nth_element = 0usize;
for &idx in &indices {
let myitem = &items[idx];
if myitem.is_stripped() {
@ -275,11 +279,13 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
write!(
w,
"<h2 id=\"{id}\" class=\"section-header\">\
<a href=\"#{id}\">{name}</a></h2>\n{}",
<a href=\"#{id}\">{name}</a>\
</h2>\n{}",
ITEM_TABLE_OPEN,
id = cx.derive_id(short.to_owned()),
name = name
);
item_table_nth_element = 0;
}
match *myitem.kind {
@ -386,6 +392,13 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
);
}
}
item_table_nth_element += 1;
if item_table_nth_element > item_table_block_size {
w.write_str(ITEM_TABLE_CLOSE);
w.write_str(ITEM_TABLE_OPEN);
item_table_nth_element = 0;
}
}
if curty.is_some() {
@ -944,15 +957,15 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni
}
fn print_tuple_struct_fields(w: &mut Buffer, cx: &Context<'_>, s: &[clean::Item]) {
for (i, ty) in s
.iter()
.map(|f| if let clean::StructFieldItem(ref ty) = *f.kind { ty } else { unreachable!() })
.enumerate()
{
for (i, ty) in s.iter().enumerate() {
if i > 0 {
w.write_str(",&nbsp;");
}
write!(w, "{}", ty.print(cx));
match *ty.kind {
clean::StrippedItem(box clean::StructFieldItem(_)) => w.write_str("_"),
clean::StructFieldItem(ref ty) => write!(w, "{}", ty.print(cx)),
_ => unreachable!(),
}
}
}
@ -1068,24 +1081,27 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
name = variant.name.as_ref().unwrap(),
);
for field in fields {
use crate::clean::StructFieldItem;
if let StructFieldItem(ref ty) = *field.kind {
let id = cx.derive_id(format!(
"variant.{}.field.{}",
variant.name.as_ref().unwrap(),
field.name.as_ref().unwrap()
));
write!(
w,
"<span id=\"{id}\" class=\"variant small-section-header\">\
<a href=\"#{id}\" class=\"anchor field\"></a>\
<code>{f}:&nbsp;{t}</code>\
</span>",
id = id,
f = field.name.as_ref().unwrap(),
t = ty.print(cx)
);
document(w, cx, field, Some(variant));
match *field.kind {
clean::StrippedItem(box clean::StructFieldItem(_)) => {}
clean::StructFieldItem(ref ty) => {
let id = cx.derive_id(format!(
"variant.{}.field.{}",
variant.name.as_ref().unwrap(),
field.name.as_ref().unwrap()
));
write!(
w,
"<span id=\"{id}\" class=\"variant small-section-header\">\
<a href=\"#{id}\" class=\"anchor field\"></a>\
<code>{f}:&nbsp;{t}</code>\
</span>",
id = id,
f = field.name.as_ref().unwrap(),
t = ty.print(cx)
);
document(w, cx, field, Some(variant));
}
_ => unreachable!(),
}
}
w.write_str("</div></div>");

View file

@ -522,6 +522,11 @@ nav.sub {
position: relative;
}
.docblock > * {
max-width: 100%;
overflow-x: auto;
}
.content .out-of-band {
flex-grow: 0;
text-align: right;

View file

@ -2,7 +2,7 @@ use super::Pass;
use crate::clean::*;
use crate::core::DocContext;
use crate::fold::DocFolder;
use crate::html::markdown::opts;
use crate::html::markdown::main_body_opts;
use core::ops::Range;
use pulldown_cmark::{Event, Parser, Tag};
use regex::Regex;
@ -83,7 +83,7 @@ impl<'a, 'tcx> DocFolder for BareUrlsLinter<'a, 'tcx> {
});
};
let mut p = Parser::new_ext(&dox, opts()).into_offset_iter();
let mut p = Parser::new_ext(&dox, main_body_opts()).into_offset_iter();
while let Some((event, range)) = p.next() {
match event {

View file

@ -4,8 +4,10 @@ use crate::fold::{self, DocFolder};
use crate::html::markdown::{find_testable_code, ErrorCodes};
use crate::passes::doc_test_lints::{should_have_doc_example, Tests};
use crate::passes::Pass;
use rustc_hir as hir;
use rustc_lint::builtin::MISSING_DOCS;
use rustc_middle::lint::LintLevelSource;
use rustc_middle::ty::DefIdTree;
use rustc_session::lint;
use rustc_span::FileName;
use serde::Serialize;
@ -221,10 +223,42 @@ impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> {
.hir()
.local_def_id_to_hir_id(i.def_id.expect_def_id().expect_local());
let (level, source) = self.ctx.tcx.lint_level_at_node(MISSING_DOCS, hir_id);
// In case we have:
//
// ```
// enum Foo { Bar(u32) }
// // or:
// struct Bar(u32);
// ```
//
// there is no need to require documentation on the fields of tuple variants and
// tuple structs.
let should_be_ignored = i
.def_id
.as_def_id()
.and_then(|def_id| self.ctx.tcx.parent(def_id))
.and_then(|def_id| self.ctx.tcx.hir().get_if_local(def_id))
.map(|node| {
matches!(
node,
hir::Node::Variant(hir::Variant {
data: hir::VariantData::Tuple(_, _),
..
}) | hir::Node::Item(hir::Item {
kind: hir::ItemKind::Struct(hir::VariantData::Tuple(_, _), _),
..
})
)
})
.unwrap_or(false);
// `missing_docs` is allow-by-default, so don't treat this as ignoring the item
// unless the user had an explicit `allow`
let should_have_docs =
level != lint::Level::Allow || matches!(source, LintLevelSource::Default);
// unless the user had an explicit `allow`.
//
let should_have_docs = !should_be_ignored
&& (level != lint::Level::Allow || matches!(source, LintLevelSource::Default));
debug!("counting {:?} {:?} in {:?}", i.type_(), i.name, filename);
self.items.entry(filename).or_default().count_item(
has_docs,

View file

@ -2,7 +2,7 @@ use super::Pass;
use crate::clean::*;
use crate::core::DocContext;
use crate::fold::DocFolder;
use crate::html::markdown::opts;
use crate::html::markdown::main_body_opts;
use core::ops::Range;
use pulldown_cmark::{Event, Parser, Tag};
use std::iter::Peekable;
@ -192,7 +192,7 @@ impl<'a, 'tcx> DocFolder for InvalidHtmlTagsLinter<'a, 'tcx> {
let mut is_in_comment = None;
let mut in_code_block = false;
let p = Parser::new_ext(&dox, opts()).into_offset_iter();
let p = Parser::new_ext(&dox, main_body_opts()).into_offset_iter();
for (event, range) in p {
match event {

View file

@ -7,3 +7,11 @@ compare-elements-property: (".top-doc .docblock", ".top-doc .docblock > p", ["sc
assert-property: (".top-doc .docblock", {"scrollWidth": "816"})
// However, since there is overflow in the <table>, its scroll width is bigger.
assert-property: (".top-doc .docblock table", {"scrollWidth": "1573"})
// Checking it works on other doc blocks as well...
// Logically, the ".docblock" and the "<p>" should have the same scroll width.
compare-elements-property: ("#implementations + details .docblock", "#implementations + details .docblock > p", ["scrollWidth"])
assert-property: ("#implementations + details .docblock", {"scrollWidth": "816"})
// However, since there is overflow in the <table>, its scroll width is bigger.
assert-property: ("#implementations + details .docblock table", {"scrollWidth": "1573"})

View file

@ -67,6 +67,15 @@ pub mod long_table {
///
/// I wanna sqdkfnqds f dsqf qds f dsqf dsq f dsq f qds f qds f qds f dsqq f dsf sqdf dsq fds f dsq f dq f ds fq sd fqds f dsq f sqd fsq df sd fdsqfqsd fdsq f dsq f dsqfd s dfq
pub struct Foo;
/// | This::is::a::kinda::very::long::header::number::one | This::is::a::kinda::very::long::header::number::two | This::is::a::kinda::very::long::header::number::one | This::is::a::kinda::very::long::header::number::two |
/// | ----------- | ----------- | ----------- | ----------- |
/// | This::is::a::kinda::long::content::number::one | This::is::a::kinda::very::long::content::number::two | This::is::a::kinda::long::content::number::one | This::is::a::kinda::very::long::content::number::two |
///
/// I wanna sqdkfnqds f dsqf qds f dsqf dsq f dsq f qds f qds f qds f dsqq f dsf sqdf dsq fds f dsq f dq f ds fq sd fqds f dsq f sqd fsq df sd fdsqfqsd fdsq f dsq f dsqfd s dfq
impl Foo {
pub fn foo(&self) {}
}
}
pub mod summary_table {

View file

@ -0,0 +1,37 @@
// compile-flags:-Z unstable-options --show-coverage
// check-pass
// The point of this test is to ensure that the number of "documented" items
// is higher than in `enum-tuple.rs`.
//! (remember the crate root is still a module)
/// so check out this enum here
pub enum ThisEnum {
/// VarOne.
VarOne(
/// hello!
String,
),
/// Var Two.
VarTwo(
/// Hello
String,
/// Bis repetita.
String,
),
}
/// Struct.
pub struct ThisStruct(
/// hello
u32,
);
/// Struct.
pub struct ThisStruct2(
/// hello
u32,
/// Bis repetita.
u8,
);

View file

@ -0,0 +1,7 @@
+-------------------------------------+------------+------------+------------+------------+
| File | Documented | Percentage | Examples | Percentage |
+-------------------------------------+------------+------------+------------+------------+
| ...overage/enum-tuple-documented.rs | 9 | 100.0% | 0 | 0.0% |
+-------------------------------------+------------+------------+------------+------------+
| Total | 9 | 100.0% | 0 | 0.0% |
+-------------------------------------+------------+------------+------------+------------+

View file

@ -0,0 +1,18 @@
// compile-flags:-Z unstable-options --show-coverage
// check-pass
//! (remember the crate root is still a module)
/// so check out this enum here
pub enum ThisEnum {
/// No need to document the field if there is only one in a tuple variant!
VarOne(String),
/// But if there is more than one... still fine!
VarTwo(String, String),
}
/// Struct.
pub struct ThisStruct(u32);
/// Struct.
pub struct ThisStruct2(u32, u8);

View file

@ -0,0 +1,7 @@
+-------------------------------------+------------+------------+------------+------------+
| File | Documented | Percentage | Examples | Percentage |
+-------------------------------------+------------+------------+------------+------------+
| ...ustdoc-ui/coverage/enum-tuple.rs | 6 | 100.0% | 0 | 0.0% |
+-------------------------------------+------------+------------+------------+------------+
| Total | 6 | 100.0% | 0 | 0.0% |
+-------------------------------------+------------+------------+------------+------------+

View file

@ -1,7 +1,7 @@
+-------------------------------------+------------+------------+------------+------------+
| File | Documented | Percentage | Examples | Percentage |
+-------------------------------------+------------+------------+------------+------------+
| ...est/rustdoc-ui/coverage/enums.rs | 6 | 66.7% | 0 | 0.0% |
| ...est/rustdoc-ui/coverage/enums.rs | 6 | 75.0% | 0 | 0.0% |
+-------------------------------------+------------+------------+------------+------------+
| Total | 6 | 66.7% | 0 | 0.0% |
| Total | 6 | 75.0% | 0 | 0.0% |
+-------------------------------------+------------+------------+------------+------------+

View file

@ -0,0 +1,34 @@
// This test ensure that #[doc(hidden)] is applied correctly in enum variant fields.
// Denotes a field which should be hidden.
pub struct H;
// Denotes a field which should not be hidden (shown).
pub struct S;
// @has issue_88600/enum.FooEnum.html
pub enum FooEnum {
// @has - '//*[@id="variant.HiddenTupleItem"]//code' 'HiddenTupleItem(_)'
// @count - '//*[@id="variant.HiddenTupleItem.field.0"]' 0
HiddenTupleItem(#[doc(hidden)] H),
// @has - '//*[@id="variant.MultipleHidden"]//code' 'MultipleHidden(_, _)'
// @count - '//*[@id="variant.MultipleHidden.field.0"]' 0
// @count - '//*[@id="variant.MultipleHidden.field.1"]' 0
MultipleHidden(#[doc(hidden)] H, #[doc(hidden)] H),
// @has - '//*[@id="variant.MixedHiddenFirst"]//code' 'MixedHiddenFirst(_, S)'
// @count - '//*[@id="variant.MixedHiddenFirst.field.0"]' 0
// @has - '//*[@id="variant.MixedHiddenFirst.field.1"]' '1: S'
MixedHiddenFirst(#[doc(hidden)] H, S),
// @has - '//*[@id="variant.MixedHiddenLast"]//code' 'MixedHiddenLast(S, _)'
// @has - '//*[@id="variant.MixedHiddenLast.field.0"]' '0: S'
// @count - '//*[@id="variant.MixedHiddenLast.field.1"]' 0
MixedHiddenLast(S, #[doc(hidden)] H),
// @has - '//*[@id="variant.HiddenStruct"]//code' 'HiddenStruct'
// @count - '//*[@id="variant.HiddenStruct.field.h"]' 0
// @has - '//*[@id="variant.HiddenStruct.field.s"]' 's: S'
HiddenStruct {
#[doc(hidden)]
h: H,
s: S,
},
}

View file

@ -0,0 +1,16 @@
#![crate_name = "foo"]
// @has foo/struct.Foo.html
// @count - '//*[@class="docblock"]/div/table' 2
// @!has - '//*[@class="docblock"]/table'
/// | hello | hello2 |
/// | ----- | ------ |
/// | data | data2 |
pub struct Foo;
impl Foo {
/// | hello | hello2 |
/// | ----- | ------ |
/// | data | data2 |
pub fn foo(&self) {}
}

View file

@ -2,6 +2,7 @@
// Test binary_search_by_key lifetime. Issue #34683
#[allow(dead_code)]
#[derive(Debug)]
struct Assignment {
topic: String,

View file

@ -1,4 +1,5 @@
// run-pass
#![allow(dead_code)]
#![deny(unused_mut)]
#[derive(Debug)]

View file

@ -3,6 +3,7 @@
// check-pass
#![allow(unreachable_code)]
#![warn(unused)]
#![allow(dead_code)]
#[derive(Debug)]
struct Point {

View file

@ -1,5 +1,5 @@
warning: value captured by `a` is never read
--> $DIR/liveness.rs:23:9
--> $DIR/liveness.rs:24:9
|
LL | a = 1;
| ^
@ -13,7 +13,7 @@ LL | #![warn(unused)]
= help: did you mean to capture by reference instead?
warning: unused variable: `a`
--> $DIR/liveness.rs:32:9
--> $DIR/liveness.rs:33:9
|
LL | a += 1;
| ^
@ -27,7 +27,7 @@ LL | #![warn(unused)]
= help: did you mean to capture by reference instead?
warning: value assigned to `a` is never read
--> $DIR/liveness.rs:52:9
--> $DIR/liveness.rs:53:9
|
LL | a += 1;
| ^
@ -35,7 +35,7 @@ LL | a += 1;
= help: maybe it is overwritten before being read?
warning: value assigned to `a` is never read
--> $DIR/liveness.rs:76:13
--> $DIR/liveness.rs:77:13
|
LL | a = Some("d1");
| ^
@ -43,7 +43,7 @@ LL | a = Some("d1");
= help: maybe it is overwritten before being read?
warning: value assigned to `b` is never read
--> $DIR/liveness.rs:84:13
--> $DIR/liveness.rs:85:13
|
LL | b = Some("e1");
| ^
@ -51,7 +51,7 @@ LL | b = Some("e1");
= help: maybe it is overwritten before being read?
warning: value assigned to `b` is never read
--> $DIR/liveness.rs:86:13
--> $DIR/liveness.rs:87:13
|
LL | b = Some("e2");
| ^
@ -59,7 +59,7 @@ LL | b = Some("e2");
= help: maybe it is overwritten before being read?
warning: unused variable: `b`
--> $DIR/liveness.rs:84:13
--> $DIR/liveness.rs:85:13
|
LL | b = Some("e1");
| ^

View file

@ -2,6 +2,7 @@
// check-pass
#![warn(unused)]
#![allow(dead_code)]
#[derive(Debug)]
struct MyStruct {

View file

@ -1,5 +1,5 @@
warning: value assigned to `a` is never read
--> $DIR/liveness_unintentional_copy.rs:19:9
--> $DIR/liveness_unintentional_copy.rs:20:9
|
LL | a = s;
| ^
@ -13,7 +13,7 @@ LL | #![warn(unused)]
= help: maybe it is overwritten before being read?
warning: unused variable: `a`
--> $DIR/liveness_unintentional_copy.rs:19:9
--> $DIR/liveness_unintentional_copy.rs:20:9
|
LL | a = s;
| ^
@ -27,7 +27,7 @@ LL | #![warn(unused)]
= help: did you mean to capture by reference instead?
warning: unused variable: `a`
--> $DIR/liveness_unintentional_copy.rs:35:9
--> $DIR/liveness_unintentional_copy.rs:36:9
|
LL | a += x;
| ^

View file

@ -1,6 +1,7 @@
// edition:2021
//check-pass
#![warn(unused)]
#![allow(dead_code)]
#![feature(rustc_attrs)]
#[derive(Debug, Clone, Copy)]

View file

@ -3,6 +3,8 @@
// Test that we can use raw ptrs when using `capture_disjoint_fields`.
#![allow(dead_code)]
#[derive(Debug)]
struct S {
s: String,

View file

@ -1,4 +1,7 @@
// run-pass
#![allow(dead_code)]
use std::fmt::Debug;
#[derive(Debug)]

View file

@ -0,0 +1,45 @@
// Checks that derived implementations of Clone and Debug do not
// contribute to dead code analysis (issue #84647).
#![forbid(dead_code)]
struct A { f: () }
//~^ ERROR: field is never read: `f`
#[derive(Clone)]
struct B { f: () }
//~^ ERROR: field is never read: `f`
#[derive(Debug)]
struct C { f: () }
//~^ ERROR: field is never read: `f`
#[derive(Debug,Clone)]
struct D { f: () }
//~^ ERROR: field is never read: `f`
struct E { f: () }
//~^ ERROR: field is never read: `f`
// Custom impl, still doesn't read f
impl Clone for E {
fn clone(&self) -> Self {
Self { f: () }
}
}
struct F { f: () }
// Custom impl that actually reads f
impl Clone for F {
fn clone(&self) -> Self {
Self { f: self.f }
}
}
fn main() {
let _ = A { f: () };
let _ = B { f: () };
let _ = C { f: () };
let _ = D { f: () };
let _ = E { f: () };
let _ = F { f: () };
}

View file

@ -0,0 +1,38 @@
error: field is never read: `f`
--> $DIR/clone-debug-dead-code.rs:6:12
|
LL | struct A { f: () }
| ^^^^^
|
note: the lint level is defined here
--> $DIR/clone-debug-dead-code.rs:4:11
|
LL | #![forbid(dead_code)]
| ^^^^^^^^^
error: field is never read: `f`
--> $DIR/clone-debug-dead-code.rs:10:12
|
LL | struct B { f: () }
| ^^^^^
error: field is never read: `f`
--> $DIR/clone-debug-dead-code.rs:14:12
|
LL | struct C { f: () }
| ^^^^^
error: field is never read: `f`
--> $DIR/clone-debug-dead-code.rs:18:12
|
LL | struct D { f: () }
| ^^^^^
error: field is never read: `f`
--> $DIR/clone-debug-dead-code.rs:21:12
|
LL | struct E { f: () }
| ^^^^^
error: aborting due to 5 previous errors

View file

@ -1,6 +1,8 @@
// run-pass
// pretty-expanded FIXME #23616
#![allow(dead_code)]
#[derive(Clone)]
struct S<T> {
foo: (),

View file

@ -1,6 +1,8 @@
// run-pass
// pretty-expanded FIXME #23616
#![allow(dead_code)]
#[derive(Clone)]
struct S {
_int: isize,

View file

@ -1,6 +1,8 @@
// run-pass
// pretty-expanded FIXME #23616
#![allow(dead_code)]
#[derive(Clone)]
struct S((), ());

View file

@ -1,4 +1,7 @@
// run-pass
#![allow(dead_code)]
pub fn main() {
#[derive(Debug)]
struct Foo {

View file

@ -0,0 +1,19 @@
// This snippet ensures that no attempt to recover on a semicolon instead of
// comma is made next to a closure body.
//
// If this recovery happens, then plenty of errors are emitted. Here, we expect
// only one error.
//
// This is part of issue #88065:
// https://github.com/rust-lang/rust/issues/88065
// run-rustfix
fn main() {
let num = 5;
(1..num).reduce(|a, b| {
//~^ ERROR: closure bodies that contain statements must be surrounded by braces
println!("{}", a);
a * b
}).unwrap();
}

View file

@ -0,0 +1,19 @@
// This snippet ensures that no attempt to recover on a semicolon instead of
// comma is made next to a closure body.
//
// If this recovery happens, then plenty of errors are emitted. Here, we expect
// only one error.
//
// This is part of issue #88065:
// https://github.com/rust-lang/rust/issues/88065
// run-rustfix
fn main() {
let num = 5;
(1..num).reduce(|a, b|
//~^ ERROR: closure bodies that contain statements must be surrounded by braces
println!("{}", a);
a * b
).unwrap();
}

View file

@ -0,0 +1,38 @@
error: closure bodies that contain statements must be surrounded by braces
--> $DIR/missing_braces_around_block.rs:14:26
|
LL | (1..num).reduce(|a, b|
| ^
...
LL | ).unwrap();
| ^
|
note: statement found outside of a block
--> $DIR/missing_braces_around_block.rs:16:26
|
LL | println!("{}", a);
| -----------------^ this `;` turns the preceding closure into a statement
| |
| this expression is a statement because of the trailing semicolon
note: the closure body may be incorrectly delimited
--> $DIR/missing_braces_around_block.rs:14:21
|
LL | (1..num).reduce(|a, b|
| _____________________^
LL | |
LL | | println!("{}", a);
| |_________________________^ this is the parsed closure...
LL | a * b
LL | ).unwrap();
| - ...but likely you meant the closure to end here
help: try adding braces
|
LL ~ (1..num).reduce(|a, b| {
LL |
LL | println!("{}", a);
LL | a * b
LL ~ }).unwrap();
|
error: aborting due to previous error

View file

@ -0,0 +1,16 @@
// Part of issue #27300.
// The problem here is that ruby-style closures are parsed as blocks whose
// first statement is a closure. See the issue for more details:
// https://github.com/rust-lang/rust/issues/27300
// Note: this test represents what the compiler currently emits. The error
// message will be improved later.
fn main() {
let p = Some(45).and_then({
//~^ expected a `FnOnce<({integer},)>` closure, found `Option<_>`
|x| println!("doubling {}", x);
Some(x * 2)
//~^ ERROR: cannot find value `x` in this scope
});
}

View file

@ -0,0 +1,18 @@
error[E0425]: cannot find value `x` in this scope
--> $DIR/ruby_style_closure.rs:13:14
|
LL | Some(x * 2)
| ^ not found in this scope
error[E0277]: expected a `FnOnce<({integer},)>` closure, found `Option<_>`
--> $DIR/ruby_style_closure.rs:10:22
|
LL | let p = Some(45).and_then({
| ^^^^^^^^ expected an `FnOnce<({integer},)>` closure, found `Option<_>`
|
= help: the trait `FnOnce<({integer},)>` is not implemented for `Option<_>`
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0277, E0425.
For more information about an error, try `rustc --explain E0277`.

View file

@ -1,4 +1,7 @@
// run-pass
#![allow(dead_code)]
trait Trait { fn dummy(&self) { } }
#[derive(Debug)]

View file

@ -2,9 +2,12 @@ error[E0277]: the size for values of type `dyn Iterator<Item = &'a mut u8>` cann
--> $DIR/issue-20605.rs:2:17
|
LL | for item in *things { *item = 0 }
| ^^^^^^^ doesn't have a size known at compile-time
| ^^^^^^^
| |
| expected an implementor of trait `IntoIterator`
| help: consider mutably borrowing here: `&mut *things`
|
= help: the trait `Sized` is not implemented for `dyn Iterator<Item = &'a mut u8>`
= note: the trait bound `dyn Iterator<Item = &'a mut u8>: IntoIterator` is not satisfied
= note: required because of the requirements on the impl of `IntoIterator` for `dyn Iterator<Item = &'a mut u8>`
note: required by `into_iter`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL

View file

@ -1,5 +1,6 @@
// run-pass
#![feature(box_syntax)]
#![allow(dead_code)]
trait T {
fn print(&self);

View file

@ -0,0 +1,11 @@
use std::fmt::Write;
fn main() {
println!(b"foo");
//~^ ERROR format argument must be a string literal
//~| HELP consider removing the leading `b`
let mut s = String::new();
write!(s, b"foo{}", "bar");
//~^ ERROR format argument must be a string literal
//~| HELP consider removing the leading `b`
}

View file

@ -0,0 +1,18 @@
error: format argument must be a string literal
--> $DIR/issue-86865.rs:4:14
|
LL | println!(b"foo");
| -^^^^^
| |
| help: consider removing the leading `b`
error: format argument must be a string literal
--> $DIR/issue-86865.rs:8:15
|
LL | write!(s, b"foo{}", "bar");
| -^^^^^^^
| |
| help: consider removing the leading `b`
error: aborting due to 2 previous errors

View file

@ -1,6 +1,7 @@
// run-pass
#![allow(non_upper_case_globals)]
#![allow(dead_code)]
/*!
* On x86_64-linux-gnu and possibly other platforms, structs get 8-byte "preferred" alignment,
* but their "ABI" alignment (i.e., what actually matters for data layout) is the largest alignment

View file

@ -1,5 +1,6 @@
// run-pass
#![allow(unused_mut)]
#![allow(dead_code)]
#![feature(box_syntax)]
#[derive(Clone)]

View file

@ -1,5 +1,6 @@
// run-pass
#![allow(unused_mut)]
#![allow(dead_code)]
#![feature(box_syntax)]
#[derive(Clone)]

View file

@ -1,5 +1,7 @@
// run-pass
#![allow(dead_code)]
use std::rc::Rc;
use std::ops::Deref;

View file

@ -1,5 +1,6 @@
// run-pass
#![feature(box_syntax)]
#![allow(dead_code)]
#[derive(Copy, Clone)]
struct Foo {

View file

@ -1,5 +1,6 @@
// run-pass
#![allow(non_camel_case_types)]
#![allow(dead_code)]
trait noisy {
fn speak(&mut self) -> isize;

View file

@ -1,5 +1,6 @@
// run-pass
#![allow(non_camel_case_types)]
#![allow(dead_code)]
trait noisy {
fn speak(&mut self);

View file

@ -1,4 +1,7 @@
// run-pass
#![allow(dead_code)]
#[derive(Debug)]
struct Foo {
x: isize,

View file

@ -1,5 +1,6 @@
// run-pass
#![allow(non_camel_case_types)]
#![allow(dead_code)]
#[derive(Debug)]
enum a_tag {

View file

@ -0,0 +1,16 @@
fn main() {
let v = vec![1i32, 2, 3];
for _ in v[1..] {
//~^ ERROR [i32]` is not an iterator [E0277]
//~^^ ERROR known at compilation time
}
struct K {
n: i32,
}
let mut v2 = vec![K { n: 1 }, K { n: 1 }, K { n: 1 }];
for i2 in v2[1..] {
//~^ ERROR [K]` is not an iterator [E0277]
//~^^ ERROR known at compilation time
i2.n = 2;
}
}

View file

@ -0,0 +1,71 @@
error[E0277]: the size for values of type `[i32]` cannot be known at compilation time
--> $DIR/slice-issue-87994.rs:3:12
|
LL | for _ in v[1..] {
| ^^^^^^
| |
| expected an implementor of trait `IntoIterator`
| help: consider borrowing here: `&v[1..]`
|
= note: the trait bound `[i32]: IntoIterator` is not satisfied
= note: required because of the requirements on the impl of `IntoIterator` for `[i32]`
note: required by `into_iter`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
|
LL | fn into_iter(self) -> Self::IntoIter;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0277]: `[i32]` is not an iterator
--> $DIR/slice-issue-87994.rs:3:12
|
LL | for _ in v[1..] {
| ^^^^^^
| |
| expected an implementor of trait `IntoIterator`
| help: consider borrowing here: `&v[1..]`
|
= note: the trait bound `[i32]: IntoIterator` is not satisfied
= note: required because of the requirements on the impl of `IntoIterator` for `[i32]`
note: required by `into_iter`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
|
LL | fn into_iter(self) -> Self::IntoIter;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0277]: the size for values of type `[K]` cannot be known at compilation time
--> $DIR/slice-issue-87994.rs:11:13
|
LL | for i2 in v2[1..] {
| ^^^^^^^
| |
| expected an implementor of trait `IntoIterator`
| help: consider borrowing here: `&v2[1..]`
|
= note: the trait bound `[K]: IntoIterator` is not satisfied
= note: required because of the requirements on the impl of `IntoIterator` for `[K]`
note: required by `into_iter`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
|
LL | fn into_iter(self) -> Self::IntoIter;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0277]: `[K]` is not an iterator
--> $DIR/slice-issue-87994.rs:11:13
|
LL | for i2 in v2[1..] {
| ^^^^^^^
| |
| expected an implementor of trait `IntoIterator`
| help: consider borrowing here: `&v2[1..]`
|
= note: the trait bound `[K]: IntoIterator` is not satisfied
= note: required because of the requirements on the impl of `IntoIterator` for `[K]`
note: required by `into_iter`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
|
LL | fn into_iter(self) -> Self::IntoIter;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0277`.

View file

@ -29,36 +29,21 @@ declare_clippy_lint! {
"#[macro_use] is no longer needed"
}
const BRACKETS: &[char] = &['<', '>'];
#[derive(Clone, Debug, PartialEq, Eq)]
struct PathAndSpan {
path: String,
span: Span,
}
/// `MacroRefData` includes the name of the macro
/// and the path from `SourceMap::span_to_filename`.
/// `MacroRefData` includes the name of the macro.
#[derive(Debug, Clone)]
pub struct MacroRefData {
name: String,
path: String,
}
impl MacroRefData {
pub fn new(name: String, callee: Span, cx: &LateContext<'_>) -> Self {
let sm = cx.sess().source_map();
let mut path = sm.filename_for_diagnostics(&sm.span_to_filename(callee)).to_string();
// std lib paths are <::std::module::file type>
// so remove brackets, space and type.
if path.contains('<') {
path = path.replace(BRACKETS, "");
}
if path.contains(' ') {
path = path.split(' ').next().unwrap().to_string();
}
Self { name, path }
pub fn new(name: String) -> Self {
Self { name }
}
}
@ -78,7 +63,7 @@ impl MacroUseImports {
fn push_unique_macro(&mut self, cx: &LateContext<'_>, span: Span) {
let call_site = span.source_callsite();
let name = snippet(cx, cx.sess().source_map().span_until_char(call_site, '!'), "_");
if let Some(callee) = span.source_callee() {
if let Some(_callee) = span.source_callee() {
if !self.collected.contains(&call_site) {
let name = if name.contains("::") {
name.split("::").last().unwrap().to_string()
@ -86,7 +71,7 @@ impl MacroUseImports {
name.to_string()
};
self.mac_refs.push(MacroRefData::new(name, callee.def_site, cx));
self.mac_refs.push(MacroRefData::new(name));
self.collected.insert(call_site);
}
}
@ -95,10 +80,10 @@ impl MacroUseImports {
fn push_unique_macro_pat_ty(&mut self, cx: &LateContext<'_>, span: Span) {
let call_site = span.source_callsite();
let name = snippet(cx, cx.sess().source_map().span_until_char(call_site, '!'), "_");
if let Some(callee) = span.source_callee() {
if let Some(_callee) = span.source_callee() {
if !self.collected.contains(&call_site) {
self.mac_refs
.push(MacroRefData::new(name.to_string(), callee.def_site, cx));
.push(MacroRefData::new(name.to_string()));
self.collected.insert(call_site);
}
}

View file

@ -3,8 +3,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
use clippy_utils::{match_def_path, paths};
use if_chain::if_chain;
use rustc_ast::ast::{LitKind, StrStyle};
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::{BorrowKind, Expr, ExprKind, HirId};
use rustc_hir::{BorrowKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::{BytePos, Span};
@ -53,10 +52,7 @@ declare_clippy_lint! {
}
#[derive(Clone, Default)]
pub struct Regex {
spans: FxHashSet<Span>,
last: Option<HirId>,
}
pub struct Regex {}
impl_lint_pass!(Regex => [INVALID_REGEX, TRIVIAL_REGEX]);

View file

@ -1,6 +1,6 @@
// run-rustfix
#![allow(unused_imports)]
#![allow(unused_imports,dead_code)]
#![deny(clippy::default_trait_access)]
use std::default;

View file

@ -1,6 +1,6 @@
// run-rustfix
#![allow(unused_imports)]
#![allow(unused_imports,dead_code)]
#![deny(clippy::default_trait_access)]
use std::default;

View file

@ -762,7 +762,6 @@ impl MacroArgKind {
#[derive(Debug, Clone)]
struct ParsedMacroArg {
kind: MacroArgKind,
span: Span,
}
impl ParsedMacroArg {
@ -780,14 +779,10 @@ impl ParsedMacroArg {
struct MacroArgParser {
/// Either a name of the next metavariable, a separator, or junk.
buf: String,
/// The start position on the current buffer.
lo: BytePos,
/// The first token of the current buffer.
start_tok: Token,
/// `true` if we are parsing a metavariable or a repeat.
is_meta_var: bool,
/// The position of the last token.
hi: BytePos,
/// The last token parsed.
last_tok: Token,
/// Holds the parsed arguments.
@ -807,8 +802,6 @@ fn last_tok(tt: &TokenTree) -> Token {
impl MacroArgParser {
fn new() -> MacroArgParser {
MacroArgParser {
lo: BytePos(0),
hi: BytePos(0),
buf: String::new(),
is_meta_var: false,
last_tok: Token {
@ -824,7 +817,6 @@ impl MacroArgParser {
}
fn set_last_tok(&mut self, tok: &TokenTree) {
self.hi = tok.span().hi();
self.last_tok = last_tok(tok);
}
@ -836,7 +828,6 @@ impl MacroArgParser {
};
self.result.push(ParsedMacroArg {
kind: MacroArgKind::Separator(self.buf.clone(), prefix),
span: mk_sp(self.lo, self.hi),
});
self.buf.clear();
}
@ -849,7 +840,6 @@ impl MacroArgParser {
};
self.result.push(ParsedMacroArg {
kind: MacroArgKind::Other(self.buf.clone(), prefix),
span: mk_sp(self.lo, self.hi),
});
self.buf.clear();
}
@ -858,11 +848,10 @@ impl MacroArgParser {
match iter.next() {
Some(TokenTree::Token(Token {
kind: TokenKind::Ident(name, _),
span,
..
})) => {
self.result.push(ParsedMacroArg {
kind: MacroArgKind::MetaVariable(name, self.buf.clone()),
span: mk_sp(self.lo, span.hi()),
});
self.buf.clear();
@ -873,10 +862,9 @@ impl MacroArgParser {
}
}
fn add_delimited(&mut self, inner: Vec<ParsedMacroArg>, delim: DelimToken, span: Span) {
fn add_delimited(&mut self, inner: Vec<ParsedMacroArg>, delim: DelimToken) {
self.result.push(ParsedMacroArg {
kind: MacroArgKind::Delimited(delim, inner),
span,
});
}
@ -886,19 +874,15 @@ impl MacroArgParser {
inner: Vec<ParsedMacroArg>,
delim: DelimToken,
iter: &mut Cursor,
span: Span,
) -> Option<()> {
let mut buffer = String::new();
let mut first = true;
let mut lo = span.lo();
let mut hi = span.hi();
// Parse '*', '+' or '?.
for tok in iter {
self.set_last_tok(&tok);
if first {
first = false;
lo = tok.span().lo();
}
match tok {
@ -918,7 +902,6 @@ impl MacroArgParser {
}
TokenTree::Token(ref t) => {
buffer.push_str(&pprust::token_to_string(&t));
hi = t.span.hi();
}
_ => return None,
}
@ -930,20 +913,17 @@ impl MacroArgParser {
} else {
Some(Box::new(ParsedMacroArg {
kind: MacroArgKind::Other(buffer, "".to_owned()),
span: mk_sp(lo, hi),
}))
};
self.result.push(ParsedMacroArg {
kind: MacroArgKind::Repeat(delim, inner, another, self.last_tok.clone()),
span: mk_sp(self.lo, self.hi),
});
Some(())
}
fn update_buffer(&mut self, t: &Token) {
if self.buf.is_empty() {
self.lo = t.span.lo();
self.start_tok = t.clone();
} else {
let needs_space = match next_space(&self.last_tok.kind) {
@ -999,7 +979,6 @@ impl MacroArgParser {
// Start keeping the name of this metavariable in the buffer.
self.is_meta_var = true;
self.lo = span.lo();
self.start_tok = Token {
kind: TokenKind::Dollar,
span,
@ -1012,7 +991,7 @@ impl MacroArgParser {
self.add_meta_variable(&mut iter)?;
}
TokenTree::Token(ref t) => self.update_buffer(t),
TokenTree::Delimited(delimited_span, delimited, ref tts) => {
TokenTree::Delimited(_delimited_span, delimited, ref tts) => {
if !self.buf.is_empty() {
if next_space(&self.last_tok.kind) == SpaceState::Always {
self.add_separator();
@ -1022,16 +1001,14 @@ impl MacroArgParser {
}
// Parse the stuff inside delimiters.
let mut parser = MacroArgParser::new();
parser.lo = delimited_span.open.lo();
let parser = MacroArgParser::new();
let delimited_arg = parser.parse(tts.clone())?;
let span = delimited_span.entire();
if self.is_meta_var {
self.add_repeat(delimited_arg, delimited, &mut iter, span)?;
self.add_repeat(delimited_arg, delimited, &mut iter)?;
self.is_meta_var = false;
} else {
self.add_delimited(delimited_arg, delimited, span);
self.add_delimited(delimited_arg, delimited);
}
}
}

View file

@ -27,7 +27,6 @@ type FileModMap<'ast> = BTreeMap<FileName, Module<'ast>>;
pub(crate) struct Module<'a> {
ast_mod_kind: Option<Cow<'a, ast::ModKind>>,
pub(crate) items: Cow<'a, Vec<rustc_ast::ptr::P<ast::Item>>>,
attrs: Cow<'a, Vec<ast::Attribute>>,
inner_attr: Vec<ast::Attribute>,
pub(crate) span: Span,
}
@ -46,7 +45,6 @@ impl<'a> Module<'a> {
.collect();
Module {
items: mod_items,
attrs: mod_attrs,
inner_attr,
span: mod_span,
ast_mod_kind,