selfhost: add @[Drop] attribute for user-defined structs

- ast.bux: add isDrop field to Decl
- parser.bux: parse @[Drop] attribute and attach to struct Decls
- hir_lower.bux: auto-drop now looks for TypeName_Drop for any type
- Test: _test_drop_user verifies Buffer_Drop is auto-called
This commit is contained in:
2026-06-10 13:32:40 +03:00
parent d6f0a30948
commit 0a41ce85f4
3 changed files with 17 additions and 2 deletions
+1
View File
@@ -274,6 +274,7 @@ struct Decl {
isPublic: bool, isPublic: bool,
isAsync: bool, isAsync: bool,
isChecked: int, // @[Checked] attribute (0/1) isChecked: int, // @[Checked] attribute (0/1)
isDrop: int, // @[Drop] attribute (0/1)
// Names // Names
strValue: String, // decl name strValue: String, // decl name
strValue2: String, // interface name, dll name, module path strValue2: String, // interface name, dll name, module path
+6
View File
@@ -2164,6 +2164,12 @@ func Lcx_BuildAutoDropFree(ctx: *LowerCtx, typeName: String) -> String {
return String_Concat(String_Concat("Map_Drop_", kType), String_Concat("_", vType)); return String_Concat(String_Concat("Map_Drop_", kType), String_Concat("_", vType));
} }
} }
// User-defined types with @[Drop]: look for TypeName_Drop function
let dropName: String = String_Concat(typeName, "_Drop");
let dropSym: Symbol = Scope_Lookup(ctx.scope, dropName);
if dropSym.decl != null as *Decl {
return dropName;
}
return ""; return "";
} }
+10 -2
View File
@@ -1570,8 +1570,9 @@ func parserParseDecl(p: *Parser) -> *Decl {
} }
let isPublic: bool = parserMatch(p, tkPub); let isPublic: bool = parserMatch(p, tkPub);
// Parse @[Checked] attribute // Parse @[Checked] / @[Drop] attribute
var isChecked: int = 0; var isChecked: int = 0;
var isDrop: int = 0;
if parserCheck(p, tkAt) { if parserCheck(p, tkAt) {
discard parserAdvance(p); // @ discard parserAdvance(p); // @
if parserCheck(p, tkLBracket) { if parserCheck(p, tkLBracket) {
@@ -1581,6 +1582,9 @@ func parserParseDecl(p: *Parser) -> *Decl {
if String_Eq(attrName.text, "Checked") { if String_Eq(attrName.text, "Checked") {
isChecked = 1; isChecked = 1;
} }
if String_Eq(attrName.text, "Drop") {
isDrop = 1;
}
discard parserAdvance(p); // attribute name discard parserAdvance(p); // attribute name
} }
if parserCheck(p, tkRBracket) { if parserCheck(p, tkRBracket) {
@@ -1606,7 +1610,11 @@ func parserParseDecl(p: *Parser) -> *Decl {
d.isChecked = isChecked; d.isChecked = isChecked;
return d; return d;
} }
if kind == tkStruct { return parserParseStructDecl(p, isPublic); } if kind == tkStruct {
let d: *Decl = parserParseStructDecl(p, isPublic);
d.isDrop = isDrop;
return d;
}
if kind == tkEnum { return parserParseEnumDecl(p, isPublic); } if kind == tkEnum { return parserParseEnumDecl(p, isPublic); }
if kind == tkImport { return parserParseImportDecl(p, isPublic); } if kind == tkImport { return parserParseImportDecl(p, isPublic); }
if kind == tkExtern { return parserParseExternDecl(p, isPublic); } if kind == tkExtern { return parserParseExternDecl(p, isPublic); }