restricted c header imports

This commit is contained in:
2026-06-14 14:42:38 +02:00
parent 4e860b033e
commit 638ca57f5c
24 changed files with 1377 additions and 45 deletions
+111 -5
View File
@@ -409,6 +409,62 @@ add_call_resolution_diagnostic :: proc(checker: ^Checker, expr: ast.Expr, target
return source.addf(checker.diagnostics, expr.span, "unresolved function '%s'", symbol_text(checker, expr.name))
}
find_unsupported :: proc(checker: ^Checker, pkg: ast.Package_Id, name: symbol.Id) -> (ast.Unsupported, bool) {
for item in checker.ast_module.unsupported {
if item.pkg == pkg && item.name == name {
return item, true
}
}
return {}, false
}
add_unsupported_diagnostic :: proc(checker: ^Checker, span: source.Span, pkg: ast.Package_Id, name: symbol.Id) -> source.Diagnostic_Id {
if item, ok := find_unsupported(checker, pkg, name); ok {
return source.addf(
checker.diagnostics,
span,
"C declaration '%s' is unavailable: %s",
symbol_text(checker, name),
item.reason,
)
}
return source.INVALID_DIAGNOSTIC
}
add_unsupported_type_diagnostic :: proc(
checker: ^Checker,
span: source.Span,
value: types.Type,
depth := 0,
) -> source.Diagnostic_Id {
if depth > 64 {
return source.INVALID_DIAGNOSTIC
}
item, ok := types.node(&checker.module.types, value)
if !ok {
return source.INVALID_DIAGNOSTIC
}
if item.kind == .Alias {
return add_unsupported_diagnostic(checker, span, ast.Package_Id(item.pkg), symbol.Id(item.name))
}
if types.is_valid(item.child) {
return add_unsupported_type_diagnostic(checker, span, item.child, depth+1)
}
return source.INVALID_DIAGNOSTIC
}
function_signatures_equal :: proc(left, right: ast.Function) -> bool {
if left.result != right.result || len(left.params) != len(right.params) {
return false
}
for param, index in left.params {
if param.type != right.params[index].type {
return false
}
}
return true
}
contains_name :: proc(names: []symbol.Id, name: symbol.Id) -> bool {
for existing in names {
if existing == name {
@@ -454,9 +510,17 @@ mark_expr_imports_used :: proc(checker: ^Checker, expr_id: ast.Expr_Id, file: as
validate_declarations :: proc(checker: ^Checker) {
for function, function_id in checker.ast_module.functions {
if len(function.unsupported_reason) > 0 {
continue
}
locals: [dynamic]symbol.Id
locals.allocator = checker.allocator
for param in function.params {
if diagnostic := add_unsupported_type_diagnostic(checker, param.span, type_from_syntax(param.type));
diagnostic != source.INVALID_DIAGNOSTIC {
checker.template_diagnostics[function_id] = diagnostic
continue
}
if param.type == types.VOID {
source.add(
checker.diagnostics,
@@ -482,6 +546,10 @@ validate_declarations :: proc(checker: ^Checker) {
)
}
}
if diagnostic := add_unsupported_type_diagnostic(checker, function.span, type_from_syntax(function.result));
diagnostic != source.INVALID_DIAGNOSTIC {
checker.template_diagnostics[function_id] = diagnostic
}
if types.contains_c_struct_by_value(type_from_syntax(function.result), &checker.module.types) {
checker.template_diagnostics[function_id] = source.addf(
checker.diagnostics,
@@ -500,6 +568,10 @@ validate_declarations :: proc(checker: ^Checker) {
}
if !function.has_body && function.c_abi {
for param in function.params {
if add_unsupported_type_diagnostic(checker, param.span, type_from_syntax(param.type)) !=
source.INVALID_DIAGNOSTIC {
continue
}
if !types.is_c_signature_type(type_from_syntax(param.type), &checker.module.types) {
checker.template_diagnostics[function_id] = source.addf(
checker.diagnostics,
@@ -510,7 +582,8 @@ validate_declarations :: proc(checker: ^Checker) {
}
}
result := type_from_syntax(function.result)
if !types.is_c_signature_type(result, &checker.module.types, true) {
if add_unsupported_type_diagnostic(checker, function.span, result) == source.INVALID_DIAGNOSTIC &&
!types.is_c_signature_type(result, &checker.module.types, true) {
checker.template_diagnostics[function_id] = source.addf(
checker.diagnostics,
function.span,
@@ -547,6 +620,9 @@ validate_declarations :: proc(checker: ^Checker) {
if other_id == function_id || other.has_body || !other.c_abi || other.name != function.name {
continue
}
if function.imported && other.imported && function_signatures_equal(function, other) {
continue
}
checker.template_diagnostics[function_id] = source.addf(
checker.diagnostics,
function.span,
@@ -901,6 +977,11 @@ infer_expr :: proc(
_ = pop(&stack)
continue
}
if len(checker.ast_module.functions[template].unsupported_reason) > 0 {
last = types.INVALID
_ = pop(&stack)
continue
}
if checker.template_diagnostics[template] != source.INVALID_DIAGNOSTIC {
declared := type_from_syntax(checker.ast_module.functions[template].result)
last = declared if is_runtime_type(checker, declared) || types.is_void(declared) else types.INVALID
@@ -1185,8 +1266,15 @@ coerce_expr :: proc(
return expr_id
}
if types.can_weaken_pointer(actual, expected, &checker.module.types) {
checker.module.exprs[expr_id].type = expected
return expr_id
return add_hir_expr(checker, hir.Expr{
kind=.Weaken_Pointer,
span=span,
type=expected,
left=expr_id,
target=hir.INVALID_REF,
right=hir.INVALID_EXPR,
diagnostic=source.INVALID_DIAGNOSTIC,
})
}
if types.is_optional(expected, &checker.module.types) {
child := types.child_type(expected, &checker.module.types)
@@ -1754,7 +1842,10 @@ build_expr :: proc(
target=hir.global_ref(hir_global), left = hir.INVALID_EXPR, right = hir.INVALID_EXPR, diagnostic = source.INVALID_DIAGNOSTIC,
})
} else {
id := add_name_resolution_diagnostic(checker, expr, target_pkg)
id := add_unsupported_diagnostic(checker, expr.span, target_pkg, expr.name)
if id == source.INVALID_DIAGNOSTIC {
id = add_name_resolution_diagnostic(checker, expr, target_pkg)
}
last = invalid_hir_expr(checker, expr.span, id)
}
}
@@ -1775,7 +1866,22 @@ build_expr :: proc(
}
template := find_template(checker, expr.name, target_pkg)
if template == ast.INVALID_FUNCTION {
id := add_call_resolution_diagnostic(checker, expr, target_pkg)
id := add_unsupported_diagnostic(checker, expr.span, target_pkg, expr.name)
if id == source.INVALID_DIAGNOSTIC {
id = add_call_resolution_diagnostic(checker, expr, target_pkg)
}
last = invalid_hir_expr(checker, expr.span, id)
_ = pop(&stack)
continue
}
if len(checker.ast_module.functions[template].unsupported_reason) > 0 {
id := source.addf(
checker.diagnostics,
expr.span,
"C declaration '%s' is unavailable: %s",
symbol_text(checker, expr.name),
checker.ast_module.functions[template].unsupported_reason,
)
last = invalid_hir_expr(checker, expr.span, id)
_ = pop(&stack)
continue