Auto merge of - matthiaskrgr:rollup-djsi6jr, r=matthiaskrgr

Rollup of 8 pull requests

Successful merges:

 -  (rustc_lint: Some early linting refactorings)
 -  (Implement RFC 3151: Scoped threads.)
 -  (Fix `let_chains` and `if_let_guard` feature flags)
 -  (Add preliminary support for inline assembly for msp430.)
 -  (Normalize field access types during borrowck)
 -  (Liberate late bound regions when collecting GAT substs in wfcheck)
 -  (Remove DiagnosticBuilder.quiet)
 -  (rustc_mir_itertools: Avoid needless `collect` with itertools)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2022-01-23 23:09:23 +00:00
commit 42313dd29b
66 changed files with 1146 additions and 340 deletions

View file

@ -758,6 +758,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
}, },
ProjectionElem::Field(field, fty) => { ProjectionElem::Field(field, fty) => {
let fty = self.sanitize_type(place, fty); let fty = self.sanitize_type(place, fty);
let fty = self.cx.normalize(fty, location);
match self.field_ty(place, base, field, location) { match self.field_ty(place, base, field, location) {
Ok(ty) => { Ok(ty) => {
let ty = self.cx.normalize(ty, location); let ty = self.cx.normalize(ty, location);

View file

@ -560,6 +560,7 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => unimplemented!(), InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => unimplemented!(),
InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => unimplemented!(), InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => unimplemented!(),
InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => unimplemented!(), InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => unimplemented!(),
InlineAsmRegClass::Msp430(_) => unimplemented!(),
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => unimplemented!(), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => unimplemented!(),
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => unimplemented!(), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => unimplemented!(),
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => unimplemented!(), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => unimplemented!(),
@ -622,6 +623,7 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(), InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(),
InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => cx.type_i32(), InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => cx.type_i32(),
InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => cx.type_f32(), InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => cx.type_f32(),
InlineAsmRegClass::Msp430(_) => unimplemented!(),
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(),
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => cx.type_i32(), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => cx.type_i32(),
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => cx.type_i64(), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => cx.type_i64(),
@ -729,6 +731,7 @@ fn modifier_to_gcc(arch: InlineAsmArch, reg: InlineAsmRegClass, modifier: Option
InlineAsmRegClass::Bpf(_) => unimplemented!(), InlineAsmRegClass::Bpf(_) => unimplemented!(),
InlineAsmRegClass::Hexagon(_) => unimplemented!(), InlineAsmRegClass::Hexagon(_) => unimplemented!(),
InlineAsmRegClass::Mips(_) => unimplemented!(), InlineAsmRegClass::Mips(_) => unimplemented!(),
InlineAsmRegClass::Msp430(_) => unimplemented!(),
InlineAsmRegClass::Nvptx(_) => unimplemented!(), InlineAsmRegClass::Nvptx(_) => unimplemented!(),
InlineAsmRegClass::PowerPC(_) => unimplemented!(), InlineAsmRegClass::PowerPC(_) => unimplemented!(),
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg)

View file

@ -232,6 +232,9 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
InlineAsmArch::SpirV => {} InlineAsmArch::SpirV => {}
InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {} InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {}
InlineAsmArch::Bpf => {} InlineAsmArch::Bpf => {}
InlineAsmArch::Msp430 => {
constraints.push("~{sr}".to_string());
}
} }
} }
if !options.contains(InlineAsmOptions::NOMEM) { if !options.contains(InlineAsmOptions::NOMEM) {
@ -580,6 +583,7 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) ->
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => "e", InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => "e",
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r", InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r",
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f", InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f",
InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => "r",
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
bug!("LLVM backend does not support SPIR-V") bug!("LLVM backend does not support SPIR-V")
} }
@ -666,6 +670,7 @@ fn modifier_to_llvm(
}, },
InlineAsmRegClass::Avr(_) => None, InlineAsmRegClass::Avr(_) => None,
InlineAsmRegClass::S390x(_) => None, InlineAsmRegClass::S390x(_) => None,
InlineAsmRegClass::Msp430(_) => None,
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
bug!("LLVM backend does not support SPIR-V") bug!("LLVM backend does not support SPIR-V")
} }
@ -734,6 +739,7 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &'
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => cx.type_i16(), InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => cx.type_i16(),
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => cx.type_i32(), InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => cx.type_i32(),
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(), InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(),
InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => cx.type_i16(),
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
bug!("LLVM backend does not support SPIR-V") bug!("LLVM backend does not support SPIR-V")
} }

View file

@ -445,9 +445,6 @@ struct HandlerInner {
deduplicated_warn_count: usize, deduplicated_warn_count: usize,
future_breakage_diagnostics: Vec<Diagnostic>, future_breakage_diagnostics: Vec<Diagnostic>,
/// If set to `true`, no warning or error will be emitted.
quiet: bool,
} }
/// A key denoting where from a diagnostic was stashed. /// A key denoting where from a diagnostic was stashed.
@ -563,19 +560,10 @@ impl Handler {
emitted_diagnostics: Default::default(), emitted_diagnostics: Default::default(),
stashed_diagnostics: Default::default(), stashed_diagnostics: Default::default(),
future_breakage_diagnostics: Vec::new(), future_breakage_diagnostics: Vec::new(),
quiet: false,
}), }),
} }
} }
pub fn with_disabled_diagnostic<T, F: FnOnce() -> T>(&self, f: F) -> T {
let prev = self.inner.borrow_mut().quiet;
self.inner.borrow_mut().quiet = true;
let ret = f();
self.inner.borrow_mut().quiet = prev;
ret
}
// This is here to not allow mutation of flags; // This is here to not allow mutation of flags;
// as of this writing it's only used in tests in librustc_middle. // as of this writing it's only used in tests in librustc_middle.
pub fn can_emit_warnings(&self) -> bool { pub fn can_emit_warnings(&self) -> bool {
@ -946,7 +934,7 @@ impl HandlerInner {
} }
fn emit_diagnostic(&mut self, diagnostic: &Diagnostic) { fn emit_diagnostic(&mut self, diagnostic: &Diagnostic) {
if diagnostic.cancelled() || self.quiet { if diagnostic.cancelled() {
return; return;
} }
@ -1170,9 +1158,6 @@ impl HandlerInner {
} }
fn delay_as_bug(&mut self, diagnostic: Diagnostic) { fn delay_as_bug(&mut self, diagnostic: Diagnostic) {
if self.quiet {
return;
}
if self.flags.report_delayed_bugs { if self.flags.report_delayed_bugs {
self.emit_diagnostic(&diagnostic); self.emit_diagnostic(&diagnostic);
} }

View file

@ -8,7 +8,7 @@ use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream};
use rustc_ast::visit::{AssocCtxt, Visitor}; use rustc_ast::visit::{AssocCtxt, Visitor};
use rustc_ast::{self as ast, AstLike, Attribute, Item, NodeId, PatKind}; use rustc_ast::{self as ast, AstLike, Attribute, Item, NodeId, PatKind};
use rustc_attr::{self as attr, Deprecation, Stability}; use rustc_attr::{self as attr, Deprecation, Stability};
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::{self, Lrc}; use rustc_data_structures::sync::{self, Lrc};
use rustc_errors::{Applicability, DiagnosticBuilder, ErrorReported}; use rustc_errors::{Applicability, DiagnosticBuilder, ErrorReported};
use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT; use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT;
@ -920,8 +920,25 @@ pub trait ResolverExpand {
/// we generated proc macros harnesses, so that we can map /// we generated proc macros harnesses, so that we can map
/// HIR proc macros items back to their harness items. /// HIR proc macros items back to their harness items.
fn declare_proc_macro(&mut self, id: NodeId); fn declare_proc_macro(&mut self, id: NodeId);
/// Tools registered with `#![register_tool]` and used by tool attributes and lints.
fn registered_tools(&self) -> &FxHashSet<Ident>;
} }
pub trait LintStoreExpand {
fn pre_expansion_lint(
&self,
sess: &Session,
registered_tools: &FxHashSet<Ident>,
node_id: NodeId,
attrs: &[Attribute],
items: &[P<Item>],
name: &str,
);
}
type LintStoreExpandDyn<'a> = Option<&'a (dyn LintStoreExpand + 'a)>;
#[derive(Clone, Default)] #[derive(Clone, Default)]
pub struct ModuleData { pub struct ModuleData {
/// Path to the module starting from the crate name, like `my_crate::foo::bar`. /// Path to the module starting from the crate name, like `my_crate::foo::bar`.
@ -956,9 +973,6 @@ pub struct ExpansionData {
pub is_trailing_mac: bool, pub is_trailing_mac: bool,
} }
type OnExternModLoaded<'a> =
Option<&'a dyn Fn(Ident, Vec<Attribute>, Vec<P<Item>>, Span) -> (Vec<Attribute>, Vec<P<Item>>)>;
/// One of these is made during expansion and incrementally updated as we go; /// One of these is made during expansion and incrementally updated as we go;
/// when a macro expansion occurs, the resulting nodes have the `backtrace() /// when a macro expansion occurs, the resulting nodes have the `backtrace()
/// -> expn_data` of their expansion context stored into their span. /// -> expn_data` of their expansion context stored into their span.
@ -973,10 +987,8 @@ pub struct ExtCtxt<'a> {
/// (or during eager expansion, but that's a hack). /// (or during eager expansion, but that's a hack).
pub force_mode: bool, pub force_mode: bool,
pub expansions: FxHashMap<Span, Vec<String>>, pub expansions: FxHashMap<Span, Vec<String>>,
/// Called directly after having parsed an external `mod foo;` in expansion. /// Used for running pre-expansion lints on freshly loaded modules.
/// pub(super) lint_store: LintStoreExpandDyn<'a>,
/// `Ident` is the module name.
pub(super) extern_mod_loaded: OnExternModLoaded<'a>,
/// When we 'expand' an inert attribute, we leave it /// When we 'expand' an inert attribute, we leave it
/// in the AST, but insert it here so that we know /// in the AST, but insert it here so that we know
/// not to expand it again. /// not to expand it again.
@ -988,14 +1000,14 @@ impl<'a> ExtCtxt<'a> {
sess: &'a Session, sess: &'a Session,
ecfg: expand::ExpansionConfig<'a>, ecfg: expand::ExpansionConfig<'a>,
resolver: &'a mut dyn ResolverExpand, resolver: &'a mut dyn ResolverExpand,
extern_mod_loaded: OnExternModLoaded<'a>, lint_store: LintStoreExpandDyn<'a>,
) -> ExtCtxt<'a> { ) -> ExtCtxt<'a> {
ExtCtxt { ExtCtxt {
sess, sess,
ecfg, ecfg,
reduced_recursion_limit: None, reduced_recursion_limit: None,
resolver, resolver,
extern_mod_loaded, lint_store,
root_path: PathBuf::new(), root_path: PathBuf::new(),
current_expansion: ExpansionData { current_expansion: ExpansionData {
id: LocalExpnId::ROOT, id: LocalExpnId::ROOT,

View file

@ -1097,7 +1097,7 @@ impl InvocationCollectorNode for P<ast::Item> {
ModKind::Unloaded => { ModKind::Unloaded => {
// We have an outline `mod foo;` so we need to parse the file. // We have an outline `mod foo;` so we need to parse the file.
let old_attrs_len = attrs.len(); let old_attrs_len = attrs.len();
let ParsedExternalMod { mut items, inner_span, file_path, dir_path, dir_ownership } = let ParsedExternalMod { items, inner_span, file_path, dir_path, dir_ownership } =
parse_external_mod( parse_external_mod(
&ecx.sess, &ecx.sess,
ident, ident,
@ -1107,8 +1107,15 @@ impl InvocationCollectorNode for P<ast::Item> {
&mut attrs, &mut attrs,
); );
if let Some(extern_mod_loaded) = ecx.extern_mod_loaded { if let Some(lint_store) = ecx.lint_store {
(attrs, items) = extern_mod_loaded(ident, attrs, items, inner_span); lint_store.pre_expansion_lint(
ecx.sess,
ecx.resolver.registered_tools(),
ecx.current_expansion.lint_node_id,
&attrs,
&items,
ident.name.as_str(),
);
} }
*mod_kind = ModKind::Loaded(items, Inline::No, inner_span); *mod_kind = ModKind::Loaded(items, Inline::No, inner_span);

View file

@ -3,7 +3,7 @@ use crate::proc_macro_decls;
use crate::util; use crate::util;
use rustc_ast::mut_visit::MutVisitor; use rustc_ast::mut_visit::MutVisitor;
use rustc_ast::{self as ast, visit, DUMMY_NODE_ID}; use rustc_ast::{self as ast, visit};
use rustc_borrowck as mir_borrowck; use rustc_borrowck as mir_borrowck;
use rustc_codegen_ssa::back::link::emit_metadata; use rustc_codegen_ssa::back::link::emit_metadata;
use rustc_codegen_ssa::traits::CodegenBackend; use rustc_codegen_ssa::traits::CodegenBackend;
@ -11,16 +11,16 @@ use rustc_data_structures::parallel;
use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal}; use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal};
use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_data_structures::temp_dir::MaybeTempDir;
use rustc_errors::{Applicability, ErrorReported, PResult}; use rustc_errors::{Applicability, ErrorReported, PResult};
use rustc_expand::base::ExtCtxt; use rustc_expand::base::{ExtCtxt, LintStoreExpand, ResolverExpand};
use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE}; use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE};
use rustc_hir::Crate; use rustc_hir::Crate;
use rustc_lint::LintStore; use rustc_lint::{EarlyCheckNode, LintStore};
use rustc_metadata::creader::CStore; use rustc_metadata::creader::CStore;
use rustc_metadata::{encode_metadata, EncodedMetadata}; use rustc_metadata::{encode_metadata, EncodedMetadata};
use rustc_middle::arena::Arena; use rustc_middle::arena::Arena;
use rustc_middle::dep_graph::DepGraph; use rustc_middle::dep_graph::DepGraph;
use rustc_middle::ty::query::{ExternProviders, Providers}; use rustc_middle::ty::query::{ExternProviders, Providers};
use rustc_middle::ty::{self, GlobalCtxt, ResolverOutputs, TyCtxt}; use rustc_middle::ty::{self, GlobalCtxt, RegisteredTools, ResolverOutputs, TyCtxt};
use rustc_mir_build as mir_build; use rustc_mir_build as mir_build;
use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_attr}; use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_attr};
use rustc_passes::{self, hir_stats, layout_test}; use rustc_passes::{self, hir_stats, layout_test};
@ -34,7 +34,7 @@ use rustc_session::lint;
use rustc_session::output::{filename_for_input, filename_for_metadata}; use rustc_session::output::{filename_for_input, filename_for_metadata};
use rustc_session::search_paths::PathKind; use rustc_session::search_paths::PathKind;
use rustc_session::{Limit, Session}; use rustc_session::{Limit, Session};
use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::symbol::{sym, Symbol};
use rustc_span::{FileName, MultiSpan}; use rustc_span::{FileName, MultiSpan};
use rustc_trait_selection::traits; use rustc_trait_selection::traits;
use rustc_typeck as typeck; use rustc_typeck as typeck;
@ -233,26 +233,43 @@ pub fn register_plugins<'a>(
Ok((krate, lint_store)) Ok((krate, lint_store))
} }
fn pre_expansion_lint( fn pre_expansion_lint<'a>(
sess: &Session, sess: &Session,
lint_store: &LintStore, lint_store: &LintStore,
krate: &ast::Crate, registered_tools: &RegisteredTools,
crate_attrs: &[ast::Attribute], check_node: impl EarlyCheckNode<'a>,
crate_name: &str, node_name: &str,
) { ) {
sess.prof.generic_activity_with_arg("pre_AST_expansion_lint_checks", crate_name).run(|| { sess.prof.generic_activity_with_arg("pre_AST_expansion_lint_checks", node_name).run(|| {
rustc_lint::check_ast_crate( rustc_lint::check_ast_node(
sess, sess,
lint_store,
krate,
crate_attrs,
true, true,
lint_store,
registered_tools,
None, None,
rustc_lint::BuiltinCombinedPreExpansionLintPass::new(), rustc_lint::BuiltinCombinedPreExpansionLintPass::new(),
check_node,
); );
}); });
} }
// Cannot implement directly for `LintStore` due to trait coherence.
struct LintStoreExpandImpl<'a>(&'a LintStore);
impl LintStoreExpand for LintStoreExpandImpl<'_> {
fn pre_expansion_lint(
&self,
sess: &Session,
registered_tools: &RegisteredTools,
node_id: ast::NodeId,
attrs: &[ast::Attribute],
items: &[rustc_ast::ptr::P<ast::Item>],
name: &str,
) {
pre_expansion_lint(sess, self.0, registered_tools, (node_id, attrs, items), name);
}
}
/// Runs the "early phases" of the compiler: initial `cfg` processing, loading compiler plugins, /// Runs the "early phases" of the compiler: initial `cfg` processing, loading compiler plugins,
/// syntax expansion, secondary `cfg` expansion, synthesis of a test /// syntax expansion, secondary `cfg` expansion, synthesis of a test
/// harness if one is to be provided, injection of a dependency on the /// harness if one is to be provided, injection of a dependency on the
@ -265,7 +282,7 @@ pub fn configure_and_expand(
resolver: &mut Resolver<'_>, resolver: &mut Resolver<'_>,
) -> Result<ast::Crate> { ) -> Result<ast::Crate> {
tracing::trace!("configure_and_expand"); tracing::trace!("configure_and_expand");
pre_expansion_lint(sess, lint_store, &krate, &krate.attrs, crate_name); pre_expansion_lint(sess, lint_store, resolver.registered_tools(), &krate, crate_name);
rustc_builtin_macros::register_builtin_macros(resolver); rustc_builtin_macros::register_builtin_macros(resolver);
krate = sess.time("crate_injection", || { krate = sess.time("crate_injection", || {
@ -321,13 +338,8 @@ pub fn configure_and_expand(
..rustc_expand::expand::ExpansionConfig::default(crate_name.to_string()) ..rustc_expand::expand::ExpansionConfig::default(crate_name.to_string())
}; };
let crate_attrs = krate.attrs.clone(); let lint_store = LintStoreExpandImpl(lint_store);
let extern_mod_loaded = |ident: Ident, attrs, items, span| { let mut ecx = ExtCtxt::new(sess, cfg, resolver, Some(&lint_store));
let krate = ast::Crate { attrs, items, span, id: DUMMY_NODE_ID, is_placeholder: false };
pre_expansion_lint(sess, lint_store, &krate, &crate_attrs, ident.name.as_str());
(krate.attrs, krate.items)
};
let mut ecx = ExtCtxt::new(sess, cfg, resolver, Some(&extern_mod_loaded));
// Expand macros now! // Expand macros now!
let krate = sess.time("expand_crate", || ecx.monotonic_expander().expand_crate(krate)); let krate = sess.time("expand_crate", || ecx.monotonic_expander().expand_crate(krate));
@ -499,14 +511,15 @@ pub fn lower_to_hir<'res, 'tcx>(
); );
sess.time("early_lint_checks", || { sess.time("early_lint_checks", || {
rustc_lint::check_ast_crate( let lint_buffer = Some(std::mem::take(resolver.lint_buffer()));
rustc_lint::check_ast_node(
sess, sess,
lint_store,
&krate,
&krate.attrs,
false, false,
Some(std::mem::take(resolver.lint_buffer())), lint_store,
resolver.registered_tools(),
lint_buffer,
rustc_lint::BuiltinCombinedEarlyLintPass::new(), rustc_lint::BuiltinCombinedEarlyLintPass::new(),
&*krate,
) )
}); });

View file

@ -912,7 +912,7 @@ declare_lint_pass!(
impl EarlyLintPass for AnonymousParameters { impl EarlyLintPass for AnonymousParameters {
fn check_trait_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) { fn check_trait_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) {
if cx.sess.edition() != Edition::Edition2015 { if cx.sess().edition() != Edition::Edition2015 {
// This is a hard error in future editions; avoid linting and erroring // This is a hard error in future editions; avoid linting and erroring
return; return;
} }
@ -921,7 +921,7 @@ impl EarlyLintPass for AnonymousParameters {
if let ast::PatKind::Ident(_, ident, None) = arg.pat.kind { if let ast::PatKind::Ident(_, ident, None) = arg.pat.kind {
if ident.name == kw::Empty { if ident.name == kw::Empty {
cx.struct_span_lint(ANONYMOUS_PARAMETERS, arg.pat.span, |lint| { cx.struct_span_lint(ANONYMOUS_PARAMETERS, arg.pat.span, |lint| {
let ty_snip = cx.sess.source_map().span_to_snippet(arg.ty.span); let ty_snip = cx.sess().source_map().span_to_snippet(arg.ty.span);
let (ty_snip, appl) = if let Ok(ref snip) = ty_snip { let (ty_snip, appl) = if let Ok(ref snip) = ty_snip {
(snip.as_str(), Applicability::MachineApplicable) (snip.as_str(), Applicability::MachineApplicable)
@ -1775,7 +1775,7 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
}; };
if join.edition() >= Edition::Edition2021 { if join.edition() >= Edition::Edition2021 {
let mut err = let mut err =
rustc_errors::struct_span_err!(cx.sess, pat.span, E0783, "{}", msg,); rustc_errors::struct_span_err!(cx.sess(), pat.span, E0783, "{}", msg,);
err.span_suggestion( err.span_suggestion(
pat.span, pat.span,
suggestion, suggestion,
@ -1799,7 +1799,7 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
let replace = "..=".to_owned(); let replace = "..=".to_owned();
if join.edition() >= Edition::Edition2021 { if join.edition() >= Edition::Edition2021 {
let mut err = let mut err =
rustc_errors::struct_span_err!(cx.sess, pat.span, E0783, "{}", msg,); rustc_errors::struct_span_err!(cx.sess(), pat.span, E0783, "{}", msg,);
err.span_suggestion_short( err.span_suggestion_short(
join, join,
suggestion, suggestion,
@ -1983,7 +1983,7 @@ impl KeywordIdents {
UnderMacro(under_macro): UnderMacro, UnderMacro(under_macro): UnderMacro,
ident: Ident, ident: Ident,
) { ) {
let next_edition = match cx.sess.edition() { let next_edition = match cx.sess().edition() {
Edition::Edition2015 => { Edition::Edition2015 => {
match ident.name { match ident.name {
kw::Async | kw::Await | kw::Try => Edition::Edition2018, kw::Async | kw::Await | kw::Try => Edition::Edition2018,
@ -2011,7 +2011,7 @@ impl KeywordIdents {
}; };
// Don't lint `r#foo`. // Don't lint `r#foo`.
if cx.sess.parse_sess.raw_identifier_spans.borrow().contains(&ident.span) { if cx.sess().parse_sess.raw_identifier_spans.borrow().contains(&ident.span) {
return; return;
} }
@ -2379,7 +2379,7 @@ declare_lint_pass!(
impl EarlyLintPass for IncompleteFeatures { impl EarlyLintPass for IncompleteFeatures {
fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) { fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
let features = cx.sess.features_untracked(); let features = cx.sess().features_untracked();
features features
.declared_lang_features .declared_lang_features
.iter() .iter()

View file

@ -16,10 +16,9 @@
use self::TargetLint::*; use self::TargetLint::*;
use crate::levels::{is_known_lint_tool, LintLevelsBuilder}; use crate::levels::LintLevelsBuilder;
use crate::passes::{EarlyLintPassObject, LateLintPassObject}; use crate::passes::{EarlyLintPassObject, LateLintPassObject};
use ast::util::unicode::TEXT_FLOW_CONTROL_CHARS; use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync; use rustc_data_structures::sync;
use rustc_errors::{struct_span_err, Applicability, SuggestionStyle}; use rustc_errors::{struct_span_err, Applicability, SuggestionStyle};
@ -32,13 +31,14 @@ use rustc_middle::middle::privacy::AccessLevels;
use rustc_middle::middle::stability; use rustc_middle::middle::stability;
use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, print::Printer, subst::GenericArg, Ty, TyCtxt}; use rustc_middle::ty::{self, print::Printer, subst::GenericArg, RegisteredTools, Ty, TyCtxt};
use rustc_serialize::json::Json; use rustc_serialize::json::Json;
use rustc_session::lint::{BuiltinLintDiagnostics, ExternDepSpec}; use rustc_session::lint::{BuiltinLintDiagnostics, ExternDepSpec};
use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId}; use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId};
use rustc_session::Session; use rustc_session::Session;
use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::{symbol::Symbol, BytePos, MultiSpan, Span, DUMMY_SP}; use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
use rustc_target::abi; use rustc_target::abi;
use tracing::debug; use tracing::debug;
@ -313,7 +313,7 @@ impl LintStore {
sess: &Session, sess: &Session,
lint_name: &str, lint_name: &str,
level: Level, level: Level,
crate_attrs: &[ast::Attribute], registered_tools: &RegisteredTools,
) { ) {
let (tool_name, lint_name_only) = parse_lint_and_tool_name(lint_name); let (tool_name, lint_name_only) = parse_lint_and_tool_name(lint_name);
if lint_name_only == crate::WARNINGS.name_lower() && level == Level::ForceWarn { if lint_name_only == crate::WARNINGS.name_lower() && level == Level::ForceWarn {
@ -326,7 +326,7 @@ impl LintStore {
) )
.emit(); .emit();
} }
let db = match self.check_lint_name(sess, lint_name_only, tool_name, crate_attrs) { let db = match self.check_lint_name(lint_name_only, tool_name, registered_tools) {
CheckLintNameResult::Ok(_) => None, CheckLintNameResult::Ok(_) => None,
CheckLintNameResult::Warning(ref msg, _) => Some(sess.struct_warn(msg)), CheckLintNameResult::Warning(ref msg, _) => Some(sess.struct_warn(msg)),
CheckLintNameResult::NoLint(suggestion) => { CheckLintNameResult::NoLint(suggestion) => {
@ -397,13 +397,16 @@ impl LintStore {
/// printing duplicate warnings. /// printing duplicate warnings.
pub fn check_lint_name( pub fn check_lint_name(
&self, &self,
sess: &Session,
lint_name: &str, lint_name: &str,
tool_name: Option<Symbol>, tool_name: Option<Symbol>,
crate_attrs: &[ast::Attribute], registered_tools: &RegisteredTools,
) -> CheckLintNameResult<'_> { ) -> CheckLintNameResult<'_> {
if let Some(tool_name) = tool_name { if let Some(tool_name) = tool_name {
if !is_known_lint_tool(tool_name, sess, crate_attrs) { // FIXME: rustc and rustdoc are considered tools for lints, but not for attributes.
if tool_name != sym::rustc
&& tool_name != sym::rustdoc
&& !registered_tools.contains(&Ident::with_dummy_span(tool_name))
{
return CheckLintNameResult::NoTool; return CheckLintNameResult::NoTool;
} }
} }
@ -553,20 +556,9 @@ pub struct LateContext<'tcx> {
pub only_module: bool, pub only_module: bool,
} }
/// Context for lint checking of the AST, after expansion, before lowering to /// Context for lint checking of the AST, after expansion, before lowering to HIR.
/// HIR.
pub struct EarlyContext<'a> { pub struct EarlyContext<'a> {
/// Type context we're checking in.
pub sess: &'a Session,
/// The crate being checked.
pub krate: &'a ast::Crate,
pub builder: LintLevelsBuilder<'a>, pub builder: LintLevelsBuilder<'a>,
/// The store of registered lints and the lint levels.
pub lint_store: &'a LintStore,
pub buffered: LintBuffer, pub buffered: LintBuffer,
} }
@ -801,19 +793,20 @@ pub trait LintContext: Sized {
} }
impl<'a> EarlyContext<'a> { impl<'a> EarlyContext<'a> {
pub fn new( pub(crate) fn new(
sess: &'a Session, sess: &'a Session,
lint_store: &'a LintStore,
krate: &'a ast::Crate,
crate_attrs: &'a [ast::Attribute],
buffered: LintBuffer,
warn_about_weird_lints: bool, warn_about_weird_lints: bool,
lint_store: &'a LintStore,
registered_tools: &'a RegisteredTools,
buffered: LintBuffer,
) -> EarlyContext<'a> { ) -> EarlyContext<'a> {
EarlyContext { EarlyContext {
sess, builder: LintLevelsBuilder::new(
krate, sess,
lint_store, warn_about_weird_lints,
builder: LintLevelsBuilder::new(sess, warn_about_weird_lints, lint_store, crate_attrs), lint_store,
registered_tools,
),
buffered, buffered,
} }
} }
@ -851,11 +844,11 @@ impl LintContext for EarlyContext<'_> {
/// Gets the overall compiler `Session` object. /// Gets the overall compiler `Session` object.
fn sess(&self) -> &Session { fn sess(&self) -> &Session {
&self.sess &self.builder.sess()
} }
fn lints(&self) -> &LintStore { fn lints(&self) -> &LintStore {
&*self.lint_store self.builder.lint_store()
} }
fn lookup<S: Into<MultiSpan>>( fn lookup<S: Into<MultiSpan>>(

View file

@ -16,9 +16,11 @@
use crate::context::{EarlyContext, LintContext, LintStore}; use crate::context::{EarlyContext, LintContext, LintStore};
use crate::passes::{EarlyLintPass, EarlyLintPassObject}; use crate::passes::{EarlyLintPass, EarlyLintPassObject};
use rustc_ast as ast; use rustc_ast::ptr::P;
use rustc_ast::visit as ast_visit; use rustc_ast::visit::{self as ast_visit, Visitor};
use rustc_ast::AstLike; use rustc_ast::AstLike;
use rustc_ast::{self as ast, walk_list};
use rustc_middle::ty::RegisteredTools;
use rustc_session::lint::{BufferedEarlyLint, LintBuffer, LintPass}; use rustc_session::lint::{BufferedEarlyLint, LintBuffer, LintPass};
use rustc_session::Session; use rustc_session::Session;
use rustc_span::symbol::Ident; use rustc_span::symbol::Ident;
@ -31,7 +33,7 @@ macro_rules! run_early_pass { ($cx:expr, $f:ident, $($args:expr),*) => ({
$cx.pass.$f(&$cx.context, $($args),*); $cx.pass.$f(&$cx.context, $($args),*);
}) } }) }
struct EarlyContextAndPass<'a, T: EarlyLintPass> { pub struct EarlyContextAndPass<'a, T: EarlyLintPass> {
context: EarlyContext<'a>, context: EarlyContext<'a>,
pass: T, pass: T,
} }
@ -57,7 +59,7 @@ impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> {
F: FnOnce(&mut Self), F: FnOnce(&mut Self),
{ {
let is_crate_node = id == ast::CRATE_NODE_ID; let is_crate_node = id == ast::CRATE_NODE_ID;
let push = self.context.builder.push(attrs, &self.context.lint_store, is_crate_node); let push = self.context.builder.push(attrs, is_crate_node);
self.check_id(id); self.check_id(id);
self.enter_attrs(attrs); self.enter_attrs(attrs);
f(self); f(self);
@ -325,48 +327,89 @@ macro_rules! early_lint_pass_impl {
crate::early_lint_methods!(early_lint_pass_impl, []); crate::early_lint_methods!(early_lint_pass_impl, []);
fn early_lint_crate<T: EarlyLintPass>( /// Early lints work on different nodes - either on the crate root, or on freshly loaded modules.
/// This trait generalizes over those nodes.
pub trait EarlyCheckNode<'a>: Copy {
fn id(self) -> ast::NodeId;
fn attrs<'b>(self) -> &'b [ast::Attribute]
where
'a: 'b;
fn check<'b>(self, cx: &mut EarlyContextAndPass<'b, impl EarlyLintPass>)
where
'a: 'b;
}
impl<'a> EarlyCheckNode<'a> for &'a ast::Crate {
fn id(self) -> ast::NodeId {
ast::CRATE_NODE_ID
}
fn attrs<'b>(self) -> &'b [ast::Attribute]
where
'a: 'b,
{
&self.attrs
}
fn check<'b>(self, cx: &mut EarlyContextAndPass<'b, impl EarlyLintPass>)
where
'a: 'b,
{
run_early_pass!(cx, check_crate, self);
ast_visit::walk_crate(cx, self);
run_early_pass!(cx, check_crate_post, self);
}
}
impl<'a> EarlyCheckNode<'a> for (ast::NodeId, &'a [ast::Attribute], &'a [P<ast::Item>]) {
fn id(self) -> ast::NodeId {
self.0
}
fn attrs<'b>(self) -> &'b [ast::Attribute]
where
'a: 'b,
{
self.1
}
fn check<'b>(self, cx: &mut EarlyContextAndPass<'b, impl EarlyLintPass>)
where
'a: 'b,
{
walk_list!(cx, visit_attribute, self.1);
walk_list!(cx, visit_item, self.2);
}
}
fn early_lint_node<'a>(
sess: &Session, sess: &Session,
lint_store: &LintStore,
krate: &ast::Crate,
crate_attrs: &[ast::Attribute],
pass: T,
buffered: LintBuffer,
warn_about_weird_lints: bool, warn_about_weird_lints: bool,
lint_store: &LintStore,
registered_tools: &RegisteredTools,
buffered: LintBuffer,
pass: impl EarlyLintPass,
check_node: impl EarlyCheckNode<'a>,
) -> LintBuffer { ) -> LintBuffer {
let mut cx = EarlyContextAndPass { let mut cx = EarlyContextAndPass {
context: EarlyContext::new( context: EarlyContext::new(
sess, sess,
lint_store,
krate,
crate_attrs,
buffered,
warn_about_weird_lints, warn_about_weird_lints,
lint_store,
registered_tools,
buffered,
), ),
pass, pass,
}; };
// Visit the whole crate. cx.with_lint_attrs(check_node.id(), check_node.attrs(), |cx| check_node.check(cx));
cx.with_lint_attrs(ast::CRATE_NODE_ID, &krate.attrs, |cx| {
// since the root module isn't visited as an item (because it isn't an
// item), warn for it here.
run_early_pass!(cx, check_crate, krate);
ast_visit::walk_crate(cx, krate);
run_early_pass!(cx, check_crate_post, krate);
});
cx.context.buffered cx.context.buffered
} }
pub fn check_ast_crate<T: EarlyLintPass>( pub fn check_ast_node<'a>(
sess: &Session, sess: &Session,
lint_store: &LintStore,
krate: &ast::Crate,
crate_attrs: &[ast::Attribute],
pre_expansion: bool, pre_expansion: bool,
lint_store: &LintStore,
registered_tools: &RegisteredTools,
lint_buffer: Option<LintBuffer>, lint_buffer: Option<LintBuffer>,
builtin_lints: T, builtin_lints: impl EarlyLintPass,
check_node: impl EarlyCheckNode<'a>,
) { ) {
let passes = let passes =
if pre_expansion { &lint_store.pre_expansion_passes } else { &lint_store.early_passes }; if pre_expansion { &lint_store.pre_expansion_passes } else { &lint_store.early_passes };
@ -374,39 +417,39 @@ pub fn check_ast_crate<T: EarlyLintPass>(
let mut buffered = lint_buffer.unwrap_or_default(); let mut buffered = lint_buffer.unwrap_or_default();
if !sess.opts.debugging_opts.no_interleave_lints { if !sess.opts.debugging_opts.no_interleave_lints {
buffered = early_lint_crate( buffered = early_lint_node(
sess, sess,
lint_store,
krate,
crate_attrs,
builtin_lints,
buffered,
pre_expansion, pre_expansion,
lint_store,
registered_tools,
buffered,
builtin_lints,
check_node,
); );
if !passes.is_empty() { if !passes.is_empty() {
buffered = early_lint_crate( buffered = early_lint_node(
sess, sess,
lint_store,
krate,
crate_attrs,
EarlyLintPassObjects { lints: &mut passes[..] },
buffered,
false, false,
lint_store,
registered_tools,
buffered,
EarlyLintPassObjects { lints: &mut passes[..] },
check_node,
); );
} }
} else { } else {
for (i, pass) in passes.iter_mut().enumerate() { for (i, pass) in passes.iter_mut().enumerate() {
buffered = buffered =
sess.prof.extra_verbose_generic_activity("run_lint", pass.name()).run(|| { sess.prof.extra_verbose_generic_activity("run_lint", pass.name()).run(|| {
early_lint_crate( early_lint_node(
sess, sess,
lint_store,
krate,
crate_attrs,
EarlyLintPassObjects { lints: slice::from_mut(pass) },
buffered,
pre_expansion && i == 0, pre_expansion && i == 0,
lint_store,
registered_tools,
buffered,
EarlyLintPassObjects { lints: slice::from_mut(pass) },
check_node,
) )
}); });
} }

View file

@ -5,7 +5,7 @@ use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::{intravisit, HirId, CRATE_HIR_ID}; use rustc_hir::{intravisit, HirId};
use rustc_middle::hir::nested_filter; use rustc_middle::hir::nested_filter;
use rustc_middle::lint::LevelAndSource; use rustc_middle::lint::LevelAndSource;
use rustc_middle::lint::LintDiagnosticBuilder; use rustc_middle::lint::LintDiagnosticBuilder;
@ -14,7 +14,7 @@ use rustc_middle::lint::{
COMMAND_LINE, COMMAND_LINE,
}; };
use rustc_middle::ty::query::Providers; use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt; use rustc_middle::ty::{RegisteredTools, TyCtxt};
use rustc_session::lint::{ use rustc_session::lint::{
builtin::{self, FORBIDDEN_LINT_GROUPS}, builtin::{self, FORBIDDEN_LINT_GROUPS},
Level, Lint, LintId, Level, Lint, LintId,
@ -27,14 +27,14 @@ use tracing::debug;
fn lint_levels(tcx: TyCtxt<'_>, (): ()) -> LintLevelMap { fn lint_levels(tcx: TyCtxt<'_>, (): ()) -> LintLevelMap {
let store = unerased_lint_store(tcx); let store = unerased_lint_store(tcx);
let crate_attrs = tcx.hir().attrs(CRATE_HIR_ID); let levels =
let levels = LintLevelsBuilder::new(tcx.sess, false, &store, crate_attrs); LintLevelsBuilder::new(tcx.sess, false, &store, &tcx.resolutions(()).registered_tools);
let mut builder = LintLevelMapBuilder { levels, tcx, store }; let mut builder = LintLevelMapBuilder { levels, tcx };
let krate = tcx.hir().krate(); let krate = tcx.hir().krate();
builder.levels.id_to_set.reserve(krate.owners.len() + 1); builder.levels.id_to_set.reserve(krate.owners.len() + 1);
let push = builder.levels.push(tcx.hir().attrs(hir::CRATE_HIR_ID), &store, true); let push = builder.levels.push(tcx.hir().attrs(hir::CRATE_HIR_ID), true);
builder.levels.register_id(hir::CRATE_HIR_ID); builder.levels.register_id(hir::CRATE_HIR_ID);
tcx.hir().walk_toplevel_module(&mut builder); tcx.hir().walk_toplevel_module(&mut builder);
builder.levels.pop(push); builder.levels.pop(push);
@ -49,7 +49,7 @@ pub struct LintLevelsBuilder<'s> {
cur: LintStackIndex, cur: LintStackIndex,
warn_about_weird_lints: bool, warn_about_weird_lints: bool,
store: &'s LintStore, store: &'s LintStore,
crate_attrs: &'s [ast::Attribute], registered_tools: &'s RegisteredTools,
} }
pub struct BuilderPush { pub struct BuilderPush {
@ -62,7 +62,7 @@ impl<'s> LintLevelsBuilder<'s> {
sess: &'s Session, sess: &'s Session,
warn_about_weird_lints: bool, warn_about_weird_lints: bool,
store: &'s LintStore, store: &'s LintStore,
crate_attrs: &'s [ast::Attribute], registered_tools: &'s RegisteredTools,
) -> Self { ) -> Self {
let mut builder = LintLevelsBuilder { let mut builder = LintLevelsBuilder {
sess, sess,
@ -71,19 +71,27 @@ impl<'s> LintLevelsBuilder<'s> {
id_to_set: Default::default(), id_to_set: Default::default(),
warn_about_weird_lints, warn_about_weird_lints,
store, store,
crate_attrs, registered_tools,
}; };
builder.process_command_line(sess, store); builder.process_command_line(sess, store);
assert_eq!(builder.sets.list.len(), 1); assert_eq!(builder.sets.list.len(), 1);
builder builder
} }
pub(crate) fn sess(&self) -> &Session {
self.sess
}
pub(crate) fn lint_store(&self) -> &LintStore {
self.store
}
fn process_command_line(&mut self, sess: &Session, store: &LintStore) { fn process_command_line(&mut self, sess: &Session, store: &LintStore) {
let mut specs = FxHashMap::default(); let mut specs = FxHashMap::default();
self.sets.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid); self.sets.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid);
for &(ref lint_name, level) in &sess.opts.lint_opts { for &(ref lint_name, level) in &sess.opts.lint_opts {
store.check_lint_name_cmdline(sess, &lint_name, level, self.crate_attrs); store.check_lint_name_cmdline(sess, &lint_name, level, self.registered_tools);
let orig_level = level; let orig_level = level;
let lint_flag_val = Symbol::intern(lint_name); let lint_flag_val = Symbol::intern(lint_name);
@ -217,12 +225,7 @@ impl<'s> LintLevelsBuilder<'s> {
/// `#[allow]` /// `#[allow]`
/// ///
/// Don't forget to call `pop`! /// Don't forget to call `pop`!
pub(crate) fn push( pub(crate) fn push(&mut self, attrs: &[ast::Attribute], is_crate_node: bool) -> BuilderPush {
&mut self,
attrs: &[ast::Attribute],
store: &LintStore,
is_crate_node: bool,
) -> BuilderPush {
let mut specs = FxHashMap::default(); let mut specs = FxHashMap::default();
let sess = self.sess; let sess = self.sess;
let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input"); let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input");
@ -310,7 +313,8 @@ impl<'s> LintLevelsBuilder<'s> {
}; };
let tool_name = tool_ident.map(|ident| ident.name); let tool_name = tool_ident.map(|ident| ident.name);
let name = pprust::path_to_string(&meta_item.path); let name = pprust::path_to_string(&meta_item.path);
let lint_result = store.check_lint_name(sess, &name, tool_name, self.crate_attrs); let lint_result =
self.store.check_lint_name(&name, tool_name, self.registered_tools);
match &lint_result { match &lint_result {
CheckLintNameResult::Ok(ids) => { CheckLintNameResult::Ok(ids) => {
let src = LintLevelSource::Node( let src = LintLevelSource::Node(
@ -459,7 +463,7 @@ impl<'s> LintLevelsBuilder<'s> {
// Ignore any errors or warnings that happen because the new name is inaccurate // Ignore any errors or warnings that happen because the new name is inaccurate
// NOTE: `new_name` already includes the tool name, so we don't have to add it again. // NOTE: `new_name` already includes the tool name, so we don't have to add it again.
if let CheckLintNameResult::Ok(ids) = if let CheckLintNameResult::Ok(ids) =
store.check_lint_name(sess, &new_name, None, self.crate_attrs) self.store.check_lint_name(&new_name, None, self.registered_tools)
{ {
let src = LintLevelSource::Node(Symbol::intern(&new_name), sp, reason); let src = LintLevelSource::Node(Symbol::intern(&new_name), sp, reason);
for &id in ids { for &id in ids {
@ -562,34 +566,19 @@ impl<'s> LintLevelsBuilder<'s> {
} }
} }
pub fn is_known_lint_tool(m_item: Symbol, sess: &Session, attrs: &[ast::Attribute]) -> bool { struct LintLevelMapBuilder<'tcx> {
if [sym::clippy, sym::rustc, sym::rustdoc].contains(&m_item) {
return true;
}
// Look for registered tools
// NOTE: does no error handling; error handling is done by rustc_resolve.
sess.filter_by_name(attrs, sym::register_tool)
.filter_map(|attr| attr.meta_item_list())
.flatten()
.filter_map(|nested_meta| nested_meta.ident())
.map(|ident| ident.name)
.any(|name| name == m_item)
}
struct LintLevelMapBuilder<'a, 'tcx> {
levels: LintLevelsBuilder<'tcx>, levels: LintLevelsBuilder<'tcx>,
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
store: &'a LintStore,
} }
impl LintLevelMapBuilder<'_, '_> { impl LintLevelMapBuilder<'_> {
fn with_lint_attrs<F>(&mut self, id: hir::HirId, f: F) fn with_lint_attrs<F>(&mut self, id: hir::HirId, f: F)
where where
F: FnOnce(&mut Self), F: FnOnce(&mut Self),
{ {
let is_crate_hir = id == hir::CRATE_HIR_ID; let is_crate_hir = id == hir::CRATE_HIR_ID;
let attrs = self.tcx.hir().attrs(id); let attrs = self.tcx.hir().attrs(id);
let push = self.levels.push(attrs, self.store, is_crate_hir); let push = self.levels.push(attrs, is_crate_hir);
if push.changed { if push.changed {
self.levels.register_id(id); self.levels.register_id(id);
} }
@ -598,7 +587,7 @@ impl LintLevelMapBuilder<'_, '_> {
} }
} }
impl<'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'_, 'tcx> { impl<'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'tcx> {
type NestedFilter = nested_filter::All; type NestedFilter = nested_filter::All;
fn nested_visit_map(&mut self) -> Self::Map { fn nested_visit_map(&mut self) -> Self::Map {

View file

@ -96,7 +96,7 @@ use unused::*;
pub use builtin::SoftLints; pub use builtin::SoftLints;
pub use context::{CheckLintNameResult, FindLintError, LintStore}; pub use context::{CheckLintNameResult, FindLintError, LintStore};
pub use context::{EarlyContext, LateContext, LintContext}; pub use context::{EarlyContext, LateContext, LintContext};
pub use early::check_ast_crate; pub use early::{check_ast_node, EarlyCheckNode};
pub use late::check_crate; pub use late::check_crate;
pub use passes::{EarlyLintPass, LateLintPass}; pub use passes::{EarlyLintPass, LateLintPass};
pub use rustc_session::lint::Level::{self, *}; pub use rustc_session::lint::Level::{self, *};

View file

@ -166,7 +166,7 @@ impl EarlyLintPass for NonAsciiIdents {
} }
let mut has_non_ascii_idents = false; let mut has_non_ascii_idents = false;
let symbols = cx.sess.parse_sess.symbol_gallery.symbols.lock(); let symbols = cx.sess().parse_sess.symbol_gallery.symbols.lock();
// Sort by `Span` so that error messages make sense with respect to the // Sort by `Span` so that error messages make sense with respect to the
// order of identifier locations in the code. // order of identifier locations in the code.

View file

@ -164,7 +164,7 @@ impl EarlyLintPass for NonCamelCaseTypes {
let has_repr_c = it let has_repr_c = it
.attrs .attrs
.iter() .iter()
.any(|attr| attr::find_repr_attrs(&cx.sess, attr).contains(&attr::ReprC)); .any(|attr| attr::find_repr_attrs(cx.sess(), attr).contains(&attr::ReprC));
if has_repr_c { if has_repr_c {
return; return;

View file

@ -119,6 +119,8 @@ mod sty;
// Data types // Data types
pub type RegisteredTools = FxHashSet<Ident>;
#[derive(Debug)] #[derive(Debug)]
pub struct ResolverOutputs { pub struct ResolverOutputs {
pub definitions: rustc_hir::definitions::Definitions, pub definitions: rustc_hir::definitions::Definitions,
@ -141,6 +143,7 @@ pub struct ResolverOutputs {
/// Mapping from ident span to path span for paths that don't exist as written, but that /// Mapping from ident span to path span for paths that don't exist as written, but that
/// exist under `std`. For example, wrote `str::from_utf8` instead of `std::str::from_utf8`. /// exist under `std`. For example, wrote `str::from_utf8` instead of `std::str::from_utf8`.
pub confused_type_with_std_module: FxHashMap<Span, Span>, pub confused_type_with_std_module: FxHashMap<Span, Span>,
pub registered_tools: RegisteredTools,
} }
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]

View file

@ -111,6 +111,7 @@
use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph}; use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph};
use super::spans::CoverageSpan; use super::spans::CoverageSpan;
use itertools::Itertools;
use rustc_middle::mir::create_dump_file; use rustc_middle::mir::create_dump_file;
use rustc_middle::mir::generic_graphviz::GraphvizWriter; use rustc_middle::mir::generic_graphviz::GraphvizWriter;
use rustc_middle::mir::spanview::{self, SpanViewable}; use rustc_middle::mir::spanview::{self, SpanViewable};
@ -739,7 +740,6 @@ pub(super) fn dump_coverage_graphviz<'tcx>(
) )
} }
}) })
.collect::<Vec<_>>()
.join("\n ") .join("\n ")
)); ));
} }
@ -768,7 +768,6 @@ fn bcb_to_string_sections<'tcx>(
.map(|expression| { .map(|expression| {
format!("Intermediate {}", debug_counters.format_counter(expression)) format!("Intermediate {}", debug_counters.format_counter(expression))
}) })
.collect::<Vec<_>>()
.join("\n"), .join("\n"),
); );
} }
@ -783,7 +782,6 @@ fn bcb_to_string_sections<'tcx>(
covspan.format(tcx, mir_body) covspan.format(tcx, mir_body)
) )
}) })
.collect::<Vec<_>>()
.join("\n"), .join("\n"),
); );
} }
@ -793,7 +791,6 @@ fn bcb_to_string_sections<'tcx>(
dependency_counters dependency_counters
.iter() .iter()
.map(|counter| debug_counters.format_counter(counter)) .map(|counter| debug_counters.format_counter(counter))
.collect::<Vec<_>>()
.join(" \n"), .join(" \n"),
)); ));
} }

View file

@ -1,5 +1,6 @@
use super::Error; use super::Error;
use itertools::Itertools;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::graph::dominators::{self, Dominators}; use rustc_data_structures::graph::dominators::{self, Dominators};
use rustc_data_structures::graph::{self, GraphSuccessors, WithNumNodes, WithStartNode}; use rustc_data_structures::graph::{self, GraphSuccessors, WithNumNodes, WithStartNode};
@ -422,14 +423,7 @@ impl BasicCoverageBlockData {
} }
pub fn id(&self) -> String { pub fn id(&self) -> String {
format!( format!("@{}", self.basic_blocks.iter().map(|bb| bb.index().to_string()).join(ID_SEPARATOR))
"@{}",
self.basic_blocks
.iter()
.map(|bb| bb.index().to_string())
.collect::<Vec<_>>()
.join(ID_SEPARATOR)
)
} }
} }

View file

@ -1,6 +1,7 @@
use super::debug::term_type; use super::debug::term_type;
use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB}; use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB};
use itertools::Itertools;
use rustc_data_structures::graph::WithNumNodes; use rustc_data_structures::graph::WithNumNodes;
use rustc_middle::mir::spanview::source_range_no_file; use rustc_middle::mir::spanview::source_range_no_file;
use rustc_middle::mir::{ use rustc_middle::mir::{
@ -169,11 +170,7 @@ impl CoverageSpan {
CoverageStatement::Statement(bb, _, index) => (bb, index), CoverageStatement::Statement(bb, _, index) => (bb, index),
CoverageStatement::Terminator(bb, _) => (bb, usize::MAX), CoverageStatement::Terminator(bb, _) => (bb, usize::MAX),
}); });
sorted_coverage_statements sorted_coverage_statements.iter().map(|covstmt| covstmt.format(tcx, mir_body)).join("\n")
.iter()
.map(|covstmt| covstmt.format(tcx, mir_body))
.collect::<Vec<_>>()
.join("\n")
} }
/// If the span is part of a macro, returns the macro name symbol. /// If the span is part of a macro, returns the macro name symbol.

View file

@ -31,6 +31,7 @@ use super::spans;
use coverage_test_macros::let_bcb; use coverage_test_macros::let_bcb;
use itertools::Itertools;
use rustc_data_structures::graph::WithNumNodes; use rustc_data_structures::graph::WithNumNodes;
use rustc_data_structures::graph::WithSuccessors; use rustc_data_structures::graph::WithSuccessors;
use rustc_index::vec::{Idx, IndexVec}; use rustc_index::vec::{Idx, IndexVec};
@ -232,11 +233,9 @@ fn print_mir_graphviz(name: &str, mir_body: &Body<'_>) {
mir_body mir_body
.successors(bb) .successors(bb)
.map(|successor| { format!(" {:?} -> {:?};", bb, successor) }) .map(|successor| { format!(" {:?} -> {:?};", bb, successor) })
.collect::<Vec<_>>()
.join("\n") .join("\n")
) )
}) })
.collect::<Vec<_>>()
.join("\n") .join("\n")
); );
} }
@ -262,11 +261,9 @@ fn print_coverage_graphviz(
basic_coverage_blocks basic_coverage_blocks
.successors(bcb) .successors(bcb)
.map(|successor| { format!(" {:?} -> {:?};", bcb, successor) }) .map(|successor| { format!(" {:?} -> {:?};", bcb, successor) })
.collect::<Vec<_>>()
.join("\n") .join("\n")
) )
}) })
.collect::<Vec<_>>()
.join("\n") .join("\n")
); );
} }

View file

@ -1,3 +1,4 @@
use itertools::Itertools;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::visit::Visitor;
@ -197,7 +198,7 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> {
let ident = self.tcx.item_name(fn_id).to_ident_string(); let ident = self.tcx.item_name(fn_id).to_ident_string();
let ty_params = fn_substs.types().map(|ty| format!("{}", ty)); let ty_params = fn_substs.types().map(|ty| format!("{}", ty));
let const_params = fn_substs.consts().map(|c| format!("{}", c)); let const_params = fn_substs.consts().map(|c| format!("{}", c));
let params = ty_params.chain(const_params).collect::<Vec<String>>().join(", "); let params = ty_params.chain(const_params).join(", ");
let num_args = fn_sig.inputs().map_bound(|inputs| inputs.len()).skip_binder(); let num_args = fn_sig.inputs().map_bound(|inputs| inputs.len()).skip_binder();
let variadic = if fn_sig.c_variadic() { ", ..." } else { "" }; let variadic = if fn_sig.c_variadic() { ", ..." } else { "" };
let ret = if fn_sig.output().skip_binder().is_unit() { "" } else { " -> _" }; let ret = if fn_sig.output().skip_binder().is_unit() { "" } else { " -> _" };

View file

@ -2383,6 +2383,17 @@ impl<'a> Parser<'a> {
} }
pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> { pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> {
fn check_let_expr(expr: &Expr) -> (bool, bool) {
match expr.kind {
ExprKind::Binary(_, ref lhs, ref rhs) => {
let lhs_rslt = check_let_expr(lhs);
let rhs_rslt = check_let_expr(rhs);
(lhs_rslt.0 || rhs_rslt.0, false)
}
ExprKind::Let(..) => (true, true),
_ => (false, true),
}
}
let attrs = self.parse_outer_attributes()?; let attrs = self.parse_outer_attributes()?;
self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| { self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
let lo = this.token.span; let lo = this.token.span;
@ -2390,9 +2401,12 @@ impl<'a> Parser<'a> {
let guard = if this.eat_keyword(kw::If) { let guard = if this.eat_keyword(kw::If) {
let if_span = this.prev_token.span; let if_span = this.prev_token.span;
let cond = this.parse_expr()?; let cond = this.parse_expr()?;
if let ExprKind::Let(..) = cond.kind { let (has_let_expr, does_not_have_bin_op) = check_let_expr(&cond);
// Remove the last feature gating of a `let` expression since it's stable. if has_let_expr {
this.sess.gated_spans.ungate_last(sym::let_chains, cond.span); if does_not_have_bin_op {
// Remove the last feature gating of a `let` expression since it's stable.
this.sess.gated_spans.ungate_last(sym::let_chains, cond.span);
}
let span = if_span.to(cond.span); let span = if_span.to(cond.span);
this.sess.gated_spans.gate(sym::if_let_guard, span); this.sess.gated_spans.gate(sym::if_let_guard, span);
} }

View file

@ -53,7 +53,7 @@ use rustc_middle::metadata::ModChild;
use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::middle::privacy::AccessLevels;
use rustc_middle::span_bug; use rustc_middle::span_bug;
use rustc_middle::ty::query::Providers; use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, DefIdTree, MainDefinition, ResolverOutputs}; use rustc_middle::ty::{self, DefIdTree, MainDefinition, RegisteredTools, ResolverOutputs};
use rustc_query_system::ich::StableHashingContext; use rustc_query_system::ich::StableHashingContext;
use rustc_session::cstore::{CrateStore, MetadataLoaderDyn}; use rustc_session::cstore::{CrateStore, MetadataLoaderDyn};
use rustc_session::lint; use rustc_session::lint;
@ -989,7 +989,7 @@ pub struct Resolver<'a> {
macro_names: FxHashSet<Ident>, macro_names: FxHashSet<Ident>,
builtin_macros: FxHashMap<Symbol, BuiltinMacroState>, builtin_macros: FxHashMap<Symbol, BuiltinMacroState>,
registered_attrs: FxHashSet<Ident>, registered_attrs: FxHashSet<Ident>,
registered_tools: FxHashSet<Ident>, registered_tools: RegisteredTools,
macro_use_prelude: FxHashMap<Symbol, &'a NameBinding<'a>>, macro_use_prelude: FxHashMap<Symbol, &'a NameBinding<'a>>,
all_macros: FxHashMap<Symbol, Res>, all_macros: FxHashMap<Symbol, Res>,
macro_map: FxHashMap<DefId, Lrc<SyntaxExtension>>, macro_map: FxHashMap<DefId, Lrc<SyntaxExtension>>,
@ -1487,6 +1487,7 @@ impl<'a> Resolver<'a> {
trait_impls: self.trait_impls, trait_impls: self.trait_impls,
proc_macros, proc_macros,
confused_type_with_std_module, confused_type_with_std_module,
registered_tools: self.registered_tools,
} }
} }
@ -1511,6 +1512,7 @@ impl<'a> Resolver<'a> {
trait_impls: self.trait_impls.clone(), trait_impls: self.trait_impls.clone(),
proc_macros, proc_macros,
confused_type_with_std_module: self.confused_type_with_std_module.clone(), confused_type_with_std_module: self.confused_type_with_std_module.clone(),
registered_tools: self.registered_tools.clone(),
} }
} }

View file

@ -23,7 +23,7 @@ use rustc_hir::def::{self, DefKind, NonMacroAttrKind};
use rustc_hir::def_id::{CrateNum, LocalDefId}; use rustc_hir::def_id::{CrateNum, LocalDefId};
use rustc_hir::PrimTy; use rustc_hir::PrimTy;
use rustc_middle::middle::stability; use rustc_middle::middle::stability;
use rustc_middle::ty; use rustc_middle::ty::{self, RegisteredTools};
use rustc_session::lint::builtin::{LEGACY_DERIVE_HELPERS, PROC_MACRO_DERIVE_RESOLUTION_FALLBACK}; use rustc_session::lint::builtin::{LEGACY_DERIVE_HELPERS, PROC_MACRO_DERIVE_RESOLUTION_FALLBACK};
use rustc_session::lint::builtin::{SOFT_UNSTABLE, UNUSED_MACROS}; use rustc_session::lint::builtin::{SOFT_UNSTABLE, UNUSED_MACROS};
use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::lint::BuiltinLintDiagnostics;
@ -447,6 +447,10 @@ impl<'a> ResolverExpand for Resolver<'a> {
fn declare_proc_macro(&mut self, id: NodeId) { fn declare_proc_macro(&mut self, id: NodeId) {
self.proc_macros.push(id) self.proc_macros.push(id)
} }
fn registered_tools(&self) -> &RegisteredTools {
&self.registered_tools
}
} }
impl<'a> Resolver<'a> { impl<'a> Resolver<'a> {

View file

@ -476,10 +476,6 @@ impl Session {
&self.parse_sess.span_diagnostic &self.parse_sess.span_diagnostic
} }
pub fn with_disabled_diagnostic<T, F: FnOnce() -> T>(&self, f: F) -> T {
self.parse_sess.span_diagnostic.with_disabled_diagnostic(f)
}
/// Analogous to calling methods on the given `DiagnosticBuilder`, but /// Analogous to calling methods on the given `DiagnosticBuilder`, but
/// deduplicates on lint ID, span (if any), and message for this `Session` /// deduplicates on lint ID, span (if any), and message for this `Session`
fn diag_once<'a, 'b>( fn diag_once<'a, 'b>(

View file

@ -152,6 +152,7 @@ mod avr;
mod bpf; mod bpf;
mod hexagon; mod hexagon;
mod mips; mod mips;
mod msp430;
mod nvptx; mod nvptx;
mod powerpc; mod powerpc;
mod riscv; mod riscv;
@ -166,6 +167,7 @@ pub use avr::{AvrInlineAsmReg, AvrInlineAsmRegClass};
pub use bpf::{BpfInlineAsmReg, BpfInlineAsmRegClass}; pub use bpf::{BpfInlineAsmReg, BpfInlineAsmRegClass};
pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass}; pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass};
pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass}; pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass};
pub use msp430::{Msp430InlineAsmReg, Msp430InlineAsmRegClass};
pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass}; pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass};
pub use powerpc::{PowerPCInlineAsmReg, PowerPCInlineAsmRegClass}; pub use powerpc::{PowerPCInlineAsmReg, PowerPCInlineAsmRegClass};
pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass}; pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass};
@ -194,6 +196,7 @@ pub enum InlineAsmArch {
Wasm64, Wasm64,
Bpf, Bpf,
Avr, Avr,
Msp430,
} }
impl FromStr for InlineAsmArch { impl FromStr for InlineAsmArch {
@ -219,6 +222,7 @@ impl FromStr for InlineAsmArch {
"wasm64" => Ok(Self::Wasm64), "wasm64" => Ok(Self::Wasm64),
"bpf" => Ok(Self::Bpf), "bpf" => Ok(Self::Bpf),
"avr" => Ok(Self::Avr), "avr" => Ok(Self::Avr),
"msp430" => Ok(Self::Msp430),
_ => Err(()), _ => Err(()),
} }
} }
@ -250,6 +254,7 @@ pub enum InlineAsmReg {
Wasm(WasmInlineAsmReg), Wasm(WasmInlineAsmReg),
Bpf(BpfInlineAsmReg), Bpf(BpfInlineAsmReg),
Avr(AvrInlineAsmReg), Avr(AvrInlineAsmReg),
Msp430(Msp430InlineAsmReg),
// Placeholder for invalid register constraints for the current target // Placeholder for invalid register constraints for the current target
Err, Err,
} }
@ -267,6 +272,7 @@ impl InlineAsmReg {
Self::S390x(r) => r.name(), Self::S390x(r) => r.name(),
Self::Bpf(r) => r.name(), Self::Bpf(r) => r.name(),
Self::Avr(r) => r.name(), Self::Avr(r) => r.name(),
Self::Msp430(r) => r.name(),
Self::Err => "<reg>", Self::Err => "<reg>",
} }
} }
@ -283,6 +289,7 @@ impl InlineAsmReg {
Self::S390x(r) => InlineAsmRegClass::S390x(r.reg_class()), Self::S390x(r) => InlineAsmRegClass::S390x(r.reg_class()),
Self::Bpf(r) => InlineAsmRegClass::Bpf(r.reg_class()), Self::Bpf(r) => InlineAsmRegClass::Bpf(r.reg_class()),
Self::Avr(r) => InlineAsmRegClass::Avr(r.reg_class()), Self::Avr(r) => InlineAsmRegClass::Avr(r.reg_class()),
Self::Msp430(r) => InlineAsmRegClass::Msp430(r.reg_class()),
Self::Err => InlineAsmRegClass::Err, Self::Err => InlineAsmRegClass::Err,
} }
} }
@ -336,6 +343,9 @@ impl InlineAsmReg {
InlineAsmArch::Avr => { InlineAsmArch::Avr => {
Self::Avr(AvrInlineAsmReg::parse(arch, target_features, target, name)?) Self::Avr(AvrInlineAsmReg::parse(arch, target_features, target, name)?)
} }
InlineAsmArch::Msp430 => {
Self::Msp430(Msp430InlineAsmReg::parse(arch, target_features, target, name)?)
}
}) })
} }
@ -358,6 +368,7 @@ impl InlineAsmReg {
Self::S390x(r) => r.emit(out, arch, modifier), Self::S390x(r) => r.emit(out, arch, modifier),
Self::Bpf(r) => r.emit(out, arch, modifier), Self::Bpf(r) => r.emit(out, arch, modifier),
Self::Avr(r) => r.emit(out, arch, modifier), Self::Avr(r) => r.emit(out, arch, modifier),
Self::Msp430(r) => r.emit(out, arch, modifier),
Self::Err => unreachable!("Use of InlineAsmReg::Err"), Self::Err => unreachable!("Use of InlineAsmReg::Err"),
} }
} }
@ -374,6 +385,7 @@ impl InlineAsmReg {
Self::S390x(_) => cb(self), Self::S390x(_) => cb(self),
Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))), Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))),
Self::Avr(r) => r.overlapping_regs(|r| cb(Self::Avr(r))), Self::Avr(r) => r.overlapping_regs(|r| cb(Self::Avr(r))),
Self::Msp430(_) => cb(self),
Self::Err => unreachable!("Use of InlineAsmReg::Err"), Self::Err => unreachable!("Use of InlineAsmReg::Err"),
} }
} }
@ -405,6 +417,7 @@ pub enum InlineAsmRegClass {
Wasm(WasmInlineAsmRegClass), Wasm(WasmInlineAsmRegClass),
Bpf(BpfInlineAsmRegClass), Bpf(BpfInlineAsmRegClass),
Avr(AvrInlineAsmRegClass), Avr(AvrInlineAsmRegClass),
Msp430(Msp430InlineAsmRegClass),
// Placeholder for invalid register constraints for the current target // Placeholder for invalid register constraints for the current target
Err, Err,
} }
@ -425,6 +438,7 @@ impl InlineAsmRegClass {
Self::Wasm(r) => r.name(), Self::Wasm(r) => r.name(),
Self::Bpf(r) => r.name(), Self::Bpf(r) => r.name(),
Self::Avr(r) => r.name(), Self::Avr(r) => r.name(),
Self::Msp430(r) => r.name(),
Self::Err => rustc_span::symbol::sym::reg, Self::Err => rustc_span::symbol::sym::reg,
} }
} }
@ -447,6 +461,7 @@ impl InlineAsmRegClass {
Self::Wasm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Wasm), Self::Wasm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Wasm),
Self::Bpf(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Bpf), Self::Bpf(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Bpf),
Self::Avr(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Avr), Self::Avr(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Avr),
Self::Msp430(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Msp430),
Self::Err => unreachable!("Use of InlineAsmRegClass::Err"), Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
} }
} }
@ -476,6 +491,7 @@ impl InlineAsmRegClass {
Self::Wasm(r) => r.suggest_modifier(arch, ty), Self::Wasm(r) => r.suggest_modifier(arch, ty),
Self::Bpf(r) => r.suggest_modifier(arch, ty), Self::Bpf(r) => r.suggest_modifier(arch, ty),
Self::Avr(r) => r.suggest_modifier(arch, ty), Self::Avr(r) => r.suggest_modifier(arch, ty),
Self::Msp430(r) => r.suggest_modifier(arch, ty),
Self::Err => unreachable!("Use of InlineAsmRegClass::Err"), Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
} }
} }
@ -501,6 +517,7 @@ impl InlineAsmRegClass {
Self::Wasm(r) => r.default_modifier(arch), Self::Wasm(r) => r.default_modifier(arch),
Self::Bpf(r) => r.default_modifier(arch), Self::Bpf(r) => r.default_modifier(arch),
Self::Avr(r) => r.default_modifier(arch), Self::Avr(r) => r.default_modifier(arch),
Self::Msp430(r) => r.default_modifier(arch),
Self::Err => unreachable!("Use of InlineAsmRegClass::Err"), Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
} }
} }
@ -525,6 +542,7 @@ impl InlineAsmRegClass {
Self::Wasm(r) => r.supported_types(arch), Self::Wasm(r) => r.supported_types(arch),
Self::Bpf(r) => r.supported_types(arch), Self::Bpf(r) => r.supported_types(arch),
Self::Avr(r) => r.supported_types(arch), Self::Avr(r) => r.supported_types(arch),
Self::Msp430(r) => r.supported_types(arch),
Self::Err => unreachable!("Use of InlineAsmRegClass::Err"), Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
} }
} }
@ -554,6 +572,7 @@ impl InlineAsmRegClass {
} }
InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmRegClass::parse(arch, name)?), InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmRegClass::parse(arch, name)?),
InlineAsmArch::Avr => Self::Avr(AvrInlineAsmRegClass::parse(arch, name)?), InlineAsmArch::Avr => Self::Avr(AvrInlineAsmRegClass::parse(arch, name)?),
InlineAsmArch::Msp430 => Self::Msp430(Msp430InlineAsmRegClass::parse(arch, name)?),
}) })
} }
@ -574,6 +593,7 @@ impl InlineAsmRegClass {
Self::Wasm(r) => r.valid_modifiers(arch), Self::Wasm(r) => r.valid_modifiers(arch),
Self::Bpf(r) => r.valid_modifiers(arch), Self::Bpf(r) => r.valid_modifiers(arch),
Self::Avr(r) => r.valid_modifiers(arch), Self::Avr(r) => r.valid_modifiers(arch),
Self::Msp430(r) => r.valid_modifiers(arch),
Self::Err => unreachable!("Use of InlineAsmRegClass::Err"), Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
} }
} }
@ -764,6 +784,11 @@ pub fn allocatable_registers(
avr::fill_reg_map(arch, target_features, target, &mut map); avr::fill_reg_map(arch, target_features, target, &mut map);
map map
} }
InlineAsmArch::Msp430 => {
let mut map = msp430::regclass_map();
msp430::fill_reg_map(arch, target_features, target, &mut map);
map
}
} }
} }

View file

@ -0,0 +1,81 @@
use super::{InlineAsmArch, InlineAsmType};
use rustc_macros::HashStable_Generic;
use rustc_span::Symbol;
use std::fmt;
def_reg_class! {
Msp430 Msp430InlineAsmRegClass {
reg,
}
}
impl Msp430InlineAsmRegClass {
pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] {
&[]
}
pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
None
}
pub fn suggest_modifier(
self,
_arch: InlineAsmArch,
_ty: InlineAsmType,
) -> Option<(char, &'static str)> {
None
}
pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
None
}
pub fn supported_types(
self,
arch: InlineAsmArch,
) -> &'static [(InlineAsmType, Option<Symbol>)] {
match (self, arch) {
(Self::reg, _) => types! { _: I8, I16; },
}
}
}
// The reserved registers are taken from:
// https://github.com/llvm/llvm-project/blob/36cb29cbbe1b22dcd298ad65e1fabe899b7d7249/llvm/lib/Target/MSP430/MSP430RegisterInfo.cpp#L73.
def_regs! {
Msp430 Msp430InlineAsmReg Msp430InlineAsmRegClass {
r5: reg = ["r5"],
r6: reg = ["r6"],
r7: reg = ["r7"],
r8: reg = ["r8"],
r9: reg = ["r9"],
r10: reg = ["r10"],
r11: reg = ["r11"],
r12: reg = ["r12"],
r13: reg = ["r13"],
r14: reg = ["r14"],
r15: reg = ["r15"],
#error = ["r0", "pc"] =>
"the program counter cannot be used as an operand for inline asm",
#error = ["r1", "sp"] =>
"the stack pointer cannot be used as an operand for inline asm",
#error = ["r2", "sr"] =>
"the status register cannot be used as an operand for inline asm",
#error = ["r3", "cg"] =>
"the constant generator cannot be used as an operand for inline asm",
#error = ["r4", "fp"] =>
"the frame pointer cannot be used as an operand for inline asm",
}
}
impl Msp430InlineAsmReg {
pub fn emit(
self,
out: &mut dyn fmt::Write,
_arch: InlineAsmArch,
_modifier: Option<char>,
) -> fmt::Result {
out.write_str(self.name())
}
}

View file

@ -312,7 +312,7 @@ fn check_gat_where_clauses(
// of the function signature. In our example, the GAT in the return // of the function signature. In our example, the GAT in the return
// type is `<Self as LendingIterator>::Item<'a>`, so 'a and Self are arguments. // type is `<Self as LendingIterator>::Item<'a>`, so 'a and Self are arguments.
let (regions, types) = let (regions, types) =
GATSubstCollector::visit(trait_item.def_id.to_def_id(), sig.output()); GATSubstCollector::visit(tcx, trait_item.def_id.to_def_id(), sig.output());
// If both regions and types are empty, then this GAT isn't in the // If both regions and types are empty, then this GAT isn't in the
// return type, and we shouldn't try to do clause analysis // return type, and we shouldn't try to do clause analysis
@ -602,6 +602,7 @@ fn resolve_regions_with_wf_tys<'tcx>(
/// the two vectors, `regions` and `types` (depending on their kind). For each /// the two vectors, `regions` and `types` (depending on their kind). For each
/// parameter `Pi` also track the index `i`. /// parameter `Pi` also track the index `i`.
struct GATSubstCollector<'tcx> { struct GATSubstCollector<'tcx> {
tcx: TyCtxt<'tcx>,
gat: DefId, gat: DefId,
// Which region appears and which parameter index its subsituted for // Which region appears and which parameter index its subsituted for
regions: FxHashSet<(ty::Region<'tcx>, usize)>, regions: FxHashSet<(ty::Region<'tcx>, usize)>,
@ -611,11 +612,16 @@ struct GATSubstCollector<'tcx> {
impl<'tcx> GATSubstCollector<'tcx> { impl<'tcx> GATSubstCollector<'tcx> {
fn visit<T: TypeFoldable<'tcx>>( fn visit<T: TypeFoldable<'tcx>>(
tcx: TyCtxt<'tcx>,
gat: DefId, gat: DefId,
t: T, t: T,
) -> (FxHashSet<(ty::Region<'tcx>, usize)>, FxHashSet<(Ty<'tcx>, usize)>) { ) -> (FxHashSet<(ty::Region<'tcx>, usize)>, FxHashSet<(Ty<'tcx>, usize)>) {
let mut visitor = let mut visitor = GATSubstCollector {
GATSubstCollector { gat, regions: FxHashSet::default(), types: FxHashSet::default() }; tcx,
gat,
regions: FxHashSet::default(),
types: FxHashSet::default(),
};
t.visit_with(&mut visitor); t.visit_with(&mut visitor);
(visitor.regions, visitor.types) (visitor.regions, visitor.types)
} }
@ -624,6 +630,13 @@ impl<'tcx> GATSubstCollector<'tcx> {
impl<'tcx> TypeVisitor<'tcx> for GATSubstCollector<'tcx> { impl<'tcx> TypeVisitor<'tcx> for GATSubstCollector<'tcx> {
type BreakTy = !; type BreakTy = !;
fn visit_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: &ty::Binder<'tcx, T>,
) -> ControlFlow<Self::BreakTy> {
self.tcx.liberate_late_bound_regions(self.gat, t.clone()).visit_with(self)
}
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match t.kind() { match t.kind() {
ty::Projection(p) if p.item_def_id == self.gat => { ty::Projection(p) if p.item_def_id == self.gat => {

View file

@ -180,6 +180,12 @@ use crate::time::Duration;
#[macro_use] #[macro_use]
mod local; mod local;
#[unstable(feature = "scoped_threads", issue = "93203")]
mod scoped;
#[unstable(feature = "scoped_threads", issue = "93203")]
pub use scoped::{scope, Scope, ScopedJoinHandle};
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub use self::local::{AccessError, LocalKey}; pub use self::local::{AccessError, LocalKey};
@ -446,6 +452,20 @@ impl Builder {
F: FnOnce() -> T, F: FnOnce() -> T,
F: Send + 'a, F: Send + 'a,
T: Send + 'a, T: Send + 'a,
{
Ok(JoinHandle(unsafe { self.spawn_unchecked_(f, None) }?))
}
unsafe fn spawn_unchecked_<'a, 'scope, F, T>(
self,
f: F,
scope_data: Option<&'scope scoped::ScopeData>,
) -> io::Result<JoinInner<'scope, T>>
where
F: FnOnce() -> T,
F: Send + 'a,
T: Send + 'a,
'scope: 'a,
{ {
let Builder { name, stack_size } = self; let Builder { name, stack_size } = self;
@ -456,7 +476,8 @@ impl Builder {
})); }));
let their_thread = my_thread.clone(); let their_thread = my_thread.clone();
let my_packet: Arc<UnsafeCell<Option<Result<T>>>> = Arc::new(UnsafeCell::new(None)); let my_packet: Arc<Packet<'scope, T>> =
Arc::new(Packet { scope: scope_data, result: UnsafeCell::new(None) });
let their_packet = my_packet.clone(); let their_packet = my_packet.clone();
let output_capture = crate::io::set_output_capture(None); let output_capture = crate::io::set_output_capture(None);
@ -480,10 +501,14 @@ impl Builder {
// closure (it is an Arc<...>) and `my_packet` will be stored in the // closure (it is an Arc<...>) and `my_packet` will be stored in the
// same `JoinInner` as this closure meaning the mutation will be // same `JoinInner` as this closure meaning the mutation will be
// safe (not modify it and affect a value far away). // safe (not modify it and affect a value far away).
unsafe { *their_packet.get() = Some(try_result) }; unsafe { *their_packet.result.get() = Some(try_result) };
}; };
Ok(JoinHandle(JoinInner { if let Some(scope_data) = scope_data {
scope_data.increment_num_running_threads();
}
Ok(JoinInner {
// SAFETY: // SAFETY:
// //
// `imp::Thread::new` takes a closure with a `'static` lifetime, since it's passed // `imp::Thread::new` takes a closure with a `'static` lifetime, since it's passed
@ -506,8 +531,8 @@ impl Builder {
)? )?
}, },
thread: my_thread, thread: my_thread,
packet: Packet(my_packet), packet: my_packet,
})) })
} }
} }
@ -1242,34 +1267,48 @@ impl fmt::Debug for Thread {
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub type Result<T> = crate::result::Result<T, Box<dyn Any + Send + 'static>>; pub type Result<T> = crate::result::Result<T, Box<dyn Any + Send + 'static>>;
// This packet is used to communicate the return value between the spawned thread // This packet is used to communicate the return value between the spawned
// and the rest of the program. Memory is shared through the `Arc` within and there's // thread and the rest of the program. It is shared through an `Arc` and
// no need for a mutex here because synchronization happens with `join()` (the // there's no need for a mutex here because synchronization happens with `join()`
// caller will never read this packet until the thread has exited). // (the caller will never read this packet until the thread has exited).
// //
// This packet itself is then stored into a `JoinInner` which in turns is placed // An Arc to the packet is stored into a `JoinInner` which in turns is placed
// in `JoinHandle` and `JoinGuard`. Due to the usage of `UnsafeCell` we need to // in `JoinHandle`.
// manually worry about impls like Send and Sync. The type `T` should struct Packet<'scope, T> {
// already always be Send (otherwise the thread could not have been created) and scope: Option<&'scope scoped::ScopeData>,
// this type is inherently Sync because no methods take &self. Regardless, result: UnsafeCell<Option<Result<T>>>,
// however, we add inheriting impls for Send/Sync to this type to ensure it's
// Send/Sync and that future modifications will still appropriately classify it.
struct Packet<T>(Arc<UnsafeCell<Option<Result<T>>>>);
unsafe impl<T: Send> Send for Packet<T> {}
unsafe impl<T: Sync> Sync for Packet<T> {}
/// Inner representation for JoinHandle
struct JoinInner<T> {
native: imp::Thread,
thread: Thread,
packet: Packet<T>,
} }
impl<T> JoinInner<T> { // Due to the usage of `UnsafeCell` we need to manually implement Sync.
// The type `T` should already always be Send (otherwise the thread could not
// have been created) and the Packet is Sync because all access to the
// `UnsafeCell` synchronized (by the `join()` boundary), and `ScopeData` is Sync.
unsafe impl<'scope, T: Sync> Sync for Packet<'scope, T> {}
impl<'scope, T> Drop for Packet<'scope, T> {
fn drop(&mut self) {
// Book-keeping so the scope knows when it's done.
if let Some(scope) = self.scope {
// If this packet was for a thread that ran in a scope, the thread
// panicked, and nobody consumed the panic payload, we make sure
// the scope function will panic.
let unhandled_panic = matches!(self.result.get_mut(), Some(Err(_)));
scope.decrement_num_running_threads(unhandled_panic);
}
}
}
/// Inner representation for JoinHandle
struct JoinInner<'scope, T> {
native: imp::Thread,
thread: Thread,
packet: Arc<Packet<'scope, T>>,
}
impl<'scope, T> JoinInner<'scope, T> {
fn join(mut self) -> Result<T> { fn join(mut self) -> Result<T> {
self.native.join(); self.native.join();
Arc::get_mut(&mut self.packet.0).unwrap().get_mut().take().unwrap() Arc::get_mut(&mut self.packet).unwrap().result.get_mut().take().unwrap()
} }
} }
@ -1336,7 +1375,7 @@ impl<T> JoinInner<T> {
/// [`thread::Builder::spawn`]: Builder::spawn /// [`thread::Builder::spawn`]: Builder::spawn
/// [`thread::spawn`]: spawn /// [`thread::spawn`]: spawn
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub struct JoinHandle<T>(JoinInner<T>); pub struct JoinHandle<T>(JoinInner<'static, T>);
#[stable(feature = "joinhandle_impl_send_sync", since = "1.29.0")] #[stable(feature = "joinhandle_impl_send_sync", since = "1.29.0")]
unsafe impl<T> Send for JoinHandle<T> {} unsafe impl<T> Send for JoinHandle<T> {}
@ -1404,13 +1443,13 @@ impl<T> JoinHandle<T> {
self.0.join() self.0.join()
} }
/// Checks if the the associated thread is still running its main function. /// Checks if the associated thread is still running its main function.
/// ///
/// This might return `false` for a brief moment after the thread's main /// This might return `false` for a brief moment after the thread's main
/// function has returned, but before the thread itself has stopped running. /// function has returned, but before the thread itself has stopped running.
#[unstable(feature = "thread_is_running", issue = "90470")] #[unstable(feature = "thread_is_running", issue = "90470")]
pub fn is_running(&self) -> bool { pub fn is_running(&self) -> bool {
Arc::strong_count(&self.0.packet.0) > 1 Arc::strong_count(&self.0.packet) > 1
} }
} }

View file

@ -0,0 +1,316 @@
use super::{current, park, Builder, JoinInner, Result, Thread};
use crate::fmt;
use crate::io;
use crate::marker::PhantomData;
use crate::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
use crate::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use crate::sync::Arc;
/// A scope to spawn scoped threads in.
///
/// See [`scope`] for details.
pub struct Scope<'env> {
data: ScopeData,
/// Invariance over 'env, to make sure 'env cannot shrink,
/// which is necessary for soundness.
///
/// Without invariance, this would compile fine but be unsound:
///
/// ```compile_fail
/// #![feature(scoped_threads)]
///
/// std::thread::scope(|s| {
/// s.spawn(|s| {
/// let a = String::from("abcd");
/// s.spawn(|_| println!("{:?}", a)); // might run after `a` is dropped
/// });
/// });
/// ```
env: PhantomData<&'env mut &'env ()>,
}
/// An owned permission to join on a scoped thread (block on its termination).
///
/// See [`Scope::spawn`] for details.
pub struct ScopedJoinHandle<'scope, T>(JoinInner<'scope, T>);
pub(super) struct ScopeData {
num_running_threads: AtomicUsize,
a_thread_panicked: AtomicBool,
main_thread: Thread,
}
impl ScopeData {
pub(super) fn increment_num_running_threads(&self) {
// We check for 'overflow' with usize::MAX / 2, to make sure there's no
// chance it overflows to 0, which would result in unsoundness.
if self.num_running_threads.fetch_add(1, Ordering::Relaxed) > usize::MAX / 2 {
// This can only reasonably happen by mem::forget()'ing many many ScopedJoinHandles.
self.decrement_num_running_threads(false);
panic!("too many running threads in thread scope");
}
}
pub(super) fn decrement_num_running_threads(&self, panic: bool) {
if panic {
self.a_thread_panicked.store(true, Ordering::Relaxed);
}
if self.num_running_threads.fetch_sub(1, Ordering::Release) == 1 {
self.main_thread.unpark();
}
}
}
/// Create a scope for spawning scoped threads.
///
/// The function passed to `scope` will be provided a [`Scope`] object,
/// through which scoped threads can be [spawned][`Scope::spawn`].
///
/// Unlike non-scoped threads, scoped threads can borrow non-`'static` data,
/// as the scope guarantees all threads will be joined at the end of the scope.
///
/// All threads spawned within the scope that haven't been manually joined
/// will be automatically joined before this function returns.
///
/// # Panics
///
/// If any of the automatically joined threads panicked, this function will panic.
///
/// If you want to handle panics from spawned threads,
/// [`join`][ScopedJoinHandle::join] them before the end of the scope.
///
/// # Example
///
/// ```
/// #![feature(scoped_threads)]
/// use std::thread;
///
/// let mut a = vec![1, 2, 3];
/// let mut x = 0;
///
/// thread::scope(|s| {
/// s.spawn(|_| {
/// println!("hello from the first scoped thread");
/// // We can borrow `a` here.
/// dbg!(&a);
/// });
/// s.spawn(|_| {
/// println!("hello from the second scoped thread");
/// // We can even mutably borrow `x` here,
/// // because no other threads are using it.
/// x += a[0] + a[2];
/// });
/// println!("hello from the main thread");
/// });
///
/// // After the scope, we can modify and access our variables again:
/// a.push(4);
/// assert_eq!(x, a.len());
/// ```
#[track_caller]
pub fn scope<'env, F, T>(f: F) -> T
where
F: FnOnce(&Scope<'env>) -> T,
{
let scope = Scope {
data: ScopeData {
num_running_threads: AtomicUsize::new(0),
main_thread: current(),
a_thread_panicked: AtomicBool::new(false),
},
env: PhantomData,
};
// Run `f`, but catch panics so we can make sure to wait for all the threads to join.
let result = catch_unwind(AssertUnwindSafe(|| f(&scope)));
// Wait until all the threads are finished.
while scope.data.num_running_threads.load(Ordering::Acquire) != 0 {
park();
}
// Throw any panic from `f`, or the return value of `f` if no thread panicked.
match result {
Err(e) => resume_unwind(e),
Ok(_) if scope.data.a_thread_panicked.load(Ordering::Relaxed) => {
panic!("a scoped thread panicked")
}
Ok(result) => result,
}
}
impl<'env> Scope<'env> {
/// Spawns a new thread within a scope, returning a [`ScopedJoinHandle`] for it.
///
/// Unlike non-scoped threads, threads spawned with this function may
/// borrow non-`'static` data from the outside the scope. See [`scope`] for
/// details.
///
/// The join handle provides a [`join`] method that can be used to join the spawned
/// thread. If the spawned thread panics, [`join`] will return an [`Err`] containing
/// the panic payload.
///
/// If the join handle is dropped, the spawned thread will implicitly joined at the
/// end of the scope. In that case, if the spawned thread panics, [`scope`] will
/// panic after all threads are joined.
///
/// This call will create a thread using default parameters of [`Builder`].
/// If you want to specify the stack size or the name of the thread, use
/// [`Builder::spawn_scoped`] instead.
///
/// # Panics
///
/// Panics if the OS fails to create a thread; use [`Builder::spawn_scoped`]
/// to recover from such errors.
///
/// [`join`]: ScopedJoinHandle::join
pub fn spawn<'scope, F, T>(&'scope self, f: F) -> ScopedJoinHandle<'scope, T>
where
F: FnOnce(&Scope<'env>) -> T + Send + 'env,
T: Send + 'env,
{
Builder::new().spawn_scoped(self, f).expect("failed to spawn thread")
}
}
impl Builder {
/// Spawns a new scoped thread using the settings set through this `Builder`.
///
/// Unlike [`Scope::spawn`], this method yields an [`io::Result`] to
/// capture any failure to create the thread at the OS level.
///
/// [`io::Result`]: crate::io::Result
///
/// # Panics
///
/// Panics if a thread name was set and it contained null bytes.
///
/// # Example
///
/// ```
/// #![feature(scoped_threads)]
/// use std::thread;
///
/// let mut a = vec![1, 2, 3];
/// let mut x = 0;
///
/// thread::scope(|s| {
/// thread::Builder::new()
/// .name("first".to_string())
/// .spawn_scoped(s, |_|
/// {
/// println!("hello from the {:?} scoped thread", thread::current().name());
/// // We can borrow `a` here.
/// dbg!(&a);
/// })
/// .unwrap();
/// thread::Builder::new()
/// .name("second".to_string())
/// .spawn_scoped(s, |_|
/// {
/// println!("hello from the {:?} scoped thread", thread::current().name());
/// // We can even mutably borrow `x` here,
/// // because no other threads are using it.
/// x += a[0] + a[2];
/// })
/// .unwrap();
/// println!("hello from the main thread");
/// });
///
/// // After the scope, we can modify and access our variables again:
/// a.push(4);
/// assert_eq!(x, a.len());
/// ```
pub fn spawn_scoped<'scope, 'env, F, T>(
self,
scope: &'scope Scope<'env>,
f: F,
) -> io::Result<ScopedJoinHandle<'scope, T>>
where
F: FnOnce(&Scope<'env>) -> T + Send + 'env,
T: Send + 'env,
{
Ok(ScopedJoinHandle(unsafe { self.spawn_unchecked_(|| f(scope), Some(&scope.data)) }?))
}
}
impl<'scope, T> ScopedJoinHandle<'scope, T> {
/// Extracts a handle to the underlying thread.
///
/// # Examples
///
/// ```
/// #![feature(scoped_threads)]
/// #![feature(thread_is_running)]
///
/// use std::thread;
///
/// thread::scope(|s| {
/// let t = s.spawn(|_| {
/// println!("hello");
/// });
/// println!("thread id: {:?}", t.thread().id());
/// });
/// ```
#[must_use]
pub fn thread(&self) -> &Thread {
&self.0.thread
}
/// Waits for the associated thread to finish.
///
/// This function will return immediately if the associated thread has already finished.
///
/// In terms of [atomic memory orderings], the completion of the associated
/// thread synchronizes with this function returning.
/// In other words, all operations performed by that thread
/// [happen before](https://doc.rust-lang.org/nomicon/atomics.html#data-accesses)
/// all operations that happen after `join` returns.
///
/// If the associated thread panics, [`Err`] is returned with the panic payload.
///
/// [atomic memory orderings]: crate::sync::atomic
///
/// # Examples
///
/// ```
/// #![feature(scoped_threads)]
/// #![feature(thread_is_running)]
///
/// use std::thread;
///
/// thread::scope(|s| {
/// let t = s.spawn(|_| {
/// panic!("oh no");
/// });
/// assert!(t.join().is_err());
/// });
/// ```
pub fn join(self) -> Result<T> {
self.0.join()
}
/// Checks if the associated thread is still running its main function.
///
/// This might return `false` for a brief moment after the thread's main
/// function has returned, but before the thread itself has stopped running.
#[unstable(feature = "thread_is_running", issue = "90470")]
pub fn is_running(&self) -> bool {
Arc::strong_count(&self.0.packet) > 1
}
}
impl<'env> fmt::Debug for Scope<'env> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Scope")
.field("num_running_threads", &self.data.num_running_threads.load(Ordering::Relaxed))
.field("a_thread_panicked", &self.data.a_thread_panicked.load(Ordering::Relaxed))
.field("main_thread", &self.data.main_thread)
.finish_non_exhaustive()
}
}
impl<'scope, T> fmt::Debug for ScopedJoinHandle<'scope, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ScopedJoinHandle").finish_non_exhaustive()
}
}

View file

@ -15,6 +15,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
- BPF - BPF
- SPIR-V - SPIR-V
- AVR - AVR
- MSP430
## Register classes ## Register classes
@ -39,6 +40,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
| AVR | `reg_pair` | `r3r2` .. `r25r24`, `X`, `Z` | `r` | | AVR | `reg_pair` | `r3r2` .. `r25r24`, `X`, `Z` | `r` |
| AVR | `reg_iw` | `r25r24`, `X`, `Z` | `w` | | AVR | `reg_iw` | `r25r24`, `X`, `Z` | `w` |
| AVR | `reg_ptr` | `X`, `Z` | `e` | | AVR | `reg_ptr` | `X`, `Z` | `e` |
| MSP430 | `reg` | `r[0-15]` | `r` |
> **Notes**: > **Notes**:
> - NVPTX doesn't have a fixed register set, so named registers are not supported. > - NVPTX doesn't have a fixed register set, so named registers are not supported.
@ -67,6 +69,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
| BPF | `wreg` | `alu32` | `i8` `i16` `i32` | | BPF | `wreg` | `alu32` | `i8` `i16` `i32` |
| AVR | `reg`, `reg_upper` | None | `i8` | | AVR | `reg`, `reg_upper` | None | `i8` |
| AVR | `reg_pair`, `reg_iw`, `reg_ptr` | None | `i16` | | AVR | `reg_pair`, `reg_iw`, `reg_ptr` | None | `i16` |
| MSP430 | `reg` | None | `i8`, `i16` |
## Register aliases ## Register aliases
@ -80,13 +83,22 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
| AVR | `XL` | `r26` | | AVR | `XL` | `r26` |
| AVR | `ZH` | `r31` | | AVR | `ZH` | `r31` |
| AVR | `ZL` | `r30` | | AVR | `ZL` | `r30` |
| MSP430 | `r0` | `pc` |
| MSP430 | `r1` | `sp` |
| MSP430 | `r2` | `sr` |
| MSP430 | `r3` | `cg` |
| MSP430 | `r4` | `fp` |
> **Notes**:
> - TI does not mandate a frame pointer for MSP430, but toolchains are allowed
to use one; LLVM uses `r4`.
## Unsupported registers ## Unsupported registers
| Architecture | Unsupported register | Reason | | Architecture | Unsupported register | Reason |
| ------------ | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ------------ | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| All | `sp` | The stack pointer must be restored to its original value at the end of an asm code block. | | All | `sp` | The stack pointer must be restored to its original value at the end of an asm code block. |
| All | `fr` (Hexagon), `$fp` (MIPS), `Y` (AVR) | The frame pointer cannot be used as an input or output. | | All | `fr` (Hexagon), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430) | The frame pointer cannot be used as an input or output. |
| All | `r19` (Hexagon) | This is used internally by LLVM as a "base pointer" for functions with complex stack frames. | | All | `r19` (Hexagon) | This is used internally by LLVM as a "base pointer" for functions with complex stack frames. |
| MIPS | `$0` or `$zero` | This is a constant zero register which can't be modified. | | MIPS | `$0` or `$zero` | This is a constant zero register which can't be modified. |
| MIPS | `$1` or `$at` | Reserved for assembler. | | MIPS | `$1` or `$at` | Reserved for assembler. |
@ -95,6 +107,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
| MIPS | `$ra` | Return address cannot be used as inputs or outputs. | | MIPS | `$ra` | Return address cannot be used as inputs or outputs. |
| Hexagon | `lr` | This is the link register which cannot be used as an input or output. | | Hexagon | `lr` | This is the link register which cannot be used as an input or output. |
| AVR | `r0`, `r1`, `r1r0` | Due to an issue in LLVM, the `r0` and `r1` registers cannot be used as inputs or outputs. If modified, they must be restored to their original values before the end of the block. | | AVR | `r0`, `r1`, `r1r0` | Due to an issue in LLVM, the `r0` and `r1` registers cannot be used as inputs or outputs. If modified, they must be restored to their original values before the end of the block. |
|MSP430 | `r0`, `r2`, `r3` | These are the program counter, status register, and constant generator respectively. Neither the status register nor constant generator can be written to. |
## Template modifiers ## Template modifiers
@ -115,3 +128,5 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
These flags registers must be restored upon exiting the asm block if the `preserves_flags` option is set: These flags registers must be restored upon exiting the asm block if the `preserves_flags` option is set:
- AVR - AVR
- The status register `SREG`. - The status register `SREG`.
- MSP430
- The status register `r2`.

View file

@ -134,11 +134,13 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
if let Some(hir_id) = segment.hir_id { if let Some(hir_id) = segment.hir_id {
let hir = self.tcx.hir(); let hir = self.tcx.hir();
let body_id = hir.enclosing_body_owner(hir_id); let body_id = hir.enclosing_body_owner(hir_id);
let typeck_results = self.tcx.sess.with_disabled_diagnostic(|| { // FIXME: this is showing error messages for parts of the code that are not
self.tcx.typeck_body( // compiled (because of cfg)!
hir.maybe_body_owned_by(body_id).expect("a body which isn't a body"), //
) // See discussion in https://github.com/rust-lang/rust/issues/69426#issuecomment-1019412352
}); let typeck_results = self.tcx.typeck_body(
hir.maybe_body_owned_by(body_id).expect("a body which isn't a body"),
);
if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) { if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) {
self.matches.insert( self.matches.insert(
segment.ident.span, segment.ident.span,

View file

@ -0,0 +1,158 @@
// min-llvm-version: 13.0
// assembly-output: emit-asm
// compile-flags: --target msp430-none-elf
// needs-llvm-components: msp430
#![feature(no_core, lang_items, rustc_attrs, asm_sym, asm_experimental_arch, asm_const)]
#![crate_type = "rlib"]
#![no_core]
#![allow(non_camel_case_types)]
#[rustc_builtin_macro]
macro_rules! asm {
() => {};
}
#[rustc_builtin_macro]
macro_rules! concat {
() => {};
}
#[lang = "sized"]
trait Sized {}
#[lang = "copy"]
trait Copy {}
type ptr = *const i16;
impl Copy for i8 {}
impl Copy for i16 {}
impl Copy for i32 {}
impl Copy for i64 {}
impl Copy for ptr {}
macro_rules! check {
($func:ident $ty:ident $class:ident) => {
#[no_mangle]
pub unsafe fn $func(x: $ty) -> $ty {
let y;
asm!("mov {}, {}", lateout($class) y, in($class) x);
y
}
};
}
macro_rules! checkb {
($func:ident $ty:ident $class:ident) => {
#[no_mangle]
pub unsafe fn $func(x: $ty) -> $ty {
let y;
asm!("mov.b {}, {}", lateout($class) y, in($class) x);
y
}
};
}
macro_rules! check_reg {
($func:ident $ty:ident $reg:tt) => {
#[no_mangle]
pub unsafe fn $func(x: $ty) -> $ty {
let y;
asm!(concat!("mov ", $reg, ", ", $reg), lateout($reg) y, in($reg) x);
y
}
};
}
macro_rules! check_regb {
($func:ident $ty:ident $reg:tt) => {
#[no_mangle]
pub unsafe fn $func(x: $ty) -> $ty {
let y;
asm!(concat!("mov.b ", $reg, ", ", $reg), lateout($reg) y, in($reg) x);
y
}
};
}
extern "C" {
fn extern_func();
static extern_static: i8;
}
// CHECK-LABEL: sym_fn
// CHECK: ;APP
// CHECK: call extern_func
// CHECK: ;NO_APP
#[no_mangle]
pub unsafe fn sym_fn() {
asm!("call {}", sym extern_func);
}
// CHECK-LABEL: sym_static
// CHECK: ;APP
// CHECK: mov.b extern_static, r{{[0-9]+}}
// CHECK: ;NO_APP
#[no_mangle]
pub unsafe fn sym_static() -> i8 {
let y;
asm!("mov.b {1}, {0}", lateout(reg) y, sym extern_static);
y
}
// CHECK-LABEL: add_const:
// CHECK: ;APP
// CHECK: add.b #5, r{{[0-9]+}}
// CHECK: ;NO_APP
#[no_mangle]
pub unsafe fn add_const() -> i8 {
let y;
asm!("add.b #{number}, {}", out(reg) y, number = const 5);
y
}
// CHECK-LABEL: mov_postincrement:
// CHECK: ;APP
// CHECK: mov @r5+, r{{[0-9]+}}
// CHECK: ;NO_APP
#[no_mangle]
pub unsafe fn mov_postincrement(mut x: *const i16) -> (i16, *const i16) {
let y;
asm!("mov @r5+, {0}", out(reg) y, inlateout("r5") x);
(y, x)
}
// CHECK-LABEL: reg_i8:
// CHECK: ;APP
// CHECK: mov r{{[0-9]+}}, r{{[0-9]+}}
// CHECK: ;NO_APP
check!(reg_i8 i8 reg);
// CHECK-LABEL: reg_i16:
// CHECK: ;APP
// CHECK: mov r{{[0-9]+}}, r{{[0-9]+}}
// CHECK: ;NO_APP
check!(reg_i16 i16 reg);
// CHECK-LABEL: reg_i8b:
// CHECK: ;APP
// CHECK: mov.b r{{[0-9]+}}, r{{[0-9]+}}
// CHECK: ;NO_APP
checkb!(reg_i8b i8 reg);
// CHECK-LABEL: r5_i8:
// CHECK: ;APP
// CHECK: mov r5, r5
// CHECK: ;NO_APP
check_reg!(r5_i8 i8 "r5");
// CHECK-LABEL: r5_i16:
// CHECK: ;APP
// CHECK: mov r5, r5
// CHECK: ;NO_APP
check_reg!(r5_i16 i16 "r5");
// CHECK-LABEL: r5_i8b:
// CHECK: ;APP
// CHECK: mov.b r5, r5
// CHECK: ;NO_APP
check_regb!(r5_i8b i8 "r5");

View file

@ -0,0 +1,10 @@
// check-pass
#![feature(generic_associated_types)]
pub trait Foo {
type Assoc<'c>;
fn function() -> for<'x> fn(Self::Assoc<'x>);
}
fn main() {}

View file

@ -0,0 +1,25 @@
// check-pass
#![feature(generic_associated_types)]
pub trait Fooey: Sized {
type Context<'c> where Self: 'c;
}
pub struct Handle<E: Fooey>(Option<Box<dyn for<'c> Fn(&mut E::Context<'c>)>>);
fn tuple<T>() -> (Option<T>,) { (Option::None,) }
pub struct FooImpl {}
impl Fooey for FooImpl {
type Context<'c> = &'c ();
}
impl FooImpl {
pub fn fail1() -> Handle<Self> {
let (tx,) = tuple();
Handle(tx)
}
}
fn main() {}

View file

@ -14,10 +14,12 @@ fn _if_let_guard() {
//~^ ERROR `let` expressions in this position are unstable //~^ ERROR `let` expressions in this position are unstable
() if true && let 0 = 1 => {} () if true && let 0 = 1 => {}
//~^ ERROR `let` expressions in this position are unstable //~^ ERROR `if let` guards are experimental
//~| ERROR `let` expressions in this position are unstable
() if let 0 = 1 && true => {} () if let 0 = 1 && true => {}
//~^ ERROR `let` expressions in this position are unstable //~^ ERROR `if let` guards are experimental
//~| ERROR `let` expressions in this position are unstable
() if (let 0 = 1) && true => {} () if (let 0 = 1) && true => {}
//~^ ERROR `let` expressions in this position are unstable //~^ ERROR `let` expressions in this position are unstable
@ -30,14 +32,17 @@ fn _if_let_guard() {
//~| ERROR `let` expressions in this position are unstable //~| ERROR `let` expressions in this position are unstable
() if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
//~^ ERROR `let` expressions in this position are unstable //~^ ERROR `if let` guards are experimental
//~| ERROR `let` expressions in this position are unstable
//~| ERROR `let` expressions in this position are unstable //~| ERROR `let` expressions in this position are unstable
//~| ERROR `let` expressions in this position are unstable //~| ERROR `let` expressions in this position are unstable
//~| ERROR `let` expressions in this position are unstable //~| ERROR `let` expressions in this position are unstable
//~| ERROR `let` expressions in this position are unstable //~| ERROR `let` expressions in this position are unstable
() if let Range { start: _, end: _ } = (true..true) && false => {} () if let Range { start: _, end: _ } = (true..true) && false => {}
//~^ ERROR `let` expressions in this position are unstable //~^ ERROR `if let` guards are experimental
//~| ERROR `let` expressions in this position are unstable
_ => {} _ => {}
} }
} }

View file

@ -1,5 +1,5 @@
error: no rules expected the token `let` error: no rules expected the token `let`
--> $DIR/feature-gate.rs:64:15 --> $DIR/feature-gate.rs:69:15
| |
LL | macro_rules! use_expr { LL | macro_rules! use_expr {
| --------------------- when calling this macro | --------------------- when calling this macro
@ -18,7 +18,47 @@ LL | () if let 0 = 1 => {}
= help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>` = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
error[E0658]: `if let` guards are experimental error[E0658]: `if let` guards are experimental
--> $DIR/feature-gate.rs:60:12 --> $DIR/feature-gate.rs:16:12
|
LL | () if true && let 0 = 1 => {}
| ^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #51114 <https://github.com/rust-lang/rust/issues/51114> for more information
= help: add `#![feature(if_let_guard)]` to the crate attributes to enable
= help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
error[E0658]: `if let` guards are experimental
--> $DIR/feature-gate.rs:20:12
|
LL | () if let 0 = 1 && true => {}
| ^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #51114 <https://github.com/rust-lang/rust/issues/51114> for more information
= help: add `#![feature(if_let_guard)]` to the crate attributes to enable
= help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
error[E0658]: `if let` guards are experimental
--> $DIR/feature-gate.rs:34:12
|
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #51114 <https://github.com/rust-lang/rust/issues/51114> for more information
= help: add `#![feature(if_let_guard)]` to the crate attributes to enable
= help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
error[E0658]: `if let` guards are experimental
--> $DIR/feature-gate.rs:42:12
|
LL | () if let Range { start: _, end: _ } = (true..true) && false => {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #51114 <https://github.com/rust-lang/rust/issues/51114> for more information
= help: add `#![feature(if_let_guard)]` to the crate attributes to enable
= help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
error[E0658]: `if let` guards are experimental
--> $DIR/feature-gate.rs:65:12
| |
LL | () if let 0 = 1 => {} LL | () if let 0 = 1 => {}
| ^^^^^^^^^^^^ | ^^^^^^^^^^^^
@ -55,7 +95,7 @@ LL | () if true && let 0 = 1 => {}
= help: add `#![feature(let_chains)]` to the crate attributes to enable = help: add `#![feature(let_chains)]` to the crate attributes to enable
error[E0658]: `let` expressions in this position are unstable error[E0658]: `let` expressions in this position are unstable
--> $DIR/feature-gate.rs:19:15 --> $DIR/feature-gate.rs:20:15
| |
LL | () if let 0 = 1 && true => {} LL | () if let 0 = 1 && true => {}
| ^^^^^^^^^ | ^^^^^^^^^
@ -64,7 +104,7 @@ LL | () if let 0 = 1 && true => {}
= help: add `#![feature(let_chains)]` to the crate attributes to enable = help: add `#![feature(let_chains)]` to the crate attributes to enable
error[E0658]: `let` expressions in this position are unstable error[E0658]: `let` expressions in this position are unstable
--> $DIR/feature-gate.rs:22:16 --> $DIR/feature-gate.rs:24:16
| |
LL | () if (let 0 = 1) && true => {} LL | () if (let 0 = 1) && true => {}
| ^^^^^^^^^ | ^^^^^^^^^
@ -73,7 +113,7 @@ LL | () if (let 0 = 1) && true => {}
= help: add `#![feature(let_chains)]` to the crate attributes to enable = help: add `#![feature(let_chains)]` to the crate attributes to enable
error[E0658]: `let` expressions in this position are unstable error[E0658]: `let` expressions in this position are unstable
--> $DIR/feature-gate.rs:25:24 --> $DIR/feature-gate.rs:27:24
| |
LL | () if true && (let 0 = 1) => {} LL | () if true && (let 0 = 1) => {}
| ^^^^^^^^^ | ^^^^^^^^^
@ -82,7 +122,7 @@ LL | () if true && (let 0 = 1) => {}
= help: add `#![feature(let_chains)]` to the crate attributes to enable = help: add `#![feature(let_chains)]` to the crate attributes to enable
error[E0658]: `let` expressions in this position are unstable error[E0658]: `let` expressions in this position are unstable
--> $DIR/feature-gate.rs:28:16 --> $DIR/feature-gate.rs:30:16
| |
LL | () if (let 0 = 1) && (let 0 = 1) => {} LL | () if (let 0 = 1) && (let 0 = 1) => {}
| ^^^^^^^^^ | ^^^^^^^^^
@ -91,7 +131,7 @@ LL | () if (let 0 = 1) && (let 0 = 1) => {}
= help: add `#![feature(let_chains)]` to the crate attributes to enable = help: add `#![feature(let_chains)]` to the crate attributes to enable
error[E0658]: `let` expressions in this position are unstable error[E0658]: `let` expressions in this position are unstable
--> $DIR/feature-gate.rs:28:31 --> $DIR/feature-gate.rs:30:31
| |
LL | () if (let 0 = 1) && (let 0 = 1) => {} LL | () if (let 0 = 1) && (let 0 = 1) => {}
| ^^^^^^^^^ | ^^^^^^^^^
@ -100,7 +140,7 @@ LL | () if (let 0 = 1) && (let 0 = 1) => {}
= help: add `#![feature(let_chains)]` to the crate attributes to enable = help: add `#![feature(let_chains)]` to the crate attributes to enable
error[E0658]: `let` expressions in this position are unstable error[E0658]: `let` expressions in this position are unstable
--> $DIR/feature-gate.rs:32:15 --> $DIR/feature-gate.rs:34:15
| |
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
| ^^^^^^^^^ | ^^^^^^^^^
@ -109,7 +149,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
= help: add `#![feature(let_chains)]` to the crate attributes to enable = help: add `#![feature(let_chains)]` to the crate attributes to enable
error[E0658]: `let` expressions in this position are unstable error[E0658]: `let` expressions in this position are unstable
--> $DIR/feature-gate.rs:32:28 --> $DIR/feature-gate.rs:34:28
| |
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
| ^^^^^^^^^ | ^^^^^^^^^
@ -118,7 +158,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
= help: add `#![feature(let_chains)]` to the crate attributes to enable = help: add `#![feature(let_chains)]` to the crate attributes to enable
error[E0658]: `let` expressions in this position are unstable error[E0658]: `let` expressions in this position are unstable
--> $DIR/feature-gate.rs:32:42 --> $DIR/feature-gate.rs:34:42
| |
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
| ^^^^^^^^^ | ^^^^^^^^^
@ -127,7 +167,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
= help: add `#![feature(let_chains)]` to the crate attributes to enable = help: add `#![feature(let_chains)]` to the crate attributes to enable
error[E0658]: `let` expressions in this position are unstable error[E0658]: `let` expressions in this position are unstable
--> $DIR/feature-gate.rs:32:55 --> $DIR/feature-gate.rs:34:55
| |
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
| ^^^^^^^^^ | ^^^^^^^^^
@ -136,7 +176,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
= help: add `#![feature(let_chains)]` to the crate attributes to enable = help: add `#![feature(let_chains)]` to the crate attributes to enable
error[E0658]: `let` expressions in this position are unstable error[E0658]: `let` expressions in this position are unstable
--> $DIR/feature-gate.rs:32:68 --> $DIR/feature-gate.rs:34:68
| |
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {} LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
| ^^^^^^^^^ | ^^^^^^^^^
@ -145,7 +185,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
= help: add `#![feature(let_chains)]` to the crate attributes to enable = help: add `#![feature(let_chains)]` to the crate attributes to enable
error[E0658]: `let` expressions in this position are unstable error[E0658]: `let` expressions in this position are unstable
--> $DIR/feature-gate.rs:39:15 --> $DIR/feature-gate.rs:42:15
| |
LL | () if let Range { start: _, end: _ } = (true..true) && false => {} LL | () if let Range { start: _, end: _ } = (true..true) && false => {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -154,7 +194,7 @@ LL | () if let Range { start: _, end: _ } = (true..true) && false => {}
= help: add `#![feature(let_chains)]` to the crate attributes to enable = help: add `#![feature(let_chains)]` to the crate attributes to enable
error[E0658]: `let` expressions in this position are unstable error[E0658]: `let` expressions in this position are unstable
--> $DIR/feature-gate.rs:54:16 --> $DIR/feature-gate.rs:59:16
| |
LL | use_expr!((let 0 = 1 && 0 == 0)); LL | use_expr!((let 0 = 1 && 0 == 0));
| ^^^^^^^^^ | ^^^^^^^^^
@ -163,7 +203,7 @@ LL | use_expr!((let 0 = 1 && 0 == 0));
= help: add `#![feature(let_chains)]` to the crate attributes to enable = help: add `#![feature(let_chains)]` to the crate attributes to enable
error[E0658]: `let` expressions in this position are unstable error[E0658]: `let` expressions in this position are unstable
--> $DIR/feature-gate.rs:56:16 --> $DIR/feature-gate.rs:61:16
| |
LL | use_expr!((let 0 = 1)); LL | use_expr!((let 0 = 1));
| ^^^^^^^^^ | ^^^^^^^^^
@ -171,6 +211,6 @@ LL | use_expr!((let 0 = 1));
= note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
= help: add `#![feature(let_chains)]` to the crate attributes to enable = help: add `#![feature(let_chains)]` to the crate attributes to enable
error: aborting due to 19 previous errors error: aborting due to 23 previous errors
For more information about this error, try `rustc --explain E0658`. For more information about this error, try `rustc --explain E0658`.

View file

@ -0,0 +1,8 @@
fn main() {
match true {
_ if let true = true && true => {}
//~^ ERROR `if let` guards are
//~| ERROR `let` expressions in this
_ => {}
}
}

View file

@ -0,0 +1,22 @@
error[E0658]: `if let` guards are experimental
--> $DIR/issue-93150.rs:3:11
|
LL | _ if let true = true && true => {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #51114 <https://github.com/rust-lang/rust/issues/51114> for more information
= help: add `#![feature(if_let_guard)]` to the crate attributes to enable
= help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
error[E0658]: `let` expressions in this position are unstable
--> $DIR/issue-93150.rs:3:14
|
LL | _ if let true = true && true => {}
| ^^^^^^^^^^^^^^^
|
= note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
= help: add `#![feature(let_chains)]` to the crate attributes to enable
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0658`.

View file

@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::{meets_msrv, msrvs}; use clippy_utils::{meets_msrv, msrvs};
use rustc_ast::ast::{FloatTy, LitFloatType, LitKind}; use rustc_ast::ast::{FloatTy, LitFloatType, LitKind};
use rustc_hir::{Expr, ExprKind}; use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass};
use rustc_semver::RustcVersion; use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::symbol; use rustc_span::symbol;

View file

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::diagnostics::span_lint_and_help;
use rustc_ast::ast::{Expr, ExprKind}; use rustc_ast::ast::{Expr, ExprKind};
use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_session::{declare_lint_pass, declare_tool_lint};
@ -48,7 +48,7 @@ declare_lint_pass!(AsConversions => [AS_CONVERSIONS]);
impl EarlyLintPass for AsConversions { impl EarlyLintPass for AsConversions {
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
if in_external_macro(cx.sess, expr.span) { if in_external_macro(cx.sess(), expr.span) {
return; return;
} }

View file

@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint; use clippy_utils::diagnostics::span_lint;
use rustc_ast::ast; use rustc_ast::ast;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_lint::{EarlyContext, EarlyLintPass, Level}; use rustc_lint::{EarlyContext, EarlyLintPass, Level, LintContext};
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use unicode_script::{Script, UnicodeScript}; use unicode_script::{Script, UnicodeScript};
@ -72,7 +72,7 @@ impl EarlyLintPass for DisallowedScriptIdents {
return; return;
} }
let symbols = cx.sess.parse_sess.symbol_gallery.symbols.lock(); let symbols = cx.sess().parse_sess.symbol_gallery.symbols.lock();
// Sort by `Span` so that error messages make sense with respect to the // Sort by `Span` so that error messages make sense with respect to the
// order of identifier locations in the code. // order of identifier locations in the code.
let mut symbols: Vec<_> = symbols.iter().collect(); let mut symbols: Vec<_> = symbols.iter().collect();

View file

@ -2,7 +2,7 @@
use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::diagnostics::span_lint_and_help;
use rustc_ast::ast::{Expr, ExprKind}; use rustc_ast::ast::{Expr, ExprKind};
use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_session::{declare_lint_pass, declare_tool_lint};
@ -50,7 +50,7 @@ declare_lint_pass!(ElseIfWithoutElse => [ELSE_IF_WITHOUT_ELSE]);
impl EarlyLintPass for ElseIfWithoutElse { impl EarlyLintPass for ElseIfWithoutElse {
fn check_expr(&mut self, cx: &EarlyContext<'_>, mut item: &Expr) { fn check_expr(&mut self, cx: &EarlyContext<'_>, mut item: &Expr) {
if in_external_macro(cx.sess, item.span) { if in_external_macro(cx.sess(), item.span) {
return; return;
} }

View file

@ -3,7 +3,7 @@ use clippy_utils::differing_macro_contexts;
use clippy_utils::source::snippet_opt; use clippy_utils::source::snippet_opt;
use if_chain::if_chain; use if_chain::if_chain;
use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp}; use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp};
use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span; use rustc_span::source_map::Span;
@ -207,7 +207,7 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) {
if let ExprKind::If(_, then, Some(else_)) = &expr.kind; if let ExprKind::If(_, then, Some(else_)) = &expr.kind;
if is_block(else_) || is_if(else_); if is_block(else_) || is_if(else_);
if !differing_macro_contexts(then.span, else_.span); if !differing_macro_contexts(then.span, else_.span);
if !then.span.from_expansion() && !in_external_macro(cx.sess, expr.span); if !then.span.from_expansion() && !in_external_macro(cx.sess(), expr.span);
// workaround for rust-lang/rust#43081 // workaround for rust-lang/rust#43081
if expr.span.lo().0 != 0 && expr.span.hi().0 != 0; if expr.span.lo().0 != 0 && expr.span.hi().0 != 0;
@ -259,7 +259,7 @@ fn has_unary_equivalent(bin_op: BinOpKind) -> bool {
} }
fn indentation(cx: &EarlyContext<'_>, span: Span) -> usize { fn indentation(cx: &EarlyContext<'_>, span: Span) -> usize {
cx.sess.source_map().lookup_char_pos(span.lo()).col.0 cx.sess().source_map().lookup_char_pos(span.lo()).col.0
} }
/// Implementation of the `POSSIBLE_MISSING_COMMA` lint for array /// Implementation of the `POSSIBLE_MISSING_COMMA` lint for array

View file

@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::{meets_msrv, msrvs}; use clippy_utils::{meets_msrv, msrvs};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass};
use rustc_semver::RustcVersion; use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::symbol::sym; use rustc_span::symbol::sym;

View file

@ -8,7 +8,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::intravisit::{self, Visitor};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter; use rustc_middle::hir::nested_filter;
use rustc_middle::ty; use rustc_middle::ty;
use rustc_semver::RustcVersion; use rustc_semver::RustcVersion;

View file

@ -2,7 +2,7 @@
use clippy_utils::diagnostics::span_lint; use clippy_utils::diagnostics::span_lint;
use rustc_ast::ast::{Block, ItemKind, StmtKind}; use rustc_ast::ast::{Block, ItemKind, StmtKind};
use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_session::{declare_lint_pass, declare_tool_lint};
@ -55,7 +55,7 @@ declare_lint_pass!(ItemsAfterStatements => [ITEMS_AFTER_STATEMENTS]);
impl EarlyLintPass for ItemsAfterStatements { impl EarlyLintPass for ItemsAfterStatements {
fn check_block(&mut self, cx: &EarlyContext<'_>, item: &Block) { fn check_block(&mut self, cx: &EarlyContext<'_>, item: &Block) {
if in_external_macro(cx.sess, item.span) { if in_external_macro(cx.sess(), item.span) {
return; return;
} }
@ -69,7 +69,7 @@ impl EarlyLintPass for ItemsAfterStatements {
// lint on all further items // lint on all further items
for stmt in stmts { for stmt in stmts {
if let StmtKind::Item(ref it) = *stmt { if let StmtKind::Item(ref it) = *stmt {
if in_external_macro(cx.sess, it.span) { if in_external_macro(cx.sess(), it.span) {
return; return;
} }
if let ItemKind::MacroDef(..) = it.kind { if let ItemKind::MacroDef(..) = it.kind {

View file

@ -7,7 +7,7 @@ use clippy_utils::source::snippet_opt;
use if_chain::if_chain; use if_chain::if_chain;
use rustc_ast::ast::{Expr, ExprKind, Lit, LitKind}; use rustc_ast::ast::{Expr, ExprKind, Lit, LitKind};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use std::iter; use std::iter;
@ -225,7 +225,7 @@ impl_lint_pass!(LiteralDigitGrouping => [
impl EarlyLintPass for LiteralDigitGrouping { impl EarlyLintPass for LiteralDigitGrouping {
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
if in_external_macro(cx.sess, expr.span) { if in_external_macro(cx.sess(), expr.span) {
return; return;
} }
@ -418,7 +418,7 @@ impl_lint_pass!(DecimalLiteralRepresentation => [DECIMAL_LITERAL_REPRESENTATION]
impl EarlyLintPass for DecimalLiteralRepresentation { impl EarlyLintPass for DecimalLiteralRepresentation {
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
if in_external_macro(cx.sess, expr.span) { if in_external_macro(cx.sess(), expr.span) {
return; return;
} }

View file

@ -5,7 +5,7 @@ use clippy_utils::{meets_msrv, msrvs};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_ast::ast::{FieldDef, Item, ItemKind, Variant, VariantData, VisibilityKind}; use rustc_ast::ast::{FieldDef, Item, ItemKind, Variant, VariantData, VisibilityKind};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_semver::RustcVersion; use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{sym, Span}; use rustc_span::{sym, Span};
@ -116,7 +116,7 @@ fn check_manual_non_exhaustive_enum(cx: &EarlyContext<'_>, item: &Item, variants
|diag| { |diag| {
if_chain! { if_chain! {
if !item.attrs.iter().any(|attr| attr.has_name(sym::non_exhaustive)); if !item.attrs.iter().any(|attr| attr.has_name(sym::non_exhaustive));
let header_span = cx.sess.source_map().span_until_char(item.span, '{'); let header_span = cx.sess().source_map().span_until_char(item.span, '{');
if let Some(snippet) = snippet_opt(cx, header_span); if let Some(snippet) = snippet_opt(cx, header_span);
then { then {
diag.span_suggestion( diag.span_suggestion(
@ -149,7 +149,7 @@ fn check_manual_non_exhaustive_struct(cx: &EarlyContext<'_>, item: &Item, data:
VariantData::Unit(_) => unreachable!("`VariantData::Unit` is already handled above"), VariantData::Unit(_) => unreachable!("`VariantData::Unit` is already handled above"),
}; };
cx.sess.source_map().span_until_char(item.span, delimiter) cx.sess().source_map().span_until_char(item.span, delimiter)
} }
let fields = data.fields(); let fields = data.fields();

View file

@ -9,7 +9,7 @@ use rustc_hir::def::Res;
use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::intravisit::{walk_expr, Visitor};
use rustc_hir::BinOpKind; use rustc_hir::BinOpKind;
use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_hir::{BorrowKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty; use rustc_middle::ty;
use rustc_semver::RustcVersion; use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};

View file

@ -25,7 +25,7 @@ use rustc_hir::{
Mutability, Node, Pat, PatKind, PathSegment, QPath, RangeEnd, TyKind, Mutability, Node, Pat, PatKind, PathSegment, QPath, RangeEnd, TyKind,
}; };
use rustc_hir::{HirIdMap, HirIdSet}; use rustc_hir::{HirIdMap, HirIdSet};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, Ty, TyS, VariantDef}; use rustc_middle::ty::{self, Ty, TyS, VariantDef};
use rustc_semver::RustcVersion; use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};

View file

@ -6,7 +6,7 @@ use if_chain::if_chain;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::LangItem::OptionNone; use rustc_hir::LangItem::OptionNone;
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, QPath}; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, QPath};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_semver::RustcVersion; use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};

View file

@ -12,7 +12,7 @@ use clippy_utils::source::snippet_opt;
use rustc_ast::ast::{Expr, ExprKind, Generics, Lit, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind}; use rustc_ast::ast::{Expr, ExprKind, Generics, Lit, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind};
use rustc_ast::visit::FnKind; use rustc_ast::visit::FnKind;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span; use rustc_span::source_map::Span;
@ -342,7 +342,7 @@ impl EarlyLintPass for MiscEarlyLints {
} }
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
if in_external_macro(cx.sess, expr.span) { if in_external_macro(cx.sess(), expr.span) {
return; return;
} }

View file

@ -5,7 +5,7 @@ use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, meets_msrv, msr
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::intravisit::FnKind; use rustc_hir::intravisit::FnKind;
use rustc_hir::{Body, Constness, FnDecl, GenericParamKind, HirId}; use rustc_hir::{Body, Constness, FnDecl, GenericParamKind, HirId};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_semver::RustcVersion; use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};

View file

@ -80,9 +80,9 @@ impl EarlyLintPass for ModStyle {
return; return;
} }
let files = cx.sess.source_map().files(); let files = cx.sess().source_map().files();
let trim_to_src = if let RealFileName::LocalPath(p) = &cx.sess.opts.working_dir { let trim_to_src = if let RealFileName::LocalPath(p) = &cx.sess().opts.working_dir {
p.to_string_lossy() p.to_string_lossy()
} else { } else {
return; return;

View file

@ -3,7 +3,7 @@ use rustc_ast::ast::{
self, Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, Item, ItemKind, Local, Pat, PatKind, self, Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, Item, ItemKind, Local, Pat, PatKind,
}; };
use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor}; use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor};
use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span; use rustc_span::source_map::Span;
@ -356,7 +356,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'a, 'tcx> {
impl EarlyLintPass for NonExpressiveNames { impl EarlyLintPass for NonExpressiveNames {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
if in_external_macro(cx.sess, item.span) { if in_external_macro(cx.sess(), item.span) {
return; return;
} }
@ -371,7 +371,7 @@ impl EarlyLintPass for NonExpressiveNames {
} }
fn check_impl_item(&mut self, cx: &EarlyContext<'_>, item: &AssocItem) { fn check_impl_item(&mut self, cx: &EarlyContext<'_>, item: &AssocItem) {
if in_external_macro(cx.sess, item.span) { if in_external_macro(cx.sess(), item.span) {
return; return;
} }

View file

@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
use rustc_ast::ast::{Expr, ExprKind}; use rustc_ast::ast::{Expr, ExprKind};
use rustc_ast::token::{Lit, LitKind}; use rustc_ast::token::{Lit, LitKind};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span; use rustc_span::Span;
@ -51,7 +51,7 @@ declare_lint_pass!(OctalEscapes => [OCTAL_ESCAPES]);
impl EarlyLintPass for OctalEscapes { impl EarlyLintPass for OctalEscapes {
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
if in_external_macro(cx.sess, expr.span) { if in_external_macro(cx.sess(), expr.span) {
return; return;
} }

View file

@ -8,7 +8,7 @@ use if_chain::if_chain;
use rustc_ast::ast::RangeLimits; use rustc_ast::ast::RangeLimits;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, QPath}; use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, QPath};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty; use rustc_middle::ty;
use rustc_semver::RustcVersion; use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};

View file

@ -8,7 +8,7 @@ use rustc_errors::Applicability;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::intravisit as hir_visit; use rustc_hir::intravisit as hir_visit;
use rustc_hir::intravisit::Visitor as HirVisitor; use rustc_hir::intravisit::Visitor as HirVisitor;
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
use rustc_middle::hir::nested_filter; use rustc_middle::hir::nested_filter;
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_session::{declare_lint_pass, declare_tool_lint};
@ -62,7 +62,7 @@ impl<'ast> ast_visit::Visitor<'ast> for ReturnVisitor {
impl EarlyLintPass for RedundantClosureCall { impl EarlyLintPass for RedundantClosureCall {
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
if in_external_macro(cx.sess, expr.span) { if in_external_macro(cx.sess(), expr.span) {
return; return;
} }
if_chain! { if_chain! {

View file

@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::diagnostics::span_lint_and_help;
use rustc_ast::ast::{Block, Expr, ExprKind, Stmt, StmtKind}; use rustc_ast::ast::{Block, Expr, ExprKind, Stmt, StmtKind};
use rustc_ast::visit::{walk_expr, Visitor}; use rustc_ast::visit::{walk_expr, Visitor};
use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_session::{declare_lint_pass, declare_tool_lint};
@ -46,7 +46,7 @@ declare_lint_pass!(RedundantElse => [REDUNDANT_ELSE]);
impl EarlyLintPass for RedundantElse { impl EarlyLintPass for RedundantElse {
fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &Stmt) { fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &Stmt) {
if in_external_macro(cx.sess, stmt.span) { if in_external_macro(cx.sess(), stmt.span) {
return; return;
} }
// Only look at expressions that are a whole statement // Only look at expressions that are a whole statement

View file

@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::{meets_msrv, msrvs}; use clippy_utils::{meets_msrv, msrvs};
use rustc_ast::ast::{Expr, ExprKind}; use rustc_ast::ast::{Expr, ExprKind};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_semver::RustcVersion; use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
@ -55,7 +55,7 @@ impl EarlyLintPass for RedundantFieldNames {
return; return;
} }
if in_external_macro(cx.sess, expr.span) { if in_external_macro(cx.sess(), expr.span) {
return; return;
} }
if let ExprKind::Struct(ref se) = expr.kind { if let ExprKind::Struct(ref se) = expr.kind {

View file

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::diagnostics::span_lint_and_help;
use rustc_ast::ast::{GenericParam, GenericParamKind}; use rustc_ast::ast::{GenericParam, GenericParamKind};
use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_session::{declare_lint_pass, declare_tool_lint};
@ -43,7 +43,7 @@ declare_lint_pass!(SingleCharLifetimeNames => [SINGLE_CHAR_LIFETIME_NAMES]);
impl EarlyLintPass for SingleCharLifetimeNames { impl EarlyLintPass for SingleCharLifetimeNames {
fn check_generic_param(&mut self, ctx: &EarlyContext<'_>, param: &GenericParam) { fn check_generic_param(&mut self, ctx: &EarlyContext<'_>, param: &GenericParam) {
if in_external_macro(ctx.sess, param.ident.span) { if in_external_macro(ctx.sess(), param.ident.span) {
return; return;
} }

View file

@ -1,7 +1,7 @@
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
use rustc_ast::{ptr::P, Crate, Item, ItemKind, MacroDef, ModKind, UseTreeKind, VisibilityKind}; use rustc_ast::{ptr::P, Crate, Item, ItemKind, MacroDef, ModKind, UseTreeKind, VisibilityKind};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{edition::Edition, symbol::kw, Span, Symbol}; use rustc_span::{edition::Edition, symbol::kw, Span, Symbol};
@ -37,7 +37,7 @@ declare_lint_pass!(SingleComponentPathImports => [SINGLE_COMPONENT_PATH_IMPORTS]
impl EarlyLintPass for SingleComponentPathImports { impl EarlyLintPass for SingleComponentPathImports {
fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) { fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) {
if cx.sess.opts.edition < Edition::Edition2018 { if cx.sess().opts.edition < Edition::Edition2018 {
return; return;
} }
check_mod(cx, &krate.items); check_mod(cx, &krate.items);

View file

@ -11,7 +11,7 @@ use rustc_hir::{
intravisit::{walk_inf, walk_ty, Visitor}, intravisit::{walk_inf, walk_ty, Visitor},
Expr, ExprKind, FnRetTy, FnSig, GenericArg, HirId, Impl, ImplItemKind, Item, ItemKind, Path, QPath, TyKind, Expr, ExprKind, FnRetTy, FnSig, GenericArg, HirId, Impl, ImplItemKind, Item, ItemKind, Path, QPath, TyKind,
}; };
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass};
use rustc_semver::RustcVersion; use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::Span; use rustc_span::Span;

View file

@ -580,7 +580,7 @@ fn get_lint_group_and_level_or_lint(
) -> Option<(String, &'static str)> { ) -> Option<(String, &'static str)> {
let result = cx let result = cx
.lint_store .lint_store
.check_lint_name(cx.sess(), lint_name, Some(sym::clippy), &[]); .check_lint_name(lint_name, Some(sym::clippy), &[]);
if let CheckLintNameResult::Tool(Ok(lint_lst)) = result { if let CheckLintNameResult::Tool(Ok(lint_lst)) = result {
if let Some(group) = get_lint_group(cx, lint_lst[0]) { if let Some(group) = get_lint_group(cx, lint_lst[0]) {
if EXCLUDED_LINT_GROUPS.contains(&group.as_str()) { if EXCLUDED_LINT_GROUPS.contains(&group.as_str()) {

View file

@ -9,7 +9,7 @@ use rustc_ast::token::{self, LitKind};
use rustc_ast::tokenstream::TokenStream; use rustc_ast::tokenstream::TokenStream;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_lexer::unescape::{self, EscapeError}; use rustc_lexer::unescape::{self, EscapeError};
use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_parse::parser; use rustc_parse::parser;
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::symbol::{kw, Symbol}; use rustc_span::symbol::{kw, Symbol};
@ -290,7 +290,7 @@ impl EarlyLintPass for Write {
fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &MacCall) { fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &MacCall) {
fn is_build_script(cx: &EarlyContext<'_>) -> bool { fn is_build_script(cx: &EarlyContext<'_>) -> bool {
// Cargo sets the crate name for build scripts to `build_script_build` // Cargo sets the crate name for build scripts to `build_script_build`
cx.sess cx.sess()
.opts .opts
.crate_name .crate_name
.as_ref() .as_ref()
@ -529,7 +529,7 @@ impl Write {
/// ``` /// ```
#[allow(clippy::too_many_lines)] #[allow(clippy::too_many_lines)]
fn check_tts<'a>(&self, cx: &EarlyContext<'a>, tts: TokenStream, is_write: bool) -> (Option<StrLit>, Option<Expr>) { fn check_tts<'a>(&self, cx: &EarlyContext<'a>, tts: TokenStream, is_write: bool) -> (Option<StrLit>, Option<Expr>) {
let mut parser = parser::Parser::new(&cx.sess.parse_sess, tts, false, None); let mut parser = parser::Parser::new(&cx.sess().parse_sess, tts, false, None);
let expr = if is_write { let expr = if is_write {
match parser match parser
.parse_expr() .parse_expr()

View file

@ -117,25 +117,15 @@ pub fn meets_msrv(msrv: Option<&RustcVersion>, lint_msrv: &RustcVersion) -> bool
#[macro_export] #[macro_export]
macro_rules! extract_msrv_attr { macro_rules! extract_msrv_attr {
(LateContext) => { ($context:ident) => {
extract_msrv_attr!(@LateContext, ());
};
(EarlyContext) => {
extract_msrv_attr!(@EarlyContext);
};
(@$context:ident$(, $call:tt)?) => {
fn enter_lint_attrs(&mut self, cx: &rustc_lint::$context<'_>, attrs: &[rustc_ast::ast::Attribute]) { fn enter_lint_attrs(&mut self, cx: &rustc_lint::$context<'_>, attrs: &[rustc_ast::ast::Attribute]) {
use $crate::get_unique_inner_attr; let sess = rustc_lint::LintContext::sess(cx);
match get_unique_inner_attr(cx.sess$($call)?, attrs, "msrv") { match $crate::get_unique_inner_attr(sess, attrs, "msrv") {
Some(msrv_attr) => { Some(msrv_attr) => {
if let Some(msrv) = msrv_attr.value_str() { if let Some(msrv) = msrv_attr.value_str() {
self.msrv = $crate::parse_msrv( self.msrv = $crate::parse_msrv(&msrv.to_string(), Some(sess), Some(msrv_attr.span));
&msrv.to_string(),
Some(cx.sess$($call)?),
Some(msrv_attr.span),
);
} else { } else {
cx.sess$($call)?.span_err(msrv_attr.span, "bad clippy attribute"); sess.span_err(msrv_attr.span, "bad clippy attribute");
} }
}, },
_ => (), _ => (),