Skip to content

compiler: extend cast syntax for initlists #301

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion analyser/module_analyser_expr.c2
Original file line number Diff line number Diff line change
Expand Up @@ -376,12 +376,36 @@ fn QualType Analyser.analyseExplicitCast(Analyser* ma, Expr** e_ptr) {
TypeRef* ref = c.getTypeRef();
QualType destType = ma.analyseTypeRef(ref);

Expr* inner = c.getInner();
if (inner.isInitList()) {
InitListExpr* initList = cast<InitListExpr*>(inner);
if (destType.isInvalid())
return QualType_Invalid;
if (destType.isArray() || destType.isStruct()) {
if (!ma.analyseInitListExpr(initList, destType))
return QualType_Invalid;
} else {
u32 num_values = initList.getNumValues();
Expr** values = initList.getValues();
if (num_values != 1 || values[0].isInitList()) {
ma.error(inner.getLoc(), "invalid initializer");
return QualType_Invalid;
}
if (!ma.analyseInitExpr(&values[0], destType, values[0].getLoc()))
return QualType_Invalid;
}
e.setLValue();
c.setDestType(destType);
return destType;
}
QualType srcType = ma.analyseExpr(c.getInner2(), true, RHS);

if (srcType.isInvalid() || destType.isInvalid()) return QualType_Invalid;

Expr* inner = c.getInner();
inner = c.getInner();
e.copyConstantFlags(inner);
// TODO: this is probably incorrect: valType should be LValue for reinterpret
// casts and RValue for conversion casts
e.copyValType(inner);
c.setDestType(destType);

Expand Down
3 changes: 2 additions & 1 deletion ast/explicit_cast_expr.c2
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public fn ExplicitCastExpr* ExplicitCastExpr.create(ast_context.Context* c,
{
u32 size = sizeof(ExplicitCastExpr) + ref.getExtraSize();
ExplicitCastExpr* e = c.alloc(size);
// TODO ValType.LValue for compound
e.base.init(ExprKind.ExplicitCast, loc, 0, 0, 0, ValType.NValue);
e.base.base.explicitCastExprBits.c_style = c_style;
e.base.base.explicitCastExprBits.src_len = src_len;
Expand Down Expand Up @@ -81,7 +82,7 @@ fn SrcLoc ExplicitCastExpr.getEndLoc(const ExplicitCastExpr* e) {
return e.base.base.loc + e.base.base.explicitCastExprBits.src_len;
}

fn void ExplicitCastExpr.printLiteral(const ExplicitCastExpr* e, string_buffer.Buf* out) {
public fn void ExplicitCastExpr.printLiteral(const ExplicitCastExpr* e, string_buffer.Buf* out) {
if (e.base.base.explicitCastExprBits.c_style) {
out.add1('(');
e.dest.print(out, true);
Expand Down
2 changes: 1 addition & 1 deletion ast/expr.c2
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ static_assert(elemsof(ExprKind), elemsof(exprKind_names));

/*
An LValue may be on the left/right side of an assignment
An RValue may only be on the left side
An RValue may only be on the right side
An NValue is an abstract object (cannot be used on either side)

Lvalue:
Expand Down
3 changes: 2 additions & 1 deletion generator/c/c2i_generator_expr.c2
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ fn void Generator.emitExpr(Generator* gen, const Expr* e) {
case BitOffset:
break;
case ExplicitCast:
break;
ExplicitCastExpr.printLiteral(cast<ExplicitCastExpr*>(e), out);
return;
case ImplicitCast:
const ImplicitCastExpr* c = cast<ImplicitCastExpr*>(e);
gen.emitExpr(c.getInner());
Expand Down
3 changes: 2 additions & 1 deletion generator/c/c_generator_expr.c2
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ fn void Generator.emitExpr(Generator* gen, string_buffer.Buf* out, Expr* e) {
ExplicitCastExpr* c = cast<ExplicitCastExpr*>(e);
out.add("((");
gen.emitTypePre(out, c.getDestType());
gen.emitTypePost(out, c.getDestType());
if (c.getCStyle()) {
out.add1(')');
gen.emitExpr(out, c.getInner());
Expand All @@ -151,7 +152,7 @@ fn void Generator.emitExpr(Generator* gen, string_buffer.Buf* out, Expr* e) {
gen.emitExpr(out, b.getLHS());
out.print(" ... ");
gen.emitExpr(out, b.getRHS());
return;
break;
}
}

Expand Down
4 changes: 4 additions & 0 deletions generator/ir/ir_generator_expr.c2
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ fn void Generator.emitExpr(Generator* gen, ir.Ref* result, const Expr* e) {
break;
case ExplicitCast:
ExplicitCastExpr* ec = cast<ExplicitCastExpr*>(e);
if (ec.getInner().isInitList()) {
assert(0); // TODO
break;
}
gen.emitExpr(result, ec.getInner());
break;
case ImplicitCast:
Expand Down
12 changes: 7 additions & 5 deletions parser/c2_parser_expr.c2
Original file line number Diff line number Diff line change
Expand Up @@ -527,16 +527,18 @@ fn Expr* Parser.parseParenExpr(Parser* p) {
TypeRefHolder ref.init();
p.parseTypeSpecifier(&ref, true, has_brackets);
p.expectAndConsume(Kind.RParen);
Expr* expr;
if (p.tok.kind == Kind.LBrace) {
// compound literal
p.error("Compound literals are not supported");
expr = p.parseInitList();
} else {
// C cast expression
if (has_brackets) p.error("array types are not allowed here");
Expr* expr = p.parseCastExpr(false, false);
u32 src_len = p.prev_loc - loc;
return p.builder.actOnExplicitCast(loc, src_len, &ref, expr, true);
if (has_brackets)
p.error("cast to array type is invalid");
expr = p.parseCastExpr(false, false);
}
u32 src_len = p.prev_loc - loc;
return p.builder.actOnExplicitCast(loc, src_len, &ref, expr, true);
}

Expr* res = p.parseExpr();
Expand Down
2 changes: 1 addition & 1 deletion test/expr/explicit_cast/explicit_c_cast_array.c2
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
module test;

fn void test1a(i32 a) {
char[2] b1 = (char[2])(a); // @error{array types are not allowed here}
char[2] b1 = (char[2])(a); // @error{cast to array type is invalid}
}

56 changes: 56 additions & 0 deletions test/literals/compound_literals.c2
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// @warnings{no-unused}
module test;

import stdio local;

type Foo struct {
i32 x;
i32 y;
}

fn void test_foo(Foo foo) {}
fn void Foo.bar(Foo* foo) {}
fn Foo Foo.create(i32 x, i32 y) { return (Foo){ x, y }; }

fn i32 sum(i32 *p, u32 count) {
i32 total = 0;
for (i32 i = 0; i < count; i++) total += p[i];
return total;
}

public fn i32 main() {
Foo[] foos = {
{ },
{ 0, 1 },
(Foo){ 1, 2 },
(Foo){ .x = 2, .y = 3 },
[4] = { },
[5] = { 3, 4 },
[6] = (Foo){ 4, 5 },
[7] = (Foo){ .x = 5, .y = 6 },
};

test_foo({});
test_foo({ 1, 2 });
test_foo({ .x = 1, .y = 2 });
test_foo((Foo){});
test_foo((Foo){ 1, 2 });
test_foo((Foo){ .x = 1, .y = 2 });

foos[0].bar();
(Foo){1, 2}.bar();

printf("%d\n", sum((i32[]){ 1 }, 1));
printf("%d\n", sum((i32[]){ 1, 2 }, 2));
printf("%d\n", sum((i32[]){ 1, 2, 3 }, 3));
printf("%d\n", sum((i32[1]){ 1 }, 1));
printf("%d\n", sum((i32[2]){ 1, 2 }, 2));
printf("%d\n", sum((i32[10]){ 1, 2, 3 }, 10));

// Enable these tests once arrays are implied for pointer arguments
//printf("%d\n", sum({ 1 }, 1));
//printf("%d\n", sum({ 1, 2 }, 2));
//printf("%d\n", sum({ 1, 2, 3 }, 3));

return 0;
}