Skip to content

Commit be8147e

Browse files
author
Oblarg
committed
fix transcriber error in declarative macros for negative integer literal const generic params
1 parent b12a129 commit be8147e

File tree

2 files changed

+110
-1
lines changed

2 files changed

+110
-1
lines changed

crates/mbe/src/expander/transcriber.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,19 @@ fn expand_var(
401401
let sub = sub.strip_invisible();
402402
let mut span = id;
403403
marker(&mut span);
404-
let wrap_in_parens = !matches!(sub.flat_tokens(), [tt::TokenTree::Leaf(_)])
404+
405+
// Check if this is a simple negative literal (MINUS + LITERAL)
406+
// that should not be wrapped in parentheses
407+
let is_negative_literal = matches!(
408+
sub.flat_tokens(),
409+
[
410+
tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: '-', .. })),
411+
tt::TokenTree::Leaf(tt::Leaf::Literal(_))
412+
]
413+
);
414+
415+
let wrap_in_parens = !is_negative_literal
416+
&& !matches!(sub.flat_tokens(), [tt::TokenTree::Leaf(_)])
405417
&& sub.try_into_subtree().is_none_or(|it| {
406418
it.top_subtree().delimiter.kind == tt::DelimiterKind::Invisible
407419
});

crates/mbe/src/tests.rs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,3 +476,100 @@ fn minus_belongs_to_literal() {
476476
--"#]],
477477
);
478478
}
479+
480+
#[test]
481+
fn negative_literals_in_const_generics() {
482+
// Test that negative literals work correctly in declarative macros
483+
// when used as const generic arguments. The issue was that expressions
484+
// like -1 would be wrapped in parentheses, creating invalid syntax
485+
// Foo::<(-1)> instead of the correct Foo::<-1>.
486+
let decl = r#"
487+
($val:expr) => {
488+
struct Foo<const I: i16> {
489+
pub value: i16,
490+
}
491+
492+
impl<const I: i16> Foo<I> {
493+
pub fn new(value: i16) -> Self {
494+
Self { value }
495+
}
496+
}
497+
498+
Foo::<$val>::new($val)
499+
};
500+
"#;
501+
let check = |args, expect| check(Edition::CURRENT, Edition::CURRENT, decl, args, expect);
502+
503+
// Test negative integer literal - should produce Foo::<-1>, not Foo::<(-1)>
504+
check(
505+
"-1",
506+
expect![[r#"
507+
SUBTREE $$ 1:Root[0000, 0]@0..2#ROOT2024 1:Root[0000, 0]@0..2#ROOT2024
508+
IDENT struct 0:Root[0000, 0]@22..28#ROOT2024
509+
IDENT Foo 0:Root[0000, 0]@29..32#ROOT2024
510+
PUNCH < [alone] 0:Root[0000, 0]@32..33#ROOT2024
511+
IDENT const 0:Root[0000, 0]@33..38#ROOT2024
512+
IDENT I 0:Root[0000, 0]@39..40#ROOT2024
513+
PUNCH : [alone] 0:Root[0000, 0]@40..41#ROOT2024
514+
IDENT i16 0:Root[0000, 0]@42..45#ROOT2024
515+
PUNCH > [alone] 0:Root[0000, 0]@45..46#ROOT2024
516+
SUBTREE {} 0:Root[0000, 0]@47..48#ROOT2024 0:Root[0000, 0]@77..78#ROOT2024
517+
IDENT pub 0:Root[0000, 0]@57..60#ROOT2024
518+
IDENT value 0:Root[0000, 0]@61..66#ROOT2024
519+
PUNCH : [alone] 0:Root[0000, 0]@66..67#ROOT2024
520+
IDENT i16 0:Root[0000, 0]@68..71#ROOT2024
521+
PUNCH , [alone] 0:Root[0000, 0]@71..72#ROOT2024
522+
IDENT impl 0:Root[0000, 0]@88..92#ROOT2024
523+
PUNCH < [alone] 0:Root[0000, 0]@92..93#ROOT2024
524+
IDENT const 0:Root[0000, 0]@93..98#ROOT2024
525+
IDENT I 0:Root[0000, 0]@99..100#ROOT2024
526+
PUNCH : [alone] 0:Root[0000, 0]@100..101#ROOT2024
527+
IDENT i16 0:Root[0000, 0]@102..105#ROOT2024
528+
PUNCH > [alone] 0:Root[0000, 0]@105..106#ROOT2024
529+
IDENT Foo 0:Root[0000, 0]@107..110#ROOT2024
530+
PUNCH < [alone] 0:Root[0000, 0]@110..111#ROOT2024
531+
IDENT I 0:Root[0000, 0]@111..112#ROOT2024
532+
PUNCH > [alone] 0:Root[0000, 0]@112..113#ROOT2024
533+
SUBTREE {} 0:Root[0000, 0]@114..115#ROOT2024 0:Root[0000, 0]@198..199#ROOT2024
534+
IDENT pub 0:Root[0000, 0]@124..127#ROOT2024
535+
IDENT fn 0:Root[0000, 0]@128..130#ROOT2024
536+
IDENT new 0:Root[0000, 0]@131..134#ROOT2024
537+
SUBTREE () 0:Root[0000, 0]@134..135#ROOT2024 0:Root[0000, 0]@145..146#ROOT2024
538+
IDENT value 0:Root[0000, 0]@135..140#ROOT2024
539+
PUNCH : [alone] 0:Root[0000, 0]@140..141#ROOT2024
540+
IDENT i16 0:Root[0000, 0]@142..145#ROOT2024
541+
PUNCH - [joint] 0:Root[0000, 0]@147..148#ROOT2024
542+
PUNCH > [alone] 0:Root[0000, 0]@148..149#ROOT2024
543+
IDENT Self 0:Root[0000, 0]@150..154#ROOT2024
544+
SUBTREE {} 0:Root[0000, 0]@155..156#ROOT2024 0:Root[0000, 0]@192..193#ROOT2024
545+
IDENT Self 0:Root[0000, 0]@169..173#ROOT2024
546+
SUBTREE {} 0:Root[0000, 0]@174..175#ROOT2024 0:Root[0000, 0]@182..183#ROOT2024
547+
IDENT value 0:Root[0000, 0]@176..181#ROOT2024
548+
IDENT Foo 0:Root[0000, 0]@209..212#ROOT2024
549+
PUNCH : [joint] 0:Root[0000, 0]@212..213#ROOT2024
550+
PUNCH : [joint] 0:Root[0000, 0]@213..214#ROOT2024
551+
PUNCH < [joint] 0:Root[0000, 0]@214..215#ROOT2024
552+
PUNCH - [alone] 1:Root[0000, 0]@0..1#ROOT2024
553+
LITERAL Integer 1 1:Root[0000, 0]@1..2#ROOT2024
554+
PUNCH > [joint] 0:Root[0000, 0]@219..220#ROOT2024
555+
PUNCH : [joint] 0:Root[0000, 0]@220..221#ROOT2024
556+
PUNCH : [alone] 0:Root[0000, 0]@221..222#ROOT2024
557+
IDENT new 0:Root[0000, 0]@222..225#ROOT2024
558+
SUBTREE () 0:Root[0000, 0]@225..226#ROOT2024 0:Root[0000, 0]@230..231#ROOT2024
559+
PUNCH - [alone] 1:Root[0000, 0]@0..1#ROOT2024
560+
LITERAL Integer 1 1:Root[0000, 0]@1..2#ROOT2024
561+
562+
struct Foo<const I:i16>{
563+
pub value:i16,
564+
}
565+
impl <const I:i16>Foo<I>{
566+
pub fn new(value:i16) -> Self {
567+
Self {
568+
value
569+
}
570+
}
571+
572+
}
573+
Foo::<-1>::new(-1)"#]],
574+
);
575+
}

0 commit comments

Comments
 (0)