Auto merge of #81493 - JohnTitor:rollup-sa4m4zh, r=JohnTitor
Rollup of 10 pull requests Successful merges: - #79570 (rustc: Stabilize `-Zrun-dsymutil` as `-Csplit-debuginfo`) - #79819 (Add `SEMICOLON_IN_EXPRESSIONS_FROM_MACROS` lint) - #79991 (rustdoc: Render HRTB correctly for bare functions) - #80215 (Use -target when linking binaries for Mac Catalyst) - #81158 (Point to span of upvar making closure FnMut) - #81176 (Improve safety of `LateContext::qpath_res`) - #81287 (Split rustdoc JSON types into separately versioned crate) - #81306 (Fuse inner iterator in FlattenCompat and improve related tests) - #81333 (clean up some const error reporting around promoteds) - #81459 (Fix rustdoc text selection for page titles) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
74500b9978
@ -3746,6 +3746,7 @@ dependencies = [
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_lexer",
|
||||
"rustc_lint_defs",
|
||||
"rustc_macros",
|
||||
"rustc_parse",
|
||||
"rustc_serialize",
|
||||
@ -4391,12 +4392,20 @@ dependencies = [
|
||||
"pulldown-cmark 0.8.0",
|
||||
"regex",
|
||||
"rustc-rayon",
|
||||
"rustdoc-json-types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"smallvec 1.4.2",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustdoc-json-types"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustdoc-themes"
|
||||
version = "0.1.0"
|
||||
|
@ -4,6 +4,7 @@ members = [
|
||||
"compiler/rustc",
|
||||
"library/std",
|
||||
"library/test",
|
||||
"src/rustdoc-json-types",
|
||||
"src/tools/cargotest",
|
||||
"src/tools/clippy",
|
||||
"src/tools/compiletest",
|
||||
|
@ -134,11 +134,9 @@ pub(crate) fn codegen_constant<'tcx>(
|
||||
{
|
||||
Ok(const_val) => const_val,
|
||||
Err(_) => {
|
||||
if promoted.is_none() {
|
||||
fx.tcx
|
||||
.sess
|
||||
.span_err(constant.span, "erroneous constant encountered");
|
||||
}
|
||||
fx.tcx
|
||||
.sess
|
||||
.span_err(constant.span, "erroneous constant encountered");
|
||||
return crate::trap::trap_unreachable_ret_value(
|
||||
fx,
|
||||
fx.layout_of(const_.ty),
|
||||
|
@ -732,10 +732,7 @@ pub unsafe fn optimize_thin_module(
|
||||
let diag_handler = cgcx.create_diag_handler();
|
||||
|
||||
let module_name = &thin_module.shared.module_names[thin_module.idx];
|
||||
let split_dwarf_file = cgcx
|
||||
.output_filenames
|
||||
.split_dwarf_filename(cgcx.split_dwarf_kind, Some(module_name.to_str().unwrap()));
|
||||
let tm_factory_config = TargetMachineFactoryConfig { split_dwarf_file };
|
||||
let tm_factory_config = TargetMachineFactoryConfig::new(cgcx, module_name.to_str().unwrap());
|
||||
let tm =
|
||||
(cgcx.tm_factory)(tm_factory_config).map_err(|e| write::llvm_err(&diag_handler, &e))?;
|
||||
|
||||
|
@ -23,13 +23,11 @@ use rustc_fs_util::{link_or_copy, path_to_c_string};
|
||||
use rustc_hir::def_id::LOCAL_CRATE;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::config::{
|
||||
self, Lto, OutputType, Passes, SanitizerSet, SplitDwarfKind, SwitchWithOptPath,
|
||||
};
|
||||
use rustc_session::config::{self, Lto, OutputType, Passes, SanitizerSet, SwitchWithOptPath};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::InnerSpan;
|
||||
use rustc_target::spec::{CodeModel, RelocModel};
|
||||
use rustc_target::spec::{CodeModel, RelocModel, SplitDebuginfo};
|
||||
use tracing::debug;
|
||||
|
||||
use libc::{c_char, c_int, c_uint, c_void, size_t};
|
||||
@ -93,9 +91,12 @@ pub fn create_informational_target_machine(sess: &Session) -> &'static mut llvm:
|
||||
}
|
||||
|
||||
pub fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> &'static mut llvm::TargetMachine {
|
||||
let split_dwarf_file = tcx
|
||||
.output_filenames(LOCAL_CRATE)
|
||||
.split_dwarf_filename(tcx.sess.opts.debugging_opts.split_dwarf, Some(mod_name));
|
||||
let split_dwarf_file = if tcx.sess.target_can_use_split_dwarf() {
|
||||
tcx.output_filenames(LOCAL_CRATE)
|
||||
.split_dwarf_filename(tcx.sess.split_debuginfo(), Some(mod_name))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let config = TargetMachineFactoryConfig { split_dwarf_file };
|
||||
target_machine_factory(&tcx.sess, tcx.backend_optimization_level(LOCAL_CRATE))(config)
|
||||
.unwrap_or_else(|err| llvm_err(tcx.sess.diagnostic(), &err).raise())
|
||||
@ -838,11 +839,17 @@ pub(crate) unsafe fn codegen(
|
||||
.generic_activity_with_arg("LLVM_module_codegen_emit_obj", &module.name[..]);
|
||||
|
||||
let dwo_out = cgcx.output_filenames.temp_path_dwo(module_name);
|
||||
let dwo_out = match cgcx.split_dwarf_kind {
|
||||
let dwo_out = match cgcx.split_debuginfo {
|
||||
// Don't change how DWARF is emitted in single mode (or when disabled).
|
||||
SplitDwarfKind::None | SplitDwarfKind::Single => None,
|
||||
SplitDebuginfo::Off | SplitDebuginfo::Packed => None,
|
||||
// Emit (a subset of the) DWARF into a separate file in split mode.
|
||||
SplitDwarfKind::Split => Some(dwo_out.as_path()),
|
||||
SplitDebuginfo::Unpacked => {
|
||||
if cgcx.target_can_use_split_dwarf {
|
||||
Some(dwo_out.as_path())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
with_codegen(tm, llmod, config.no_builtins, |cpm| {
|
||||
@ -880,7 +887,7 @@ pub(crate) unsafe fn codegen(
|
||||
|
||||
Ok(module.into_compiled_module(
|
||||
config.emit_obj != EmitObj::None,
|
||||
cgcx.split_dwarf_kind == SplitDwarfKind::Split,
|
||||
cgcx.target_can_use_split_dwarf && cgcx.split_debuginfo == SplitDebuginfo::Unpacked,
|
||||
config.emit_bc,
|
||||
&cgcx.output_filenames,
|
||||
))
|
||||
|
@ -995,10 +995,13 @@ pub fn compile_unit_metadata(
|
||||
let flags = "\0";
|
||||
|
||||
let out_dir = &tcx.output_filenames(LOCAL_CRATE).out_directory;
|
||||
let split_name = tcx
|
||||
.output_filenames(LOCAL_CRATE)
|
||||
.split_dwarf_filename(tcx.sess.opts.debugging_opts.split_dwarf, Some(codegen_unit_name))
|
||||
.unwrap_or_default();
|
||||
let split_name = if tcx.sess.target_can_use_split_dwarf() {
|
||||
tcx.output_filenames(LOCAL_CRATE)
|
||||
.split_dwarf_filename(tcx.sess.split_debuginfo(), Some(codegen_unit_name))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
.unwrap_or_default();
|
||||
let out_dir = out_dir.to_str().unwrap();
|
||||
let split_name = split_name.to_str().unwrap();
|
||||
|
||||
|
@ -351,12 +351,7 @@ impl ModuleLlvm {
|
||||
unsafe {
|
||||
let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names);
|
||||
let llmod_raw = back::lto::parse_module(llcx, name, buffer, handler)?;
|
||||
|
||||
let split_dwarf_file = cgcx
|
||||
.output_filenames
|
||||
.split_dwarf_filename(cgcx.split_dwarf_kind, Some(name.to_str().unwrap()));
|
||||
let tm_factory_config = TargetMachineFactoryConfig { split_dwarf_file };
|
||||
|
||||
let tm_factory_config = TargetMachineFactoryConfig::new(&cgcx, name.to_str().unwrap());
|
||||
let tm = match (cgcx.tm_factory)(tm_factory_config) {
|
||||
Ok(m) => m,
|
||||
Err(e) => {
|
||||
|
@ -14,7 +14,7 @@ use rustc_session::utils::NativeLibKind;
|
||||
use rustc_session::{filesearch, Session};
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_target::spec::crt_objects::{CrtObjects, CrtObjectsFallback};
|
||||
use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor};
|
||||
use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor, SplitDebuginfo};
|
||||
use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, Target};
|
||||
|
||||
use super::archive::ArchiveBuilder;
|
||||
@ -99,9 +99,6 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
|
||||
path.as_ref(),
|
||||
target_cpu,
|
||||
);
|
||||
if sess.opts.debugging_opts.split_dwarf == config::SplitDwarfKind::Split {
|
||||
link_dwarf_object(sess, &out_filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
if sess.opts.json_artifact_notifications {
|
||||
@ -828,29 +825,43 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
|
||||
}
|
||||
}
|
||||
|
||||
// On macOS, debuggers need this utility to get run to do some munging of
|
||||
// the symbols. Note, though, that if the object files are being preserved
|
||||
// for their debug information there's no need for us to run dsymutil.
|
||||
if sess.target.is_like_osx
|
||||
&& sess.opts.debuginfo != DebugInfo::None
|
||||
&& !preserve_objects_for_their_debuginfo(sess)
|
||||
{
|
||||
let prog = Command::new("dsymutil").arg(out_filename).output();
|
||||
match prog {
|
||||
Ok(prog) => {
|
||||
if !prog.status.success() {
|
||||
let mut output = prog.stderr.clone();
|
||||
output.extend_from_slice(&prog.stdout);
|
||||
sess.struct_warn(&format!(
|
||||
"processing debug info with `dsymutil` failed: {}",
|
||||
prog.status
|
||||
))
|
||||
.note(&escape_string(&output))
|
||||
.emit();
|
||||
match sess.split_debuginfo() {
|
||||
// If split debug information is disabled or located in individual files
|
||||
// there's nothing to do here.
|
||||
SplitDebuginfo::Off | SplitDebuginfo::Unpacked => {}
|
||||
|
||||
// If packed split-debuginfo is requested, but the final compilation
|
||||
// doesn't actually have any debug information, then we skip this step.
|
||||
SplitDebuginfo::Packed if sess.opts.debuginfo == DebugInfo::None => {}
|
||||
|
||||
// On macOS the external `dsymutil` tool is used to create the packed
|
||||
// debug information. Note that this will read debug information from
|
||||
// the objects on the filesystem which we'll clean up later.
|
||||
SplitDebuginfo::Packed if sess.target.is_like_osx => {
|
||||
let prog = Command::new("dsymutil").arg(out_filename).output();
|
||||
match prog {
|
||||
Ok(prog) => {
|
||||
if !prog.status.success() {
|
||||
let mut output = prog.stderr.clone();
|
||||
output.extend_from_slice(&prog.stdout);
|
||||
sess.struct_warn(&format!(
|
||||
"processing debug info with `dsymutil` failed: {}",
|
||||
prog.status
|
||||
))
|
||||
.note(&escape_string(&output))
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
Err(e) => sess.fatal(&format!("unable to run `dsymutil`: {}", e)),
|
||||
}
|
||||
Err(e) => sess.fatal(&format!("unable to run `dsymutil`: {}", e)),
|
||||
}
|
||||
|
||||
// On MSVC packed debug information is produced by the linker itself so
|
||||
// there's no need to do anything else here.
|
||||
SplitDebuginfo::Packed if sess.target.is_like_msvc => {}
|
||||
|
||||
// ... and otherwise we're processing a `*.dwp` packed dwarf file.
|
||||
SplitDebuginfo::Packed => link_dwarf_object(sess, &out_filename),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1050,28 +1061,9 @@ fn preserve_objects_for_their_debuginfo(sess: &Session) -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Single mode keeps debuginfo in the same object file, but in such a way that it it skipped
|
||||
// by the linker - so it's expected that when codegen units are linked together that this
|
||||
// debuginfo would be lost without keeping around the temps.
|
||||
if sess.opts.debugging_opts.split_dwarf == config::SplitDwarfKind::Single {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we're on OSX then the equivalent of split dwarf is turned on by
|
||||
// default. The final executable won't actually have any debug information
|
||||
// except it'll have pointers to elsewhere. Historically we've always run
|
||||
// `dsymutil` to "link all the dwarf together" but this is actually sort of
|
||||
// a bummer for incremental compilation! (the whole point of split dwarf is
|
||||
// that you don't do this sort of dwarf link).
|
||||
//
|
||||
// Basically as a result this just means that if we're on OSX and we're
|
||||
// *not* running dsymutil then the object files are the only source of truth
|
||||
// for debug information, so we must preserve them.
|
||||
if sess.target.is_like_osx {
|
||||
return !sess.opts.debugging_opts.run_dsymutil;
|
||||
}
|
||||
|
||||
false
|
||||
// "unpacked" split debuginfo means that we leave object files as the
|
||||
// debuginfo is found in the original object files themselves
|
||||
sess.split_debuginfo() == SplitDebuginfo::Unpacked
|
||||
}
|
||||
|
||||
pub fn archive_search_paths(sess: &Session) -> Vec<PathBuf> {
|
||||
@ -2211,8 +2203,13 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
|
||||
return;
|
||||
}
|
||||
};
|
||||
let arch_name = llvm_target.split('-').next().expect("LLVM target must have a hyphen");
|
||||
cmd.args(&["-arch", arch_name, "-isysroot", &sdk_root, "-Wl,-syslibroot", &sdk_root]);
|
||||
if llvm_target.contains("macabi") {
|
||||
cmd.args(&["-target", llvm_target])
|
||||
} else {
|
||||
let arch_name = llvm_target.split('-').next().expect("LLVM target must have a hyphen");
|
||||
cmd.args(&["-arch", arch_name])
|
||||
}
|
||||
cmd.args(&["-isysroot", &sdk_root, "-Wl,-syslibroot", &sdk_root]);
|
||||
}
|
||||
|
||||
fn get_apple_sdk_root(sdk_name: &str) -> Result<String, String> {
|
||||
|
@ -282,6 +282,20 @@ pub struct TargetMachineFactoryConfig {
|
||||
pub split_dwarf_file: Option<PathBuf>,
|
||||
}
|
||||
|
||||
impl TargetMachineFactoryConfig {
|
||||
pub fn new(
|
||||
cgcx: &CodegenContext<impl WriteBackendMethods>,
|
||||
module_name: &str,
|
||||
) -> TargetMachineFactoryConfig {
|
||||
let split_dwarf_file = if cgcx.target_can_use_split_dwarf {
|
||||
cgcx.output_filenames.split_dwarf_filename(cgcx.split_debuginfo, Some(module_name))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
TargetMachineFactoryConfig { split_dwarf_file }
|
||||
}
|
||||
}
|
||||
|
||||
pub type TargetMachineFactoryFn<B> = Arc<
|
||||
dyn Fn(TargetMachineFactoryConfig) -> Result<<B as WriteBackendMethods>::TargetMachine, String>
|
||||
+ Send
|
||||
@ -311,10 +325,11 @@ pub struct CodegenContext<B: WriteBackendMethods> {
|
||||
pub tm_factory: TargetMachineFactoryFn<B>,
|
||||
pub msvc_imps_needed: bool,
|
||||
pub is_pe_coff: bool,
|
||||
pub target_can_use_split_dwarf: bool,
|
||||
pub target_pointer_width: u32,
|
||||
pub target_arch: String,
|
||||
pub debuginfo: config::DebugInfo,
|
||||
pub split_dwarf_kind: config::SplitDwarfKind,
|
||||
pub split_debuginfo: rustc_target::spec::SplitDebuginfo,
|
||||
|
||||
// Number of cgus excluding the allocator/metadata modules
|
||||
pub total_cgus: usize,
|
||||
@ -1035,10 +1050,11 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
||||
total_cgus,
|
||||
msvc_imps_needed: msvc_imps_needed(tcx),
|
||||
is_pe_coff: tcx.sess.target.is_like_windows,
|
||||
target_can_use_split_dwarf: tcx.sess.target_can_use_split_dwarf(),
|
||||
target_pointer_width: tcx.sess.target.pointer_width,
|
||||
target_arch: tcx.sess.target.arch.clone(),
|
||||
debuginfo: tcx.sess.opts.debuginfo,
|
||||
split_dwarf_kind: tcx.sess.opts.debugging_opts.split_dwarf,
|
||||
split_debuginfo: tcx.sess.split_debuginfo(),
|
||||
};
|
||||
|
||||
// This is the "main loop" of parallel work happening for parallel codegen.
|
||||
|
@ -30,12 +30,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
.tcx()
|
||||
.const_eval_resolve(ty::ParamEnv::reveal_all(), def, substs, promoted, None)
|
||||
.map_err(|err| {
|
||||
if promoted.is_none() {
|
||||
self.cx
|
||||
.tcx()
|
||||
.sess
|
||||
.span_err(constant.span, "erroneous constant encountered");
|
||||
}
|
||||
self.cx.tcx().sess.span_err(constant.span, "erroneous constant encountered");
|
||||
err
|
||||
}),
|
||||
ty::ConstKind::Value(value) => Ok(value),
|
||||
|
@ -18,6 +18,7 @@ rustc_attr = { path = "../rustc_attr" }
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
rustc_feature = { path = "../rustc_feature" }
|
||||
rustc_lint_defs = { path = "../rustc_lint_defs" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_lexer = { path = "../rustc_lexer" }
|
||||
rustc_parse = { path = "../rustc_parse" }
|
||||
|
@ -11,12 +11,14 @@ use crate::mbe::transcribe::transcribe;
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::token::{self, NonterminalKind, NtTT, Token, TokenKind::*};
|
||||
use rustc_ast::tokenstream::{DelimSpan, TokenStream};
|
||||
use rustc_ast::NodeId;
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_attr::{self as attr, TransparencyError};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::{Applicability, DiagnosticBuilder};
|
||||
use rustc_feature::Features;
|
||||
use rustc_lint_defs::builtin::SEMICOLON_IN_EXPRESSIONS_FROM_MACROS;
|
||||
use rustc_parse::parser::Parser;
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_session::Session;
|
||||
@ -37,6 +39,7 @@ crate struct ParserAnyMacro<'a> {
|
||||
site_span: Span,
|
||||
/// The ident of the macro we're parsing
|
||||
macro_ident: Ident,
|
||||
lint_node_id: NodeId,
|
||||
arm_span: Span,
|
||||
}
|
||||
|
||||
@ -110,7 +113,8 @@ fn emit_frag_parse_err(
|
||||
|
||||
impl<'a> ParserAnyMacro<'a> {
|
||||
crate fn make(mut self: Box<ParserAnyMacro<'a>>, kind: AstFragmentKind) -> AstFragment {
|
||||
let ParserAnyMacro { site_span, macro_ident, ref mut parser, arm_span } = *self;
|
||||
let ParserAnyMacro { site_span, macro_ident, ref mut parser, lint_node_id, arm_span } =
|
||||
*self;
|
||||
let snapshot = &mut parser.clone();
|
||||
let fragment = match parse_ast_fragment(parser, kind) {
|
||||
Ok(f) => f,
|
||||
@ -124,6 +128,12 @@ impl<'a> ParserAnyMacro<'a> {
|
||||
// `macro_rules! m { () => { panic!(); } }` isn't parsed by `.parse_expr()`,
|
||||
// but `m!()` is allowed in expression positions (cf. issue #34706).
|
||||
if kind == AstFragmentKind::Expr && parser.token == token::Semi {
|
||||
parser.sess.buffer_lint(
|
||||
SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
|
||||
parser.token.span,
|
||||
lint_node_id,
|
||||
"trailing semicolon in macro used in expression position",
|
||||
);
|
||||
parser.bump();
|
||||
}
|
||||
|
||||
@ -276,6 +286,7 @@ fn generic_extension<'cx>(
|
||||
|
||||
let mut p = Parser::new(sess, tts, false, None);
|
||||
p.last_type_ascription = cx.current_expansion.prior_type_ascription;
|
||||
let lint_node_id = cx.resolver.lint_node_id(cx.current_expansion.id);
|
||||
|
||||
// Let the context choose how to interpret the result.
|
||||
// Weird, but useful for X-macros.
|
||||
@ -287,6 +298,7 @@ fn generic_extension<'cx>(
|
||||
// macro leaves unparsed tokens.
|
||||
site_span: sp,
|
||||
macro_ident: name,
|
||||
lint_node_id,
|
||||
arm_span,
|
||||
});
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ use rustc_span::edition::{Edition, DEFAULT_EDITION};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::SourceFileHashAlgorithm;
|
||||
use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy};
|
||||
use rustc_target::spec::{RelocModel, RelroLevel, TlsModel};
|
||||
use rustc_target::spec::{RelocModel, RelroLevel, SplitDebuginfo, TlsModel};
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::iter::FromIterator;
|
||||
use std::path::PathBuf;
|
||||
@ -446,6 +446,7 @@ fn test_codegen_options_tracking_hash() {
|
||||
tracked!(profile_use, Some(PathBuf::from("abc")));
|
||||
tracked!(relocation_model, Some(RelocModel::Pic));
|
||||
tracked!(soft_float, true);
|
||||
tracked!(split_debuginfo, Some(SplitDebuginfo::Packed));
|
||||
tracked!(target_cpu, Some(String::from("abc")));
|
||||
tracked!(target_feature, String::from("all the features, all of them"));
|
||||
}
|
||||
@ -579,7 +580,6 @@ fn test_debugging_options_tracking_hash() {
|
||||
tracked!(relax_elf_relocations, Some(true));
|
||||
tracked!(relro_level, Some(RelroLevel::Full));
|
||||
tracked!(report_delayed_bugs, true);
|
||||
tracked!(run_dsymutil, false);
|
||||
tracked!(sanitizer, SanitizerSet::ADDRESS);
|
||||
tracked!(sanitizer_memory_track_origins, 2);
|
||||
tracked!(sanitizer_recover, SanitizerSet::ADDRESS);
|
||||
|
@ -746,6 +746,14 @@ impl<'tcx> LateContext<'tcx> {
|
||||
hir::QPath::Resolved(_, ref path) => path.res,
|
||||
hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
|
||||
.maybe_typeck_results()
|
||||
.filter(|typeck_results| typeck_results.hir_owner == id.owner)
|
||||
.or_else(|| {
|
||||
if self.tcx.has_typeck_results(id.owner.to_def_id()) {
|
||||
Some(self.tcx.typeck(id.owner))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.and_then(|typeck_results| typeck_results.type_dependent_def(id))
|
||||
.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
|
||||
}
|
||||
|
@ -140,6 +140,8 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
|
||||
fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
|
||||
let generics = self.context.generics.take();
|
||||
self.context.generics = it.kind.generics();
|
||||
let old_cached_typeck_results = self.context.cached_typeck_results.take();
|
||||
let old_enclosing_body = self.context.enclosing_body.take();
|
||||
self.with_lint_attrs(it.hir_id, &it.attrs, |cx| {
|
||||
cx.with_param_env(it.hir_id, |cx| {
|
||||
lint_callback!(cx, check_item, it);
|
||||
@ -147,6 +149,8 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
|
||||
lint_callback!(cx, check_item_post, it);
|
||||
});
|
||||
});
|
||||
self.context.enclosing_body = old_enclosing_body;
|
||||
self.context.cached_typeck_results.set(old_cached_typeck_results);
|
||||
self.context.generics = generics;
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
// ignore-tidy-filelength
|
||||
//! Some lints that are built in to the compiler.
|
||||
//!
|
||||
//! These are the built-in lints that are emitted direct in the main
|
||||
@ -2833,6 +2834,52 @@ declare_lint! {
|
||||
"detects `#[unstable]` on stable trait implementations for stable types"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `semicolon_in_expressions_from_macros` lint detects trailing semicolons
|
||||
/// in macro bodies when the macro is invoked in expression position.
|
||||
/// This was previous accepted, but is being phased out.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// #![deny(semicolon_in_expressions_from_macros)]
|
||||
/// macro_rules! foo {
|
||||
/// () => { true; }
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// let val = match true {
|
||||
/// true => false,
|
||||
/// _ => foo!()
|
||||
/// };
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Previous, Rust ignored trailing semicolon in a macro
|
||||
/// body when a macro was invoked in expression position.
|
||||
/// However, this makes the treatment of semicolons in the language
|
||||
/// inconsistent, and could lead to unexpected runtime behavior
|
||||
/// in some circumstances (e.g. if the macro author expects
|
||||
/// a value to be dropped).
|
||||
///
|
||||
/// This is a [future-incompatible] lint to transition this
|
||||
/// to a hard error in the future. See [issue #79813] for more details.
|
||||
///
|
||||
/// [issue #79813]: https://github.com/rust-lang/rust/issues/79813
|
||||
/// [future-incompatible]: ../index.md#future-incompatible-lints
|
||||
pub SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
|
||||
Allow,
|
||||
"trailing semicolon in macro body used as expression",
|
||||
@future_incompatible = FutureIncompatibleInfo {
|
||||
reference: "issue #79813 <https://github.com/rust-lang/rust/issues/79813>",
|
||||
edition: None,
|
||||
};
|
||||
}
|
||||
|
||||
declare_lint_pass! {
|
||||
/// Does nothing as a lint pass, but registers some `Lint`s
|
||||
/// that are used by other parts of the compiler.
|
||||
@ -2920,6 +2967,7 @@ declare_lint_pass! {
|
||||
USELESS_DEPRECATED,
|
||||
UNSUPPORTED_NAKED_FUNCTIONS,
|
||||
MISSING_ABI,
|
||||
SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,12 @@
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::Node;
|
||||
use rustc_index::vec::Idx;
|
||||
use rustc_middle::mir::{self, ClearCrossCrate, Local, LocalDecl, LocalInfo, Location};
|
||||
use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::{
|
||||
hir::place::PlaceBase,
|
||||
mir::{self, ClearCrossCrate, Local, LocalDecl, LocalInfo, Location},
|
||||
};
|
||||
use rustc_span::source_map::DesugaringKind;
|
||||
use rustc_span::symbol::{kw, Symbol};
|
||||
use rustc_span::Span;
|
||||
@ -241,6 +244,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
format!("mut {}", self.local_names[local].unwrap()),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
let tcx = self.infcx.tcx;
|
||||
if let ty::Closure(id, _) = the_place_err.ty(self.body, tcx).ty.kind() {
|
||||
self.show_mutating_upvar(tcx, id, the_place_err, &mut err);
|
||||
}
|
||||
}
|
||||
|
||||
// Also suggest adding mut for upvars
|
||||
@ -271,6 +278,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let tcx = self.infcx.tcx;
|
||||
if let ty::Ref(_, ty, Mutability::Mut) = the_place_err.ty(self.body, tcx).ty.kind()
|
||||
{
|
||||
if let ty::Closure(id, _) = ty.kind() {
|
||||
self.show_mutating_upvar(tcx, id, the_place_err, &mut err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// complete hack to approximate old AST-borrowck
|
||||
@ -463,6 +478,45 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
err.buffer(&mut self.errors_buffer);
|
||||
}
|
||||
|
||||
// point to span of upvar making closure call require mutable borrow
|
||||
fn show_mutating_upvar(
|
||||
&self,
|
||||
tcx: TyCtxt<'_>,
|
||||
id: &hir::def_id::DefId,
|
||||
the_place_err: PlaceRef<'tcx>,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
) {
|
||||
let id = id.expect_local();
|
||||
let tables = tcx.typeck(id);
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(id);
|
||||
let (span, place) = &tables.closure_kind_origins()[hir_id];
|
||||
let reason = if let PlaceBase::Upvar(upvar_id) = place.base {
|
||||
let upvar = ty::place_to_string_for_capture(tcx, place);
|
||||
match tables.upvar_capture(upvar_id) {
|
||||
ty::UpvarCapture::ByRef(ty::UpvarBorrow {
|
||||
kind: ty::BorrowKind::MutBorrow,
|
||||
..
|
||||
}) => {
|
||||
format!("mutable borrow of `{}`", upvar)
|
||||
}
|
||||
ty::UpvarCapture::ByValue(_) => {
|
||||
format!("possible mutation of `{}`", upvar)
|
||||
}
|
||||
_ => bug!("upvar `{}` borrowed, but not mutably", upvar),
|
||||
}
|
||||
} else {
|
||||
bug!("not an upvar")
|
||||
};
|
||||
err.span_label(
|
||||
*span,
|
||||
format!(
|
||||
"calling `{}` requires mutable binding due to {}",
|
||||
self.describe_place(the_place_err).unwrap(),
|
||||
reason
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Targeted error when encountering an `FnMut` closure where an `Fn` closure was expected.
|
||||
fn expected_fn_found_fn_mut_call(&self, err: &mut DiagnosticBuilder<'_>, sp: Span, act: &str) {
|
||||
err.span_label(sp, format!("cannot {}", act));
|
||||
|
@ -298,6 +298,8 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
|
||||
tcx.def_span(def.did),
|
||||
key.param_env,
|
||||
CompileTimeInterpreter::new(tcx.sess.const_eval_limit()),
|
||||
// Statics (and promoteds inside statics) may access other statics, because unlike consts
|
||||
// they do not have to behave "as if" they were evaluated at runtime.
|
||||
MemoryExtra { can_access_statics: is_static },
|
||||
);
|
||||
|
||||
@ -305,83 +307,35 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
|
||||
match res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, &body)) {
|
||||
Err(error) => {
|
||||
let err = ConstEvalErr::new(&ecx, error, None);
|
||||
// errors in statics are always emitted as fatal errors
|
||||
if is_static {
|
||||
// Ensure that if the above error was either `TooGeneric` or `Reported`
|
||||
// an error must be reported.
|
||||
let v = err.report_as_error(
|
||||
ecx.tcx.at(ecx.cur_span()),
|
||||
"could not evaluate static initializer",
|
||||
);
|
||||
|
||||
// If this is `Reveal:All`, then we need to make sure an error is reported but if
|
||||
// this is `Reveal::UserFacing`, then it's expected that we could get a
|
||||
// `TooGeneric` error. When we fall back to `Reveal::All`, then it will either
|
||||
// succeed or we'll report this error then.
|
||||
if key.param_env.reveal() == Reveal::All {
|
||||
tcx.sess.delay_span_bug(
|
||||
err.span,
|
||||
&format!("static eval failure did not emit an error: {:#?}", v),
|
||||
);
|
||||
}
|
||||
|
||||
Err(v)
|
||||
} else if let Some(def) = def.as_local() {
|
||||
// constant defined in this crate, we can figure out a lint level!
|
||||
match tcx.def_kind(def.did.to_def_id()) {
|
||||
// constants never produce a hard error at the definition site. Anything else is
|
||||
// a backwards compatibility hazard (and will break old versions of winapi for
|
||||
// sure)
|
||||
//
|
||||
// note that validation may still cause a hard error on this very same constant,
|
||||
// because any code that existed before validation could not have failed
|
||||
// validation thus preventing such a hard error from being a backwards
|
||||
// compatibility hazard
|
||||
DefKind::Const | DefKind::AssocConst => {
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
|
||||
Err(err.report_as_lint(
|
||||
tcx.at(tcx.def_span(def.did)),
|
||||
"any use of this value will cause an error",
|
||||
hir_id,
|
||||
Some(err.span),
|
||||
))
|
||||
}
|
||||
// promoting runtime code is only allowed to error if it references broken
|
||||
// constants any other kind of error will be reported to the user as a
|
||||
// deny-by-default lint
|
||||
_ => {
|
||||
if let Some(p) = cid.promoted {
|
||||
let span = tcx.promoted_mir_opt_const_arg(def.to_global())[p].span;
|
||||
if let err_inval!(ReferencedConstant) = err.error {
|
||||
Err(err.report_as_error(
|
||||
tcx.at(span),
|
||||
"evaluation of constant expression failed",
|
||||
))
|
||||
} else {
|
||||
Err(err.report_as_lint(
|
||||
tcx.at(span),
|
||||
"reaching this expression at runtime will panic or abort",
|
||||
tcx.hir().local_def_id_to_hir_id(def.did),
|
||||
Some(err.span),
|
||||
))
|
||||
}
|
||||
// anything else (array lengths, enum initializers, constant patterns) are
|
||||
// reported as hard errors
|
||||
} else {
|
||||
Err(err.report_as_error(
|
||||
ecx.tcx.at(ecx.cur_span()),
|
||||
"evaluation of constant value failed",
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
// Some CTFE errors raise just a lint, not a hard error; see
|
||||
// <https://github.com/rust-lang/rust/issues/71800>.
|
||||
let emit_as_lint = if let Some(def) = def.as_local() {
|
||||
// (Associated) consts only emit a lint, since they might be unused.
|
||||
matches!(tcx.def_kind(def.did.to_def_id()), DefKind::Const | DefKind::AssocConst)
|
||||
} else {
|
||||
// use of broken constant from other crate
|
||||
Err(err.report_as_error(ecx.tcx.at(ecx.cur_span()), "could not evaluate constant"))
|
||||
// use of broken constant from other crate: always an error
|
||||
false
|
||||
};
|
||||
if emit_as_lint {
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(def.as_local().unwrap().did);
|
||||
Err(err.report_as_lint(
|
||||
tcx.at(tcx.def_span(def.did)),
|
||||
"any use of this value will cause an error",
|
||||
hir_id,
|
||||
Some(err.span),
|
||||
))
|
||||
} else {
|
||||
let msg = if is_static {
|
||||
"could not evaluate static initializer"
|
||||
} else {
|
||||
"evaluation of constant value failed"
|
||||
};
|
||||
Err(err.report_as_error(ecx.tcx.at(ecx.cur_span()), msg))
|
||||
}
|
||||
}
|
||||
Ok(mplace) => {
|
||||
// Since evaluation had no errors, valiate the resulting constant:
|
||||
// Since evaluation had no errors, validate the resulting constant.
|
||||
// This is a separate `try` block to provide more targeted error reporting.
|
||||
let validation = try {
|
||||
let mut ref_tracking = RefTracking::new(mplace);
|
||||
let mut inner = false;
|
||||
@ -399,7 +353,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
|
||||
}
|
||||
};
|
||||
if let Err(error) = validation {
|
||||
// Validation failed, report an error
|
||||
// Validation failed, report an error. This is always a hard error.
|
||||
let err = ConstEvalErr::new(&ecx, error, None);
|
||||
Err(err.struct_error(
|
||||
ecx.tcx,
|
||||
|
@ -344,6 +344,8 @@ impl<'a> ResolverExpand for Resolver<'a> {
|
||||
}
|
||||
|
||||
fn lint_node_id(&mut self, expn_id: ExpnId) -> NodeId {
|
||||
// FIXME - make this more precise. This currently returns the NodeId of the
|
||||
// nearest closing item - we should try to return the closest parent of the ExpnId
|
||||
self.invocation_parents
|
||||
.get(&expn_id)
|
||||
.map_or(ast::CRATE_NODE_ID, |id| self.def_id_to_node_id[*id])
|
||||
|
@ -13,7 +13,7 @@ use rustc_data_structures::impl_stable_hash_via_hash;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
|
||||
use rustc_target::abi::{Align, TargetDataLayout};
|
||||
use rustc_target::spec::{Target, TargetTriple};
|
||||
use rustc_target::spec::{SplitDebuginfo, Target, TargetTriple};
|
||||
|
||||
use crate::parse::CrateConfig;
|
||||
use rustc_feature::UnstableFeatures;
|
||||
@ -221,23 +221,6 @@ pub enum DebugInfo {
|
||||
Full,
|
||||
}
|
||||
|
||||
/// Some debuginfo requires link-time relocation and some does not. LLVM can partition the debuginfo
|
||||
/// into sections depending on whether or not it requires link-time relocation. Split DWARF
|
||||
/// provides a mechanism which allows the linker to skip the sections which don't require link-time
|
||||
/// relocation - either by putting those sections into DWARF object files, or keeping them in the
|
||||
/// object file in such a way that the linker will skip them.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Hash)]
|
||||
pub enum SplitDwarfKind {
|
||||
/// Disabled.
|
||||
None,
|
||||
/// Sections which do not require relocation are written into the object file but ignored
|
||||
/// by the linker.
|
||||
Single,
|
||||
/// Sections which do not require relocation are written into a DWARF object (`.dwo`) file,
|
||||
/// which is skipped by the linker by virtue of being a different file.
|
||||
Split,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
|
||||
#[derive(Encodable, Decodable)]
|
||||
pub enum OutputType {
|
||||
@ -635,10 +618,10 @@ impl OutputFilenames {
|
||||
/// mode is being used, which is the logic that this function is intended to encapsulate.
|
||||
pub fn split_dwarf_filename(
|
||||
&self,
|
||||
split_dwarf_kind: SplitDwarfKind,
|
||||
split_debuginfo_kind: SplitDebuginfo,
|
||||
cgu_name: Option<&str>,
|
||||
) -> Option<PathBuf> {
|
||||
self.split_dwarf_path(split_dwarf_kind, cgu_name)
|
||||
self.split_dwarf_path(split_debuginfo_kind, cgu_name)
|
||||
.map(|path| path.strip_prefix(&self.out_directory).unwrap_or(&path).to_path_buf())
|
||||
}
|
||||
|
||||
@ -646,19 +629,19 @@ impl OutputFilenames {
|
||||
/// mode is being used, which is the logic that this function is intended to encapsulate.
|
||||
pub fn split_dwarf_path(
|
||||
&self,
|
||||
split_dwarf_kind: SplitDwarfKind,
|
||||
split_debuginfo_kind: SplitDebuginfo,
|
||||
cgu_name: Option<&str>,
|
||||
) -> Option<PathBuf> {
|
||||
let obj_out = self.temp_path(OutputType::Object, cgu_name);
|
||||
let dwo_out = self.temp_path_dwo(cgu_name);
|
||||
match split_dwarf_kind {
|
||||
SplitDwarfKind::None => None,
|
||||
match split_debuginfo_kind {
|
||||
SplitDebuginfo::Off => None,
|
||||
// Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes
|
||||
// (pointing at the path which is being determined here). Use the path to the current
|
||||
// object file.
|
||||
SplitDwarfKind::Single => Some(obj_out),
|
||||
SplitDebuginfo::Packed => Some(obj_out),
|
||||
// Split mode emits the DWARF into a different file, use that path.
|
||||
SplitDwarfKind::Split => Some(dwo_out),
|
||||
SplitDebuginfo::Unpacked => Some(dwo_out),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1910,6 +1893,15 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
||||
|
||||
let pretty = parse_pretty(matches, &debugging_opts, error_format);
|
||||
|
||||
if !debugging_opts.unstable_options
|
||||
&& !target_triple.triple().contains("apple")
|
||||
&& cg.split_debuginfo.is_some()
|
||||
{
|
||||
{
|
||||
early_error(error_format, "`-Csplit-debuginfo` is unstable on this platform");
|
||||
}
|
||||
}
|
||||
|
||||
Options {
|
||||
crate_types,
|
||||
optimize: opt_level,
|
||||
@ -2191,7 +2183,7 @@ crate mod dep_tracking {
|
||||
use rustc_feature::UnstableFeatures;
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
|
||||
use rustc_target::spec::{RelroLevel, TargetTriple, TlsModel};
|
||||
use rustc_target::spec::{RelroLevel, SplitDebuginfo, TargetTriple, TlsModel};
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::collections::BTreeMap;
|
||||
use std::hash::Hash;
|
||||
@ -2263,6 +2255,7 @@ crate mod dep_tracking {
|
||||
impl_dep_tracking_hash_via_hash!(TargetTriple);
|
||||
impl_dep_tracking_hash_via_hash!(Edition);
|
||||
impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
|
||||
impl_dep_tracking_hash_via_hash!(Option<SplitDebuginfo>);
|
||||
impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
|
||||
impl_dep_tracking_hash_via_hash!(Option<SymbolManglingVersion>);
|
||||
impl_dep_tracking_hash_via_hash!(Option<SourceFileHashAlgorithm>);
|
||||
|
@ -6,7 +6,7 @@ use crate::search_paths::SearchPath;
|
||||
use crate::utils::NativeLibKind;
|
||||
|
||||
use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy};
|
||||
use rustc_target::spec::{RelocModel, RelroLevel, TargetTriple, TlsModel};
|
||||
use rustc_target::spec::{RelocModel, RelroLevel, SplitDebuginfo, TargetTriple, TlsModel};
|
||||
|
||||
use rustc_feature::UnstableFeatures;
|
||||
use rustc_span::edition::Edition;
|
||||
@ -269,7 +269,6 @@ macro_rules! options {
|
||||
pub const parse_switch_with_opt_path: &str =
|
||||
"an optional path to the profiling data output directory";
|
||||
pub const parse_merge_functions: &str = "one of: `disabled`, `trampolines`, or `aliases`";
|
||||
pub const parse_split_dwarf_kind: &str = "one of: `none`, `single` or `split`";
|
||||
pub const parse_symbol_mangling_version: &str = "either `legacy` or `v0` (RFC 2603)";
|
||||
pub const parse_src_file_hash: &str = "either `md5` or `sha1`";
|
||||
pub const parse_relocation_model: &str =
|
||||
@ -280,6 +279,8 @@ macro_rules! options {
|
||||
"one of supported TLS models (`rustc --print tls-models`)";
|
||||
pub const parse_target_feature: &str = parse_string;
|
||||
pub const parse_wasi_exec_model: &str = "either `command` or `reactor`";
|
||||
pub const parse_split_debuginfo: &str =
|
||||
"one of supported split-debuginfo modes (`off` or `dsymutil`)";
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
@ -678,19 +679,6 @@ macro_rules! options {
|
||||
true
|
||||
}
|
||||
|
||||
fn parse_split_dwarf_kind(
|
||||
slot: &mut SplitDwarfKind,
|
||||
v: Option<&str>,
|
||||
) -> bool {
|
||||
*slot = match v {
|
||||
Some("none") => SplitDwarfKind::None,
|
||||
Some("split") => SplitDwarfKind::Split,
|
||||
Some("single") => SplitDwarfKind::Single,
|
||||
_ => return false,
|
||||
};
|
||||
true
|
||||
}
|
||||
|
||||
fn parse_symbol_mangling_version(
|
||||
slot: &mut Option<SymbolManglingVersion>,
|
||||
v: Option<&str>,
|
||||
@ -732,6 +720,14 @@ macro_rules! options {
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn parse_split_debuginfo(slot: &mut Option<SplitDebuginfo>, v: Option<&str>) -> bool {
|
||||
match v.and_then(|s| SplitDebuginfo::from_str(s).ok()) {
|
||||
Some(e) => *slot = Some(e),
|
||||
_ => return false,
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
) }
|
||||
|
||||
@ -830,6 +826,8 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options,
|
||||
"save all temporary output files during compilation (default: no)"),
|
||||
soft_float: bool = (false, parse_bool, [TRACKED],
|
||||
"use soft float ABI (*eabihf targets only) (default: no)"),
|
||||
split_debuginfo: Option<SplitDebuginfo> = (None, parse_split_debuginfo, [TRACKED],
|
||||
"how to handle split-debuginfo, a platform-specific option"),
|
||||
target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
|
||||
"select target processor (`rustc --print target-cpus` for details)"),
|
||||
target_feature: String = (String::new(), parse_target_feature, [TRACKED],
|
||||
@ -1073,11 +1071,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
||||
"choose which RELRO level to use"),
|
||||
report_delayed_bugs: bool = (false, parse_bool, [TRACKED],
|
||||
"immediately print bugs registered with `delay_span_bug` (default: no)"),
|
||||
// The default historical behavior was to always run dsymutil, so we're
|
||||
// preserving that temporarily, but we're likely to switch the default
|
||||
// soon.
|
||||
run_dsymutil: bool = (true, parse_bool, [TRACKED],
|
||||
"if on Mac, run `dsymutil` and delete intermediate object files (default: yes)"),
|
||||
sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
|
||||
"use a sanitizer"),
|
||||
sanitizer_memory_track_origins: usize = (0, parse_sanitizer_memory_track_origins, [TRACKED],
|
||||
@ -1112,8 +1105,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
||||
"hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"),
|
||||
strip: Strip = (Strip::None, parse_strip, [UNTRACKED],
|
||||
"tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"),
|
||||
split_dwarf: SplitDwarfKind = (SplitDwarfKind::None, parse_split_dwarf_kind, [UNTRACKED],
|
||||
"enable generation of split dwarf"),
|
||||
split_dwarf_inlining: bool = (true, parse_bool, [UNTRACKED],
|
||||
"provide minimal debug info in the object/executable to facilitate online \
|
||||
symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF"),
|
||||
|
@ -28,7 +28,7 @@ use rustc_span::source_map::{FileLoader, MultiSpan, RealFileLoader, SourceMap, S
|
||||
use rustc_span::{sym, SourceFileHashAlgorithm, Symbol};
|
||||
use rustc_target::asm::InlineAsmArch;
|
||||
use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel};
|
||||
use rustc_target::spec::{Target, TargetTriple, TlsModel};
|
||||
use rustc_target::spec::{SplitDebuginfo, Target, TargetTriple, TlsModel};
|
||||
|
||||
use std::cell::{self, RefCell};
|
||||
use std::env;
|
||||
@ -804,6 +804,14 @@ impl Session {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn split_debuginfo(&self) -> SplitDebuginfo {
|
||||
self.opts.cg.split_debuginfo.unwrap_or(self.target.split_debuginfo)
|
||||
}
|
||||
|
||||
pub fn target_can_use_split_dwarf(&self) -> bool {
|
||||
!self.target.is_like_windows && !self.target.is_like_osx
|
||||
}
|
||||
|
||||
pub fn must_not_eliminate_frame_pointers(&self) -> bool {
|
||||
// "mcount" function relies on stack pointer.
|
||||
// See <https://sourceware.org/binutils/docs/gprof/Implementation.html>.
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::env;
|
||||
|
||||
use crate::spec::{LinkArgs, TargetOptions};
|
||||
use crate::spec::{LinkArgs, SplitDebuginfo, TargetOptions};
|
||||
|
||||
pub fn opts(os: &str) -> TargetOptions {
|
||||
// ELF TLS is only available in macOS 10.7+. If you try to compile for 10.6
|
||||
@ -36,6 +36,10 @@ pub fn opts(os: &str) -> TargetOptions {
|
||||
emit_debug_gdb_scripts: false,
|
||||
eh_frame_header: false,
|
||||
|
||||
// The historical default for macOS targets is to run `dsymutil` which
|
||||
// generates a packed version of debuginfo split from the main file.
|
||||
split_debuginfo: SplitDebuginfo::Packed,
|
||||
|
||||
// This environment variable is pretty magical but is intended for
|
||||
// producing deterministic builds. This was first discovered to be used
|
||||
// by the `ar` tool as a way to control whether or not mtime entries in
|
||||
|
@ -448,6 +448,69 @@ impl fmt::Display for LinkOutputKind {
|
||||
|
||||
pub type LinkArgs = BTreeMap<LinkerFlavor, Vec<String>>;
|
||||
|
||||
#[derive(Clone, Copy, Hash, Debug, PartialEq, Eq)]
|
||||
pub enum SplitDebuginfo {
|
||||
/// Split debug-information is disabled, meaning that on supported platforms
|
||||
/// you can find all debug information in the executable itself. This is
|
||||
/// only supported for ELF effectively.
|
||||
///
|
||||
/// * Windows - not supported
|
||||
/// * macOS - don't run `dsymutil`
|
||||
/// * ELF - `.dwarf_*` sections
|
||||
Off,
|
||||
|
||||
/// Split debug-information can be found in a "packed" location separate
|
||||
/// from the final artifact. This is supported on all platforms.
|
||||
///
|
||||
/// * Windows - `*.pdb`
|
||||
/// * macOS - `*.dSYM` (run `dsymutil`)
|
||||
/// * ELF - `*.dwp` (run `rust-llvm-dwp`)
|
||||
Packed,
|
||||
|
||||
/// Split debug-information can be found in individual object files on the
|
||||
/// filesystem. The main executable may point to the object files.
|
||||
///
|
||||
/// * Windows - not supported
|
||||
/// * macOS - supported, scattered object files
|
||||
/// * ELF - supported, scattered `*.dwo` files
|
||||
Unpacked,
|
||||
}
|
||||
|
||||
impl SplitDebuginfo {
|
||||
fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
SplitDebuginfo::Off => "off",
|
||||
SplitDebuginfo::Packed => "packed",
|
||||
SplitDebuginfo::Unpacked => "unpacked",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for SplitDebuginfo {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<SplitDebuginfo, ()> {
|
||||
Ok(match s {
|
||||
"off" => SplitDebuginfo::Off,
|
||||
"unpacked" => SplitDebuginfo::Unpacked,
|
||||
"packed" => SplitDebuginfo::Packed,
|
||||
_ => return Err(()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ToJson for SplitDebuginfo {
|
||||
fn to_json(&self) -> Json {
|
||||
self.as_str().to_json()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for SplitDebuginfo {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(self.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! supported_targets {
|
||||
( $(($( $triple:literal, )+ $module:ident ),)+ ) => {
|
||||
$(mod $module;)+
|
||||
@ -1085,6 +1148,10 @@ pub struct TargetOptions {
|
||||
/// Is true if the target is an ARM architecture using thumb v1 which allows for
|
||||
/// thumb and arm interworking.
|
||||
pub has_thumb_interworking: bool,
|
||||
|
||||
/// How to handle split debug information, if at all. Specifying `None` has
|
||||
/// target-specific meaning.
|
||||
pub split_debuginfo: SplitDebuginfo,
|
||||
}
|
||||
|
||||
impl Default for TargetOptions {
|
||||
@ -1184,6 +1251,7 @@ impl Default for TargetOptions {
|
||||
use_ctors_section: false,
|
||||
eh_frame_header: true,
|
||||
has_thumb_interworking: false,
|
||||
split_debuginfo: SplitDebuginfo::Off,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1382,6 +1450,18 @@ impl Target {
|
||||
Some(Ok(()))
|
||||
})).unwrap_or(Ok(()))
|
||||
} );
|
||||
($key_name:ident, SplitDebuginfo) => ( {
|
||||
let name = (stringify!($key_name)).replace("_", "-");
|
||||
obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
|
||||
match s.parse::<SplitDebuginfo>() {
|
||||
Ok(level) => base.$key_name = level,
|
||||
_ => return Some(Err(format!("'{}' is not a valid value for \
|
||||
split-debuginfo. Use 'off' or 'dsymutil'.",
|
||||
s))),
|
||||
}
|
||||
Some(Ok(()))
|
||||
})).unwrap_or(Ok(()))
|
||||
} );
|
||||
($key_name:ident, list) => ( {
|
||||
let name = (stringify!($key_name)).replace("_", "-");
|
||||
if let Some(v) = obj.find(&name).and_then(Json::as_array) {
|
||||
@ -1627,6 +1707,7 @@ impl Target {
|
||||
key!(use_ctors_section, bool);
|
||||
key!(eh_frame_header, bool);
|
||||
key!(has_thumb_interworking, bool);
|
||||
key!(split_debuginfo, SplitDebuginfo)?;
|
||||
|
||||
// NB: The old name is deprecated, but support for it is retained for
|
||||
// compatibility.
|
||||
@ -1862,6 +1943,7 @@ impl ToJson for Target {
|
||||
target_option_val!(use_ctors_section);
|
||||
target_option_val!(eh_frame_header);
|
||||
target_option_val!(has_thumb_interworking);
|
||||
target_option_val!(split_debuginfo);
|
||||
|
||||
if default.unsupported_abis != self.unsupported_abis {
|
||||
d.insert(
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, TargetOptions};
|
||||
use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, SplitDebuginfo, TargetOptions};
|
||||
|
||||
pub fn opts() -> TargetOptions {
|
||||
let pre_link_args_msvc = vec![
|
||||
@ -27,6 +27,10 @@ pub fn opts() -> TargetOptions {
|
||||
abi_return_struct_as_int: true,
|
||||
emit_debug_gdb_scripts: false,
|
||||
|
||||
// Currently this is the only supported method of debuginfo on MSVC
|
||||
// where `*.pdb` files show up next to the final artifact.
|
||||
split_debuginfo: SplitDebuginfo::Packed,
|
||||
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
@ -265,7 +265,13 @@ where
|
||||
}
|
||||
}
|
||||
match self.iter.next() {
|
||||
None => return self.backiter.as_mut()?.next(),
|
||||
None => match self.backiter.as_mut()?.next() {
|
||||
None => {
|
||||
self.backiter = None;
|
||||
return None;
|
||||
}
|
||||
elt @ Some(_) => return elt,
|
||||
},
|
||||
Some(inner) => self.frontiter = Some(inner.into_iter()),
|
||||
}
|
||||
}
|
||||
@ -353,7 +359,13 @@ where
|
||||
}
|
||||
}
|
||||
match self.iter.next_back() {
|
||||
None => return self.frontiter.as_mut()?.next_back(),
|
||||
None => match self.frontiter.as_mut()?.next_back() {
|
||||
None => {
|
||||
self.frontiter = None;
|
||||
return None;
|
||||
}
|
||||
elt @ Some(_) => return elt,
|
||||
},
|
||||
next => self.backiter = next.map(IntoIterator::into_iter),
|
||||
}
|
||||
}
|
||||
|
@ -64,6 +64,14 @@ fn test_flatten_non_fused_outer() {
|
||||
assert_eq!(iter.next_back(), Some(1));
|
||||
assert_eq!(iter.next(), Some(0));
|
||||
assert_eq!(iter.next(), None);
|
||||
assert_eq!(iter.next(), None);
|
||||
|
||||
let mut iter = NonFused::new(once(0..2)).flatten();
|
||||
|
||||
assert_eq!(iter.next(), Some(0));
|
||||
assert_eq!(iter.next_back(), Some(1));
|
||||
assert_eq!(iter.next_back(), None);
|
||||
assert_eq!(iter.next_back(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -74,6 +82,15 @@ fn test_flatten_non_fused_inner() {
|
||||
assert_eq!(iter.next(), Some(0));
|
||||
assert_eq!(iter.next(), Some(1));
|
||||
assert_eq!(iter.next(), None);
|
||||
assert_eq!(iter.next(), None);
|
||||
|
||||
let mut iter = once(0..1).chain(once(1..3)).flat_map(NonFused::new);
|
||||
|
||||
assert_eq!(iter.next(), Some(0));
|
||||
assert_eq!(iter.next_back(), Some(2));
|
||||
assert_eq!(iter.next_back(), Some(1));
|
||||
assert_eq!(iter.next_back(), None);
|
||||
assert_eq!(iter.next_back(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -833,6 +833,7 @@ class RustBuild(object):
|
||||
target_linker = self.get_toml("linker", build_section)
|
||||
if target_linker is not None:
|
||||
env["RUSTFLAGS"] += " -C linker=" + target_linker
|
||||
# cfg(bootstrap): Add `-Wsemicolon_in_expressions_from_macros` after the next beta bump
|
||||
env["RUSTFLAGS"] += " -Wrust_2018_idioms -Wunused_lifetimes"
|
||||
if self.get_toml("deny-warnings", "rust") != "false":
|
||||
env["RUSTFLAGS"] += " -Dwarnings"
|
||||
|
@ -1139,10 +1139,18 @@ impl<'a> Builder<'a> {
|
||||
// itself, we skip it by default since we know it's safe to do so in that case.
|
||||
// See https://github.com/rust-lang/rust/issues/79361 for more info on this flag.
|
||||
if target.contains("apple") {
|
||||
if self.config.rust_run_dsymutil {
|
||||
rustflags.arg("-Zrun-dsymutil=yes");
|
||||
if stage == 0 {
|
||||
if self.config.rust_run_dsymutil {
|
||||
rustflags.arg("-Zrun-dsymutil=yes");
|
||||
} else {
|
||||
rustflags.arg("-Zrun-dsymutil=no");
|
||||
}
|
||||
} else {
|
||||
rustflags.arg("-Zrun-dsymutil=no");
|
||||
if self.config.rust_run_dsymutil {
|
||||
rustflags.arg("-Csplit-debuginfo=packed");
|
||||
} else {
|
||||
rustflags.arg("-Csplit-debuginfo=unpacked");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1250,6 +1258,12 @@ impl<'a> Builder<'a> {
|
||||
// some code doesn't go through this `rustc` wrapper.
|
||||
lint_flags.push("-Wrust_2018_idioms");
|
||||
lint_flags.push("-Wunused_lifetimes");
|
||||
// cfg(bootstrap): unconditionally enable this warning after the next beta bump
|
||||
// This is currently disabled for the stage1 libstd, since build scripts
|
||||
// will end up using the bootstrap compiler (which doesn't yet support this lint)
|
||||
if compiler.stage != 0 && mode != Mode::Std {
|
||||
lint_flags.push("-Wsemicolon_in_expressions_from_macros");
|
||||
}
|
||||
|
||||
if self.config.deny_warnings {
|
||||
lint_flags.push("-Dwarnings");
|
||||
|
@ -492,6 +492,34 @@ point instructions in software. It takes one of the following values:
|
||||
* `y`, `yes`, `on`, or no value: use soft floats.
|
||||
* `n`, `no`, or `off`: use hardware floats (the default).
|
||||
|
||||
## split-debuginfo
|
||||
|
||||
This option controls the emission of "split debuginfo" for debug information
|
||||
that `rustc` generates. The default behavior of this option is
|
||||
platform-specific, and not all possible values for this option work on all
|
||||
platform. Possible values are:
|
||||
|
||||
* `off` - This is the default for platforms with ELF binaries and windows-gnu
|
||||
(not Windows MSVC and not macOS). This typically means that dwarf debug
|
||||
information can be found in the final artifact in sections of the executable.
|
||||
This option is not supported on Windows MSVC. On macOS this options prevents
|
||||
the final execution of `dsymutil` to generate debuginfo.
|
||||
|
||||
* `packed` - This is the default for Windows MSVC and macOS platforms. The term
|
||||
"packed" here means that all the debug information is packed into a separate
|
||||
file from the main executable. On Windows MSVC this is a `*.pdb` file, on
|
||||
macOS this is a `*.dSYM` folder, and on other platforms this is a `*.dwp`
|
||||
files.
|
||||
|
||||
* `unpacked` - This means that debug information will be found in separate
|
||||
files for each compilation unit (object file). This is not supported on
|
||||
Windows MSVC. On macOS this means the original object files will contain
|
||||
debug information. On other Unix platforms this means that `*.dwo` files will
|
||||
contain debug information.
|
||||
|
||||
Note that `packed` and `unpacked` gated behind `-Zunstable-options` on
|
||||
non-macOS platforms at this time.
|
||||
|
||||
## target-cpu
|
||||
|
||||
This instructs `rustc` to generate code specifically for a particular processor.
|
||||
@ -499,7 +527,7 @@ This instructs `rustc` to generate code specifically for a particular processor.
|
||||
You can run `rustc --print target-cpus` to see the valid options to pass
|
||||
here. Each target has a default base CPU. Special values include:
|
||||
|
||||
* `native` can be passed to use the processor of the host machine.
|
||||
* `native` can be passed to use the processor of the host machine.
|
||||
* `generic` refers to an LLVM target with minimal features but modern tuning.
|
||||
|
||||
## target-feature
|
||||
|
@ -17,6 +17,7 @@ smallvec = "1.0"
|
||||
tempfile = "3"
|
||||
itertools = "0.9"
|
||||
regex = "1"
|
||||
rustdoc-json-types = { path = "../rustdoc-json-types" }
|
||||
|
||||
[dev-dependencies]
|
||||
expect-test = "1.0"
|
||||
|
@ -659,6 +659,8 @@ fn fmt_type(
|
||||
use_absolute: bool,
|
||||
cache: &Cache,
|
||||
) -> fmt::Result {
|
||||
debug!("fmt_type(t = {:?})", t);
|
||||
|
||||
match *t {
|
||||
clean::Generic(name) => write!(f, "{}", name),
|
||||
clean::ResolvedPath { did, ref param_names, ref path, is_generic } => {
|
||||
@ -675,21 +677,22 @@ fn fmt_type(
|
||||
if f.alternate() {
|
||||
write!(
|
||||
f,
|
||||
"{}{:#}fn{:#}{:#}",
|
||||
"{:#}{}{:#}fn{:#}",
|
||||
decl.print_hrtb_with_space(cache),
|
||||
decl.unsafety.print_with_space(),
|
||||
print_abi_with_space(decl.abi),
|
||||
decl.print_generic_params(cache),
|
||||
decl.decl.print(cache)
|
||||
)
|
||||
} else {
|
||||
write!(
|
||||
f,
|
||||
"{}{}",
|
||||
"{}{}{}",
|
||||
decl.print_hrtb_with_space(cache),
|
||||
decl.unsafety.print_with_space(),
|
||||
print_abi_with_space(decl.abi)
|
||||
)?;
|
||||
primitive_link(f, PrimitiveType::Fn, "fn", cache)?;
|
||||
write!(f, "{}{}", decl.print_generic_params(cache), decl.decl.print(cache))
|
||||
write!(f, "{}", decl.decl.print(cache))
|
||||
}
|
||||
}
|
||||
clean::Tuple(ref typs) => {
|
||||
@ -992,8 +995,14 @@ impl clean::FnRetTy {
|
||||
}
|
||||
|
||||
impl clean::BareFunctionDecl {
|
||||
fn print_generic_params<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
|
||||
comma_sep(self.generic_params.iter().map(move |g| g.print(cache)))
|
||||
fn print_hrtb_with_space<'a>(&'a self, cache: &'a Cache) -> impl fmt::Display + 'a {
|
||||
display_fn(move |f| {
|
||||
if !self.generic_params.is_empty() {
|
||||
write!(f, "for<{}> ", comma_sep(self.generic_params.iter().map(|g| g.print(cache))))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1345,6 +1345,7 @@ impl AllTypes {
|
||||
write!(
|
||||
f,
|
||||
"<h1 class=\"fqn\">\
|
||||
<span class=\"in-band\">List of all items</span>\
|
||||
<span class=\"out-of-band\">\
|
||||
<span id=\"render-detail\">\
|
||||
<a id=\"toggle-all-docs\" href=\"javascript:void(0)\" \
|
||||
@ -1353,7 +1354,6 @@ impl AllTypes {
|
||||
</a>\
|
||||
</span>
|
||||
</span>
|
||||
<span class=\"in-band\">List of all items</span>\
|
||||
</h1>"
|
||||
);
|
||||
print_entries(f, &self.structs, "Structs", "structs");
|
||||
@ -1711,36 +1711,7 @@ where
|
||||
fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer) {
|
||||
debug_assert!(!item.is_stripped());
|
||||
// Write the breadcrumb trail header for the top
|
||||
write!(buf, "<h1 class=\"fqn\"><span class=\"out-of-band\">");
|
||||
render_stability_since_raw(
|
||||
buf,
|
||||
item.stable_since(cx.tcx()).as_deref(),
|
||||
item.const_stable_since(cx.tcx()).as_deref(),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
write!(
|
||||
buf,
|
||||
"<span id=\"render-detail\">\
|
||||
<a id=\"toggle-all-docs\" href=\"javascript:void(0)\" \
|
||||
title=\"collapse all docs\">\
|
||||
[<span class=\"inner\">−</span>]\
|
||||
</a>\
|
||||
</span>"
|
||||
);
|
||||
|
||||
// Write `src` tag
|
||||
//
|
||||
// When this item is part of a `crate use` in a downstream crate, the
|
||||
// [src] link in the downstream documentation will actually come back to
|
||||
// this page, and this link will be auto-clicked. The `id` attribute is
|
||||
// used to find the link to auto-click.
|
||||
if cx.shared.include_sources && !item.is_primitive() {
|
||||
write_srclink(cx, item, buf);
|
||||
}
|
||||
|
||||
write!(buf, "</span>"); // out-of-band
|
||||
write!(buf, "<span class=\"in-band\">");
|
||||
write!(buf, "<h1 class=\"fqn\"><span class=\"in-band\">");
|
||||
let name = match *item.kind {
|
||||
clean::ModuleItem(ref m) => {
|
||||
if m.is_crate {
|
||||
@ -1788,7 +1759,36 @@ fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer) {
|
||||
}
|
||||
write!(buf, "<a class=\"{}\" href=\"\">{}</a>", item.type_(), item.name.as_ref().unwrap());
|
||||
|
||||
write!(buf, "</span></h1>"); // in-band
|
||||
write!(buf, "</span>"); // in-band
|
||||
write!(buf, "<span class=\"out-of-band\">");
|
||||
render_stability_since_raw(
|
||||
buf,
|
||||
item.stable_since(cx.tcx()).as_deref(),
|
||||
item.const_stable_since(cx.tcx()).as_deref(),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
write!(
|
||||
buf,
|
||||
"<span id=\"render-detail\">\
|
||||
<a id=\"toggle-all-docs\" href=\"javascript:void(0)\" \
|
||||
title=\"collapse all docs\">\
|
||||
[<span class=\"inner\">−</span>]\
|
||||
</a>\
|
||||
</span>"
|
||||
);
|
||||
|
||||
// Write `src` tag
|
||||
//
|
||||
// When this item is part of a `crate use` in a downstream crate, the
|
||||
// [src] link in the downstream documentation will actually come back to
|
||||
// this page, and this link will be auto-clicked. The `id` attribute is
|
||||
// used to find the link to auto-click.
|
||||
if cx.shared.include_sources && !item.is_primitive() {
|
||||
write_srclink(cx, item, buf);
|
||||
}
|
||||
|
||||
write!(buf, "</span></h1>"); // out-of-band
|
||||
|
||||
match *item.kind {
|
||||
clean::ModuleItem(ref m) => item_module(buf, cx, item, &m.items),
|
||||
|
@ -9,9 +9,10 @@ use rustc_hir::def::CtorKind;
|
||||
use rustc_span::def_id::{DefId, CRATE_DEF_INDEX};
|
||||
use rustc_span::Pos;
|
||||
|
||||
use rustdoc_json_types::*;
|
||||
|
||||
use crate::clean;
|
||||
use crate::formats::item_type::ItemType;
|
||||
use crate::json::types::*;
|
||||
use crate::json::JsonRenderer;
|
||||
|
||||
impl JsonRenderer<'_> {
|
||||
@ -22,7 +23,7 @@ impl JsonRenderer<'_> {
|
||||
match *kind {
|
||||
clean::StrippedItem(_) => None,
|
||||
kind => Some(Item {
|
||||
id: def_id.into(),
|
||||
id: from_def_id(def_id),
|
||||
crate_id: def_id.krate.as_u32(),
|
||||
name: name.map(|sym| sym.to_string()),
|
||||
source: self.convert_span(source),
|
||||
@ -32,7 +33,7 @@ impl JsonRenderer<'_> {
|
||||
.links
|
||||
.into_iter()
|
||||
.filter_map(|clean::ItemLink { link, did, .. }| {
|
||||
did.map(|did| (link, did.into()))
|
||||
did.map(|did| (link, from_def_id(did)))
|
||||
})
|
||||
.collect(),
|
||||
attrs: attrs
|
||||
@ -40,7 +41,7 @@ impl JsonRenderer<'_> {
|
||||
.iter()
|
||||
.map(rustc_ast_pretty::pprust::attribute_to_string)
|
||||
.collect(),
|
||||
deprecation: deprecation.map(Into::into),
|
||||
deprecation: deprecation.map(from_deprecation),
|
||||
kind: item_type.into(),
|
||||
inner: kind.into(),
|
||||
}),
|
||||
@ -74,19 +75,17 @@ impl JsonRenderer<'_> {
|
||||
Inherited => Visibility::Default,
|
||||
Restricted(did) if did.index == CRATE_DEF_INDEX => Visibility::Crate,
|
||||
Restricted(did) => Visibility::Restricted {
|
||||
parent: did.into(),
|
||||
parent: from_def_id(did),
|
||||
path: self.tcx.def_path(did).to_string_no_crate_verbose(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<rustc_attr::Deprecation> for Deprecation {
|
||||
fn from(deprecation: rustc_attr::Deprecation) -> Self {
|
||||
#[rustfmt::skip]
|
||||
let rustc_attr::Deprecation { since, note, is_since_rustc_version: _, suggestion: _ } = deprecation;
|
||||
Deprecation { since: since.map(|s| s.to_string()), note: note.map(|s| s.to_string()) }
|
||||
}
|
||||
crate fn from_deprecation(deprecation: rustc_attr::Deprecation) -> Deprecation {
|
||||
#[rustfmt::skip]
|
||||
let rustc_attr::Deprecation { since, note, is_since_rustc_version: _, suggestion: _ } = deprecation;
|
||||
Deprecation { since: since.map(|s| s.to_string()), note: note.map(|s| s.to_string()) }
|
||||
}
|
||||
|
||||
impl From<clean::GenericArgs> for GenericArgs {
|
||||
@ -141,10 +140,8 @@ impl From<clean::TypeBindingKind> for TypeBindingKind {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DefId> for Id {
|
||||
fn from(did: DefId) -> Self {
|
||||
Id(format!("{}:{}", did.krate.as_u32(), u32::from(did.index)))
|
||||
}
|
||||
crate fn from_def_id(did: DefId) -> Id {
|
||||
Id(format!("{}:{}", did.krate.as_u32(), u32::from(did.index)))
|
||||
}
|
||||
|
||||
impl From<clean::ItemKind> for ItemEnum {
|
||||
@ -199,7 +196,7 @@ impl From<clean::Struct> for Struct {
|
||||
fn from(struct_: clean::Struct) -> Self {
|
||||
let clean::Struct { struct_type, generics, fields, fields_stripped } = struct_;
|
||||
Struct {
|
||||
struct_type: struct_type.into(),
|
||||
struct_type: from_ctor_kind(struct_type),
|
||||
generics: generics.into(),
|
||||
fields_stripped,
|
||||
fields: ids(fields),
|
||||
@ -221,13 +218,11 @@ impl From<clean::Union> for Struct {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CtorKind> for StructType {
|
||||
fn from(struct_type: CtorKind) -> Self {
|
||||
match struct_type {
|
||||
CtorKind::Fictive => StructType::Plain,
|
||||
CtorKind::Fn => StructType::Tuple,
|
||||
CtorKind::Const => StructType::Unit,
|
||||
}
|
||||
crate fn from_ctor_kind(struct_type: CtorKind) -> StructType {
|
||||
match struct_type {
|
||||
CtorKind::Fictive => StructType::Plain,
|
||||
CtorKind::Fn => StructType::Tuple,
|
||||
CtorKind::Const => StructType::Unit,
|
||||
}
|
||||
}
|
||||
|
||||
@ -310,7 +305,7 @@ impl From<clean::GenericBound> for GenericBound {
|
||||
GenericBound::TraitBound {
|
||||
trait_: trait_.into(),
|
||||
generic_params: generic_params.into_iter().map(Into::into).collect(),
|
||||
modifier: modifier.into(),
|
||||
modifier: from_trait_bound_modifier(modifier),
|
||||
}
|
||||
}
|
||||
Outlives(lifetime) => GenericBound::Outlives(lifetime.0.to_string()),
|
||||
@ -318,14 +313,12 @@ impl From<clean::GenericBound> for GenericBound {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<rustc_hir::TraitBoundModifier> for TraitBoundModifier {
|
||||
fn from(modifier: rustc_hir::TraitBoundModifier) -> Self {
|
||||
use rustc_hir::TraitBoundModifier::*;
|
||||
match modifier {
|
||||
None => TraitBoundModifier::None,
|
||||
Maybe => TraitBoundModifier::Maybe,
|
||||
MaybeConst => TraitBoundModifier::MaybeConst,
|
||||
}
|
||||
crate fn from_trait_bound_modifier(modifier: rustc_hir::TraitBoundModifier) -> TraitBoundModifier {
|
||||
use rustc_hir::TraitBoundModifier::*;
|
||||
match modifier {
|
||||
None => TraitBoundModifier::None,
|
||||
Maybe => TraitBoundModifier::Maybe,
|
||||
MaybeConst => TraitBoundModifier::MaybeConst,
|
||||
}
|
||||
}
|
||||
|
||||
@ -335,7 +328,7 @@ impl From<clean::Type> for Type {
|
||||
match ty {
|
||||
ResolvedPath { path, param_names, did, is_generic: _ } => Type::ResolvedPath {
|
||||
name: path.whole_name(),
|
||||
id: did.into(),
|
||||
id: from_def_id(did),
|
||||
args: path.segments.last().map(|args| Box::new(args.clone().args.into())),
|
||||
param_names: param_names
|
||||
.map(|v| v.into_iter().map(Into::into).collect())
|
||||
@ -470,7 +463,7 @@ impl From<clean::VariantStruct> for Struct {
|
||||
fn from(struct_: clean::VariantStruct) -> Self {
|
||||
let clean::VariantStruct { struct_type, fields, fields_stripped } = struct_;
|
||||
Struct {
|
||||
struct_type: struct_type.into(),
|
||||
struct_type: from_ctor_kind(struct_type),
|
||||
generics: Default::default(),
|
||||
fields_stripped,
|
||||
fields: ids(fields),
|
||||
@ -497,13 +490,13 @@ impl From<clean::Import> for Import {
|
||||
Simple(s) => Import {
|
||||
span: import.source.path.whole_name(),
|
||||
name: s.to_string(),
|
||||
id: import.source.did.map(Into::into),
|
||||
id: import.source.did.map(from_def_id),
|
||||
glob: false,
|
||||
},
|
||||
Glob => Import {
|
||||
span: import.source.path.whole_name(),
|
||||
name: import.source.path.last_name().to_string(),
|
||||
id: import.source.did.map(Into::into),
|
||||
id: import.source.did.map(from_def_id),
|
||||
glob: true,
|
||||
},
|
||||
}
|
||||
@ -513,20 +506,18 @@ impl From<clean::Import> for Import {
|
||||
impl From<clean::ProcMacro> for ProcMacro {
|
||||
fn from(mac: clean::ProcMacro) -> Self {
|
||||
ProcMacro {
|
||||
kind: mac.kind.into(),
|
||||
kind: from_macro_kind(mac.kind),
|
||||
helpers: mac.helpers.iter().map(|x| x.to_string()).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<rustc_span::hygiene::MacroKind> for MacroKind {
|
||||
fn from(kind: rustc_span::hygiene::MacroKind) -> Self {
|
||||
use rustc_span::hygiene::MacroKind::*;
|
||||
match kind {
|
||||
Bang => MacroKind::Bang,
|
||||
Attr => MacroKind::Attr,
|
||||
Derive => MacroKind::Derive,
|
||||
}
|
||||
crate fn from_macro_kind(kind: rustc_span::hygiene::MacroKind) -> MacroKind {
|
||||
use rustc_span::hygiene::MacroKind::*;
|
||||
match kind {
|
||||
Bang => MacroKind::Bang,
|
||||
Attr => MacroKind::Attr,
|
||||
Derive => MacroKind::Derive,
|
||||
}
|
||||
}
|
||||
|
||||
@ -599,5 +590,5 @@ impl From<ItemType> for ItemKind {
|
||||
}
|
||||
|
||||
fn ids(items: impl IntoIterator<Item = clean::Item>) -> Vec<Id> {
|
||||
items.into_iter().filter(|x| !x.is_stripped()).map(|i| i.def_id.into()).collect()
|
||||
items.into_iter().filter(|x| !x.is_stripped()).map(|i| from_def_id(i.def_id)).collect()
|
||||
}
|
||||
|
@ -5,7 +5,6 @@
|
||||
//! docs for usage and details.
|
||||
|
||||
mod conversions;
|
||||
pub mod types;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::fs::File;
|
||||
@ -17,12 +16,15 @@ use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::edition::Edition;
|
||||
|
||||
use rustdoc_json_types as types;
|
||||
|
||||
use crate::clean;
|
||||
use crate::config::{RenderInfo, RenderOptions};
|
||||
use crate::error::Error;
|
||||
use crate::formats::cache::Cache;
|
||||
use crate::formats::FormatRenderer;
|
||||
use crate::html::render::cache::ExternalLocation;
|
||||
use crate::json::conversions::from_def_id;
|
||||
|
||||
#[derive(Clone)]
|
||||
crate struct JsonRenderer<'tcx> {
|
||||
@ -50,7 +52,7 @@ impl JsonRenderer<'_> {
|
||||
.map(|i| {
|
||||
let item = &i.impl_item;
|
||||
self.item(item.clone()).unwrap();
|
||||
item.def_id.into()
|
||||
from_def_id(item.def_id)
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
@ -68,7 +70,7 @@ impl JsonRenderer<'_> {
|
||||
let item = &i.impl_item;
|
||||
if item.def_id.is_local() {
|
||||
self.item(item.clone()).unwrap();
|
||||
Some(item.def_id.into())
|
||||
Some(from_def_id(item.def_id))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -87,9 +89,9 @@ impl JsonRenderer<'_> {
|
||||
if !id.is_local() {
|
||||
trait_item.items.clone().into_iter().for_each(|i| self.item(i).unwrap());
|
||||
Some((
|
||||
id.into(),
|
||||
from_def_id(id),
|
||||
types::Item {
|
||||
id: id.into(),
|
||||
id: from_def_id(id),
|
||||
crate_id: id.krate.as_u32(),
|
||||
name: self
|
||||
.cache
|
||||
@ -163,7 +165,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
|
||||
} else if let types::ItemEnum::EnumItem(ref mut e) = new_item.inner {
|
||||
e.impls = self.get_impls(id)
|
||||
}
|
||||
let removed = self.index.borrow_mut().insert(id.into(), new_item.clone());
|
||||
let removed = self.index.borrow_mut().insert(from_def_id(id), new_item.clone());
|
||||
// FIXME(adotinthevoid): Currently, the index is duplicated. This is a sanity check
|
||||
// to make sure the items are unique.
|
||||
if let Some(old_item) = removed {
|
||||
@ -203,11 +205,14 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
|
||||
debug!("Done with crate");
|
||||
let mut index = (*self.index).clone().into_inner();
|
||||
index.extend(self.get_trait_items());
|
||||
// This needs to be the default HashMap for compatibility with the public interface for
|
||||
// rustdoc-json
|
||||
#[allow(rustc::default_hash_types)]
|
||||
let output = types::Crate {
|
||||
root: types::Id(String::from("0:0")),
|
||||
crate_version: krate.version.clone(),
|
||||
includes_private: self.cache.document_private,
|
||||
index,
|
||||
index: index.into_iter().collect(),
|
||||
paths: self
|
||||
.cache
|
||||
.paths
|
||||
@ -216,7 +221,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
|
||||
.chain(self.cache.external_paths.clone().into_iter())
|
||||
.map(|(k, (path, kind))| {
|
||||
(
|
||||
k.into(),
|
||||
from_def_id(k),
|
||||
types::ItemSummary { crate_id: k.krate.as_u32(), path, kind: kind.into() },
|
||||
)
|
||||
})
|
||||
|
11
src/rustdoc-json-types/Cargo.toml
Normal file
11
src/rustdoc-json-types/Cargo.toml
Normal file
@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "rustdoc-json-types"
|
||||
version = "0.1.0"
|
||||
authors = ["The Rust Project Developers"]
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1.0", features = ["derive"] }
|
12
src/rustdoc-json-types/README.md
Normal file
12
src/rustdoc-json-types/README.md
Normal file
@ -0,0 +1,12 @@
|
||||
# Rustdoc JSON Types
|
||||
|
||||
This crate exposes the Rustdoc JSON API as a set of types with serde implementations.
|
||||
These types are part of the public interface of the rustdoc JSON output, and making them
|
||||
their own crate allows them to be versioned and distributed without having to depend on
|
||||
any rustc/rustdoc internals. This way, consumers can rely on this crate for both documentation
|
||||
of the output, and as a way to read the output easily, and its versioning is intended to
|
||||
follow semver guarantees about the version of the format. JSON format X will always be
|
||||
compatible with rustdoc-json-types version N.
|
||||
|
||||
Currently, this crate is only used by rustdoc itself. Upon the stabilization of
|
||||
rustdoc-json, it may be distributed separately for consumers of the API.
|
@ -3,9 +3,9 @@
|
||||
//! These types are the public API exposed through the `--output-format json` flag. The [`Crate`]
|
||||
//! struct is the root of the JSON blob and all other items are contained within.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
|
||||
@ -21,11 +21,11 @@ pub struct Crate {
|
||||
pub includes_private: bool,
|
||||
/// A collection of all items in the local crate as well as some external traits and their
|
||||
/// items that are referenced locally.
|
||||
pub index: FxHashMap<Id, Item>,
|
||||
pub index: HashMap<Id, Item>,
|
||||
/// Maps IDs to fully qualified paths and other info helpful for generating links.
|
||||
pub paths: FxHashMap<Id, ItemSummary>,
|
||||
pub paths: HashMap<Id, ItemSummary>,
|
||||
/// Maps `crate_id` of items to a crate name and html_root_url if it exists.
|
||||
pub external_crates: FxHashMap<u32, ExternalCrate>,
|
||||
pub external_crates: HashMap<u32, ExternalCrate>,
|
||||
/// A single version number to be used in the future when making backwards incompatible changes
|
||||
/// to the JSON output.
|
||||
pub format_version: u32,
|
||||
@ -72,7 +72,7 @@ pub struct Item {
|
||||
/// Some("") if there is some documentation but it is empty (EG `#[doc = ""]`).
|
||||
pub docs: Option<String>,
|
||||
/// This mapping resolves [intra-doc links](https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md) from the docstring to their IDs
|
||||
pub links: FxHashMap<String, Id>,
|
||||
pub links: HashMap<String, Id>,
|
||||
/// Stringified versions of the attributes on this item (e.g. `"#[inline]"`)
|
||||
pub attrs: Vec<String>,
|
||||
pub deprecation: Option<Deprecation>,
|
59
src/test/run-make-fulldeps/split-debuginfo/Makefile
Normal file
59
src/test/run-make-fulldeps/split-debuginfo/Makefile
Normal file
@ -0,0 +1,59 @@
|
||||
-include ../tools.mk
|
||||
|
||||
all: off packed unpacked
|
||||
|
||||
ifeq ($(UNAME),Darwin)
|
||||
# If disabled, don't run dsymutil
|
||||
off:
|
||||
rm -rf $(TMPDIR)/*.dSYM
|
||||
$(RUSTC) foo.rs -g -C split-debuginfo=off
|
||||
[ ! -d $(TMPDIR)/foo.dSYM ]
|
||||
|
||||
# Packed by default, but only if debuginfo is requested
|
||||
packed:
|
||||
rm -rf $(TMPDIR)/*.dSYM
|
||||
$(RUSTC) foo.rs
|
||||
[ ! -d $(TMPDIR)/foo.dSYM ]
|
||||
rm -rf $(TMPDIR)/*.dSYM
|
||||
$(RUSTC) foo.rs -g
|
||||
[ -d $(TMPDIR)/foo.dSYM ]
|
||||
rm -rf $(TMPDIR)/*.dSYM
|
||||
$(RUSTC) foo.rs -g -C split-debuginfo=packed
|
||||
[ -d $(TMPDIR)/foo.dSYM ]
|
||||
rm -rf $(TMPDIR)/*.dSYM
|
||||
|
||||
# Object files are preserved with unpacked and `dsymutil` isn't run
|
||||
unpacked:
|
||||
$(RUSTC) foo.rs -g -C split-debuginfo=unpacked
|
||||
ls $(TMPDIR)/*.o
|
||||
[ ! -d $(TMPDIR)/foo.dSYM ]
|
||||
else
|
||||
ifdef IS_WINDOWS
|
||||
# Windows only supports =off
|
||||
off:
|
||||
packed:
|
||||
unpacked:
|
||||
else
|
||||
# If disabled, don't run dsymutil
|
||||
off:
|
||||
$(RUSTC) foo.rs -g -C split-debuginfo=off -Z unstable-options
|
||||
[ ! -f $(TMPDIR)/*.dwp ]
|
||||
[ ! -f $(TMPDIR)/*.dwo ]
|
||||
|
||||
$(RUSTC) foo.rs -g
|
||||
[ ! -f $(TMPDIR)/*.dwp ]
|
||||
[ ! -f $(TMPDIR)/*.dwo ]
|
||||
|
||||
packed:
|
||||
$(RUSTC) foo.rs -g -C split-debuginfo=packed -Z unstable-options
|
||||
ls $(TMPDIR)/*.dwp
|
||||
ls $(TMPDIR)/*.dwo && exit 1 || exit 0
|
||||
rm -rf $(TMPDIR)/*.dwp
|
||||
|
||||
unpacked:
|
||||
$(RUSTC) foo.rs -g -C split-debuginfo=unpacked -Z unstable-options
|
||||
ls $(TMPDIR)/*.dwp && exit 1 || exit 0
|
||||
ls $(TMPDIR)/*.dwo
|
||||
rm -rf $(TMPDIR)/*.dwo
|
||||
endif
|
||||
endif
|
1
src/test/run-make-fulldeps/split-debuginfo/foo.rs
Normal file
1
src/test/run-make-fulldeps/split-debuginfo/foo.rs
Normal file
@ -0,0 +1 @@
|
||||
fn main() {}
|
@ -3,6 +3,6 @@
|
||||
# only-linux
|
||||
|
||||
all:
|
||||
$(RUSTC) -Z split-dwarf=split foo.rs
|
||||
$(RUSTC) -Z unstable-options -C split-debuginfo=packed foo.rs -g
|
||||
rm $(TMPDIR)/foo.dwp
|
||||
rm $(TMPDIR)/$(call BIN,foo)
|
||||
|
15
src/test/rustdoc/fn-type.rs
Normal file
15
src/test/rustdoc/fn-type.rs
Normal file
@ -0,0 +1,15 @@
|
||||
// ignore-tidy-linelength
|
||||
|
||||
#![crate_name = "foo"]
|
||||
#![crate_type = "lib"]
|
||||
|
||||
pub struct Foo<'a, T> {
|
||||
pub generic: fn(val: &T) -> T,
|
||||
|
||||
pub lifetime: fn(val: &'a i32) -> i32,
|
||||
pub hrtb_lifetime: for<'b, 'c> fn(one: &'b i32, two: &'c &'b i32) -> (&'b i32, &'c i32),
|
||||
}
|
||||
|
||||
// @has 'foo/struct.Foo.html' '//span[@id="structfield.generic"]' "generic: fn(val: &T) -> T"
|
||||
// @has 'foo/struct.Foo.html' '//span[@id="structfield.lifetime"]' "lifetime: fn(val: &'a i32) -> i32"
|
||||
// @has 'foo/struct.Foo.html' '//span[@id="structfield.hrtb_lifetime"]' "hrtb_lifetime: for<'b, 'c> fn(one: &'b i32, two: &'c &'b i32) -> (&'b i32, &'c i32)"
|
14
src/test/rustdoc/for-lifetime.rs
Normal file
14
src/test/rustdoc/for-lifetime.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// ignore-tidy-linelength
|
||||
|
||||
#![crate_name = "foo"]
|
||||
#![crate_type = "lib"]
|
||||
|
||||
pub struct Foo {
|
||||
pub some_func: for<'a> fn(val: &'a i32) -> i32,
|
||||
pub some_trait: dyn for<'a> Trait<'a>,
|
||||
}
|
||||
|
||||
// @has foo/struct.Foo.html '//span[@id="structfield.some_func"]' "some_func: for<'a> fn(val: &'a i32) -> i32"
|
||||
// @has foo/struct.Foo.html '//span[@id="structfield.some_trait"]' "some_trait: dyn Trait<'a>"
|
||||
|
||||
pub trait Trait<'a> {}
|
@ -31,7 +31,7 @@ impl Tr for u32 {
|
||||
fn main() {
|
||||
assert_eq!(<() as Tr>::A, 255);
|
||||
assert_eq!(<() as Tr>::B, 0); // causes the error above
|
||||
//~^ ERROR evaluation of constant expression failed
|
||||
//~^ ERROR evaluation of constant value failed
|
||||
//~| ERROR erroneous constant used
|
||||
|
||||
assert_eq!(<u8 as Tr>::A, 254);
|
||||
|
@ -8,15 +8,11 @@ LL | const B: u8 = Self::A + 1;
|
||||
|
|
||||
= note: `#[deny(const_err)]` on by default
|
||||
|
||||
error[E0080]: evaluation of constant expression failed
|
||||
--> $DIR/defaults-not-assumed-fail.rs:33:5
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/defaults-not-assumed-fail.rs:33:16
|
||||
|
|
||||
LL | assert_eq!(<() as Tr>::B, 0); // causes the error above
|
||||
| ^^^^^^^^^^^-------------^^^^^
|
||||
| |
|
||||
| referenced constant has errors
|
||||
|
|
||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
| ^^^^^^^^^^^^^ referenced constant has errors
|
||||
|
||||
error: erroneous constant used
|
||||
--> $DIR/defaults-not-assumed-fail.rs:33:5
|
||||
|
30
src/test/ui/backtrace-apple-no-dsymutil.rs
Normal file
30
src/test/ui/backtrace-apple-no-dsymutil.rs
Normal file
@ -0,0 +1,30 @@
|
||||
// run-pass
|
||||
|
||||
// compile-flags:-g -Csplit-debuginfo=unpacked
|
||||
// only-macos
|
||||
|
||||
#![feature(backtrace)]
|
||||
|
||||
use std::process::Command;
|
||||
use std::str;
|
||||
|
||||
#[inline(never)]
|
||||
fn main() {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
if args.len() >= 2 {
|
||||
println!("{}", std::backtrace::Backtrace::force_capture());
|
||||
return;
|
||||
}
|
||||
let out = Command::new(&args[0]).env("RUST_BACKTRACE", "1").arg("foo").output().unwrap();
|
||||
let output = format!(
|
||||
"{}\n{}",
|
||||
str::from_utf8(&out.stdout).unwrap(),
|
||||
str::from_utf8(&out.stderr).unwrap(),
|
||||
);
|
||||
if out.status.success() && output.contains(file!()) {
|
||||
return;
|
||||
}
|
||||
println!("status: {}", out.status);
|
||||
println!("child output:\n\t{}", output.replace("\n", "\n\t"));
|
||||
panic!("failed to find {:?} in output", file!());
|
||||
}
|
@ -20,7 +20,9 @@ error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable
|
||||
|
|
||||
LL | let f = || {
|
||||
| - help: consider changing this to be mutable: `mut f`
|
||||
...
|
||||
LL | let y = &raw mut x;
|
||||
| - calling `f` requires mutable binding due to mutable borrow of `x`
|
||||
LL | };
|
||||
LL | f();
|
||||
| ^ cannot borrow as mutable
|
||||
|
||||
|
@ -0,0 +1,7 @@
|
||||
fn main() {
|
||||
let mut my_var = false;
|
||||
let callback = || {
|
||||
&mut my_var;
|
||||
};
|
||||
callback(); //~ ERROR E0596
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable
|
||||
--> $DIR/issue-80313-mutable-borrow-in-closure.rs:6:5
|
||||
|
|
||||
LL | let callback = || {
|
||||
| -------- help: consider changing this to be mutable: `mut callback`
|
||||
LL | &mut my_var;
|
||||
| ------ calling `callback` requires mutable binding due to mutable borrow of `my_var`
|
||||
LL | };
|
||||
LL | callback();
|
||||
| ^^^^^^^^ cannot borrow as mutable
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0596`.
|
@ -0,0 +1,7 @@
|
||||
fn main() {
|
||||
let mut my_var = false;
|
||||
let callback = move || {
|
||||
&mut my_var;
|
||||
};
|
||||
callback(); //~ ERROR E0596
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable
|
||||
--> $DIR/issue-80313-mutable-borrow-in-move-closure.rs:6:5
|
||||
|
|
||||
LL | let callback = move || {
|
||||
| -------- help: consider changing this to be mutable: `mut callback`
|
||||
LL | &mut my_var;
|
||||
| ------ calling `callback` requires mutable binding due to possible mutation of `my_var`
|
||||
LL | };
|
||||
LL | callback();
|
||||
| ^^^^^^^^ cannot borrow as mutable
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0596`.
|
7
src/test/ui/closures/issue-80313-mutation-in-closure.rs
Normal file
7
src/test/ui/closures/issue-80313-mutation-in-closure.rs
Normal file
@ -0,0 +1,7 @@
|
||||
fn main() {
|
||||
let mut my_var = false;
|
||||
let callback = || {
|
||||
my_var = true;
|
||||
};
|
||||
callback(); //~ ERROR E0596
|
||||
}
|
14
src/test/ui/closures/issue-80313-mutation-in-closure.stderr
Normal file
14
src/test/ui/closures/issue-80313-mutation-in-closure.stderr
Normal file
@ -0,0 +1,14 @@
|
||||
error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable
|
||||
--> $DIR/issue-80313-mutation-in-closure.rs:6:5
|
||||
|
|
||||
LL | let callback = || {
|
||||
| -------- help: consider changing this to be mutable: `mut callback`
|
||||
LL | my_var = true;
|
||||
| ------ calling `callback` requires mutable binding due to mutable borrow of `my_var`
|
||||
LL | };
|
||||
LL | callback();
|
||||
| ^^^^^^^^ cannot borrow as mutable
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0596`.
|
@ -0,0 +1,7 @@
|
||||
fn main() {
|
||||
let mut my_var = false;
|
||||
let callback = move || {
|
||||
my_var = true;
|
||||
};
|
||||
callback(); //~ ERROR E0596
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable
|
||||
--> $DIR/issue-80313-mutation-in-move-closure.rs:6:5
|
||||
|
|
||||
LL | let callback = move || {
|
||||
| -------- help: consider changing this to be mutable: `mut callback`
|
||||
LL | my_var = true;
|
||||
| ------ calling `callback` requires mutable binding due to possible mutation of `my_var`
|
||||
LL | };
|
||||
LL | callback();
|
||||
| ^^^^^^^^ cannot borrow as mutable
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0596`.
|
@ -12,7 +12,7 @@ note: the lint level is defined here
|
||||
LL | #![warn(const_err)]
|
||||
| ^^^^^^^^^
|
||||
|
||||
error[E0080]: evaluation of constant expression failed
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/conditional_array_execution.rs:11:20
|
||||
|
|
||||
LL | println!("{}", FOO);
|
||||
|
@ -21,6 +21,6 @@ const X: i32 = 1 / 0; //~WARN any use of this value will cause an error
|
||||
|
||||
fn main() {
|
||||
let x: &'static i32 = &X;
|
||||
//~^ ERROR evaluation of constant expression failed
|
||||
//~^ ERROR evaluation of constant value failed
|
||||
println!("x={}", x);
|
||||
}
|
||||
|
@ -12,13 +12,11 @@ note: the lint level is defined here
|
||||
LL | #[warn(const_err)]
|
||||
| ^^^^^^^^^
|
||||
|
||||
error[E0080]: evaluation of constant expression failed
|
||||
--> $DIR/const-eval-query-stack.rs:23:27
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/const-eval-query-stack.rs:23:28
|
||||
|
|
||||
LL | let x: &'static i32 = &X;
|
||||
| ^-
|
||||
| |
|
||||
| referenced constant has errors
|
||||
| ^ referenced constant has errors
|
||||
query stack during panic:
|
||||
#0 [normalize_generic_arg_after_erasing_regions] normalizing `main::promoted[1]`
|
||||
#1 [optimized_mir] optimizing MIR for `main`
|
||||
|
@ -18,7 +18,7 @@ const Z: usize = bar(double, 2); // FIXME: should fail to typeck someday
|
||||
|
||||
fn main() {
|
||||
assert_eq!(Y, 4);
|
||||
//~^ ERROR evaluation of constant expression failed
|
||||
//~^ ERROR evaluation of constant value failed
|
||||
assert_eq!(Z, 4);
|
||||
//~^ ERROR evaluation of constant expression failed
|
||||
//~^ ERROR evaluation of constant value failed
|
||||
}
|
||||
|
@ -1,22 +1,14 @@
|
||||
error[E0080]: evaluation of constant expression failed
|
||||
--> $DIR/const_fn_ptr_fail2.rs:20:5
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/const_fn_ptr_fail2.rs:20:16
|
||||
|
|
||||
LL | assert_eq!(Y, 4);
|
||||
| ^^^^^^^^^^^-^^^^^
|
||||
| |
|
||||
| referenced constant has errors
|
||||
|
|
||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
| ^ referenced constant has errors
|
||||
|
||||
error[E0080]: evaluation of constant expression failed
|
||||
--> $DIR/const_fn_ptr_fail2.rs:22:5
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/const_fn_ptr_fail2.rs:22:16
|
||||
|
|
||||
LL | assert_eq!(Z, 4);
|
||||
| ^^^^^^^^^^^-^^^^^
|
||||
| |
|
||||
| referenced constant has errors
|
||||
|
|
||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
| ^ referenced constant has errors
|
||||
|
||||
warning: skipping const checks
|
||||
|
|
||||
|
@ -12,8 +12,8 @@ fn main() {
|
||||
const Y: u32 = foo(0 - 1);
|
||||
//~^ WARN any use of this value will cause
|
||||
println!("{} {}", X, Y);
|
||||
//~^ ERROR evaluation of constant expression failed
|
||||
//~| ERROR evaluation of constant expression failed
|
||||
//~^ ERROR evaluation of constant value failed
|
||||
//~| ERROR evaluation of constant value failed
|
||||
//~| WARN erroneous constant used [const_err]
|
||||
//~| WARN erroneous constant used [const_err]
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ LL | const Y: u32 = foo(0 - 1);
|
||||
| |
|
||||
| attempt to compute `0_u32 - 1_u32`, which would overflow
|
||||
|
||||
error[E0080]: evaluation of constant expression failed
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/issue-43197.rs:14:23
|
||||
|
|
||||
LL | println!("{} {}", X, Y);
|
||||
@ -32,7 +32,7 @@ warning: erroneous constant used
|
||||
LL | println!("{} {}", X, Y);
|
||||
| ^ referenced constant has errors
|
||||
|
||||
error[E0080]: evaluation of constant expression failed
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/issue-43197.rs:14:26
|
||||
|
|
||||
LL | println!("{} {}", X, Y);
|
||||
|
@ -25,5 +25,5 @@ impl Foo for u16 {
|
||||
|
||||
fn main() {
|
||||
println!("{}", <Bar<u16, u8> as Foo>::AMT);
|
||||
//~^ ERROR evaluation of constant expression failed [E0080]
|
||||
//~^ ERROR evaluation of constant value failed [E0080]
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
error[E0080]: evaluation of constant expression failed
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/issue-44578.rs:27:20
|
||||
|
|
||||
LL | println!("{}", <Bar<u16, u8> as Foo>::AMT);
|
||||
|
@ -8,13 +8,11 @@ LL | const BAR: usize = [5, 6, 7][T::BOO];
|
||||
|
|
||||
= note: `#[deny(const_err)]` on by default
|
||||
|
||||
error[E0080]: evaluation of constant expression failed
|
||||
--> $DIR/issue-50814-2.rs:18:5
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/issue-50814-2.rs:18:6
|
||||
|
|
||||
LL | &<A<T> as Foo<T>>::BAR
|
||||
| ^---------------------
|
||||
| |
|
||||
| referenced constant has errors
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -8,13 +8,11 @@ LL | const MAX: u8 = A::MAX + B::MAX;
|
||||
|
|
||||
= note: `#[deny(const_err)]` on by default
|
||||
|
||||
error[E0080]: evaluation of constant expression failed
|
||||
--> $DIR/issue-50814.rs:20:5
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/issue-50814.rs:20:6
|
||||
|
|
||||
LL | &Sum::<U8,U8>::MAX
|
||||
| ^-----------------
|
||||
| |
|
||||
| referenced constant has errors
|
||||
| ^^^^^^^^^^^^^^^^^ referenced constant has errors
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -20,15 +20,11 @@ note: the lint level is defined here
|
||||
LL | #[warn(const_err)]
|
||||
| ^^^^^^^^^
|
||||
|
||||
error[E0080]: evaluation of constant expression failed
|
||||
--> $DIR/const_unsafe_unreachable_ub.rs:17:3
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/const_unsafe_unreachable_ub.rs:17:14
|
||||
|
|
||||
LL | assert_eq!(BAR, true);
|
||||
| ^^^^^^^^^^^---^^^^^^^^
|
||||
| |
|
||||
| referenced constant has errors
|
||||
|
|
||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
| ^^^ referenced constant has errors
|
||||
|
||||
error: erroneous constant used
|
||||
--> $DIR/const_unsafe_unreachable_ub.rs:17:3
|
||||
|
@ -2,15 +2,12 @@ error[E0080]: values of the type `[u8; SIZE]` are too big for the current archit
|
||||
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
|
||||
|
|
||||
LL | intrinsics::size_of::<T>()
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| inside `std::mem::size_of::<[u8; SIZE]>` at $SRC_DIR/core/src/mem/mod.rs:LL:COL
|
||||
| inside `main` at $DIR/issue-55878.rs:7:26
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ inside `std::mem::size_of::<[u8; SIZE]>` at $SRC_DIR/core/src/mem/mod.rs:LL:COL
|
||||
|
|
||||
::: $DIR/issue-55878.rs:7:26
|
||||
|
|
||||
LL | println!("Size: {}", std::mem::size_of::<[u8; u64::MAX as usize]>());
|
||||
| ----------------------------------------------
|
||||
| ---------------------------------------------- inside `main` at $DIR/issue-55878.rs:7:26
|
||||
|
||||
error: erroneous constant used
|
||||
--> $DIR/issue-55878.rs:7:26
|
||||
|
@ -0,0 +1,15 @@
|
||||
// check-pass
|
||||
// Ensure that trailing semicolons are allowed by default
|
||||
|
||||
macro_rules! foo {
|
||||
() => {
|
||||
true;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let val = match true {
|
||||
true => false,
|
||||
_ => foo!()
|
||||
};
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
// check-pass
|
||||
#![warn(semicolon_in_expressions_from_macros)]
|
||||
|
||||
#[allow(dead_code)]
|
||||
macro_rules! foo {
|
||||
($val:ident) => {
|
||||
true; //~ WARN trailing
|
||||
//~| WARN this was previously
|
||||
//~| WARN trailing
|
||||
//~| WARN this was previously
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// This `allow` doesn't work
|
||||
#[allow(semicolon_in_expressions_from_macros)]
|
||||
let _ = {
|
||||
foo!(first)
|
||||
};
|
||||
|
||||
// This 'allow' doesn't work either
|
||||
#[allow(semicolon_in_expressions_from_macros)]
|
||||
let _ = foo!(second);
|
||||
|
||||
// But this 'allow' does
|
||||
#[allow(semicolon_in_expressions_from_macros)]
|
||||
fn inner() {
|
||||
let _ = foo!(third);
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
warning: trailing semicolon in macro used in expression position
|
||||
--> $DIR/semicolon-in-expressions-from-macros.rs:7:13
|
||||
|
|
||||
LL | true;
|
||||
| ^
|
||||
...
|
||||
LL | foo!(first)
|
||||
| ----------- in this macro invocation
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/semicolon-in-expressions-from-macros.rs:2:9
|
||||
|
|
||||
LL | #![warn(semicolon_in_expressions_from_macros)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
|
||||
= note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
warning: trailing semicolon in macro used in expression position
|
||||
--> $DIR/semicolon-in-expressions-from-macros.rs:7:13
|
||||
|
|
||||
LL | true;
|
||||
| ^
|
||||
...
|
||||
LL | let _ = foo!(second);
|
||||
| ------------ in this macro invocation
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
|
||||
= note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
warning: 2 warnings emitted
|
||||
|
@ -3,6 +3,8 @@ error[E0596]: cannot borrow `tick1` as mutable, as it is not declared as mutable
|
||||
|
|
||||
LL | let tick1 = || {
|
||||
| ----- help: consider changing this to be mutable: `mut tick1`
|
||||
LL | counter += 1;
|
||||
| ------- calling `tick1` requires mutable binding due to mutable borrow of `counter`
|
||||
...
|
||||
LL | tick1();
|
||||
| ^^^^^ cannot borrow as mutable
|
||||
@ -12,6 +14,8 @@ error[E0596]: cannot borrow `tick2` as mutable, as it is not declared as mutable
|
||||
|
|
||||
LL | let tick2 = || {
|
||||
| ----- help: consider changing this to be mutable: `mut tick2`
|
||||
LL | tick1();
|
||||
| ----- calling `tick2` requires mutable binding due to mutable borrow of `tick1`
|
||||
...
|
||||
LL | tick2();
|
||||
| ^^^^^ cannot borrow as mutable
|
||||
|
@ -2,7 +2,9 @@ error[E0596]: cannot borrow `tick` as mutable, as it is not declared as mutable
|
||||
--> $DIR/unboxed-closures-infer-fnmut-missing-mut.rs:7:5
|
||||
|
|
||||
LL | let tick = || counter += 1;
|
||||
| ---- help: consider changing this to be mutable: `mut tick`
|
||||
| ---- ------- calling `tick` requires mutable binding due to mutable borrow of `counter`
|
||||
| |
|
||||
| help: consider changing this to be mutable: `mut tick`
|
||||
LL | tick();
|
||||
| ^^^^ cannot borrow as mutable
|
||||
|
||||
|
@ -2,7 +2,9 @@ error[E0596]: cannot borrow `tick` as mutable, as it is not declared as mutable
|
||||
--> $DIR/unboxed-closures-infer-fnmut-move-missing-mut.rs:7:5
|
||||
|
|
||||
LL | let tick = move || counter += 1;
|
||||
| ---- help: consider changing this to be mutable: `mut tick`
|
||||
| ---- ------- calling `tick` requires mutable binding due to possible mutation of `counter`
|
||||
| |
|
||||
| help: consider changing this to be mutable: `mut tick`
|
||||
LL | tick();
|
||||
| ^^^^ cannot borrow as mutable
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::utils::{
|
||||
any_parent_is_automatically_derived, contains_name, match_def_path, paths, qpath_res, snippet_with_macro_callsite,
|
||||
any_parent_is_automatically_derived, contains_name, match_def_path, paths, snippet_with_macro_callsite,
|
||||
};
|
||||
use crate::utils::{span_lint_and_note, span_lint_and_sugg};
|
||||
use if_chain::if_chain;
|
||||
@ -231,7 +231,7 @@ fn is_expr_default<'tcx>(expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> bool
|
||||
if_chain! {
|
||||
if let ExprKind::Call(ref fn_expr, _) = &expr.kind;
|
||||
if let ExprKind::Path(qpath) = &fn_expr.kind;
|
||||
if let Res::Def(_, def_id) = qpath_res(cx, qpath, fn_expr.hir_id);
|
||||
if let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id);
|
||||
then {
|
||||
// right hand side of assignment is `Default::default`
|
||||
match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD)
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::utils::{is_copy, match_def_path, paths, qpath_res, span_lint_and_note};
|
||||
use crate::utils::{is_copy, match_def_path, paths, span_lint_and_note};
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
@ -114,7 +114,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
|
||||
if let ExprKind::Call(ref path, ref args) = expr.kind;
|
||||
if let ExprKind::Path(ref qpath) = path.kind;
|
||||
if args.len() == 1;
|
||||
if let Some(def_id) = qpath_res(cx, qpath, path.hir_id).opt_def_id();
|
||||
if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id();
|
||||
then {
|
||||
let lint;
|
||||
let msg;
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::utils::{is_entrypoint_fn, match_def_path, paths, qpath_res, span_lint};
|
||||
use crate::utils::{is_entrypoint_fn, match_def_path, paths, span_lint};
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
@ -29,7 +29,7 @@ impl<'tcx> LateLintPass<'tcx> for Exit {
|
||||
if_chain! {
|
||||
if let ExprKind::Call(ref path_expr, ref _args) = e.kind;
|
||||
if let ExprKind::Path(ref path) = path_expr.kind;
|
||||
if let Some(def_id) = qpath_res(cx, path, path_expr.hir_id).opt_def_id();
|
||||
if let Some(def_id) = cx.qpath_res(path, path_expr.hir_id).opt_def_id();
|
||||
if match_def_path(cx, def_id, &paths::EXIT);
|
||||
then {
|
||||
let parent = cx.tcx.hir().get_parent_item(e.hir_id);
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::utils::{
|
||||
attr_by_name, attrs::is_proc_macro, is_must_use_ty, is_trait_impl_item, is_type_diagnostic_item, iter_input_pats,
|
||||
last_path_segment, match_def_path, must_use_attr, qpath_res, return_ty, snippet, snippet_opt, span_lint,
|
||||
span_lint_and_help, span_lint_and_then, trait_ref_of_method, type_is_unsafe_function,
|
||||
last_path_segment, match_def_path, must_use_attr, return_ty, snippet, snippet_opt, span_lint, span_lint_and_help,
|
||||
span_lint_and_then, trait_ref_of_method, type_is_unsafe_function,
|
||||
};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::Attribute;
|
||||
@ -659,7 +659,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> {
|
||||
impl<'a, 'tcx> DerefVisitor<'a, 'tcx> {
|
||||
fn check_arg(&self, ptr: &hir::Expr<'_>) {
|
||||
if let hir::ExprKind::Path(ref qpath) = ptr.kind {
|
||||
if let Res::Local(id) = qpath_res(self.cx, qpath, ptr.hir_id) {
|
||||
if let Res::Local(id) = self.cx.qpath_res(qpath, ptr.hir_id) {
|
||||
if self.ptrs.contains(&id) {
|
||||
span_lint(
|
||||
self.cx,
|
||||
@ -722,7 +722,7 @@ fn is_mutated_static(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> bool {
|
||||
use hir::ExprKind::{Field, Index, Path};
|
||||
|
||||
match e.kind {
|
||||
Path(ref qpath) => !matches!(qpath_res(cx, qpath, e.hir_id), Res::Local(_)),
|
||||
Path(ref qpath) => !matches!(cx.qpath_res(qpath, e.hir_id), Res::Local(_)),
|
||||
Field(ref inner, _) | Index(ref inner, _) => is_mutated_static(cx, inner),
|
||||
_ => false,
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::utils::{qpath_res, snippet, span_lint_and_then, visitors::LocalUsedVisitor};
|
||||
use crate::utils::{snippet, span_lint_and_then, visitors::LocalUsedVisitor};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
@ -145,7 +145,7 @@ fn check_assign<'tcx>(
|
||||
if let hir::StmtKind::Semi(ref expr) = expr.kind;
|
||||
if let hir::ExprKind::Assign(ref var, ref value, _) = expr.kind;
|
||||
if let hir::ExprKind::Path(ref qpath) = var.kind;
|
||||
if let Res::Local(local_id) = qpath_res(cx, qpath, var.hir_id);
|
||||
if let Res::Local(local_id) = cx.qpath_res(qpath, var.hir_id);
|
||||
if decl == local_id;
|
||||
then {
|
||||
let mut v = LocalUsedVisitor::new(decl);
|
||||
|
@ -6,9 +6,9 @@ use crate::utils::visitors::LocalUsedVisitor;
|
||||
use crate::utils::{
|
||||
contains_name, get_enclosing_block, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait,
|
||||
indent_of, is_in_panic_handler, is_integer_const, is_no_std_crate, is_refutable, is_type_diagnostic_item,
|
||||
last_path_segment, match_trait_method, match_type, match_var, multispan_sugg, qpath_res, single_segment_path,
|
||||
snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_help,
|
||||
span_lint_and_sugg, span_lint_and_then, sugg, SpanlessEq,
|
||||
last_path_segment, match_trait_method, match_type, match_var, multispan_sugg, single_segment_path, snippet,
|
||||
snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg,
|
||||
span_lint_and_then, sugg, SpanlessEq,
|
||||
};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast;
|
||||
@ -848,7 +848,7 @@ fn same_var<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, var: HirId) -> bool {
|
||||
if let ExprKind::Path(qpath) = &expr.kind;
|
||||
if let QPath::Resolved(None, path) = qpath;
|
||||
if path.segments.len() == 1;
|
||||
if let Res::Local(local_id) = qpath_res(cx, qpath, expr.hir_id);
|
||||
if let Res::Local(local_id) = cx.qpath_res(qpath, expr.hir_id);
|
||||
then {
|
||||
// our variable!
|
||||
local_id == var
|
||||
@ -1420,7 +1420,7 @@ fn detect_same_item_push<'tcx>(
|
||||
// Make sure that the push does not involve possibly mutating values
|
||||
match pushed_item.kind {
|
||||
ExprKind::Path(ref qpath) => {
|
||||
match qpath_res(cx, qpath, pushed_item.hir_id) {
|
||||
match cx.qpath_res(qpath, pushed_item.hir_id) {
|
||||
// immutable bindings that are initialized with literal or constant
|
||||
Res::Local(hir_id) => {
|
||||
if_chain! {
|
||||
@ -1437,7 +1437,7 @@ fn detect_same_item_push<'tcx>(
|
||||
ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item),
|
||||
// immutable bindings that are initialized with constant
|
||||
ExprKind::Path(ref path) => {
|
||||
if let Res::Def(DefKind::Const, ..) = qpath_res(cx, path, init.hir_id) {
|
||||
if let Res::Def(DefKind::Const, ..) = cx.qpath_res(path, init.hir_id) {
|
||||
emit_lint(cx, vec, pushed_item);
|
||||
}
|
||||
}
|
||||
@ -2028,7 +2028,7 @@ fn check_for_mutability(cx: &LateContext<'_>, bound: &Expr<'_>) -> Option<HirId>
|
||||
if let ExprKind::Path(ref qpath) = bound.kind;
|
||||
if let QPath::Resolved(None, _) = *qpath;
|
||||
then {
|
||||
let res = qpath_res(cx, qpath, bound.hir_id);
|
||||
let res = cx.qpath_res(qpath, bound.hir_id);
|
||||
if let Res::Local(hir_id) = res {
|
||||
let node_str = cx.tcx.hir().get(hir_id);
|
||||
if_chain! {
|
||||
@ -2120,7 +2120,7 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> {
|
||||
if self.prefer_mutable {
|
||||
self.indexed_mut.insert(seqvar.segments[0].ident.name);
|
||||
}
|
||||
let res = qpath_res(self.cx, seqpath, seqexpr.hir_id);
|
||||
let res = self.cx.qpath_res(seqpath, seqexpr.hir_id);
|
||||
match res {
|
||||
Res::Local(hir_id) => {
|
||||
let parent_id = self.cx.tcx.hir().get_parent_item(expr.hir_id);
|
||||
@ -2184,7 +2184,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
|
||||
if let QPath::Resolved(None, ref path) = *qpath;
|
||||
if path.segments.len() == 1;
|
||||
then {
|
||||
if let Res::Local(local_id) = qpath_res(self.cx, qpath, expr.hir_id) {
|
||||
if let Res::Local(local_id) = self.cx.qpath_res(qpath, expr.hir_id) {
|
||||
if local_id == self.var {
|
||||
self.nonindex = true;
|
||||
} else {
|
||||
@ -2589,7 +2589,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> {
|
||||
|
||||
fn var_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<HirId> {
|
||||
if let ExprKind::Path(ref qpath) = expr.kind {
|
||||
let path_res = qpath_res(cx, qpath, expr.hir_id);
|
||||
let path_res = cx.qpath_res(qpath, expr.hir_id);
|
||||
if let Res::Local(hir_id) = path_res {
|
||||
return Some(hir_id);
|
||||
}
|
||||
@ -2819,7 +2819,7 @@ impl<'a, 'tcx> VarCollectorVisitor<'a, 'tcx> {
|
||||
if_chain! {
|
||||
if let ExprKind::Path(ref qpath) = ex.kind;
|
||||
if let QPath::Resolved(None, _) = *qpath;
|
||||
let res = qpath_res(self.cx, qpath, ex.hir_id);
|
||||
let res = self.cx.qpath_res(qpath, ex.hir_id);
|
||||
then {
|
||||
match res {
|
||||
Res::Local(hir_id) => {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::consts::{constant, Constant};
|
||||
use crate::utils::usage::mutated_variables;
|
||||
use crate::utils::{
|
||||
eq_expr_value, higher, match_def_path, meets_msrv, multispan_sugg, paths, qpath_res, snippet, span_lint_and_then,
|
||||
eq_expr_value, higher, match_def_path, meets_msrv, multispan_sugg, paths, snippet, span_lint_and_then,
|
||||
};
|
||||
|
||||
use if_chain::if_chain;
|
||||
@ -92,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
let target_res = qpath_res(cx, &target_path, target_arg.hir_id);
|
||||
let target_res = cx.qpath_res(&target_path, target_arg.hir_id);
|
||||
if target_res == Res::Err {
|
||||
return;
|
||||
};
|
||||
@ -221,7 +221,7 @@ fn find_stripping<'tcx>(
|
||||
if let ExprKind::Index(indexed, index) = &unref.kind;
|
||||
if let Some(higher::Range { start, end, .. }) = higher::range(index);
|
||||
if let ExprKind::Path(path) = &indexed.kind;
|
||||
if qpath_res(self.cx, path, ex.hir_id) == self.target;
|
||||
if self.cx.qpath_res(path, ex.hir_id) == self.target;
|
||||
then {
|
||||
match (self.strip_kind, start, end) {
|
||||
(StripKind::Prefix, Some(start), None) => {
|
||||
@ -235,7 +235,7 @@ fn find_stripping<'tcx>(
|
||||
if let ExprKind::Binary(Spanned { node: BinOpKind::Sub, .. }, left, right) = end.kind;
|
||||
if let Some(left_arg) = len_arg(self.cx, left);
|
||||
if let ExprKind::Path(left_path) = &left_arg.kind;
|
||||
if qpath_res(self.cx, left_path, left_arg.hir_id) == self.target;
|
||||
if self.cx.qpath_res(left_path, left_arg.hir_id) == self.target;
|
||||
if eq_pattern_length(self.cx, self.pattern, right);
|
||||
then {
|
||||
self.results.push(ex.span);
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::utils::{match_def_path, paths, qpath_res, span_lint};
|
||||
use crate::utils::{match_def_path, paths, span_lint};
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
@ -29,7 +29,7 @@ impl<'tcx> LateLintPass<'tcx> for MemForget {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
|
||||
if let ExprKind::Call(ref path_expr, ref args) = e.kind {
|
||||
if let ExprKind::Path(ref qpath) = path_expr.kind {
|
||||
if let Some(def_id) = qpath_res(cx, qpath, path_expr.hir_id).opt_def_id() {
|
||||
if let Some(def_id) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id() {
|
||||
if match_def_path(cx, def_id, &paths::MEM_FORGET) {
|
||||
let forgot_ty = cx.typeck_results().expr_ty(&args[0]);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::utils::{has_drop, qpath_res, snippet_opt, span_lint, span_lint_and_sugg};
|
||||
use crate::utils::{has_drop, snippet_opt, span_lint, span_lint_and_sugg};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::{BinOpKind, BlockCheckMode, Expr, ExprKind, Stmt, StmtKind, UnsafeSource};
|
||||
@ -67,7 +67,7 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
},
|
||||
ExprKind::Call(ref callee, ref args) => {
|
||||
if let ExprKind::Path(ref qpath) = callee.kind {
|
||||
let res = qpath_res(cx, qpath, callee.hir_id);
|
||||
let res = cx.qpath_res(qpath, callee.hir_id);
|
||||
match res {
|
||||
Res::Def(DefKind::Struct | DefKind::Variant | DefKind::Ctor(..), ..) => {
|
||||
!has_drop(cx, cx.typeck_results().expr_ty(expr))
|
||||
@ -146,7 +146,7 @@ fn reduce_expression<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<Vec
|
||||
},
|
||||
ExprKind::Call(ref callee, ref args) => {
|
||||
if let ExprKind::Path(ref qpath) = callee.kind {
|
||||
let res = qpath_res(cx, qpath, callee.hir_id);
|
||||
let res = cx.qpath_res(qpath, callee.hir_id);
|
||||
match res {
|
||||
Res::Def(DefKind::Struct | DefKind::Variant | DefKind::Ctor(..), ..)
|
||||
if !has_drop(cx, cx.typeck_results().expr_ty(expr)) =>
|
||||
|
@ -18,7 +18,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::{InnerSpan, Span, DUMMY_SP};
|
||||
use rustc_typeck::hir_ty_to_ty;
|
||||
|
||||
use crate::utils::{in_constant, qpath_res, span_lint_and_then};
|
||||
use crate::utils::{in_constant, span_lint_and_then};
|
||||
use if_chain::if_chain;
|
||||
|
||||
// FIXME: this is a correctness problem but there's no suitable
|
||||
@ -339,7 +339,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
|
||||
}
|
||||
|
||||
// Make sure it is a const item.
|
||||
let item_def_id = match qpath_res(cx, qpath, expr.hir_id) {
|
||||
let item_def_id = match cx.qpath_res(qpath, expr.hir_id) {
|
||||
Res::Def(DefKind::Const | DefKind::AssocConst, did) => did,
|
||||
_ => return,
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::utils::{match_def_path, match_trait_method, paths, qpath_res, span_lint};
|
||||
use crate::utils::{match_def_path, match_trait_method, paths, span_lint};
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::{Expr, ExprKind, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind};
|
||||
@ -94,7 +94,7 @@ impl LateLintPass<'_> for ToStringInDisplay {
|
||||
if match_trait_method(cx, expr, &paths::TO_STRING);
|
||||
if self.in_display_impl;
|
||||
if let ExprKind::Path(ref qpath) = args[0].kind;
|
||||
if let Res::Local(hir_id) = qpath_res(cx, qpath, args[0].hir_id);
|
||||
if let Res::Local(hir_id) = cx.qpath_res(qpath, args[0].hir_id);
|
||||
if let Some(self_hir_id) = self.self_hir_id;
|
||||
if hir_id == self_hir_id;
|
||||
then {
|
||||
|
@ -34,7 +34,7 @@ use crate::utils::sugg::Sugg;
|
||||
use crate::utils::{
|
||||
clip, comparisons, differing_macro_contexts, higher, in_constant, indent_of, int_bits, is_hir_ty_cfg_dependant,
|
||||
is_type_diagnostic_item, last_path_segment, match_def_path, match_path, meets_msrv, method_chain_args,
|
||||
multispan_sugg, numeric_literal::NumericLiteral, qpath_res, reindent_multiline, sext, snippet, snippet_opt,
|
||||
multispan_sugg, numeric_literal::NumericLiteral, reindent_multiline, sext, snippet, snippet_opt,
|
||||
snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg,
|
||||
span_lint_and_then, unsext,
|
||||
};
|
||||
@ -298,7 +298,7 @@ fn match_type_parameter(cx: &LateContext<'_>, qpath: &QPath<'_>, path: &[&str])
|
||||
_ => None,
|
||||
});
|
||||
if let TyKind::Path(ref qpath) = ty.kind;
|
||||
if let Some(did) = qpath_res(cx, qpath, ty.hir_id).opt_def_id();
|
||||
if let Some(did) = cx.qpath_res(qpath, ty.hir_id).opt_def_id();
|
||||
if match_def_path(cx, did, path);
|
||||
then {
|
||||
return Some(ty.span);
|
||||
@ -365,7 +365,7 @@ impl Types {
|
||||
match hir_ty.kind {
|
||||
TyKind::Path(ref qpath) if !is_local => {
|
||||
let hir_id = hir_ty.hir_id;
|
||||
let res = qpath_res(cx, qpath, hir_id);
|
||||
let res = cx.qpath_res(qpath, hir_id);
|
||||
if let Some(def_id) = res.opt_def_id() {
|
||||
if Some(def_id) == cx.tcx.lang_items().owned_box() {
|
||||
if let Some(span) = match_borrows_parameter(cx, qpath) {
|
||||
@ -535,7 +535,7 @@ impl Types {
|
||||
});
|
||||
// ty is now _ at this point
|
||||
if let TyKind::Path(ref ty_qpath) = ty.kind;
|
||||
let res = qpath_res(cx, ty_qpath, ty.hir_id);
|
||||
let res = cx.qpath_res(ty_qpath, ty.hir_id);
|
||||
if let Some(def_id) = res.opt_def_id();
|
||||
if Some(def_id) == cx.tcx.lang_items().owned_box();
|
||||
// At this point, we know ty is Box<T>, now get T
|
||||
@ -652,7 +652,7 @@ impl Types {
|
||||
match mut_ty.ty.kind {
|
||||
TyKind::Path(ref qpath) => {
|
||||
let hir_id = mut_ty.ty.hir_id;
|
||||
let def = qpath_res(cx, qpath, hir_id);
|
||||
let def = cx.qpath_res(qpath, hir_id);
|
||||
if_chain! {
|
||||
if let Some(def_id) = def.opt_def_id();
|
||||
if Some(def_id) == cx.tcx.lang_items().owned_box();
|
||||
@ -739,7 +739,7 @@ fn is_any_trait(t: &hir::Ty<'_>) -> bool {
|
||||
|
||||
fn get_bounds_if_impl_trait<'tcx>(cx: &LateContext<'tcx>, qpath: &QPath<'_>, id: HirId) -> Option<GenericBounds<'tcx>> {
|
||||
if_chain! {
|
||||
if let Some(did) = qpath_res(cx, qpath, id).opt_def_id();
|
||||
if let Some(did) = cx.qpath_res(qpath, id).opt_def_id();
|
||||
if let Some(Node::GenericParam(generic_param)) = cx.tcx.hir().get_if_local(did);
|
||||
if let GenericParamKind::Type { synthetic, .. } = generic_param.kind;
|
||||
if synthetic == Some(SyntheticTyParamKind::ImplTrait);
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::consts::{constant_simple, Constant};
|
||||
use crate::utils::{
|
||||
is_expn_of, match_def_path, match_qpath, match_type, method_calls, path_to_res, paths, qpath_res, run_lints,
|
||||
snippet, span_lint, span_lint_and_help, span_lint_and_sugg, SpanlessEq,
|
||||
is_expn_of, match_def_path, match_qpath, match_type, method_calls, path_to_res, paths, run_lints, snippet,
|
||||
span_lint, span_lint_and_help, span_lint_and_sugg, SpanlessEq,
|
||||
};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::{Crate as AstCrate, ItemKind, LitKind, NodeId};
|
||||
@ -787,7 +787,7 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Ve
|
||||
|
||||
match &expr.kind {
|
||||
ExprKind::AddrOf(.., expr) => return path_to_matched_type(cx, expr),
|
||||
ExprKind::Path(qpath) => match qpath_res(cx, qpath, expr.hir_id) {
|
||||
ExprKind::Path(qpath) => match cx.qpath_res(qpath, expr.hir_id) {
|
||||
Res::Local(hir_id) => {
|
||||
let parent_id = cx.tcx.hir().get_parent_node(hir_id);
|
||||
if let Some(Node::Local(local)) = cx.tcx.hir().find(parent_id) {
|
||||
|
@ -369,19 +369,6 @@ pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Option<def::Res> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn qpath_res(cx: &LateContext<'_>, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
|
||||
match qpath {
|
||||
hir::QPath::Resolved(_, path) => path.res,
|
||||
hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => {
|
||||
if cx.tcx.has_typeck_results(id.owner.to_def_id()) {
|
||||
cx.tcx.typeck(id.owner).qpath_res(qpath, id)
|
||||
} else {
|
||||
Res::Err
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Convenience function to get the `DefId` of a trait by path.
|
||||
/// It could be a trait or trait alias.
|
||||
pub fn get_trait_def_id(cx: &LateContext<'_>, path: &[&str]) -> Option<DefId> {
|
||||
|
@ -2015,10 +2015,10 @@ impl<'test> TestCx<'test> {
|
||||
rustc.args(&["-Zchalk"]);
|
||||
}
|
||||
Some(CompareMode::SplitDwarf) => {
|
||||
rustc.args(&["-Zsplit-dwarf=split"]);
|
||||
rustc.args(&["-Csplit-debuginfo=unpacked", "-Zunstable-options"]);
|
||||
}
|
||||
Some(CompareMode::SplitDwarfSingle) => {
|
||||
rustc.args(&["-Zsplit-dwarf=single"]);
|
||||
rustc.args(&["-Csplit-debuginfo=packed", "-Zunstable-options"]);
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ use std::path::Path;
|
||||
|
||||
const ENTRY_LIMIT: usize = 1000;
|
||||
// FIXME: The following limits should be reduced eventually.
|
||||
const ROOT_ENTRY_LIMIT: usize = 1458;
|
||||
const ROOT_ENTRY_LIMIT: usize = 1459;
|
||||
const ISSUES_ENTRY_LIMIT: usize = 2669;
|
||||
|
||||
fn check_entries(path: &Path, bad: &mut bool) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user