@@ -30,13 +30,13 @@ use crate::{
3030 BuiltinExplicitOutlivesSuggestion , BuiltinFeatureIssueNote , BuiltinIncompleteFeatures ,
3131 BuiltinIncompleteFeaturesHelp , BuiltinInternalFeatures , BuiltinKeywordIdents ,
3232 BuiltinMissingCopyImpl , BuiltinMissingDebugImpl , BuiltinMissingDoc ,
33- BuiltinMutablesTransmutes , BuiltinNamedAsmLabel , BuiltinNoMangleGeneric ,
34- BuiltinNonShorthandFieldPatterns , BuiltinSpecialModuleNameUsed , BuiltinTrivialBounds ,
35- BuiltinTypeAliasGenericBounds , BuiltinTypeAliasGenericBoundsSuggestion ,
36- BuiltinTypeAliasWhereClause , BuiltinUngatedAsyncFnTrackCaller , BuiltinUnpermittedTypeInit ,
33+ BuiltinMutablesTransmutes , BuiltinNoMangleGeneric , BuiltinNonShorthandFieldPatterns ,
34+ BuiltinSpecialModuleNameUsed , BuiltinTrivialBounds , BuiltinTypeAliasGenericBounds ,
35+ BuiltinTypeAliasGenericBoundsSuggestion , BuiltinTypeAliasWhereClause ,
36+ BuiltinUngatedAsyncFnTrackCaller , BuiltinUnpermittedTypeInit ,
3737 BuiltinUnpermittedTypeInitSub , BuiltinUnreachablePub , BuiltinUnsafe ,
3838 BuiltinUnstableFeatures , BuiltinUnusedDocComment , BuiltinUnusedDocCommentSub ,
39- BuiltinWhileTrue , SuggestChangingAssocTypes ,
39+ BuiltinWhileTrue , InvalidAsmLabel , SuggestChangingAssocTypes ,
4040 } ,
4141 EarlyContext , EarlyLintPass , LateContext , LateLintPass , Level , LintContext ,
4242} ;
@@ -45,7 +45,7 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree};
4545use rustc_ast:: visit:: { FnCtxt , FnKind } ;
4646use rustc_ast:: { self as ast, * } ;
4747use rustc_ast_pretty:: pprust:: { self , expr_to_string} ;
48- use rustc_errors:: { Applicability , LintDiagnostic , MultiSpan } ;
48+ use rustc_errors:: { Applicability , LintDiagnostic } ;
4949use rustc_feature:: { deprecated_attributes, AttributeGate , BuiltinAttribute , GateIssue , Stability } ;
5050use rustc_hir as hir;
5151use rustc_hir:: def:: { DefKind , Res } ;
@@ -70,7 +70,6 @@ use rustc_target::abi::Abi;
7070use rustc_trait_selection:: infer:: { InferCtxtExt , TyCtxtInferExt } ;
7171use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt as _;
7272use rustc_trait_selection:: traits:: { self , misc:: type_allowed_to_implement_copy} ;
73- use tracing:: debug;
7473
7574use crate :: nonstandard_style:: { method_context, MethodLateContext } ;
7675
@@ -2804,10 +2803,48 @@ declare_lint! {
28042803 "named labels in inline assembly" ,
28052804}
28062805
2807- declare_lint_pass ! ( NamedAsmLabels => [ NAMED_ASM_LABELS ] ) ;
2806+ declare_lint ! {
2807+ /// The `binary_asm_labels` lint detects the use of numeric labels containing only binary
2808+ /// digits in the inline `asm!` macro.
2809+ ///
2810+ /// ### Example
2811+ ///
2812+ /// ```rust,compile_fail
2813+ /// # #![feature(asm_experimental_arch)]
2814+ /// use std::arch::asm;
2815+ ///
2816+ /// fn main() {
2817+ /// unsafe {
2818+ /// asm!("0: bar");
2819+ /// }
2820+ /// }
2821+ /// ```
2822+ ///
2823+ /// {{produces}}
2824+ ///
2825+ /// ### Explanation
2826+ ///
2827+ /// A bug in LLVM causes this code to fail
2828+ ///
2829+ /// See the explanation in [Rust By Example] for more details.
2830+ ///
2831+ /// [local labels]: https://sourceware.org/binutils/docs/as/Symbol-Names.html#Local-Labels
2832+ /// [Rust By Example]: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels
2833+ pub BINARY_ASM_LABELS ,
2834+ Deny ,
2835+ "labels in inline assembly containing only 0 or 1 digits" ,
2836+ }
2837+
2838+ declare_lint_pass ! ( AsmLabels => [ NAMED_ASM_LABELS , BINARY_ASM_LABELS ] ) ;
2839+
2840+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
2841+ enum AsmLabelKind {
2842+ Named ,
2843+ FormatArg ,
2844+ Binary ,
2845+ }
28082846
2809- impl < ' tcx > LateLintPass < ' tcx > for NamedAsmLabels {
2810- #[ allow( rustc:: diagnostic_outside_of_impl) ]
2847+ impl < ' tcx > LateLintPass < ' tcx > for AsmLabels {
28112848 fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx hir:: Expr < ' tcx > ) {
28122849 if let hir:: Expr {
28132850 kind : hir:: ExprKind :: InlineAsm ( hir:: InlineAsm { template_strs, options, .. } ) ,
@@ -2835,7 +2872,8 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels {
28352872 None
28362873 } ;
28372874
2838- let mut found_labels = Vec :: new ( ) ;
2875+ // diagnostics are emitted per-template, so this is created here as opposed to the outer loop
2876+ let mut spans = Vec :: new ( ) ;
28392877
28402878 // A semicolon might not actually be specified as a separator for all targets, but
28412879 // it seems like LLVM accepts it always.
@@ -2858,16 +2896,21 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels {
28582896
28592897 // Whether a { bracket has been seen and its } hasn't been found yet.
28602898 let mut in_bracket = false ;
2899+ let mut label_kind = AsmLabelKind :: Named ;
28612900
2862- // A label starts with an ASCII alphabetic character or . or _
28632901 // A label can also start with a format arg, if it's not a raw asm block.
28642902 if !raw && start == '{' {
28652903 in_bracket = true ;
2904+ label_kind = AsmLabelKind :: FormatArg ;
2905+ } else if matches ! ( start, '0' | '1' ) {
2906+ // binary labels have only the characters 0 or 1
2907+ label_kind = AsmLabelKind :: Binary ;
28662908 } else if !( start. is_ascii_alphabetic ( ) || matches ! ( start, '.' | '_' ) ) {
2909+ // named labels start with ASCII letters or . or _
2910+ // anything else is not a label
28672911 break ' label_loop;
28682912 }
28692913
2870- // Labels continue with ASCII alphanumeric characters, _, or $
28712914 for c in chars {
28722915 // Inside a template format arg, any character is permitted for the
28732916 // puproses of label detection because we assume that it can be
@@ -2888,34 +2931,55 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels {
28882931 } else if !raw && c == '{' {
28892932 // Start of a format arg.
28902933 in_bracket = true ;
2934+ label_kind = AsmLabelKind :: FormatArg ;
28912935 } else {
2892- if !( c. is_ascii_alphanumeric ( ) || matches ! ( c, '_' | '$' ) ) {
2936+ let can_continue = match label_kind {
2937+ // format arg labels are considered to be named labels for the purposes
2938+ // of continuing outside of their {} pair.
2939+ AsmLabelKind :: Named | AsmLabelKind :: FormatArg => {
2940+ c. is_ascii_alphanumeric ( ) || matches ! ( c, '_' | '$' )
2941+ }
2942+ AsmLabelKind :: Binary => matches ! ( c, '0' | '1' ) ,
2943+ } ;
2944+
2945+ if !can_continue {
28932946 // The potential label had an invalid character inside it, it
28942947 // cannot be a label.
28952948 break ' label_loop;
28962949 }
28972950 }
28982951 }
28992952
2900- // If all characters passed the label checks, this is likely a label.
2901- found_labels . push ( possible_label) ;
2953+ // If all characters passed the label checks, this is a label.
2954+ spans . push ( ( find_label_span ( possible_label) , label_kind ) ) ;
29022955 start_idx = idx + 1 ;
29032956 }
29042957 }
29052958
2906- debug ! ( "NamedAsmLabels::check_expr(): found_labels: {:#?}" , & found_labels) ;
2907-
2908- if found_labels. len ( ) > 0 {
2909- let spans = found_labels
2910- . into_iter ( )
2911- . filter_map ( |label| find_label_span ( label) )
2912- . collect :: < Vec < Span > > ( ) ;
2913- // If there were labels but we couldn't find a span, combine the warnings and
2914- // use the template span.
2915- let target_spans: MultiSpan =
2916- if spans. len ( ) > 0 { spans. into ( ) } else { ( * template_span) . into ( ) } ;
2917-
2918- cx. emit_span_lint ( NAMED_ASM_LABELS , target_spans, BuiltinNamedAsmLabel ) ;
2959+ for ( span, label_kind) in spans {
2960+ let missing_precise_span = span. is_none ( ) ;
2961+ let span = span. unwrap_or ( * template_span) ;
2962+ match label_kind {
2963+ AsmLabelKind :: Named => {
2964+ cx. emit_span_lint (
2965+ NAMED_ASM_LABELS ,
2966+ span,
2967+ InvalidAsmLabel :: Named { missing_precise_span } ,
2968+ ) ;
2969+ }
2970+ AsmLabelKind :: FormatArg => {
2971+ cx. emit_span_lint (
2972+ NAMED_ASM_LABELS ,
2973+ span,
2974+ InvalidAsmLabel :: FormatArg { missing_precise_span } ,
2975+ ) ;
2976+ }
2977+ AsmLabelKind :: Binary => cx. emit_span_lint (
2978+ BINARY_ASM_LABELS ,
2979+ span,
2980+ InvalidAsmLabel :: Binary { missing_precise_span } ,
2981+ ) ,
2982+ } ;
29192983 }
29202984 }
29212985 }
0 commit comments