mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 03:51:18 +00:00
Updates to bitstruct
This commit is contained in:
committed by
Christoffer Lerno
parent
15f902579b
commit
4662133893
@@ -95,6 +95,7 @@ const char *decl_to_name(Decl *decl)
|
||||
case VARDECL_PARAM:
|
||||
return "parameter";
|
||||
case VARDECL_MEMBER:
|
||||
case VARDECL_BITMEMBER:
|
||||
return "member";
|
||||
case VARDECL_PARAM_CT:
|
||||
return "compile time parameter";
|
||||
|
||||
@@ -1774,6 +1774,7 @@ static inline bool decl_var_is_assignable(Decl *decl)
|
||||
case VARDECL_LOCAL_CT_TYPE:
|
||||
case VARDECL_UNWRAPPED:
|
||||
return true;
|
||||
case VARDECL_BITMEMBER:
|
||||
case VARDECL_CONST:
|
||||
case VARDECL_MEMBER:
|
||||
case VARDECL_PARAM_EXPR:
|
||||
|
||||
@@ -582,19 +582,20 @@ typedef enum
|
||||
typedef enum
|
||||
{
|
||||
VARDECL_CONST = 0,
|
||||
VARDECL_GLOBAL = 1,
|
||||
VARDECL_LOCAL = 2,
|
||||
VARDECL_PARAM = 3,
|
||||
VARDECL_MEMBER = 4,
|
||||
VARDECL_PARAM_CT = 5,
|
||||
VARDECL_PARAM_CT_TYPE = 6,
|
||||
VARDECL_PARAM_REF = 7,
|
||||
VARDECL_PARAM_EXPR = 8,
|
||||
VARDECL_LOCAL_CT = 9,
|
||||
VARDECL_LOCAL_CT_TYPE = 10,
|
||||
VARDECL_UNWRAPPED = 11,
|
||||
VARDECL_ERASE = 12,
|
||||
VARDECL_REWRAPPED = 13,
|
||||
VARDECL_GLOBAL,
|
||||
VARDECL_LOCAL,
|
||||
VARDECL_PARAM,
|
||||
VARDECL_MEMBER,
|
||||
VARDECL_BITMEMBER,
|
||||
VARDECL_PARAM_CT,
|
||||
VARDECL_PARAM_CT_TYPE,
|
||||
VARDECL_PARAM_REF,
|
||||
VARDECL_PARAM_EXPR,
|
||||
VARDECL_LOCAL_CT,
|
||||
VARDECL_LOCAL_CT_TYPE,
|
||||
VARDECL_UNWRAPPED,
|
||||
VARDECL_ERASE,
|
||||
VARDECL_REWRAPPED,
|
||||
} VarDeclKind;
|
||||
|
||||
typedef enum
|
||||
|
||||
@@ -1681,6 +1681,47 @@ void lexer_init_with_file(Lexer *lexer, File *file)
|
||||
lexer->current_line = 1;
|
||||
lexer->line_start = lexer->current;
|
||||
lexer->lexer_index = file->token_start_id;
|
||||
const unsigned char *check = (const unsigned char *)lexer->current;
|
||||
unsigned c;
|
||||
int balance = 0;
|
||||
while ((c = *(check++)) != '\0')
|
||||
{
|
||||
if (c != 0xE2) continue;
|
||||
unsigned char type = check[1];
|
||||
switch (check[0])
|
||||
{
|
||||
case 0x80:
|
||||
if (type == 0xAC)
|
||||
{
|
||||
balance--;
|
||||
if (balance < 0) goto DONE;
|
||||
}
|
||||
if (type >= 0xAA && type <= 0xAE)
|
||||
{
|
||||
balance++;
|
||||
}
|
||||
break;
|
||||
case 0x81:
|
||||
if (type >= 0xA6 && type <= 0xA8)
|
||||
{
|
||||
balance++;
|
||||
}
|
||||
else if (type == 0xA9)
|
||||
{
|
||||
balance--;
|
||||
if (balance < 0) goto DONE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
DONE:
|
||||
if (balance != 0)
|
||||
{
|
||||
add_error_token(lexer, "Invalid encoding - Unbalanced bidirectional markers.");
|
||||
return;
|
||||
}
|
||||
while(1)
|
||||
{
|
||||
if (!lexer_scan_token_inner(lexer, LEX_NORMAL))
|
||||
|
||||
@@ -601,6 +601,36 @@ static void gencontext_emit_member_addr(GenContext *c, BEValue *value, Decl *par
|
||||
} while (found != member);
|
||||
}
|
||||
|
||||
static void llvm_emit_bitstruct_member(GenContext *c, BEValue *value, Decl *parent, Decl *member)
|
||||
{
|
||||
assert(member->resolve_status == RESOLVE_DONE);
|
||||
Decl *found = NULL;
|
||||
do
|
||||
{
|
||||
int index = find_member_index(parent, member);
|
||||
assert(index > -1);
|
||||
found = parent->strukt.members[index];
|
||||
switch (parent->type->canonical->type_kind)
|
||||
{
|
||||
case TYPE_UNION:
|
||||
llvm_value_addr(c, value);
|
||||
llvm_value_set_address_align(value,
|
||||
llvm_emit_bitcast(c, value->value, type_get_ptr(found->type)),
|
||||
found->type,
|
||||
value->alignment);
|
||||
break;
|
||||
case TYPE_STRUCT:
|
||||
llvm_value_struct_gep(c, value, value, index);
|
||||
break;
|
||||
case TYPE_BITSTRUCT:
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
parent = found;
|
||||
} while (found != member);
|
||||
}
|
||||
|
||||
static LLVMValueRef llvm_emit_bswap(GenContext *c, LLVMValueRef value)
|
||||
{
|
||||
if (LLVMIsConstant(value))
|
||||
@@ -937,8 +967,10 @@ static inline void llvm_emit_bitaccess(GenContext *c, BEValue *be_value, Expr *e
|
||||
Expr *parent = expr->access_expr.parent;
|
||||
llvm_emit_expr(c, be_value, parent);
|
||||
|
||||
Decl *member = expr->access_expr.ref;
|
||||
assert(be_value && be_value->type);
|
||||
|
||||
llvm_emit_bitstruct_member(c, be_value, type_flatten(parent->type)->decl, member);
|
||||
llvm_extract_bitvalue(c, be_value, parent, expr->access_expr.ref);
|
||||
}
|
||||
|
||||
@@ -4502,6 +4534,7 @@ static inline void llvm_emit_macro_block(GenContext *context, BEValue *be_value,
|
||||
case VARDECL_UNWRAPPED:
|
||||
case VARDECL_REWRAPPED:
|
||||
case VARDECL_ERASE:
|
||||
case VARDECL_BITMEMBER:
|
||||
UNREACHABLE
|
||||
case VARDECL_PARAM_REF:
|
||||
{
|
||||
|
||||
@@ -1406,7 +1406,7 @@ static inline bool parse_bitstruct_body(Context *context, Decl *decl)
|
||||
SEMA_TOKEN_ERROR(context->tok, "Expected a field name at this position.");
|
||||
return false;
|
||||
}
|
||||
Decl *member_decl = decl_new_var(context->prev_tok, type, VARDECL_MEMBER, VISIBLE_LOCAL);
|
||||
Decl *member_decl = decl_new_var(context->prev_tok, type, VARDECL_BITMEMBER, VISIBLE_LOCAL);
|
||||
CONSUME_OR(TOKEN_COLON, false);
|
||||
ASSIGN_EXPR_ELSE(member_decl->var.start, parse_constant_expr(context), false);
|
||||
if (try_consume(context, TOKEN_DOTDOT))
|
||||
|
||||
@@ -484,6 +484,7 @@ static inline bool sema_analyse_bitstruct_member(Context *context, Decl *decl, u
|
||||
return false;
|
||||
}
|
||||
}
|
||||
member->resolve_status = RESOLVE_DONE;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1276,6 +1277,7 @@ static inline bool sema_analyse_macro(Context *context, Decl *decl)
|
||||
case VARDECL_GLOBAL:
|
||||
case VARDECL_LOCAL:
|
||||
case VARDECL_MEMBER:
|
||||
case VARDECL_BITMEMBER:
|
||||
case VARDECL_LOCAL_CT:
|
||||
case VARDECL_LOCAL_CT_TYPE:
|
||||
case VARDECL_UNWRAPPED:
|
||||
@@ -1310,6 +1312,7 @@ static inline bool sema_analyse_macro(Context *context, Decl *decl)
|
||||
case VARDECL_GLOBAL:
|
||||
case VARDECL_LOCAL:
|
||||
case VARDECL_MEMBER:
|
||||
case VARDECL_BITMEMBER:
|
||||
case VARDECL_LOCAL_CT:
|
||||
case VARDECL_LOCAL_CT_TYPE:
|
||||
case VARDECL_UNWRAPPED:
|
||||
|
||||
@@ -129,6 +129,7 @@ static inline bool expr_unary_addr_is_constant_eval(Expr *expr, ConstantEvalKind
|
||||
return decl->var.is_static;
|
||||
case VARDECL_PARAM:
|
||||
case VARDECL_MEMBER:
|
||||
case VARDECL_BITMEMBER:
|
||||
case VARDECL_PARAM_CT:
|
||||
case VARDECL_PARAM_CT_TYPE:
|
||||
case VARDECL_PARAM_REF:
|
||||
@@ -468,6 +469,7 @@ bool expr_is_ltype(Expr *expr)
|
||||
return true;
|
||||
case VARDECL_CONST:
|
||||
case VARDECL_MEMBER:
|
||||
case VARDECL_BITMEMBER:
|
||||
case VARDECL_PARAM_CT:
|
||||
case VARDECL_PARAM_CT_TYPE:
|
||||
case VARDECL_PARAM_EXPR:
|
||||
@@ -582,6 +584,7 @@ static inline bool sema_cast_ident_rvalue(Context *context, Expr *expr)
|
||||
case VARDECL_LOCAL:
|
||||
case VARDECL_UNWRAPPED:
|
||||
return true;
|
||||
case VARDECL_BITMEMBER:
|
||||
case VARDECL_MEMBER:
|
||||
SEMA_ERROR(expr, "Expected '%s' followed by a method call or property.", decl->name);
|
||||
return expr_poison(expr);
|
||||
@@ -1406,6 +1409,7 @@ static inline bool sema_expr_analyse_call_invocation(Context *context, Expr *cal
|
||||
case VARDECL_GLOBAL:
|
||||
case VARDECL_LOCAL:
|
||||
case VARDECL_MEMBER:
|
||||
case VARDECL_BITMEMBER:
|
||||
case VARDECL_LOCAL_CT:
|
||||
case VARDECL_LOCAL_CT_TYPE:
|
||||
case VARDECL_UNWRAPPED:
|
||||
@@ -2750,7 +2754,7 @@ CHECK_DEEPER:
|
||||
}
|
||||
|
||||
// Transform bitstruct access to expr_bitaccess.
|
||||
if (decl->decl_kind == DECL_BITSTRUCT)
|
||||
if (member->var.kind == VARDECL_BITMEMBER)
|
||||
{
|
||||
expr->expr_kind = EXPR_BITACCESS;
|
||||
}
|
||||
@@ -2759,6 +2763,7 @@ CHECK_DEEPER:
|
||||
expr->access_expr.parent = current_parent;
|
||||
expr->type = type_get_opt_fail(member->type, failable);
|
||||
expr->access_expr.ref = member;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2838,12 +2843,13 @@ static int64_t sema_analyse_designator_index(Context *context, Expr *index)
|
||||
return index_val;
|
||||
}
|
||||
|
||||
static Type *sema_find_type_of_element(Context *context, Type *type, DesignatorElement **elements, unsigned *curr_index, bool *is_constant, bool *did_report_error, ArrayIndex *max_index)
|
||||
static Type *sema_find_type_of_element(Context *context, Type *type, DesignatorElement **elements, unsigned *curr_index, bool *is_constant, bool *did_report_error, ArrayIndex *max_index, Decl **member_ptr)
|
||||
{
|
||||
Type *type_flattened = type_flatten(type);
|
||||
DesignatorElement *element = elements[*curr_index];
|
||||
if (element->kind == DESIGNATOR_ARRAY || element->kind == DESIGNATOR_RANGE)
|
||||
{
|
||||
*member_ptr = NULL;
|
||||
ByteSize len;
|
||||
Type *base;
|
||||
switch (type_flattened->type_kind)
|
||||
@@ -2909,26 +2915,30 @@ static Type *sema_find_type_of_element(Context *context, Type *type, DesignatorE
|
||||
return NULL;
|
||||
}
|
||||
Decl *member = sema_resolve_element_for_name(type_flattened->decl->strukt.members, elements, curr_index);
|
||||
*member_ptr = member;
|
||||
if (!member) return NULL;
|
||||
return member->type;
|
||||
}
|
||||
|
||||
static Type *sema_expr_analyse_designator(Context *context, Type *current, Expr *expr, ArrayIndex *max_index)
|
||||
static Type *sema_expr_analyse_designator(Context *context, Type *current, Expr *expr, ArrayIndex *max_index, Decl **member_ptr)
|
||||
{
|
||||
DesignatorElement **path = expr->designator_expr.path;
|
||||
|
||||
// Walk down into this path
|
||||
bool is_constant = true;
|
||||
bool did_report_error = false;
|
||||
*member_ptr = NULL;
|
||||
for (unsigned i = 0; i < vec_size(path); i++)
|
||||
{
|
||||
Type *new_current = sema_find_type_of_element(context, current, path, &i, &is_constant, &did_report_error, i == 0 ? max_index : NULL);
|
||||
Decl *member_found;
|
||||
Type *new_current = sema_find_type_of_element(context, current, path, &i, &is_constant, &did_report_error, i == 0 ? max_index : NULL, &member_found);
|
||||
if (!new_current)
|
||||
{
|
||||
if (!did_report_error) SEMA_ERROR(expr, "This is not a valid member of '%s'.", type_to_error_string(current));
|
||||
return NULL;
|
||||
}
|
||||
current = new_current;
|
||||
*member_ptr = member_found;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
@@ -3231,17 +3241,23 @@ static bool sema_expr_analyse_designated_initializer(Context *context, Type *ass
|
||||
{
|
||||
Expr **init_expressions = initializer->designated_init_list;
|
||||
Type *original = assigned->canonical;
|
||||
bool is_structlike = type_is_structlike(assigned->canonical);
|
||||
|
||||
bool is_bitstruct = original->type_kind == TYPE_BITSTRUCT;
|
||||
bool is_structlike = type_is_structlike(original) || is_bitstruct;
|
||||
ArrayIndex max_index = -1;
|
||||
bool failable = false;
|
||||
VECEACH(init_expressions, i)
|
||||
{
|
||||
Expr *expr = init_expressions[i];
|
||||
Type *result = sema_expr_analyse_designator(context, original, expr, &max_index);
|
||||
Decl *member;
|
||||
Type *result = sema_expr_analyse_designator(context, original, expr, &max_index, &member);
|
||||
if (!result) return false;
|
||||
Expr *value = expr->designator_expr.value;
|
||||
if (!sema_analyse_expr_rhs(context, result, value, true)) return false;
|
||||
DesignatorElement *element = VECLAST(expr->designator_expr.path);
|
||||
if (member && member->decl_kind == DECL_VAR && member->var.kind == VARDECL_BITMEMBER)
|
||||
{
|
||||
if (!sema_bit_assignment_check(value, member)) return false;
|
||||
}
|
||||
failable = failable || IS_FAILABLE(value);
|
||||
expr->resolve_status = RESOLVE_DONE;
|
||||
}
|
||||
@@ -3261,6 +3277,32 @@ static bool sema_expr_analyse_designated_initializer(Context *context, Type *ass
|
||||
return true;
|
||||
}
|
||||
|
||||
static int decl_count_elements(Decl *structlike)
|
||||
{
|
||||
int elements = 0;
|
||||
Decl **members = structlike->strukt.members;
|
||||
VECEACH(members, i)
|
||||
{
|
||||
Decl *member = members[i];
|
||||
if (member->decl_kind != DECL_VAR && !member->name)
|
||||
{
|
||||
elements += decl_count_elements(member);
|
||||
continue;
|
||||
}
|
||||
elements++;
|
||||
}
|
||||
return elements;
|
||||
}
|
||||
|
||||
static inline void not_enough_elements(Expr *initializer, int element)
|
||||
{
|
||||
if (element == 0)
|
||||
{
|
||||
SEMA_ERROR(initializer, "The initializer is missing elements.");
|
||||
return;
|
||||
}
|
||||
SEMA_ERROR(initializer->initializer_list[element - 1], "Too few elements in initializer, there should be elements after this one.");
|
||||
}
|
||||
/**
|
||||
* Perform analysis for a plain initializer, that is one initializing all fields.
|
||||
* @return true if analysis succeeds.
|
||||
@@ -3298,31 +3340,76 @@ static inline bool sema_expr_analyse_struct_plain_initializer(Context *context,
|
||||
}
|
||||
}
|
||||
// 3. Loop through all elements.
|
||||
VECEACH(elements, i)
|
||||
int max_loop = MAX(size, expected_members);
|
||||
for (unsigned i = 0; i < max_loop; i++)
|
||||
{
|
||||
// 4. Check if we exceeded the list of elements in the struct/union.
|
||||
// This way we can check the other elements which might help the
|
||||
// user pinpoint where they put the double elements.
|
||||
Expr *element = elements[i];
|
||||
if (i >= expected_members)
|
||||
{
|
||||
SEMA_ERROR(element, "Too many elements in initializer, expected only %d.", expected_members);
|
||||
assert(i < size);
|
||||
SEMA_ERROR(elements[i], "Too many elements in initializer, expected only %d.", expected_members);
|
||||
return false;
|
||||
}
|
||||
// 5. We know the required type, so resolve the expression.
|
||||
// 5. We might have anonymous members
|
||||
Decl *member = members[i];
|
||||
if (member->decl_kind != DECL_VAR && !member->name)
|
||||
{
|
||||
int sub_element_count = decl_count_elements(members[i]);
|
||||
if (!sub_element_count)
|
||||
{
|
||||
vec_add(initializer->initializer_list, NULL);
|
||||
for (int j = size - 1; j > i; j--)
|
||||
{
|
||||
initializer->initializer_list[j] = initializer->initializer_list[j - 1];
|
||||
}
|
||||
Expr *new_initializer = expr_new(EXPR_INITIALIZER_LIST, initializer->span);
|
||||
ConstInitializer *empty = CALLOCS(ConstInitializer);
|
||||
empty->kind = CONST_INIT_ZERO;
|
||||
empty->type = member->type;
|
||||
expr_set_as_const_list(new_initializer, empty);
|
||||
initializer->initializer_list[i] = new_initializer;
|
||||
size += 1;
|
||||
continue;
|
||||
}
|
||||
if (i >= size)
|
||||
{
|
||||
not_enough_elements(initializer, i);
|
||||
return false;
|
||||
}
|
||||
Expr *new_initializer = expr_new(EXPR_INITIALIZER_LIST, elements[i]->span);
|
||||
int max_index_to_copy = MIN(i + sub_element_count, size);
|
||||
for (int j = i; j < max_index_to_copy; j++)
|
||||
{
|
||||
vec_add(new_initializer->initializer_list, elements[j]);
|
||||
}
|
||||
int reduce_by = max_index_to_copy - i - 1;
|
||||
size -= reduce_by;
|
||||
max_loop = MAX(size, expected_members);
|
||||
assert(size <= vec_size(initializer->initializer_list));
|
||||
vec_resize(initializer->initializer_list, size);
|
||||
elements = initializer->initializer_list;
|
||||
elements[i] = new_initializer;
|
||||
}
|
||||
if (i >= size)
|
||||
{
|
||||
not_enough_elements(initializer, i);
|
||||
}
|
||||
Expr *element = elements[i];
|
||||
// 6. We know the required type, so resolve the expression.
|
||||
if (!sema_analyse_expr_rhs(context, members[i]->type, element, true)) return false;
|
||||
if (is_bitstruct && !sema_bit_assignment_check(element, members[i])) return false;
|
||||
if (member->decl_kind == DECL_VAR && member->var.kind == VARDECL_BITMEMBER)
|
||||
{
|
||||
if (!sema_bit_assignment_check(element, members[i])) return false;
|
||||
}
|
||||
failable = failable || IS_FAILABLE(element);
|
||||
}
|
||||
assert(initializer->type);
|
||||
if (failable) initializer->type = type_get_failable(initializer->type);
|
||||
|
||||
// 6. There's the case of too few values as well. Mark the last field as wrong.
|
||||
if (expected_members > size)
|
||||
{
|
||||
SEMA_ERROR(elements[size - 1], "Too few elements in initializer, there should be elements after this one.");
|
||||
return false;
|
||||
}
|
||||
assert(expected_members <= size);
|
||||
|
||||
if (expr_is_constant_eval(initializer, CONSTANT_EVAL_ANY))
|
||||
{
|
||||
@@ -3348,6 +3435,8 @@ static inline bool sema_expr_analyse_struct_plain_initializer(Context *context,
|
||||
|
||||
// 7. Done!
|
||||
return true;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -4798,6 +4887,7 @@ static inline bool sema_take_addr_of_var(Expr *expr, Decl *decl)
|
||||
// May not be reached due to EXPR_CT_IDENT being handled elsewhere.
|
||||
UNREACHABLE;
|
||||
case VARDECL_MEMBER:
|
||||
case VARDECL_BITMEMBER:
|
||||
case VARDECL_UNWRAPPED:
|
||||
case VARDECL_REWRAPPED:
|
||||
case VARDECL_ERASE:
|
||||
@@ -5792,6 +5882,7 @@ static inline bool decl_is_local(Decl *decl)
|
||||
|| kind == VARDECL_LOCAL_CT
|
||||
|| kind == VARDECL_PARAM_REF
|
||||
|| kind == VARDECL_PARAM_EXPR
|
||||
|| kind == VARDECL_BITMEMBER
|
||||
|| kind == VARDECL_MEMBER;
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "A239"
|
||||
#define COMPILER_VERSION "A240"
|
||||
@@ -1,4 +1,3 @@
|
||||
// #skip
|
||||
module foo;
|
||||
|
||||
bitstruct Foo : uint
|
||||
@@ -33,7 +32,7 @@ fn void testNested()
|
||||
Bar2 b3 = { 1, 3 };
|
||||
Bar2 b4 = { .x = 123, .z = 3 };
|
||||
Bar2 b5 = { .x = 123, .z = 4 }; // #error: would be truncated
|
||||
Bar2 b6 = { 1, 3 }; // #error: would be truncated
|
||||
Bar2 b6 = { 1, 4 }; // #error: would be truncated
|
||||
Bar b7 = { 3, { 4 } }; // #error: would be truncated
|
||||
Bar b8 = { .x = 3, .baz.x = 4 }; // #error: would be truncated
|
||||
|
||||
|
||||
87
test/test_suite/bitstruct/embedded_bitstruct.c3t
Normal file
87
test/test_suite/bitstruct/embedded_bitstruct.c3t
Normal file
@@ -0,0 +1,87 @@
|
||||
// #target: x64-darwin
|
||||
|
||||
module foo;
|
||||
|
||||
struct Bar
|
||||
{
|
||||
int x;
|
||||
struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
int y;
|
||||
}
|
||||
struct
|
||||
{}
|
||||
union
|
||||
{
|
||||
struct { }
|
||||
}
|
||||
}
|
||||
bitstruct : uint
|
||||
{
|
||||
int ww : 2..10;
|
||||
}
|
||||
}
|
||||
|
||||
struct Foo
|
||||
{
|
||||
struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
int x;
|
||||
}
|
||||
struct
|
||||
{
|
||||
int y;
|
||||
}
|
||||
int z;
|
||||
}
|
||||
int w;
|
||||
}
|
||||
extern fn void printf(char*, ...);
|
||||
|
||||
fn void main()
|
||||
{
|
||||
Bar b = { 1, 2, -5 };
|
||||
printf("%d %d\n", b.y, b.ww);
|
||||
Foo f = { 5, 6, 7, 8 };
|
||||
printf("%d %d %d %d\n", f.x, f.y, f.z, f.w);
|
||||
}
|
||||
|
||||
/* #expect: foo.ll
|
||||
|
||||
define void @main() #0 {
|
||||
entry:
|
||||
%b = alloca %Bar, align 4
|
||||
%f = alloca %Foo, align 4
|
||||
%0 = bitcast %Bar* %b to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast (%Bar* @.__const to i8*), i32 12, i1 false)
|
||||
%1 = getelementptr inbounds %Bar, %Bar* %b, i32 0, i32 1
|
||||
%2 = getelementptr inbounds %anon, %anon* %1, i32 0, i32 0
|
||||
%3 = getelementptr inbounds %anon.0, %anon.0* %2, i32 0, i32 0
|
||||
%4 = load i32, i32* %3, align 4
|
||||
%5 = getelementptr inbounds %Bar, %Bar* %b, i32 0, i32 2
|
||||
%6 = load i32, i32* %5, align 4
|
||||
%7 = shl i32 %6, 21
|
||||
%8 = ashr i32 %7, 23
|
||||
call void (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str, i32 0, i32 0), i32 %4, i32 %8)
|
||||
%9 = bitcast %Foo* %f to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %9, i8* align 4 bitcast (%Foo* @.__const.8 to i8*), i32 16, i1 false)
|
||||
%10 = getelementptr inbounds %Foo, %Foo* %f, i32 0, i32 0
|
||||
%11 = getelementptr inbounds %anon.4, %anon.4* %10, i32 0, i32 0
|
||||
%12 = getelementptr inbounds %anon.5, %anon.5* %11, i32 0, i32 0
|
||||
%13 = load i32, i32* %12, align 4
|
||||
%14 = getelementptr inbounds %Foo, %Foo* %f, i32 0, i32 0
|
||||
%15 = getelementptr inbounds %anon.4, %anon.4* %14, i32 0, i32 1
|
||||
%16 = getelementptr inbounds %anon.6, %anon.6* %15, i32 0, i32 0
|
||||
%17 = load i32, i32* %16, align 4
|
||||
%18 = getelementptr inbounds %Foo, %Foo* %f, i32 0, i32 0
|
||||
%19 = getelementptr inbounds %anon.4, %anon.4* %18, i32 0, i32 2
|
||||
%20 = load i32, i32* %19, align 4
|
||||
%21 = getelementptr inbounds %Foo, %Foo* %f, i32 0, i32 1
|
||||
%22 = load i32, i32* %21, align 4
|
||||
call void (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.9, i32 0, i32 0), i32 %13, i32 %17, i32 %20, i32 %22)
|
||||
ret void
|
||||
}
|
||||
10
test/test_suite/unicode/commenting-out.c3
Normal file
10
test/test_suite/unicode/commenting-out.c3
Normal file
@@ -0,0 +1,10 @@
|
||||
// #error: Invalid encoding - Unbalanced bidirectional markers.
|
||||
int main() {
|
||||
bool isAdmin = false;
|
||||
/* } if (isAdmin) begin admins only */
|
||||
printf("You are an admin.\n");
|
||||
/* end admins only { */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user