Allow -preview=in only with extern(D|C++)

The intent of `-preview=in` is to make `in` the go-to storage class for input parameters in D.
However it is D centric, as it is an enhanced version of `scope const ref`.
As non-`extern(D)` functions usually are expected to match a specific ABI,
using `in` is hardly a good idea.

However, as C++, also have a "go to" storage class for input parameters (`const T&`),
`in` can also be applied on `extern(C++)` function in order to bind to `const T&` parameters.
This also allows to expose a closer API for a function than via `const ref`,
as `in` will allow to bind rvalues to `const T&`, as in C++.
This commit is contained in:
Geod24 2021-02-24 19:31:56 +09:00 committed by The Dlang Bot
parent 37436a4446
commit b3cc517966
5 changed files with 75 additions and 23 deletions

View file

@ -0,0 +1,11 @@
`-preview=in` can now be used with `extern(C++)`, disabled for other non-D linkage
The intent of `-preview=in` is to make `in` the go-to storage class for input parameters in D.
However, it is D centric, as it is an enhanced version of `scope const ref`.
As non-`extern(D)` functions usually are expected to match a specific ABI,
using `in` is hardly a good idea.
As C++ also has a "go to" storage class for input parameters (`const T&`),
`in` can also be applied on `extern(C++)` function in order to bind to `const T&` parameters.
This also allows to expose a closer API for a function than via `const ref`,
as `in` will allow to bind rvalues to `const T&`, as in C++.

View file

@ -1224,6 +1224,25 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
continue;
}
// -preview=in: Always add `ref` when used with `extern(C++)` functions
// Done here to allow passing opaque types with `in`
if (global.params.previewIn && (fparam.storageClass & (STC.in_ | STC.ref_)) == STC.in_)
{
switch (tf.linkage)
{
case LINK.cpp:
fparam.storageClass |= STC.ref_;
break;
case LINK.default_, LINK.d:
break;
default:
.error(loc, "cannot use `in` parameters with `extern(%s)` functions",
linkageToChars(tf.linkage));
.errorSupplemental(loc, "parameter `%s` declared as `in` here", fparam.toChars());
break;
}
}
if (t.ty == Tfunction)
{
.error(loc, "cannot have parameter of function type `%s`", fparam.type.toChars());

View file

@ -0,0 +1,18 @@
/*
REQUIRED_ARGS: -preview=in -preview=dip1000
TEST_OUTPUT:
---
fail_compilation/previewin2.d(1): Error: cannot use `in` parameters with `extern(C)` functions
fail_compilation/previewin2.d(1): parameter `a` declared as `in` here
fail_compilation/previewin2.d(2): Error: cannot use `in` parameters with `extern(Windows)` functions
fail_compilation/previewin2.d(2): parameter `a` declared as `in` here
fail_compilation/previewin2.d(4): Error: cannot use `in` parameters with `extern(C)` functions
fail_compilation/previewin2.d(4): parameter `__anonymous_param` declared as `in` here
---
*/
#line 1
extern(C) void wrongLink1 (in int a);
extern(Windows) void wrongLink2 (in void* a);
struct Large { ulong[64] data; }
extern(C) void wrongLink3 (in Large);

View file

@ -1,3 +1,4 @@
// REQUIRED_ARGS: -preview=in
// PERMUTE_ARGS: -g
// EXTRA_CPP_SOURCES: cppb.cpp
// EXTRA_FILES: extra-files/cppb.h
@ -1637,7 +1638,13 @@ void test19134()
}
// https://issues.dlang.org/show_bug.cgi?id=18955
alias std_string = std.basic_string!(char);
version (linux)
alias std_string = std.basic_string!(char);
else
{
import core.stdcpp.string : core_basic_string = basic_string;
alias std_string = core_basic_string!(char);
}
extern(C++) void callback18955(ref const(std_string) str)
{
@ -1646,6 +1653,16 @@ extern(C++) void test18955();
/****************************************/
extern(C++) void testPreviewIn();
extern(C++) void previewInFunction(in int a, in std_string b, ref const(std_string) c)
{
assert(a == 42);
assert(&b is &c);
}
/****************************************/
void main()
{
test1();
@ -1695,6 +1712,7 @@ void main()
test18966();
test19134();
test18955();
testPreviewIn();
printf("Success\n");
}

View file

@ -4,30 +4,8 @@
#include <exception>
#include <cstdarg>
#if _WIN32 // otherwise defined in C header files!
// https://issues.dlang.org/show_bug.cgi?id=18955
namespace std
{
template<typename Char>
struct char_traits
{
};
template<typename Char>
class allocator
{
};
template<typename Char, typename Traits, typename Alloc>
class basic_string
{
};
typedef basic_string<char, char_traits<char>, allocator<char> > string;
}
#else // if POSIX
#include <string>
#endif // _WIN32
#include "cppb.h"
/**************************************/
@ -936,3 +914,11 @@ void test18955()
callback18955(s);
#endif
}
void previewInFunction(const int& a, const std::string& b, const std::string& c);
void testPreviewIn()
{
std::string s = "Hello World";
previewInFunction(42, s, s);
}