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:
commit
22719efcc5
93 changed files with 976 additions and 212 deletions
|
@ -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,8 +441,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
deref_target_ty
|
||||
));
|
||||
|
||||
// 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)) =
|
||||
self.move_error_reported.insert(move_out_indices, (used_place, err))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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())),
|
||||
};
|
||||
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);
|
||||
|
|
|
@ -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();
|
||||
})
|
||||
})
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -16,7 +16,6 @@ macro_rules! declare_features {
|
|||
since: $ver,
|
||||
issue: to_nonzero($issue),
|
||||
edition: None,
|
||||
description: concat!($($doc,)*),
|
||||
}
|
||||
),+
|
||||
];
|
||||
|
|
|
@ -37,7 +37,6 @@ macro_rules! declare_features {
|
|||
since: $ver,
|
||||
issue: to_nonzero($issue),
|
||||
edition: $edition,
|
||||
description: concat!($($doc,)*),
|
||||
}
|
||||
),+];
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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,)*),
|
||||
}
|
||||
),+
|
||||
];
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,12 +785,31 @@ impl<'a> Parser<'a> {
|
|||
let sp = self.prev_token.span.shrink_to_hi();
|
||||
let token_str = pprust::token_kind_to_string(t);
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If this was a missing `@` in a binding pattern
|
||||
// bail with a suggestion
|
||||
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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.
|
||||
///
|
||||
|
|
|
@ -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.
|
||||
///
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
//!
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
///
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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!()
|
||||
|
|
|
@ -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, ¯o_def, def_id, &item.vis),
|
||||
imported_from: None,
|
||||
}),
|
||||
ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref item_ids) => {
|
||||
let items = item_ids
|
||||
|
|
|
@ -2202,7 +2202,6 @@ crate struct ImportSource {
|
|||
#[derive(Clone, Debug)]
|
||||
crate struct Macro {
|
||||
crate source: String,
|
||||
crate imported_from: Option<Symbol>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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(", ");
|
||||
}
|
||||
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,8 +1081,9 @@ 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 {
|
||||
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(),
|
||||
|
@ -1087,6 +1101,8 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
|
|||
);
|
||||
document(w, cx, field, Some(variant));
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
w.write_str("</div></div>");
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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"})
|
||||
|
|
|
@ -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 {
|
||||
|
|
37
src/test/rustdoc-ui/coverage/enum-tuple-documented.rs
Normal file
37
src/test/rustdoc-ui/coverage/enum-tuple-documented.rs
Normal 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,
|
||||
);
|
|
@ -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% |
|
||||
+-------------------------------------+------------+------------+------------+------------+
|
18
src/test/rustdoc-ui/coverage/enum-tuple.rs
Normal file
18
src/test/rustdoc-ui/coverage/enum-tuple.rs
Normal 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);
|
7
src/test/rustdoc-ui/coverage/enum-tuple.stdout
Normal file
7
src/test/rustdoc-ui/coverage/enum-tuple.stdout
Normal 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% |
|
||||
+-------------------------------------+------------+------------+------------+------------+
|
|
@ -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% |
|
||||
+-------------------------------------+------------+------------+------------+------------+
|
||||
|
|
34
src/test/rustdoc/issue-88600.rs
Normal file
34
src/test/rustdoc/issue-88600.rs
Normal 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,
|
||||
},
|
||||
}
|
16
src/test/rustdoc/table-in-docblock.rs
Normal file
16
src/test/rustdoc/table-in-docblock.rs
Normal 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) {}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
// Test binary_search_by_key lifetime. Issue #34683
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
struct Assignment {
|
||||
topic: String,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// run-pass
|
||||
#![allow(dead_code)]
|
||||
#![deny(unused_mut)]
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// check-pass
|
||||
#![allow(unreachable_code)]
|
||||
#![warn(unused)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Point {
|
||||
|
|
|
@ -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");
|
||||
| ^
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
// check-pass
|
||||
#![warn(unused)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
#[derive(Debug)]
|
||||
struct MyStruct {
|
||||
|
|
|
@ -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;
|
||||
| ^
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// edition:2021
|
||||
//check-pass
|
||||
#![warn(unused)]
|
||||
#![allow(dead_code)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
// run-pass
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
45
src/test/ui/derives/clone-debug-dead-code.rs
Normal file
45
src/test/ui/derives/clone-debug-dead-code.rs
Normal 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: () };
|
||||
}
|
38
src/test/ui/derives/clone-debug-dead-code.stderr
Normal file
38
src/test/ui/derives/clone-debug-dead-code.stderr
Normal 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
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
// run-pass
|
||||
// pretty-expanded FIXME #23616
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
#[derive(Clone)]
|
||||
struct S<T> {
|
||||
foo: (),
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
// run-pass
|
||||
// pretty-expanded FIXME #23616
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
#[derive(Clone)]
|
||||
struct S {
|
||||
_int: isize,
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
// run-pass
|
||||
// pretty-expanded FIXME #23616
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
#[derive(Clone)]
|
||||
struct S((), ());
|
||||
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
// run-pass
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
pub fn main() {
|
||||
#[derive(Debug)]
|
||||
struct Foo {
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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
|
||||
|
16
src/test/ui/expr/malformed_closure/ruby_style_closure.rs
Normal file
16
src/test/ui/expr/malformed_closure/ruby_style_closure.rs
Normal 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
|
||||
});
|
||||
}
|
18
src/test/ui/expr/malformed_closure/ruby_style_closure.stderr
Normal file
18
src/test/ui/expr/malformed_closure/ruby_style_closure.stderr
Normal 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`.
|
|
@ -1,4 +1,7 @@
|
|||
// run-pass
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
trait Trait { fn dummy(&self) { } }
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// run-pass
|
||||
#![feature(box_syntax)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
trait T {
|
||||
fn print(&self);
|
||||
|
|
11
src/test/ui/issues/issue-86865.rs
Normal file
11
src/test/ui/issues/issue-86865.rs
Normal 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`
|
||||
}
|
18
src/test/ui/issues/issue-86865.stderr
Normal file
18
src/test/ui/issues/issue-86865.stderr
Normal 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
|
||||
|
|
@ -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
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// run-pass
|
||||
#![allow(unused_mut)]
|
||||
#![allow(dead_code)]
|
||||
#![feature(box_syntax)]
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// run-pass
|
||||
#![allow(unused_mut)]
|
||||
#![allow(dead_code)]
|
||||
#![feature(box_syntax)]
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
// run-pass
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::rc::Rc;
|
||||
use std::ops::Deref;
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// run-pass
|
||||
#![feature(box_syntax)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct Foo {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// run-pass
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
trait noisy {
|
||||
fn speak(&mut self) -> isize;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// run-pass
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
trait noisy {
|
||||
fn speak(&mut self);
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
// run-pass
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Foo {
|
||||
x: isize,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// run-pass
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
#[derive(Debug)]
|
||||
enum a_tag {
|
||||
|
|
16
src/test/ui/suggestions/slice-issue-87994.rs
Normal file
16
src/test/ui/suggestions/slice-issue-87994.rs
Normal 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;
|
||||
}
|
||||
}
|
71
src/test/ui/suggestions/slice-issue-87994.stderr
Normal file
71
src/test/ui/suggestions/slice-issue-87994.stderr
Normal 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`.
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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]);
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// run-rustfix
|
||||
|
||||
#![allow(unused_imports)]
|
||||
#![allow(unused_imports,dead_code)]
|
||||
#![deny(clippy::default_trait_access)]
|
||||
|
||||
use std::default;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// run-rustfix
|
||||
|
||||
#![allow(unused_imports)]
|
||||
#![allow(unused_imports,dead_code)]
|
||||
#![deny(clippy::default_trait_access)]
|
||||
|
||||
use std::default;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Reference in a new issue