www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Error: function std.stdio.setmode is not accessible from module a

reply Kirill Kryukov <kkryukov gmail.com> writes:
Hello,

dmd 2.072.0 broke my project. I reduced it to following:

===== a.d start =====
import std.stdio;

void main()
{
     setmode(stdin.fileno, 0x8000);
}
===== a.d end =====

Compiling on Windows 7 64-bit with the following commands:

C:\utl\dev\D\dmd-2.071.2\windows\bin\dmd.exe a.d -ofa1.exe
C:\utl\dev\D\dmd-2.072.0\windows\bin\dmd.exe a.d -ofa2.exe

The first one succeeds (producing a working executable), the 
second one fails with these messages:

a.d(6): Deprecation: std.stdio.setmode is not visible from module 
a
a.d(6): Error: function std.stdio.setmode is not accessible from 
module a

2.072.0 changelog does not seem to mention anything relevant. Is 
there something obvious I'm missing, or should I file a bug 
report?

Thanks,
Kirill
Nov 02 2016
parent reply Jonathan M Davis via Digitalmars-d-learn writes:
On Wednesday, November 02, 2016 08:58:04 Kirill Kryukov via Digitalmars-d-
learn wrote:
 Hello,

 dmd 2.072.0 broke my project. I reduced it to following:

 ===== a.d start =====
 import std.stdio;

 void main()
 {
      setmode(stdin.fileno, 0x8000);
 }
 ===== a.d end =====

 Compiling on Windows 7 64-bit with the following commands:

 C:\utl\dev\D\dmd-2.071.2\windows\bin\dmd.exe a.d -ofa1.exe
 C:\utl\dev\D\dmd-2.072.0\windows\bin\dmd.exe a.d -ofa2.exe

 The first one succeeds (producing a working executable), the
 second one fails with these messages:

 a.d(6): Deprecation: std.stdio.setmode is not visible from module
 a
 a.d(6): Error: function std.stdio.setmode is not accessible from
 module a

 2.072.0 changelog does not seem to mention anything relevant. Is
 there something obvious I'm missing, or should I file a bug
 report?
setmode was never publicly documented, and technically, you weren't supposed to be using it from there (since it wasn't documented). It was fixed in 2.072.0 so that all of the undocumented stuff in std.stdio was made private. It was never intended that setmode be part of the public API in std.stdio. But of course, since you were using it in spite of it being undocumented, your code broke. Now, setmode is a C function from Windows, so it should be in druntime where you could easily import it, but unfortunately, it looks like it's currently missing from there. Rather, the bindings for it were just put directly in std.stdio instead of in druntime where they belongs. So, if anything, the bug is that druntime doesn't have it. So, it would make sense to open a bug for that. But if you want to still use it without it being in druntime, you can just declare the bindings yourself, as annoying as that may be. e.g. this is essentially what's in std.stdio: version(DIGITAL_MARS_STDIO) extern(C) int setmode(int, int) nothrow nogc; else version(MICROSOFT_STDIO) { extern(C) int _setmode(int, int) nothrow nogc; alias setmode = _setmode; } It really should be put in druntime though. - Jonathan M Davis
Nov 02 2016
next sibling parent reply Kirill Kryukov <kkryukov gmail.com> writes:
On Wednesday, 2 November 2016 at 11:17:49 UTC, Jonathan M Davis 
wrote:
 setmode was never publicly documented, and technically, you 
 weren't supposed to be using it from there (since it wasn't 
 documented). It was fixed in 2.072.0 so that all of the 
 undocumented stuff in std.stdio was made private. It was never 
 intended that setmode be part of the public API in std.stdio. 
 But of course, since you were using it in spite of it being 
 undocumented, your code broke.

 Now, setmode is a C function from Windows, so it should be in 
 druntime where you could easily import it, but unfortunately, 
 it looks like it's currently missing from there. Rather, the 
 bindings for it were just put directly in std.stdio instead of 
 in druntime where they belongs. So, if anything, the bug is 
 that druntime doesn't have it. So, it would make sense to open 
 a bug for that. But if you want to still use it without it 
 being in druntime, you can just declare the bindings yourself, 
 as annoying as that may be. e.g. this is essentially what's in 
 std.stdio:

 version(DIGITAL_MARS_STDIO)
     extern(C) int setmode(int, int) nothrow  nogc;
 else version(MICROSOFT_STDIO)
 {
     extern(C) int _setmode(int, int) nothrow  nogc;
     alias setmode = _setmode;
 }

 It really should be put in druntime though.

 - Jonathan M Davis
Thanks for the explanation, Jonathan! OK, I'll try adding my own binding for the time being, and submit a feature request. I guess this does not count as regression since it was undocumented, as you say. Although I would have thought it was a documentation deficiency instead. Working, not obviously wrong code stopped working without an alternative method available. Perhaps it's OK if it can be added to druntime the future. Also I am confused by it being both deprecation and error. I thought that deprecation message was just a warning about something that will stop working in the future, and the code should still compile. However in this case dmd first informs me that something is deprecated (it's not clear what exactly is deprecated). And then immediately fails with an error, on the same function call. Is it another separate diagnostic issue, or is it working as intended? Thanks, Kirill
Nov 02 2016
parent reply Jonathan M Davis via Digitalmars-d-learn writes:
On Thursday, November 03, 2016 03:25:31 Kirill Kryukov via Digitalmars-d-
learn wrote:
 Thanks for the explanation, Jonathan! OK, I'll try adding my own
 binding for the time being, and submit a feature request.

 I guess this does not count as regression since it was
 undocumented, as you say. Although I would have thought it was a
 documentation deficiency instead. Working, not obviously wrong
 code stopped working without an alternative method available.
 Perhaps it's OK if it can be added to druntime the future.
It's a C binding, and there aren't supposed to be any public C bindings in Phobos outside of etc.c, and even that is pretty much a legacy thing, since bindings for 3rd party projects would normally go in deimos now. So, it's clear that it was accidental that setmode was public, and any time that you use a symbol that doesn't have a ddoc comment on it, you risk that your code will break later, even if that symbol really should have been private or package. It's not in the documentation, so it's an implementation detail and not part of the Phobos API. And there has been some recent work to make sure that undocumented symbols are either properly documented or made private or package, so anyone using undocumented symbols from Phobos definitely runs a risk of their code breaking, as you experienced.
 Also I am confused by it being both deprecation and error. I
 thought that deprecation message was just a warning about
 something that will stop working in the future, and the code
 should still compile. However in this case dmd first informs me
 that something is deprecated (it's not clear what exactly is
 deprecated). And then immediately fails with an error, on the
 same function call. Is it another separate diagnostic issue, or
 is it working as intended?
That part is definitely weird. I don't know what's going on there exactly, but it probably relates to how private symbols used to be considered for stuff like function overloading just like public symbols, and the access level was only considered after that (meaning that private symbols could cause symbol conflicts), whereas that was fixed a release or two back. But I don't think that the symbol is actually completely invisible now like that deprecation warning implies, just not considered in overloading. But I don't know. Regardless, it's a diagnostic issue separate from setmode specifically. You can reproduce it easily enough with just creating a module with a private symbol and trying to use it in a module that imports it. So, that may very well merit a bug report. It's certainly not how deprecation warnings normally work, and I don't know under what circumstances you could get that warning without the error. The only time that I'm sure there's a difference is when there's a symbol conflict with a private symbol, and previously, you would have gotten an error, whereas now, you wouldn't, so there's nothing to warn about, just an error that went away. - Jonathan M Davis
Nov 03 2016
parent Kirill Kryukov <kkryukov gmail.com> writes:
On Thursday, 3 November 2016 at 08:04:45 UTC, Jonathan M Davis 
wrote:
 [...]
Thank you for a detailed clarification about setmode availability. I'll think more about how to proceed with it, and whether I should request it in druntime. I will try to make a bug report about deprecation. Thanks! Kirill
Nov 03 2016
prev sibling parent Kirill Kryukov <kkryukov gmail.com> writes:
On Wednesday, 2 November 2016 at 11:17:49 UTC, Jonathan M Davis 
wrote:
 version(DIGITAL_MARS_STDIO)
     extern(C) int setmode(int, int) nothrow  nogc;
 else version(MICROSOFT_STDIO)
 {
     extern(C) int _setmode(int, int) nothrow  nogc;
     alias setmode = _setmode;
 }

 It really should be put in druntime though.

 - Jonathan M Davis
In case someone else needs this, here is a possible binding: version(CRuntime_DigitalMars) { extern(C) int setmode(int, int) nothrow nogc; } else version(CRuntime_Microsoft) { extern(C) int _setmode(int, int) nothrow nogc; alias setmode = _setmode; } (DIGITAL_MARS_STDIO and MICROSOFT_STDIO seem to be internal to std.stdio)
Nov 04 2016