Examples of DFA
Richard (Rikki) Andrew Cattermole
richard at cattermole.co.nz
Tue Sep 23 09:43:14 UTC 2025
On 23/09/2025 5:54 PM, Walter Bright wrote:
> This is what I am talking about:
> ```
> @nogc void foo() { bar(); }
>
> void bar() { abc(); }
>
> void abc() { bar(); }
> ```
> Both bar() and abc() are @nogc. But the forward-only checking cannot
> deduce it, and the result is:
>
> test.d(3): Error: `@nogc` function `test.foo` cannot call non- at nogc
> function `test.bar`
>
> This is the simplest version of this problem. It can be quite complex,
> but the result is the same - it cannot be figured out without solving
> recursive data flow equations.
>
> Another version of the problem:
> ```
> @nogc void foo() { bar(); }
>
> void bar() { abc(); }
>
> void abc();
> ```
> The body of abc() is not available to the compiler, so the compiler
> cannot deduce @nogc for abc(). So, in order to deduce attributes of
> abc(), the compiler must have the source code available for it. To do a
> complete job, then, requires compilation of the entire program's code
> base. Which will require a lot of memory and time.
>
> Adam, Rikki, if I'm wrong, please show me how.
I will assume that ``@nogc`` is lint level attribute that does not
effect mangling, as that would be a requirement for everything to link.
If it does effect mangling, things get so much harder to solve and a lot
less flexible, hence I am not keen on such approach for DFA attributes.
To solve this is very simple, but it does require the compiler to see
the result of the compilation of all three functions. Attributes via the
.di generator, or a dedicated special file containing the information
are both valid options here.
Instead of writing ``@nogc``, we write ``@nogc iff(foo, bar, abc)``.
From there its a simple dependency resolver either during the
compilation of the three functions or on usage.
This is the basis for my solution to a problem Adam has proposed for
PhobosV3, which essentially is the desire to whitelist attributes. Use
``@localnogc`` & if the function calls are all ``@nogc``, therefore the
function is allowed to be ``@nogc``.
```d
void foo() @nogc => bar; // dependency resolve bar&abc's @nogc iff's
void bar() @nogc iff(abc) => abc;
void abc() @nogc iff(bar) => bar;
```
```d
void foo() @nogc => bar; // dependency resolve bar&abc's @nogc iff's
void bar() @nogc iff(abc); // body is irrelevant
void abc() @nogc iff(bar); // body is irrelevant
```
This is a very simple demonstrating of whole program graph analysis with
whole function graph representation of equations per function. As far as
I know no production language supports this and has been left in
experimental 90's languages.
I won't say any .net language does this, but because they are an
application VM, they do in fact see the whole program (minus FFI). What
they can do, and what we can do without excellent serialization
capabilities in the compiler isn't the same.
Of course I'm not suggesting @nogc should get this particular treatment,
in practice its "good enough" (if we ignore white listing), but as an
example of effect analysis its a good one even if it isn't a classical
problem like pure.
Am I right to assume that the reason you haven't presented this
solution, is because you want attributes to be finalized when bar&abc
complete?
More information about the Digitalmars-d
mailing list