diff options
Diffstat (limited to 'compiler')
21 files changed, 302 insertions, 105 deletions
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 40b0cefd83a..2c5e180f80d 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -33,10 +33,6 @@ impl MarkedAttrs { } } -pub fn is_known_lint_tool(m_item: Ident) -> bool { - [sym::clippy, sym::rustc, sym::rustdoc].contains(&m_item.name) -} - impl NestedMetaItem { /// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem`. pub fn meta_item(&self) -> Option<&MetaItem> { diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 093f7f2668c..7e58426d27d 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -784,33 +784,6 @@ impl Nonterminal { NtTT(tt) => tt.span(), } } - - /// This nonterminal looks like some specific enums from - /// `proc-macro-hack` and `procedural-masquerade` crates. - /// We need to maintain some special pretty-printing behavior for them due to incorrect - /// asserts in old versions of those crates and their wide use in the ecosystem. - /// See issue #73345 for more details. - /// FIXME(#73933): Remove this eventually. - pub fn pretty_printing_compatibility_hack(&self) -> bool { - let item = match self { - NtItem(item) => item, - NtStmt(stmt) => match &stmt.kind { - ast::StmtKind::Item(item) => item, - _ => return false, - }, - _ => return false, - }; - - let name = item.ident.name; - if name == sym::ProceduralMasqueradeDummyType || name == sym::ProcMacroHack { - if let ast::ItemKind::Enum(enum_def, _) = &item.kind { - if let [variant] = &*enum_def.variants { - return variant.ident.name == sym::Input; - } - } - } - false - } } impl PartialEq for Nonterminal { diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 36cd6c281b4..8d8b3f4f6aa 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -7,7 +7,10 @@ use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_expand::base::{self, *}; use rustc_parse::parser::Parser; use rustc_parse_format as parse; -use rustc_span::symbol::{kw, sym, Symbol}; +use rustc_span::{ + symbol::{kw, sym, Symbol}, + BytePos, +}; use rustc_span::{InnerSpan, Span}; struct AsmArgs { @@ -399,6 +402,8 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, sp: Span, args: AsmArgs) -> P<ast let mut line_spans = Vec::with_capacity(args.templates.len()); let mut curarg = 0; + let default_dialect = ecx.sess.inline_asm_dialect(); + for template_expr in args.templates.into_iter() { if !template.is_empty() { template.push(ast::InlineAsmTemplatePiece::String("\n".to_string())); @@ -424,6 +429,60 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, sp: Span, args: AsmArgs) -> P<ast let template_str = &template_str.as_str(); let template_snippet = ecx.source_map().span_to_snippet(template_sp).ok(); + + if let Some(snippet) = &template_snippet { + let snippet = snippet.trim_matches('"'); + match default_dialect { + ast::LlvmAsmDialect::Intel => { + if let Some(span) = check_syntax_directive(snippet, ".intel_syntax") { + let span = template_span.from_inner(span); + let mut err = ecx.struct_span_err(span, "intel syntax is the default syntax on this target, and trying to use this directive may cause issues"); + err.span_suggestion( + span, + "remove this assembler directive", + "".to_string(), + Applicability::MachineApplicable, + ); + err.emit(); + } + + if let Some(span) = check_syntax_directive(snippet, ".att_syntax") { + let span = template_span.from_inner(span); + let mut err = ecx.struct_span_err(span, "using the .att_syntax directive may cause issues, use the att_syntax option instead"); + let asm_end = sp.hi() - BytePos(2); + let suggestions = vec![ + (span, "".to_string()), + ( + Span::new(asm_end, asm_end, sp.ctxt()), + ", options(att_syntax)".to_string(), + ), + ]; + err.multipart_suggestion( + "remove the assembler directive and replace it with options(att_syntax)", + suggestions, + Applicability::MachineApplicable, + ); + err.emit(); + } + } + ast::LlvmAsmDialect::Att => { + if let Some(span) = check_syntax_directive(snippet, ".att_syntax") { + let span = template_span.from_inner(span); + let mut err = ecx.struct_span_err(span, "att syntax is the default syntax on this target, and trying to use this directive may cause issues"); + err.span_suggestion( + span, + "remove this assembler directive", + "".to_string(), + Applicability::MachineApplicable, + ); + err.emit(); + } + + // Use of .intel_syntax is ignored + } + } + } + let mut parser = parse::Parser::new( template_str, str_style, @@ -631,3 +690,15 @@ pub fn expand_asm<'cx>( } } } + +fn check_syntax_directive<S: AsRef<str>>(piece: S, syntax: &str) -> Option<InnerSpan> { + let piece = piece.as_ref(); + if let Some(idx) = piece.find(syntax) { + let end = + idx + &piece[idx..].find(|c| matches!(c, '\n' | ';')).unwrap_or(piece[idx..].len()); + // Offset by one because these represent the span with the " removed + Some(InnerSpan::new(idx + 1, end + 1)) + } else { + None + } +} diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 444a9d4ba04..352638aa88e 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -254,7 +254,7 @@ fn save_function_record( /// /// 1. The file name of an "Unreachable" function must match the file name of the existing /// codegenned (covered) function to which the unreachable code regions will be added. -/// 2. The function to which the unreachable code regions will be added must not be a genaric +/// 2. The function to which the unreachable code regions will be added must not be a generic /// function (must not have type parameters) because the coverage tools will get confused /// if the codegenned function has more than one instantiation and additional `CodeRegion`s /// attached to only one of those instantiations. @@ -284,7 +284,7 @@ fn add_unreachable_coverage<'tcx>( let all_def_ids: DefIdSet = tcx.mir_keys(LOCAL_CRATE).iter().map(|local_def_id| local_def_id.to_def_id()).collect(); - let (codegenned_def_ids, _) = tcx.collect_and_partition_mono_items(LOCAL_CRATE); + let codegenned_def_ids = tcx.codegened_and_inlined_items(LOCAL_CRATE); let mut unreachable_def_ids_by_file: FxHashMap<Symbol, Vec<DefId>> = FxHashMap::default(); for &non_codegenned_def_id in all_def_ids.difference(codegenned_def_ids) { diff --git a/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs b/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs index 549b8d41f51..af6482fdbc2 100644 --- a/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs +++ b/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs @@ -8,7 +8,7 @@ use rustc_middle::mir::coverage::{ use rustc_middle::ty::Instance; use rustc_middle::ty::TyCtxt; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub struct Expression { lhs: ExpressionOperandId, op: Op, @@ -64,7 +64,9 @@ impl<'tcx> FunctionCoverage<'tcx> { /// Adds a code region to be counted by an injected counter intrinsic. pub fn add_counter(&mut self, id: CounterValueReference, region: CodeRegion) { - self.counters[id].replace(region).expect_none("add_counter called with duplicate `id`"); + if let Some(previous_region) = self.counters[id].replace(region.clone()) { + assert_eq!(previous_region, region, "add_counter: code region for id changed"); + } } /// Both counters and "counter expressions" (or simply, "expressions") can be operands in other @@ -94,9 +96,18 @@ impl<'tcx> FunctionCoverage<'tcx> { expression_id, lhs, op, rhs, region ); let expression_index = self.expression_index(u32::from(expression_id)); - self.expressions[expression_index] - .replace(Expression { lhs, op, rhs, region }) - .expect_none("add_counter_expression called with duplicate `id_descending_from_max`"); + if let Some(previous_expression) = self.expressions[expression_index].replace(Expression { + lhs, + op, + rhs, + region: region.clone(), + }) { + assert_eq!( + previous_expression, + Expression { lhs, op, rhs, region }, + "add_counter_expression: expression for id changed" + ); + } } /// Add a region that will be marked as "unreachable", with a constant "zero counter". diff --git a/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs b/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs index a115d358666..5ab1baafb57 100644 --- a/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs @@ -2,27 +2,38 @@ use crate::traits::*; use rustc_middle::mir::coverage::*; use rustc_middle::mir::Coverage; +use rustc_middle::mir::SourceScope; use super::FunctionCx; impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { - pub fn codegen_coverage(&self, bx: &mut Bx, coverage: Coverage) { + pub fn codegen_coverage(&self, bx: &mut Bx, coverage: Coverage, scope: SourceScope) { + // Determine the instance that coverage data was originally generated for. + let scope_data = &self.mir.source_scopes[scope]; + let instance = if let Some((inlined_instance, _)) = scope_data.inlined { + self.monomorphize(inlined_instance) + } else if let Some(inlined_scope) = scope_data.inlined_parent_scope { + self.monomorphize(self.mir.source_scopes[inlined_scope].inlined.unwrap().0) + } else { + self.instance + }; + let Coverage { kind, code_region } = coverage; match kind { CoverageKind::Counter { function_source_hash, id } => { - if bx.set_function_source_hash(self.instance, function_source_hash) { + if bx.set_function_source_hash(instance, function_source_hash) { // If `set_function_source_hash()` returned true, the coverage map is enabled, // so continue adding the counter. if let Some(code_region) = code_region { // Note: Some counters do not have code regions, but may still be referenced // from expressions. In that case, don't add the counter to the coverage map, // but do inject the counter intrinsic. - bx.add_coverage_counter(self.instance, id, code_region); + bx.add_coverage_counter(instance, id, code_region); } - let coverageinfo = bx.tcx().coverageinfo(self.instance.def_id()); + let coverageinfo = bx.tcx().coverageinfo(instance.def_id()); - let fn_name = bx.create_pgo_func_name_var(self.instance); + let fn_name = bx.create_pgo_func_name_var(instance); let hash = bx.const_u64(function_source_hash); let num_counters = bx.const_u32(coverageinfo.num_counters); let index = bx.const_u32(u32::from(id)); @@ -34,11 +45,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } CoverageKind::Expression { id, lhs, op, rhs } => { - bx.add_coverage_counter_expression(self.instance, id, lhs, op, rhs, code_region); + bx.add_coverage_counter_expression(instance, id, lhs, op, rhs, code_region); } CoverageKind::Unreachable => { bx.add_coverage_unreachable( - self.instance, + instance, code_region.expect("unreachable regions always have code regions"), ); } diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs index 5523e5f2e86..fe7f6288adb 100644 --- a/compiler/rustc_codegen_ssa/src/mir/statement.rs +++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs @@ -112,7 +112,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx } mir::StatementKind::Coverage(box ref coverage) => { - self.codegen_coverage(&mut bx, coverage.clone()); + self.codegen_coverage(&mut bx, coverage.clone(), statement.source_info.scope); bx } mir::StatementKind::CopyNonOverlapping(box mir::CopyNonOverlapping { diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 05e5c13dab7..594b9a82ad0 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -10,6 +10,8 @@ use rustc_attr::{self as attr, Deprecation, Stability}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::{self, Lrc}; use rustc_errors::{DiagnosticBuilder, ErrorReported}; +use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT; +use rustc_lint_defs::BuiltinLintDiagnostics; use rustc_parse::{self, nt_to_tokenstream, parser, MACRO_ARGUMENTS}; use rustc_session::{parse::ParseSess, Limit, Session}; use rustc_span::def_id::DefId; @@ -1241,3 +1243,41 @@ pub fn get_exprs_from_tts( } Some(es) } + +/// This nonterminal looks like some specific enums from +/// `proc-macro-hack` and `procedural-masquerade` crates. +/// We need to maintain some special pretty-printing behavior for them due to incorrect +/// asserts in old versions of those crates and their wide use in the ecosystem. +/// See issue #73345 for more details. +/// FIXME(#73933): Remove this eventually. +pub(crate) fn pretty_printing_compatibility_hack(nt: &Nonterminal, sess: &ParseSess) -> bool { + let item = match nt { + Nonterminal::NtItem(item) => item, + Nonterminal::NtStmt(stmt) => match &stmt.kind { + ast::StmtKind::Item(item) => item, + _ => return false, + }, + _ => return false, + }; + + let name = item.ident.name; + if name == sym::ProceduralMasqueradeDummyType { + if let ast::ItemKind::Enum(enum_def, _) = &item.kind { + if let [variant] = &*enum_def.variants { + if variant.ident.name == sym::Input { + sess.buffer_lint_with_diagnostic( + &PROC_MACRO_BACK_COMPAT, + item.ident.span, + ast::CRATE_NODE_ID, + "using `procedural-masquerade` crate", + BuiltinLintDiagnostics::ProcMacroBackCompat( + "The `procedural-masquerade` crate has been unnecessary since Rust 1.30.0. \ + Versions of this crate below 0.1.7 will eventually stop compiling.".to_string()) + ); + return true; + } + } + } + } + false +} diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index 8cbaa7c945a..61b776ff2d2 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -90,7 +90,8 @@ impl MultiItemModifier for ProcMacroDerive { } _ => unreachable!(), }; - let input = if item.pretty_printing_compatibility_hack() { + let input = if crate::base::pretty_printing_compatibility_hack(&item, &ecx.sess.parse_sess) + { TokenTree::token(token::Interpolated(Lrc::new(item)), DUMMY_SP).into() } else { nt_to_tokenstream(&item, &ecx.sess.parse_sess, CanSynthesizeMissingTokens::Yes) diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 837fad90580..67edfe19da3 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -187,7 +187,7 @@ impl FromInternal<(TreeAndSpacing, &'_ ParseSess, &'_ mut Vec<Self>)> delimiter: Delimiter::None, stream, span: DelimSpan::from_single(span), - flatten: nt.pretty_printing_compatibility_hack(), + flatten: crate::base::pretty_printing_compatibility_hack(&nt, sess), }) } } diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 3ba687124ae..c9de85a2f18 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -748,7 +748,7 @@ impl<'a> EarlyContext<'a> { sess, krate, lint_store, - builder: LintLevelsBuilder::new(sess, warn_about_weird_lints, lint_store), + builder: LintLevelsBuilder::new(sess, warn_about_weird_lints, lint_store, &krate.attrs), buffered, } } diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 5e6b090027c..a332c300787 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -1,13 +1,12 @@ use crate::context::{CheckLintNameResult, LintStore}; use crate::late::unerased_lint_store; use rustc_ast as ast; -use rustc_ast::attr; use rustc_ast::unwrap_or; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; -use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::{intravisit, HirId}; use rustc_middle::hir::map::Map; use rustc_middle::lint::LevelAndSource; @@ -32,7 +31,8 @@ use std::cmp; fn lint_levels(tcx: TyCtxt<'_>, cnum: CrateNum) -> LintLevelMap { assert_eq!(cnum, LOCAL_CRATE); let store = unerased_lint_store(tcx); - let levels = LintLevelsBuilder::new(tcx.sess, false, &store); + let crate_attrs = tcx.get_attrs(DefId { krate: cnum, index: CRATE_DEF_INDEX }); + let levels = LintLevelsBuilder::new(tcx.sess, false, &store, crate_attrs); let mut builder = LintLevelMapBuilder { levels, tcx, store }; let krate = tcx.hir().krate(); @@ -56,6 +56,7 @@ pub struct LintLevelsBuilder<'s> { cur: u32, warn_about_weird_lints: bool, store: &'s LintStore, + crate_attrs: &'s [ast::Attribute], } pub struct BuilderPush { @@ -64,7 +65,12 @@ pub struct BuilderPush { } impl<'s> LintLevelsBuilder<'s> { - pub fn new(sess: &'s Session, warn_about_weird_lints: bool, store: &'s LintStore) -> Self { + pub fn new( + sess: &'s Session, + warn_about_weird_lints: bool, + store: &'s LintStore, + crate_attrs: &'s [ast::Attribute], + ) -> Self { let mut builder = LintLevelsBuilder { sess, sets: LintLevelSets::new(), @@ -72,6 +78,7 @@ impl<'s> LintLevelsBuilder<'s> { id_to_set: Default::default(), warn_about_weird_lints, store, + crate_attrs, }; builder.process_command_line(sess, store); assert_eq!(builder.sets.list.len(), 1); @@ -304,15 +311,22 @@ impl<'s> LintLevelsBuilder<'s> { }; let tool_name = if meta_item.path.segments.len() > 1 { let tool_ident = meta_item.path.segments[0].ident; - if !attr::is_known_lint_tool(tool_ident) { - struct_span_err!( + if !is_known_lint_tool(tool_ident.name, sess, &self.crate_attrs) { + let mut err = struct_span_err!( sess, tool_ident.span, E0710, - "an unknown tool name found in scoped lint: `{}`", + "unknown tool name `{}` found in scoped lint: `{}`", + tool_ident.name, pprust::path_to_string(&meta_item.path), - ) - .emit(); + ); + if sess.is_nightly_build() { + err.help(&format!( + "add `#![register_tool({})]` to the crate root", + tool_ident.name + )); + } + err.emit(); continue; } @@ -559,6 +573,20 @@ impl<'s> LintLevelsBuilder<'s> { } } +fn is_known_lint_tool(m_item: Symbol, sess: &Session, attrs: &[ast::Attribute]) -> bool { + 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()) + .flat_map(std::convert::identity) + .filter_map(|nested_meta| nested_meta.ident()) + .map(|ident| ident.name) + .any(|name| name == m_item) +} + struct LintLevelMapBuilder<'a, 'tcx> { levels: LintLevelsBuilder<'tcx>, tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 872cf1ed194..ae367db019b 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1407,6 +1407,14 @@ rustc_queries! { query is_codegened_item(def_id: DefId) -> bool { desc { |tcx| "determining whether `{}` needs codegen", tcx.def_path_str(def_id) } } + + /// All items participating in code generation together with items inlined into them. + query codegened_and_inlined_items(_: CrateNum) + -> &'tcx DefIdSet { + eval_always + desc { "codegened_and_inlined_items" } + } + query codegen_unit(_: Symbol) -> &'tcx CodegenUnit<'tcx> { desc { "codegen_unit" } } diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs b/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs index b68a8104fba..dc2379fd92b 100644 --- a/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs +++ b/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs @@ -424,8 +424,33 @@ fn collect_and_partition_mono_items<'tcx>( (tcx.arena.alloc(mono_items), codegen_units) } +fn codegened_and_inlined_items<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> &'tcx DefIdSet { + let (items, cgus) = tcx.collect_and_partition_mono_items(cnum); + let mut visited = DefIdSet::default(); + let mut result = items.clone(); + + for cgu in cgus { + for (item, _) in cgu.items() { + if let MonoItem::Fn(ref instance) = item { + let did = instance.def_id(); + if !visited.insert(did) { + continue; + } + for scope in &tcx.instance_mir(instance.def).source_scopes { + if let Some((ref inlined, _)) = scope.inlined { + result.insert(inlined.def_id()); + } + } + } + } + } + + tcx.arena.alloc(result) +} + pub fn provide(providers: &mut Providers) { providers.collect_and_partition_mono_items = collect_and_partition_mono_items; + providers.codegened_and_inlined_items = codegened_and_inlined_items; providers.is_codegened_item = |tcx, def_id| { let (all_mono_items, _) = tcx.collect_and_partition_mono_items(LOCAL_CRATE); diff --git a/compiler/rustc_mir/src/transform/coverage/query.rs b/compiler/rustc_mir/src/transform/coverage/query.rs index 4b455a6a1ba..de8447f1974 100644 --- a/compiler/rustc_mir/src/transform/coverage/query.rs +++ b/compiler/rustc_mir/src/transform/coverage/query.rs @@ -1,8 +1,7 @@ use super::*; use rustc_middle::mir::coverage::*; -use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{self, Coverage, CoverageInfo, Location}; +use rustc_middle::mir::{self, Body, Coverage, CoverageInfo}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::def_id::DefId; @@ -85,10 +84,21 @@ impl CoverageVisitor { } } } -} -impl Visitor<'_> for CoverageVisitor { - fn visit_coverage(&mut self, coverage: &Coverage, _location: Location) { + fn visit_body(&mut self, body: &Body<'_>) { + for bb_data in body.basic_blocks().iter() { + for statement in bb_data.statements.iter() { + if let StatementKind::Coverage(box ref coverage) = statement.kind { + if is_inlined(body, statement) { + continue; + } + self.visit_coverage(coverage); + } + } + } + } + + fn visit_coverage(&mut self, coverage: &Coverage) { if self.add_missing_operands { match coverage.kind { CoverageKind::Expression { lhs, rhs, .. } => { @@ -129,10 +139,14 @@ fn coverageinfo_from_mir<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> CoverageInfo } fn covered_file_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<Symbol> { - for bb_data in mir_body(tcx, def_id).basic_blocks().iter() { + let body = mir_body(tcx, def_id); + for bb_data in body.basic_blocks().iter() { for statement in bb_data.statements.iter() { if let StatementKind::Coverage(box ref coverage) = statement.kind { if let Some(code_region) = coverage.code_region.as_ref() { + if is_inlined(body, statement) { + continue; + } return Some(code_region.file_name); } } @@ -151,13 +165,17 @@ fn mir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx mir::Body<'tcx> { } fn covered_code_regions<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Vec<&'tcx CodeRegion> { - mir_body(tcx, def_id) - .basic_blocks() + let body = mir_body(tcx, def_id); + body.basic_blocks() .iter() .map(|data| { data.statements.iter().filter_map(|statement| match statement.kind { StatementKind::Coverage(box ref coverage) => { - coverage.code_region.as_ref() // may be None + if is_inlined(body, statement) { + None + } else { + coverage.code_region.as_ref() // may be None + } } _ => None, }) @@ -165,3 +183,8 @@ fn covered_code_regions<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Vec<&'tcx Cod .flatten() .collect() } + +fn is_inlined(body: &Body<'_>, statement: &Statement<'_>) -> bool { + let scope_data = &body.source_scopes[statement.source_info.scope]; + scope_data.inlined.is_some() || scope_data.inlined_parent_scope.is_some() +} diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs index dd06daecd5d..12fdbd6582e 100644 --- a/compiler/rustc_mir/src/transform/inline.rs +++ b/compiler/rustc_mir/src/transform/inline.rs @@ -39,15 +39,6 @@ struct CallSite<'tcx> { /// Returns true if MIR inlining is enabled in the current compilation session. crate fn is_enabled(tcx: TyCtxt<'_>) -> bool { - if tcx.sess.opts.debugging_opts.instrument_coverage { - // Since `Inline` happens after `InstrumentCoverage`, the function-specific coverage - // counters can be invalidated, such as by merging coverage counter statements from - // a pre-inlined function into a different function. This kind of change is invalid, - // so inlining must be skipped. Note: This check is performed here so inlining can - // be disabled without preventing other optimizations (regardless of `mir_opt_level`). - return false; - } - if let Some(enabled) = tcx.sess.opts.debugging_opts.inline_mir { return enabled; } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 025415036b6..70dbaa53d38 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -204,6 +204,7 @@ impl<'a> Parser<'a> { def: &mut Defaultness, req_name: ReqName, ) -> PResult<'a, Option<ItemInfo>> { + let def_final = def == &Defaultness::Final; let mut def = || mem::replace(def, Defaultness::Final); let info = if self.eat_keyword(kw::Use) { @@ -226,7 +227,7 @@ impl<'a> Parser<'a> { } (Ident::invalid(), ItemKind::Use(tree)) - } else if self.check_fn_front_matter() { + } else if self.check_fn_front_matter(def_final) { // FUNCTION ITEM let (ident, sig, generics, body) = self.parse_fn(attrs, req_name, lo)?; (ident, ItemKind::Fn(box FnKind(def(), sig, generics, body))) @@ -1634,18 +1635,27 @@ impl<'a> Parser<'a> { } /// Is the current token the start of an `FnHeader` / not a valid parse? - pub(super) fn check_fn_front_matter(&mut self) -> bool { + /// + /// `check_pub` adds additional `pub` to the checks in case users place it + /// wrongly, can be used to ensure `pub` never comes after `default`. + pub(super) fn check_fn_front_matter(&mut self, check_pub: bool) -> bool { // We use an over-approximation here. // `const const`, `fn const` won't parse, but we're not stepping over other syntax either. - const QUALS: [Symbol; 4] = [kw::Const, kw::Async, kw::Unsafe, kw::Extern]; + // `pub` is added in case users got confused with the ordering like `async pub fn`, + // only if it wasn't preceeded by `default` as `default pub` is invalid. + let quals: &[Symbol] = if check_pub { + &[kw::Pub, kw::Const, kw::Async, kw::Unsafe, kw::Extern] + } else { + &[kw::Const, kw::Async, kw::Unsafe, kw::Extern] + }; self.check_keyword(kw::Fn) // Definitely an `fn`. // `$qual fn` or `$qual $qual`: - || QUALS.iter().any(|&kw| self.check_keyword(kw)) + || quals.iter().any(|&kw| self.check_keyword(kw)) && self.look_ahead(1, |t| { // `$qual fn`, e.g. `const fn` or `async fn`. t.is_keyword(kw::Fn) // Two qualifiers `$qual $qual` is enough, e.g. `async unsafe`. - || t.is_non_raw_ident_where(|i| QUALS.contains(&i.name) + || t.is_non_raw_ident_where(|i| quals.contains(&i.name) // Rule out 2015 `const async: T = val`. && i.is_reserved() // Rule out unsafe extern block. @@ -1666,6 +1676,7 @@ impl<'a> Parser<'a> { /// FnFrontMatter = FnQual "fn" ; /// ``` pub(super) fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> { + let sp_start = self.token.span; let constness = self.parse_constness(); let asyncness = self.parse_asyncness(); let unsafety = self.parse_unsafety(); @@ -1679,8 +1690,27 @@ impl<'a> Parser<'a> { // It is possible for `expect_one_of` to recover given the contents of // `self.expected_tokens`, therefore, do not use `self.unexpected()` which doesn't // account for this. - if !self.expect_one_of(&[], &[])? { - unreachable!() + match self.expect_one_of(&[], &[]) { + Ok(true) => {} + Ok(false) => unreachable!(), + Err(mut err) => { + // Recover incorrect visibility order such as `async pub`. + if self.check_keyword(kw::Pub) { + let sp = sp_start.to(self.prev_token.span); + if let Ok(snippet) = self.span_to_snippet(sp) { + let vis = self.parse_visibility(FollowedByType::No)?; + let vs = pprust::vis_to_string(&vis); + let vs = vs.trim_end(); + err.span_suggestion( + sp_start.to(self.prev_token.span), + &format!("visibility `{}` must come before `{}`", vs, snippet), + format!("{} {}", vs, snippet), + Applicability::MachineApplicable, + ); + } + } + return Err(err); + } } } diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 8f03bfd4c3a..0f7b8ebd376 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -209,7 +209,7 @@ impl<'a> Parser<'a> { } else if self.eat_keyword(kw::Underscore) { // A type to be inferred `_` TyKind::Infer - } else if self.check_fn_front_matter() { + } else if self.check_fn_front_matter(false) { // Function pointer type self.parse_ty_bare_fn(lo, Vec::new(), recover_return_sign)? } else if self.check_keyword(kw::For) { @@ -217,7 +217,7 @@ impl<'a> Parser<'a> { // `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T` // `for<'lt> Trait1<'lt> + Trait2 + 'a` let lifetime_defs = self.parse_late_bound_lifetime_defs()?; - if self.check_fn_front_matter() { + if self.check_fn_front_matter(false) { self.parse_ty_bare_fn(lo, lifetime_defs, recover_return_sign)? } else { let path = self.parse_path(PathStyle::Type)?; diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index c1be90efc72..75078a12311 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1937,25 +1937,6 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { } Some(SymbolManglingVersion::V0) => {} } - - if let Some(mir_opt_level) = debugging_opts.mir_opt_level { - if mir_opt_level > 1 { - // Functions inlined during MIR transform can, at best, make it impossible to - // effectively cover inlined functions, and, at worst, break coverage map generation - // during LLVM codegen. For example, function counter IDs are only unique within a - // function. Inlining after these counters are injected can produce duplicate counters, - // resulting in an invalid coverage map (and ICE); so this option combination is not - // allowed. - early_warn( - error_format, - &format!( - "`-Z mir-opt-level={}` (or any level > 1) enables function inlining, which \ - is incompatible with `-Z instrument-coverage`. Inlining will be disabled.", - mir_opt_level, - ), - ); - } - } } if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") { diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 4f611118360..fc57b6b8ace 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -793,6 +793,13 @@ impl Session { } } + pub fn inline_asm_dialect(&self) -> rustc_ast::LlvmAsmDialect { + match self.asm_arch { + Some(InlineAsmArch::X86 | InlineAsmArch::X86_64) => rustc_ast::LlvmAsmDialect::Intel, + _ => rustc_ast::LlvmAsmDialect::Att, + } + } + pub fn relocation_model(&self) -> RelocModel { self.opts.cg.relocation_model.unwrap_or(self.target.relocation_model) } diff --git a/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs index 33a785fdfee..aa823b13fdd 100644 --- a/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs @@ -11,6 +11,7 @@ pub fn target() -> Target { options: TargetOptions { linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), linker: Some("rust-lld".to_string()), + llvm_abiname: "lp64d".to_string(), cpu: "generic-rv64".to_string(), max_atomic_width: Some(64), atomic_cas: true, |
