11use crate :: util:: { err_span, vir_err_span_str} ;
2- use rustc_ast:: token:: { Token , TokenKind } ;
2+ use rustc_ast:: token:: { LitKind , TokenKind } ;
33use rustc_ast:: tokenstream:: { TokenStream , TokenTree } ;
44use rustc_hir:: { AttrArgs , Attribute } ;
55use rustc_span:: Span ;
66use vir:: ast:: { AcceptRecursiveType , Mode , TriggerAnnotation , VirErr , VirErrAs } ;
77
8+ /// The syntax tree of an attribute.
9+ ///
10+ /// For example, `#[trigger(42)]` would be encoded as follows:
11+ /// `Fun(span, "trigger", [Lit(LitKind::Integer, "42")])`
812#[ derive( Debug ) ]
9- pub ( crate ) enum AttrTree {
13+ enum AttrTree {
14+ /// Similar to a function call, e.g. `trigger(42)`
1015 Fun ( Span , String , Option < Box < [ AttrTree ] > > ) ,
16+ /// A literal, e.g. `42`, `42.0`, `"forty-two"`, etc.
17+ Lit ( LitKind , String ) ,
1118 //Eq(Span, String, String), // TODO(main_new)
1219}
1320
14- pub ( crate ) fn token_to_string ( token : & Token ) -> Result < Option < String > , ( ) > {
15- match token. kind {
16- TokenKind :: Literal ( lit) => Ok ( Some ( lit. symbol . as_str ( ) . to_string ( ) ) ) ,
17- TokenKind :: Ident ( symbol, _) => Ok ( Some ( symbol. as_str ( ) . to_string ( ) ) ) ,
18- TokenKind :: Comma => Ok ( None ) ,
19- _ => Err ( ( ) ) ,
20- }
21- }
22-
23- pub ( crate ) fn token_stream_to_trees (
24- span : Span ,
25- stream : & TokenStream ,
26- ) -> Result < Box < [ AttrTree ] > , ( ) > {
21+ fn token_stream_to_trees ( span : Span , stream : & TokenStream ) -> Result < Box < [ AttrTree ] > , ( ) > {
2722 let mut token_trees: Vec < & TokenTree > = Vec :: new ( ) ;
2823 for x in stream. iter ( ) {
2924 // TODO(1.83) trees?
@@ -32,25 +27,30 @@ pub(crate) fn token_stream_to_trees(
3227 let mut i = 0 ;
3328 let mut trees: Vec < AttrTree > = Vec :: new ( ) ;
3429 while i < token_trees. len ( ) {
35- match & token_trees[ i] {
36- TokenTree :: Token ( token, _spacing) => {
37- if let Some ( name) = token_to_string ( token) ? {
38- let fargs = if i + 1 < token_trees. len ( ) {
39- if let TokenTree :: Delimited ( _, _, _, token_stream) = & token_trees[ i + 1 ] {
40- i += 1 ;
41- Some ( token_stream_to_trees ( span, token_stream) ?)
42- } else {
43- None
44- }
45- } else {
46- None
47- } ;
48- trees. push ( AttrTree :: Fun ( span, name, fargs) ) ;
49- }
50- i += 1 ;
30+ let TokenTree :: Token ( token, _spacing) = & token_trees[ i] else {
31+ return Err ( ( ) ) ;
32+ } ;
33+ match token. kind {
34+ TokenKind :: Literal ( lit) => {
35+ let text = lit. symbol . as_str ( ) . to_string ( ) ;
36+ trees. push ( AttrTree :: Lit ( lit. kind , text) ) ;
37+ }
38+ TokenKind :: Ident ( symbol, _) => {
39+ let name = symbol. as_str ( ) . to_string ( ) ;
40+ let fargs = if let Some ( TokenTree :: Delimited ( _, _, _, token_stream) ) =
41+ & token_trees. get ( i + 1 )
42+ {
43+ i += 1 ;
44+ Some ( token_stream_to_trees ( span, token_stream) ?)
45+ } else {
46+ None
47+ } ;
48+ trees. push ( AttrTree :: Fun ( span, name, fargs) ) ;
5149 }
50+ TokenKind :: Comma => { }
5251 _ => return Err ( ( ) ) ,
5352 }
53+ i += 1 ;
5454 }
5555 Ok ( trees. into_boxed_slice ( ) )
5656}
@@ -260,6 +260,8 @@ pub(crate) enum Attr {
260260 AllowInSpec ,
261261 // specify list of places where == is promoted to =~=
262262 AutoExtEqual ( vir:: ast:: AutoExtEqual ) ,
263+ /// Label for a proof obligation, i.e. the attribute `#[verifier::proof_note("label")]`
264+ ProofNote ( String ) ,
263265 // add manual trigger to expression inside quantifier
264266 Trigger ( Option < Vec < u64 > > ) ,
265267 // custom error string to report for precondition failures
@@ -357,7 +359,27 @@ pub(crate) enum Attr {
357359fn get_trigger_arg ( span : Span , attr_tree : & AttrTree ) -> Result < u64 , VirErr > {
358360 let err_fn = || err_span ( span, format ! ( "expected integer constant, found {:?}" , & attr_tree) ) ;
359361 match attr_tree {
360- AttrTree :: Fun ( _, name, None ) => name. parse :: < u64 > ( ) . or_else ( |_e| err_fn ( ) ) ,
362+ AttrTree :: Lit ( LitKind :: Integer , digits) => digits. parse :: < u64 > ( ) . or_else ( |_e| err_fn ( ) ) ,
363+ _ => err_fn ( ) ,
364+ }
365+ }
366+
367+ /// Get the `"label"` part out of an attribute like `#[verifier::proof_note("label")]`
368+ fn get_proof_note_label ( span : Span , attrs : & Option < Box < [ AttrTree ] > > ) -> Result < & String , VirErr > {
369+ let Some ( [ AttrTree :: Lit ( LitKind :: Str , label) ] ) = attrs. as_deref ( ) else {
370+ return err_span ( span, "expected exactly one argument, a string literal" ) ;
371+ } ;
372+ Ok ( label)
373+ }
374+
375+ /// Get the `42` part out of an attribute like `#[rlimit(42)]`
376+ fn get_rlimit_arg ( span : Span , attrs : & Option < Box < [ AttrTree ] > > ) -> Result < f32 , VirErr > {
377+ let err_fn = || err_span ( span, "expected number, or `infinity` for rlimit" ) ;
378+ match attrs. as_deref ( ) {
379+ Some ( [ AttrTree :: Lit ( LitKind :: Float | LitKind :: Integer , text) ] ) => {
380+ text. parse :: < f32 > ( ) . or_else ( |_| err_fn ( ) )
381+ }
382+ Some ( [ AttrTree :: Fun ( _, text, None ) ] ) if text == "infinity" => Ok ( f32:: INFINITY ) ,
361383 _ => err_fn ( ) ,
362384 }
363385}
@@ -389,6 +411,10 @@ pub(crate) fn parse_attrs(
389411 }
390412 AttrTree :: Fun ( _, name, None ) if name == "proof" => v. push ( Attr :: Mode ( Mode :: Proof ) ) ,
391413 AttrTree :: Fun ( _, name, None ) if name == "exec" => v. push ( Attr :: Mode ( Mode :: Exec ) ) ,
414+ AttrTree :: Fun ( span, name, attrs) if name == "proof_note" => {
415+ let label = get_proof_note_label ( * span, attrs) ?;
416+ v. push ( Attr :: ProofNote ( label. clone ( ) ) )
417+ }
392418 AttrTree :: Fun ( _, name, None ) if name == "trigger" => v. push ( Attr :: Trigger ( None ) ) ,
393419 AttrTree :: Fun ( span, name, Some ( args) ) if name == "trigger" => {
394420 let mut groups: Vec < u64 > = Vec :: new ( ) ;
@@ -487,12 +513,12 @@ pub(crate) fn parse_attrs(
487513 AttrTree :: Fun ( _, arg, None ) if arg == "invariant_block" => {
488514 v. push ( Attr :: InvariantBlock )
489515 }
490- AttrTree :: Fun ( _, arg, Some ( box [ AttrTree :: Fun ( _ , msg, None ) ] ) )
516+ AttrTree :: Fun ( _, arg, Some ( box [ AttrTree :: Lit ( LitKind :: Str , msg) ] ) )
491517 if arg == "custom_req_err" =>
492518 {
493519 v. push ( Attr :: CustomReqErr ( msg. clone ( ) ) )
494520 }
495- AttrTree :: Fun ( _, arg, Some ( box [ AttrTree :: Fun ( _ , msg, None ) ] ) )
521+ AttrTree :: Fun ( _, arg, Some ( box [ AttrTree :: Lit ( LitKind :: Str , msg) ] ) )
496522 if arg == "custom_err" =>
497523 {
498524 v. push ( Attr :: CustomErr ( msg. clone ( ) ) )
@@ -587,17 +613,9 @@ pub(crate) fn parse_attrs(
587613 v. push ( Attr :: AutoExtEqual ( auto_ext_equal) )
588614 }
589615 AttrTree :: Fun ( _, arg, None ) if arg == "memoize" => v. push ( Attr :: Memoize ) ,
590- AttrTree :: Fun ( span, name, Some ( box [ AttrTree :: Fun ( _, r, None ) ] ) )
591- if name == "rlimit" =>
592- {
593- let Some ( rlimit) = r
594- . parse :: < f32 > ( )
595- . ok ( )
596- . or_else ( || if r == "infinity" { Some ( f32:: INFINITY ) } else { None } )
597- else {
598- return err_span ( * span, "expected number, or `infinity` for rlimit" ) ;
599- } ;
600- v. push ( Attr :: RLimit ( rlimit) ) ;
616+ AttrTree :: Fun ( span, name, attrs) if name == "rlimit" => {
617+ let number = get_rlimit_arg ( * span, attrs) ?;
618+ v. push ( Attr :: RLimit ( number) ) ;
601619 }
602620 AttrTree :: Fun ( _, arg, None ) if arg == "truncate" => v. push ( Attr :: Truncate ) ,
603621 AttrTree :: Fun ( _, arg, None ) if arg == "external_fn_specification" => {
@@ -815,8 +833,9 @@ pub(crate) fn parse_attrs(
815833 } ,
816834 } ,
817835 AttrPrefix :: Rustc => {
818- let AttrTree :: Fun ( span, name, _) = & attr;
819- v. push ( Attr :: UnsupportedRustcAttr ( name. clone ( ) , * span) ) ;
836+ if let AttrTree :: Fun ( span, name, _) = & attr {
837+ v. push ( Attr :: UnsupportedRustcAttr ( name. clone ( ) , * span) ) ;
838+ }
820839 }
821840 }
822841 }
@@ -1306,6 +1325,9 @@ pub(crate) fn get_verifier_attrs_maybe_check(
13061325 Attr :: Memoize => vs. memoize = true ,
13071326 Attr :: RLimit ( rlimit) => vs. rlimit = Some ( rlimit) ,
13081327 Attr :: Truncate => vs. truncate = true ,
1328+ Attr :: ProofNote ( _) => {
1329+ // TODO: https://github.com/verus-lang/verus/issues/2152
1330+ }
13091331 Attr :: UnwrappedBinding => vs. unwrapped_binding = true ,
13101332 Attr :: Mode ( _) => vs. sets_mode = true ,
13111333 Attr :: InternalRevealFn => vs. internal_reveal_fn = true ,
0 commit comments