@@ -161,10 +161,8 @@ pub(crate) enum AddressUse {
161161impl AddressUse {
162162 fn or ( & self , other : & AddressUse ) -> AddressUse {
163163 match ( self , other) {
164- ( AddressUse :: IncludesAddress , _) | ( _, AddressUse :: IncludesAddress ) => {
165- AddressUse :: IncludesAddress
166- }
167- _ => AddressUse :: NotAddress ,
164+ ( AddressUse :: NotAddress , AddressUse :: NotAddress ) => AddressUse :: NotAddress ,
165+ _ => AddressUse :: IncludesAddress ,
168166 }
169167 }
170168}
@@ -249,7 +247,9 @@ impl SymbolContext {
249247 pub ( crate ) fn origin ( block_id : BlockIdentifier , origin : Origin ) -> SymbolContext {
250248 let span = origin. span ( ) ;
251249 SymbolContext {
252- address : AddressUse :: NotAddress ,
250+ // All origins are (implicitly) uses of the symbol as an
251+ // address.
252+ address : AddressUse :: IncludesAddress ,
253253 origin : OriginUse :: IncludesOrigin ( block_id, origin) ,
254254 uses : SymbolContext :: uses ( span) ,
255255 }
@@ -301,7 +301,7 @@ impl SymbolContext {
301301 OriginUse :: IncludesOrigin ( my_block, my_origin) ,
302302 OriginUse :: IncludesOrigin ( their_block, their_origin) ,
303303 ) => {
304- if my_block == their_block && my_origin . has_same_specification ( their_origin ) {
304+ if my_block == their_block {
305305 // If one of the origins is a deduced origin, that
306306 // has more information, so retain that one.
307307 //
@@ -366,7 +366,24 @@ impl SymbolContext {
366366 }
367367
368368 pub ( super ) fn requires_rc_word_allocation ( & self ) -> bool {
369- self . address == AddressUse :: IncludesAddress
369+ if self . address == AddressUse :: IncludesAddress {
370+ if matches ! ( & self . origin, & OriginUse :: IncludesOrigin ( _, _) ) {
371+ // This symbol is used in address contexts, but it is
372+ // the name used for an origin. Therefore we do not
373+ // need to allocate an RC-word for it.
374+ false
375+ } else {
376+ // This name is used in an address context but it is
377+ // not the name of an origin, so when there is no tag
378+ // definition for it, we will need to allocate an
379+ // RC-word for it.
380+ true
381+ }
382+ } else {
383+ // Since nothing expects this symbol to refer to an
384+ // address, there is no need to allocate an RC-word.
385+ false
386+ }
370387 }
371388
372389 pub ( super ) fn any_span ( & self ) -> & Span {
@@ -511,17 +528,103 @@ fn test_origin_cannot_be_used_as_a_configuration_value() {
511528
512529#[ test]
513530fn test_deduced_origin_merge ( ) {
514- use super :: span:: span;
515- use base:: prelude:: Address ;
516- use base:: u18;
517- let span = span ( 0 ..4 ) ;
518- let block = BlockIdentifier :: from ( 0 ) ;
519- let name = SymbolName :: from ( "OGN" ) ;
520- let address = Address :: from ( u18 ! ( 0o200_000 ) ) ;
521- let mut current = SymbolContext :: origin ( block, Origin :: Symbolic ( span, name. clone ( ) ) ) ;
522- let new_use = SymbolContext :: origin ( block, Origin :: Deduced ( span, name. clone ( ) , address) ) ;
523- assert_eq ! ( current. merge( & name, new_use. clone( ) ) , Ok ( ( ) ) ) ;
524- assert_eq ! ( current, new_use) ;
531+ struct Contexts {
532+ reference : SymbolContext ,
533+ origin_definition : SymbolContext ,
534+ expected_merge : SymbolContext ,
535+ }
536+ // Convenience function for creating the test input and expected output.
537+ fn make_symbolic_and_deduced_origin_contexts (
538+ name : SymbolName ,
539+ is_forward_reference : bool ,
540+ ) -> Contexts {
541+ let block = BlockIdentifier :: from ( 0 ) ;
542+
543+ let deduced_origin_span: Span = span ( 1000 ..1010 ) ;
544+ let symbol_span = if is_forward_reference {
545+ // The reference appears before the origin specification
546+ span ( 10 ..20 )
547+ } else {
548+ // The reference appears after the origin specification
549+ span ( 2000 ..2020 )
550+ } ;
551+
552+ // In our examples, the deduced origin value is a
553+ // symbolically-defined origin to which we would deduced
554+ // address (from the locations and sizes of the blocks
555+ // preceding it).
556+ let deduced_origin_context = SymbolContext {
557+ address : AddressUse :: IncludesAddress ,
558+ origin : OriginUse :: IncludesOrigin (
559+ block,
560+ Origin :: Symbolic ( deduced_origin_span, name. clone ( ) ) ,
561+ ) ,
562+ uses : SymbolContext :: uses ( deduced_origin_span) ,
563+ } ;
564+
565+ // The symbolic context is is simply a reference to the
566+ // origin, either preceding (is_forward_reference) or
567+ // following (!is_forward_reference) the definition of the
568+ // origin.
569+ let reference_context = SymbolContext {
570+ address : AddressUse :: IncludesAddress ,
571+ // Although this use of the symbol will turn out to be a
572+ // reference to an origin, we cannot tell that at the
573+ // reference site, and so the context in which this symbol
574+ // is used at that point is not an origin context.
575+ origin : OriginUse :: NotOrigin {
576+ config : ConfigUse :: NotConfig ,
577+ index : IndexUse :: NotIndex ,
578+ } ,
579+ uses : SymbolContext :: uses ( symbol_span) ,
580+ } ;
581+
582+ Contexts {
583+ reference : reference_context,
584+ origin_definition : deduced_origin_context,
585+ expected_merge : SymbolContext {
586+ address : AddressUse :: IncludesAddress ,
587+ origin : OriginUse :: IncludesOrigin (
588+ BlockIdentifier :: from ( 0 ) ,
589+ Origin :: Symbolic ( deduced_origin_span, name. clone ( ) ) ,
590+ ) ,
591+ uses : [
592+ OrderableSpan ( deduced_origin_span) ,
593+ OrderableSpan ( symbol_span) ,
594+ ]
595+ . into_iter ( )
596+ . collect ( ) ,
597+ } ,
598+ }
599+ }
600+ let name = SymbolName :: from ( "OGNX" ) ;
601+ // Set up contexts for the forward-reference and the backward-reference cases.
602+ let contexts_backward_ref = make_symbolic_and_deduced_origin_contexts ( name. clone ( ) , false ) ;
603+ let contexts_forward_ref = make_symbolic_and_deduced_origin_contexts ( name. clone ( ) , true ) ;
604+ // The value in expected_merge is not the same in each case, since
605+ // although the span of the origin definition is fixed, the span
606+ // of the reference to it is different for the forward-reference
607+ // and backward-reference cases.
608+
609+ // Merge for the defined-then-used direction (where we encouter
610+ // the origin defintiion and later a reference to it).
611+ let mut current = contexts_backward_ref. origin_definition . clone ( ) ;
612+ assert_eq ! (
613+ current. merge( & name, contexts_backward_ref. reference. clone( ) ) ,
614+ Ok ( ( ) )
615+ ) ;
616+ assert_eq ! ( current, contexts_backward_ref. expected_merge) ;
617+
618+ // Merge in forward-reference direction (where we find a reference
619+ // to the origin address of a block before we have seen the origin
620+ // definition of that block).
621+ //
622+ let mut current = contexts_forward_ref. reference . clone ( ) ; // we find the fwd ref first
623+ assert_eq ! (
624+ current. merge( & name, contexts_forward_ref. origin_definition. clone( ) ) ,
625+ Ok ( ( ) )
626+ ) ;
627+ assert_eq ! ( current, contexts_forward_ref. expected_merge) ;
525628}
526629
527630impl From < ( & Script , Span ) > for SymbolContext {
0 commit comments