Closed jrfondren closed 10 months ago
In Overview documentation, in Pointer section we can read
local n = nilptr -- a generic pointer, initialized to nilptr
local p: pointer -- a generic pointer to anything, initialized to nilptr
local i: *integer -- pointer to an integer
which in other words, what your code is actually doing is indeed trying to assign NULL
inside NULL
; but if you replace your auto
to pointer
, it compiles as expected.
This is the generated C code with the usage of auto
:
static void tmp_chars_1(nlstring s, void* state);
static int nelua_main(int argc, char** argv);
/* ------------------------------ DEFINITIONS ------------------------------- */
void tmp_chars_1(nlstring s, void* state) {
for(intptr_t i = 1, _end = ((intptr_t)(s).size); i <= _end; i += 1) {
NULL = NULL;
}
}
and this is with the usage of pointer
instead:
static void tmp_chars(nlstring s, void* state);
static int nelua_main(int argc, char** argv);
/* ------------------------------ DEFINITIONS ------------------------------- */
void tmp_chars(nlstring s, void* state) {
for(intptr_t i = 1, _end = ((intptr_t)(s).size); i <= _end; i += 1) {
state = (void*)NULL;
}
}
When I read your code I said to myself: "wait, isn't state
going to become nilptr
and you want to assign nilptr
in it? Is this even allowed?" and decided to run the aforementioned tests.
I don't see how that part of the overview implies what you say it does. I know that nilptr is NULL. What I wanted to do was pass NULL to the function. The state
parameter, though, is not NULL: it is a variable with the value of NULL, and assignment to it should only replace that value and not write to NULL. This is akin to replacing to contents of a CPU register, not writing to memory. Similar to this C program:
include <stdlib.h>
void f(void *p) { p = NULL; }
int main() {
f(NULL);
return 0;
}
Or, maybe with auto
it isn't a variable with the value of NULL. I don't get that part. But it seems like an error that Nelua and not the C compiler shouldn't be reporting.
Hmm...yes, you have a point :thinking:
Update: The following code helps me understand the logic a bit more, but I could be wrong here.
Only @edubart can enlighten us with this behavior.
do
local function typenameof(x: auto): string
return #[tostring(x.type)]#
end
local function tellmemytype(x: auto)
print('my type is:', typenameof(x))
x = nilptr
print('my type now is:', typenameof(x))
end
-- local foo = nilptr
-- tellmemytype(foo)
tellmemytype(nilptr)
end
The way I interpret tellmemytype()
's behavior is that I pass it a type nilptr
whereas I should have had passed it a variable, because this is what the auto
does behind the scenes; it deduces to type based on user input as value.
If I comment it out and uncomment the two lines above it, it returns pointer
as printed type.
I hope I've got it right :confused:
So, after some further investigation, it seems like that indeed nilptr
is an rvalue
, it's not a type; its type should be pointer
.
What helped me realized this was the flag --print-analyzed-ast
.
Call {
attr = {
calleesym = "tellmemytype: function(x: nilptr): void",
calleetype = "function(x: nilptr): void",
polyeval = "table: 0x7f5114df7a00",
pseudoargattrs = "table: 0x7f5114dfae40",
pseudoargtypes = "table: 0x7f5114dfae00",
type = "void",
},
{
Nilptr {
attr = {
comptime = true,
type = "nilptr",
},
}
},
...
@edubart I have just tested this commit and the generated C code for definition looks like this:
void tmp_chars_1(nlstring s, void* state) {
bool stop = false;
for(intptr_t i = 1, _end = ((intptr_t)(s).size); i <= _end; i += 1) {
bool _asgntmp_1 = false;
stop = _asgntmp_1;
}
}
Excuse my ignorance, but shouldn't the aforementioned code look something like
void tmp_chars_1(nlstring s, void* state) {
bool stop = false;
for(intptr_t i = 1, _end = ((intptr_t)(s).size); i <= _end; i += 1) {
bool _asgntmp_1 = false;
stop = _asgntmp_1;
state = (void *) NULL;
}
}
Pass some other pointers. The function that doesn't assign state
to NULL is the one that's specialized to state
already being NULL.
Pass some other pointers. The function that doesn't assign
state
to NULL is the one that's specialized tostate
already being NULL.
In other words, in
local function chars(s: string, state: auto)
local stop = false
for i=1, #s do
stop, state = false, nilptr
end
end
chars('abc', nilptr)
because we pass a nilptr
in chars()
, the compiler gets informed to ignore the ,nilptr
part from the for
loop?
because we pass a
nilptr
inchars()
, the compiler gets informed to ignore the,nilptr
part from thefor
loop?
Correct, the thing is already nilptr
, so the compiler eliminates the code.
...wait, you have applied Dead Code Elimination in AST mechanism, before emitting C code?! Bruh! O.o
Code example
Current behavior
Another example
This results in a compilation to
NULL = NULL;
Workaround
Almost any change will result in working code or a clean error from Nelua instead of this error from C. Giving
state
an explicit stop, or assigning something other thannilptr
. In this example,nil
also works. The error was naturally arrived at bynilptr
to be a reasonable "don't care" value.Environment
x86_64 linux Nelua 0.2.0-dev Build number: 1588 Git date: 2023-09-16 16:20:44 -0300 Git hash: 596fcca5c77932da8a07c249de59a9dff3099495 Semantic version: 0.2.0-dev.1588+596fcca5 Copyright (C) 2019-2022 Eduardo Bart (https://nelua.io/)