diff options
| -rw-r--r-- | lib/xixanta/src/assembler.rs | 87 | ||||
| -rw-r--r-- | lib/xixanta/src/object.rs | 8 | ||||
| -rwxr-xr-x | scripts/test-e2e.sh | 2 | ||||
| -rw-r--r-- | tests/expected/unused-warning.txt | 4 | ||||
| -rw-r--r-- | tests/expected/unused_macro_arg.txt | 1 | ||||
| -rw-r--r-- | tests/unused_macro_arg.s | 4 |
6 files changed, 69 insertions, 37 deletions
diff --git a/lib/xixanta/src/assembler.rs b/lib/xixanta/src/assembler.rs index bc74d9e..dac298a 100644 --- a/lib/xixanta/src/assembler.rs +++ b/lib/xixanta/src/assembler.rs @@ -1221,30 +1221,60 @@ impl<'a> Assembler<'a> { // If this was a .proc definition then we are certain that // this is dead code, which is a really crappy situation. - if matches!(bundle.object_type, ObjectType::Proc) { - errors.push(Error { - line: 0, - message: format!("proc '{full_name}' is unused"), - source, - expanded_from: self.macro_context.clone(), - global: true, - }); - } else { - let (line, global) = match &bundle.node { - Some(n) => (n.value.line, false), - None => (0, true), - }; + // Otherwise, we cannot exactly pin down whether this is + // harmless or not. Hence, just issue a warning and let the + // programmer decide on this. + match &bundle.object_type { + ObjectType::Proc => { + errors.push(Error { + line: 0, + message: format!("proc '{full_name}' is unused"), + source, + expanded_from: self.macro_context.clone(), + global: true, + }); + } + ObjectType::Argument(macro_name) => match self.macros.get(macro_name) { + Some(mcr) => { + let macro_definition = &mcr.left.as_ref().unwrap().value; + self.warnings.push(Error { + line: macro_definition.line, + message: format!( + "argument '{name}' of the macro '{}' is unused", + macro_definition.value + ), + source, + expanded_from: self.macro_context.clone(), + global: false, + }); + } + None => { + self.warnings.push(Error { + line: 0, + message: format!( + "{} '{full_name}' is unused", + bundle.object_type + ), + source, + expanded_from: self.macro_context.clone(), + global: true, + }); + } + }, + _ => { + let (line, global) = match &bundle.node { + Some(n) => (n.value.line, false), + None => (0, true), + }; - // Otherwise, we cannot exactly pin down whether this is - // harmless or not. Hence, just issue a warning and let - // the programmer decide on this. - self.warnings.push(Error { - line, - message: format!("{} '{full_name}' is unused", bundle.object_type), - source, - expanded_from: self.macro_context.clone(), - global, - }); + self.warnings.push(Error { + line, + message: format!("{} '{full_name}' is unused", bundle.object_type), + source, + expanded_from: self.macro_context.clone(), + global, + }); + } } continue; } @@ -1463,7 +1493,8 @@ impl<'a> Assembler<'a> { // Consume a node which contains a macro call by pushing its bundles now. fn bundle_call(&mut self, node: &PNode) -> Result<(), Vec<Error>> { // Get the macro we are trying to reproduce. - let mcr = *self.macros.get(&node.value.value).ok_or(Error { + let macro_name = &node.value.value; + let mcr = *self.macros.get(macro_name).ok_or(Error { line: node.value.line, message: format!( "could not find a macro with the name '{}'", @@ -1517,7 +1548,7 @@ impl<'a> Assembler<'a> { node: Some(arg.clone()), mapping: self.current_mapping, segment: self.current_segment, - object_type: ObjectType::Argument, + object_type: ObjectType::Argument(macro_name.clone()), asan_ignore: false, asan_reserve: 1, accessed: 0, @@ -3240,7 +3271,7 @@ impl<'a> Assembler<'a> { if let Ok(var) = self.context.get_variable(&node.value, &self.mappings) { if matches!( var.object_type, - ObjectType::Address | ObjectType::Argument | ObjectType::Proc + ObjectType::Address | ObjectType::Argument(_) | ObjectType::Proc ) { return Ok(()); } @@ -3274,7 +3305,7 @@ impl<'a> Assembler<'a> { if let Ok(var) = self.context.get_variable(left_name, &self.mappings) { if matches!( var.object_type, - ObjectType::Address | ObjectType::Argument | ObjectType::Proc + ObjectType::Address | ObjectType::Argument(_) | ObjectType::Proc ) { return Ok(()); } @@ -3282,7 +3313,7 @@ impl<'a> Assembler<'a> { if let Ok(var) = self.context.get_variable(right_name, &self.mappings) { if matches!( var.object_type, - ObjectType::Address | ObjectType::Argument | ObjectType::Proc + ObjectType::Address | ObjectType::Argument(_) | ObjectType::Proc ) { return Ok(()); } diff --git a/lib/xixanta/src/object.rs b/lib/xixanta/src/object.rs index 08f94fd..64d4298 100644 --- a/lib/xixanta/src/object.rs +++ b/lib/xixanta/src/object.rs @@ -120,7 +120,7 @@ pub enum ObjectType { Address, Proc, Value, - Argument, + Argument(String), } impl std::fmt::Display for ObjectType { @@ -129,7 +129,7 @@ impl std::fmt::Display for ObjectType { ObjectType::Address => write!(f, "label"), ObjectType::Proc => write!(f, "proc"), ObjectType::Value => write!(f, "variable"), - ObjectType::Argument => write!(f, "macro argument"), + ObjectType::Argument(_) => write!(f, "macro argument"), } } } @@ -242,7 +242,7 @@ impl Context { 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 => { + ObjectType::Value | ObjectType::Argument(_) => { var.accessed += 1; Ok(var.clone()) } @@ -348,7 +348,7 @@ impl Context { // For macro arguments, we still want to preserve the // 'accessed' member, as arguments are re-created on each // use and this information might get lost in the process. - ObjectType::Argument => { + ObjectType::Argument(_) => { let before = sc.accessed; *sc = object.clone(); sc.accessed = before; diff --git a/scripts/test-e2e.sh b/scripts/test-e2e.sh index 9505274..071df71 100755 --- a/scripts/test-e2e.sh +++ b/scripts/test-e2e.sh @@ -120,7 +120,7 @@ diff tests/out/unused_definition.txt tests/expected/unused_definition.txt exit_code=$((exit_code + $?)) echo "test: custom => unused_macro_arg.nes" -./target/debug/nasm -c empty -Werror --asan tests/unused_macro_arg.s -o tests/out/unused_macro_arg.nes 2>tests/out/unused_macro_arg.txt +./target/debug/nasm -c empty --asan tests/unused_macro_arg.s -o tests/out/unused_macro_arg.nes 2>tests/out/unused_macro_arg.txt diff tests/out/unused_macro_arg.txt tests/expected/unused_macro_arg.txt exit_code=$((exit_code + $?)) diff tests/out/unused_macro_arg.nes tests/expected/unused_macro_arg.nes diff --git a/tests/expected/unused-warning.txt b/tests/expected/unused-warning.txt index 2917e2e..4d49cca 100644 --- a/tests/expected/unused-warning.txt +++ b/tests/expected/unused-warning.txt @@ -1,3 +1,3 @@ +warning: argument 'UNUSED_ARG' of the macro 'USED_MACRO' is unused (unused.s: line 12) warning: macro 'UNUSED_MACRO' is unused (unused.s) -warning: macro argument 'UNUSED_ARG' is unused (unused.s) -warning: variable 'zp_unused' is unused (unused.s) +warning: variable 'zp_unused' is unused (unused.s: line 24) diff --git a/tests/expected/unused_macro_arg.txt b/tests/expected/unused_macro_arg.txt index e69de29..7ca122a 100644 --- a/tests/expected/unused_macro_arg.txt +++ b/tests/expected/unused_macro_arg.txt @@ -0,0 +1 @@ +warning: argument 'OTHER' of the macro 'BCD_ADD' is unused (unused_macro_arg.s: line 11) diff --git a/tests/unused_macro_arg.s b/tests/unused_macro_arg.s index fe4d7f0..ef75a23 100644 --- a/tests/unused_macro_arg.s +++ b/tests/unused_macro_arg.s @@ -8,7 +8,7 @@ ;;; asan:stack full -.macro BCD_ADD ADDR +.macro BCD_ADD ADDR, OTHER adc ADDR bcc :+ nop @@ -16,7 +16,7 @@ .endmacro .proc add_to_player_y - BCD_ADD additions + BCD_ADD additions, 2 rts |
