dmd
dmd copied to clipboard
add scope const to ... parameters
core.stdc.stdio.printf
already does this.
Thanks for your pull request, @WalterBright!
Bugzilla references
Your PR doesn't reference any Bugzilla issue.
If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog.
Testing this PR locally
If you don't have a local development environment setup, you can use Digger to test this PR:
dub run digger -- build "master + dmd#15556"
Dautotest apparently cannot handle scope const ...
parameters, it fails with:
src/dmd/errors.d(174): [1;33mWarning: [mDdoc: parameter count mismatch, expected 3, got 2
``
core.stdc.stdio.printf
already does this.
Which is wrong, because the %n
specifier modifies a variadic argument, violating const
I don't see much point in adding unchecked and wrong annotations to dirty old printf. If we want to move to something type safe / memory @safe
/ pure
, we have to step away from printf and go for a D solution.
Ha, I forgot about %n. But we never use it, and I've never seen it used. From a pedantic standpoint, you're quite correct. From a pragmatic point of view, I'm not so sure. Replacing printf just for that seems a lot of work for little payoff.
From a pragmatic point of view, I'm not so sure.
I agree I'm being pedantic, but from a pragmatic point of view, there's little advantage of adding const
. We're already passing const(char)*
arguments to ...
without const
, and the compiler doesn't complain, so it only inaccurately documents what's already known.
Replacing printf just for that seems a lot of work for little payoff
It's not just const
, it's also for @safe
and getting rid of C strings, which is something you said you wanted.
It's not just const, it's also for @safe and getting rid of C strings, which is something you said you wanted.
printf still works with D strings, we do it all the time. One of the impediments to getting rid of all the C strings, which I do want, is interfacing with the C++ gdc and ldc backends.
I do want to make the dmd source code @safe and dip1000 compliant. The way we use printf is trustable and dip1000 compliant. It's better than the hack we use to get a pure malloc and free.
The way we use printf is trustable and dip1000 compliant.
You can keep using printf
deep down to do the string concatenation and wrap it in a safe interface with @trusted
, but the fundamental problem is that the current interface of the error()
family of functions (which this PR tries to improve) is not @safe
, and cannot be @safe
as long as it's a thin wrapper where the format string and arguments are C strings, and passed verbatim to printf
.
void error(const ref Loc loc, const(char)* format, scope const ...)
This will only ever be called from a @system
or @trusted
context, so no scope
checks will ever happen. And because C variadics throw type safety completely out the window, the const
doesn't serve any purpose either. Only when we change it to something safe, for example:
void error(const ref Loc loc, string format, RootObject[] args...);
void error(T...)(const ref Loc loc, string format, T args);
Only then would it make sense to add const
or scope
(if scope
is not inferred already).
This will only ever be called from a @system or @trusted context
@safe code can call a @trusted function with scope
parameters and scope
will be checked. If error() is @trusted, it must provide a safe interface, and that implies it must properly use va_args to correctly get the types and values of arguments.
As for char* 0 terminated strings, they can be passed to @safe functions. It's just that the @safe function cannot do any pointer arithmetic on it, it can only look at the first character of the string. But it can pass the pointer along to an @trusted function, which can then do pointer arithmetic on it. Pointers-to-strings essentially become opaque objects to @safe code.
So I think we're good. Besides, if we can't do this, D cannot successfully interface with C code.
it must properly use va_args to correctly get the types and values of arguments
How?
But it can pass the pointer along to an
@trusted
function, which can then do pointer arithmetic on it.
Only if the @trusted
function can verify it is indeed a 0 terminated string and not e.g. a new char('a')
. How is it going to do that?
How?
That's why it's a trusted function! Not sure just what you're asking?
Only if the @trusted function can verify it is indeed a 0 terminated string and not e.g. a new char('a'). How is it going to do that?
Great question! The answer is, the @trusted function is indeed doing something unsafe with the pointer, but that's why it's @trusted.
Only if the @trusted function can verify it is indeed a 0 terminated string and not e.g. a new char('a'). How is it going to do that?
Great question! The answer is, the @trusted function is indeed doing something unsafe with the pointer, but that's why it's @trusted.
No. @trusted
functions must have safe interfaces. A function that assumes a null-terminated string behind a char*
cannot be @trusted
. It can only be @system
. This is the very core idea of @trusted
. I'm not being pedantic. Violating that rule is not being pragmatic.
That's why it's a trusted function! Not sure just what you're asking?
I thought you were implying there was a way to use va_args
and retrieve extra type information so it could be made type safe. Reading it again, it seems like you're saying "the caller must pass the variadic arguments with the right types in order for it to be safe". Like aG0aep6G said, that's not how @trusted
works.
@trusted
does not mean: "this is unsafe but I don't care". It means: "this is safe, though the compiler might not understand". If you want @trusted
functions that accept C strings, you need to have a "zero-terminated C string" type that is ABI-compatible with char*
.
In any case, you cannot trust printf
. It will result in undefined behavior for bad argument combinations.
It will result in undefined behavior for bad argument combinations.
We've added a checker for the arguments based on the printf format string.
the caller must pass the variadic arguments with the right types in order for it to be safe
import core.stdc.stdio;
void test(int i) { printf("%p\n", i); }
test.d(3): Deprecation: argument `i` for format specification `"%p"` must be `void*`, not `int`
@tgehr does that mean no opaque types are allowed in @safe code?
We've added a checker for the arguments based on the printf format string.
Which is not sufficient for @trusted
printf("%s", new char('a')); // permitted
Which is wrong, because the %n specifier modifies a variadic argument, violating const
https://issues.dlang.org/show_bug.cgi?id=24133
The error seems to be a tester problem.