aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/xixanta/src/assembler.rs87
-rw-r--r--lib/xixanta/src/object.rs8
-rwxr-xr-xscripts/test-e2e.sh2
-rw-r--r--tests/expected/unused-warning.txt4
-rw-r--r--tests/expected/unused_macro_arg.txt1
-rw-r--r--tests/unused_macro_arg.s4
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