Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.

Commit 0572437

Browse files
authored
Merge pull request #2719 from TurkeyMan/string_on_gcc_modern
Fix string tests not running merged-on-behalf-of: Nicholas Wilson <thewilsonator@users.noreply.github.com>
2 parents 6dc5e77 + 733d85f commit 0572437

File tree

4 files changed

+70
-76
lines changed

4 files changed

+70
-76
lines changed

changelog/std_string.dd

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
Added `core.stdcpp.string`.
22

3-
Added `core.stdcpp.string`, which links against C++ `std::string`
3+
Added `core.stdcpp.string`, which links against C++ `std::basic_string`
44

5-
Currently only supported and tested for the Visual Studio C++ runtime library. Other runtimes coming soon(tm)!
5+
Known issues:
6+
7+
Currently, the GCC (`libstdc++`) implementation has a known issue with the modern `__cxx11` ABI, because the C++ struct contains an interior pointer which is illegal in D, and incompatible with D move semantics.
8+
To use `core.stdcpp.string` on linux/GCC, you must use the old string ABI by supplying `-D_GLIBCXX_USE_CXX11_ABI=0` to `g++`, and also `-version=_GLIBCXX_USE_CXX98_ABI` to your D compiler.
9+
Work to define D move constructors is ongoing and expected to resolve this issue when it arrives.

src/core/stdcpp/string.d

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,37 +13,42 @@
1313
module core.stdcpp.string;
1414

1515
import core.stdcpp.allocator;
16+
import core.stdcpp.xutility : StdNamespace;
1617
import core.stdc.stddef : wchar_t;
1718

19+
version (OSX)
20+
{
21+
// Apple decided to rock a different ABI... good for them!
22+
version = _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT;
23+
}
1824
version (CppRuntime_Gcc)
1925
{
2026
version (_GLIBCXX_USE_CXX98_ABI)
2127
{
22-
private enum StdNamespace = "std";
28+
private enum StringNamespace = "std";
2329
// version = __GTHREADS; // TODO: we need to make ref-count interactions atomic
2430
}
2531
else
2632
{
2733
import core.internal.traits : AliasSeq;
28-
private enum StdNamespace = AliasSeq!("std", "__cxx11");
34+
private enum StringNamespace = AliasSeq!("std", "__cxx11");
2935
}
3036
}
3137
else
32-
import core.stdcpp.xutility : StdNamespace;
38+
alias StringNamespace = StdNamespace;
3339

3440
enum DefaultConstruct { value }
3541

3642
/// Constructor argument for default construction
3743
enum Default = DefaultConstruct();
3844

39-
extern(C++, (StdNamespace)):
4045
@nogc:
4146

4247
/**
4348
* Character traits classes specify character properties and provide specific
4449
* semantics for certain operations on characters and sequences of characters.
4550
*/
46-
struct char_traits(CharT) {}
51+
extern(C++, (StdNamespace)) struct char_traits(CharT) {}
4752

4853
// I don't think we can have these here, otherwise symbols are emit to druntime, and we don't want that...
4954
//alias std_string = basic_string!char;
@@ -57,6 +62,7 @@ struct char_traits(CharT) {}
5762
* C++ reference: $(LINK2 https://en.cppreference.com/w/cpp/string/basic_string)
5863
*/
5964
extern(C++, class)
65+
extern(C++, (StringNamespace))
6066
struct basic_string(T, Traits = char_traits!T, Alloc = allocator!T)
6167
{
6268
extern(D):
@@ -727,6 +733,8 @@ extern(D):
727733
}
728734
else
729735
{
736+
pragma(msg, "libstdc++ std::__cxx11::basic_string is not yet supported; the struct contains an interior pointer which breaks D move semantics!");
737+
730738
//----------------------------------------------------------------------------------
731739
// GCC/libstdc++ modern implementation
732740
//----------------------------------------------------------------------------------
@@ -1309,8 +1317,8 @@ private:
13091317
version (CppRuntime_Microsoft)
13101318
{
13111319
import core.stdcpp.xutility : _ITERATOR_DEBUG_LEVEL;
1312-
extern(C++, "std"):
13131320

1321+
extern(C++, (StdNamespace)):
13141322
extern (C++) struct _String_base_types(_Elem, _Alloc)
13151323
{
13161324
alias Ty = _Elem;

test/stdcpp/Makefile

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,22 @@ TESTS:=allocator new
66
TESTS11:=array
77
TESTS17:=string_view
88
OLDABITESTS:=
9-
LIBCPPTESTS:=
109

1110
ifeq (osx,$(OS))
12-
TESTS+=string
11+
# TESTS+=string
1312
# TESTS+=vector
1413
endif
1514
ifeq (linux,$(OS))
16-
# TESTS+=string vector
15+
# TESTS+=string
16+
# TESTS+=vector
1717
OLDABITESTS+=string
18-
# OLDABITESTS+=vector
19-
# LIBCPPTESTS:=string
2018
endif
2119
ifeq (freebsd,$(OS))
2220
TESTS+=string
2321
# TESTS+=vector
2422
endif
2523

24+
# some build machines have ancient compilers, so we need to disable C++17 tests
2625
ifneq (yes,$(HASCPP17))
2726
TESTS17:=
2827
endif
@@ -59,11 +58,6 @@ $(ROOT)/%_old.done : $(ROOT)/%_old
5958
@echo Testing $*_old
6059
$(QUIET)$(TIMELIMIT)$(ROOT)/$*_old $(RUN_ARGS)
6160
@touch $@
62-
# run libc++ tests with GCC
63-
$(ROOT)/%_libcpp.done : $(ROOT)/%_libcpp
64-
@echo Testing $*_libcpp
65-
$(QUIET)$(TIMELIMIT)$(ROOT)/$*_libcpp $(RUN_ARGS)
66-
@touch $@
6761

6862
# build C++98 tests
6963
$(ROOT)/%: $(SRC)/%.cpp $(SRC)/%_test.d
@@ -85,11 +79,6 @@ $(ROOT)/%_old: $(SRC)/%.cpp $(SRC)/%_test.d
8579
mkdir -p $(dir $@)
8680
$(QUIET)$(DMD) $(DFLAGS) -version=_GLIBCXX_USE_CXX98_ABI -main -unittest -c -of=$(ROOT)/$*_old_d.o $(SRC)/$*_test.d
8781
$(QUIET)$(CXX) $(CXXFLAGS_BASE) -D_GLIBCXX_USE_CXX11_ABI=0 -o $@ $< $(ROOT)/$*_old_d.o $(DRUNTIME) -lpthread
88-
# build libc++ tests with GCC
89-
$(ROOT)/%_libcpp: $(SRC)/%.cpp $(SRC)/%_test.d
90-
mkdir -p $(dir $@)
91-
$(QUIET)$(DMD) $(DFLAGS) -version=CppRuntime_Clang -main -unittest -c -of=$(ROOT)/$*_libcpp_d.o $(SRC)/$*_test.d
92-
$(QUIET)$(CXX) $(CXXFLAGS_BASE) -stdlib=libc++ -o $@ $< $(ROOT)/$*_libcpp_d.o $(DRUNTIME) -lpthread
9382

9483
clean:
9584
rm -rf $(GENERATED)

test/stdcpp/src/string_test.d

Lines changed: 46 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -7,59 +7,52 @@ alias std_wstring = basic_string!wchar;
77

88
unittest
99
{
10-
version(Windows)
11-
{
12-
std_string str = std_string("Hello");
13-
14-
assert(str.size == 5);
15-
assert(str.length == 5);
16-
assert(str.empty == false);
17-
18-
assert(sumOfElements_val(str) == 1500);
19-
assert(sumOfElements_ref(str) == 500);
20-
21-
str = "Hello again with a long long string woo";
22-
assert(sumOfElements_val(str) == 10935);
23-
assert(sumOfElements_ref(str) == 3645);
24-
25-
std_string str2 = std_string(Default);
26-
assert(str2.size == 0);
27-
assert(str2.length == 0);
28-
assert(str2.empty == true);
29-
assert(str2[] == []);
30-
31-
str2 = std_string("World");
32-
assert(str2[] == "World");
33-
str = str2;
34-
assert(str[] == "World");
35-
str2 = "Direct";
36-
assert(str2[] == "Direct");
37-
assert(str2[2] == 'r');
38-
assert(str2[2 .. 5] == "rec");
39-
str2[] = "Plonk!";
40-
assert(str2[] == "Plonk!");
41-
str2[2] = 'a';
42-
str2[3 .. 5] = "ne";
43-
assert(str2[] == "Plane!");
44-
str2[] = 'a';
45-
str2[1 .. 5] = 'b';
46-
str2[] += 1;
47-
str2[1] += 1;
48-
str2[2 .. 4] += 2;
49-
assert(str2[] == "bdeecb");
50-
51-
// test local instantiations...
52-
// there's no basic_string<char16_t> instantiation in C++
53-
std_wstring str3 = std_wstring("Hello"w);
54-
55-
assert(str3.size == 5);
56-
assert(str3.length == 5);
57-
assert(str3.empty == false);
58-
}
59-
else
60-
{
61-
pragma(msg, "std.string implementation not yet done for linux - gcc/clang");
62-
}
10+
std_string str = std_string("Hello");
11+
12+
assert(str.size == 5);
13+
assert(str.length == 5);
14+
assert(str.empty == false);
15+
16+
assert(sumOfElements_val(str) == 1500);
17+
assert(sumOfElements_ref(str) == 500);
18+
19+
str = "Hello again with a long long string woo";
20+
assert(sumOfElements_val(str) == 10935);
21+
assert(sumOfElements_ref(str) == 3645);
22+
23+
std_string str2 = std_string(Default);
24+
assert(str2.size == 0);
25+
assert(str2.length == 0);
26+
assert(str2.empty == true);
27+
assert(str2[] == []);
28+
29+
str2 = std_string("World");
30+
assert(str2[] == "World");
31+
str = str2;
32+
assert(str[] == "World");
33+
str2 = "Direct";
34+
assert(str2[] == "Direct");
35+
assert(str2[2] == 'r');
36+
assert(str2[2 .. 5] == "rec");
37+
str2[] = "Plonk!";
38+
assert(str2[] == "Plonk!");
39+
str2[2] = 'a';
40+
str2[3 .. 5] = "ne";
41+
assert(str2[] == "Plane!");
42+
str2[] = 'a';
43+
str2[1 .. 5] = 'b';
44+
str2[] += 1;
45+
str2[1] += 1;
46+
str2[2 .. 4] += 2;
47+
assert(str2[] == "bdeecb");
48+
49+
// test local instantiations...
50+
// there's no basic_string<char16_t> instantiation in C++
51+
std_wstring str3 = std_wstring("Hello"w);
52+
53+
assert(str3.size == 5);
54+
assert(str3.length == 5);
55+
assert(str3.empty == false);
6356
}
6457

6558

0 commit comments

Comments
 (0)