From 26150a9d3b719ac1f0d3fff236378687aa20639c Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Mon, 28 Sep 2020 15:30:47 +0200 Subject: [PATCH] Add lint for inline assembly syntax style preference --- CHANGELOG.md | 2 + clippy_lints/src/asm_syntax.rs | 155 +++++++++++++++++++++++++++++++++ clippy_lints/src/lib.rs | 7 ++ src/lintlist/mod.rs | 14 +++ tests/ui/asm_syntax.rs | 29 ++++++ tests/ui/asm_syntax.stderr | 28 ++++++ 6 files changed, 235 insertions(+) create mode 100644 clippy_lints/src/asm_syntax.rs create mode 100644 tests/ui/asm_syntax.rs create mode 100644 tests/ui/asm_syntax.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 575cbd60792f..0de6f4b4235f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1635,6 +1635,8 @@ Released 2018-09-13 [`inherent_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string [`inherent_to_string_shadow_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string_shadow_display [`inline_always`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_always +[`inline_asm_x86_att_syntax`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_asm_x86_att_syntax +[`inline_asm_x86_intel_syntax`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_asm_x86_intel_syntax [`inline_fn_without_body`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_fn_without_body [`int_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#int_plus_one [`integer_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_arithmetic diff --git a/clippy_lints/src/asm_syntax.rs b/clippy_lints/src/asm_syntax.rs new file mode 100644 index 000000000000..ab48938a7347 --- /dev/null +++ b/clippy_lints/src/asm_syntax.rs @@ -0,0 +1,155 @@ +use std::fmt; + +use crate::utils::span_lint_and_help; +use rustc_ast::{ + ast::MacCall, + token::{Token, TokenKind}, + tokenstream::{self, TokenTree}, +}; +use rustc_lint::{EarlyContext, EarlyLintPass, Lint}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::Span; + +#[derive(Clone, Copy, PartialEq, Eq)] +enum AsmStyle { + Intel, + Att, +} + +impl fmt::Display for AsmStyle { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + AsmStyle::Intel => f.write_str("Intel"), + AsmStyle::Att => f.write_str("AT&T"), + } + } +} + +impl std::ops::Not for AsmStyle { + type Output = AsmStyle; + + fn not(self) -> AsmStyle { + match self { + AsmStyle::Intel => AsmStyle::Att, + AsmStyle::Att => AsmStyle::Intel, + } + } +} + +fn check_mac_asm_syntax(lint: &'static Lint, cx: &EarlyContext<'_>, mac: &MacCall, check_for: AsmStyle) { + /// Find the `options(...)` specified in an `asm!` macro call, if any + fn find_options_tts(mac: &MacCall) -> Option<(Span, tokenstream::Cursor)> { + let mut cursor = mac.args.inner_tokens().trees().fuse(); + for tt in &mut cursor { + match tt { + TokenTree::Token(Token { + kind: TokenKind::Ident(ident, _), + span: ident_span, + }) if ident == sym!(options) => { + if let TokenTree::Delimited(tts_span, _, stream) = cursor.next()? { + return Some((ident_span.to(tts_span.close), stream.trees())); + } else { + return None; + } + }, + _ => {}, + } + } + None + } + + /// Find the `att_syntax` specified in an `asm!` macro call options, if any + fn find_att_syntax_ident(cursor: tokenstream::Cursor) -> Option { + for tt in cursor { + match tt { + TokenTree::Token(Token { + kind: TokenKind::Ident(ident, _), + span, + }) if ident == sym!(att_syntax) => return Some(span), + _ => {}, + } + } + None + } + + if mac.path == sym!(asm) { + let (style, relevant_span) = match find_options_tts(mac) { + Some((opt_span, options)) => match find_att_syntax_ident(options) { + Some(att_span) => (AsmStyle::Att, att_span), + None => (AsmStyle::Intel, opt_span), + }, + None => (AsmStyle::Intel, mac.span()), + }; + + if style == check_for { + span_lint_and_help( + cx, + lint, + relevant_span, + &format!("{} x86 assembly syntax used", style), + None, + &format!("use {} x86 assembly syntax", !style), + ); + } + } +} + +declare_clippy_lint! { + /// **What it does:** Checks for usage of Intel x86 assembly syntax. + /// + /// **Why is this bad?** The lint has been enabled to indicate a preference + /// for AT&T x86 assembly syntax. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr); + /// ``` + /// Use instead: + /// ```rust + /// asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax)); + /// ``` + pub INLINE_ASM_X86_INTEL_SYNTAX, + restriction, + "prefer AT&T x86 assembly syntax" +} + +declare_lint_pass!(InlineAsmX86IntelSyntax => [INLINE_ASM_X86_INTEL_SYNTAX]); + +impl EarlyLintPass for InlineAsmX86IntelSyntax { + fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &MacCall) { + check_mac_asm_syntax(Self::get_lints()[0], cx, mac, AsmStyle::Intel); + } +} + +declare_clippy_lint! { + /// **What it does:** Checks for usage of AT&T x86 assembly syntax. + /// + /// **Why is this bad?** The lint has been enabled to indicate a preference + /// for Intel x86 assembly syntax. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax)); + /// ``` + /// Use instead: + /// ```rust + /// asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr); + /// ``` + pub INLINE_ASM_X86_ATT_SYNTAX, + restriction, + "prefer Intel x86 assembly syntax" +} + +declare_lint_pass!(InlineAsmX86AttSyntax => [INLINE_ASM_X86_ATT_SYNTAX]); + +impl EarlyLintPass for InlineAsmX86AttSyntax { + fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &MacCall) { + check_mac_asm_syntax(Self::get_lints()[0], cx, mac, AsmStyle::Att); + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 529c2450541d..7ec68a0ce5be 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -153,6 +153,7 @@ mod utils; mod approx_const; mod arithmetic; mod as_conversions; +mod asm_syntax; mod assertions_on_constants; mod assign_ops; mod async_yields_async; @@ -347,6 +348,8 @@ pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore) { store.register_pre_expansion_pass(|| box write::Write::default()); store.register_pre_expansion_pass(|| box attrs::EarlyAttributes); store.register_pre_expansion_pass(|| box dbg_macro::DbgMacro); + store.register_pre_expansion_pass(|| box asm_syntax::InlineAsmX86AttSyntax); + store.register_pre_expansion_pass(|| box asm_syntax::InlineAsmX86IntelSyntax); } #[doc(hidden)] @@ -487,6 +490,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &arithmetic::FLOAT_ARITHMETIC, &arithmetic::INTEGER_ARITHMETIC, &as_conversions::AS_CONVERSIONS, + &asm_syntax::INLINE_ASM_X86_ATT_SYNTAX, + &asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX, &assertions_on_constants::ASSERTIONS_ON_CONSTANTS, &assign_ops::ASSIGN_OP_PATTERN, &assign_ops::MISREFACTORED_ASSIGN_OP, @@ -1129,6 +1134,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&arithmetic::FLOAT_ARITHMETIC), LintId::of(&arithmetic::INTEGER_ARITHMETIC), LintId::of(&as_conversions::AS_CONVERSIONS), + LintId::of(&asm_syntax::INLINE_ASM_X86_ATT_SYNTAX), + LintId::of(&asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX), LintId::of(&create_dir::CREATE_DIR), LintId::of(&dbg_macro::DBG_MACRO), LintId::of(&else_if_without_else::ELSE_IF_WITHOUT_ELSE), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 76e655ad6030..16ceb6179654 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -899,6 +899,20 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "attrs", }, + Lint { + name: "inline_asm_x86_att_syntax", + group: "restriction", + desc: "prefer Intel x86 assembly syntax", + deprecation: None, + module: "asm_syntax", + }, + Lint { + name: "inline_asm_x86_intel_syntax", + group: "restriction", + desc: "prefer AT&T x86 assembly syntax", + deprecation: None, + module: "asm_syntax", + }, Lint { name: "inline_fn_without_body", group: "correctness", diff --git a/tests/ui/asm_syntax.rs b/tests/ui/asm_syntax.rs new file mode 100644 index 000000000000..21ba766983a5 --- /dev/null +++ b/tests/ui/asm_syntax.rs @@ -0,0 +1,29 @@ +#![feature(asm)] + +#[cfg(any(target_arch = "x86_64", target_arch = "x86"))] +#[warn(clippy::inline_asm_x86_intel_syntax)] +mod warn_intel { + pub(super) unsafe fn use_asm() { + asm!(""); + asm!("", options()); + asm!("", options(att_syntax)); + } +} + +#[cfg(any(target_arch = "x86_64", target_arch = "x86"))] +#[warn(clippy::inline_asm_x86_att_syntax)] +mod warn_att { + pub(super) unsafe fn use_asm() { + asm!(""); + asm!("", options()); + asm!("", options(att_syntax)); + } +} + +fn main() { + #[cfg(any(target_arch = "x86_64", target_arch = "x86"))] + unsafe { + warn_att::use_asm(); + warn_intel::use_asm(); + } +} diff --git a/tests/ui/asm_syntax.stderr b/tests/ui/asm_syntax.stderr new file mode 100644 index 000000000000..dfe73f5b55c0 --- /dev/null +++ b/tests/ui/asm_syntax.stderr @@ -0,0 +1,28 @@ +error: Intel x86 assembly syntax used + --> $DIR/asm_syntax.rs:7:9 + | +LL | asm!(""); + | ^^^^^^^^ + | + = note: `-D clippy::inline-asm-x86-intel-syntax` implied by `-D warnings` + = help: use AT&T x86 assembly syntax + +error: Intel x86 assembly syntax used + --> $DIR/asm_syntax.rs:8:18 + | +LL | asm!("", options()); + | ^^^^^^^^^ + | + = help: use AT&T x86 assembly syntax + +error: AT&T x86 assembly syntax used + --> $DIR/asm_syntax.rs:19:26 + | +LL | asm!("", options(att_syntax)); + | ^^^^^^^^^^ + | + = note: `-D clippy::inline-asm-x86-att-syntax` implied by `-D warnings` + = help: use Intel x86 assembly syntax + +error: aborting due to 3 previous errors +