about summary refs log tree commit diff
path: root/compiler/rustc_lint/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-08-25 16:22:57 +0000
committerbors <bors@rust-lang.org>2021-08-25 16:22:57 +0000
commit7b0e554ee2c94e9b3865a8c2d24d720224512dec (patch)
treec593474b55894db3cd17a5a78200005ba265bd53 /compiler/rustc_lint/src
parenta992a11913b39a258158646bb1e03528c5aa5060 (diff)
parentd9ed23a9130b0941fd1ed4a651cbbec8a6621dd8 (diff)
downloadrust-7b0e554ee2c94e9b3865a8c2d24d720224512dec.tar.gz
rust-7b0e554ee2c94e9b3865a8c2d24d720224512dec.zip
Auto merge of #88329 - LeSeulArtichaut:rollup-blg8hc0, r=LeSeulArtichaut
Rollup of 16 pull requests

Successful merges:

 - #87944 (add Cell::as_array_of_cells, similar to Cell::as_slice_of_cells)
 - #88156 (Adjust / fix documentation of `Arc::make_mut`)
 - #88157 (bootstrap.py: recognize riscv64 when auto-detect)
 - #88196 (Refactor `named_asm_labels` to a HIR lint)
 - #88218 (Remove `Session.trait_methods_not_found`)
 - #88223 (Remove the `TryV2` alias)
 - #88226 (Fix typo “a Rc” → “an Rc” (and a few more))
 - #88267 (2229: Update signature for truncate function)
 - #88273 (Fix references to `ControlFlow` in docs)
 - #88277 (Update books)
 - #88291 (Add SAFETY comments to core::slice::sort::partition_in_blocks)
 - #88293 (Fix grammar in alloc test)
 - #88298 (Errorkind reorder)
 - #88299 (Stabilise BufWriter::into_parts)
 - #88314 (Add type of a let tait test)
 - #88325 (Add mutable-noalias to the release notes for 1.54)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'compiler/rustc_lint/src')
-rw-r--r--compiler/rustc_lint/src/builtin.rs124
-rw-r--r--compiler/rustc_lint/src/lib.rs1
2 files changed, 123 insertions, 2 deletions
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index afa2cfca188..add0c0ff332 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -45,11 +45,11 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::subst::{GenericArgKind, Subst};
 use rustc_middle::ty::Instance;
 use rustc_middle::ty::{self, layout::LayoutError, Ty, TyCtxt};
-use rustc_session::lint::FutureIncompatibilityReason;
+use rustc_session::lint::{BuiltinLintDiagnostics, FutureIncompatibilityReason};
 use rustc_span::edition::Edition;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{BytePos, Span};
+use rustc_span::{BytePos, InnerSpan, MultiSpan, Span};
 use rustc_target::abi::{LayoutOf, VariantIdx};
 use rustc_trait_selection::traits::misc::can_type_implement_copy;
 
@@ -3140,3 +3140,123 @@ impl<'tcx> LateLintPass<'tcx> for DerefNullPtr {
         }
     }
 }
+
+declare_lint! {
+    /// The `named_asm_labels` lint detects the use of named labels in the
+    /// inline `asm!` macro.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![feature(asm)]
+    /// fn main() {
+    ///     unsafe {
+    ///         asm!("foo: bar");
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// LLVM is allowed to duplicate inline assembly blocks for any
+    /// reason, for example when it is in a function that gets inlined. Because
+    /// of this, GNU assembler [local labels] *must* be used instead of labels
+    /// with a name. Using named labels might cause assembler or linker errors.
+    ///
+    /// See the [unstable book] for more details.
+    ///
+    /// [local labels]: https://sourceware.org/binutils/docs/as/Symbol-Names.html#Local-Labels
+    /// [unstable book]: https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels
+    pub NAMED_ASM_LABELS,
+    Deny,
+    "named labels in inline assembly",
+}
+
+declare_lint_pass!(NamedAsmLabels => [NAMED_ASM_LABELS]);
+
+impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
+        if let hir::Expr {
+            kind: hir::ExprKind::InlineAsm(hir::InlineAsm { template_strs, .. }),
+            ..
+        } = expr
+        {
+            for (template_sym, template_snippet, template_span) in template_strs.iter() {
+                let template_str = &template_sym.as_str();
+                let find_label_span = |needle: &str| -> Option<Span> {
+                    if let Some(template_snippet) = template_snippet {
+                        let snippet = template_snippet.as_str();
+                        if let Some(pos) = snippet.find(needle) {
+                            let end = pos
+                                + &snippet[pos..]
+                                    .find(|c| c == ':')
+                                    .unwrap_or(snippet[pos..].len() - 1);
+                            let inner = InnerSpan::new(pos, end);
+                            return Some(template_span.from_inner(inner));
+                        }
+                    }
+
+                    None
+                };
+
+                let mut found_labels = Vec::new();
+
+                // A semicolon might not actually be specified as a separator for all targets, but it seems like LLVM accepts it always
+                let statements = template_str.split(|c| matches!(c, '\n' | ';'));
+                for statement in statements {
+                    // If there's a comment, trim it from the statement
+                    let statement = statement.find("//").map_or(statement, |idx| &statement[..idx]);
+                    let mut start_idx = 0;
+                    for (idx, _) in statement.match_indices(':') {
+                        let possible_label = statement[start_idx..idx].trim();
+                        let mut chars = possible_label.chars();
+                        if let Some(c) = chars.next() {
+                            // A label starts with an alphabetic character or . or _ and continues with alphanumeric characters, _, or $
+                            if (c.is_alphabetic() || matches!(c, '.' | '_'))
+                                && chars.all(|c| c.is_alphanumeric() || matches!(c, '_' | '$'))
+                            {
+                                found_labels.push(possible_label);
+                            } else {
+                                // If we encounter a non-label, there cannot be any further labels, so stop checking
+                                break;
+                            }
+                        } else {
+                            // Empty string means a leading ':' in this section, which is not a label
+                            break;
+                        }
+
+                        start_idx = idx + 1;
+                    }
+                }
+
+                debug!("NamedAsmLabels::check_expr(): found_labels: {:#?}", &found_labels);
+
+                if found_labels.len() > 0 {
+                    let spans = found_labels
+                        .into_iter()
+                        .filter_map(|label| find_label_span(label))
+                        .collect::<Vec<Span>>();
+                    // If there were labels but we couldn't find a span, combine the warnings and use the template span
+                    let target_spans: MultiSpan =
+                        if spans.len() > 0 { spans.into() } else { (*template_span).into() };
+
+                    cx.lookup_with_diagnostics(
+                            NAMED_ASM_LABELS,
+                            Some(target_spans),
+                            |diag| {
+                                let mut err =
+                                    diag.build("avoid using named labels in inline assembly");
+                                err.emit();
+                            },
+                            BuiltinLintDiagnostics::NamedAsmLabel(
+                                "only local labels of the form `<number>:` should be used in inline asm"
+                                    .to_string(),
+                            ),
+                        );
+                }
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index c4008e77bab..24ac723f2c9 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -168,6 +168,7 @@ macro_rules! late_lint_passes {
                 NonPanicFmt: NonPanicFmt,
                 NoopMethodCall: NoopMethodCall,
                 InvalidAtomicOrdering: InvalidAtomicOrdering,
+                NamedAsmLabels: NamedAsmLabels,
             ]
         );
     };