diff --git a/analyser/module_analyser_expr.c2 b/analyser/module_analyser_expr.c2 index 560f82c4..9a68ea9b 100644 --- a/analyser/module_analyser_expr.c2 +++ b/analyser/module_analyser_expr.c2 @@ -420,12 +420,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(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(), false, false)) + 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); diff --git a/ast/explicit_cast_expr.c2 b/ast/explicit_cast_expr.c2 index ace695b1..e1eb0717 100644 --- a/ast/explicit_cast_expr.c2 +++ b/ast/explicit_cast_expr.c2 @@ -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; diff --git a/ast/expr.c2 b/ast/expr.c2 index 6fb57083..d8b45d4c 100644 --- a/ast/expr.c2 +++ b/ast/expr.c2 @@ -75,7 +75,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: diff --git a/generator/c/c_generator_expr.c2 b/generator/c/c_generator_expr.c2 index 6fce9c75..50e7a643 100644 --- a/generator/c/c_generator_expr.c2 +++ b/generator/c/c_generator_expr.c2 @@ -140,7 +140,7 @@ fn void Generator.emitExpr2(Generator* gen, string_buffer.Buf* out, Expr* e, C_P case ExplicitCast: ExplicitCastExpr* c = (ExplicitCastExpr*)e; if (prec > Prefix) out.lparen(); - gen.emitCast(out, c.getDestType(), false); + gen.emitCast(out, c.getDestType(), true); if (c.getCStyle()) { gen.emitExpr2(out, c.getInner(), Prefix); } else { @@ -173,7 +173,7 @@ fn void Generator.emitExpr2(Generator* gen, string_buffer.Buf* out, Expr* e, C_P out.add(" ... "); gen.emitExpr(out, b.getRHS()); if (prec > Assignment) out.rparen(); - return; + break; case NamedArgument: NamedArgument* n = (NamedArgument*)e; gen.emitExpr(out, n.getInner()); diff --git a/generator/ir/ir_generator_expr.c2 b/generator/ir/ir_generator_expr.c2 index bfddd54b..d6344b17 100644 --- a/generator/ir/ir_generator_expr.c2 +++ b/generator/ir/ir_generator_expr.c2 @@ -89,6 +89,10 @@ fn void Generator.emitExpr(Generator* gen, ir.Ref* result, const Expr* e) { break; case ExplicitCast: ExplicitCastExpr* ec = (ExplicitCastExpr*)e; + if (ec.getInner().isInitList()) { + assert(0); // TODO + break; + } gen.emitExpr(result, ec.getInner()); break; case ImplicitCast: diff --git a/parser/c2_parser_expr.c2 b/parser/c2_parser_expr.c2 index 96c676f9..cb977688 100644 --- a/parser/c2_parser_expr.c2 +++ b/parser/c2_parser_expr.c2 @@ -545,16 +545,17 @@ fn Expr* Parser.parseParenExpr(Parser* p) { TypeRefHolder ref.init(); p.parseTypeSpecifier(&ref); 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 (ref.isArray()) 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 (ref.isArray()) 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(); diff --git a/test/expr/explicit_cast/explicit_c_cast_array.c2 b/test/expr/explicit_cast/explicit_c_cast_array.c2 index 52e96a71..cdc2ed54 100644 --- a/test/expr/explicit_cast/explicit_c_cast_array.c2 +++ b/test/expr/explicit_cast/explicit_c_cast_array.c2 @@ -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} } diff --git a/test/expr/explicit_cast/explicit_cast_array.c2 b/test/expr/explicit_cast/explicit_cast_array.c2 index 0460dfdf..d9a53c61 100644 --- a/test/expr/explicit_cast/explicit_cast_array.c2 +++ b/test/expr/explicit_cast/explicit_cast_array.c2 @@ -2,6 +2,6 @@ module test; fn void test1(i32 a) { - char[2] b = (char[2])a; // @error{array types are not allowed here} + char[2] b = (char[2])a; // @error{cast to array type is invalid} } diff --git a/test/literals/compound_literals.c2 b/test/literals/compound_literals.c2 new file mode 100644 index 00000000..8129525c --- /dev/null +++ b/test/literals/compound_literals.c2 @@ -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; +}