From f7b42b2c26481734a4214aac856b33a942c93c23 Mon Sep 17 00:00:00 2001 From: Miquel Sabaté Solà Date: Tue, 28 Apr 2026 16:06:33 +0200 Subject: Send an error for unused .proc's MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We cannot safely detect all scenarios in which there is dead code, but we can safely do it for .proc's. Even if they are not called directly, they might be referenced via jump tables and shenanigans like that. Long story short, if you are not referencing a .proc in any meaningful way, then we have dead code. A pattern could also be given in which a function that was too long has been splitted into smaller functions which are not called directly. This is, in my opinion, an anti-pattern (as we generally expect an rts or a jmp from .proc's), and anyways can be avoided via the use of __fallthrough__ if the programmer is really set to write this kind of code. Signed-off-by: Miquel Sabaté Solà --- lib/xixanta/src/object.rs | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) (limited to 'lib/xixanta/src/object.rs') diff --git a/lib/xixanta/src/object.rs b/lib/xixanta/src/object.rs index cd1db1f..a05c315 100644 --- a/lib/xixanta/src/object.rs +++ b/lib/xixanta/src/object.rs @@ -118,10 +118,22 @@ impl Bundle { #[derive(Debug, Clone)] pub enum ObjectType { Address, + Proc, Value, Argument, } +impl std::fmt::Display for ObjectType { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + ObjectType::Address => write!(f, "raw address"), + ObjectType::Proc => write!(f, "proc"), + ObjectType::Value => write!(f, "variable"), + ObjectType::Argument => write!(f, "macro argument"), + } + } +} + /// Bundle and metadata which is stored on the context table for a given /// variable or label. #[derive(Debug, Clone)] @@ -214,7 +226,7 @@ impl Context { /// Returns the value of the object represented by the given `id`. Note that /// this `id` can be scoped or not, and this function will try to pick the /// variable from the right scope. The value itself will be resolved if the - /// type is ObjectType::Address. + /// type is ObjectType::Address or ObjectType::Proc. pub fn get_variable(&mut self, id: &PString, mappings: &[Mapping]) -> Result { // First of all, figure out the name of the scope and the real name of // the variable. If this was not scoped at all (None case when trying to @@ -242,14 +254,24 @@ impl Context { match self.map.get_mut(scope_name) { Some(scope) => match scope.get_mut(var_name) { Some(var) => match var.object_type { + // If it's a value or an argument, then we just account for + // the number of times it was accessed and return it as is. ObjectType::Value | ObjectType::Argument => { var.accessed += 1; Ok(var.clone()) } + // If it's a raw address, then we return the resolved value. ObjectType::Address => { let var_to_resolve = var.clone(); Ok(self.resolve_label(mappings, &var_to_resolve)?) } + // If it's a .proc, then we account for the number of times + // it was accessed, and we return the resolved value. + ObjectType::Proc => { + var.accessed += 1; + let var_to_resolve = var.clone(); + Ok(self.resolve_label(mappings, &var_to_resolve)?) + } }, None => { // If it cannot be found, then we have to move up through @@ -290,9 +312,13 @@ impl Context { /// address. /// /// NOTE: this function asserts that the given `object` is of type - /// ObjectType::Address, otherwise it doesn't make sense to call it. + /// ObjectType::Address or ObjectType::Proc, otherwise it doesn't make sense + /// to call it. pub fn resolve_label(&self, mappings: &[Mapping], object: &Object) -> Result { - assert!(matches!(object.object_type, ObjectType::Address)); + assert!(matches!( + object.object_type, + ObjectType::Address | ObjectType::Proc + )); let mut ret = object.clone(); -- cgit v1.2.3