Merge from rustc
This commit is contained in:
commit
b122fa6d6a
194 changed files with 2663 additions and 767 deletions
3
.mailmap
3
.mailmap
|
|
@ -458,6 +458,7 @@ Philipp Matthias Schäfer <philipp.matthias.schaefer@posteo.de>
|
|||
phosphorus <steepout@qq.com>
|
||||
Pierre Krieger <pierre.krieger1708@gmail.com>
|
||||
pierwill <pierwill@users.noreply.github.com> <19642016+pierwill@users.noreply.github.com>
|
||||
Pietro Albini <pietro@pietroalbini.org> <pietro@pietroalbini.io> <pietro.albini@ferrous-systems.com>
|
||||
Pradyumna Rahul <prkinformed@gmail.com>
|
||||
Przemysław Wesołek <jest@go.art.pl> Przemek Wesołek <jest@go.art.pl>
|
||||
r00ster <r00ster91@protonmail.com>
|
||||
|
|
@ -495,6 +496,8 @@ Ryan Wiedemann <Ryan1729@gmail.com>
|
|||
S Pradeep Kumar <gohanpra@gmail.com>
|
||||
Sam Radhakrishnan <sk09idm@gmail.com>
|
||||
Samuel Tardieu <sam@rfc1149.net>
|
||||
Santiago Pastorino <spastorino@gmail.com>
|
||||
Santiago Pastorino <spastorino@gmail.com> <santiago@wyeworks.com>
|
||||
Scott McMurray <scottmcm@users.noreply.github.com>
|
||||
Scott Olson <scott@solson.me> Scott Olson <scott@scott-olson.org>
|
||||
Sean Gillespie <sean.william.g@gmail.com> swgillespie <sean.william.g@gmail.com>
|
||||
|
|
|
|||
|
|
@ -457,7 +457,7 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> {
|
|||
|
||||
// Don't hash unless necessary, because it's expensive.
|
||||
let opt_hir_hash =
|
||||
if tcx.sess.needs_crate_hash() { Some(compute_hir_hash(tcx, &owners)) } else { None };
|
||||
if tcx.needs_crate_hash() { Some(compute_hir_hash(tcx, &owners)) } else { None };
|
||||
hir::Crate { owners, opt_hir_hash }
|
||||
}
|
||||
|
||||
|
|
@ -648,7 +648,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let bodies = SortedMap::from_presorted_elements(bodies);
|
||||
|
||||
// Don't hash unless necessary, because it's expensive.
|
||||
let (opt_hash_including_bodies, attrs_hash) = if self.tcx.sess.needs_crate_hash() {
|
||||
let (opt_hash_including_bodies, attrs_hash) = if self.tcx.needs_crate_hash() {
|
||||
self.tcx.with_stable_hashing_context(|mut hcx| {
|
||||
let mut stable_hasher = StableHasher::new();
|
||||
hcx.with_hir_bodies(node.def_id(), &bodies, |hcx| {
|
||||
|
|
|
|||
|
|
@ -239,5 +239,10 @@ ast_passes_visibility_not_permitted =
|
|||
.individual_impl_items = place qualifiers on individual impl items instead
|
||||
.individual_foreign_items = place qualifiers on individual foreign items instead
|
||||
|
||||
ast_passes_where_after_type_alias = where clauses are not allowed after the type for type aliases
|
||||
ast_passes_where_clause_after_type_alias = where clauses are not allowed after the type for type aliases
|
||||
.note = see issue #112792 <https://github.com/rust-lang/rust/issues/112792> for more information
|
||||
.help = add `#![feature(lazy_type_alias)]` to the crate attributes to enable
|
||||
|
||||
ast_passes_where_clause_before_type_alias = where clauses are not allowed before the type for type aliases
|
||||
.note = see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
|
||||
.suggestion = move it to the end of the type declaration
|
||||
|
|
|
|||
|
|
@ -136,40 +136,42 @@ impl<'a> AstValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_gat_where(
|
||||
fn check_type_alias_where_clause_location(
|
||||
&mut self,
|
||||
id: NodeId,
|
||||
before_predicates: &[WherePredicate],
|
||||
where_clauses: (ast::TyAliasWhereClause, ast::TyAliasWhereClause),
|
||||
) {
|
||||
if !before_predicates.is_empty() {
|
||||
let mut state = State::new();
|
||||
if !where_clauses.1.0 {
|
||||
state.space();
|
||||
state.word_space("where");
|
||||
} else {
|
||||
ty_alias: &TyAlias,
|
||||
) -> Result<(), errors::WhereClauseBeforeTypeAlias> {
|
||||
let before_predicates =
|
||||
ty_alias.generics.where_clause.predicates.split_at(ty_alias.where_predicates_split).0;
|
||||
|
||||
if ty_alias.ty.is_none() || before_predicates.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut state = State::new();
|
||||
if !ty_alias.where_clauses.1.0 {
|
||||
state.space();
|
||||
state.word_space("where");
|
||||
} else {
|
||||
state.word_space(",");
|
||||
}
|
||||
let mut first = true;
|
||||
for p in before_predicates {
|
||||
if !first {
|
||||
state.word_space(",");
|
||||
}
|
||||
let mut first = true;
|
||||
for p in before_predicates.iter() {
|
||||
if !first {
|
||||
state.word_space(",");
|
||||
}
|
||||
first = false;
|
||||
state.print_where_predicate(p);
|
||||
}
|
||||
let suggestion = state.s.eof();
|
||||
self.lint_buffer.buffer_lint_with_diagnostic(
|
||||
DEPRECATED_WHERE_CLAUSE_LOCATION,
|
||||
id,
|
||||
where_clauses.0.1,
|
||||
fluent::ast_passes_deprecated_where_clause_location,
|
||||
BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
|
||||
where_clauses.1.1.shrink_to_hi(),
|
||||
suggestion,
|
||||
),
|
||||
);
|
||||
first = false;
|
||||
state.print_where_predicate(p);
|
||||
}
|
||||
|
||||
let span = ty_alias.where_clauses.0.1;
|
||||
Err(errors::WhereClauseBeforeTypeAlias {
|
||||
span,
|
||||
sugg: errors::WhereClauseBeforeTypeAliasSugg {
|
||||
left: span,
|
||||
snippet: state.s.eof(),
|
||||
right: ty_alias.where_clauses.1.1.shrink_to_hi(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
|
||||
|
|
@ -1009,7 +1011,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
replace_span: self.ending_semi_or_hi(item.span),
|
||||
});
|
||||
}
|
||||
ItemKind::TyAlias(box TyAlias { defaultness, where_clauses, bounds, ty, .. }) => {
|
||||
ItemKind::TyAlias(
|
||||
ty_alias @ box TyAlias { defaultness, bounds, where_clauses, ty, .. },
|
||||
) => {
|
||||
self.check_defaultness(item.span, *defaultness);
|
||||
if ty.is_none() {
|
||||
self.session.emit_err(errors::TyAliasWithoutBody {
|
||||
|
|
@ -1018,9 +1022,16 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
});
|
||||
}
|
||||
self.check_type_no_bounds(bounds, "this context");
|
||||
if where_clauses.1.0 {
|
||||
self.err_handler()
|
||||
.emit_err(errors::WhereAfterTypeAlias { span: where_clauses.1.1 });
|
||||
|
||||
if self.session.features_untracked().lazy_type_alias {
|
||||
if let Err(err) = self.check_type_alias_where_clause_location(ty_alias) {
|
||||
self.err_handler().emit_err(err);
|
||||
}
|
||||
} else if where_clauses.1.0 {
|
||||
self.err_handler().emit_err(errors::WhereClauseAfterTypeAlias {
|
||||
span: where_clauses.1.1,
|
||||
help: self.session.is_nightly_build().then_some(()),
|
||||
});
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
|
@ -1313,18 +1324,18 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
if let AssocItemKind::Type(box TyAlias {
|
||||
generics,
|
||||
where_clauses,
|
||||
where_predicates_split,
|
||||
ty: Some(_),
|
||||
..
|
||||
}) = &item.kind
|
||||
if let AssocItemKind::Type(ty_alias) = &item.kind
|
||||
&& let Err(err) = self.check_type_alias_where_clause_location(ty_alias)
|
||||
{
|
||||
self.check_gat_where(
|
||||
self.lint_buffer.buffer_lint_with_diagnostic(
|
||||
DEPRECATED_WHERE_CLAUSE_LOCATION,
|
||||
item.id,
|
||||
generics.where_clause.predicates.split_at(*where_predicates_split).0,
|
||||
*where_clauses,
|
||||
err.span,
|
||||
fluent::ast_passes_deprecated_where_clause_location,
|
||||
BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
|
||||
err.sugg.right,
|
||||
err.sugg.snippet,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -496,11 +496,37 @@ pub struct FieldlessUnion {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_where_after_type_alias)]
|
||||
#[diag(ast_passes_where_clause_after_type_alias)]
|
||||
#[note]
|
||||
pub struct WhereAfterTypeAlias {
|
||||
pub struct WhereClauseAfterTypeAlias {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[help]
|
||||
pub help: Option<()>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_where_clause_before_type_alias)]
|
||||
#[note]
|
||||
pub struct WhereClauseBeforeTypeAlias {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub sugg: WhereClauseBeforeTypeAliasSugg,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
ast_passes_suggestion,
|
||||
applicability = "machine-applicable",
|
||||
style = "verbose"
|
||||
)]
|
||||
pub struct WhereClauseBeforeTypeAliasSugg {
|
||||
#[suggestion_part(code = "")]
|
||||
pub left: Span,
|
||||
pub snippet: String,
|
||||
#[suggestion_part(code = "{snippet}")]
|
||||
pub right: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token;
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::{token, StmtKind};
|
||||
use rustc_ast::{
|
||||
Expr, ExprKind, FormatAlignment, FormatArgPosition, FormatArgPositionKind, FormatArgs,
|
||||
FormatArgsPiece, FormatArgument, FormatArgumentKind, FormatArguments, FormatCount,
|
||||
|
|
@ -163,7 +163,7 @@ fn make_format_args(
|
|||
|
||||
let MacroInput { fmtstr: efmt, mut args, is_direct_literal } = input;
|
||||
|
||||
let (fmt_str, fmt_style, fmt_span) = match expr_to_spanned_string(ecx, efmt, msg) {
|
||||
let (fmt_str, fmt_style, fmt_span) = match expr_to_spanned_string(ecx, efmt.clone(), msg) {
|
||||
Ok(mut fmt) if append_newline => {
|
||||
fmt.0 = Symbol::intern(&format!("{}\n", fmt.0));
|
||||
fmt
|
||||
|
|
@ -171,17 +171,33 @@ fn make_format_args(
|
|||
Ok(fmt) => fmt,
|
||||
Err(err) => {
|
||||
if let Some((mut err, suggested)) = err {
|
||||
let sugg_fmt = match args.explicit_args().len() {
|
||||
0 => "{}".to_string(),
|
||||
_ => format!("{}{{}}", "{} ".repeat(args.explicit_args().len())),
|
||||
};
|
||||
if !suggested {
|
||||
err.span_suggestion(
|
||||
unexpanded_fmt_span.shrink_to_lo(),
|
||||
"you might be missing a string literal to format with",
|
||||
format!("\"{sugg_fmt}\", "),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
if let ExprKind::Block(block, None) = &efmt.kind
|
||||
&& block.stmts.len() == 1
|
||||
&& let StmtKind::Expr(expr) = &block.stmts[0].kind
|
||||
&& let ExprKind::Path(None, path) = &expr.kind
|
||||
&& path.is_potential_trivial_const_arg()
|
||||
{
|
||||
err.multipart_suggestion(
|
||||
"quote your inlined format argument to use as string literal",
|
||||
vec![
|
||||
(unexpanded_fmt_span.shrink_to_hi(), "\"".to_string()),
|
||||
(unexpanded_fmt_span.shrink_to_lo(), "\"".to_string()),
|
||||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
let sugg_fmt = match args.explicit_args().len() {
|
||||
0 => "{}".to_string(),
|
||||
_ => format!("{}{{}}", "{} ".repeat(args.explicit_args().len())),
|
||||
};
|
||||
err.span_suggestion(
|
||||
unexpanded_fmt_span.shrink_to_lo(),
|
||||
"you might be missing a string literal to format with",
|
||||
format!("\"{sugg_fmt}\", "),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
|
|||
tcx.sess.fatal("JIT mode doesn't work with `cargo check`");
|
||||
}
|
||||
|
||||
if !tcx.sess.crate_types().contains(&rustc_session::config::CrateType::Executable) {
|
||||
if !tcx.crate_types().contains(&rustc_session::config::CrateType::Executable) {
|
||||
tcx.sess.fatal("can't jit non-executable crate");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ pub unsafe fn create_module<'ll>(
|
|||
// PIE is potentially more effective than PIC, but can only be used in executables.
|
||||
// If all our outputs are executables, then we can relax PIC to PIE.
|
||||
if reloc_model == RelocModel::Pie
|
||||
|| sess.crate_types().iter().all(|ty| *ty == CrateType::Executable)
|
||||
|| tcx.crate_types().iter().all(|ty| *ty == CrateType::Executable)
|
||||
{
|
||||
llvm::LLVMRustSetModulePIELevel(llmod);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,8 +12,7 @@ use rustc_middle::bug;
|
|||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use rustc_middle::mir::coverage::CodeRegion;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
||||
use std::ffi::CString;
|
||||
use rustc_span::Symbol;
|
||||
|
||||
/// Generates and exports the Coverage Map.
|
||||
///
|
||||
|
|
@ -89,7 +88,10 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
|
|||
|
||||
// Encode all filenames referenced by counters/expressions in this module
|
||||
let filenames_buffer = llvm::build_byte_buffer(|filenames_buffer| {
|
||||
coverageinfo::write_filenames_section_to_buffer(&mapgen.filenames, filenames_buffer);
|
||||
coverageinfo::write_filenames_section_to_buffer(
|
||||
mapgen.filenames.iter().map(Symbol::as_str),
|
||||
filenames_buffer,
|
||||
);
|
||||
});
|
||||
|
||||
let filenames_size = filenames_buffer.len();
|
||||
|
|
@ -117,7 +119,7 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
|
|||
}
|
||||
|
||||
struct CoverageMapGenerator {
|
||||
filenames: FxIndexSet<CString>,
|
||||
filenames: FxIndexSet<Symbol>,
|
||||
}
|
||||
|
||||
impl CoverageMapGenerator {
|
||||
|
|
@ -128,11 +130,10 @@ impl CoverageMapGenerator {
|
|||
// Since rustc generates coverage maps with relative paths, the
|
||||
// compilation directory can be combined with the relative paths
|
||||
// to get absolute paths, if needed.
|
||||
let working_dir =
|
||||
tcx.sess.opts.working_dir.remapped_path_if_available().to_string_lossy().to_string();
|
||||
let c_filename =
|
||||
CString::new(working_dir).expect("null error converting filename to C string");
|
||||
filenames.insert(c_filename);
|
||||
let working_dir = Symbol::intern(
|
||||
&tcx.sess.opts.working_dir.remapped_path_if_available().to_string_lossy(),
|
||||
);
|
||||
filenames.insert(working_dir);
|
||||
Self { filenames }
|
||||
}
|
||||
|
||||
|
|
@ -170,10 +171,8 @@ impl CoverageMapGenerator {
|
|||
current_file_id += 1;
|
||||
}
|
||||
current_file_name = Some(file_name);
|
||||
let c_filename = CString::new(file_name.to_string())
|
||||
.expect("null error converting filename to C string");
|
||||
debug!(" file_id: {} = '{:?}'", current_file_id, c_filename);
|
||||
let (filenames_index, _) = self.filenames.insert_full(c_filename);
|
||||
debug!(" file_id: {} = '{:?}'", current_file_id, file_name);
|
||||
let (filenames_index, _) = self.filenames.insert_full(file_name);
|
||||
virtual_file_mapping.push(filenames_index as u32);
|
||||
}
|
||||
debug!("Adding counter {:?} to map for {:?}", counter, region);
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ use rustc_middle::ty::Instance;
|
|||
use rustc_middle::ty::Ty;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::ffi::CString;
|
||||
|
||||
pub(crate) mod ffi;
|
||||
pub(crate) mod map_data;
|
||||
|
|
@ -332,21 +331,32 @@ fn create_pgo_func_name_var<'ll, 'tcx>(
|
|||
cx: &CodegenCx<'ll, 'tcx>,
|
||||
instance: Instance<'tcx>,
|
||||
) -> &'ll llvm::Value {
|
||||
let mangled_fn_name = CString::new(cx.tcx.symbol_name(instance).name)
|
||||
.expect("error converting function name to C string");
|
||||
let mangled_fn_name: &str = cx.tcx.symbol_name(instance).name;
|
||||
let llfn = cx.get_fn(instance);
|
||||
unsafe { llvm::LLVMRustCoverageCreatePGOFuncNameVar(llfn, mangled_fn_name.as_ptr()) }
|
||||
unsafe {
|
||||
llvm::LLVMRustCoverageCreatePGOFuncNameVar(
|
||||
llfn,
|
||||
mangled_fn_name.as_ptr().cast(),
|
||||
mangled_fn_name.len(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn write_filenames_section_to_buffer<'a>(
|
||||
filenames: impl IntoIterator<Item = &'a CString>,
|
||||
filenames: impl IntoIterator<Item = &'a str>,
|
||||
buffer: &RustString,
|
||||
) {
|
||||
let c_str_vec = filenames.into_iter().map(|cstring| cstring.as_ptr()).collect::<Vec<_>>();
|
||||
let (pointers, lengths) = filenames
|
||||
.into_iter()
|
||||
.map(|s: &str| (s.as_ptr().cast(), s.len()))
|
||||
.unzip::<_, _, Vec<_>, Vec<_>>();
|
||||
|
||||
unsafe {
|
||||
llvm::LLVMRustCoverageWriteFilenamesSectionToBuffer(
|
||||
c_str_vec.as_ptr(),
|
||||
c_str_vec.len(),
|
||||
pointers.as_ptr(),
|
||||
pointers.len(),
|
||||
lengths.as_ptr(),
|
||||
lengths.len(),
|
||||
buffer,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ pub fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool {
|
|||
// each rlib could produce a different set of visualizers that would be embedded
|
||||
// in the `.debug_gdb_scripts` section. For that reason, we make sure that the
|
||||
// section is only emitted for leaf crates.
|
||||
let embed_visualizers = cx.sess().crate_types().iter().any(|&crate_type| match crate_type {
|
||||
let embed_visualizers = cx.tcx.crate_types().iter().any(|&crate_type| match crate_type {
|
||||
CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::Staticlib => {
|
||||
// These are crate types for which we will embed pretty printers since they
|
||||
// are treated as leaf crates.
|
||||
|
|
|
|||
|
|
@ -1707,6 +1707,8 @@ extern "C" {
|
|||
pub fn LLVMRustCoverageWriteFilenamesSectionToBuffer(
|
||||
Filenames: *const *const c_char,
|
||||
FilenamesLen: size_t,
|
||||
Lengths: *const size_t,
|
||||
LengthsLen: size_t,
|
||||
BufferOut: &RustString,
|
||||
);
|
||||
|
||||
|
|
@ -1721,7 +1723,11 @@ extern "C" {
|
|||
BufferOut: &RustString,
|
||||
);
|
||||
|
||||
pub fn LLVMRustCoverageCreatePGOFuncNameVar(F: &Value, FuncName: *const c_char) -> &Value;
|
||||
pub fn LLVMRustCoverageCreatePGOFuncNameVar(
|
||||
F: &Value,
|
||||
FuncName: *const c_char,
|
||||
FuncNameLen: size_t,
|
||||
) -> &Value;
|
||||
pub fn LLVMRustCoverageHashByteArray(Bytes: *const c_char, NumBytes: size_t) -> u64;
|
||||
|
||||
#[allow(improper_ctypes)]
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ impl CodegenCx<'_, '_> {
|
|||
}
|
||||
|
||||
// Symbols from executables can't really be imported any further.
|
||||
let all_exe = self.tcx.sess.crate_types().iter().all(|ty| *ty == CrateType::Executable);
|
||||
let all_exe = self.tcx.crate_types().iter().all(|ty| *ty == CrateType::Executable);
|
||||
let is_declaration_for_linker =
|
||||
is_declaration || linkage == llvm::Linkage::AvailableExternallyLinkage;
|
||||
if all_exe && !is_declaration_for_linker {
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ pub fn link_binary<'a>(
|
|||
let _timer = sess.timer("link_binary");
|
||||
let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata);
|
||||
let mut tempfiles_for_stdout_output: Vec<PathBuf> = Vec::new();
|
||||
for &crate_type in sess.crate_types().iter() {
|
||||
for &crate_type in &codegen_results.crate_info.crate_types {
|
||||
// Ignore executable crates if we have -Z no-codegen, as they will error.
|
||||
if (sess.opts.unstable_opts.no_codegen || !sess.opts.output_types.should_codegen())
|
||||
&& !output_metadata
|
||||
|
|
|
|||
|
|
@ -1703,7 +1703,7 @@ fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<String> {
|
|||
return Vec::new();
|
||||
}
|
||||
|
||||
let stable_crate_id = tcx.sess.local_stable_crate_id();
|
||||
let stable_crate_id = tcx.stable_crate_id(LOCAL_CRATE);
|
||||
let proc_macro_decls_name = tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id);
|
||||
let metadata_symbol_name = exported_symbols::metadata_symbol_name(tcx);
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use rustc_session::config::{CrateType, OomStrategy};
|
|||
use rustc_target::spec::SanitizerSet;
|
||||
|
||||
pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel {
|
||||
crates_export_threshold(&tcx.sess.crate_types())
|
||||
crates_export_threshold(tcx.crate_types())
|
||||
}
|
||||
|
||||
fn crate_export_threshold(crate_type: CrateType) -> SymbolExportLevel {
|
||||
|
|
@ -290,8 +290,8 @@ fn exported_symbols_provider_local(
|
|||
}));
|
||||
}
|
||||
|
||||
if tcx.sess.crate_types().contains(&CrateType::Dylib)
|
||||
|| tcx.sess.crate_types().contains(&CrateType::ProcMacro)
|
||||
if tcx.crate_types().contains(&CrateType::Dylib)
|
||||
|| tcx.crate_types().contains(&CrateType::ProcMacro)
|
||||
{
|
||||
let symbol_name = metadata_symbol_name(tcx);
|
||||
let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name));
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ pub struct ModuleConfig {
|
|||
impl ModuleConfig {
|
||||
fn new(
|
||||
kind: ModuleKind,
|
||||
sess: &Session,
|
||||
tcx: TyCtxt<'_>,
|
||||
no_builtins: bool,
|
||||
is_compiler_builtins: bool,
|
||||
) -> ModuleConfig {
|
||||
|
|
@ -135,6 +135,7 @@ impl ModuleConfig {
|
|||
};
|
||||
}
|
||||
|
||||
let sess = tcx.sess;
|
||||
let opt_level_and_size = if_regular!(Some(sess.opts.optimize), None);
|
||||
|
||||
let save_temps = sess.opts.cg.save_temps;
|
||||
|
|
@ -166,7 +167,7 @@ impl ModuleConfig {
|
|||
// `#![no_builtins]` is assumed to not participate in LTO and
|
||||
// instead goes on to generate object code.
|
||||
EmitObj::Bitcode
|
||||
} else if need_bitcode_in_object(sess) {
|
||||
} else if need_bitcode_in_object(tcx) {
|
||||
EmitObj::ObjectCode(BitcodeSection::Full)
|
||||
} else {
|
||||
EmitObj::ObjectCode(BitcodeSection::None)
|
||||
|
|
@ -414,9 +415,10 @@ pub struct CompiledModules {
|
|||
pub allocator_module: Option<CompiledModule>,
|
||||
}
|
||||
|
||||
fn need_bitcode_in_object(sess: &Session) -> bool {
|
||||
fn need_bitcode_in_object(tcx: TyCtxt<'_>) -> bool {
|
||||
let sess = tcx.sess;
|
||||
let requested_for_rlib = sess.opts.cg.embed_bitcode
|
||||
&& sess.crate_types().contains(&CrateType::Rlib)
|
||||
&& tcx.crate_types().contains(&CrateType::Rlib)
|
||||
&& sess.opts.output_types.contains_key(&OutputType::Exe);
|
||||
let forced_by_target = sess.target.forces_embed_bitcode;
|
||||
requested_for_rlib || forced_by_target
|
||||
|
|
@ -450,11 +452,11 @@ pub fn start_async_codegen<B: ExtraBackendMethods>(
|
|||
let crate_info = CrateInfo::new(tcx, target_cpu);
|
||||
|
||||
let regular_config =
|
||||
ModuleConfig::new(ModuleKind::Regular, sess, no_builtins, is_compiler_builtins);
|
||||
ModuleConfig::new(ModuleKind::Regular, tcx, no_builtins, is_compiler_builtins);
|
||||
let metadata_config =
|
||||
ModuleConfig::new(ModuleKind::Metadata, sess, no_builtins, is_compiler_builtins);
|
||||
ModuleConfig::new(ModuleKind::Metadata, tcx, no_builtins, is_compiler_builtins);
|
||||
let allocator_config =
|
||||
ModuleConfig::new(ModuleKind::Allocator, sess, no_builtins, is_compiler_builtins);
|
||||
ModuleConfig::new(ModuleKind::Allocator, tcx, no_builtins, is_compiler_builtins);
|
||||
|
||||
let (shared_emitter, shared_emitter_main) = SharedEmitter::new();
|
||||
let (codegen_worker_send, codegen_worker_receive) = channel();
|
||||
|
|
@ -1092,7 +1094,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
};
|
||||
|
||||
let cgcx = CodegenContext::<B> {
|
||||
crate_types: sess.crate_types().to_vec(),
|
||||
crate_types: tcx.crate_types().to_vec(),
|
||||
each_linked_rlib_for_lto,
|
||||
lto: sess.lto(),
|
||||
fewer_names: sess.fewer_names(),
|
||||
|
|
@ -2063,7 +2065,7 @@ fn msvc_imps_needed(tcx: TyCtxt<'_>) -> bool {
|
|||
);
|
||||
|
||||
tcx.sess.target.is_like_windows &&
|
||||
tcx.sess.crate_types().iter().any(|ct| *ct == CrateType::Rlib) &&
|
||||
tcx.crate_types().iter().any(|ct| *ct == CrateType::Rlib) &&
|
||||
// ThinLTO can't handle this workaround in all cases, so we don't
|
||||
// emit the `__imp_` symbols. Instead we make them unnecessary by disallowing
|
||||
// dynamic linking when linker plugin LTO is enabled.
|
||||
|
|
|
|||
|
|
@ -779,18 +779,13 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
|
|||
|
||||
impl CrateInfo {
|
||||
pub fn new(tcx: TyCtxt<'_>, target_cpu: String) -> CrateInfo {
|
||||
let exported_symbols = tcx
|
||||
.sess
|
||||
.crate_types()
|
||||
let crate_types = tcx.crate_types().to_vec();
|
||||
let exported_symbols = crate_types
|
||||
.iter()
|
||||
.map(|&c| (c, crate::back::linker::exported_symbols(tcx, c)))
|
||||
.collect();
|
||||
let linked_symbols = tcx
|
||||
.sess
|
||||
.crate_types()
|
||||
.iter()
|
||||
.map(|&c| (c, crate::back::linker::linked_symbols(tcx, c)))
|
||||
.collect();
|
||||
let linked_symbols =
|
||||
crate_types.iter().map(|&c| (c, crate::back::linker::linked_symbols(tcx, c))).collect();
|
||||
let local_crate_name = tcx.crate_name(LOCAL_CRATE);
|
||||
let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
|
||||
let subsystem = attr::first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem);
|
||||
|
|
@ -829,6 +824,7 @@ impl CrateInfo {
|
|||
|
||||
let mut info = CrateInfo {
|
||||
target_cpu,
|
||||
crate_types,
|
||||
exported_symbols,
|
||||
linked_symbols,
|
||||
local_crate_name,
|
||||
|
|
@ -916,7 +912,7 @@ impl CrateInfo {
|
|||
});
|
||||
}
|
||||
|
||||
let embed_visualizers = tcx.sess.crate_types().iter().any(|&crate_type| match crate_type {
|
||||
let embed_visualizers = tcx.crate_types().iter().any(|&crate_type| match crate_type {
|
||||
CrateType::Executable | CrateType::Dylib | CrateType::Cdylib => {
|
||||
// These are crate types for which we invoke the linker and can embed
|
||||
// NatVis visualizers.
|
||||
|
|
@ -1013,7 +1009,7 @@ fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> CguR
|
|||
match compute_per_cgu_lto_type(
|
||||
&tcx.sess.lto(),
|
||||
&tcx.sess.opts,
|
||||
&tcx.sess.crate_types(),
|
||||
tcx.crate_types(),
|
||||
ModuleKind::Regular,
|
||||
) {
|
||||
ComputedLtoType::No => CguReuse::PostLto,
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ impl From<&cstore::NativeLib> for NativeLib {
|
|||
#[derive(Debug, Encodable, Decodable)]
|
||||
pub struct CrateInfo {
|
||||
pub target_cpu: String,
|
||||
pub crate_types: Vec<CrateType>,
|
||||
pub exported_symbols: FxHashMap<CrateType, Vec<String>>,
|
||||
pub linked_symbols: FxHashMap<CrateType, Vec<(String, SymbolExportKind)>>,
|
||||
pub local_crate_name: Symbol,
|
||||
|
|
|
|||
|
|
@ -653,8 +653,6 @@ fn show_md_content_with_pager(content: &str, color: ColorConfig) {
|
|||
pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Compilation {
|
||||
if sess.opts.unstable_opts.link_only {
|
||||
if let Input::File(file) = &sess.io.input {
|
||||
// FIXME: #![crate_type] and #![crate_name] support not implemented yet
|
||||
sess.init_crate_types(collect_crate_types(sess, &[]));
|
||||
let outputs = compiler.build_output_filenames(sess, &[]);
|
||||
let rlink_data = fs::read(file).unwrap_or_else(|err| {
|
||||
sess.emit_fatal(RlinkUnableToRead { err });
|
||||
|
|
|
|||
|
|
@ -1843,7 +1843,7 @@ impl Expr<'_> {
|
|||
.iter()
|
||||
.map(|field| field.expr)
|
||||
.chain(init.into_iter())
|
||||
.all(|e| e.can_have_side_effects()),
|
||||
.any(|e| e.can_have_side_effects()),
|
||||
|
||||
ExprKind::Array(args)
|
||||
| ExprKind::Tup(args)
|
||||
|
|
@ -1857,7 +1857,7 @@ impl Expr<'_> {
|
|||
..
|
||||
},
|
||||
args,
|
||||
) => args.iter().all(|arg| arg.can_have_side_effects()),
|
||||
) => args.iter().any(|arg| arg.can_have_side_effects()),
|
||||
ExprKind::If(..)
|
||||
| ExprKind::Match(..)
|
||||
| ExprKind::MethodCall(..)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use super::potentially_plural_count;
|
||||
use crate::errors::LifetimesOrBoundsMismatchOnTrait;
|
||||
use hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
|
||||
use rustc_errors::{
|
||||
pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed, MultiSpan,
|
||||
};
|
||||
|
|
@ -265,7 +265,6 @@ fn compare_method_predicate_entailment<'tcx>(
|
|||
infer::HigherRankedType,
|
||||
tcx.fn_sig(impl_m.def_id).instantiate_identity(),
|
||||
);
|
||||
let unnormalized_impl_fty = Ty::new_fn_ptr(tcx, ty::Binder::dummy(unnormalized_impl_sig));
|
||||
|
||||
let norm_cause = ObligationCause::misc(impl_m_span, impl_m_def_id);
|
||||
let impl_sig = ocx.normalize(&norm_cause, param_env, unnormalized_impl_sig);
|
||||
|
|
@ -309,16 +308,44 @@ fn compare_method_predicate_entailment<'tcx>(
|
|||
}
|
||||
|
||||
if check_implied_wf == CheckImpliedWfMode::Check && !(impl_sig, trait_sig).references_error() {
|
||||
// We need to check that the impl's args are well-formed given
|
||||
// the hybrid param-env (impl + trait method where-clauses).
|
||||
ocx.register_obligation(traits::Obligation::new(
|
||||
infcx.tcx,
|
||||
ObligationCause::dummy(),
|
||||
param_env,
|
||||
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(
|
||||
unnormalized_impl_fty.into(),
|
||||
))),
|
||||
));
|
||||
// See #108544. Annoying, we can end up in cases where, because of winnowing,
|
||||
// we pick param env candidates over a more general impl, leading to more
|
||||
// stricter lifetime requirements than we would otherwise need. This can
|
||||
// trigger the lint. Instead, let's only consider type outlives and
|
||||
// region outlives obligations.
|
||||
//
|
||||
// FIXME(-Ztrait-solver=next): Try removing this hack again once
|
||||
// the new solver is stable.
|
||||
let mut wf_args: smallvec::SmallVec<[_; 4]> =
|
||||
unnormalized_impl_sig.inputs_and_output.iter().map(|ty| ty.into()).collect();
|
||||
// Annoyingly, asking for the WF predicates of an array (with an unevaluated const (only?))
|
||||
// will give back the well-formed predicate of the same array.
|
||||
let mut wf_args_seen: FxHashSet<_> = wf_args.iter().copied().collect();
|
||||
while let Some(arg) = wf_args.pop() {
|
||||
let Some(obligations) = rustc_trait_selection::traits::wf::obligations(
|
||||
infcx,
|
||||
param_env,
|
||||
impl_m_def_id,
|
||||
0,
|
||||
arg,
|
||||
impl_m_span,
|
||||
) else {
|
||||
continue;
|
||||
};
|
||||
for obligation in obligations {
|
||||
match obligation.predicate.kind().skip_binder() {
|
||||
ty::PredicateKind::Clause(
|
||||
ty::ClauseKind::RegionOutlives(..) | ty::ClauseKind::TypeOutlives(..),
|
||||
) => ocx.register_obligation(obligation),
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
|
||||
if wf_args_seen.insert(arg) {
|
||||
wf_args.push(arg)
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check that all obligations are satisfied by the implementation's
|
||||
|
|
|
|||
|
|
@ -645,18 +645,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.typeck_results.borrow().qpath_res(qpath, callee_expr.hir_id)
|
||||
}
|
||||
hir::ExprKind::Call(ref inner_callee, _) => {
|
||||
// If the call spans more than one line and the callee kind is
|
||||
// itself another `ExprCall`, that's a clue that we might just be
|
||||
// missing a semicolon (Issue #51055)
|
||||
let call_is_multiline = self.tcx.sess.source_map().is_multiline(call_expr.span);
|
||||
if call_is_multiline {
|
||||
err.span_suggestion(
|
||||
callee_expr.span.shrink_to_hi(),
|
||||
"consider using a semicolon here",
|
||||
";",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
if let hir::ExprKind::Path(ref inner_qpath) = inner_callee.kind {
|
||||
inner_callee_path = Some(inner_qpath);
|
||||
self.typeck_results.borrow().qpath_res(inner_qpath, inner_callee.hir_id)
|
||||
|
|
@ -668,6 +656,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
};
|
||||
|
||||
if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) {
|
||||
// If the call spans more than one line and the callee kind is
|
||||
// itself another `ExprCall`, that's a clue that we might just be
|
||||
// missing a semicolon (#51055, #106515).
|
||||
let call_is_multiline = self
|
||||
.tcx
|
||||
.sess
|
||||
.source_map()
|
||||
.is_multiline(call_expr.span.with_lo(callee_expr.span.hi()))
|
||||
&& call_expr.span.ctxt() == callee_expr.span.ctxt();
|
||||
if call_is_multiline {
|
||||
err.span_suggestion(
|
||||
callee_expr.span.shrink_to_hi(),
|
||||
"consider using a semicolon here to finish the statement",
|
||||
";",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
if let Some((maybe_def, output_ty, _)) = self.extract_callable_info(callee_ty)
|
||||
&& !self.type_is_sized_modulo_regions(self.param_env, output_ty)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -510,9 +510,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
success(adjustments, ty, obligations)
|
||||
}
|
||||
|
||||
// &[T; n] or &mut [T; n] -> &[T]
|
||||
// or &mut [T; n] -> &mut [T]
|
||||
// or &Concrete -> &Trait, etc.
|
||||
/// Performs [unsized coercion] by emulating a fulfillment loop on a
|
||||
/// `CoerceUnsized` goal until all `CoerceUnsized` and `Unsize` goals
|
||||
/// are successfully selected.
|
||||
///
|
||||
/// [unsized coercion](https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions)
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn coerce_unsized(&self, mut source: Ty<'tcx>, mut target: Ty<'tcx>) -> CoerceResult<'tcx> {
|
||||
source = self.shallow_resolve(source);
|
||||
|
|
@ -1039,6 +1041,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
/// Returns false if the coercion creates any obligations that result in
|
||||
/// errors.
|
||||
pub fn can_coerce(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> bool {
|
||||
// FIXME(-Ztrait-solver=next): We need to structurally resolve both types here.
|
||||
let source = self.resolve_vars_with_obligations(expr_ty);
|
||||
debug!("coercion::can_with_predicates({:?} -> {:?})", source, target);
|
||||
|
||||
|
|
|
|||
|
|
@ -260,7 +260,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
));
|
||||
let expr = expr.peel_drop_temps();
|
||||
let cause = self.misc(expr.span);
|
||||
let expr_ty = self.resolve_vars_with_obligations(checked_ty);
|
||||
let expr_ty = self.resolve_vars_if_possible(checked_ty);
|
||||
let mut err = self.err_ctxt().report_mismatched_types(&cause, expected, expr_ty, e);
|
||||
|
||||
let is_insufficiently_polymorphic =
|
||||
|
|
|
|||
|
|
@ -85,16 +85,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
/// to get more type information.
|
||||
// FIXME(-Ztrait-solver=next): A lot of the calls to this method should
|
||||
// probably be `try_structurally_resolve_type` or `structurally_resolve_type` instead.
|
||||
pub(in super::super) fn resolve_vars_with_obligations(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
self.resolve_vars_with_obligations_and_mutate_fulfillment(ty, |_| {})
|
||||
}
|
||||
|
||||
#[instrument(skip(self, mutate_fulfillment_errors), level = "debug", ret)]
|
||||
pub(in super::super) fn resolve_vars_with_obligations_and_mutate_fulfillment(
|
||||
&self,
|
||||
mut ty: Ty<'tcx>,
|
||||
mutate_fulfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>),
|
||||
) -> Ty<'tcx> {
|
||||
#[instrument(skip(self), level = "debug", ret)]
|
||||
pub(in super::super) fn resolve_vars_with_obligations(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
// No Infer()? Nothing needs doing.
|
||||
if !ty.has_non_region_infer() {
|
||||
debug!("no inference var, nothing needs doing");
|
||||
|
|
@ -112,7 +104,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// possible. This can help substantially when there are
|
||||
// indirect dependencies that don't seem worth tracking
|
||||
// precisely.
|
||||
self.select_obligations_where_possible(mutate_fulfillment_errors);
|
||||
self.select_obligations_where_possible(|_| {});
|
||||
self.resolve_vars_if_possible(ty)
|
||||
}
|
||||
|
||||
|
|
@ -626,8 +618,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
match *self_ty.kind() {
|
||||
ty::Infer(ty::TyVar(found_vid)) => {
|
||||
// FIXME: consider using `sub_root_var` here so we
|
||||
// can see through subtyping.
|
||||
let found_vid = self.root_var(found_vid);
|
||||
debug!("self_type_matches_expected_vid - found_vid={:?}", found_vid);
|
||||
expected_vid == found_vid
|
||||
|
|
@ -642,8 +632,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self_ty: ty::TyVid,
|
||||
) -> impl DoubleEndedIterator<Item = traits::PredicateObligation<'tcx>> + Captures<'tcx> + 'b
|
||||
{
|
||||
// FIXME: consider using `sub_root_var` here so we
|
||||
// can see through subtyping.
|
||||
let ty_var_root = self.root_var(self_ty);
|
||||
trace!("pending_obligations = {:#?}", self.fulfillment_cx.borrow().pending_obligations());
|
||||
|
||||
|
|
|
|||
|
|
@ -950,7 +950,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
if !expected.is_unit() {
|
||||
return;
|
||||
}
|
||||
let found = self.resolve_vars_with_obligations(found);
|
||||
let found = self.resolve_vars_if_possible(found);
|
||||
|
||||
let in_loop = self.is_loop(id)
|
||||
|| self
|
||||
|
|
|
|||
|
|
@ -2994,7 +2994,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// This occurs for UFCS desugaring of `T::method`, where there is no
|
||||
// receiver expression for the method call, and thus no autoderef.
|
||||
if let SelfSource::QPath(_) = source {
|
||||
return is_local(self.resolve_vars_with_obligations(rcvr_ty));
|
||||
return is_local(rcvr_ty);
|
||||
}
|
||||
|
||||
self.autoderef(span, rcvr_ty).any(|(ty, _)| is_local(ty))
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal};
|
|||
use rustc_errors::PResult;
|
||||
use rustc_expand::base::{ExtCtxt, LintStoreExpand};
|
||||
use rustc_fs_util::try_canonicalize;
|
||||
use rustc_hir::def_id::LOCAL_CRATE;
|
||||
use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE};
|
||||
use rustc_lint::{unerased_lint_store, BufferedEarlyLint, EarlyCheckNode, LintStore};
|
||||
use rustc_metadata::creader::CStore;
|
||||
use rustc_middle::arena::Arena;
|
||||
|
|
@ -248,7 +248,7 @@ fn configure_and_expand(
|
|||
rustc_ast_passes::ast_validation::check_crate(sess, &krate, resolver.lint_buffer())
|
||||
});
|
||||
|
||||
let crate_types = sess.crate_types();
|
||||
let crate_types = tcx.crate_types();
|
||||
let is_executable_crate = crate_types.contains(&CrateType::Executable);
|
||||
let is_proc_macro_crate = crate_types.contains(&CrateType::ProcMacro);
|
||||
|
||||
|
|
@ -340,11 +340,12 @@ fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) {
|
|||
|
||||
// Returns all the paths that correspond to generated files.
|
||||
fn generated_output_paths(
|
||||
sess: &Session,
|
||||
tcx: TyCtxt<'_>,
|
||||
outputs: &OutputFilenames,
|
||||
exact_name: bool,
|
||||
crate_name: Symbol,
|
||||
) -> Vec<PathBuf> {
|
||||
let sess = tcx.sess;
|
||||
let mut out_filenames = Vec::new();
|
||||
for output_type in sess.opts.output_types.keys() {
|
||||
let out_filename = outputs.path(*output_type);
|
||||
|
|
@ -353,7 +354,7 @@ fn generated_output_paths(
|
|||
// If the filename has been overridden using `-o`, it will not be modified
|
||||
// by appending `.rlib`, `.exe`, etc., so we can skip this transformation.
|
||||
OutputType::Exe if !exact_name => {
|
||||
for crate_type in sess.crate_types().iter() {
|
||||
for crate_type in tcx.crate_types().iter() {
|
||||
let p = filename_for_input(sess, *crate_type, crate_name, outputs);
|
||||
out_filenames.push(p.as_path().to_path_buf());
|
||||
}
|
||||
|
|
@ -586,7 +587,7 @@ fn output_filenames(tcx: TyCtxt<'_>, (): ()) -> Arc<OutputFilenames> {
|
|||
let outputs = util::build_output_filenames(&krate.attrs, sess);
|
||||
|
||||
let output_paths =
|
||||
generated_output_paths(sess, &outputs, sess.io.output_file.is_some(), crate_name);
|
||||
generated_output_paths(tcx, &outputs, sess.io.output_file.is_some(), crate_name);
|
||||
|
||||
// Ensure the source file isn't accidentally overwritten during compilation.
|
||||
if let Some(ref input_path) = sess.io.input.opt_path() {
|
||||
|
|
@ -664,6 +665,8 @@ pub static DEFAULT_EXTERN_QUERY_PROVIDERS: LazyLock<ExternProviders> = LazyLock:
|
|||
|
||||
pub fn create_global_ctxt<'tcx>(
|
||||
compiler: &'tcx Compiler,
|
||||
crate_types: Vec<CrateType>,
|
||||
stable_crate_id: StableCrateId,
|
||||
lint_store: Lrc<LintStore>,
|
||||
dep_graph: DepGraph,
|
||||
untracked: Untracked,
|
||||
|
|
@ -696,6 +699,8 @@ pub fn create_global_ctxt<'tcx>(
|
|||
gcx_cell.get_or_init(move || {
|
||||
TyCtxt::create_global_ctxt(
|
||||
sess,
|
||||
crate_types,
|
||||
stable_crate_id,
|
||||
lint_store,
|
||||
arena,
|
||||
hir_arena,
|
||||
|
|
|
|||
|
|
@ -234,13 +234,13 @@ impl<'tcx> Queries<'tcx> {
|
|||
debug_assert_eq!(_id, CRATE_DEF_ID);
|
||||
let untracked = Untracked { cstore, source_span, definitions };
|
||||
|
||||
// FIXME: Move these fields from session to tcx and make them immutable.
|
||||
sess.init_crate_types(crate_types);
|
||||
sess.stable_crate_id.set(stable_crate_id).expect("not yet initialized");
|
||||
// FIXME: Move features from session to tcx and make them immutable.
|
||||
sess.init_features(rustc_expand::config::features(sess, &pre_configured_attrs));
|
||||
|
||||
let qcx = passes::create_global_ctxt(
|
||||
self.compiler,
|
||||
crate_types,
|
||||
stable_crate_id,
|
||||
lint_store,
|
||||
self.dep_graph(dep_graph_future),
|
||||
untracked,
|
||||
|
|
@ -320,7 +320,7 @@ impl<'tcx> Queries<'tcx> {
|
|||
|
||||
let (crate_hash, prepare_outputs, dep_graph) = self.global_ctxt()?.enter(|tcx| {
|
||||
(
|
||||
if tcx.sess.needs_crate_hash() { Some(tcx.crate_hash(LOCAL_CRATE)) } else { None },
|
||||
if tcx.needs_crate_hash() { Some(tcx.crate_hash(LOCAL_CRATE)) } else { None },
|
||||
tcx.output_filenames(()).clone(),
|
||||
tcx.dep_graph.clone(),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -103,12 +103,20 @@ fromRust(LLVMRustCounterExprKind Kind) {
|
|||
}
|
||||
|
||||
extern "C" void LLVMRustCoverageWriteFilenamesSectionToBuffer(
|
||||
const char* const Filenames[],
|
||||
const char *const Filenames[],
|
||||
size_t FilenamesLen,
|
||||
const size_t *const Lengths,
|
||||
size_t LengthsLen,
|
||||
RustStringRef BufferOut) {
|
||||
if (FilenamesLen != LengthsLen) {
|
||||
report_fatal_error(
|
||||
"Mismatched lengths in LLVMRustCoverageWriteFilenamesSectionToBuffer");
|
||||
}
|
||||
|
||||
SmallVector<std::string,32> FilenameRefs;
|
||||
FilenameRefs.reserve(FilenamesLen);
|
||||
for (size_t i = 0; i < FilenamesLen; i++) {
|
||||
FilenameRefs.push_back(std::string(Filenames[i]));
|
||||
FilenameRefs.emplace_back(Filenames[i], Lengths[i]);
|
||||
}
|
||||
auto FilenamesWriter =
|
||||
coverage::CoverageFilenamesSectionWriter(ArrayRef<std::string>(FilenameRefs));
|
||||
|
|
@ -153,8 +161,11 @@ extern "C" void LLVMRustCoverageWriteMappingToBuffer(
|
|||
CoverageMappingWriter.write(OS);
|
||||
}
|
||||
|
||||
extern "C" LLVMValueRef LLVMRustCoverageCreatePGOFuncNameVar(LLVMValueRef F, const char *FuncName) {
|
||||
StringRef FuncNameRef(FuncName);
|
||||
extern "C" LLVMValueRef LLVMRustCoverageCreatePGOFuncNameVar(
|
||||
LLVMValueRef F,
|
||||
const char *FuncName,
|
||||
size_t FuncNameLen) {
|
||||
StringRef FuncNameRef(FuncName, FuncNameLen);
|
||||
return wrap(createPGOFuncNameVar(*cast<Function>(unwrap(F)), FuncNameRef));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -545,7 +545,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
|
|||
name,
|
||||
// The all loop is because `--crate-type=rlib --crate-type=rlib` is
|
||||
// legal and produces both inside this type.
|
||||
self.sess.crate_types().iter().all(|c| *c == CrateType::Rlib),
|
||||
self.tcx.crate_types().iter().all(|c| *c == CrateType::Rlib),
|
||||
hash,
|
||||
extra_filename,
|
||||
false, // is_host
|
||||
|
|
@ -689,7 +689,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
|
|||
fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
|
||||
// If we're only compiling an rlib, then there's no need to select a
|
||||
// panic runtime, so we just skip this section entirely.
|
||||
let any_non_rlib = self.sess.crate_types().iter().any(|ct| *ct != CrateType::Rlib);
|
||||
let any_non_rlib = self.tcx.crate_types().iter().any(|ct| *ct != CrateType::Rlib);
|
||||
if !any_non_rlib {
|
||||
info!("panic runtime injection skipped, only generating rlib");
|
||||
return;
|
||||
|
|
@ -818,7 +818,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
|
|||
// At this point we've determined that we need an allocator. Let's see
|
||||
// if our compilation session actually needs an allocator based on what
|
||||
// we're emitting.
|
||||
let all_rlib = self.sess.crate_types().iter().all(|ct| matches!(*ct, CrateType::Rlib));
|
||||
let all_rlib = self.tcx.crate_types().iter().all(|ct| matches!(*ct, CrateType::Rlib));
|
||||
if all_rlib {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,8 +66,7 @@ use rustc_session::cstore::CrateDepKind;
|
|||
use rustc_session::cstore::LinkagePreference::{self, RequireDynamic, RequireStatic};
|
||||
|
||||
pub(crate) fn calculate(tcx: TyCtxt<'_>) -> Dependencies {
|
||||
tcx.sess
|
||||
.crate_types()
|
||||
tcx.crate_types()
|
||||
.iter()
|
||||
.map(|&ty| {
|
||||
let linkage = calculate_type(tcx, ty);
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> (EncodedMetadata, bool) {
|
|||
|
||||
// Always create a file at `metadata_filename`, even if we have nothing to write to it.
|
||||
// This simplifies the creation of the output `out_filename` when requested.
|
||||
let metadata_kind = tcx.sess.metadata_kind();
|
||||
let metadata_kind = tcx.metadata_kind();
|
||||
match metadata_kind {
|
||||
MetadataKind::None => {
|
||||
std::fs::File::create(&metadata_filename).unwrap_or_else(|err| {
|
||||
|
|
|
|||
|
|
@ -52,10 +52,11 @@ fn find_bundled_library(
|
|||
verbatim: Option<bool>,
|
||||
kind: NativeLibKind,
|
||||
has_cfg: bool,
|
||||
sess: &Session,
|
||||
tcx: TyCtxt<'_>,
|
||||
) -> Option<Symbol> {
|
||||
let sess = tcx.sess;
|
||||
if let NativeLibKind::Static { bundle: Some(true) | None, whole_archive } = kind
|
||||
&& sess.crate_types().iter().any(|t| matches!(t, &CrateType::Rlib | CrateType::Staticlib))
|
||||
&& tcx.crate_types().iter().any(|t| matches!(t, &CrateType::Rlib | CrateType::Staticlib))
|
||||
&& (sess.opts.unstable_opts.packed_bundled_libs || has_cfg || whole_archive == Some(true))
|
||||
{
|
||||
let verbatim = verbatim.unwrap_or(false);
|
||||
|
|
@ -364,7 +365,7 @@ impl<'tcx> Collector<'tcx> {
|
|||
};
|
||||
|
||||
let kind = kind.unwrap_or(NativeLibKind::Unspecified);
|
||||
let filename = find_bundled_library(name, verbatim, kind, cfg.is_some(), sess);
|
||||
let filename = find_bundled_library(name, verbatim, kind, cfg.is_some(), self.tcx);
|
||||
self.libs.push(NativeLib {
|
||||
name,
|
||||
filename,
|
||||
|
|
@ -442,9 +443,13 @@ impl<'tcx> Collector<'tcx> {
|
|||
// Add if not found
|
||||
let new_name: Option<&str> = passed_lib.new_name.as_deref();
|
||||
let name = Symbol::intern(new_name.unwrap_or(&passed_lib.name));
|
||||
let sess = self.tcx.sess;
|
||||
let filename =
|
||||
find_bundled_library(name, passed_lib.verbatim, passed_lib.kind, false, sess);
|
||||
let filename = find_bundled_library(
|
||||
name,
|
||||
passed_lib.verbatim,
|
||||
passed_lib.kind,
|
||||
false,
|
||||
self.tcx,
|
||||
);
|
||||
self.libs.push(NativeLib {
|
||||
name,
|
||||
filename,
|
||||
|
|
|
|||
|
|
@ -1741,7 +1741,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn encode_proc_macros(&mut self) -> Option<ProcMacroData> {
|
||||
let is_proc_macro = self.tcx.sess.crate_types().contains(&CrateType::ProcMacro);
|
||||
let is_proc_macro = self.tcx.crate_types().contains(&CrateType::ProcMacro);
|
||||
if is_proc_macro {
|
||||
let tcx = self.tcx;
|
||||
let hir = tcx.hir();
|
||||
|
|
@ -2204,7 +2204,7 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>, path: &Path) {
|
|||
source_file_cache,
|
||||
interpret_allocs: Default::default(),
|
||||
required_source_files,
|
||||
is_proc_macro: tcx.sess.crate_types().contains(&CrateType::ProcMacro),
|
||||
is_proc_macro: tcx.crate_types().contains(&CrateType::ProcMacro),
|
||||
hygiene_ctxt: &hygiene_ctxt,
|
||||
symbol_table: Default::default(),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ use crate::mir::mono::MonoItem;
|
|||
use crate::ty::TyCtxt;
|
||||
|
||||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
|
||||
use rustc_hir::definitions::DefPathHash;
|
||||
use rustc_hir::{HirId, ItemLocalId, OwnerId};
|
||||
use rustc_query_system::dep_graph::FingerprintStyle;
|
||||
|
|
@ -371,7 +371,7 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for HirId {
|
|||
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
|
||||
if tcx.fingerprint_style(dep_node.kind) == FingerprintStyle::HirId {
|
||||
let (local_hash, local_id) = Fingerprint::from(dep_node.hash).split();
|
||||
let def_path_hash = DefPathHash::new(tcx.sess.local_stable_crate_id(), local_hash);
|
||||
let def_path_hash = DefPathHash::new(tcx.stable_crate_id(LOCAL_CRATE), local_hash);
|
||||
let def_id = tcx
|
||||
.def_path_hash_to_def_id(def_path_hash, &mut || {
|
||||
panic!("Failed to extract HirId: {:?} {}", dep_node.kind, dep_node.hash)
|
||||
|
|
|
|||
|
|
@ -1210,7 +1210,7 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh {
|
|||
owner_spans.hash_stable(&mut hcx, &mut stable_hasher);
|
||||
}
|
||||
tcx.sess.opts.dep_tracking_hash(true).hash_stable(&mut hcx, &mut stable_hasher);
|
||||
tcx.sess.local_stable_crate_id().hash_stable(&mut hcx, &mut stable_hasher);
|
||||
tcx.stable_crate_id(LOCAL_CRATE).hash_stable(&mut hcx, &mut stable_hasher);
|
||||
// Hash visibility information since it does not appear in HIR.
|
||||
resolutions.visibilities.hash_stable(&mut hcx, &mut stable_hasher);
|
||||
resolutions.has_pub_restricted.hash_stable(&mut hcx, &mut stable_hasher);
|
||||
|
|
|
|||
|
|
@ -72,6 +72,6 @@ pub fn metadata_symbol_name(tcx: TyCtxt<'_>) -> String {
|
|||
format!(
|
||||
"rust_metadata_{}_{:08x}",
|
||||
tcx.crate_name(LOCAL_CRATE),
|
||||
tcx.sess.local_stable_crate_id(),
|
||||
tcx.stable_crate_id(LOCAL_CRATE),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -524,13 +524,13 @@ impl<'tcx> CodegenUnitNameBuilder<'tcx> {
|
|||
// local crate's ID. Otherwise there can be collisions between CGUs
|
||||
// instantiating stuff for upstream crates.
|
||||
let local_crate_id = if cnum != LOCAL_CRATE {
|
||||
let local_stable_crate_id = tcx.sess.local_stable_crate_id();
|
||||
let local_stable_crate_id = tcx.stable_crate_id(LOCAL_CRATE);
|
||||
format!("-in-{}.{:08x}", tcx.crate_name(LOCAL_CRATE), local_stable_crate_id)
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
let stable_crate_id = tcx.sess.local_stable_crate_id();
|
||||
let stable_crate_id = tcx.stable_crate_id(LOCAL_CRATE);
|
||||
format!("{}.{:08x}{}", tcx.crate_name(cnum), stable_crate_id, local_crate_id)
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -59,8 +59,7 @@ use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
|
|||
use rustc_session::config::CrateType;
|
||||
use rustc_session::cstore::{CrateStoreDyn, Untracked};
|
||||
use rustc_session::lint::Lint;
|
||||
use rustc_session::Limit;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::{Limit, MetadataKind, Session};
|
||||
use rustc_span::def_id::{DefPathHash, StableCrateId};
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
|
@ -527,6 +526,13 @@ pub struct GlobalCtxt<'tcx> {
|
|||
interners: CtxtInterners<'tcx>,
|
||||
|
||||
pub sess: &'tcx Session,
|
||||
crate_types: Vec<CrateType>,
|
||||
/// The `stable_crate_id` is constructed out of the crate name and all the
|
||||
/// `-C metadata` arguments passed to the compiler. Its value forms a unique
|
||||
/// global identifier for the crate. It is used to allow multiple crates
|
||||
/// with the same name to coexist. See the
|
||||
/// `rustc_symbol_mangling` crate for more information.
|
||||
stable_crate_id: StableCrateId,
|
||||
|
||||
/// This only ever stores a `LintStore` but we don't want a dependency on that type here.
|
||||
///
|
||||
|
|
@ -687,6 +693,8 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
/// has a valid reference to the context, to allow formatting values that need it.
|
||||
pub fn create_global_ctxt(
|
||||
s: &'tcx Session,
|
||||
crate_types: Vec<CrateType>,
|
||||
stable_crate_id: StableCrateId,
|
||||
lint_store: Lrc<dyn Any + sync::DynSend + sync::DynSync>,
|
||||
arena: &'tcx WorkerLocal<Arena<'tcx>>,
|
||||
hir_arena: &'tcx WorkerLocal<hir::Arena<'tcx>>,
|
||||
|
|
@ -705,6 +713,8 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
|
||||
GlobalCtxt {
|
||||
sess: s,
|
||||
crate_types,
|
||||
stable_crate_id,
|
||||
lint_store,
|
||||
arena,
|
||||
hir_arena,
|
||||
|
|
@ -800,10 +810,47 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn crate_types(self) -> &'tcx [CrateType] {
|
||||
&self.crate_types
|
||||
}
|
||||
|
||||
pub fn metadata_kind(self) -> MetadataKind {
|
||||
self.crate_types()
|
||||
.iter()
|
||||
.map(|ty| match *ty {
|
||||
CrateType::Executable | CrateType::Staticlib | CrateType::Cdylib => {
|
||||
MetadataKind::None
|
||||
}
|
||||
CrateType::Rlib => MetadataKind::Uncompressed,
|
||||
CrateType::Dylib | CrateType::ProcMacro => MetadataKind::Compressed,
|
||||
})
|
||||
.max()
|
||||
.unwrap_or(MetadataKind::None)
|
||||
}
|
||||
|
||||
pub fn needs_metadata(self) -> bool {
|
||||
self.metadata_kind() != MetadataKind::None
|
||||
}
|
||||
|
||||
pub fn needs_crate_hash(self) -> bool {
|
||||
// Why is the crate hash needed for these configurations?
|
||||
// - debug_assertions: for the "fingerprint the result" check in
|
||||
// `rustc_query_system::query::plumbing::execute_job`.
|
||||
// - incremental: for query lookups.
|
||||
// - needs_metadata: for putting into crate metadata.
|
||||
// - instrument_coverage: for putting into coverage data (see
|
||||
// `hash_mir_source`).
|
||||
cfg!(debug_assertions)
|
||||
|| self.sess.opts.incremental.is_some()
|
||||
|| self.needs_metadata()
|
||||
|| self.sess.instrument_coverage()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn stable_crate_id(self, crate_num: CrateNum) -> StableCrateId {
|
||||
if crate_num == LOCAL_CRATE {
|
||||
self.sess.local_stable_crate_id()
|
||||
self.stable_crate_id
|
||||
} else {
|
||||
self.cstore_untracked().stable_crate_id(crate_num)
|
||||
}
|
||||
|
|
@ -813,7 +860,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
/// that the crate in question has already been loaded by the CrateStore.
|
||||
#[inline]
|
||||
pub fn stable_crate_id_to_crate_num(self, stable_crate_id: StableCrateId) -> CrateNum {
|
||||
if stable_crate_id == self.sess.local_stable_crate_id() {
|
||||
if stable_crate_id == self.stable_crate_id(LOCAL_CRATE) {
|
||||
LOCAL_CRATE
|
||||
} else {
|
||||
self.cstore_untracked().stable_crate_id_to_crate_num(stable_crate_id)
|
||||
|
|
@ -830,7 +877,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
|
||||
// If this is a DefPathHash from the local crate, we can look up the
|
||||
// DefId in the tcx's `Definitions`.
|
||||
if stable_crate_id == self.sess.local_stable_crate_id() {
|
||||
if stable_crate_id == self.stable_crate_id(LOCAL_CRATE) {
|
||||
self.untracked.definitions.read().local_def_path_hash_to_def_id(hash, err).to_def_id()
|
||||
} else {
|
||||
// If this is a DefPathHash from an upstream crate, let the CrateStore map
|
||||
|
|
@ -847,7 +894,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
// statements within the query system and we'd run into endless
|
||||
// recursion otherwise.
|
||||
let (crate_name, stable_crate_id) = if def_id.is_local() {
|
||||
(self.crate_name(LOCAL_CRATE), self.sess.local_stable_crate_id())
|
||||
(self.crate_name(LOCAL_CRATE), self.stable_crate_id(LOCAL_CRATE))
|
||||
} else {
|
||||
let cstore = &*self.cstore_untracked();
|
||||
(cstore.crate_name(def_id.krate), cstore.stable_crate_id(def_id.krate))
|
||||
|
|
@ -986,7 +1033,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
pub fn local_crate_exports_generics(self) -> bool {
|
||||
debug_assert!(self.sess.opts.share_generics());
|
||||
|
||||
self.sess.crate_types().iter().any(|crate_type| {
|
||||
self.crate_types().iter().any(|crate_type| {
|
||||
match crate_type {
|
||||
CrateType::Executable
|
||||
| CrateType::Staticlib
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ struct EntryContext<'tcx> {
|
|||
}
|
||||
|
||||
fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> {
|
||||
let any_exe = tcx.sess.crate_types().iter().any(|ty| *ty == CrateType::Executable);
|
||||
let any_exe = tcx.crate_types().iter().any(|ty| *ty == CrateType::Executable);
|
||||
if !any_exe {
|
||||
// No need to find a main function.
|
||||
return None;
|
||||
|
|
|
|||
|
|
@ -364,10 +364,10 @@ fn has_custom_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
|
|||
fn reachable_set(tcx: TyCtxt<'_>, (): ()) -> LocalDefIdSet {
|
||||
let effective_visibilities = &tcx.effective_visibilities(());
|
||||
|
||||
let any_library =
|
||||
tcx.sess.crate_types().iter().any(|ty| {
|
||||
*ty == CrateType::Rlib || *ty == CrateType::Dylib || *ty == CrateType::ProcMacro
|
||||
});
|
||||
let any_library = tcx
|
||||
.crate_types()
|
||||
.iter()
|
||||
.any(|ty| *ty == CrateType::Rlib || *ty == CrateType::Dylib || *ty == CrateType::ProcMacro);
|
||||
let mut reachable_context = ReachableContext {
|
||||
tcx,
|
||||
maybe_typeck_results: None,
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ pub fn check_crate(tcx: TyCtxt<'_>, items: &mut lang_items::LanguageItems) {
|
|||
fn verify(tcx: TyCtxt<'_>, items: &lang_items::LanguageItems) {
|
||||
// We only need to check for the presence of weak lang items if we're
|
||||
// emitting something that's not an rlib.
|
||||
let needs_check = tcx.sess.crate_types().iter().any(|kind| match *kind {
|
||||
let needs_check = tcx.crate_types().iter().any(|kind| match *kind {
|
||||
CrateType::Dylib
|
||||
| CrateType::ProcMacro
|
||||
| CrateType::Cdylib
|
||||
|
|
|
|||
|
|
@ -4374,7 +4374,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
|||
if let Some(res) = res
|
||||
&& let Some(def_id) = res.opt_def_id()
|
||||
&& !def_id.is_local()
|
||||
&& self.r.tcx.sess.crate_types().contains(&CrateType::ProcMacro)
|
||||
&& self.r.tcx.crate_types().contains(&CrateType::ProcMacro)
|
||||
&& matches!(self.r.tcx.sess.opts.resolve_doc_links, ResolveDocLinks::ExportedMetadata) {
|
||||
// Encoding foreign def ids in proc macro crate metadata will ICE.
|
||||
return None;
|
||||
|
|
@ -4389,7 +4389,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
|||
match self.r.tcx.sess.opts.resolve_doc_links {
|
||||
ResolveDocLinks::None => return,
|
||||
ResolveDocLinks::ExportedMetadata
|
||||
if !self.r.tcx.sess.crate_types().iter().copied().any(CrateType::has_metadata)
|
||||
if !self.r.tcx.crate_types().iter().copied().any(CrateType::has_metadata)
|
||||
|| !maybe_exported.eval(self.r) =>
|
||||
{
|
||||
return;
|
||||
|
|
@ -4448,7 +4448,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
|||
.into_iter()
|
||||
.filter_map(|tr| {
|
||||
if !tr.def_id.is_local()
|
||||
&& self.r.tcx.sess.crate_types().contains(&CrateType::ProcMacro)
|
||||
&& self.r.tcx.crate_types().contains(&CrateType::ProcMacro)
|
||||
&& matches!(
|
||||
self.r.tcx.sess.opts.resolve_doc_links,
|
||||
ResolveDocLinks::ExportedMetadata
|
||||
|
|
|
|||
|
|
@ -152,14 +152,6 @@ pub struct Session {
|
|||
/// Input, input file path and output file path to this compilation process.
|
||||
pub io: CompilerIO,
|
||||
|
||||
crate_types: OnceCell<Vec<CrateType>>,
|
||||
/// The `stable_crate_id` is constructed out of the crate name and all the
|
||||
/// `-C metadata` arguments passed to the compiler. Its value forms a unique
|
||||
/// global identifier for the crate. It is used to allow multiple crates
|
||||
/// with the same name to coexist. See the
|
||||
/// `rustc_symbol_mangling` crate for more information.
|
||||
pub stable_crate_id: OnceCell<StableCrateId>,
|
||||
|
||||
features: OnceCell<rustc_feature::Features>,
|
||||
|
||||
incr_comp_session: OneThread<RefCell<IncrCompSession>>,
|
||||
|
|
@ -310,55 +302,11 @@ impl Session {
|
|||
self.parse_sess.span_diagnostic.emit_future_breakage_report(diags);
|
||||
}
|
||||
|
||||
pub fn local_stable_crate_id(&self) -> StableCrateId {
|
||||
self.stable_crate_id.get().copied().unwrap()
|
||||
}
|
||||
|
||||
pub fn crate_types(&self) -> &[CrateType] {
|
||||
self.crate_types.get().unwrap().as_slice()
|
||||
}
|
||||
|
||||
/// Returns true if the crate is a testing one.
|
||||
pub fn is_test_crate(&self) -> bool {
|
||||
self.opts.test
|
||||
}
|
||||
|
||||
pub fn needs_crate_hash(&self) -> bool {
|
||||
// Why is the crate hash needed for these configurations?
|
||||
// - debug_assertions: for the "fingerprint the result" check in
|
||||
// `rustc_query_system::query::plumbing::execute_job`.
|
||||
// - incremental: for query lookups.
|
||||
// - needs_metadata: for putting into crate metadata.
|
||||
// - instrument_coverage: for putting into coverage data (see
|
||||
// `hash_mir_source`).
|
||||
cfg!(debug_assertions)
|
||||
|| self.opts.incremental.is_some()
|
||||
|| self.needs_metadata()
|
||||
|| self.instrument_coverage()
|
||||
}
|
||||
|
||||
pub fn metadata_kind(&self) -> MetadataKind {
|
||||
self.crate_types()
|
||||
.iter()
|
||||
.map(|ty| match *ty {
|
||||
CrateType::Executable | CrateType::Staticlib | CrateType::Cdylib => {
|
||||
MetadataKind::None
|
||||
}
|
||||
CrateType::Rlib => MetadataKind::Uncompressed,
|
||||
CrateType::Dylib | CrateType::ProcMacro => MetadataKind::Compressed,
|
||||
})
|
||||
.max()
|
||||
.unwrap_or(MetadataKind::None)
|
||||
}
|
||||
|
||||
pub fn needs_metadata(&self) -> bool {
|
||||
self.metadata_kind() != MetadataKind::None
|
||||
}
|
||||
|
||||
pub fn init_crate_types(&self, crate_types: Vec<CrateType>) {
|
||||
self.crate_types.set(crate_types).expect("`crate_types` was initialized twice")
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn struct_span_warn<S: Into<MultiSpan>>(
|
||||
|
|
@ -1516,8 +1464,6 @@ pub fn build_session(
|
|||
parse_sess,
|
||||
sysroot,
|
||||
io,
|
||||
crate_types: OnceCell::new(),
|
||||
stable_crate_id: OnceCell::new(),
|
||||
features: OnceCell::new(),
|
||||
incr_comp_session: OneThread::new(RefCell::new(IncrCompSession::NotInitialized)),
|
||||
cgu_reuse_tracker,
|
||||
|
|
|
|||
|
|
@ -63,6 +63,10 @@ pub fn trait_def(did: DefId) -> stable_mir::ty::TraitDef {
|
|||
with_tables(|t| t.trait_def(did))
|
||||
}
|
||||
|
||||
pub fn impl_def(did: DefId) -> stable_mir::ty::ImplDef {
|
||||
with_tables(|t| t.impl_def(did))
|
||||
}
|
||||
|
||||
impl<'tcx> Tables<'tcx> {
|
||||
pub fn item_def_id(&self, item: &stable_mir::CrateItem) -> DefId {
|
||||
self.def_ids[item.0]
|
||||
|
|
@ -72,6 +76,10 @@ impl<'tcx> Tables<'tcx> {
|
|||
self.def_ids[trait_def.0]
|
||||
}
|
||||
|
||||
pub fn impl_trait_def_id(&self, impl_def: &stable_mir::ty::ImplDef) -> DefId {
|
||||
self.def_ids[impl_def.0]
|
||||
}
|
||||
|
||||
pub fn crate_item(&mut self, did: DefId) -> stable_mir::CrateItem {
|
||||
stable_mir::CrateItem(self.create_def_id(did))
|
||||
}
|
||||
|
|
@ -116,6 +124,10 @@ impl<'tcx> Tables<'tcx> {
|
|||
stable_mir::ty::ConstDef(self.create_def_id(did))
|
||||
}
|
||||
|
||||
pub fn impl_def(&mut self, did: DefId) -> stable_mir::ty::ImplDef {
|
||||
stable_mir::ty::ImplDef(self.create_def_id(did))
|
||||
}
|
||||
|
||||
fn create_def_id(&mut self, did: DefId) -> stable_mir::DefId {
|
||||
// FIXME: this becomes inefficient when we have too many ids
|
||||
for (i, &d) in self.def_ids.iter().enumerate() {
|
||||
|
|
|
|||
|
|
@ -59,6 +59,20 @@ impl<'tcx> Context for Tables<'tcx> {
|
|||
trait_def.stable(self)
|
||||
}
|
||||
|
||||
fn all_trait_impls(&mut self) -> stable_mir::ImplTraitDecls {
|
||||
self.tcx
|
||||
.trait_impls_in_crate(LOCAL_CRATE)
|
||||
.iter()
|
||||
.map(|impl_def_id| self.impl_def(*impl_def_id))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn trait_impl(&mut self, impl_def: &stable_mir::ty::ImplDef) -> stable_mir::ty::ImplTrait {
|
||||
let def_id = self.impl_trait_def_id(impl_def);
|
||||
let impl_trait = self.tcx.impl_trait_ref(def_id).unwrap();
|
||||
impl_trait.stable(self)
|
||||
}
|
||||
|
||||
fn mir_body(&mut self, item: &stable_mir::CrateItem) -> stable_mir::mir::Body {
|
||||
let def_id = self.item_def_id(item);
|
||||
let mir = self.tcx.optimized_mir(def_id);
|
||||
|
|
@ -840,6 +854,19 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx, S, V> Stable<'tcx> for ty::EarlyBinder<S>
|
||||
where
|
||||
S: Stable<'tcx, T = V>,
|
||||
{
|
||||
type T = stable_mir::ty::EarlyBinder<V>;
|
||||
|
||||
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||
use stable_mir::ty::EarlyBinder;
|
||||
|
||||
EarlyBinder { value: self.as_ref().skip_binder().stable(tables) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for ty::FnSig<'tcx> {
|
||||
type T = stable_mir::ty::FnSig;
|
||||
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||
|
|
@ -1154,3 +1181,12 @@ impl<'tcx> Stable<'tcx> for rustc_middle::mir::ConstantKind<'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for ty::TraitRef<'tcx> {
|
||||
type T = stable_mir::ty::TraitRef;
|
||||
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||
use stable_mir::ty::TraitRef;
|
||||
|
||||
TraitRef { def_id: rustc_internal::trait_def(self.def_id), args: self.args.stable(tables) }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use std::cell::Cell;
|
|||
|
||||
use crate::rustc_smir::Tables;
|
||||
|
||||
use self::ty::{TraitDecl, TraitDef, Ty, TyKind};
|
||||
use self::ty::{ImplDef, ImplTrait, TraitDecl, TraitDef, Ty, TyKind};
|
||||
|
||||
pub mod mir;
|
||||
pub mod ty;
|
||||
|
|
@ -32,9 +32,12 @@ pub type DefId = usize;
|
|||
/// A list of crate items.
|
||||
pub type CrateItems = Vec<CrateItem>;
|
||||
|
||||
/// A list of crate items.
|
||||
/// A list of trait decls.
|
||||
pub type TraitDecls = Vec<TraitDef>;
|
||||
|
||||
/// A list of impl trait decls.
|
||||
pub type ImplTraitDecls = Vec<ImplDef>;
|
||||
|
||||
/// Holds information about a crate.
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct Crate {
|
||||
|
|
@ -89,6 +92,8 @@ pub trait Context {
|
|||
fn mir_body(&mut self, item: &CrateItem) -> mir::Body;
|
||||
fn all_trait_decls(&mut self) -> TraitDecls;
|
||||
fn trait_decl(&mut self, trait_def: &TraitDef) -> TraitDecl;
|
||||
fn all_trait_impls(&mut self) -> ImplTraitDecls;
|
||||
fn trait_impl(&mut self, trait_impl: &ImplDef) -> ImplTrait;
|
||||
/// Get information about the local crate.
|
||||
fn local_crate(&self) -> Crate;
|
||||
/// Retrieve a list of all external crates.
|
||||
|
|
|
|||
|
|
@ -119,6 +119,15 @@ impl TraitDef {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct ImplDef(pub(crate) DefId);
|
||||
|
||||
impl ImplDef {
|
||||
pub fn trait_impl(&self) -> ImplTrait {
|
||||
with(|cx| cx.trait_impl(self))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct GenericArgs(pub Vec<GenericArgKind>);
|
||||
|
||||
|
|
@ -196,6 +205,11 @@ pub struct Binder<T> {
|
|||
pub bound_vars: Vec<BoundVariableKind>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct EarlyBinder<T> {
|
||||
pub value: T,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum BoundVariableKind {
|
||||
Ty(BoundTyKind),
|
||||
|
|
@ -432,3 +446,10 @@ pub struct TraitDecl {
|
|||
pub implement_via_object: bool,
|
||||
pub deny_explicit_impl: bool,
|
||||
}
|
||||
|
||||
pub type ImplTrait = EarlyBinder<TraitRef>;
|
||||
|
||||
pub struct TraitRef {
|
||||
pub def_id: TraitDef,
|
||||
pub args: GenericArgs,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ fn compute_symbol_name<'tcx>(
|
|||
|
||||
if let Some(def_id) = def_id.as_local() {
|
||||
if tcx.proc_macro_decls_static(()) == Some(def_id) {
|
||||
let stable_crate_id = tcx.sess.local_stable_crate_id();
|
||||
let stable_crate_id = tcx.stable_crate_id(LOCAL_CRATE);
|
||||
return tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -824,11 +824,8 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
|
|||
}
|
||||
|
||||
ty::Array(ty0, len) => {
|
||||
let len = len
|
||||
.try_to_scalar()
|
||||
.unwrap()
|
||||
.to_u64()
|
||||
.unwrap_or_else(|_| panic!("failed to convert length to u64"));
|
||||
let len = len.eval_target_usize(tcx, ty::ParamEnv::reveal_all());
|
||||
|
||||
ty = Ty::new_array(tcx, transform_ty(tcx, *ty0, options), len);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,21 +19,25 @@ rustc_index::newtype_index! {
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(super) struct ProvisionalEntry<'tcx> {
|
||||
// In case we have a coinductive cycle, this is the
|
||||
// the currently least restrictive result of this goal.
|
||||
pub(super) response: QueryResult<'tcx>,
|
||||
// In case of a cycle, the position of deepest stack entry involved
|
||||
// in that cycle. This is monotonically decreasing in the stack as all
|
||||
// elements between the current stack element in the deepest stack entry
|
||||
// involved have to also be involved in that cycle.
|
||||
//
|
||||
// We can only move entries to the global cache once we're complete done
|
||||
// with the cycle. If this entry has not been involved in a cycle,
|
||||
// this is just its own depth.
|
||||
/// In case we have a coinductive cycle, this is the
|
||||
/// the current provisional result of this goal.
|
||||
///
|
||||
/// This starts out as `None` for all goals and gets to some
|
||||
/// when the goal gets popped from the stack or we rerun evaluation
|
||||
/// for this goal to reach a fixpoint.
|
||||
pub(super) response: Option<QueryResult<'tcx>>,
|
||||
/// In case of a cycle, the position of deepest stack entry involved
|
||||
/// in that cycle. This is monotonically decreasing in the stack as all
|
||||
/// elements between the current stack element in the deepest stack entry
|
||||
/// involved have to also be involved in that cycle.
|
||||
///
|
||||
/// We can only move entries to the global cache once we're complete done
|
||||
/// with the cycle. If this entry has not been involved in a cycle,
|
||||
/// this is just its own depth.
|
||||
pub(super) depth: StackDepth,
|
||||
|
||||
// The goal for this entry. Should always be equal to the corresponding goal
|
||||
// in the lookup table.
|
||||
/// The goal for this entry. Should always be equal to the corresponding goal
|
||||
/// in the lookup table.
|
||||
pub(super) input: CanonicalInput<'tcx>,
|
||||
}
|
||||
|
||||
|
|
@ -92,7 +96,7 @@ impl<'tcx> ProvisionalCache<'tcx> {
|
|||
self.entries[entry_index].depth
|
||||
}
|
||||
|
||||
pub(super) fn provisional_result(&self, entry_index: EntryIndex) -> QueryResult<'tcx> {
|
||||
pub(super) fn provisional_result(&self, entry_index: EntryIndex) -> Option<QueryResult<'tcx>> {
|
||||
self.entries[entry_index].response
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use rustc_middle::traits::solve::CacheData;
|
|||
use rustc_middle::traits::solve::{CanonicalInput, Certainty, EvaluationCache, QueryResult};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::Limit;
|
||||
use std::{collections::hash_map::Entry, mem};
|
||||
use std::collections::hash_map::Entry;
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
pub struct StackDepth {}
|
||||
|
|
@ -216,8 +216,8 @@ impl<'tcx> SearchGraph<'tcx> {
|
|||
cycle_participants: Default::default(),
|
||||
};
|
||||
assert_eq!(self.stack.push(entry), depth);
|
||||
let response = Self::response_no_constraints(tcx, input, Certainty::Yes);
|
||||
let entry_index = cache.entries.push(ProvisionalEntry { response, depth, input });
|
||||
let entry_index =
|
||||
cache.entries.push(ProvisionalEntry { response: None, depth, input });
|
||||
v.insert(entry_index);
|
||||
}
|
||||
// We have a nested goal which relies on a goal `root` deeper in the stack.
|
||||
|
|
@ -243,23 +243,31 @@ impl<'tcx> SearchGraph<'tcx> {
|
|||
root.cycle_participants.insert(e.input);
|
||||
}
|
||||
|
||||
// NOTE: The goals on the stack aren't the only goals involved in this cycle.
|
||||
// We can also depend on goals which aren't part of the stack but coinductively
|
||||
// depend on the stack themselves. We already checked whether all the goals
|
||||
// between these goals and their root on the stack. This means that as long as
|
||||
// each goal in a cycle is checked for coinductivity by itself, simply checking
|
||||
// the stack is enough.
|
||||
if self.stack.raw[stack_depth.index()..]
|
||||
.iter()
|
||||
.all(|g| g.input.value.goal.predicate.is_coinductive(tcx))
|
||||
{
|
||||
// If we're in a coinductive cycle, we have to retry proving the current goal
|
||||
// until we reach a fixpoint.
|
||||
self.stack[stack_depth].has_been_used = true;
|
||||
return cache.provisional_result(entry_index);
|
||||
// If we're in a cycle, we have to retry proving the current goal
|
||||
// until we reach a fixpoint.
|
||||
self.stack[stack_depth].has_been_used = true;
|
||||
return if let Some(result) = cache.provisional_result(entry_index) {
|
||||
result
|
||||
} else {
|
||||
return Self::response_no_constraints(tcx, input, Certainty::OVERFLOW);
|
||||
}
|
||||
// If we don't have a provisional result yet, the goal has to
|
||||
// still be on the stack.
|
||||
let mut goal_on_stack = false;
|
||||
let mut is_coinductive = true;
|
||||
for entry in self.stack.raw[stack_depth.index()..]
|
||||
.iter()
|
||||
.skip_while(|entry| entry.input != input)
|
||||
{
|
||||
goal_on_stack = true;
|
||||
is_coinductive &= entry.input.value.goal.predicate.is_coinductive(tcx);
|
||||
}
|
||||
debug_assert!(goal_on_stack);
|
||||
|
||||
if is_coinductive {
|
||||
Self::response_no_constraints(tcx, input, Certainty::Yes)
|
||||
} else {
|
||||
Self::response_no_constraints(tcx, input, Certainty::OVERFLOW)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -288,15 +296,18 @@ impl<'tcx> SearchGraph<'tcx> {
|
|||
let provisional_entry_index =
|
||||
*cache.lookup_table.get(&stack_entry.input).unwrap();
|
||||
let provisional_entry = &mut cache.entries[provisional_entry_index];
|
||||
let prev_response = mem::replace(&mut provisional_entry.response, response);
|
||||
if stack_entry.has_been_used && prev_response != response {
|
||||
// If so, remove all entries whose result depends on this goal
|
||||
// from the provisional cache...
|
||||
if stack_entry.has_been_used
|
||||
&& provisional_entry.response.map_or(true, |r| r != response)
|
||||
{
|
||||
// If so, update the provisional result for this goal and remove
|
||||
// all entries whose result depends on this goal from the provisional
|
||||
// cache...
|
||||
//
|
||||
// That's not completely correct, as a nested goal can also
|
||||
// That's not completely correct, as a nested goal can also only
|
||||
// depend on a goal which is lower in the stack so it doesn't
|
||||
// actually depend on the current goal. This should be fairly
|
||||
// rare and is hopefully not relevant for performance.
|
||||
provisional_entry.response = Some(response);
|
||||
#[allow(rustc::potential_query_instability)]
|
||||
cache.lookup_table.retain(|_key, index| *index <= provisional_entry_index);
|
||||
cache.entries.truncate(provisional_entry_index.index() + 1);
|
||||
|
|
@ -315,8 +326,8 @@ impl<'tcx> SearchGraph<'tcx> {
|
|||
});
|
||||
|
||||
// We're now done with this goal. In case this goal is involved in a larger cycle
|
||||
// do not remove it from the provisional cache and do not add it to the global
|
||||
// cache.
|
||||
// do not remove it from the provisional cache and update its provisional result.
|
||||
// We only add the root of cycles to the global cache.
|
||||
//
|
||||
// It is not possible for any nested goal to depend on something deeper on the
|
||||
// stack, as this would have also updated the depth of the current goal.
|
||||
|
|
@ -348,6 +359,8 @@ impl<'tcx> SearchGraph<'tcx> {
|
|||
dep_node,
|
||||
result,
|
||||
)
|
||||
} else {
|
||||
provisional_entry.response = Some(result);
|
||||
}
|
||||
|
||||
result
|
||||
|
|
|
|||
|
|
@ -2394,7 +2394,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
|||
Ok(args) => args,
|
||||
Err(()) => {
|
||||
// FIXME: A rematch may fail when a candidate cache hit occurs
|
||||
// on thefreshened form of the trait predicate, but the match
|
||||
// on the freshened form of the trait predicate, but the match
|
||||
// fails for some reason that is not captured in the freshened
|
||||
// cache key. For example, equating an impl trait ref against
|
||||
// the placeholder trait ref may fail due the Generalizer relation
|
||||
|
|
|
|||
|
|
@ -200,7 +200,9 @@ pub enum TyKind<I: Interner> {
|
|||
/// A tuple type. For example, `(i32, bool)`.
|
||||
Tuple(I::ListTy),
|
||||
|
||||
/// A projection or opaque type. Both of these types
|
||||
/// A projection, opaque type, weak type alias, or inherent associated type.
|
||||
/// All of these types are represented as pairs of def-id and args, and can
|
||||
/// be normalized, so they are grouped conceptually.
|
||||
Alias(AliasKind, I::AliasTy),
|
||||
|
||||
/// A type parameter; for example, `T` in `fn f<T>(x: T) {}`.
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use core::hash::{Hash, Hasher};
|
|||
use core::iter::FusedIterator;
|
||||
use core::marker::PhantomData;
|
||||
use core::mem;
|
||||
use core::ptr::{NonNull, Unique};
|
||||
use core::ptr::NonNull;
|
||||
|
||||
use super::SpecExtend;
|
||||
use crate::alloc::{Allocator, Global};
|
||||
|
|
@ -168,15 +168,16 @@ impl<T, A: Allocator> LinkedList<T, A> {
|
|||
/// Adds the given node to the front of the list.
|
||||
///
|
||||
/// # Safety
|
||||
/// `node` must point to a valid node that was boxed using the list's allocator.
|
||||
/// `node` must point to a valid node that was boxed and leaked using the list's allocator.
|
||||
/// This method takes ownership of the node, so the pointer should not be used again.
|
||||
#[inline]
|
||||
unsafe fn push_front_node(&mut self, node: Unique<Node<T>>) {
|
||||
unsafe fn push_front_node(&mut self, node: NonNull<Node<T>>) {
|
||||
// This method takes care not to create mutable references to whole nodes,
|
||||
// to maintain validity of aliasing pointers into `element`.
|
||||
unsafe {
|
||||
(*node.as_ptr()).next = self.head;
|
||||
(*node.as_ptr()).prev = None;
|
||||
let node = Some(NonNull::from(node));
|
||||
let node = Some(node);
|
||||
|
||||
match self.head {
|
||||
None => self.tail = node,
|
||||
|
|
@ -212,15 +213,16 @@ impl<T, A: Allocator> LinkedList<T, A> {
|
|||
/// Adds the given node to the back of the list.
|
||||
///
|
||||
/// # Safety
|
||||
/// `node` must point to a valid node that was boxed using the list's allocator.
|
||||
/// `node` must point to a valid node that was boxed and leaked using the list's allocator.
|
||||
/// This method takes ownership of the node, so the pointer should not be used again.
|
||||
#[inline]
|
||||
unsafe fn push_back_node(&mut self, node: Unique<Node<T>>) {
|
||||
unsafe fn push_back_node(&mut self, node: NonNull<Node<T>>) {
|
||||
// This method takes care not to create mutable references to whole nodes,
|
||||
// to maintain validity of aliasing pointers into `element`.
|
||||
unsafe {
|
||||
(*node.as_ptr()).next = None;
|
||||
(*node.as_ptr()).prev = self.tail;
|
||||
let node = Some(NonNull::from(node));
|
||||
let node = Some(node);
|
||||
|
||||
match self.tail {
|
||||
None => self.head = node,
|
||||
|
|
@ -842,8 +844,8 @@ impl<T, A: Allocator> LinkedList<T, A> {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn push_front(&mut self, elt: T) {
|
||||
let node = Box::new_in(Node::new(elt), &self.alloc);
|
||||
let node_ptr = Unique::from(Box::leak(node));
|
||||
// SAFETY: node_ptr is a unique pointer to a node we boxed with self.alloc
|
||||
let node_ptr = NonNull::from(Box::leak(node));
|
||||
// SAFETY: node_ptr is a unique pointer to a node we boxed with self.alloc and leaked
|
||||
unsafe {
|
||||
self.push_front_node(node_ptr);
|
||||
}
|
||||
|
|
@ -890,8 +892,8 @@ impl<T, A: Allocator> LinkedList<T, A> {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn push_back(&mut self, elt: T) {
|
||||
let node = Box::new_in(Node::new(elt), &self.alloc);
|
||||
let node_ptr = Unique::from(Box::leak(node));
|
||||
// SAFETY: node_ptr is a unique pointer to a node we boxed with self.alloc
|
||||
let node_ptr = NonNull::from(Box::leak(node));
|
||||
// SAFETY: node_ptr is a unique pointer to a node we boxed with self.alloc and leaked
|
||||
unsafe {
|
||||
self.push_back_node(node_ptr);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2491,9 +2491,9 @@ impl<T, A: Allocator> From<Vec<T, A>> for Rc<[T], A> {
|
|||
///
|
||||
/// ```
|
||||
/// # use std::rc::Rc;
|
||||
/// let original: Box<Vec<i32>> = Box::new(vec![1, 2, 3]);
|
||||
/// let shared: Rc<Vec<i32>> = Rc::from(original);
|
||||
/// assert_eq!(vec![1, 2, 3], *shared);
|
||||
/// let unique: Vec<i32> = vec![1, 2, 3];
|
||||
/// let shared: Rc<[i32]> = Rc::from(unique);
|
||||
/// assert_eq!(&[1, 2, 3], &shared[..]);
|
||||
/// ```
|
||||
#[inline]
|
||||
fn from(v: Vec<T, A>) -> Rc<[T], A> {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use super::*;
|
||||
use crate::cmp::Ordering::{self, Equal, Greater, Less};
|
||||
use crate::intrinsics::{self, const_eval_select};
|
||||
use crate::mem;
|
||||
use crate::mem::{self, SizedTypeProperties};
|
||||
use crate::slice::{self, SliceIndex};
|
||||
|
||||
impl<T: ?Sized> *const T {
|
||||
|
|
@ -995,14 +995,23 @@ impl<T: ?Sized> *const T {
|
|||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[must_use = "returns a new pointer rather than modifying its argument"]
|
||||
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
|
||||
// We could always go back to wrapping if unchecked becomes unacceptable
|
||||
#[rustc_allow_const_fn_unstable(const_int_unchecked_arith)]
|
||||
#[inline(always)]
|
||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
|
||||
pub const unsafe fn sub(self, count: usize) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
// SAFETY: the caller must uphold the safety contract for `offset`.
|
||||
unsafe { self.offset((count as isize).wrapping_neg()) }
|
||||
if T::IS_ZST {
|
||||
// Pointer arithmetic does nothing when the pointee is a ZST.
|
||||
self
|
||||
} else {
|
||||
// SAFETY: the caller must uphold the safety contract for `offset`.
|
||||
// Because the pointee is *not* a ZST, that means that `count` is
|
||||
// at most `isize::MAX`, and thus the negation cannot overflow.
|
||||
unsafe { self.offset(intrinsics::unchecked_sub(0, count as isize)) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculates the offset from a pointer in bytes (convenience for
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use super::*;
|
||||
use crate::cmp::Ordering::{self, Equal, Greater, Less};
|
||||
use crate::intrinsics::{self, const_eval_select};
|
||||
use crate::mem::SizedTypeProperties;
|
||||
use crate::slice::{self, SliceIndex};
|
||||
|
||||
impl<T: ?Sized> *mut T {
|
||||
|
|
@ -1095,14 +1096,23 @@ impl<T: ?Sized> *mut T {
|
|||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[must_use = "returns a new pointer rather than modifying its argument"]
|
||||
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
|
||||
// We could always go back to wrapping if unchecked becomes unacceptable
|
||||
#[rustc_allow_const_fn_unstable(const_int_unchecked_arith)]
|
||||
#[inline(always)]
|
||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
|
||||
pub const unsafe fn sub(self, count: usize) -> Self
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
// SAFETY: the caller must uphold the safety contract for `offset`.
|
||||
unsafe { self.offset((count as isize).wrapping_neg()) }
|
||||
if T::IS_ZST {
|
||||
// Pointer arithmetic does nothing when the pointee is a ZST.
|
||||
self
|
||||
} else {
|
||||
// SAFETY: the caller must uphold the safety contract for `offset`.
|
||||
// Because the pointee is *not* a ZST, that means that `count` is
|
||||
// at most `isize::MAX`, and thus the negation cannot overflow.
|
||||
unsafe { self.offset(intrinsics::unchecked_sub(0, count as isize)) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculates the offset from a pointer in bytes (convenience for
|
||||
|
|
|
|||
|
|
@ -25,14 +25,12 @@ hashbrown = { version = "0.14", default-features = false, features = ['rustc-dep
|
|||
std_detect = { path = "../stdarch/crates/std_detect", default-features = false, features = ['rustc-dep-of-std'] }
|
||||
|
||||
# Dependencies of the `backtrace` crate
|
||||
addr2line = { version = "0.20.0", optional = true, default-features = false }
|
||||
rustc-demangle = { version = "0.1.21", features = ['rustc-dep-of-std'] }
|
||||
miniz_oxide = { version = "0.7.0", optional = true, default-features = false, public = false }
|
||||
[dependencies.object]
|
||||
version = "0.31.1"
|
||||
optional = true
|
||||
default-features = false
|
||||
features = ['read_core', 'elf', 'macho', 'pe', 'unaligned', 'archive']
|
||||
|
||||
[target.'cfg(not(all(windows, target_env = "msvc", not(target_vendor = "uwp"))))'.dependencies]
|
||||
miniz_oxide = { version = "0.7.0", optional = true, default-features = false }
|
||||
addr2line = { version = "0.20.0", optional = true, default-features = false }
|
||||
object = { version = "0.31.1", default-features = false, optional = true, features = ['read_core', 'elf', 'macho', 'pe', 'unaligned', 'archive'] }
|
||||
|
||||
[dev-dependencies]
|
||||
rand = { version = "0.8.5", default-features = false, features = ["alloc"] }
|
||||
|
|
|
|||
|
|
@ -791,6 +791,7 @@ impl Write for &File {
|
|||
self.inner.is_write_vectored()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
self.inner.flush()
|
||||
}
|
||||
|
|
@ -836,6 +837,7 @@ impl Write for File {
|
|||
fn is_write_vectored(&self) -> bool {
|
||||
(&&*self).is_write_vectored()
|
||||
}
|
||||
#[inline]
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
(&*self).flush()
|
||||
}
|
||||
|
|
@ -881,6 +883,7 @@ impl Write for Arc<File> {
|
|||
fn is_write_vectored(&self) -> bool {
|
||||
(&**self).is_write_vectored()
|
||||
}
|
||||
#[inline]
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
(&**self).flush()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -310,6 +310,7 @@ impl<'a> Write for BorrowedCursor<'a> {
|
|||
Ok(buf.len())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn flush(&mut self) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -397,9 +397,15 @@ extern crate libc;
|
|||
#[allow(unused_extern_crates)]
|
||||
extern crate unwind;
|
||||
|
||||
// FIXME: #94122 this extern crate definition only exist here to stop
|
||||
// miniz_oxide docs leaking into std docs. Find better way to do it.
|
||||
// Remove exclusion from tidy platform check when this removed.
|
||||
#[doc(masked)]
|
||||
#[allow(unused_extern_crates)]
|
||||
#[cfg(feature = "miniz_oxide")]
|
||||
#[cfg(all(
|
||||
not(all(windows, target_env = "msvc", not(target_vendor = "uwp"))),
|
||||
feature = "miniz_oxide"
|
||||
))]
|
||||
extern crate miniz_oxide;
|
||||
|
||||
// During testing, this crate is not actually the "real" std library, but rather
|
||||
|
|
|
|||
|
|
@ -647,6 +647,7 @@ impl Write for TcpStream {
|
|||
self.0.is_write_vectored()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -685,6 +686,7 @@ impl Write for &TcpStream {
|
|||
self.0.is_write_vectored()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -712,6 +712,7 @@ impl<'a> io::Write for &'a UnixStream {
|
|||
self.0.is_write_vectored()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -280,6 +280,7 @@ impl Write for ChildStdin {
|
|||
io::Write::is_write_vectored(&&*self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
(&*self).flush()
|
||||
}
|
||||
|
|
@ -299,6 +300,7 @@ impl Write for &ChildStdin {
|
|||
self.inner.is_write_vectored()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -130,11 +130,8 @@ impl Barrier {
|
|||
let local_gen = lock.generation_id;
|
||||
lock.count += 1;
|
||||
if lock.count < self.num_threads {
|
||||
// We need a while loop to guard against spurious wakeups.
|
||||
// https://en.wikipedia.org/wiki/Spurious_wakeup
|
||||
while local_gen == lock.generation_id {
|
||||
lock = self.cvar.wait(lock).unwrap();
|
||||
}
|
||||
let _guard =
|
||||
self.cvar.wait_while(lock, |state| local_gen == state.generation_id).unwrap();
|
||||
BarrierWaitResult(false)
|
||||
} else {
|
||||
lock.count = 0;
|
||||
|
|
|
|||
|
|
@ -335,6 +335,7 @@ impl File {
|
|||
false
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn flush(&self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1204,6 +1204,7 @@ impl File {
|
|||
self.0.write_vectored_at(bufs, offset)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn flush(&self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ impl io::Write for Stdout {
|
|||
true
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -81,6 +82,7 @@ impl io::Write for Stderr {
|
|||
true
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1129,7 +1129,7 @@ fn needs_codegen_config(run: &RunConfig<'_>) -> bool {
|
|||
needs_codegen_cfg
|
||||
}
|
||||
|
||||
const CODEGEN_BACKEND_PREFIX: &str = "rustc_codegen_";
|
||||
pub(crate) const CODEGEN_BACKEND_PREFIX: &str = "rustc_codegen_";
|
||||
|
||||
fn is_codegen_cfg_needed(path: &TaskPath, run: &RunConfig<'_>) -> bool {
|
||||
if path.path.to_str().unwrap().contains(&CODEGEN_BACKEND_PREFIX) {
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ use std::str::FromStr;
|
|||
use crate::cache::{Interned, INTERNER};
|
||||
use crate::cc_detect::{ndk_compiler, Language};
|
||||
use crate::channel::{self, GitInfo};
|
||||
use crate::compile::CODEGEN_BACKEND_PREFIX;
|
||||
pub use crate::flags::Subcommand;
|
||||
use crate::flags::{Color, Flags, Warnings};
|
||||
use crate::util::{exe, output, t};
|
||||
|
|
@ -1443,8 +1444,21 @@ impl Config {
|
|||
.map(|v| v.parse().expect("failed to parse rust.llvm-libunwind"));
|
||||
|
||||
if let Some(ref backends) = rust.codegen_backends {
|
||||
config.rust_codegen_backends =
|
||||
backends.iter().map(|s| INTERNER.intern_str(s)).collect();
|
||||
let available_backends = vec!["llvm", "cranelift", "gcc"];
|
||||
|
||||
config.rust_codegen_backends = backends.iter().map(|s| {
|
||||
if let Some(backend) = s.strip_prefix(CODEGEN_BACKEND_PREFIX) {
|
||||
if available_backends.contains(&backend) {
|
||||
panic!("Invalid value '{s}' for 'rust.codegen-backends'. Instead, please use '{backend}'.");
|
||||
} else {
|
||||
println!("help: '{s}' for 'rust.codegen-backends' might fail. \
|
||||
Codegen backends are mostly defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \
|
||||
In this case, it would be referred to as '{backend}'.");
|
||||
}
|
||||
}
|
||||
|
||||
INTERNER.intern_str(s)
|
||||
}).collect();
|
||||
}
|
||||
|
||||
config.rust_codegen_units = rust.codegen_units.map(threads_from_config);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# `profile-sample-use
|
||||
# `profile-sample-use`
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -4890,12 +4890,14 @@ Released 2018-09-13
|
|||
[`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else
|
||||
[`if_then_some_else_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none
|
||||
[`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond
|
||||
[`ignored_unit_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#ignored_unit_patterns
|
||||
[`impl_trait_in_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#impl_trait_in_params
|
||||
[`implicit_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_clone
|
||||
[`implicit_hasher`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_hasher
|
||||
[`implicit_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_return
|
||||
[`implicit_saturating_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_saturating_add
|
||||
[`implicit_saturating_sub`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_saturating_sub
|
||||
[`impossible_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#impossible_comparisons
|
||||
[`imprecise_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#imprecise_flops
|
||||
[`inconsistent_digit_grouping`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_digit_grouping
|
||||
[`inconsistent_struct_constructor`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_struct_constructor
|
||||
|
|
@ -5190,6 +5192,7 @@ Released 2018-09-13
|
|||
[`redundant_closure`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
|
||||
[`redundant_closure_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_call
|
||||
[`redundant_closure_for_method_calls`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_for_method_calls
|
||||
[`redundant_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_comparisons
|
||||
[`redundant_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_else
|
||||
[`redundant_feature_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_feature_names
|
||||
[`redundant_field_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ fn main() {
|
|||
matches.get_one::<String>("type").map(String::as_str),
|
||||
matches.get_flag("msrv"),
|
||||
) {
|
||||
Ok(_) => update_lints::update(update_lints::UpdateMode::Change),
|
||||
Ok(()) => update_lints::update(update_lints::UpdateMode::Change),
|
||||
Err(e) => eprintln!("Unable to create lint: {e}"),
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ fn check_install_precondition(force_override: bool) -> bool {
|
|||
}
|
||||
} else {
|
||||
match fs::create_dir(vs_dir_path) {
|
||||
Ok(_) => {
|
||||
Ok(()) => {
|
||||
println!("info: created `{VSCODE_DIR}` directory for clippy");
|
||||
},
|
||||
Err(err) => {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, Mutability, TyKind};
|
||||
use rustc_lint::LateContext;
|
||||
|
|
@ -16,33 +14,41 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) {
|
|||
return;
|
||||
}
|
||||
|
||||
if_chain! {
|
||||
if let ExprKind::Cast(cast_expr, cast_to_hir_ty) = expr.kind;
|
||||
let (cast_from, cast_to) = (cx.typeck_results().expr_ty(cast_expr), cx.typeck_results().expr_ty(expr));
|
||||
if let ty::RawPtr(TypeAndMut { mutbl: from_mutbl, .. }) = cast_from.kind();
|
||||
if let ty::RawPtr(TypeAndMut { ty: to_pointee_ty, mutbl: to_mutbl }) = cast_to.kind();
|
||||
if matches!((from_mutbl, to_mutbl),
|
||||
(Mutability::Not, Mutability::Not) | (Mutability::Mut, Mutability::Mut));
|
||||
if let ExprKind::Cast(cast_expr, cast_to_hir_ty) = expr.kind
|
||||
&& let (cast_from, cast_to) = (cx.typeck_results().expr_ty(cast_expr), cx.typeck_results().expr_ty(expr))
|
||||
&& let ty::RawPtr(TypeAndMut { mutbl: from_mutbl, .. }) = cast_from.kind()
|
||||
&& let ty::RawPtr(TypeAndMut { ty: to_pointee_ty, mutbl: to_mutbl }) = cast_to.kind()
|
||||
&& matches!((from_mutbl, to_mutbl),
|
||||
(Mutability::Not, Mutability::Not) | (Mutability::Mut, Mutability::Mut))
|
||||
// The `U` in `pointer::cast` have to be `Sized`
|
||||
// as explained here: https://github.com/rust-lang/rust/issues/60602.
|
||||
if to_pointee_ty.is_sized(cx.tcx, cx.param_env);
|
||||
then {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let cast_expr_sugg = Sugg::hir_with_applicability(cx, cast_expr, "_", &mut applicability);
|
||||
let turbofish = match &cast_to_hir_ty.kind {
|
||||
TyKind::Infer => Cow::Borrowed(""),
|
||||
TyKind::Ptr(mut_ty) if matches!(mut_ty.ty.kind, TyKind::Infer) => Cow::Borrowed(""),
|
||||
_ => Cow::Owned(format!("::<{to_pointee_ty}>")),
|
||||
};
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
PTR_AS_PTR,
|
||||
expr.span,
|
||||
"`as` casting between raw pointers without changing its mutability",
|
||||
"try `pointer::cast`, a safer alternative",
|
||||
format!("{}.cast{turbofish}()", cast_expr_sugg.maybe_par()),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
&& to_pointee_ty.is_sized(cx.tcx, cx.param_env)
|
||||
{
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let cast_expr_sugg = Sugg::hir_with_applicability(cx, cast_expr, "_", &mut app);
|
||||
let turbofish = match &cast_to_hir_ty.kind {
|
||||
TyKind::Infer => String::new(),
|
||||
TyKind::Ptr(mut_ty) => {
|
||||
if matches!(mut_ty.ty.kind, TyKind::Infer) {
|
||||
String::new()
|
||||
} else {
|
||||
format!(
|
||||
"::<{}>",
|
||||
snippet_with_applicability(cx, mut_ty.ty.span, "/* type */", &mut app)
|
||||
)
|
||||
}
|
||||
},
|
||||
_ => return,
|
||||
};
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
PTR_AS_PTR,
|
||||
expr.span,
|
||||
"`as` casting between raw pointers without changing its mutability",
|
||||
"try `pointer::cast`, a safer alternative",
|
||||
format!("{}.cast{turbofish}()", cast_expr_sugg.maybe_par()),
|
||||
app,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -203,6 +203,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
|||
crate::if_let_mutex::IF_LET_MUTEX_INFO,
|
||||
crate::if_not_else::IF_NOT_ELSE_INFO,
|
||||
crate::if_then_some_else_none::IF_THEN_SOME_ELSE_NONE_INFO,
|
||||
crate::ignored_unit_patterns::IGNORED_UNIT_PATTERNS_INFO,
|
||||
crate::implicit_hasher::IMPLICIT_HASHER_INFO,
|
||||
crate::implicit_return::IMPLICIT_RETURN_INFO,
|
||||
crate::implicit_saturating_add::IMPLICIT_SATURATING_ADD_INFO,
|
||||
|
|
@ -517,6 +518,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
|||
crate::operators::FLOAT_CMP_CONST_INFO,
|
||||
crate::operators::FLOAT_EQUALITY_WITHOUT_ABS_INFO,
|
||||
crate::operators::IDENTITY_OP_INFO,
|
||||
crate::operators::IMPOSSIBLE_COMPARISONS_INFO,
|
||||
crate::operators::INEFFECTIVE_BIT_MASK_INFO,
|
||||
crate::operators::INTEGER_DIVISION_INFO,
|
||||
crate::operators::MISREFACTORED_ASSIGN_OP_INFO,
|
||||
|
|
@ -525,6 +527,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
|||
crate::operators::NEEDLESS_BITWISE_BOOL_INFO,
|
||||
crate::operators::OP_REF_INFO,
|
||||
crate::operators::PTR_EQ_INFO,
|
||||
crate::operators::REDUNDANT_COMPARISONS_INFO,
|
||||
crate::operators::SELF_ASSIGNMENT_INFO,
|
||||
crate::operators::VERBOSE_BIT_MASK_INFO,
|
||||
crate::option_env_unwrap::OPTION_ENV_UNWRAP_INFO,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
use clippy_utils::diagnostics::{
|
||||
span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then,
|
||||
};
|
||||
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::ty::{implements_trait, implements_trait_with_env, is_copy};
|
||||
use clippy_utils::{is_lint_allowed, match_def_path, paths};
|
||||
use if_chain::if_chain;
|
||||
|
|
@ -8,15 +6,14 @@ use rustc_errors::Applicability;
|
|||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor};
|
||||
use rustc_hir::{
|
||||
self as hir, BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, Impl, Item, ItemKind,
|
||||
UnsafeSource, Unsafety,
|
||||
self as hir, BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, Impl, Item, ItemKind, UnsafeSource, Unsafety,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::traits::Reveal;
|
||||
use rustc_middle::ty::{
|
||||
self, ClauseKind, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv,
|
||||
ToPredicate, TraitPredicate, Ty, TyCtxt,
|
||||
self, ClauseKind, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv, ToPredicate, TraitPredicate, Ty,
|
||||
TyCtxt,
|
||||
};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
|
|
@ -207,10 +204,13 @@ declare_lint_pass!(Derive => [
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for Derive {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
|
||||
if let ItemKind::Impl(Impl { of_trait: Some(ref trait_ref), .. }) = item.kind {
|
||||
if let ItemKind::Impl(Impl {
|
||||
of_trait: Some(ref trait_ref),
|
||||
..
|
||||
}) = item.kind
|
||||
{
|
||||
let ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
|
||||
let is_automatically_derived =
|
||||
cx.tcx.has_attr(item.owner_id, sym::automatically_derived);
|
||||
let is_automatically_derived = cx.tcx.has_attr(item.owner_id, sym::automatically_derived);
|
||||
|
||||
check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived);
|
||||
check_ord_partial_ord(cx, item.span, trait_ref, ty, is_automatically_derived);
|
||||
|
|
@ -327,12 +327,7 @@ fn check_ord_partial_ord<'tcx>(
|
|||
}
|
||||
|
||||
/// Implementation of the `EXPL_IMPL_CLONE_ON_COPY` lint.
|
||||
fn check_copy_clone<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
item: &Item<'_>,
|
||||
trait_ref: &hir::TraitRef<'_>,
|
||||
ty: Ty<'tcx>,
|
||||
) {
|
||||
fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) {
|
||||
let clone_id = match cx.tcx.lang_items().clone_trait() {
|
||||
Some(id) if trait_ref.trait_def_id() == Some(id) => id,
|
||||
_ => return,
|
||||
|
|
@ -350,9 +345,10 @@ fn check_copy_clone<'tcx>(
|
|||
if !is_copy(cx, ty) {
|
||||
if ty_subs.non_erasable_generics().next().is_some() {
|
||||
let has_copy_impl = cx.tcx.all_local_trait_impls(()).get(©_id).map_or(false, |impls| {
|
||||
impls
|
||||
.iter()
|
||||
.any(|&id| matches!(cx.tcx.type_of(id).instantiate_identity().kind(), ty::Adt(adt, _) if ty_adt.did() == adt.did()))
|
||||
impls.iter().any(|&id| {
|
||||
matches!(cx.tcx.type_of(id).instantiate_identity().kind(), ty::Adt(adt, _)
|
||||
if ty_adt.did() == adt.did())
|
||||
})
|
||||
});
|
||||
if !has_copy_impl {
|
||||
return;
|
||||
|
|
@ -431,14 +427,7 @@ struct UnsafeVisitor<'a, 'tcx> {
|
|||
impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
|
||||
type NestedFilter = nested_filter::All;
|
||||
|
||||
fn visit_fn(
|
||||
&mut self,
|
||||
kind: FnKind<'tcx>,
|
||||
decl: &'tcx FnDecl<'_>,
|
||||
body_id: BodyId,
|
||||
_: Span,
|
||||
id: LocalDefId,
|
||||
) {
|
||||
fn visit_fn(&mut self, kind: FnKind<'tcx>, decl: &'tcx FnDecl<'_>, body_id: BodyId, _: Span, id: LocalDefId) {
|
||||
if self.has_unsafe {
|
||||
return;
|
||||
}
|
||||
|
|
@ -474,12 +463,7 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
|
|||
}
|
||||
|
||||
/// Implementation of the `DERIVE_PARTIAL_EQ_WITHOUT_EQ` lint.
|
||||
fn check_partial_eq_without_eq<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
span: Span,
|
||||
trait_ref: &hir::TraitRef<'_>,
|
||||
ty: Ty<'tcx>,
|
||||
) {
|
||||
fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) {
|
||||
if_chain! {
|
||||
if let ty::Adt(adt, args) = ty.kind();
|
||||
if cx.tcx.visibility(adt.did()).is_public();
|
||||
|
|
|
|||
|
|
@ -716,10 +716,7 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) {
|
|||
let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
|
||||
let fallback_bundle =
|
||||
rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false);
|
||||
let emitter = EmitterWriter::new(
|
||||
Box::new(io::sink()),
|
||||
fallback_bundle,
|
||||
);
|
||||
let emitter = EmitterWriter::new(Box::new(io::sink()), fallback_bundle);
|
||||
let handler = Handler::with_emitter(Box::new(emitter)).disable_warnings();
|
||||
let sess = ParseSess::with_span_handler(handler, sm);
|
||||
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ use rustc_hir::{BindingAnnotation, Expr, ExprKind, FnRetTy, Param, PatKind, QPat
|
|||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::{
|
||||
self, Binder, ClosureArgs, ClosureKind, EarlyBinder, FnSig, GenericArg, GenericArgKind,
|
||||
GenericArgsRef, ImplPolarity, List, Region, RegionKind, Ty, TypeVisitableExt, TypeckResults,
|
||||
self, Binder, ClosureArgs, ClosureKind, EarlyBinder, FnSig, GenericArg, GenericArgKind, GenericArgsRef,
|
||||
ImplPolarity, List, Region, RegionKind, Ty, TypeVisitableExt, TypeckResults,
|
||||
};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::symbol::sym;
|
||||
|
|
|
|||
52
src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs
Normal file
52
src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use hir::PatKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for usage of `_` in patterns of type `()`.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Matching with `()` explicitly instead of `_` outlines
|
||||
/// the fact that the pattern contains no data. Also it
|
||||
/// would detect a type change that `_` would ignore.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// match std::fs::create_dir("tmp-work-dir") {
|
||||
/// Ok(_) => println!("Working directory created"),
|
||||
/// Err(s) => eprintln!("Could not create directory: {s}"),
|
||||
/// }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// match std::fs::create_dir("tmp-work-dir") {
|
||||
/// Ok(()) => println!("Working directory created"),
|
||||
/// Err(s) => eprintln!("Could not create directory: {s}"),
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.73.0"]
|
||||
pub IGNORED_UNIT_PATTERNS,
|
||||
pedantic,
|
||||
"suggest replacing `_` by `()` in patterns where appropriate"
|
||||
}
|
||||
declare_lint_pass!(IgnoredUnitPatterns => [IGNORED_UNIT_PATTERNS]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for IgnoredUnitPatterns {
|
||||
fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx hir::Pat<'tcx>) {
|
||||
if matches!(pat.kind, PatKind::Wild) && cx.typeck_results().pat_ty(pat).is_unit() {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
IGNORED_UNIT_PATTERNS,
|
||||
pat.span,
|
||||
"matching over `()` is more explicit",
|
||||
"use `()` instead of `_`",
|
||||
String::from("()"),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -147,6 +147,7 @@ mod future_not_send;
|
|||
mod if_let_mutex;
|
||||
mod if_not_else;
|
||||
mod if_then_some_else_none;
|
||||
mod ignored_unit_patterns;
|
||||
mod implicit_hasher;
|
||||
mod implicit_return;
|
||||
mod implicit_saturating_add;
|
||||
|
|
@ -1093,6 +1094,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
})
|
||||
});
|
||||
store.register_late_pass(|_| Box::new(redundant_locals::RedundantLocals));
|
||||
store.register_late_pass(|_| Box::new(ignored_unit_patterns::IgnoredUnitPatterns));
|
||||
// add lints here, do not remove this comment, it's used in `new_lint`
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -162,7 +162,9 @@ fn never_loop_expr<'tcx>(
|
|||
ExprKind::Binary(_, e1, e2)
|
||||
| ExprKind::Assign(e1, e2, _)
|
||||
| ExprKind::AssignOp(_, e1, e2)
|
||||
| ExprKind::Index(e1, e2, _) => never_loop_expr_all(cx, &mut [e1, e2].iter().copied(), ignore_ids, main_loop_id),
|
||||
| ExprKind::Index(e1, e2, _) => {
|
||||
never_loop_expr_all(cx, &mut [e1, e2].iter().copied(), ignore_ids, main_loop_id)
|
||||
},
|
||||
ExprKind::Loop(b, _, _, _) => {
|
||||
// Break can come from the inner loop so remove them.
|
||||
absorb_break(never_loop_block(cx, b, ignore_ids, main_loop_id))
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
|
|||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
if !in_external_macro(cx.sess(), expr.span)
|
||||
&& (
|
||||
matches!(cx.tcx.constness(cx.tcx.hir().enclosing_body_owner(expr.hir_id)), Constness::NotConst)
|
||||
matches!(cx.tcx.constness(cx.tcx.hir().enclosing_body_owner(expr.hir_id)), Constness::NotConst)
|
||||
|| cx.tcx.features().active(sym!(const_float_classify))
|
||||
) && let ExprKind::Binary(kind, lhs, rhs) = expr.kind
|
||||
&& let ExprKind::Binary(lhs_kind, lhs_lhs, lhs_rhs) = lhs.kind
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
|
|||
use clippy_utils::path_to_local;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::visitors::{for_each_expr, is_local_used};
|
||||
use rustc_ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::{Arm, BinOpKind, Expr, ExprKind, Guard, MatchSource, Node, Pat, PatKind};
|
||||
|
|
@ -160,6 +161,11 @@ fn emit_redundant_guards<'tcx>(
|
|||
}
|
||||
|
||||
/// Checks if the given `Expr` can also be represented as a `Pat`.
|
||||
///
|
||||
/// All literals generally also work as patterns, however float literals are special.
|
||||
/// They are currently (as of 2023/08/08) still allowed in patterns, but that will become
|
||||
/// an error in the future, and rustc already actively warns against this (see rust#41620),
|
||||
/// so we don't consider those as usable within patterns for linting purposes.
|
||||
fn expr_can_be_pat(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
for_each_expr(expr, |expr| {
|
||||
if match expr.kind {
|
||||
|
|
@ -177,8 +183,8 @@ fn expr_can_be_pat(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
|||
ExprKind::AddrOf(..)
|
||||
| ExprKind::Array(..)
|
||||
| ExprKind::Tup(..)
|
||||
| ExprKind::Struct(..)
|
||||
| ExprKind::Lit(..) => true,
|
||||
| ExprKind::Struct(..) => true,
|
||||
ExprKind::Lit(lit) if !matches!(lit.node, LitKind::Float(..)) => true,
|
||||
_ => false,
|
||||
} {
|
||||
return ControlFlow::Continue(());
|
||||
|
|
|
|||
|
|
@ -1,44 +0,0 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{is_in_cfg_test, is_in_test_function};
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::sym;
|
||||
|
||||
use super::EXPECT_USED;
|
||||
|
||||
/// lint use of `expect()` or `expect_err` for `Result` and `expect()` for `Option`.
|
||||
pub(super) fn check(
|
||||
cx: &LateContext<'_>,
|
||||
expr: &hir::Expr<'_>,
|
||||
recv: &hir::Expr<'_>,
|
||||
is_err: bool,
|
||||
allow_expect_in_tests: bool,
|
||||
) {
|
||||
let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
|
||||
|
||||
let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) && !is_err {
|
||||
Some((EXPECT_USED, "an `Option`", "None", ""))
|
||||
} else if is_type_diagnostic_item(cx, obj_ty, sym::Result) {
|
||||
Some((EXPECT_USED, "a `Result`", if is_err { "Ok" } else { "Err" }, "an "))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let method = if is_err { "expect_err" } else { "expect" };
|
||||
|
||||
if allow_expect_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some((lint, kind, none_value, none_prefix)) = mess {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
lint,
|
||||
expr.span,
|
||||
&format!("used `{method}()` on {kind} value"),
|
||||
None,
|
||||
&format!("if this value is {none_prefix}`{none_value}`, it will panic"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
use super::FILTER_MAP_BOOL_THEN;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::paths::BOOL_THEN;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
|
|
@ -7,10 +8,9 @@ use rustc_errors::Applicability;
|
|||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty::Binder;
|
||||
use rustc_span::{sym, Span};
|
||||
|
||||
use super::FILTER_MAP_BOOL_THEN;
|
||||
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &Expr<'_>, call_span: Span) {
|
||||
if !in_external_macro(cx.sess(), expr.span)
|
||||
&& is_trait_method(cx, expr, sym::Iterator)
|
||||
|
|
@ -21,7 +21,15 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &
|
|||
// `inputs` and `params` here as we need both the type and the span
|
||||
&& let param_ty = closure.fn_decl.inputs[0]
|
||||
&& let param = body.params[0]
|
||||
&& is_copy(cx, cx.typeck_results().node_type(param_ty.hir_id).peel_refs())
|
||||
// Issue #11309
|
||||
&& let param_ty = cx.tcx.liberate_late_bound_regions(
|
||||
closure.def_id.to_def_id(),
|
||||
Binder::bind_with_vars(
|
||||
cx.typeck_results().node_type(param_ty.hir_id),
|
||||
cx.tcx.late_bound_vars(cx.tcx.hir().local_def_id_to_hir_id(closure.def_id)),
|
||||
),
|
||||
)
|
||||
&& is_copy(cx, param_ty)
|
||||
&& let ExprKind::MethodCall(_, recv, [then_arg], _) = value.kind
|
||||
&& let ExprKind::Closure(then_closure) = then_arg.kind
|
||||
&& let then_body = peel_blocks(cx.tcx.hir().body(then_closure.body).value)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ mod collapsible_str_replace;
|
|||
mod drain_collect;
|
||||
mod err_expect;
|
||||
mod expect_fun_call;
|
||||
mod expect_used;
|
||||
mod extend_with_drain;
|
||||
mod filetype_is_file;
|
||||
mod filter_map;
|
||||
|
|
@ -105,7 +104,7 @@ mod unnecessary_lazy_eval;
|
|||
mod unnecessary_literal_unwrap;
|
||||
mod unnecessary_sort_by;
|
||||
mod unnecessary_to_owned;
|
||||
mod unwrap_used;
|
||||
mod unwrap_expect_used;
|
||||
mod useless_asref;
|
||||
mod utils;
|
||||
mod vec_resize_to_zero;
|
||||
|
|
@ -3881,6 +3880,13 @@ impl Methods {
|
|||
unnecessary_lazy_eval::check(cx, expr, recv, arg, "and");
|
||||
}
|
||||
},
|
||||
("any", [arg]) if let ExprKind::Closure(arg) = arg.kind
|
||||
&& let body = cx.tcx.hir().body(arg.body)
|
||||
&& let [param] = body.params
|
||||
&& let Some(("chars", recv, _, _, _)) = method_call(recv) =>
|
||||
{
|
||||
string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv);
|
||||
}
|
||||
("arg", [arg]) => {
|
||||
suspicious_command_arg_space::check(cx, recv, arg, span);
|
||||
}
|
||||
|
|
@ -3941,13 +3947,27 @@ impl Methods {
|
|||
match method_call(recv) {
|
||||
Some(("ok", recv, [], _, _)) => ok_expect::check(cx, expr, recv),
|
||||
Some(("err", recv, [], err_span, _)) => err_expect::check(cx, expr, recv, span, err_span, &self.msrv),
|
||||
_ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests),
|
||||
_ => unwrap_expect_used::check(
|
||||
cx,
|
||||
expr,
|
||||
recv,
|
||||
false,
|
||||
self.allow_expect_in_tests,
|
||||
unwrap_expect_used::Variant::Expect,
|
||||
),
|
||||
}
|
||||
unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
|
||||
},
|
||||
("expect_err", [_]) => {
|
||||
unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
|
||||
expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests);
|
||||
unwrap_expect_used::check(
|
||||
cx,
|
||||
expr,
|
||||
recv,
|
||||
true,
|
||||
self.allow_expect_in_tests,
|
||||
unwrap_expect_used::Variant::Expect,
|
||||
);
|
||||
},
|
||||
("extend", [arg]) => {
|
||||
string_extend_chars::check(cx, expr, recv, arg);
|
||||
|
|
@ -3999,20 +4019,9 @@ impl Methods {
|
|||
unnecessary_join::check(cx, expr, recv, join_arg, span);
|
||||
}
|
||||
},
|
||||
("skip", [arg]) => {
|
||||
iter_skip_zero::check(cx, expr, arg);
|
||||
|
||||
if let Some((name2, recv2, args2, _span2, _)) = method_call(recv) {
|
||||
if let ("cloned", []) = (name2, args2) {
|
||||
iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
("last", []) => {
|
||||
if let Some((name2, recv2, args2, _span2, _)) = method_call(recv) {
|
||||
if let ("cloned", []) = (name2, args2) {
|
||||
iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
|
||||
}
|
||||
if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
|
||||
iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
|
||||
}
|
||||
},
|
||||
("lock", []) => {
|
||||
|
|
@ -4060,13 +4069,6 @@ impl Methods {
|
|||
}
|
||||
}
|
||||
},
|
||||
("any", [arg]) if let ExprKind::Closure(arg) = arg.kind
|
||||
&& let body = cx.tcx.hir().body(arg.body)
|
||||
&& let [param] = body.params
|
||||
&& let Some(("chars", recv, _, _, _)) = method_call(recv) =>
|
||||
{
|
||||
string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv);
|
||||
}
|
||||
("nth", [n_arg]) => match method_call(recv) {
|
||||
Some(("bytes", recv2, [], _, _)) => bytes_nth::check(cx, expr, recv2, n_arg),
|
||||
Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
|
||||
|
|
@ -4120,6 +4122,13 @@ impl Methods {
|
|||
seek_to_start_instead_of_rewind::check(cx, expr, recv, arg, span);
|
||||
}
|
||||
},
|
||||
("skip", [arg]) => {
|
||||
iter_skip_zero::check(cx, expr, arg);
|
||||
|
||||
if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
|
||||
iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
|
||||
}
|
||||
}
|
||||
("sort", []) => {
|
||||
stable_sort_primitive::check(cx, expr, recv);
|
||||
},
|
||||
|
|
@ -4142,10 +4151,8 @@ impl Methods {
|
|||
},
|
||||
("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
|
||||
("take", [_arg]) => {
|
||||
if let Some((name2, recv2, args2, _span2, _)) = method_call(recv) {
|
||||
if let ("cloned", []) = (name2, args2) {
|
||||
iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
|
||||
}
|
||||
if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
|
||||
iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
|
||||
}
|
||||
},
|
||||
("take", []) => needless_option_take::check(cx, expr, recv),
|
||||
|
|
@ -4180,11 +4187,25 @@ impl Methods {
|
|||
_ => {},
|
||||
}
|
||||
unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
|
||||
unwrap_used::check(cx, expr, recv, false, self.allow_unwrap_in_tests);
|
||||
unwrap_expect_used::check(
|
||||
cx,
|
||||
expr,
|
||||
recv,
|
||||
false,
|
||||
self.allow_unwrap_in_tests,
|
||||
unwrap_expect_used::Variant::Unwrap,
|
||||
);
|
||||
},
|
||||
("unwrap_err", []) => {
|
||||
unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
|
||||
unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests);
|
||||
unwrap_expect_used::check(
|
||||
cx,
|
||||
expr,
|
||||
recv,
|
||||
true,
|
||||
self.allow_unwrap_in_tests,
|
||||
unwrap_expect_used::Variant::Unwrap,
|
||||
);
|
||||
},
|
||||
("unwrap_or", [u_arg]) => {
|
||||
match method_call(recv) {
|
||||
|
|
@ -4214,6 +4235,9 @@ impl Methods {
|
|||
}
|
||||
unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
|
||||
},
|
||||
("write", []) => {
|
||||
readonly_write_lock::check(cx, expr, recv);
|
||||
}
|
||||
("zip", [arg]) => {
|
||||
if let ExprKind::MethodCall(name, iter_recv, [], _) = recv.kind
|
||||
&& name.ident.name == sym::iter
|
||||
|
|
@ -4221,9 +4245,6 @@ impl Methods {
|
|||
range_zip_with_len::check(cx, expr, iter_recv, arg);
|
||||
}
|
||||
},
|
||||
("write", []) => {
|
||||
readonly_write_lock::check(cx, expr, recv);
|
||||
}
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,83 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::ty::{is_never_like, is_type_diagnostic_item};
|
||||
use clippy_utils::{is_in_cfg_test, is_in_test_function, is_lint_allowed};
|
||||
use rustc_hir::Expr;
|
||||
use rustc_lint::{LateContext, Lint};
|
||||
use rustc_middle::ty;
|
||||
use rustc_span::sym;
|
||||
|
||||
use super::{EXPECT_USED, UNWRAP_USED};
|
||||
|
||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||
pub(super) enum Variant {
|
||||
Unwrap,
|
||||
Expect,
|
||||
}
|
||||
|
||||
impl Variant {
|
||||
fn method_name(self, is_err: bool) -> &'static str {
|
||||
match (self, is_err) {
|
||||
(Variant::Unwrap, true) => "unwrap_err",
|
||||
(Variant::Unwrap, false) => "unwrap",
|
||||
(Variant::Expect, true) => "expect_err",
|
||||
(Variant::Expect, false) => "expect",
|
||||
}
|
||||
}
|
||||
|
||||
fn lint(self) -> &'static Lint {
|
||||
match self {
|
||||
Variant::Unwrap => UNWRAP_USED,
|
||||
Variant::Expect => EXPECT_USED,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Lint usage of `unwrap` or `unwrap_err` for `Result` and `unwrap()` for `Option` (and their
|
||||
/// `expect` counterparts).
|
||||
pub(super) fn check(
|
||||
cx: &LateContext<'_>,
|
||||
expr: &Expr<'_>,
|
||||
recv: &Expr<'_>,
|
||||
is_err: bool,
|
||||
allow_unwrap_in_tests: bool,
|
||||
variant: Variant,
|
||||
) {
|
||||
let ty = cx.typeck_results().expr_ty(recv).peel_refs();
|
||||
|
||||
let (kind, none_value, none_prefix) = if is_type_diagnostic_item(cx, ty, sym::Option) && !is_err {
|
||||
("an `Option`", "None", "")
|
||||
} else if is_type_diagnostic_item(cx, ty, sym::Result)
|
||||
&& let ty::Adt(_, substs) = ty.kind()
|
||||
&& let Some(t_or_e_ty) = substs[usize::from(!is_err)].as_type()
|
||||
{
|
||||
if is_never_like(t_or_e_ty) {
|
||||
return;
|
||||
}
|
||||
|
||||
("a `Result`", if is_err { "Ok" } else { "Err" }, "an ")
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
||||
let method_suffix = if is_err { "_err" } else { "" };
|
||||
|
||||
if allow_unwrap_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
variant.lint(),
|
||||
expr.span,
|
||||
&format!("used `{}()` on {kind} value", variant.method_name(is_err)),
|
||||
|diag| {
|
||||
diag.note(format!("if this value is {none_prefix}`{none_value}`, it will panic"));
|
||||
|
||||
if variant == Variant::Unwrap && is_lint_allowed(cx, EXPECT_USED, expr.hir_id) {
|
||||
diag.help(format!(
|
||||
"consider using `expect{method_suffix}()` to provide a better panic message"
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{is_in_cfg_test, is_in_test_function, is_lint_allowed};
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::sym;
|
||||
|
||||
use super::{EXPECT_USED, UNWRAP_USED};
|
||||
|
||||
/// lint use of `unwrap()` or `unwrap_err` for `Result` and `unwrap()` for `Option`.
|
||||
pub(super) fn check(
|
||||
cx: &LateContext<'_>,
|
||||
expr: &hir::Expr<'_>,
|
||||
recv: &hir::Expr<'_>,
|
||||
is_err: bool,
|
||||
allow_unwrap_in_tests: bool,
|
||||
) {
|
||||
let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
|
||||
|
||||
let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) && !is_err {
|
||||
Some((UNWRAP_USED, "an `Option`", "None", ""))
|
||||
} else if is_type_diagnostic_item(cx, obj_ty, sym::Result) {
|
||||
Some((UNWRAP_USED, "a `Result`", if is_err { "Ok" } else { "Err" }, "an "))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let method_suffix = if is_err { "_err" } else { "" };
|
||||
|
||||
if allow_unwrap_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some((lint, kind, none_value, none_prefix)) = mess {
|
||||
let help = if is_lint_allowed(cx, EXPECT_USED, expr.hir_id) {
|
||||
format!(
|
||||
"if you don't want to handle the `{none_value}` case gracefully, consider \
|
||||
using `expect{method_suffix}()` to provide a better panic message"
|
||||
)
|
||||
} else {
|
||||
format!("if this value is {none_prefix}`{none_value}`, it will panic")
|
||||
};
|
||||
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
lint,
|
||||
expr.span,
|
||||
&format!("used `unwrap{method_suffix}()` on {kind} value"),
|
||||
None,
|
||||
&help,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -74,7 +74,6 @@ fn is_executable_or_proc_macro(cx: &LateContext<'_>) -> bool {
|
|||
use rustc_session::config::CrateType;
|
||||
|
||||
cx.tcx
|
||||
.sess
|
||||
.crate_types()
|
||||
.iter()
|
||||
.any(|t: &CrateType| matches!(t, CrateType::Executable | CrateType::ProcMacro))
|
||||
|
|
|
|||
|
|
@ -37,6 +37,11 @@ declare_lint_pass!(UnnecessaryMutPassed => [UNNECESSARY_MUT_PASSED]);
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
|
||||
if e.span.from_expansion() {
|
||||
// Issue #11268
|
||||
return;
|
||||
}
|
||||
|
||||
match e.kind {
|
||||
ExprKind::Call(fn_expr, arguments) => {
|
||||
if let ExprKind::Path(ref path) = fn_expr.kind {
|
||||
|
|
|
|||
207
src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs
Normal file
207
src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
#![allow(clippy::match_same_arms)]
|
||||
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::layout::HasTyCtxt;
|
||||
use rustc_middle::ty::{Ty, TypeckResults};
|
||||
use rustc_span::source_map::{Span, Spanned};
|
||||
|
||||
use clippy_utils::diagnostics::span_lint_and_note;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::SpanlessEq;
|
||||
|
||||
use super::{IMPOSSIBLE_COMPARISONS, REDUNDANT_COMPARISONS};
|
||||
|
||||
// Extract a comparison between a const and non-const
|
||||
// Flip yoda conditionals, turnings expressions like `42 < x` into `x > 42`
|
||||
fn comparison_to_const<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
typeck: &TypeckResults<'tcx>,
|
||||
expr: &'tcx Expr<'tcx>,
|
||||
) -> Option<(CmpOp, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>, Constant<'tcx>, Ty<'tcx>)> {
|
||||
if_chain! {
|
||||
if let ExprKind::Binary(operator, left, right) = expr.kind;
|
||||
if let Ok(cmp_op) = CmpOp::try_from(operator.node);
|
||||
then {
|
||||
match (constant(cx, typeck, left), constant(cx, typeck, right)) {
|
||||
(Some(_), Some(_)) => None,
|
||||
(_, Some(con)) => Some((cmp_op, left, right, con, typeck.expr_ty(right))),
|
||||
(Some(con), _) => Some((cmp_op.reverse(), right, left, con, typeck.expr_ty(left))),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
and_op: Spanned<BinOpKind>,
|
||||
left_cond: &'tcx Expr<'tcx>,
|
||||
right_cond: &'tcx Expr<'tcx>,
|
||||
span: Span,
|
||||
) {
|
||||
if_chain! {
|
||||
// Ensure that the binary operator is &&
|
||||
if and_op.node == BinOpKind::And;
|
||||
|
||||
// Check that both operands to '&&' are themselves a binary operation
|
||||
// The `comparison_to_const` step also checks this, so this step is just an optimization
|
||||
if let ExprKind::Binary(_, _, _) = left_cond.kind;
|
||||
if let ExprKind::Binary(_, _, _) = right_cond.kind;
|
||||
|
||||
let typeck = cx.typeck_results();
|
||||
|
||||
// Check that both operands to '&&' compare a non-literal to a literal
|
||||
if let Some((left_cmp_op, left_expr, left_const_expr, left_const, left_type)) =
|
||||
comparison_to_const(cx, typeck, left_cond);
|
||||
if let Some((right_cmp_op, right_expr, right_const_expr, right_const, right_type)) =
|
||||
comparison_to_const(cx, typeck, right_cond);
|
||||
|
||||
if left_type == right_type;
|
||||
|
||||
// Check that the same expression is compared in both comparisons
|
||||
if SpanlessEq::new(cx).eq_expr(left_expr, right_expr);
|
||||
|
||||
if !left_expr.can_have_side_effects();
|
||||
|
||||
// Compare the two constant expressions
|
||||
if let Some(ordering) = Constant::partial_cmp(cx.tcx(), left_type, &left_const, &right_const);
|
||||
|
||||
// Rule out the `x >= 42 && x <= 42` corner case immediately
|
||||
// Mostly to simplify the implementation, but it is also covered by `clippy::double_comparisons`
|
||||
if !matches!(
|
||||
(&left_cmp_op, &right_cmp_op, ordering),
|
||||
(CmpOp::Le | CmpOp::Ge, CmpOp::Le | CmpOp::Ge, Ordering::Equal)
|
||||
);
|
||||
|
||||
then {
|
||||
if left_cmp_op.direction() == right_cmp_op.direction() {
|
||||
let lhs_str = snippet(cx, left_cond.span, "<lhs>");
|
||||
let rhs_str = snippet(cx, right_cond.span, "<rhs>");
|
||||
// We already know that either side of `&&` has no effect,
|
||||
// but emit a different error message depending on which side it is
|
||||
if left_side_is_useless(left_cmp_op, ordering) {
|
||||
span_lint_and_note(
|
||||
cx,
|
||||
REDUNDANT_COMPARISONS,
|
||||
span,
|
||||
"left-hand side of `&&` operator has no effect",
|
||||
Some(left_cond.span.until(right_cond.span)),
|
||||
&format!("`if `{rhs_str}` evaluates to true, {lhs_str}` will always evaluate to true as well"),
|
||||
);
|
||||
} else {
|
||||
span_lint_and_note(
|
||||
cx,
|
||||
REDUNDANT_COMPARISONS,
|
||||
span,
|
||||
"right-hand side of `&&` operator has no effect",
|
||||
Some(and_op.span.to(right_cond.span)),
|
||||
&format!("`if `{lhs_str}` evaluates to true, {rhs_str}` will always evaluate to true as well"),
|
||||
);
|
||||
}
|
||||
// We could autofix this error but choose not to,
|
||||
// because code triggering this lint probably not behaving correctly in the first place
|
||||
}
|
||||
else if !comparison_is_possible(left_cmp_op.direction(), ordering) {
|
||||
let expr_str = snippet(cx, left_expr.span, "..");
|
||||
let lhs_str = snippet(cx, left_const_expr.span, "<lhs>");
|
||||
let rhs_str = snippet(cx, right_const_expr.span, "<rhs>");
|
||||
let note = match ordering {
|
||||
Ordering::Less => format!("since `{lhs_str}` < `{rhs_str}`, the expression evaluates to false for any value of `{expr_str}`"),
|
||||
Ordering::Equal => format!("`{expr_str}` cannot simultaneously be greater than and less than `{lhs_str}`"),
|
||||
Ordering::Greater => format!("since `{lhs_str}` > `{rhs_str}`, the expression evaluates to false for any value of `{expr_str}`"),
|
||||
};
|
||||
span_lint_and_note(
|
||||
cx,
|
||||
IMPOSSIBLE_COMPARISONS,
|
||||
span,
|
||||
"boolean expression will never evaluate to 'true'",
|
||||
None,
|
||||
¬e,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn left_side_is_useless(left_cmp_op: CmpOp, ordering: Ordering) -> bool {
|
||||
// Special-case for equal constants with an inclusive comparison
|
||||
if ordering == Ordering::Equal {
|
||||
match left_cmp_op {
|
||||
CmpOp::Lt | CmpOp::Gt => false,
|
||||
CmpOp::Le | CmpOp::Ge => true,
|
||||
}
|
||||
} else {
|
||||
match (left_cmp_op.direction(), ordering) {
|
||||
(CmpOpDirection::Lesser, Ordering::Less) => false,
|
||||
(CmpOpDirection::Lesser, Ordering::Equal) => false,
|
||||
(CmpOpDirection::Lesser, Ordering::Greater) => true,
|
||||
(CmpOpDirection::Greater, Ordering::Less) => true,
|
||||
(CmpOpDirection::Greater, Ordering::Equal) => false,
|
||||
(CmpOpDirection::Greater, Ordering::Greater) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn comparison_is_possible(left_cmp_direction: CmpOpDirection, ordering: Ordering) -> bool {
|
||||
match (left_cmp_direction, ordering) {
|
||||
(CmpOpDirection::Lesser, Ordering::Less | Ordering::Equal) => false,
|
||||
(CmpOpDirection::Lesser, Ordering::Greater) => true,
|
||||
(CmpOpDirection::Greater, Ordering::Greater | Ordering::Equal) => false,
|
||||
(CmpOpDirection::Greater, Ordering::Less) => true,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||
enum CmpOpDirection {
|
||||
Lesser,
|
||||
Greater,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum CmpOp {
|
||||
Lt,
|
||||
Le,
|
||||
Ge,
|
||||
Gt,
|
||||
}
|
||||
|
||||
impl CmpOp {
|
||||
fn reverse(self) -> Self {
|
||||
match self {
|
||||
CmpOp::Lt => CmpOp::Gt,
|
||||
CmpOp::Le => CmpOp::Ge,
|
||||
CmpOp::Ge => CmpOp::Le,
|
||||
CmpOp::Gt => CmpOp::Lt,
|
||||
}
|
||||
}
|
||||
|
||||
fn direction(self) -> CmpOpDirection {
|
||||
match self {
|
||||
CmpOp::Lt => CmpOpDirection::Lesser,
|
||||
CmpOp::Le => CmpOpDirection::Lesser,
|
||||
CmpOp::Ge => CmpOpDirection::Greater,
|
||||
CmpOp::Gt => CmpOpDirection::Greater,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<BinOpKind> for CmpOp {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(bin_op: BinOpKind) -> Result<Self, Self::Error> {
|
||||
match bin_op {
|
||||
BinOpKind::Lt => Ok(CmpOp::Lt),
|
||||
BinOpKind::Le => Ok(CmpOp::Le),
|
||||
BinOpKind::Ge => Ok(CmpOp::Ge),
|
||||
BinOpKind::Gt => Ok(CmpOp::Gt),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ mod absurd_extreme_comparisons;
|
|||
mod assign_op_pattern;
|
||||
mod bit_mask;
|
||||
mod cmp_owned;
|
||||
mod const_comparisons;
|
||||
mod double_comparison;
|
||||
mod duration_subsec;
|
||||
mod eq_op;
|
||||
|
|
@ -298,6 +299,45 @@ declare_clippy_lint! {
|
|||
"unnecessary double comparisons that can be simplified"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for double comparisons that can never succeed
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// The whole expression can be replaced by `false`,
|
||||
/// which is probably not the programmer's intention
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// # let status_code = 200;
|
||||
/// if status_code <= 400 && status_code > 500 {}
|
||||
/// ```
|
||||
#[clippy::version = "1.71.0"]
|
||||
pub IMPOSSIBLE_COMPARISONS,
|
||||
correctness,
|
||||
"double comparisons that will never evaluate to `true`"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for ineffective double comparisons against constants.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Only one of the comparisons has any effect on the result, the programmer
|
||||
/// probably intended to flip one of the comparison operators, or compare a
|
||||
/// different value entirely.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// # let status_code = 200;
|
||||
/// if status_code <= 400 && status_code < 500 {}
|
||||
/// ```
|
||||
#[clippy::version = "1.71.0"]
|
||||
pub REDUNDANT_COMPARISONS,
|
||||
correctness,
|
||||
"double comparisons where one of them can be removed"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for calculation of subsecond microseconds or milliseconds
|
||||
|
|
@ -742,6 +782,8 @@ impl_lint_pass!(Operators => [
|
|||
INEFFECTIVE_BIT_MASK,
|
||||
VERBOSE_BIT_MASK,
|
||||
DOUBLE_COMPARISONS,
|
||||
IMPOSSIBLE_COMPARISONS,
|
||||
REDUNDANT_COMPARISONS,
|
||||
DURATION_SUBSEC,
|
||||
EQ_OP,
|
||||
OP_REF,
|
||||
|
|
@ -786,6 +828,7 @@ impl<'tcx> LateLintPass<'tcx> for Operators {
|
|||
bit_mask::check(cx, e, op.node, lhs, rhs);
|
||||
verbose_bit_mask::check(cx, e, op.node, lhs, rhs, self.verbose_bit_mask_threshold);
|
||||
double_comparison::check(cx, op.node, lhs, rhs, e.span);
|
||||
const_comparisons::check(cx, op, lhs, rhs, e.span);
|
||||
duration_subsec::check(cx, e, op.node, lhs, rhs);
|
||||
float_equality_without_abs::check(cx, e, op.node, lhs, rhs);
|
||||
integer_division::check(cx, e, op.node, lhs, rhs);
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ fn try_get_option_occurrence<'tcx>(
|
|||
});
|
||||
if let ExprKind::Path(QPath::Resolved(None, Path { res: Res::Local(local_id), .. })) = e.kind {
|
||||
match some_captures.get(local_id)
|
||||
.or_else(|| (method_sugg == "map_or_else").then_some(()).and_then(|_| none_captures.get(local_id)))
|
||||
.or_else(|| (method_sugg == "map_or_else").then_some(()).and_then(|()| none_captures.get(local_id)))
|
||||
{
|
||||
Some(CaptureKind::Value | CaptureKind::Ref(Mutability::Mut)) => return None,
|
||||
Some(CaptureKind::Ref(Mutability::Not)) if as_mut => return None,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
use crate::manual_let_else::{MatchLintBehaviour, MANUAL_LET_ELSE};
|
||||
use crate::question_mark_used::QUESTION_MARK_USED;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::msrvs::Msrv;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{
|
||||
eq_expr_value, get_parent_node, higher, in_constant, is_else_clause, is_path_lang_item, is_res_lang_ctor,
|
||||
pat_and_expr_can_be_question_mark, path_to_local, path_to_local_id, peel_blocks, peel_blocks_with_stmt,
|
||||
eq_expr_value, get_parent_node, higher, in_constant, is_else_clause, is_lint_allowed, is_path_lang_item,
|
||||
is_res_lang_ctor, pat_and_expr_can_be_question_mark, path_to_local, path_to_local_id, peel_blocks,
|
||||
peel_blocks_with_stmt,
|
||||
};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
|
|
@ -299,13 +301,17 @@ fn is_try_block(cx: &LateContext<'_>, bl: &rustc_hir::Block<'_>) -> bool {
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for QuestionMark {
|
||||
fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
|
||||
if !is_lint_allowed(cx, QUESTION_MARK_USED, stmt.hir_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if !in_constant(cx, stmt.hir_id) {
|
||||
check_let_some_else_return_none(cx, stmt);
|
||||
}
|
||||
self.check_manual_let_else(cx, stmt);
|
||||
}
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if !in_constant(cx, expr.hir_id) {
|
||||
if !in_constant(cx, expr.hir_id) && is_lint_allowed(cx, QUESTION_MARK_USED, expr.hir_id) {
|
||||
self.check_is_none_or_err_and_early_return(cx, expr);
|
||||
self.check_if_let_some_or_err_and_early_return(cx, expr);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::is_from_proc_macro;
|
||||
use clippy_utils::ty::needs_ordered_drop;
|
||||
use rustc_ast::Mutability;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::{
|
||||
BindingAnnotation, ByRef, Expr, ExprKind, HirId, Local, Node, Pat, PatKind, QPath,
|
||||
|
|
@ -9,6 +10,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext};
|
|||
use rustc_middle::lint::{in_external_macro, is_from_async_await};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::DesugaringKind;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
|
@ -47,6 +49,7 @@ declare_lint_pass!(RedundantLocals => [REDUNDANT_LOCALS]);
|
|||
impl<'tcx> LateLintPass<'tcx> for RedundantLocals {
|
||||
fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
|
||||
if_chain! {
|
||||
if !local.span.is_desugaring(DesugaringKind::Async);
|
||||
// the pattern is a single by-value binding
|
||||
if let PatKind::Binding(BindingAnnotation(ByRef::No, mutability), _, ident, None) = local.pat.kind;
|
||||
// the binding is not type-ascribed
|
||||
|
|
@ -62,6 +65,8 @@ impl<'tcx> LateLintPass<'tcx> for RedundantLocals {
|
|||
if let Node::Pat(binding_pat) = cx.tcx.hir().get(binding_id);
|
||||
// the previous binding has the same mutability
|
||||
if find_binding(binding_pat, ident).unwrap().1 == mutability;
|
||||
// the local does not change the effect of assignments to the binding. see #11290
|
||||
if !affects_assignments(cx, mutability, binding_id, local.hir_id);
|
||||
// the local does not affect the code's drop behavior
|
||||
if !affects_drop_behavior(cx, binding_id, local.hir_id, expr);
|
||||
// the local is user-controlled
|
||||
|
|
@ -97,6 +102,14 @@ fn find_binding(pat: &Pat<'_>, name: Ident) -> Option<BindingAnnotation> {
|
|||
ret
|
||||
}
|
||||
|
||||
/// Check if a rebinding of a local changes the effect of assignments to the binding.
|
||||
fn affects_assignments(cx: &LateContext<'_>, mutability: Mutability, bind: HirId, rebind: HirId) -> bool {
|
||||
let hir = cx.tcx.hir();
|
||||
|
||||
// the binding is mutable and the rebinding is in a different scope than the original binding
|
||||
mutability == Mutability::Mut && hir.get_enclosing_scope(bind) != hir.get_enclosing_scope(rebind)
|
||||
}
|
||||
|
||||
/// Check if a rebinding of a local affects the code's drop behavior.
|
||||
fn affects_drop_behavior<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::is_lint_allowed;
|
||||
use rustc_ast::LitKind;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
|
@ -45,8 +47,8 @@ fn is_same_type<'tcx>(cx: &LateContext<'tcx>, ty_resolved_path: hir::def::Res, f
|
|||
return primty.name() == func_return_type_sym;
|
||||
}
|
||||
|
||||
// type annotation is any other non generic type
|
||||
if let hir::def::Res::Def(_, defid) = ty_resolved_path
|
||||
// type annotation is a non generic type
|
||||
if let hir::def::Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum, defid) = ty_resolved_path
|
||||
&& let Some(annotation_ty) = cx.tcx.type_of(defid).no_bound_vars()
|
||||
{
|
||||
return annotation_ty == func_return_type;
|
||||
|
|
@ -130,8 +132,9 @@ fn extract_primty(ty_kind: &hir::TyKind<'_>) -> Option<hir::PrimTy> {
|
|||
|
||||
impl LateLintPass<'_> for RedundantTypeAnnotations {
|
||||
fn check_local<'tcx>(&mut self, cx: &LateContext<'tcx>, local: &'tcx rustc_hir::Local<'tcx>) {
|
||||
// type annotation part
|
||||
if !local.span.from_expansion()
|
||||
if !is_lint_allowed(cx, REDUNDANT_TYPE_ANNOTATIONS, local.hir_id)
|
||||
// type annotation part
|
||||
&& !local.span.from_expansion()
|
||||
&& let Some(ty) = &local.ty
|
||||
|
||||
// initialization part
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue