diff --git a/src/libponyc/codegen/gentype.c b/src/libponyc/codegen/gentype.c index db6a6da6028..81a9fa12c0f 100644 --- a/src/libponyc/codegen/gentype.c +++ b/src/libponyc/codegen/gentype.c @@ -407,6 +407,7 @@ static bool make_struct(compile_t* c, reach_type_t* t) { LLVMTypeRef type; int extra = 0; + bool packed = false; switch(t->underlying) { @@ -421,12 +422,18 @@ static bool make_struct(compile_t* c, reach_type_t* t) break; case TK_STRUCT: + { // Pointer and Maybe will have no structure. if(t->structure == NULL) return true; type = t->structure; + ast_t* def = (ast_t*)ast_data(t->ast); + if(ast_has_annotation(def, "packed")) + packed = true; + break; + } case TK_PRIMITIVE: // Machine words will have a primitive. @@ -481,7 +488,7 @@ static bool make_struct(compile_t* c, reach_type_t* t) } } - LLVMStructSetBody(type, elements, t->field_count + extra, false); + LLVMStructSetBody(type, elements, t->field_count + extra, packed); ponyint_pool_free_size(buf_size, elements); return true; } diff --git a/test/libponyc/codegen.cc b/test/libponyc/codegen.cc new file mode 100644 index 00000000000..75e10053a9e --- /dev/null +++ b/test/libponyc/codegen.cc @@ -0,0 +1,105 @@ +#include +#include + +#include + +#include "util.h" + +#ifdef _MSC_VER +// Stop MSVC from complaining about conversions from LLVMBool to bool. +# pragma warning(disable:4800) +#endif + +#define TEST_COMPILE(src) DO(test_compile(src, "ir")) + + +class CodegenTest : public PassTest +{}; + + +TEST_F(CodegenTest, PackedStructIsPacked) +{ + const char* src = + "struct \\packed\\ Foo\n" + " var a: U8 = 0\n" + " var b: U32 = 0\n" + + "actor Main\n" + " new create(env: Env) =>\n" + " Foo"; + + TEST_COMPILE(src); + + reach_t* reach = compile->reach; + reach_type_t* foo = reach_type_name(reach, "Foo"); + ASSERT_TRUE(foo != NULL); + + LLVMTypeRef type = foo->structure; + ASSERT_TRUE(LLVMIsPackedStruct(type)); +} + + +TEST_F(CodegenTest, NonPackedStructIsntPacked) +{ + const char* src = + "struct Foo\n" + " var a: U8 = 0\n" + " var b: U32 = 0\n" + + "actor Main\n" + " new create(env: Env) =>\n" + " Foo"; + + TEST_COMPILE(src); + + reach_t* reach = compile->reach; + reach_type_t* foo = reach_type_name(reach, "Foo"); + ASSERT_TRUE(foo != NULL); + + LLVMTypeRef type = foo->structure; + ASSERT_TRUE(!LLVMIsPackedStruct(type)); +} + + +TEST_F(CodegenTest, ClassCannotBePacked) +{ + const char* src = + "class \\packed\\ Foo\n" + " var a: U8 = 0\n" + " var b: U32 = 0\n" + + "actor Main\n" + " new create(env: Env) =>\n" + " Foo"; + + TEST_COMPILE(src); + + reach_t* reach = compile->reach; + reach_type_t* foo = reach_type_name(reach, "Foo"); + ASSERT_TRUE(foo != NULL); + + LLVMTypeRef type = foo->structure; + ASSERT_TRUE(!LLVMIsPackedStruct(type)); +} + + +TEST_F(CodegenTest, ActorCannotBePacked) +{ + const char* src = + "actor \\packed\\ Foo\n" + " var a: U8 = 0\n" + " var b: U32 = 0\n" + + "actor Main\n" + " new create(env: Env) =>\n" + " Foo"; + + TEST_COMPILE(src); + + reach_t* reach = compile->reach; + reach_type_t* foo = reach_type_name(reach, "Foo"); + ASSERT_TRUE(foo != NULL); + + LLVMTypeRef type = foo->structure; + ASSERT_TRUE(!LLVMIsPackedStruct(type)); +}