Skip to content
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

cgen error with -cstrict -cc clang, and source code with a defer body in a match branch, using a local var declared in the match branch #19092

Open
spytheman opened this issue Aug 9, 2023 · 3 comments
Labels
Bug This tag is applied to issues which reports bugs. Unit: cgen Bugs/feature requests, that are related to the default C generating backend. Unit: Checker Bugs/feature requests, that are related to the type checker. Unit: Compiler Bugs/feature requests, that are related to the V compiler in general.

Comments

@spytheman
Copy link
Member

V doctor:

V full version: V 0.4.0 286d397.b7afe6b
OS: linux, Ubuntu 20.04.6 LTS
Processor: 4 cpus, 64bit, little endian, Intel(R) Core(TM) i3-3225 CPU @ 3.30GHz

getwd: /v/vnew
vexe: /v/vnew/v
vexe mtime: 2023-08-09 06:44:42

vroot: OK, value: /v/vnew
VMODULES: OK, value: /home/delian/.vmodules
VTMP: OK, value: /tmp/v_1000

Git version: git version 2.41.0
Git vroot status: weekly.2023.32-8-gb7afe6b2
.git/config present: true

CC version: cc (Ubuntu 10.5.0-1ubuntu1~20.04) 10.5.0
thirdparty/tcc status: thirdparty-linux-amd64 12f392c3

What did you do?
v -g -o vdbg cmd/v && vdbg defer_in_match.v

struct Object {
mut:
	context bool
}

fn (o Object) g() {
	println('o.context: $o.context')
}	

fn (mut o Object) f(x int) int {
	eprintln('o.f(), o.context at start: $o.context')
	defer {
		eprintln('o.f(), o.context at end: $o.context')
	}
	match x {
		0 {
			old := o.context
			defer {
				o.context = old
			}
			o.context = true
			o.g()
		}
		1 {
			return 123
		}
		else{}
	}
	return 42
}

fn main() {
	mut o := Object{}
	dump( o.f(0) )
	dump( o.f(1) )
	dump( o.f(2) )
}

What did you expect to see?

A checker error, telling me that the second defer is not allowed, since it uses variables that are only available inside the match branch, and will not be available or properly initialised outside that match

Alternatively, cgen should have generated not just bool old; but bool old = false;, so that compilation with -cstrict -cc clang will pass (V's defer implementation ensures that it will not be used, but the C compiler does not know that).

What did you see instead?
Without -cstrict:

o.f(), o.context at start: false
o.context: true
o.f(), o.context at end: false
[defer_in_match.v:34] o.f(0): 42
o.f(), o.context at start: false
o.f(), o.context at end: false
[defer_in_match.v:35] o.f(1): 123
o.f(), o.context at start: false
o.f(), o.context at end: false
[defer_in_match.v:36] o.f(2): 42

With -cstring -cc clang:

#148 10:24:50 ᛋ master /v/vnew❱v -cstrict -cc clang defer_in_match.v 
==================
/tmp/v_1000/defer_in_match.7567724782063835319.tmp.c:12518:20: error: variable 'old' is uninitialized when used here [-Werror,-Wuninitialized]
                                                o->context = old;
                                                             ^~~
/tmp/v_1000/defer_in_match.7567724782063835319.tmp.c:12503:10: note: initialize the variable 'old' to silence this warning
        bool old;
                ^
                 = '\0'
1 error generated.
...
@spytheman spytheman added Bug This tag is applied to issues which reports bugs. Unit: Compiler Bugs/feature requests, that are related to the V compiler in general. Unit: Checker Bugs/feature requests, that are related to the type checker. Unit: cgen Bugs/feature requests, that are related to the default C generating backend. labels Aug 9, 2023
@spytheman
Copy link
Member Author

Note: the generated C code is:

VV_LOCAL_SYMBOL int main__Object_f(main__Object* o, int x) {
    bool main__Object_f_defer_0 = false;
    bool main__Object_f_defer_1 = false;
    bool old; // <----- this is not initialized, and `-cstrict` complains about it
    eprintln( str_intp(2, _MOV((StrIntpData[]){{_SLIT("o.f(), o.context at start: "), /*115 &bool*/0xfe10, {.d_s = o->context ? _SLIT("true") : _SLIT("false")}}, {_SLIT0, 0, { .d_c = 0 }}})));
    main__Object_f_defer_0 = true;
    switch (x) {
        case 0: {
                old = o->context;
                main__Object_f_defer_1 = true;
                o->context = true;
                main__Object_g(/*rec*/*o);
                break;
        }
        case 1: {
                int _t1 = 123;
                    // Defer begin
                    if (main__Object_f_defer_1) {
                        o->context = old;
                    }
                    // Defer end
                    // Defer begin
                    if (main__Object_f_defer_0) {
                        eprintln( str_intp(2, _MOV((StrIntpData[]){{_SLIT("o.f(), o.context at end: "), /*115 &bool*/0xfe10, {.d_s = o->context ? _SLIT("true") : _SLIT("false")}}, {_SLIT0, 0, { .d_c = 0 }}})));
                    }
                    // Defer end
                return _t1;
        }
        default: {
                break;
        }
    }

    int _t2 = 42;
        // Defer begin
        if (main__Object_f_defer_1) {
            o->context = old;
        }
        // Defer end
        // Defer begin
        if (main__Object_f_defer_0) {
            eprintln( str_intp(2, _MOV((StrIntpData[]){{_SLIT("o.f(), o.context at end: "), /*115 &bool*/0xfe10, {.d_s = o->context ? _SLIT("true") : _SLIT("false")}}, {_SLIT0, 0, { .d_c = 0 }}})));
        }
        // Defer end
    return _t2;
}

@spytheman
Copy link
Member Author

On a side note, this is another example, why a scoped defer will be much better default, instead of a function scoped defer.

@JalonSolov
Copy link
Contributor

"cgen should have generated not just bool old; but bool old = false;"

There really should never be a case where it doesn't do that, otherwise it does not match V's claim that all variables will be initialized with their 0-type by default.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug This tag is applied to issues which reports bugs. Unit: cgen Bugs/feature requests, that are related to the default C generating backend. Unit: Checker Bugs/feature requests, that are related to the type checker. Unit: Compiler Bugs/feature requests, that are related to the V compiler in general.
Projects
None yet
Development

No branches or pull requests

2 participants