diff --git a/compiler/noirc_frontend/src/ast/structure.rs b/compiler/noirc_frontend/src/ast/structure.rs index 5db08c87677..8c8fe6e6387 100644 --- a/compiler/noirc_frontend/src/ast/structure.rs +++ b/compiler/noirc_frontend/src/ast/structure.rs @@ -19,6 +19,12 @@ pub struct NoirStruct { pub span: Span, } +impl NoirStruct { + pub fn is_abi(&self) -> bool { + self.attributes.iter().any(|attr| attr.is_abi()) + } +} + #[derive(Clone, Debug, PartialEq, Eq)] pub struct StructField { pub visibility: ItemVisibility, diff --git a/compiler/noirc_frontend/src/elaborator/mod.rs b/compiler/noirc_frontend/src/elaborator/mod.rs index fd548e394dc..a9173621fc7 100644 --- a/compiler/noirc_frontend/src/elaborator/mod.rs +++ b/compiler/noirc_frontend/src/elaborator/mod.rs @@ -751,7 +751,7 @@ impl<'context> Elaborator<'context> { ); if is_entry_point { - self.mark_parameter_type_as_used(&typ); + self.mark_type_as_used(&typ); } let pattern = self.elaborate_pattern_and_store_ids( @@ -832,33 +832,33 @@ impl<'context> Elaborator<'context> { self.current_item = None; } - fn mark_parameter_type_as_used(&mut self, typ: &Type) { + fn mark_type_as_used(&mut self, typ: &Type) { match typ { - Type::Array(_n, typ) => self.mark_parameter_type_as_used(typ), - Type::Slice(typ) => self.mark_parameter_type_as_used(typ), + Type::Array(_n, typ) => self.mark_type_as_used(typ), + Type::Slice(typ) => self.mark_type_as_used(typ), Type::Tuple(types) => { for typ in types { - self.mark_parameter_type_as_used(typ); + self.mark_type_as_used(typ); } } Type::Struct(struct_type, generics) => { self.mark_struct_as_constructed(struct_type.clone()); for generic in generics { - self.mark_parameter_type_as_used(generic); + self.mark_type_as_used(generic); } for (_, typ) in struct_type.borrow().get_fields(generics) { - self.mark_parameter_type_as_used(&typ); + self.mark_type_as_used(&typ); } } Type::Alias(alias_type, generics) => { - self.mark_parameter_type_as_used(&alias_type.borrow().get_type(generics)); + self.mark_type_as_used(&alias_type.borrow().get_type(generics)); } Type::MutableReference(typ) => { - self.mark_parameter_type_as_used(typ); + self.mark_type_as_used(typ); } Type::InfixExpr(left, _op, right) => { - self.mark_parameter_type_as_used(left); - self.mark_parameter_type_as_used(right); + self.mark_type_as_used(left); + self.mark_type_as_used(right); } Type::FieldElement | Type::Integer(..) @@ -1277,6 +1277,13 @@ impl<'context> Elaborator<'context> { self.local_module = typ.module_id; let fields = self.resolve_struct_fields(&typ.struct_def, *type_id); + + if typ.struct_def.is_abi() { + for field in &fields { + self.mark_type_as_used(&field.typ); + } + } + let fields_len = fields.len(); self.interner.update_struct(*type_id, |struct_def| { struct_def.set_fields(fields); diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs index ba1075dfb30..65912023661 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs @@ -1013,12 +1013,14 @@ pub fn collect_struct( let parent_module_id = ModuleId { krate, local_id: module_id }; - interner.usage_tracker.add_unused_item( - parent_module_id, - name.clone(), - UnusedItem::Struct(id), - visibility, - ); + if !unresolved.struct_def.is_abi() { + interner.usage_tracker.add_unused_item( + parent_module_id, + name.clone(), + UnusedItem::Struct(id), + visibility, + ); + } if let Err((first_def, second_def)) = result { let error = DefCollectorErrorKind::Duplicate { diff --git a/compiler/noirc_frontend/src/lexer/token.rs b/compiler/noirc_frontend/src/lexer/token.rs index c4c31a2dd8a..4037135a889 100644 --- a/compiler/noirc_frontend/src/lexer/token.rs +++ b/compiler/noirc_frontend/src/lexer/token.rs @@ -995,6 +995,10 @@ impl SecondaryAttribute { _ => false, } } + + pub(crate) fn is_abi(&self) -> bool { + matches!(self, SecondaryAttribute::Abi(_)) + } } impl fmt::Display for SecondaryAttribute { diff --git a/compiler/noirc_frontend/src/tests/unused_items.rs b/compiler/noirc_frontend/src/tests/unused_items.rs index 80b6c7db09a..c89670a9043 100644 --- a/compiler/noirc_frontend/src/tests/unused_items.rs +++ b/compiler/noirc_frontend/src/tests/unused_items.rs @@ -231,3 +231,33 @@ fn no_warning_on_inner_struct_when_parent_is_used() { let errors = get_program_errors(src); assert_eq!(errors.len(), 0); } + +#[test] +fn no_warning_on_struct_if_it_has_an_abi_attribute() { + let src = r#" + #[abi(functions)] + struct Foo { + a: Field, + } + + fn main() {} + "#; + assert_no_errors(src); +} + +#[test] +fn no_warning_on_indirect_struct_if_it_has_an_abi_attribute() { + let src = r#" + struct Bar { + field: Field, + } + + #[abi(functions)] + struct Foo { + bar: Bar, + } + + fn main() {} + "#; + assert_no_errors(src); +}