Both safe and wrong?

Jonathan M Davis newsgroup.d at jmdavisprog.com
Thu Feb 7 23:53:48 UTC 2019


On Thursday, February 7, 2019 3:33:45 PM MST Luís Marques via Digitalmars-d 
wrote:
> On Thursday, 7 February 2019 at 17:33:01 UTC, Olivier FAURE wrote:
> > One way to fix this would be to forbid using @system global
> > variables in @safe functions, but this would definitely be a
> > breaking change, unless global variable safety is determined by
> > the compiler by default (which is its own can of worms).
>
> You are discussing evaluating the safety to the variable. Why not
> evaluate the safety of the variable's initialization expression?
> That is, @safe would always refer to code, just not necessarily
> functions.

Indeed. You don't check variables for @safety. You check code that runs.
Initialization expressions are a bit weird in that they're a way for code
that is run to exist outside of a function. In all other cases, any code
that is run (as opposed to being a declaration) is inside a function of some
kind. So, what we have here is simply a case of the small amount of runnable
code that doesn't exist in a function being missed in the design of @safe.
If you just think of all initialization expressions as being essentially
lambdas that declared and called in place, then all that we need is for
those lambdas to be marked as @safe when the section of code that they're in
is marked with @safe.

It is possible that fixing this will cause code breakage, but it's likely to
be rare, since you aren't normally going to get code like the original
example had where an initialization expression outside of a function was
taking an address. That code probably wasn't even legal until fairly
recently, because it didn't used to be possible to directly initialize
pointers when their value had to be known at compile time. As I understand
it, being able to do something like

int* i = new int(42);

with a variable outside of a functions is a fairly recent improvement.

Regardless, I think that it's pretty clear that we need to fix this, and my
inclination is to argue that initialization expressions should just be
treated as if they were lowered to lambdas that were immediately called.
e.g.

int* y = cast(int*) &x;

becomes something like

int* y = () { return cast(int*) &x; }();

Then when you have something like

@safe pure:
int* y = cast(int*) &x;

it's quite clear what should happen. But I don't know if there are any
issues with that particular way of spec-ing it, and it's not like you want
to _actually_ add any lambdas - though in most cases lambdas like that
should be optimized out anywhere they're used anyway (though IIRC, that
doesn't necessarily happen with dmd at present). However, it does make the
attribute portion of things very straightforward.

- Jonathan M Davis






More information about the Digitalmars-d mailing list