@@ -7,10 +7,10 @@ use rustc_errors::{Applicability, DiagnosticBuilder};
7
7
use rustc_expand:: base:: { self , * } ;
8
8
use rustc_parse:: parser:: Parser ;
9
9
use rustc_parse_format as parse;
10
- use rustc_session:: lint;
10
+ use rustc_session:: lint:: { self , BuiltinLintDiagnostics } ;
11
11
use rustc_span:: symbol:: Ident ;
12
12
use rustc_span:: symbol:: { kw, sym, Symbol } ;
13
- use rustc_span:: { InnerSpan , Span } ;
13
+ use rustc_span:: { InnerSpan , MultiSpan , Span } ;
14
14
use rustc_target:: asm:: InlineAsmArch ;
15
15
use smallvec:: smallvec;
16
16
@@ -397,7 +397,11 @@ fn parse_reg<'a>(
397
397
Ok ( result)
398
398
}
399
399
400
- fn expand_preparsed_asm ( ecx : & mut ExtCtxt < ' _ > , args : AsmArgs ) -> Option < ast:: InlineAsm > {
400
+ fn expand_preparsed_asm (
401
+ ecx : & mut ExtCtxt < ' _ > ,
402
+ args : AsmArgs ,
403
+ is_local_asm : bool ,
404
+ ) -> Option < ast:: InlineAsm > {
401
405
let mut template = vec ! [ ] ;
402
406
// Register operands are implicitly used since they are not allowed to be
403
407
// referenced in the template string.
@@ -469,6 +473,72 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
469
473
}
470
474
}
471
475
476
+ // Lint against the use of named labels in inline `asm!` but not `global_asm!`
477
+ if is_local_asm {
478
+ let find_label_span = |needle : & str | -> Option < Span > {
479
+ if let Some ( snippet) = & template_snippet {
480
+ if let Some ( pos) = snippet. find ( needle) {
481
+ let end = pos
482
+ + & snippet[ pos..]
483
+ . find ( |c| c == ':' )
484
+ . unwrap_or ( snippet[ pos..] . len ( ) - 1 ) ;
485
+ let inner = InnerSpan :: new ( pos, end) ;
486
+ return Some ( template_sp. from_inner ( inner) ) ;
487
+ }
488
+ }
489
+
490
+ None
491
+ } ;
492
+
493
+ let mut found_labels = Vec :: new ( ) ;
494
+
495
+ // A semicolon might not actually be specified as a separator for all targets, but it seems like LLVM accepts it always
496
+ let statements = template_str. split ( |c| matches ! ( c, '\n' | ';' ) ) ;
497
+ for statement in statements {
498
+ // If there's a comment, trim it from the statement
499
+ let statement = statement. find ( "//" ) . map_or ( statement, |idx| & statement[ ..idx] ) ;
500
+ let mut start_idx = 0 ;
501
+ for ( idx, _) in statement. match_indices ( ':' ) {
502
+ let possible_label = statement[ start_idx..idx] . trim ( ) ;
503
+ let mut chars = possible_label. chars ( ) ;
504
+ if let Some ( c) = chars. next ( ) {
505
+ // A label starts with an alphabetic character or . or _ and continues with alphanumeric characters, _, or $
506
+ if ( c. is_alphabetic ( ) || matches ! ( c, '.' | '_' ) )
507
+ && chars. all ( |c| c. is_alphanumeric ( ) || matches ! ( c, '_' | '$' ) )
508
+ {
509
+ found_labels. push ( possible_label) ;
510
+ } else {
511
+ // If we encounter a non-label, there cannot be any further labels, so stop checking
512
+ break ;
513
+ }
514
+ } else {
515
+ // Empty string means a leading ':' in this section, which is not a label
516
+ break ;
517
+ }
518
+
519
+ start_idx = idx + 1 ;
520
+ }
521
+ }
522
+
523
+ if found_labels. len ( ) > 0 {
524
+ let spans =
525
+ found_labels. into_iter ( ) . filter_map ( find_label_span) . collect :: < Vec < Span > > ( ) ;
526
+ // If there were labels but we couldn't find a span, combine the warnings and use the template span
527
+ let target_spans: MultiSpan =
528
+ if spans. len ( ) > 0 { spans. into ( ) } else { template_sp. into ( ) } ;
529
+ ecx. parse_sess ( ) . buffer_lint_with_diagnostic (
530
+ lint:: builtin:: NAMED_ASM_LABELS ,
531
+ target_spans,
532
+ ecx. current_expansion . lint_node_id ,
533
+ "avoid using named labels in inline assembly" ,
534
+ BuiltinLintDiagnostics :: NamedAsmLabel (
535
+ "only local labels of the form `<number>:` should be used in inline asm"
536
+ . to_string ( ) ,
537
+ ) ,
538
+ ) ;
539
+ }
540
+ }
541
+
472
542
// Don't treat raw asm as a format string.
473
543
if args. options . contains ( ast:: InlineAsmOptions :: RAW ) {
474
544
template. push ( ast:: InlineAsmTemplatePiece :: String ( template_str. to_string ( ) ) ) ;
@@ -670,7 +740,7 @@ pub fn expand_asm<'cx>(
670
740
) -> Box < dyn base:: MacResult + ' cx > {
671
741
match parse_args ( ecx, sp, tts, false ) {
672
742
Ok ( args) => {
673
- let expr = if let Some ( inline_asm) = expand_preparsed_asm ( ecx, args) {
743
+ let expr = if let Some ( inline_asm) = expand_preparsed_asm ( ecx, args, true ) {
674
744
P ( ast:: Expr {
675
745
id : ast:: DUMMY_NODE_ID ,
676
746
kind : ast:: ExprKind :: InlineAsm ( P ( inline_asm) ) ,
@@ -697,7 +767,7 @@ pub fn expand_global_asm<'cx>(
697
767
) -> Box < dyn base:: MacResult + ' cx > {
698
768
match parse_args ( ecx, sp, tts, true ) {
699
769
Ok ( args) => {
700
- if let Some ( inline_asm) = expand_preparsed_asm ( ecx, args) {
770
+ if let Some ( inline_asm) = expand_preparsed_asm ( ecx, args, false ) {
701
771
MacEager :: items ( smallvec ! [ P ( ast:: Item {
702
772
ident: Ident :: invalid( ) ,
703
773
attrs: Vec :: new( ) ,
0 commit comments