@@ -30,13 +30,13 @@ use crate::{
30
30
BuiltinExplicitOutlivesSuggestion , BuiltinFeatureIssueNote , BuiltinIncompleteFeatures ,
31
31
BuiltinIncompleteFeaturesHelp , BuiltinInternalFeatures , BuiltinKeywordIdents ,
32
32
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 ,
37
37
BuiltinUnpermittedTypeInitSub , BuiltinUnreachablePub , BuiltinUnsafe ,
38
38
BuiltinUnstableFeatures , BuiltinUnusedDocComment , BuiltinUnusedDocCommentSub ,
39
- BuiltinWhileTrue , SuggestChangingAssocTypes ,
39
+ BuiltinWhileTrue , InvalidAsmLabel , SuggestChangingAssocTypes ,
40
40
} ,
41
41
EarlyContext , EarlyLintPass , LateContext , LateLintPass , Level , LintContext ,
42
42
} ;
@@ -45,7 +45,7 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree};
45
45
use rustc_ast:: visit:: { FnCtxt , FnKind } ;
46
46
use rustc_ast:: { self as ast, * } ;
47
47
use rustc_ast_pretty:: pprust:: { self , expr_to_string} ;
48
- use rustc_errors:: { Applicability , LintDiagnostic , MultiSpan } ;
48
+ use rustc_errors:: { Applicability , LintDiagnostic } ;
49
49
use rustc_feature:: { deprecated_attributes, AttributeGate , BuiltinAttribute , GateIssue , Stability } ;
50
50
use rustc_hir as hir;
51
51
use rustc_hir:: def:: { DefKind , Res } ;
@@ -70,7 +70,6 @@ use rustc_target::abi::Abi;
70
70
use rustc_trait_selection:: infer:: { InferCtxtExt , TyCtxtInferExt } ;
71
71
use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt as _;
72
72
use rustc_trait_selection:: traits:: { self , misc:: type_allowed_to_implement_copy} ;
73
- use tracing:: debug;
74
73
75
74
use crate :: nonstandard_style:: { method_context, MethodLateContext } ;
76
75
@@ -2804,10 +2803,48 @@ declare_lint! {
2804
2803
"named labels in inline assembly" ,
2805
2804
}
2806
2805
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
+ }
2808
2846
2809
- impl < ' tcx > LateLintPass < ' tcx > for NamedAsmLabels {
2810
- #[ allow( rustc:: diagnostic_outside_of_impl) ]
2847
+ impl < ' tcx > LateLintPass < ' tcx > for AsmLabels {
2811
2848
fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx hir:: Expr < ' tcx > ) {
2812
2849
if let hir:: Expr {
2813
2850
kind : hir:: ExprKind :: InlineAsm ( hir:: InlineAsm { template_strs, options, .. } ) ,
@@ -2835,7 +2872,8 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels {
2835
2872
None
2836
2873
} ;
2837
2874
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 ( ) ;
2839
2877
2840
2878
// A semicolon might not actually be specified as a separator for all targets, but
2841
2879
// it seems like LLVM accepts it always.
@@ -2858,16 +2896,21 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels {
2858
2896
2859
2897
// Whether a { bracket has been seen and its } hasn't been found yet.
2860
2898
let mut in_bracket = false ;
2899
+ let mut label_kind = AsmLabelKind :: Named ;
2861
2900
2862
- // A label starts with an ASCII alphabetic character or . or _
2863
2901
// A label can also start with a format arg, if it's not a raw asm block.
2864
2902
if !raw && start == '{' {
2865
2903
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 ;
2866
2908
} else if !( start. is_ascii_alphabetic ( ) || matches ! ( start, '.' | '_' ) ) {
2909
+ // named labels start with ASCII letters or . or _
2910
+ // anything else is not a label
2867
2911
break ' label_loop;
2868
2912
}
2869
2913
2870
- // Labels continue with ASCII alphanumeric characters, _, or $
2871
2914
for c in chars {
2872
2915
// Inside a template format arg, any character is permitted for the
2873
2916
// puproses of label detection because we assume that it can be
@@ -2888,34 +2931,55 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels {
2888
2931
} else if !raw && c == '{' {
2889
2932
// Start of a format arg.
2890
2933
in_bracket = true ;
2934
+ label_kind = AsmLabelKind :: FormatArg ;
2891
2935
} 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 {
2893
2946
// The potential label had an invalid character inside it, it
2894
2947
// cannot be a label.
2895
2948
break ' label_loop;
2896
2949
}
2897
2950
}
2898
2951
}
2899
2952
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 ) ) ;
2902
2955
start_idx = idx + 1 ;
2903
2956
}
2904
2957
}
2905
2958
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
+ } ;
2919
2983
}
2920
2984
}
2921
2985
}
0 commit comments