When I was switching my toy project sgio.d to dmd 2.067.1, I came across another compiler error. Cool! I submitted an issue on the bug tracker, and it looks like this particular change was intentional. Regardless if it's a bug or not, I'll describe the syntax that caused the break.
My sgio.d project can send scsi ioctls to native devices on Windows and Linux hosts. Some scsi devices have a "management network address", like iSCSI, and we can get the IP address of the LUNs by sending the device a Management Network Address (MNA) Vital Product Data (VPD) page (0x85). If you're interested look at the SCSI Primary Commands 4 (SPC-4) document, it details the definitions of basic SCSI commands. Or glance at the summary of VPD on Wikipedia. sgio.d will send an ioctl and then unmarshall the response buffer into a usable object.
The contents of a MNA VPD response page is some header information and a list of Network Service Descriptors. The unmarshalling of the MNA VPD is easy but I found that some devices may return a truncated Command Data Block (CDB), so I have a check to ensure that we don't walk off the end of the buffer. We do that by checking that the descriptors offset plus the descriptor's length (plus a 2-byte header) is still within the original buffer.
We know that the MNA VPD response has a list of descriptors and the offset in the buffer for a descriptor will change each iteration. Taking that in mind, the unmarshall with truncated buffer check looks like this (the source):
override protected void unmarshall() {
m_network_descriptors_length = bigEndianToNative!ushort(datain[2..4]);
m_network_descriptors = make!(Array!NetworkServicesDescriptor)();
size_t offset = 4;
while (offset < m_network_descriptors_length) {
if (offset + 4 + bigEndianToNative!ushort(
cast(ubyte[2]) datain[offset+2..offset+4])
> datain.length) {
// truncated buffer
}
auto ns_descriptor = new NetworkServicesDescriptor(datain[offset..$]);
m_network_descriptors ~= ns_descriptor;
offset += ns_descriptor.network_address_length + 4;
}
}
The code is nice and clean but the compiler doesn't like it because the std.bitmap bigEndianToNative function doesn't accept a buffer slice composed of variables. What I mean is the slice allows only literals, like buffer[2..4]
and not buffer[offset+2..offset+4]
.
The workaround is to just manually convert the bytes which is done with (datain[offset+2]<<8 | datain[offset+2+1])
instead of bigEndianToNative!ushort(cast(ubyte[2]) datain[offset+2..offset+4])
. It's very convenient that D has a stdlib method that does byte conversions, even if it is just slices with literals. D is a great project!