mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
- Bitstructs, unions and flexible arrays now correctly emitted in headers.
- Require `@export` functions to have `@export` types.
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
- Improved error notes when call expressions have errors.
|
||||
- Trailing body arguments may now be `&ref`, `#hash`, `$const` and `$Type` arguments.
|
||||
- "panic-msg" setting to suppress panic message output.
|
||||
- Require `@export` functions to have `@export` types.
|
||||
|
||||
### Fixes
|
||||
- Error with unsigned compare in `@ensure` when early returning 0 #1207.
|
||||
@@ -18,6 +19,7 @@
|
||||
- No longer possible to dereference a function pointer.
|
||||
- Fix bug with @jump miscompile.
|
||||
- Bit negate does implicit integer promotion.
|
||||
- Bitstructs, unions and flexible arrays now correctly emitted in headers.
|
||||
|
||||
### Stdlib changes
|
||||
- Added `remove_first_item` `remove_last_item` and `remove_item` as aliases for the `match` functions.
|
||||
|
||||
@@ -49,7 +49,7 @@ const char *trust_level[3] = {
|
||||
|
||||
#define EOUTPUT(string, ...) fprintf(stderr, string "\n", ##__VA_ARGS__)
|
||||
#define PRINTF(string, ...) fprintf(stdout, string "\n", ##__VA_ARGS__) // NOLINT
|
||||
#define FAIL_WITH_ERR(string, ...) do { fprintf(stderr, "Error: " string "\n\n", ##__VA_ARGS__); usage(); exit_compiler(EXIT_FAILURE); } while (0)
|
||||
#define FAIL_WITH_ERR(string, ...) do { fprintf(stderr, "Error: " string "\n\n", ##__VA_ARGS__); usage(); exit_compiler(EXIT_FAILURE); } while (0) /* NOLINT */
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
|
||||
@@ -2471,6 +2471,7 @@ Type *type_find_parent_type(Type *type);
|
||||
bool type_is_subtype(Type *type, Type *possible_subtype);
|
||||
bool type_is_abi_aggregate(Type *type);
|
||||
bool type_is_int128(Type *type);
|
||||
Decl * type_no_export(Type *type);
|
||||
|
||||
Type *type_from_token(TokenType type);
|
||||
bool type_is_user_defined(Type *type);
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
|
||||
#include "compiler_internal.h"
|
||||
|
||||
#define PRINTF(x, ...) fprintf(file, x, ## __VA_ARGS__)
|
||||
#define PRINTF(x, ...) fprintf(file, x, ## __VA_ARGS__) /* NOLINT */
|
||||
#define INDENT() indent_line(file, indent)
|
||||
#define OUT(file, x, ...) fprintf(file, x, ## __VA_ARGS__)
|
||||
#define OUT(file, x, ...) fprintf(file, x, ## __VA_ARGS__) /* NOLINT */
|
||||
|
||||
static void header_gen_struct_union(FILE *file, int indent, Decl *decl);
|
||||
static void header_gen_maybe_generate_type(FILE *file, HTable *table, Type *type);
|
||||
@@ -125,11 +125,8 @@ static void header_print_type(FILE *file, Type *type)
|
||||
return;
|
||||
case TYPE_DISTINCT:
|
||||
case TYPE_TYPEDEF:
|
||||
UNREACHABLE
|
||||
case TYPE_FLEXIBLE_ARRAY:
|
||||
header_print_type(file, type->array.base);
|
||||
PRINTF("[]");
|
||||
return;
|
||||
UNREACHABLE
|
||||
case TYPE_ARRAY:
|
||||
PRINTF("struct { ");
|
||||
header_print_type(file, type->array.base);
|
||||
@@ -203,6 +200,7 @@ static void header_gen_function_ptr(FILE *file, HTable *table, Type *type)
|
||||
static void header_gen_function(FILE *file, FILE *file_types, HTable *table, Decl *decl)
|
||||
{
|
||||
if (!decl->is_export) return;
|
||||
if (decl->name[0] == '_' && decl->name[1] == '_') return;
|
||||
Signature *sig = &decl->func_decl.signature;
|
||||
PRINTF("extern ");
|
||||
Type *rtype = typeget(sig->rtype);
|
||||
@@ -240,23 +238,41 @@ static void header_gen_members(FILE *file, int indent, Decl **members)
|
||||
VECEACH(members, i)
|
||||
{
|
||||
Decl *member = members[i];
|
||||
Type *type = type_flatten(member->type);
|
||||
switch (member->decl_kind)
|
||||
{
|
||||
case DECL_VAR:
|
||||
INDENT();
|
||||
if (member->type->canonical->type_kind == TYPE_ARRAY)
|
||||
switch (type->type_kind)
|
||||
{
|
||||
header_print_type(file, member->type->canonical->array.base);
|
||||
PRINTF(" %s[%d];\n", member->name, member->type->canonical->array.len);
|
||||
break;
|
||||
case TYPE_ARRAY:
|
||||
header_print_type(file, type->array.base);
|
||||
PRINTF(" %s[%d];\n", member->name, type->array.len);
|
||||
break;
|
||||
case TYPE_FLEXIBLE_ARRAY:
|
||||
header_print_type(file, type->array.base);
|
||||
PRINTF(" %s[];\n", member->name);
|
||||
break;
|
||||
default:
|
||||
header_print_type(file, member->type);
|
||||
PRINTF(" %s;\n", member->name);
|
||||
break;
|
||||
}
|
||||
header_print_type(file, member->type);
|
||||
PRINTF(" %s;\n", member->name);
|
||||
break;
|
||||
case DECL_STRUCT:
|
||||
case DECL_UNION:
|
||||
header_gen_struct_union(file, indent, member);
|
||||
break;
|
||||
case DECL_BITSTRUCT:
|
||||
INDENT();
|
||||
header_print_type(file, member->bitstruct.base_type->type->canonical);
|
||||
if (member->name)
|
||||
{
|
||||
PRINTF(" %s;\n", member->name);
|
||||
break;
|
||||
}
|
||||
PRINTF(" __bits%d;\n", i);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
@@ -266,7 +282,7 @@ static void header_gen_struct_union(FILE *file, int indent, Decl *decl)
|
||||
{
|
||||
if (!indent)
|
||||
{
|
||||
PRINTF("typedef struct %s__ %s;\n", decl->extname, decl->extname);
|
||||
PRINTF("typedef %s %s__ %s;\n", struct_union_str(decl), decl->extname, decl->extname);
|
||||
}
|
||||
INDENT();
|
||||
if (decl->name)
|
||||
@@ -343,6 +359,8 @@ void header_ensure_member_types_exist(FILE *file, HTable *table, Decl **members)
|
||||
case DECL_UNION:
|
||||
header_ensure_member_types_exist(file, table, member->strukt.members);
|
||||
break;
|
||||
case DECL_BITSTRUCT:
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
@@ -419,7 +437,7 @@ RETRY:
|
||||
if (htable_get(table, type)) return;
|
||||
{
|
||||
Decl *decl = type->decl;
|
||||
PRINTF("typedef struct %s__ %s;\n", decl_get_extname(decl), decl_get_extname(decl));
|
||||
PRINTF("typedef %s %s__ %s;\n", struct_union_str(decl), decl_get_extname(decl), decl_get_extname(decl));
|
||||
htable_set(table, type, type);
|
||||
header_ensure_member_types_exist(file, table, decl->strukt.members);
|
||||
PRINTF("%s %s__\n", struct_union_str(decl), decl->extname);
|
||||
@@ -544,6 +562,7 @@ void header_gen(Module **modules, unsigned module_count)
|
||||
FILE *file_types = fopen(filename_types, "w");
|
||||
OUT(file_types, "#include <stdint.h>\n");
|
||||
OUT(file_types, "#include <stddef.h>\n");
|
||||
OUT(file_types, "#include <stdbool.h>\n");
|
||||
OUT(file_types, "#ifndef __c3__\n");
|
||||
OUT(file_types, "#define __c3__\n\n");
|
||||
OUT(file_types, "typedef void* c3typeid_t;\n");
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
static inline bool sema_analyse_func_macro(SemaContext *context, Decl *decl, AttributeDomain domain, bool *erase_decl);
|
||||
static inline bool sema_analyse_func(SemaContext *context, Decl *decl, bool *erase_decl);
|
||||
static inline bool sema_analyse_macro(SemaContext *context, Decl *decl, bool *erase_decl);
|
||||
static inline bool sema_analyse_signature(SemaContext *context, Signature *sig, TypeInfoId type_parent);
|
||||
static inline bool sema_analyse_signature(SemaContext *context, Signature *sig, TypeInfoId type_parent, bool is_export);
|
||||
static inline bool sema_analyse_main_function(SemaContext *context, Decl *decl);
|
||||
static inline bool sema_check_param_uniqueness_and_type(SemaContext *context, Decl **decls, Decl *current,
|
||||
unsigned current_index, unsigned count);
|
||||
@@ -27,6 +27,7 @@ static inline Decl *operator_in_module(SemaContext *c, Module *module, OperatorO
|
||||
static inline bool sema_analyse_operator_element_at(SemaContext *context, Decl *method);
|
||||
static inline bool sema_analyse_operator_element_set(SemaContext *context, Decl *method);
|
||||
static inline bool sema_analyse_operator_len(Decl *method, SemaContext *context);
|
||||
static bool sema_require_export_type(SemaContext *context, TypeInfo *type_info);
|
||||
static bool sema_check_operator_method_validity(SemaContext *context, Decl *method);
|
||||
static inline const char *method_name_by_decl(Decl *method_like);
|
||||
|
||||
@@ -229,6 +230,7 @@ static inline bool sema_analyse_struct_member(SemaContext *context, Decl *parent
|
||||
sema_decl_stack_push(decl);
|
||||
}
|
||||
|
||||
bool is_export = parent->is_export;
|
||||
// Analysis depends on the underlying type.
|
||||
switch (decl->decl_kind)
|
||||
{
|
||||
@@ -240,6 +242,7 @@ static inline bool sema_analyse_struct_member(SemaContext *context, Decl *parent
|
||||
assert(type_infoptrzero(decl->var.type_info));
|
||||
TypeInfo *type_info = type_infoptr(decl->var.type_info);
|
||||
if (!sema_resolve_type_info(context, type_info, RESOLVE_TYPE_ALLOW_FLEXIBLE)) return decl_poison(decl);
|
||||
if (is_export && !sema_require_export_type(context, type_info)) return decl_poison(decl);
|
||||
Type *type = type_info->type;
|
||||
switch (type_storage_type(type))
|
||||
{
|
||||
@@ -259,6 +262,7 @@ static inline bool sema_analyse_struct_member(SemaContext *context, Decl *parent
|
||||
case DECL_STRUCT:
|
||||
case DECL_UNION:
|
||||
case DECL_BITSTRUCT:
|
||||
decl->is_export = is_export;
|
||||
if (!sema_analyse_decl(context, decl)) return false;
|
||||
return true;
|
||||
default:
|
||||
@@ -945,7 +949,17 @@ ERROR:
|
||||
return decl_poison(decl);
|
||||
}
|
||||
|
||||
static inline bool sema_analyse_signature(SemaContext *context, Signature *sig, TypeInfoId type_parent)
|
||||
static bool sema_require_export_type(SemaContext *context, TypeInfo *type_info)
|
||||
{
|
||||
Decl *decl = type_no_export(type_info->type);
|
||||
if (!decl) return true;
|
||||
SEMA_ERROR(type_info, "%s must also be an exported type, to make this work '%s' needs to be marked '@export'",
|
||||
type_quoted_error_string(type_info->type), decl->name);
|
||||
SEMA_NOTE(decl, "The definition is here.");
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool sema_analyse_signature(SemaContext *context, Signature *sig, TypeInfoId type_parent, bool is_export)
|
||||
{
|
||||
Variadic variadic_type = sig->variadic;
|
||||
Decl **params = sig->params;
|
||||
@@ -963,6 +977,7 @@ static inline bool sema_analyse_signature(SemaContext *context, Signature *sig,
|
||||
is_macro ? RESOLVE_TYPE_ALLOW_INFER
|
||||
: RESOLVE_TYPE_DEFAULT)) return false;
|
||||
rtype = rtype_info->type;
|
||||
if (is_export && !sema_require_export_type(context, rtype_info)) return false;
|
||||
if (sig->attrs.nodiscard)
|
||||
{
|
||||
if (type_is_void(rtype))
|
||||
@@ -993,10 +1008,12 @@ static inline bool sema_analyse_signature(SemaContext *context, Signature *sig,
|
||||
return false;
|
||||
}
|
||||
|
||||
TypeInfo *method_parent = type_infoptrzero(type_parent);
|
||||
if (is_export && method_parent && !sema_require_export_type(context, method_parent)) return false;
|
||||
|
||||
// Fill in the type if the first parameter is lacking a type.
|
||||
if (type_parent && params && params[0] && !params[0]->var.type_info)
|
||||
if (method_parent && params && params[0] && !params[0]->var.type_info)
|
||||
{
|
||||
TypeInfo *method_parent = type_infoptr(type_parent);
|
||||
if (!sema_resolve_type_info(context, method_parent,
|
||||
is_macro ? RESOLVE_TYPE_MACRO_METHOD : RESOLVE_TYPE_FUNC_METHOD)) return false;
|
||||
Decl *param = params[0];
|
||||
@@ -1067,6 +1084,7 @@ static inline bool sema_analyse_signature(SemaContext *context, Signature *sig,
|
||||
if (!sema_resolve_type_info(context, type_info,
|
||||
is_macro ? RESOLVE_TYPE_ALLOW_INFER
|
||||
: RESOLVE_TYPE_DEFAULT)) return decl_poison(param);
|
||||
if (is_export && !sema_require_export_type(context, type_info)) return false;
|
||||
param->type = type_info->type;
|
||||
}
|
||||
switch (var_kind)
|
||||
@@ -1181,7 +1199,7 @@ bool sema_analyse_function_signature(SemaContext *context, Decl *func_decl, Call
|
||||
// Get param count and variadic type
|
||||
Decl **params = signature->params;
|
||||
|
||||
if (!sema_analyse_signature(context, signature, func_decl->func_decl.type_parent)) return false;
|
||||
if (!sema_analyse_signature(context, signature, func_decl->func_decl.type_parent, func_decl->is_export)) return false;
|
||||
|
||||
Variadic variadic_type = signature->variadic;
|
||||
// Remove the last empty value.
|
||||
@@ -3273,7 +3291,8 @@ static inline bool sema_analyse_macro(SemaContext *context, Decl *decl, bool *er
|
||||
|
||||
if (!sema_analyse_func_macro(context, decl, ATTR_MACRO, erase_decl)) return false;
|
||||
if (*erase_decl) return true;
|
||||
if (!sema_analyse_signature(context, &decl->func_decl.signature, decl->func_decl.type_parent)) return decl_poison(decl);
|
||||
if (!sema_analyse_signature(context, &decl->func_decl.signature, decl->func_decl.type_parent,
|
||||
false)) return decl_poison(decl);
|
||||
|
||||
if (!decl->func_decl.signature.is_at_macro && decl->func_decl.body_param && !decl->func_decl.signature.is_safemacro)
|
||||
{
|
||||
|
||||
@@ -384,6 +384,59 @@ bool type_flat_is_boolintlike(Type *type)
|
||||
return kind == TYPE_BOOL || (kind >= TYPE_INTEGER_FIRST && kind <= TYPE_INTEGER_LAST);
|
||||
}
|
||||
|
||||
Decl *type_no_export(Type *type)
|
||||
{
|
||||
type = type->canonical;
|
||||
RETRY:
|
||||
switch (type->type_kind)
|
||||
{
|
||||
case TYPE_POISONED:
|
||||
case TYPE_UNTYPED_LIST:
|
||||
case TYPE_WILDCARD:
|
||||
case TYPE_MEMBER:
|
||||
case TYPE_TYPEINFO:
|
||||
return NULL;
|
||||
case TYPE_VOID:
|
||||
case TYPE_BOOL:
|
||||
case ALL_INTS:
|
||||
case ALL_FLOATS:
|
||||
case TYPE_ANY:
|
||||
case TYPE_INTERFACE:
|
||||
case TYPE_ANYFAULT:
|
||||
case TYPE_TYPEID:
|
||||
return NULL;
|
||||
case TYPE_POINTER:
|
||||
type = type->pointer;
|
||||
goto RETRY;
|
||||
case TYPE_FUNC_PTR:
|
||||
type = type->pointer;
|
||||
FALLTHROUGH;
|
||||
case TYPE_FUNC_RAW:
|
||||
case TYPE_ENUM:
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_UNION:
|
||||
case TYPE_BITSTRUCT:
|
||||
case TYPE_FAULTTYPE:
|
||||
case TYPE_DISTINCT:
|
||||
if (type->decl->is_export) return NULL;
|
||||
return type->decl;
|
||||
case TYPE_SLICE:
|
||||
case TYPE_TYPEDEF:
|
||||
case TYPE_ARRAY:
|
||||
case TYPE_FLEXIBLE_ARRAY:
|
||||
case TYPE_INFERRED_ARRAY:
|
||||
type = type->array.base;
|
||||
goto RETRY;
|
||||
case TYPE_VECTOR:
|
||||
case TYPE_INFERRED_VECTOR:
|
||||
return NULL;
|
||||
case TYPE_OPTIONAL:
|
||||
type = type->optional;
|
||||
goto RETRY;
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
|
||||
bool type_is_int128(Type *type)
|
||||
{
|
||||
|
||||
@@ -83,11 +83,11 @@ distinct Color = float[<4>];
|
||||
const Color BLACK = {0, 0, 0, 1};
|
||||
const Color WHITE = {1, 1, 1, 1};
|
||||
|
||||
struct Arena {
|
||||
struct Arena @export {
|
||||
usz cursor;
|
||||
}
|
||||
|
||||
struct Arena_Cursor {
|
||||
struct Arena_Cursor @export {
|
||||
Arena* arena;
|
||||
usz cursor;
|
||||
}
|
||||
@@ -690,11 +690,11 @@ no_match: ; preds = %compare
|
||||
!106 = !{!12}
|
||||
!107 = !DILocalVariable(name: "scratch", scope: !108, file: !5, line: 110, type: !109, align: 8)
|
||||
!108 = distinct !DISubprogram(name: "@scratch", linkageName: "@scratch", scope: !5, file: !5, line: 109, scopeLine: 109, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit:
|
||||
!109 = !DICompositeType(tag: DW_TAG_structure_type, name: "Arena_Cursor", scope: !5, file: !5, line: 88, size: 128, align: 64, elements: !110, identifier: "foo.Arena_Cursor")
|
||||
!109 = !DICompositeType(tag: DW_TAG_structure_type, name: "Arena_Cursor", scope: !5, file: !5, line: 88, size: 128, align: 64, elements: !110, identifier: "foo_Arena_Cursor")
|
||||
!110 = !{!111, !116}
|
||||
!111 = !DIDerivedType(tag: DW_TAG_member, name: "arena", scope: !109, file: !5, line: 89, baseType: !112, size: 64, align: 64)
|
||||
!112 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "Arena*", baseType: !113, size: 64, align: 64, dwarfAddressSpace: 0)
|
||||
!113 = !DICompositeType(tag: DW_TAG_structure_type, name: "Arena", scope: !5, file: !5, line: 84, size: 64, align: 64, elements: !114, identifier: "foo.Arena")
|
||||
!113 = !DICompositeType(tag: DW_TAG_structure_type, name: "Arena", scope: !5, file: !5, line: 84, size: 64, align: 64, elements: !114, identifier: "foo_Arena")
|
||||
!114 = !{!115}
|
||||
!115 = !DIDerivedType(tag: DW_TAG_member, name: "cursor", scope: !113, file: !5, line: 85, baseType: !44, size: 64, align: 64)
|
||||
!116 = !DIDerivedType(tag: DW_TAG_member, name: "cursor", scope: !109, file: !5, line: 90, baseType: !44, size: 64, align: 64, offset: 64)
|
||||
|
||||
41
test/test_suite/visibility/export_property.c3
Normal file
41
test/test_suite/visibility/export_property.c3
Normal file
@@ -0,0 +1,41 @@
|
||||
fn Abcd test(Test a) @export
|
||||
{
|
||||
return Abcd.ABC;
|
||||
}
|
||||
|
||||
fn void test2(Abc a) @export // #error: must also be an exported type
|
||||
{
|
||||
}
|
||||
|
||||
fault Abcd @export
|
||||
{
|
||||
ABC,
|
||||
EFG
|
||||
}
|
||||
enum Abc
|
||||
{
|
||||
ABC,
|
||||
DEF
|
||||
}
|
||||
struct Test @export
|
||||
{
|
||||
struct
|
||||
{
|
||||
int a;
|
||||
int b;
|
||||
}
|
||||
bitstruct : int
|
||||
{
|
||||
int fa : 1..6;
|
||||
}
|
||||
int[*] x;
|
||||
|
||||
}
|
||||
|
||||
struct Test2 @export
|
||||
{
|
||||
struct
|
||||
{
|
||||
Abc d; // #error: must also be an exported type
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user