The case of -debug -O and: is breaking pure/@nogc/nothrow/@safe UB under -debug?

Jonathan M Davis newsgroup.d at jmdavisprog.com
Wed Apr 18 13:47:35 UTC 2018


On Wednesday, April 18, 2018 13:15:08 Guillaume Piolat via Digitalmars-d-
learn wrote:
> The D specification says:
>
> "A ConditionalStatement that has a DebugCondition is called a
> DebugStatement. DebugStatements have relaxed semantic checks in
> that pure, @nogc, nothrow and @safe checks are not done. Neither
> do DebugStatements influence the inference of pure, @nogc,
> nothrow and @safe attributes."
>
>
> So it seems under a debug clause you don't have to conform to
> pure/@nogc/nothrow/@safe.
>
> The immediate question that follow is:
>
> "Is breaking pure/@nogc/nothrow/@safe Undefined Behaviour (UB) in
> a DebugStatement?"
>
> Would the optimizer -O breaks code that breaks such by virtue of
> being -debug?
>
> If no (not UB), doesn't this guarantees that no optimizations
> will ever be performed thanks to pure/@nogc/nothrow/@safe?

It wouldn't surprise me if Walter were the only person who could really
answer that, though maybe one of the other compiler devs could.

However, I'm quite sure that if you have strongly pure function, and you've
turned on optimizations, extra calls to it will be elided regardless of the
function internals, because that decision is made based on the function
signature. The same will go for any optimization that is done based on the
function signature.

nothrow, for instance, would cause problems. If the function is nothrow, the
compiler will have omitted all of the exception handling code around the
function call, so if an exception is somehow thrown from a nothrow function,
it's likely to cause some unpleasant problems. I expect that it will work on
some level, since you can throw Errors from nothrow functions, but in the
case of Errors, it's not guaranteed that any clean-up code is run (e.g.
destructors and scope statements may or may not run and almost certainly
won't if the function being called was nothrow, since that's the kind of
thing that gets removed from around calls to nothrow functions when
optimizing code). So, an Exception being thrown from a nothrow function
would be very similar to an Error being thrown from a nothrow function.
Either way, you don't want it to happen if it's not then going to kill your
program, and while an Error is virtually guaranteed to bubble to the top and
result in your program dying, in the case of an Exception, you might have
something catching Exceptions which will end up catching it, in which case
the program will be an invalid state, but it won't actually be killed. So,
that could be very bad.

I don't think that @nogc matters much one way or the other unless you
haven't linked in the GC (e.g. if you're using -betterC). AFAIK, _all_ @nogc
does is provide a way for the programmer to know for sure that a function
doesn't allocate using the GC, and I don't think that it does any
optimizations of any kind (I honestly don't know of any way that that
information could even theoretically be used for optimizations). So, that
probably doesn't matter in practice, though it wouldn't surprise me if at
some point, someone figures out something clever that can be assumed based
on @nogc, and you end up with problems if you violate it.

All that violating @safe is going to do is essentially mean that you've
marked a section of code as @trusted. If the code in question is actually
@safe but just couldn't be verified as such by the compiler, then you're
fine, but if it's actually doing something that isn't @safe, then you could
have memory corruption problems. But that's the same with anything that's
marked @trusted.

What I can't say for sure is what happens inside the function when it's
compiled. What I expect would happen would be that inside the debug
statement, any errors related to stuff like pure would be ignored but that
the compiler would otherwise treat that code like any other code in the
function.

- Jonathan M Davis



More information about the Digitalmars-d-learn mailing list