mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Fixes member visibility for anonymous bitstruct. Bitstruct member attributes works. Anonymous bitstruct assignment fixed.
This commit is contained in:
@@ -152,6 +152,8 @@
|
||||
- Added posix socket functions.
|
||||
|
||||
### Fixes
|
||||
- Anonymous bitstructs check of duplicate member names fixed.
|
||||
- Assignment to anonymous bitstruct members in structs.
|
||||
- Fix casts on empty initializers.
|
||||
- Fix to DString reserve
|
||||
- @local declarations in generic modules available by accident.
|
||||
|
||||
@@ -737,13 +737,14 @@ typedef enum
|
||||
ATTR_FAULT = 1 << 7,
|
||||
ATTR_DEF = 1 << 8,
|
||||
ATTR_MEMBER = 1 << 9,
|
||||
ATTR_INTERFACE = 1 << 10,
|
||||
ATTR_CALL = 1 << 11,
|
||||
ATTR_BITSTRUCT = 1 << 12,
|
||||
ATTR_MACRO = 1 << 13,
|
||||
ATTR_INITIALIZER = 1 << 14,
|
||||
ATTR_FINALIZER = 1 << 15,
|
||||
ATTR_DEFINE = 1 << 16,
|
||||
ATTR_BITSTRUCT_MEMBER = 1 << 10,
|
||||
ATTR_INTERFACE = 1 << 11,
|
||||
ATTR_CALL = 1 << 12,
|
||||
ATTR_BITSTRUCT = 1 << 13,
|
||||
ATTR_MACRO = 1 << 14,
|
||||
ATTR_INITIALIZER = 1 << 15,
|
||||
ATTR_FINALIZER = 1 << 16,
|
||||
ATTR_DEFINE = 1 << 17,
|
||||
ATTR_XXLIZER = ATTR_INITIALIZER | ATTR_FINALIZER
|
||||
} AttributeDomain;
|
||||
|
||||
|
||||
@@ -1105,9 +1105,9 @@ static inline void llvm_emit_bitassign_expr(GenContext *c, BEValue *be_value, Ex
|
||||
|
||||
// Grab the parent
|
||||
BEValue parent;
|
||||
llvm_emit_expr(c, &parent, parent_expr);
|
||||
|
||||
Decl *member = lhs->access_expr.ref;
|
||||
llvm_emit_expr(c, &parent, parent_expr);
|
||||
llvm_emit_bitstruct_member(c, &parent, type_flatten(parent_expr->type)->decl, member);
|
||||
|
||||
// If we have assign + op, load the current value, perform the operation.
|
||||
if (expr->binary_expr.operator != BINARYOP_ASSIGN)
|
||||
|
||||
@@ -28,10 +28,10 @@ static inline const char *method_name_by_decl(Decl *method_like);
|
||||
|
||||
static bool sema_analyse_struct_union(SemaContext *context, Decl *decl, bool *erase_decl);
|
||||
static bool sema_analyse_bitstruct(SemaContext *context, Decl *decl, bool *erase_decl);
|
||||
static bool sema_analyse_union_members(SemaContext *context, Decl *decl, Decl **members);
|
||||
static bool sema_analyse_struct_members(SemaContext *context, Decl *decl, Decl **members);
|
||||
static bool sema_analyse_union_members(SemaContext *context, Decl *decl);
|
||||
static bool sema_analyse_struct_members(SemaContext *context, Decl *decl);
|
||||
static inline bool sema_analyse_struct_member(SemaContext *context, Decl *parent, Decl *decl, bool *erase_decl);
|
||||
static inline bool sema_analyse_bitstruct_member(SemaContext *context, Decl *decl, unsigned index, bool allow_overlap);
|
||||
static inline bool sema_analyse_bitstruct_member(SemaContext *context, Decl *parent, Decl *member, unsigned index, bool allow_overlap, bool *erase_decl);
|
||||
|
||||
static inline bool sema_analyse_doc_header(AstId doc, Decl **params, Decl **extra_params, bool *pure_ref);
|
||||
|
||||
@@ -207,13 +207,14 @@ static inline bool sema_analyse_struct_member(SemaContext *context, Decl *parent
|
||||
}
|
||||
}
|
||||
|
||||
static bool sema_analyse_union_members(SemaContext *context, Decl *decl, Decl **members)
|
||||
static bool sema_analyse_union_members(SemaContext *context, Decl *decl)
|
||||
{
|
||||
AlignSize max_size = 0;
|
||||
MemberIndex max_alignment_element = 0;
|
||||
AlignSize max_alignment = 0;
|
||||
|
||||
bool has_named_parameter = false;
|
||||
Decl **members = decl->strukt.members;
|
||||
unsigned member_count = vec_size(members);
|
||||
for (unsigned i = 0; i < member_count; i++)
|
||||
{
|
||||
@@ -308,7 +309,7 @@ static bool sema_analyse_union_members(SemaContext *context, Decl *decl, Decl **
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool sema_analyse_struct_members(SemaContext *context, Decl *decl, Decl **members)
|
||||
static bool sema_analyse_struct_members(SemaContext *context, Decl *decl)
|
||||
{
|
||||
// Default alignment is 1 even if it is empty.
|
||||
AlignSize natural_alignment = 1;
|
||||
@@ -316,8 +317,8 @@ static bool sema_analyse_struct_members(SemaContext *context, Decl *decl, Decl *
|
||||
AlignSize size = 0;
|
||||
AlignSize offset = 0;
|
||||
bool is_packed = decl->is_packed;
|
||||
unsigned member_count = vec_size(members);
|
||||
Decl **struct_members = decl->strukt.members;
|
||||
unsigned member_count = vec_size(struct_members);
|
||||
|
||||
for (unsigned i = 0; i < member_count; i++)
|
||||
{
|
||||
@@ -481,11 +482,11 @@ static bool sema_analyse_struct_union(SemaContext *context, Decl *decl, bool *er
|
||||
Decl** state = sema_decl_stack_store();
|
||||
if (decl->decl_kind == DECL_UNION)
|
||||
{
|
||||
success = sema_analyse_union_members(context, decl, decl->strukt.members);
|
||||
success = sema_analyse_union_members(context, decl);
|
||||
}
|
||||
else
|
||||
{
|
||||
success = sema_analyse_struct_members(context, decl, decl->strukt.members);
|
||||
success = sema_analyse_struct_members(context, decl);
|
||||
}
|
||||
sema_decl_stack_restore(state);
|
||||
}
|
||||
@@ -493,11 +494,11 @@ static bool sema_analyse_struct_union(SemaContext *context, Decl *decl, bool *er
|
||||
{
|
||||
if (decl->decl_kind == DECL_UNION)
|
||||
{
|
||||
success = sema_analyse_union_members(context, decl, decl->strukt.members);
|
||||
success = sema_analyse_union_members(context, decl);
|
||||
}
|
||||
else
|
||||
{
|
||||
success = sema_analyse_struct_members(context, decl, decl->strukt.members);
|
||||
success = sema_analyse_struct_members(context, decl);
|
||||
}
|
||||
}
|
||||
DEBUG_LOG("Struct/union size %d, alignment %d.", (int)decl->strukt.size, (int)decl->alignment);
|
||||
@@ -506,11 +507,38 @@ static bool sema_analyse_struct_union(SemaContext *context, Decl *decl, bool *er
|
||||
return decl_ok(decl);
|
||||
}
|
||||
|
||||
static inline bool sema_analyse_bitstruct_member(SemaContext *context, Decl *decl, unsigned index, bool allow_overlap)
|
||||
static inline bool sema_analyse_bitstruct_member(SemaContext *context, Decl *parent, Decl *member, unsigned index, bool allow_overlap, bool *erase_decl)
|
||||
{
|
||||
bool is_consecutive = decl->bitstruct.consecutive;
|
||||
Decl **members = decl->bitstruct.members;
|
||||
Decl *member = members[index];
|
||||
|
||||
if (member->resolve_status == RESOLVE_DONE)
|
||||
{
|
||||
if (!decl_ok(member)) return false;
|
||||
if (member->name) sema_decl_stack_push(member);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (member->resolve_status == RESOLVE_RUNNING)
|
||||
{
|
||||
RETURN_SEMA_ERROR(member, "Circular dependency resolving member.");
|
||||
}
|
||||
|
||||
bool ease_decl = false;
|
||||
if (!sema_analyse_attributes(context, member, member->attributes, ATTR_BITSTRUCT_MEMBER, erase_decl)) return decl_poison(member);
|
||||
if (*erase_decl) return true;
|
||||
|
||||
if (member->name)
|
||||
{
|
||||
Decl *other = sema_decl_stack_resolve_symbol(member->name);
|
||||
if (other)
|
||||
{
|
||||
SEMA_ERROR(member, "Duplicate member name '%s'.", other->name);
|
||||
SEMA_NOTE(other, "Previous declaration was here.");
|
||||
return false;
|
||||
}
|
||||
if (member->name) sema_decl_stack_push(member);
|
||||
}
|
||||
|
||||
bool is_consecutive = parent->bitstruct.consecutive;
|
||||
|
||||
// Resolve the type.
|
||||
if (!sema_resolve_type_info(context, member->var.type_info)) return false;
|
||||
@@ -528,11 +556,11 @@ static inline bool sema_analyse_bitstruct_member(SemaContext *context, Decl *dec
|
||||
}
|
||||
|
||||
// Grab the underlying bit type size.
|
||||
BitSize bits = type_size(decl->bitstruct.base_type->type) * (BitSize)8;
|
||||
BitSize bits = type_size(parent->bitstruct.base_type->type) * (BitSize)8;
|
||||
|
||||
if (bits > MAX_BITSTRUCT)
|
||||
{
|
||||
SEMA_ERROR(decl->bitstruct.base_type, "Bitstruct size may not exceed %d bits.", MAX_BITSTRUCT);
|
||||
SEMA_ERROR(parent->bitstruct.base_type, "Bitstruct size may not exceed %d bits.", MAX_BITSTRUCT);
|
||||
return false;
|
||||
}
|
||||
Int max_bits = (Int) { .type = TYPE_I64, .i = { .low = bits } };
|
||||
@@ -632,26 +660,21 @@ static inline bool sema_analyse_bitstruct_member(SemaContext *context, Decl *dec
|
||||
member->var.end_bit = end_bit;
|
||||
|
||||
AFTER_BIT_CHECK:
|
||||
// Check for duplicate members.
|
||||
for (unsigned i = 0; i < index; i++)
|
||||
// Check for overlap
|
||||
if (!allow_overlap)
|
||||
{
|
||||
Decl *other_member = members[i];
|
||||
if (member->name == other_member->name)
|
||||
Decl **members = parent->bitstruct.members;
|
||||
for (unsigned i = 0; i < index; i++)
|
||||
{
|
||||
SEMA_ERROR(member, "Duplicate members with the name '%s'.", member->name);
|
||||
SEMA_NOTE(other_member, "The other member was declared here.");
|
||||
return false;
|
||||
}
|
||||
// And possibly overlap.
|
||||
if (allow_overlap) continue;
|
||||
|
||||
// Check for overlap.
|
||||
if ((start_bit >= other_member->var.start_bit || end_bit >= other_member->var.start_bit)
|
||||
&& start_bit <= other_member->var.end_bit)
|
||||
{
|
||||
SEMA_ERROR(member, "Overlapping members, please use '@overlap' if this is intended.");
|
||||
SEMA_NOTE(other_member, "The other member was declared here.");
|
||||
return false;
|
||||
Decl *other_member = members[i];
|
||||
// Check for overlap.
|
||||
if ((start_bit >= other_member->var.start_bit || end_bit >= other_member->var.start_bit)
|
||||
&& start_bit <= other_member->var.end_bit)
|
||||
{
|
||||
SEMA_ERROR(member, "Overlapping members, please use '@overlap' if this is intended.");
|
||||
SEMA_NOTE(other_member, "The other member was declared here.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
member->resolve_status = RESOLVE_DONE;
|
||||
@@ -673,14 +696,29 @@ static bool sema_analyse_bitstruct(SemaContext *context, Decl *decl, bool *erase
|
||||
return false;
|
||||
}
|
||||
Decl **members = decl->bitstruct.members;
|
||||
VECEACH(members, i)
|
||||
unsigned member_count = vec_size(members);
|
||||
|
||||
Decl **state = decl->name ? sema_decl_stack_store() : NULL;
|
||||
for (unsigned i = 0; i < member_count; i++)
|
||||
{
|
||||
if (!sema_analyse_bitstruct_member(context, decl, i, decl->bitstruct.overlap))
|
||||
AGAIN:;
|
||||
Decl *member = members[i];
|
||||
if (!decl_ok(member)) goto ERROR;
|
||||
bool erase_decl_member = false;
|
||||
if (!sema_analyse_bitstruct_member(context, decl, member, i, decl->bitstruct.overlap, &erase_decl_member)) goto ERROR;
|
||||
if (erase_decl_member)
|
||||
{
|
||||
return decl_poison(decl);
|
||||
vec_erase_ptr_at(members, i);
|
||||
member_count--;
|
||||
if (i < member_count) goto AGAIN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (state) sema_decl_stack_restore(state);
|
||||
return true;
|
||||
ERROR:
|
||||
if (state) sema_decl_stack_restore(state);
|
||||
return decl_poison(decl);
|
||||
}
|
||||
|
||||
|
||||
@@ -1544,6 +1582,8 @@ static const char *attribute_domain_to_string(AttributeDomain domain)
|
||||
return "interface";
|
||||
case ATTR_MEMBER:
|
||||
return "member";
|
||||
case ATTR_BITSTRUCT_MEMBER:
|
||||
return "bitstruct member";
|
||||
case ATTR_FUNC:
|
||||
return "function";
|
||||
case ATTR_GLOBAL:
|
||||
@@ -1626,7 +1666,7 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
|
||||
[ATTRIBUTE_BIGENDIAN] = ATTR_BITSTRUCT,
|
||||
[ATTRIBUTE_BUILTIN] = ATTR_MACRO | ATTR_FUNC | ATTR_GLOBAL | ATTR_CONST,
|
||||
[ATTRIBUTE_CALLCONV] = ATTR_FUNC,
|
||||
[ATTRIBUTE_DEPRECATED] = USER_DEFINED_TYPES | ATTR_FUNC | ATTR_MACRO | ATTR_CONST | ATTR_GLOBAL | ATTR_MEMBER,
|
||||
[ATTRIBUTE_DEPRECATED] = USER_DEFINED_TYPES | ATTR_FUNC | ATTR_MACRO | ATTR_CONST | ATTR_GLOBAL | ATTR_MEMBER | ATTR_BITSTRUCT_MEMBER,
|
||||
[ATTRIBUTE_DYNAMIC] = ATTR_FUNC,
|
||||
[ATTRIBUTE_EXPORT] = ATTR_FUNC | ATTR_GLOBAL | ATTR_CONST | EXPORTED_USER_DEFINED_TYPES,
|
||||
[ATTRIBUTE_EXTERN] = ATTR_FUNC | ATTR_GLOBAL | ATTR_CONST | USER_DEFINED_TYPES,
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "0.4.595"
|
||||
#define COMPILER_VERSION "0.4.596"
|
||||
24
test/test_suite/bitstruct/anon_bitstruct_name_overlap.c3
Normal file
24
test/test_suite/bitstruct/anon_bitstruct_name_overlap.c3
Normal file
@@ -0,0 +1,24 @@
|
||||
import std::io;
|
||||
|
||||
struct Test {
|
||||
ushort a;
|
||||
bitstruct : ushort @overlap {
|
||||
ushort ab : 0..15;
|
||||
char a : 8..15; // #error: Duplicate member name 'a'
|
||||
char b : 0..7;
|
||||
bool c : 7;
|
||||
bool d : 6;
|
||||
bool e : 5;
|
||||
bool f : 4;
|
||||
}
|
||||
}
|
||||
|
||||
fn void main() {
|
||||
io::printfn("Weird structs :P");
|
||||
|
||||
Test test;
|
||||
test.ab = 0xAFBA;
|
||||
|
||||
io::printfn("%02x %02x -> %04x\n", test.a, test.b, test.ab);
|
||||
io::printfn("%x %x %x %x\n", test.c, test.d, test.e, test.f);
|
||||
}
|
||||
122
test/test_suite/bitstruct/bitstruct_anon_in_struct_ok.c3t
Normal file
122
test/test_suite/bitstruct/bitstruct_anon_in_struct_ok.c3t
Normal file
@@ -0,0 +1,122 @@
|
||||
// #target: macos-x64
|
||||
module foo;
|
||||
import std::io;
|
||||
|
||||
struct Test {
|
||||
ushort afff;
|
||||
bitstruct : ushort @overlap {
|
||||
ushort ab : 0..15;
|
||||
char a : 8..15;
|
||||
char b : 0..7;
|
||||
bool c : 7;
|
||||
bool d : 6;
|
||||
bool e : 5;
|
||||
bool f : 4;
|
||||
}
|
||||
}
|
||||
|
||||
fn void main() {
|
||||
|
||||
|
||||
Test test;
|
||||
test.ab = 0xAFBA;
|
||||
|
||||
io::printfn("%02x %02x -> %04x\n", test.a, test.b, test.ab);
|
||||
io::printfn("%x %x %x %x\n", test.c, test.d, test.e, test.f);
|
||||
}
|
||||
|
||||
/* #expect: foo.ll
|
||||
|
||||
|
||||
define void @foo.main() #0 {
|
||||
entry:
|
||||
%test = alloca %Test, align 2
|
||||
%retparam = alloca i64, align 8
|
||||
%varargslots = alloca [3 x %any], align 16
|
||||
%taddr = alloca i8, align 1
|
||||
%taddr2 = alloca i8, align 1
|
||||
%taddr3 = alloca i16, align 2
|
||||
%retparam4 = alloca i64, align 8
|
||||
%varargslots5 = alloca [4 x %any], align 16
|
||||
%taddr8 = alloca i8, align 1
|
||||
%taddr11 = alloca i8, align 1
|
||||
%taddr14 = alloca i8, align 1
|
||||
%taddr17 = alloca i8, align 1
|
||||
%0 = getelementptr inbounds %Test, ptr %test, i32 0, i32 0
|
||||
store i16 0, ptr %0, align 2
|
||||
%1 = getelementptr inbounds %Test, ptr %test, i32 0, i32 1
|
||||
store i16 0, ptr %1, align 2
|
||||
%2 = getelementptr inbounds %Test, ptr %test, i32 0, i32 1
|
||||
%3 = load i16, ptr %2, align 2
|
||||
store i16 -20550, ptr %2, align 2
|
||||
%4 = getelementptr inbounds %Test, ptr %test, i32 0, i32 1
|
||||
%5 = load i16, ptr %4, align 2
|
||||
%lshrl = lshr i16 %5, 8
|
||||
%6 = and i16 255, %lshrl
|
||||
%trunc = trunc i16 %6 to i8
|
||||
store i8 %trunc, ptr %taddr, align 1
|
||||
%7 = insertvalue %any undef, ptr %taddr, 0
|
||||
%8 = insertvalue %any %7, i64 ptrtoint (ptr @"$ct.char" to i64), 1
|
||||
%9 = getelementptr inbounds [3 x %any], ptr %varargslots, i64 0, i64 0
|
||||
store %any %8, ptr %9, align 16
|
||||
%10 = getelementptr inbounds %Test, ptr %test, i32 0, i32 1
|
||||
%11 = load i16, ptr %10, align 2
|
||||
%12 = and i16 255, %11
|
||||
%trunc1 = trunc i16 %12 to i8
|
||||
store i8 %trunc1, ptr %taddr2, align 1
|
||||
%13 = insertvalue %any undef, ptr %taddr2, 0
|
||||
%14 = insertvalue %any %13, i64 ptrtoint (ptr @"$ct.char" to i64), 1
|
||||
%15 = getelementptr inbounds [3 x %any], ptr %varargslots, i64 0, i64 1
|
||||
store %any %14, ptr %15, align 16
|
||||
%16 = getelementptr inbounds %Test, ptr %test, i32 0, i32 1
|
||||
%17 = load i16, ptr %16, align 2
|
||||
store i16 %17, ptr %taddr3, align 2
|
||||
%18 = insertvalue %any undef, ptr %taddr3, 0
|
||||
%19 = insertvalue %any %18, i64 ptrtoint (ptr @"$ct.ushort" to i64), 1
|
||||
%20 = getelementptr inbounds [3 x %any], ptr %varargslots, i64 0, i64 2
|
||||
store %any %19, ptr %20, align 16
|
||||
%21 = call i64 @std.io.printfn(ptr %retparam, ptr @.str, i64 18, ptr %varargslots, i64 3)
|
||||
%22 = getelementptr inbounds %Test, ptr %test, i32 0, i32 1
|
||||
%23 = load i16, ptr %22, align 2
|
||||
%lshrl6 = lshr i16 %23, 7
|
||||
%24 = and i16 1, %lshrl6
|
||||
%trunc7 = trunc i16 %24 to i8
|
||||
store i8 %trunc7, ptr %taddr8, align 1
|
||||
%25 = insertvalue %any undef, ptr %taddr8, 0
|
||||
%26 = insertvalue %any %25, i64 ptrtoint (ptr @"$ct.bool" to i64), 1
|
||||
%27 = getelementptr inbounds [4 x %any], ptr %varargslots5, i64 0, i64 0
|
||||
store %any %26, ptr %27, align 16
|
||||
%28 = getelementptr inbounds %Test, ptr %test, i32 0, i32 1
|
||||
%29 = load i16, ptr %28, align 2
|
||||
%lshrl9 = lshr i16 %29, 6
|
||||
%30 = and i16 1, %lshrl9
|
||||
%trunc10 = trunc i16 %30 to i8
|
||||
store i8 %trunc10, ptr %taddr11, align 1
|
||||
%31 = insertvalue %any undef, ptr %taddr11, 0
|
||||
%32 = insertvalue %any %31, i64 ptrtoint (ptr @"$ct.bool" to i64), 1
|
||||
%33 = getelementptr inbounds [4 x %any], ptr %varargslots5, i64 0, i64 1
|
||||
store %any %32, ptr %33, align 16
|
||||
%34 = getelementptr inbounds %Test, ptr %test, i32 0, i32 1
|
||||
%35 = load i16, ptr %34, align 2
|
||||
%lshrl12 = lshr i16 %35, 5
|
||||
%36 = and i16 1, %lshrl12
|
||||
%trunc13 = trunc i16 %36 to i8
|
||||
store i8 %trunc13, ptr %taddr14, align 1
|
||||
%37 = insertvalue %any undef, ptr %taddr14, 0
|
||||
%38 = insertvalue %any %37, i64 ptrtoint (ptr @"$ct.bool" to i64), 1
|
||||
%39 = getelementptr inbounds [4 x %any], ptr %varargslots5, i64 0, i64 2
|
||||
store %any %38, ptr %39, align 16
|
||||
%40 = getelementptr inbounds %Test, ptr %test, i32 0, i32 1
|
||||
%41 = load i16, ptr %40, align 2
|
||||
%lshrl15 = lshr i16 %41, 4
|
||||
%42 = and i16 1, %lshrl15
|
||||
%trunc16 = trunc i16 %42 to i8
|
||||
store i8 %trunc16, ptr %taddr17, align 1
|
||||
%43 = insertvalue %any undef, ptr %taddr17, 0
|
||||
%44 = insertvalue %any %43, i64 ptrtoint (ptr @"$ct.bool" to i64), 1
|
||||
%45 = getelementptr inbounds [4 x %any], ptr %varargslots5, i64 0, i64 3
|
||||
store %any %44, ptr %45, align 16
|
||||
%46 = call i64 @std.io.printfn(ptr %retparam4, ptr @.str.1, i64 12, ptr %varargslots5, i64 4)
|
||||
ret void
|
||||
}
|
||||
|
||||
@@ -2,5 +2,5 @@ module testing;
|
||||
|
||||
fn void main()
|
||||
{
|
||||
(void){}; // #error: foekfoe
|
||||
(void){}; // #error: cannot use compound literal initialization
|
||||
}
|
||||
Reference in New Issue
Block a user