diff --git a/changelog/previewInLink.dd b/changelog/previewInLink.dd new file mode 100644 index 0000000000..f34cb5f315 --- /dev/null +++ b/changelog/previewInLink.dd @@ -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++. diff --git a/src/dmd/typesem.d b/src/dmd/typesem.d index cca24d6c84..d4149931c8 100644 --- a/src/dmd/typesem.d +++ b/src/dmd/typesem.d @@ -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()); diff --git a/test/fail_compilation/previewin2.d b/test/fail_compilation/previewin2.d new file mode 100644 index 0000000000..e9fe6a1fa8 --- /dev/null +++ b/test/fail_compilation/previewin2.d @@ -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); diff --git a/test/runnable_cxx/cppa.d b/test/runnable_cxx/cppa.d index e31588948a..cd91dd5583 100644 --- a/test/runnable_cxx/cppa.d +++ b/test/runnable_cxx/cppa.d @@ -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"); } diff --git a/test/runnable_cxx/extra-files/cppb.cpp b/test/runnable_cxx/extra-files/cppb.cpp index 4fa87efcff..83667cbddc 100644 --- a/test/runnable_cxx/extra-files/cppb.cpp +++ b/test/runnable_cxx/extra-files/cppb.cpp @@ -4,30 +4,8 @@ #include #include -#if _WIN32 // otherwise defined in C header files! -// https://issues.dlang.org/show_bug.cgi?id=18955 -namespace std -{ - template - struct char_traits - { - }; - template - class allocator - { - }; - template - class basic_string - { - }; - typedef basic_string, allocator > string; -} -#else // if POSIX - #include -#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); +}