January 31, 2017
On 1/31/2017 2:44 AM, Nordlöw wrote:
> On Tuesday, 31 January 2017 at 10:20:59 UTC, Olivier FAURE wrote:
>> I thought it meant "the parameter can be returned" not "the parameter *will*
>> be returned".
>
> And what about multiple `return`-qualified function parameters?

'return' means treat the return value "as if" it was derived from that parameter. If multiple parameters are marked as 'return', treat the return value as if it was derived from one of them.

This "as if" thing enables the designer of a function API to set the desired relationships even if the implementation is doing some deviated preversion with the data (i.e. a ref counted object).
January 31, 2017
On Tuesday, 31 January 2017 at 19:26:51 UTC, Walter Bright wrote:
> On 1/31/2017 2:44 AM, Nordlöw wrote:
>> On Tuesday, 31 January 2017 at 10:20:59 UTC, Olivier FAURE wrote:
>>> I thought it meant "the parameter can be returned" not "the parameter *will*
>>> be returned".
>>
>> And what about multiple `return`-qualified function parameters?
>
> 'return' means treat the return value "as if" it was derived from that parameter. If multiple parameters are marked as 'return', treat the return value as if it was derived from one of them.
>
> This "as if" thing enables the designer of a function API to set the desired relationships even if the implementation is doing some deviated preversion with the data (i.e. a ref counted object).

Why is this feature used? Optimizations? Safety?
January 31, 2017
On Tuesday, 31 January 2017 at 01:30:48 UTC, Walter Bright wrote:
>
> By this information being knowable from the declaration, the compiler knows it too and can make use of it.

*Can* make use of it... But won't.
Any code calling memcpy has to be in a @trusted wrapper, in which `return scope` is not checked.
So adding `return scope` annotations to non-safe D binding is just like adding documentation. Which is on par with what C is doing, in the end.
January 31, 2017
On Tuesday, 31 January 2017 at 19:32:58 UTC, Nordlöw wrote:
> Why is this feature used? Optimizations? Safety?

Just me being lazy. I'm gonna read up on https://wiki.dlang.org/DIP25
January 31, 2017
On Tuesday, 31 January 2017 at 19:20:40 UTC, Walter Bright wrote:
> On 1/31/2017 5:50 AM, Richard Delorme wrote:
>> Well, I would not have taken memcpy as an example in favor of D. Good C
>> compilers (like gcc) know what memcpy does and are able to optimize it according
>> to its arguments. DMD may know better about memcpy through its declaration but
>> does not make any use about it.
>
> That may be true, but is not my point. The compiler cannot have built in knowledge of every function. I just used memcpy() as an example because it is extremely well known.
>
> As for making use of the type signature information, DMD uses it to check the memory safety of arguments supplied to memcpy(), something gcc does not do.

May we have an example of how the memory safety of arguments supplied to memcpy is checked in a way gcc cannot do?

I was thinking of the return attribute, that prevents for example to return the address of a local variable through a call to memcpy:

module dmemcpy;

import std.stdio;

extern (C) @system nothrow @nogc
pure void* memcpy(return void* s1, const scope void *s2, size_t n);

void *copy(const scope void *c, size_t n) {
	byte [16] d;
	return memcpy(&d[0], c, n);
}	

void main() {
	byte [16] a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
	byte *b = cast (byte*) copy(&a[0], 8);

	foreach (i; 0..16) write(b[i], ", ");
	writeln();
}
// ------- end ----------
$ dmd dmemcpy2.d
dmemcpy2.d(9): Error: escaping reference to local variable d

without the return attribute in memcpy declaration, dmd does not issue this error message.

The equivalent program in C:

#include <string.h>
#include <stdio.h>

void *copy(const void *c, size_t n) {
	char d[16];
	return memcpy(d, c, n);
}	

int main(void) {
	char a[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
	char *b = copy(a, 8);

	for (int i = 0; i < 16; ++i) printf("%d ", b[i]);
	putchar('\n');
}
// --- end of program ----
Compiling with gcc:
$ gcc memcpy2.c -O2 -W
memcpy2.c: In function 'copy':
memcpy2.c:6:9: warning: function returns address of local variable [-Wreturn-local-addr]
  return memcpy(d, c, n);
         ^~~~~~~~~~~~~~~
memcpy2.c:5:7: note: declared here
  char d[16];

Or with clang:
$ clang memcpy2.c --analyze
memcpy2.c:6:2: warning: Address of stack memory associated with local variable 'd' returned to caller
        return memcpy(d, c, n);
        ^~~~~~~~~~~~~~~~~~~~~~

So, even without a return attribute, good C compilers like gcc or clang are able to emit a warning message.

I am not really convinced by the necessity of attributes to enhance memory safety. I think the compiler should be able to check for safety without the user to ask it. Having to write attributes is a burden put on the user of the compiler. What if I forget to write an attribute? I just mistakenly make my program unsafe :-( Having a compiler checking for potential errors without me asking for is much safer in my humble opinion.

--
Richard Delorme

January 31, 2017
On 1/31/2017 3:00 PM, Richard Delorme wrote:
> May we have an example of how the memory safety of arguments supplied to memcpy
> is checked in a way gcc cannot do?
>
> I was thinking of the return attribute, that prevents for example to return the
> address of a local variable through a call to memcpy:

The thing about memcpy is compilers build in a LOT of information about it that simply is not there in the declaration. I suggest retrying your example for gcc/clang, but use your own memcpy, i.e.:

   void* mymemcpy(void * restrict s1, const void * restrict s2, size_t n);

Let us know what the results are!

January 31, 2017
On 1/31/2017 12:00 PM, Mathias Lang wrote:
> *Can* make use of it... But won't.
> Any code calling memcpy has to be in a @trusted wrapper, in which `return scope`
> is not checked.
> So adding `return scope` annotations to non-safe D binding is just like adding
> documentation. Which is on par with what C is doing, in the end.


----
import core.stdc.string;

void* foo()
{
    char[10] d;
    char[10] s;
    return memcpy(&d[0], &s[0], 10); // Error: escaping reference to local variable d
}
----

There was a bit of discussion about this a while back. The result was we agreed to not break existing NOT BROKEN code with the new escape detection feature. The above code is broken, and so is diagnosed regardless of -dip1000 settings, @safe, @trusted or @system attributes.
January 31, 2017
On 1/31/2017 11:32 AM, Nordlöw wrote:
> On Tuesday, 31 January 2017 at 19:26:51 UTC, Walter Bright wrote:
>> This "as if" thing enables the designer of a function API to set the desired
>> relationships even if the implementation is doing some deviated preversion
>> with the data (i.e. a ref counted object).
>
> Why is this feature used? Optimizations? Safety?

So ref counted containers can be built.

January 31, 2017
On Tuesday, 31 January 2017 at 23:42:43 UTC, Walter Bright wrote:
> On 1/31/2017 11:32 AM, Nordlöw wrote:
>> On Tuesday, 31 January 2017 at 19:26:51 UTC, Walter Bright wrote:
>>> This "as if" thing enables the designer of a function API to set the desired
>>> relationships even if the implementation is doing some deviated preversion
>>> with the data (i.e. a ref counted object).
>>
>> Why is this feature used? Optimizations? Safety?
>
> So ref counted containers can be built.

As long as they don't use a tree or any other datastructure that require more than one level of indirection internally.
February 01, 2017
Walter Bright <newshound2@digitalmars.com> wrote:
> Rust says https://doc.rust-lang.org/1.14.0/libc/fn.memcpy.html:
> 
>   pub unsafe extern fn memcpy(dest: *mut c_void,
>                             src: *const c_void,
>                             n: size_t)
>                             -> *mut c_void
> 
> 
> [...]
> The Rust declaration does not give us 1, 2 or 4 (because it is marked as
> unsafe). If it was safe, the declaration does not give us 2.

Using an FFI function to compare D vs Rust doesn't tell you much. Foreign
functions are usually not used directly in Rust, they are used to build
safe wrappers that will give you *all* possible guarantees, including type
safety.
As a consequence it's not necessary to augment the C declaration with
additional information.

Marking the function as safe would be wrong in Rust, because dereferencing raw pointers is unsafe. Raw pointers are not necessarily valid, even in safe code. You need references for that guarantee. But again, raw pointers are usually only used for FFI and to build safe abstractions.

Tobi