Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Add an error message for non-C-interoperable structs #2133

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

Merged
merged 8 commits into from
Jul 9, 2023
Merged
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
2 changes: 2 additions & 0 deletions integration_tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,7 @@ 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)
Expand Down Expand Up @@ -568,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)
Expand Down
9 changes: 4 additions & 5 deletions integration_tests/bindc_09.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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:
Expand All @@ -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

Expand Down
44 changes: 44 additions & 0 deletions integration_tests/bindc_09b.py
Original file line number Diff line number Diff line change
@@ -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()
2 changes: 0 additions & 2 deletions integration_tests/structs_02.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
43 changes: 43 additions & 0 deletions integration_tests/structs_02b.py
Original file line number Diff line number Diff line change
@@ -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()
4 changes: 3 additions & 1 deletion integration_tests/structs_13.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down
15 changes: 15 additions & 0 deletions src/lpython/semantics/python_ast_to_asr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2734,6 +2734,21 @@ class CommonVisitor : public AST::BaseVisitor<Struct> {
);
throw SemanticAbort();
}
if (ASR::is_a<ASR::Struct_t>(*asr_alloc_type)) {
ASR::StructType_t *st = ASR::down_cast<ASR::StructType_t>(ASR::down_cast<ASR::Struct_t>(asr_alloc_type)->m_derived_type);
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);
}
Expand Down
31 changes: 31 additions & 0 deletions tests/errors/bindc_10e.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
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))


@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()
13 changes: 13 additions & 0 deletions tests/reference/asr-bindc_10e-8b10394.json
Original file line number Diff line number Diff line change
@@ -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": "36d1b5d366716d6a601db544fe8ff32aba76518181e71a98a4e6500c",
"outfile": null,
"outfile_hash": null,
"stdout": null,
"stdout_hash": null,
"stderr": "asr-bindc_10e-8b10394.stderr",
"stderr_hash": "7686dd8c9b718548d301e28d39cd15a85b00030172c5658b38a75af5",
"returncode": 2
}
12 changes: 12 additions & 0 deletions tests/reference/asr-bindc_10e-8b10394.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
semantic error: The struct in c_p_pointer must be C interoperable
--> tests/errors/bindc_10e.py:23:38
|
23 | p2: Pointer[S] = c_p_pointer(p1, S)
| ^ not C interoperable
|
15 | class S:
| ~~~~~~~~...
...
|
17 | b: i64
| ...~~~~~~~~~~ help: add the @ccallable decorator to this struct to make it C interoperable
4 changes: 2 additions & 2 deletions tests/reference/asr-structs_02-2ab459a.json
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
22 changes: 0 additions & 22 deletions tests/reference/asr-structs_02-2ab459a.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions tests/tests.toml
Original file line number Diff line number Diff line change
Expand Up @@ -1151,6 +1151,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
Expand Down