diff --git a/integration_tests/CMakeLists.txt b/integration_tests/CMakeLists.txt index 2a08363d08..0e85f2d872 100644 --- a/integration_tests/CMakeLists.txt +++ b/integration_tests/CMakeLists.txt @@ -374,6 +374,9 @@ RUN(NAME bindc_04 LABELS llvm c NOFAST) RUN(NAME bindc_07 LABELS cpython llvm c NOFAST) RUN(NAME bindc_08 LABELS cpython llvm c) RUN(NAME bindc_09 LABELS cpython llvm c) +RUN(NAME bindc_09b LABELS cpython llvm c) +RUN(NAME bindc_10 LABELS cpython llvm c NOFAST) +RUN(NAME bindc_11 LABELS cpython) # This is CPython test only RUN(NAME exit_01 LABELS cpython llvm c NOFAST) RUN(NAME exit_02 FAIL LABELS cpython llvm c NOFAST) RUN(NAME exit_03 LABELS cpython llvm c wasm wasm_x86 wasm_x64) @@ -457,6 +460,7 @@ RUN(NAME test_list_repeat LABELS cpython llvm NOFAST) RUN(NAME test_list_reverse LABELS cpython llvm) RUN(NAME test_list_pop LABELS cpython llvm NOFAST) # TODO: Remove NOFAST from here. RUN(NAME test_list_pop2 LABELS cpython llvm NOFAST) # TODO: Remove NOFAST from here. +RUN(NAME test_list_compare LABELS cpython llvm) RUN(NAME test_tuple_01 LABELS cpython llvm c) RUN(NAME test_tuple_02 LABELS cpython llvm c NOFAST) RUN(NAME test_tuple_03 LABELS cpython llvm c) @@ -565,6 +569,7 @@ RUN(NAME test_bool_binop LABELS cpython llvm c) RUN(NAME test_issue_518 LABELS cpython llvm c NOFAST) RUN(NAME structs_01 LABELS cpython llvm c) RUN(NAME structs_02 LABELS cpython llvm c) +RUN(NAME structs_02b LABELS cpython llvm c NOFAST) RUN(NAME structs_03 LABELS llvm c) RUN(NAME structs_04 LABELS cpython llvm c) RUN(NAME structs_05 LABELS cpython llvm c) @@ -600,6 +605,7 @@ RUN(NAME structs_29 LABELS cpython llvm) RUN(NAME structs_30 LABELS cpython llvm c) RUN(NAME structs_31 LABELS cpython llvm c) RUN(NAME structs_32 LABELS cpython llvm c) +RUN(NAME structs_33 LABELS cpython llvm c) RUN(NAME symbolics_01 LABELS cpython_sym c_sym) RUN(NAME symbolics_02 LABELS cpython_sym c_sym) diff --git a/integration_tests/bindc_09.py b/integration_tests/bindc_09.py index 18fdaad29e..956b56b658 100644 --- a/integration_tests/bindc_09.py +++ b/integration_tests/bindc_09.py @@ -1,6 +1,7 @@ from enum import Enum -from lpython import CPtr, c_p_pointer, p_c_pointer, dataclass, empty_c_void_p, pointer, Pointer, i32, ccallable +from lpython import (CPtr, c_p_pointer, p_c_pointer, dataclass, empty_c_void_p, + pointer, Pointer, i32, ccallable, InOut) class Value(Enum): TEN: i32 = 10 @@ -17,8 +18,7 @@ class Foo: class FooC: value: Value -def bar(foo_ptr: CPtr) -> None: - foo: Pointer[Foo] = c_p_pointer(foo_ptr, Foo) +def bar(foo: InOut[Foo]) -> None: foo.value = Value.FIVE def barc(foo_ptr: CPtr) -> None: @@ -30,8 +30,7 @@ def main() -> None: fooc: FooC = FooC(Value.TWO) foo_ptr: CPtr = empty_c_void_p() - p_c_pointer(pointer(foo), foo_ptr) - bar(foo_ptr) + bar(foo) print(foo.value, foo.value.name) assert foo.value == Value.FIVE diff --git a/integration_tests/bindc_09b.py b/integration_tests/bindc_09b.py new file mode 100644 index 0000000000..58be1e768b --- /dev/null +++ b/integration_tests/bindc_09b.py @@ -0,0 +1,44 @@ +from enum import Enum + +from lpython import CPtr, c_p_pointer, p_c_pointer, dataclass, empty_c_void_p, pointer, Pointer, i32, ccallable + +class Value(Enum): + TEN: i32 = 10 + TWO: i32 = 2 + ONE: i32 = 1 + FIVE: i32 = 5 + +@ccallable +@dataclass +class Foo: + value: Value + +@ccallable +@dataclass +class FooC: + value: Value + +def bar(foo_ptr: CPtr) -> None: + foo: Pointer[Foo] = c_p_pointer(foo_ptr, Foo) + foo.value = Value.FIVE + +def barc(foo_ptr: CPtr) -> None: + foo: Pointer[FooC] = c_p_pointer(foo_ptr, FooC) + foo.value = Value.ONE + +def main() -> None: + foo: Foo = Foo(Value.TEN) + fooc: FooC = FooC(Value.TWO) + foo_ptr: CPtr = empty_c_void_p() + + p_c_pointer(pointer(foo), foo_ptr) + bar(foo_ptr) + print(foo.value) + assert foo.value == Value.FIVE.value + + p_c_pointer(pointer(fooc), foo_ptr) + barc(foo_ptr) + print(fooc.value) + assert fooc.value == Value.ONE.value + +main() diff --git a/integration_tests/bindc_10.py b/integration_tests/bindc_10.py new file mode 100644 index 0000000000..934eacfd43 --- /dev/null +++ b/integration_tests/bindc_10.py @@ -0,0 +1,32 @@ +from lpython import (i64, i16, CPtr, c_p_pointer, Pointer, sizeof, packed, + dataclass, ccallable, ccall, i32) + +@ccall +def _lfortran_malloc(size: i32) -> CPtr: + pass + + +def alloc(buf_size:i64) -> CPtr: + return _lfortran_malloc(i32(buf_size)) + + +@ccallable +@packed +@dataclass +class S: + a: i16 + b: i64 + + +def main(): + p1: CPtr = alloc(sizeof(S)) + print(p1) + p2: Pointer[S] = c_p_pointer(p1, S) + p2.a = i16(5) + p2.b = i64(4) + print(p2.a, p2.b) + assert p2.a == i16(5) + assert p2.b == i64(4) + + +main() diff --git a/integration_tests/bindc_11.py b/integration_tests/bindc_11.py new file mode 100644 index 0000000000..c2e81c9a0a --- /dev/null +++ b/integration_tests/bindc_11.py @@ -0,0 +1,34 @@ +import numpy, ctypes +from lpython import (i64, i16, CPtr, c_p_pointer, Pointer, sizeof, packed, + dataclass, ccallable, ccall, i32) + +global_arrays = [] + + +def alloc(buf_size:i64) -> CPtr: + xs = numpy.empty(buf_size, dtype=numpy.uint8) + global_arrays.append(xs) + p = ctypes.c_void_p(xs.ctypes.data) + return ctypes.cast(p.value, ctypes.c_void_p) + + +@ccallable +@packed +@dataclass +class S: + a: i16 + b: i64 + + +def main(): + p1: CPtr = alloc(sizeof(S)) + print(p1) + p2: Pointer[S] = c_p_pointer(p1, S) + p2.a = i16(5) + p2.b = i64(4) + print(p2.a, p2.b) + assert p2.a == i16(5) + assert p2.b == i64(4) + + +main() diff --git a/integration_tests/structs_02.py b/integration_tests/structs_02.py index f3325d6a9a..0e99458c34 100644 --- a/integration_tests/structs_02.py +++ b/integration_tests/structs_02.py @@ -17,8 +17,6 @@ def f(a: CPtr) -> None: y = a2.y assert x == 3 assert f64(y) == 3.25 - a2 = c_p_pointer(a, A) - print(a, a2, pointer(a1)) def g(): b: CPtr = empty_c_void_p() diff --git a/integration_tests/structs_02b.py b/integration_tests/structs_02b.py new file mode 100644 index 0000000000..ed061ff6ce --- /dev/null +++ b/integration_tests/structs_02b.py @@ -0,0 +1,43 @@ +from lpython import (i32, f32, dataclass, CPtr, Pointer, c_p_pointer, pointer, + ccallable, empty_c_void_p, f64, ccall, sizeof, i64) + +@ccall +def _lfortran_malloc(size: i32) -> CPtr: + pass + +def alloc(buf_size:i64) -> CPtr: + return _lfortran_malloc(i32(buf_size)) + +@ccallable +@dataclass +class A: + x: i32 + y: f32 + +@ccallable +def f(a: CPtr) -> None: + x: i32 + y: f32 + a1: A = A(3, f32(3.25)) + a2: Pointer[A] + a2 = pointer(a1) + print(a2, pointer(a1)) + # TODO: does not work: + #x = a2.x + #y = a2.y + #assert x == 3 + #assert f64(y) == 3.25 + a2 = c_p_pointer(a, A) + print(a, a2, pointer(a1)) + print(a2.x, a2.y) + assert a2.x == 5 + assert a2.y == f32(6.0) + +def g(): + b: CPtr = alloc(sizeof(A)) + b2: Pointer[A] = c_p_pointer(b, A) + b2.x = 5 + b2.y = f32(6) + f(b) + +g() diff --git a/integration_tests/structs_13.py b/integration_tests/structs_13.py index 651518fc05..9806fa1ac9 100644 --- a/integration_tests/structs_13.py +++ b/integration_tests/structs_13.py @@ -1,6 +1,8 @@ -from lpython import i32, i16, i64, CPtr, dataclass, ccall, Pointer, c_p_pointer, sizeof +from lpython import (i32, i16, i64, CPtr, dataclass, ccall, Pointer, + c_p_pointer, sizeof, ccallable) from numpy import array +@ccallable @dataclass class A: x: i32 diff --git a/integration_tests/structs_33.py b/integration_tests/structs_33.py new file mode 100644 index 0000000000..c8f02cb8e6 --- /dev/null +++ b/integration_tests/structs_33.py @@ -0,0 +1,24 @@ +from lpython import packed, dataclass, i32, ccallback, CPtr, ccall + +# test issue 2125 + +@packed +@dataclass +class inner_struct: + inner_field: i32 = 0 + + +@packed +@dataclass +class outer_struct: + inner_s : inner_struct = inner_struct() + + +def check() -> None: + outer_struct_instance : outer_struct = outer_struct(inner_struct(5)) + outer_struct_instance2 : outer_struct = outer_struct_instance + inner_struct_instance : inner_struct = outer_struct_instance2.inner_s + assert inner_struct_instance.inner_field == 5 + + +check() diff --git a/integration_tests/test_list_compare.py b/integration_tests/test_list_compare.py new file mode 100644 index 0000000000..24fcc485d5 --- /dev/null +++ b/integration_tests/test_list_compare.py @@ -0,0 +1,53 @@ +from lpython import i32, f64 + +def test_list_compare(): + l1: list[i32] = [1, 2, 3] + l2: list[i32] = [1, 2, 3, 4] + l3: list[tuple[i32, f64, str]] = [(1, 2.0, 'a'), (3, 4.0, 'b')] + l4: list[tuple[i32, f64, str]] = [(1, 3.0, 'a')] + l5: list[list[str]] = [[''], ['']] + l6: list[str] = [] + l7: list[str] = [] + t1: tuple[i32, i32] + t2: tuple[i32, i32] + i: i32 + + assert l1 < l2 and l1 <= l2 + assert not l1 > l2 and not l1 >= l2 + i = l2.pop() + i = l2.pop() + assert l2 < l1 and l1 > l2 and l1 >= l2 + assert not (l1 < l2) + + l1 = [3, 4, 5] + l2 = [1, 6, 7] + assert l1 > l2 and l1 >= l2 + assert not l1 < l2 and not l1 <= l2 + + l1 = l2 + assert l1 == l2 and l1 <= l2 and l1 >= l2 + assert not l1 < l2 and not l1 > l2 + + assert l4 > l3 and l4 >= l3 + l4[0] = l3[0] + assert l4 < l3 + + for i in range(0, 10): + if i % 2 == 0: + l6.append('a') + else: + l7.append('a') + l5[0] = l6 + l5[1] = l7 + if i % 2 == 0: + assert l5[1 - i % 2] < l5[i % 2] + assert l5[1 - i % 2] <= l5[i % 2] + assert not l5[1 - i % 2] > l5[i % 2] + assert not l5[1 - i % 2] >= l5[i % 2] + + t1 = (1, 2) + t2 = (2, 3) + assert t1 < t2 and t1 <= t2 + assert not t1 > t2 and not t1 >= t2 + +test_list_compare() \ No newline at end of file diff --git a/src/bin/lpython.cpp b/src/bin/lpython.cpp index 4eca2b4da3..013c89e04f 100644 --- a/src/bin/lpython.cpp +++ b/src/bin/lpython.cpp @@ -44,6 +44,9 @@ #include #include #endif + +extern std::string lcompilers_unique_ID; + namespace { using LCompilers::endswith; @@ -54,6 +57,7 @@ enum class Backend { llvm, cpp, c, x86, wasm, wasm_x86, wasm_x64 }; + std::string remove_extension(const std::string& filename) { size_t lastdot = filename.find_last_of("."); if (lastdot == std::string::npos) return filename; @@ -1610,6 +1614,9 @@ int main(int argc, char *argv[]) app.require_subcommand(0, 1); CLI11_PARSE(app, argc, argv); + lcompilers_unique_ID = LCompilers::get_unique_ID(); + + if( compiler_options.fast && compiler_options.enable_bounds_checking ) { // ReleaseSafe Mode } else if ( compiler_options.fast ) { diff --git a/src/libasr/asr_scopes.cpp b/src/libasr/asr_scopes.cpp index acbb50d9c6..ebd3b7c476 100644 --- a/src/libasr/asr_scopes.cpp +++ b/src/libasr/asr_scopes.cpp @@ -4,6 +4,8 @@ #include #include +std::string lcompilers_unique_ID; + namespace LCompilers { template< typename T > diff --git a/src/libasr/codegen/asr_to_llvm.cpp b/src/libasr/codegen/asr_to_llvm.cpp index 1170bb491f..3cd6826cad 100644 --- a/src/libasr/codegen/asr_to_llvm.cpp +++ b/src/libasr/codegen/asr_to_llvm.cpp @@ -1427,10 +1427,31 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor this->visit_expr(*x.m_right); llvm::Value* right = tmp; ptr_loads = ptr_loads_copy; - tmp = llvm_utils->is_equal_by_value(left, right, *module, - ASRUtils::expr_type(x.m_left)); - if (x.m_op == ASR::cmpopType::NotEq) { - tmp = builder->CreateNot(tmp); + + ASR::ttype_t* int32_type = ASRUtils::TYPE(ASR::make_Integer_t(al, x.base.base.loc, 4)); + + if(x.m_op == ASR::cmpopType::Eq || x.m_op == ASR::cmpopType::NotEq) { + tmp = llvm_utils->is_equal_by_value(left, right, *module, + ASRUtils::expr_type(x.m_left)); + if (x.m_op == ASR::cmpopType::NotEq) { + tmp = builder->CreateNot(tmp); + } + } + else if(x.m_op == ASR::cmpopType::Lt) { + tmp = llvm_utils->is_ineq_by_value(left, right, *module, + ASRUtils::expr_type(x.m_left), 0, int32_type); + } + else if(x.m_op == ASR::cmpopType::LtE) { + tmp = llvm_utils->is_ineq_by_value(left, right, *module, + ASRUtils::expr_type(x.m_left), 1, int32_type); + } + else if(x.m_op == ASR::cmpopType::Gt) { + tmp = llvm_utils->is_ineq_by_value(left, right, *module, + ASRUtils::expr_type(x.m_left), 2, int32_type); + } + else if(x.m_op == ASR::cmpopType::GtE) { + tmp = llvm_utils->is_ineq_by_value(left, right, *module, + ASRUtils::expr_type(x.m_left), 3, int32_type); } } @@ -1761,10 +1782,28 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor this->visit_expr(*x.m_right); llvm::Value* right = tmp; ptr_loads = ptr_loads_copy; - tmp = llvm_utils->is_equal_by_value(left, right, *module, - ASRUtils::expr_type(x.m_left)); - if (x.m_op == ASR::cmpopType::NotEq) { - tmp = builder->CreateNot(tmp); + if(x.m_op == ASR::cmpopType::Eq || x.m_op == ASR::cmpopType::NotEq) { + tmp = llvm_utils->is_equal_by_value(left, right, *module, + ASRUtils::expr_type(x.m_left)); + if (x.m_op == ASR::cmpopType::NotEq) { + tmp = builder->CreateNot(tmp); + } + } + else if(x.m_op == ASR::cmpopType::Lt) { + tmp = llvm_utils->is_ineq_by_value(left, right, *module, + ASRUtils::expr_type(x.m_left), 0); + } + else if(x.m_op == ASR::cmpopType::LtE) { + tmp = llvm_utils->is_ineq_by_value(left, right, *module, + ASRUtils::expr_type(x.m_left), 1); + } + else if(x.m_op == ASR::cmpopType::Gt) { + tmp = llvm_utils->is_ineq_by_value(left, right, *module, + ASRUtils::expr_type(x.m_left), 2); + } + else if(x.m_op == ASR::cmpopType::GtE) { + tmp = llvm_utils->is_ineq_by_value(left, right, *module, + ASRUtils::expr_type(x.m_left), 3); } } diff --git a/src/libasr/codegen/c_utils.h b/src/libasr/codegen/c_utils.h index 84dbed81e2..4ac7fb7e94 100644 --- a/src/libasr/codegen/c_utils.h +++ b/src/libasr/codegen/c_utils.h @@ -842,14 +842,14 @@ class CCPPDSUtils { + struct_type_str + "* src, " + struct_type_str + "* dest)"; func_decls += "inline " + signature + ";\n"; - generated_code += indent + signature + " {\n"; + std::string tmp_generated = indent + signature + " {\n"; for(size_t i=0; i < struct_type_t->n_members; i++) { std::string mem_name = std::string(struct_type_t->m_members[i]); ASR::symbol_t* member = struct_type_t->m_symtab->get_symbol(mem_name); ASR::ttype_t* member_type_asr = ASRUtils::symbol_type(member); if( CUtils::is_non_primitive_DT(member_type_asr) || ASR::is_a(*member_type_asr) ) { - generated_code += indent + tab + get_deepcopy(member_type_asr, "&(src->" + mem_name + ")", + tmp_generated += indent + tab + get_deepcopy(member_type_asr, "&(src->" + mem_name + ")", "&(dest->" + mem_name + ")") + ";\n"; } else if( ASRUtils::is_array(member_type_asr) ) { ASR::dimension_t* m_dims = nullptr; @@ -857,17 +857,18 @@ class CCPPDSUtils { if( ASRUtils::is_fixed_size_array(m_dims, n_dims) ) { std::string array_size = std::to_string(ASRUtils::get_fixed_size_of_array(m_dims, n_dims)); array_size += "*sizeof(" + CUtils::get_c_type_from_ttype_t(member_type_asr) + ")"; - generated_code += indent + tab + "memcpy(dest->" + mem_name + ", src->" + mem_name + + tmp_generated += indent + tab + "memcpy(dest->" + mem_name + ", src->" + mem_name + ", " + array_size + ");\n"; } else { - generated_code += indent + tab + get_deepcopy(member_type_asr, "src->" + mem_name, + tmp_generated += indent + tab + get_deepcopy(member_type_asr, "src->" + mem_name, "dest->" + mem_name) + ";\n"; } } else { - generated_code += indent + tab + "dest->" + mem_name + " = " + " src->" + mem_name + ";\n"; + tmp_generated += indent + tab + "dest->" + mem_name + " = " + " src->" + mem_name + ";\n"; } } - generated_code += indent + "}\n\n"; + tmp_generated += indent + "}\n\n"; + generated_code += tmp_generated; } void list_deepcopy(std::string list_struct_type, diff --git a/src/libasr/codegen/llvm_utils.cpp b/src/libasr/codegen/llvm_utils.cpp index 0599e97130..4c2a241a84 100644 --- a/src/libasr/codegen/llvm_utils.cpp +++ b/src/libasr/codegen/llvm_utils.cpp @@ -1452,6 +1452,153 @@ namespace LCompilers { } } + llvm::Value* LLVMUtils::is_ineq_by_value(llvm::Value* left, llvm::Value* right, + llvm::Module& module, ASR::ttype_t* asr_type, + int8_t overload_id, ASR::ttype_t* int32_type) { + /** + * overloads: + * 0 < + * 1 <= + * 2 > + * 3 >= + */ + llvm::CmpInst::Predicate pred; + + switch( asr_type->type ) { + case ASR::ttypeType::Integer: + case ASR::ttypeType::Logical: { + switch( overload_id ) { + case 0: { + pred = llvm::CmpInst::Predicate::ICMP_SLT; + break; + } + case 1: { + pred = llvm::CmpInst::Predicate::ICMP_SLE; + break; + } + case 2: { + pred = llvm::CmpInst::Predicate::ICMP_SGT; + break; + } + case 3: { + pred = llvm::CmpInst::Predicate::ICMP_SGE; + break; + } + default: { + // can exit with error + } + } + return builder->CreateCmp(pred, left, right); + } + case ASR::ttypeType::Real: { + switch( overload_id ) { + case 0: { + pred = llvm::CmpInst::Predicate::FCMP_OLT; + break; + } + case 1: { + pred = llvm::CmpInst::Predicate::FCMP_OLE; + break; + } + case 2: { + pred = llvm::CmpInst::Predicate::FCMP_OGT; + break; + } + case 3: { + pred = llvm::CmpInst::Predicate::FCMP_OGE; + break; + } + default: { + // can exit with error + } + } + return builder->CreateCmp(pred, left, right); + } + case ASR::ttypeType::Character: { + if( !are_iterators_set ) { + str_cmp_itr = builder->CreateAlloca(llvm::Type::getInt32Ty(context), nullptr); + } + llvm::Value* null_char = llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), + llvm::APInt(8, '\0')); + llvm::Value* idx = str_cmp_itr; + LLVM::CreateStore(*builder, + llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), llvm::APInt(32, 0)), + idx); + llvm::BasicBlock *loophead = llvm::BasicBlock::Create(context, "loop.head"); + llvm::BasicBlock *loopbody = llvm::BasicBlock::Create(context, "loop.body"); + llvm::BasicBlock *loopend = llvm::BasicBlock::Create(context, "loop.end"); + + // head + start_new_block(loophead); + { + llvm::Value* i = LLVM::CreateLoad(*builder, idx); + llvm::Value* l = LLVM::CreateLoad(*builder, create_ptr_gep(left, i)); + llvm::Value* r = LLVM::CreateLoad(*builder, create_ptr_gep(right, i)); + llvm::Value *cond = builder->CreateAnd( + builder->CreateICmpNE(l, null_char), + builder->CreateICmpNE(r, null_char) + ); + switch( overload_id ) { + case 0: { + pred = llvm::CmpInst::Predicate::ICMP_ULT; + break; + } + case 1: { + pred = llvm::CmpInst::Predicate::ICMP_ULE; + break; + } + case 2: { + pred = llvm::CmpInst::Predicate::ICMP_UGT; + break; + } + case 3: { + pred = llvm::CmpInst::Predicate::ICMP_UGE; + break; + } + default: { + // can exit with error + } + } + cond = builder->CreateAnd(cond, builder->CreateCmp(pred, l, r)); + builder->CreateCondBr(cond, loopbody, loopend); + } + + // body + start_new_block(loopbody); + { + llvm::Value* i = LLVM::CreateLoad(*builder, idx); + i = builder->CreateAdd(i, llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), + llvm::APInt(32, 1))); + LLVM::CreateStore(*builder, i, idx); + } + + builder->CreateBr(loophead); + + // end + start_new_block(loopend); + llvm::Value* i = LLVM::CreateLoad(*builder, idx); + llvm::Value* l = LLVM::CreateLoad(*builder, create_ptr_gep(left, i)); + llvm::Value* r = LLVM::CreateLoad(*builder, create_ptr_gep(right, i)); + return builder->CreateICmpULT(l, r); + } + case ASR::ttypeType::Tuple: { + ASR::Tuple_t* tuple_type = ASR::down_cast(asr_type); + return tuple_api->check_tuple_inequality(left, right, tuple_type, context, + builder, module, overload_id); + } + case ASR::ttypeType::List: { + ASR::List_t* list_type = ASR::down_cast(asr_type); + return list_api->check_list_inequality(left, right, list_type->m_type, + context, builder, module, + overload_id, int32_type); + } + default: { + throw LCompilersException("LLVMUtils::is_equal_by_value isn't implemented for " + + ASRUtils::type_to_str_python(asr_type)); + } + } + } + void LLVMUtils::deepcopy(llvm::Value* src, llvm::Value* dest, ASR::ttype_t* asr_type, llvm::Module* module, std::map>& name2memidx) { @@ -4276,6 +4423,101 @@ namespace LCompilers { return LLVM::CreateLoad(*builder, is_equal); } + llvm::Value* LLVMList::check_list_inequality(llvm::Value* l1, llvm::Value* l2, + ASR::ttype_t* item_type, + llvm::LLVMContext& context, + llvm::IRBuilder<>* builder, + llvm::Module& module, int8_t overload_id, + ASR::ttype_t* int32_type) { + /** + * Equivalent in C++ + * + * equality_holds = 1; + * inequality_holds = 0; + * i = 0; + * + * while( i < a_len && i < b_len && equality_holds ) { + * equality_holds &= (a[i] == b[i]); + * inequality_holds |= (a[i] op b[i]); + * i++; + * } + * + * if( (i == a_len || i == b_len) && equality_holds ) { + * inequality_holds = a_len op b_len; + * } + * + */ + + llvm::AllocaInst *equality_holds = builder->CreateAlloca( + llvm::Type::getInt1Ty(context), nullptr); + LLVM::CreateStore(*builder, llvm::ConstantInt::get(context, llvm::APInt(1, 1)), + equality_holds); + llvm::AllocaInst *inequality_holds = builder->CreateAlloca( + llvm::Type::getInt1Ty(context), nullptr); + LLVM::CreateStore(*builder, llvm::ConstantInt::get(context, llvm::APInt(1, 0)), + inequality_holds); + + llvm::Value *a_len = llvm_utils->list_api->len(l1); + llvm::Value *b_len = llvm_utils->list_api->len(l2); + llvm::AllocaInst *idx = builder->CreateAlloca(llvm::Type::getInt32Ty(context), nullptr); + LLVM::CreateStore(*builder, llvm::ConstantInt::get( + context, llvm::APInt(32, 0)), idx); + llvm::BasicBlock *loophead = llvm::BasicBlock::Create(context, "loop.head"); + llvm::BasicBlock *loopbody = llvm::BasicBlock::Create(context, "loop.body"); + llvm::BasicBlock *loopend = llvm::BasicBlock::Create(context, "loop.end"); + + // head + llvm_utils->start_new_block(loophead); + { + llvm::Value* i = LLVM::CreateLoad(*builder, idx); + llvm::Value* cnd = builder->CreateICmpSLT(i, a_len); + cnd = builder->CreateAnd(cnd, builder->CreateICmpSLT(i, b_len)); + cnd = builder->CreateAnd(cnd, LLVM::CreateLoad(*builder, equality_holds)); + builder->CreateCondBr(cnd, loopbody, loopend); + } + + // body + llvm_utils->start_new_block(loopbody); + { + llvm::Value* i = LLVM::CreateLoad(*builder, idx); + llvm::Value* left_arg = llvm_utils->list_api->read_item(l1, i, + false, module, LLVM::is_llvm_struct(item_type)); + llvm::Value* right_arg = llvm_utils->list_api->read_item(l2, i, + false, module, LLVM::is_llvm_struct(item_type)); + llvm::Value* res = llvm_utils->is_ineq_by_value(left_arg, right_arg, module, + item_type, overload_id); + res = builder->CreateOr(LLVM::CreateLoad(*builder, inequality_holds), res); + LLVM::CreateStore(*builder, res, inequality_holds); + res = llvm_utils->is_equal_by_value(left_arg, right_arg, module, + item_type); + res = builder->CreateAnd(LLVM::CreateLoad(*builder, equality_holds), res); + LLVM::CreateStore(*builder, res, equality_holds); + i = builder->CreateAdd(i, llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), + llvm::APInt(32, 1))); + LLVM::CreateStore(*builder, i, idx); + } + + builder->CreateBr(loophead); + + // end + llvm_utils->start_new_block(loopend); + + llvm::Value* cond = builder->CreateICmpEQ(LLVM::CreateLoad(*builder, idx), + a_len); + cond = builder->CreateOr(cond, builder->CreateICmpEQ( + LLVM::CreateLoad(*builder, idx), b_len)); + cond = builder->CreateAnd(cond, LLVM::CreateLoad(*builder, equality_holds)); + llvm_utils->create_if_else(cond, [&]() { + LLVM::CreateStore(*builder, llvm_utils->is_ineq_by_value(a_len, b_len, + module, int32_type, overload_id), inequality_holds); + }, []() { + // LLVM::CreateStore(*builder, llvm::ConstantInt::get( + // context, llvm::APInt(1, 0)), inequality_holds); + }); + + return LLVM::CreateLoad(*builder, inequality_holds); + } + void LLVMList::list_repeat_copy(llvm::Value* repeat_list, llvm::Value* init_list, llvm::Value* num_times, llvm::Value* init_list_len, llvm::Module* module) { @@ -4421,6 +4663,58 @@ namespace LCompilers { return is_equal; } + llvm::Value* LLVMTuple::check_tuple_inequality(llvm::Value* t1, llvm::Value* t2, + ASR::Tuple_t* tuple_type, + llvm::LLVMContext& context, + llvm::IRBuilder<>* builder, + llvm::Module& module, int8_t overload_id) { + /** + * Equivalent in C++ + * + * equality_holds = 1; + * inequality_holds = 0; + * i = 0; + * + * // owing to compile-time access of indices, + * // loop is unrolled into multiple if statements + * while( i < a_len && equality_holds ) { + * inequality_holds |= (a[i] op b[i]); + * equality_holds &= (a[i] == b[i]); + * i++; + * } + * + * return inequality_holds; + * + */ + + llvm::AllocaInst *equality_holds = builder->CreateAlloca( + llvm::Type::getInt1Ty(context), nullptr); + LLVM::CreateStore(*builder, llvm::ConstantInt::get(context, llvm::APInt(1, 1)), + equality_holds); + llvm::AllocaInst *inequality_holds = builder->CreateAlloca( + llvm::Type::getInt1Ty(context), nullptr); + LLVM::CreateStore(*builder, llvm::ConstantInt::get(context, llvm::APInt(1, 0)), + inequality_holds); + + for( size_t i = 0; i < tuple_type->n_type; i++ ) { + llvm_utils->create_if_else(LLVM::CreateLoad(*builder, equality_holds), [&]() { + llvm::Value* t1i = llvm_utils->tuple_api->read_item(t1, i, LLVM::is_llvm_struct( + tuple_type->m_type[i])); + llvm::Value* t2i = llvm_utils->tuple_api->read_item(t2, i, LLVM::is_llvm_struct( + tuple_type->m_type[i])); + llvm::Value* res = llvm_utils->is_ineq_by_value(t1i, t2i, module, + tuple_type->m_type[i], overload_id); + res = builder->CreateOr(LLVM::CreateLoad(*builder, inequality_holds), res); + LLVM::CreateStore(*builder, res, inequality_holds); + res = llvm_utils->is_equal_by_value(t1i, t2i, module, tuple_type->m_type[i]); + res = builder->CreateAnd(LLVM::CreateLoad(*builder, equality_holds), res); + LLVM::CreateStore(*builder, res, equality_holds); + }, [](){}); + } + + return LLVM::CreateLoad(*builder, inequality_holds); + } + void LLVMTuple::concat(llvm::Value* t1, llvm::Value* t2, ASR::Tuple_t* tuple_type_1, ASR::Tuple_t* tuple_type_2, llvm::Value* concat_tuple, ASR::Tuple_t* concat_tuple_type, llvm::Module& module, diff --git a/src/libasr/codegen/llvm_utils.h b/src/libasr/codegen/llvm_utils.h index fcdfaddeb1..54bbaef366 100644 --- a/src/libasr/codegen/llvm_utils.h +++ b/src/libasr/codegen/llvm_utils.h @@ -220,6 +220,10 @@ namespace LCompilers { llvm::Value* is_equal_by_value(llvm::Value* left, llvm::Value* right, llvm::Module& module, ASR::ttype_t* asr_type); + llvm::Value* is_ineq_by_value(llvm::Value* left, llvm::Value* right, + llvm::Module& module, ASR::ttype_t* asr_type, + int8_t overload_id, ASR::ttype_t* int32_type=nullptr); + void set_iterators(); void reset_iterators(); @@ -413,6 +417,11 @@ namespace LCompilers { llvm::Value* check_list_equality(llvm::Value* l1, llvm::Value* l2, ASR::ttype_t *item_type, llvm::LLVMContext& context, llvm::IRBuilder<>* builder, llvm::Module& module); + llvm::Value* check_list_inequality(llvm::Value* l1, llvm::Value* l2, + ASR::ttype_t *item_type, llvm::LLVMContext& context, + llvm::IRBuilder<>* builder, llvm::Module& module, + int8_t overload_id, ASR::ttype_t* int32_type=nullptr); + void list_repeat_copy(llvm::Value* repeat_list, llvm::Value* init_list, llvm::Value* num_times, llvm::Value* init_list_len, llvm::Module* module); @@ -454,6 +463,10 @@ namespace LCompilers { ASR::Tuple_t* tuple_type, llvm::LLVMContext& context, llvm::IRBuilder<>* builder, llvm::Module& module); + llvm::Value* check_tuple_inequality(llvm::Value* t1, llvm::Value* t2, + ASR::Tuple_t* tuple_type, llvm::LLVMContext& context, + llvm::IRBuilder<>* builder, llvm::Module& module, int8_t overload_id); + void concat(llvm::Value* t1, llvm::Value* t2, ASR::Tuple_t* tuple_type_1, ASR::Tuple_t* tuple_type_2, llvm::Value* concat_tuple, ASR::Tuple_t* concat_tuple_type, llvm::Module& module, diff --git a/src/libasr/utils.h b/src/libasr/utils.h index a0b0c00451..e19e0e3ae4 100644 --- a/src/libasr/utils.h +++ b/src/libasr/utils.h @@ -20,6 +20,8 @@ enum Platform { std::string pf2s(Platform); Platform get_platform(); +std::string get_unique_ID(); + struct CompilerOptions { std::filesystem::path mod_files_dir; std::vector include_dirs; diff --git a/src/libasr/utils2.cpp b/src/libasr/utils2.cpp index 62cabe162d..51a2a3c5f4 100644 --- a/src/libasr/utils2.cpp +++ b/src/libasr/utils2.cpp @@ -4,6 +4,8 @@ #endif #include +#include +#include #include #include @@ -11,6 +13,19 @@ namespace LCompilers { +std::string get_unique_ID() { + static std::random_device dev; + static std::mt19937 rng(dev()); + std::uniform_int_distribution dist(0, 61); + const std::string v = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + std::string res; + for (int i = 0; i < 22; i++) { + res += v[dist(rng)]; + } + return res; +} + bool read_file(const std::string &filename, std::string &text) { std::ifstream ifs(filename.c_str(), std::ios::in | std::ios::binary diff --git a/src/lpython/semantics/python_ast_to_asr.cpp b/src/lpython/semantics/python_ast_to_asr.cpp index 2f876f394f..b5e8c153d8 100644 --- a/src/lpython/semantics/python_ast_to_asr.cpp +++ b/src/lpython/semantics/python_ast_to_asr.cpp @@ -2734,6 +2734,24 @@ class CommonVisitor : public AST::BaseVisitor { ); throw SemanticAbort(); } + if (ASR::is_a(*asr_alloc_type)) { + ASR::symbol_t *sym = ASRUtils::symbol_get_past_external(ASR::down_cast(asr_alloc_type)->m_derived_type); + if (ASR::is_a(*sym)) { + ASR::StructType_t *st = ASR::down_cast(sym); + if (st->m_abi != ASR::abiType::BindC) { + diag.add(diag::Diagnostic( + "The struct in c_p_pointer must be C interoperable", + diag::Level::Error, diag::Stage::Semantic, { + diag::Label("not C interoperable", + {asr_alloc_type->base.loc}), + diag::Label("help: add the @ccallable decorator to this struct to make it C interoperable", + {st->base.base.loc}, false) + }) + ); + throw SemanticAbort(); + } + } + } fill_shape_and_lower_bound_for_CPtrToPointer(); return ASR::make_CPtrToPointer_t(al, loc, cptr, pptr, target_shape, lower_bounds); } @@ -6303,14 +6321,20 @@ class BodyVisitor : public CommonVisitor { tmp = ASR::make_StringCompare_t(al, x.base.base.loc, left, asr_op, right, type, value); } else if (ASR::is_a(*dest_type)) { - if (asr_op != ASR::cmpopType::Eq && asr_op != ASR::cmpopType::NotEq) { - throw SemanticError("Only Equal and Not-equal operators are supported for Tuples", + if (asr_op != ASR::cmpopType::Eq && asr_op != ASR::cmpopType::NotEq + && asr_op != ASR::cmpopType::Lt && asr_op != ASR::cmpopType::LtE + && asr_op != ASR::cmpopType::Gt && asr_op != ASR::cmpopType::GtE) { + throw SemanticError("Only ==, !=, <, <=, >, >= operators " + "are supported for Tuples", x.base.base.loc); } tmp = ASR::make_TupleCompare_t(al, x.base.base.loc, left, asr_op, right, type, value); } else if (ASR::is_a(*dest_type)) { - if (asr_op != ASR::cmpopType::Eq && asr_op != ASR::cmpopType::NotEq) { - throw SemanticError("Only Equal and Not-equal operators are supported for Tuples", + if (asr_op != ASR::cmpopType::Eq && asr_op != ASR::cmpopType::NotEq + && asr_op != ASR::cmpopType::Lt && asr_op != ASR::cmpopType::LtE + && asr_op != ASR::cmpopType::Gt && asr_op != ASR::cmpopType::GtE) { + throw SemanticError("Only ==, !=, <, <=, >, >= operators " + "are supported for Lists", x.base.base.loc); } tmp = ASR::make_ListCompare_t(al, x.base.base.loc, left, asr_op, right, type, value); diff --git a/src/runtime/lpython_intrinsic_numpy.py b/src/runtime/lpython_intrinsic_numpy.py index 17243dd994..43b1f3a8d7 100644 --- a/src/runtime/lpython_intrinsic_numpy.py +++ b/src/runtime/lpython_intrinsic_numpy.py @@ -1,8 +1,5 @@ from lpython import i32, i64, f64, f32, ccall, vectorize, overload -pi_64: f64 = f64(3.141592653589793238462643383279502884197) -pi_32: f32 = f32(3.141592653589793238462643383279502884197) - ########## sin ########## @ccall @@ -274,11 +271,13 @@ def arctan(x: f32) -> f32: @overload @vectorize def degrees(x: f64) -> f64: + pi_64: Const[f64] = f64(3.141592653589793238462643383279502884197) return x*180.0/pi_64 @overload @vectorize def degrees(x: f32) -> f32: + pi_32: Const[f32] = f32(3.141592653589793238462643383279502884197) return x*f32(f32(180)/pi_32) ########## radians ########## @@ -286,11 +285,13 @@ def degrees(x: f32) -> f32: @overload @vectorize def radians(x: f64) -> f64: + pi_64: Const[f64] = f64(3.141592653589793238462643383279502884197) return x*pi_64/180.0 @overload @vectorize def radians(x: f32) -> f32: + pi_32: Const[f32] = f32(3.141592653589793238462643383279502884197) return x*f32(pi_32/f32(180)) ########## arcsinh ########## diff --git a/tests/errors/bindc_10e.py b/tests/errors/bindc_10e.py new file mode 100644 index 0000000000..f8d9ca5c4b --- /dev/null +++ b/tests/errors/bindc_10e.py @@ -0,0 +1,23 @@ +from lpython import i64, i16, CPtr, c_p_pointer, Pointer, sizeof, ccall, i32 +from bindc_10e_mod import S + +@ccall +def _lfortran_malloc(size: i32) -> CPtr: + pass + + +def alloc(buf_size:i64) -> CPtr: + return _lfortran_malloc(i32(buf_size)) + +def main(): + p1: CPtr = alloc(sizeof(S)) + print(p1) + p2: Pointer[S] = c_p_pointer(p1, S) + p2.a = i16(5) + p2.b = i64(4) + print(p2.a, p2.b) + assert p2.a == i16(5) + assert p2.b == i64(4) + + +main() diff --git a/tests/errors/bindc_10e_mod.py b/tests/errors/bindc_10e_mod.py new file mode 100644 index 0000000000..1b0f48e086 --- /dev/null +++ b/tests/errors/bindc_10e_mod.py @@ -0,0 +1,7 @@ +from lpython import packed, dataclass, i16, i64 + +@packed +@dataclass +class S: + a: i16 + b: i64 diff --git a/tests/reference/asr-bindc_10e-8b10394.json b/tests/reference/asr-bindc_10e-8b10394.json new file mode 100644 index 0000000000..38439231b2 --- /dev/null +++ b/tests/reference/asr-bindc_10e-8b10394.json @@ -0,0 +1,13 @@ +{ + "basename": "asr-bindc_10e-8b10394", + "cmd": "lpython --show-asr --no-color {infile} -o {outfile}", + "infile": "tests/errors/bindc_10e.py", + "infile_hash": "fa023d4ad17e426f778a99326998e6dbeac5428fa252974a39a3219d", + "outfile": null, + "outfile_hash": null, + "stdout": null, + "stdout_hash": null, + "stderr": "asr-bindc_10e-8b10394.stderr", + "stderr_hash": "9ea4ff2c8a8789057456196deb5772e4b3a2dffadbd10ecfe5f15f29", + "returncode": 2 +} \ No newline at end of file diff --git a/tests/reference/asr-bindc_10e-8b10394.stderr b/tests/reference/asr-bindc_10e-8b10394.stderr new file mode 100644 index 0000000000..cc7c1cd0aa --- /dev/null +++ b/tests/reference/asr-bindc_10e-8b10394.stderr @@ -0,0 +1,14 @@ +semantic error: The struct in c_p_pointer must be C interoperable + --> tests/errors/bindc_10e.py:15:38 + | +15 | p2: Pointer[S] = c_p_pointer(p1, S) + | ^ not C interoperable + + --> tests/errors/bindc_10e_mod.py:5:1 - 7:10 + | + 5 | class S: + | ~~~~~~~~... +... + | + 7 | b: i64 + | ...~~~~~~~~~~ help: add the @ccallable decorator to this struct to make it C interoperable diff --git a/tests/reference/asr-structs_02-2ab459a.json b/tests/reference/asr-structs_02-2ab459a.json index 2056a9f832..4d7980c0f1 100644 --- a/tests/reference/asr-structs_02-2ab459a.json +++ b/tests/reference/asr-structs_02-2ab459a.json @@ -2,11 +2,11 @@ "basename": "asr-structs_02-2ab459a", "cmd": "lpython --show-asr --no-color {infile} -o {outfile}", "infile": "tests/../integration_tests/structs_02.py", - "infile_hash": "6d54aa7c2bb850cbce2c0add7b77f9f72c9323162ae080c7eef4867a", + "infile_hash": "281bc75fb743f18fb6f011b278d7ab8103cc688f5856a59cb1f54895", "outfile": null, "outfile_hash": null, "stdout": "asr-structs_02-2ab459a.stdout", - "stdout_hash": "e5df0fb84bfc694b884736c1c4a5ddaec25933d8dba54e894de3e961", + "stdout_hash": "3a3e1108225886c52d459a08a26d5b35d4aea338982034d43079769d", "stderr": null, "stderr_hash": null, "returncode": 0 diff --git a/tests/reference/asr-structs_02-2ab459a.stdout b/tests/reference/asr-structs_02-2ab459a.stdout index feaf95ffa6..83bfd63a07 100644 --- a/tests/reference/asr-structs_02-2ab459a.stdout +++ b/tests/reference/asr-structs_02-2ab459a.stdout @@ -304,28 +304,6 @@ () ) () - ) - (CPtrToPointer - (Var 3 a) - (Var 3 a2) - () - () - ) - (Print - () - [(Var 3 a) - (Var 3 a2) - (GetPointer - (Var 3 a1) - (Pointer - (Struct - 8 A - ) - ) - () - )] - () - () )] () Public diff --git a/tests/reference/c-bindc_06-a30d20f.json b/tests/reference/c-bindc_06-a30d20f.json index 2b91aefedc..6449300ee9 100644 --- a/tests/reference/c-bindc_06-a30d20f.json +++ b/tests/reference/c-bindc_06-a30d20f.json @@ -6,7 +6,7 @@ "outfile": null, "outfile_hash": null, "stdout": "c-bindc_06-a30d20f.stdout", - "stdout_hash": "6a93f686a1c2fe616c5de50dd3e339f5db7d226f48b29e5569412402", + "stdout_hash": "7fdf946af48e4b286aa2a5a328ed8edb8e50b98c252f7290f273d1a0", "stderr": null, "stderr_hash": null, "returncode": 0 diff --git a/tests/reference/c-bindc_06-a30d20f.stdout b/tests/reference/c-bindc_06-a30d20f.stdout index a9e0d8e2fe..e99f8e9dcc 100644 --- a/tests/reference/c-bindc_06-a30d20f.stdout +++ b/tests/reference/c-bindc_06-a30d20f.stdout @@ -81,8 +81,6 @@ float _lfortran_caimag(float complex x); double _lfortran_zaimag(double complex x); -float pi_32 = 3.14159265358979312e+00; -double pi_64 = 3.14159265358979312e+00; double _lfortran_dacos(double x); double _lfortran_dacosh(double x); diff --git a/tests/reference/c-structs_33-4a3339f.json b/tests/reference/c-structs_33-4a3339f.json new file mode 100644 index 0000000000..73a432ee7b --- /dev/null +++ b/tests/reference/c-structs_33-4a3339f.json @@ -0,0 +1,13 @@ +{ + "basename": "c-structs_33-4a3339f", + "cmd": "lpython --no-color --show-c {infile}", + "infile": "tests/../integration_tests/structs_33.py", + "infile_hash": "15fdcb483c864b6322ebcf6c495e635bbe917f1d8b407ccf4dc3e2ee", + "outfile": null, + "outfile_hash": null, + "stdout": "c-structs_33-4a3339f.stdout", + "stdout_hash": "425a22068f547e15ba187e2974220f28f0af3a70305b67cfd4a6a655", + "stderr": null, + "stderr_hash": null, + "returncode": 0 +} \ No newline at end of file diff --git a/tests/reference/c-structs_33-4a3339f.stdout b/tests/reference/c-structs_33-4a3339f.stdout new file mode 100644 index 0000000000..5aaf931d35 --- /dev/null +++ b/tests/reference/c-structs_33-4a3339f.stdout @@ -0,0 +1,61 @@ +#include + +#include +#include +#include +#include +#include + +struct dimension_descriptor +{ + int32_t lower_bound, length; +}; +struct __attribute__((packed)) inner_struct { + int32_t inner_field; +}; + +struct __attribute__((packed)) outer_struct { + struct inner_struct inner_s; +}; + + +inline void struct_deepcopy_outer_struct(struct outer_struct* src, struct outer_struct* dest); +inline void struct_deepcopy_inner_struct(struct inner_struct* src, struct inner_struct* dest); + + +// Implementations +void check() +{ + struct inner_struct inner_struct_instance_value; + struct inner_struct* inner_struct_instance = &inner_struct_instance_value; + struct outer_struct outer_struct_instance_value; + struct outer_struct* outer_struct_instance = &outer_struct_instance_value; + struct outer_struct outer_struct_instance2_value; + struct outer_struct* outer_struct_instance2 = &outer_struct_instance2_value; + outer_struct_instance->inner_s.inner_field = 5; + struct_deepcopy_outer_struct(outer_struct_instance, outer_struct_instance2); + struct_deepcopy_inner_struct(&outer_struct_instance2->inner_s, inner_struct_instance); + ASSERT(inner_struct_instance->inner_field == 5); +} + +void _lpython_main_program() +{ + check(); +} + +int main(int argc, char* argv[]) +{ + _lpython_set_argv(argc, argv); + _lpython_main_program(); + return 0; +} + +void struct_deepcopy_inner_struct(struct inner_struct* src, struct inner_struct* dest) { + dest->inner_field = src->inner_field; +} + +void struct_deepcopy_outer_struct(struct outer_struct* src, struct outer_struct* dest) { + struct_deepcopy_inner_struct(&(src->inner_s), &(dest->inner_s));; +} + + diff --git a/tests/tests.toml b/tests/tests.toml index 057269e597..13ac8257cd 100644 --- a/tests/tests.toml +++ b/tests/tests.toml @@ -337,6 +337,10 @@ asr = true filename = "../integration_tests/structs_05.py" asr = true +[[test]] +filename = "../integration_tests/structs_33.py" +c = true + [[test]] filename = "../integration_tests/callback_01.py" asr = true @@ -1151,6 +1155,10 @@ asr = true filename = "errors/bindc_04.py" asr = true +[[test]] +filename = "errors/bindc_10e.py" +asr = true + [[test]] filename = "errors/cptr_01.py" asr = true