Skip to content

Commit 8ffc8de

Browse files
dtoh: Don't assert when handling complex and imaginary types (dlang#12068)
* dtoh: Don't assert when handling complex and imaginary types * Fixup initial commit Co-authored-by: MoonlightSentinel <[email protected]>
1 parent 20b0788 commit 8ffc8de

File tree

5 files changed

+275
-14
lines changed

5 files changed

+275
-14
lines changed

changelog/dtoh-improvements.dd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ experimental C++ header generator:
66
- Declarations from template mixins are emitted into the instantation context
77
- (Superclass) methods aliases are emitted as `using ...` instead of `typedef ...`
88
- Renamed imports are emitted as `using ...`
9+
- Complex types are emitted as `_Complex`.
910

1011
Note: The header generator is still considerer experimental, so please submit
1112
any bugs encountered to [the bug tracker](https://issues.dlang.org).

src/dmd/astcodegen.d

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ struct ASTCodegen
5757
alias Tfloat80 = dmd.mtype.Tfloat80;
5858
alias Tfunction = dmd.mtype.Tfunction;
5959
alias Tpointer = dmd.mtype.Tpointer;
60+
alias Treference = dmd.mtype.Treference;
6061
alias Tident = dmd.mtype.Tident;
6162
alias Tint8 = dmd.mtype.Tint8;
6263
alias Tint16 = dmd.mtype.Tint16;
@@ -71,6 +72,13 @@ struct ASTCodegen
7172
alias Tvoid = dmd.mtype.Tvoid;
7273
alias Twchar = dmd.mtype.Twchar;
7374

75+
alias Timaginary32 = dmd.mtype.Timaginary32;
76+
alias Timaginary64 = dmd.mtype.Timaginary64;
77+
alias Timaginary80 = dmd.mtype.Timaginary80;
78+
alias Tcomplex32 = dmd.mtype.Tcomplex32;
79+
alias Tcomplex64 = dmd.mtype.Tcomplex64;
80+
alias Tcomplex80 = dmd.mtype.Tcomplex80;
81+
7482
alias ParameterList = dmd.mtype.ParameterList;
7583
alias VarArg = dmd.mtype.VarArg;
7684
alias STC = dmd.declaration.STC;

src/dmd/dtoh.d

Lines changed: 99 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,49 @@ public:
518518
buf.writeByte('_');
519519
}
520520

521+
/// Checks whether `t` is a type that can be exported to C++
522+
private bool isSupportedType(AST.Type t)
523+
{
524+
if (!t)
525+
{
526+
assert(tdparent);
527+
return true;
528+
}
529+
530+
switch (t.ty)
531+
{
532+
// Nested types
533+
case AST.Tarray:
534+
case AST.Tsarray:
535+
case AST.Tpointer:
536+
case AST.Treference:
537+
case AST.Tdelegate:
538+
return isSupportedType((cast(AST.TypeNext) t).next);
539+
540+
// Function pointers
541+
case AST.Tfunction:
542+
{
543+
auto tf = cast(AST.TypeFunction) t;
544+
if (!isSupportedType(tf.next))
545+
return false;
546+
foreach (_, param; tf.parameterList)
547+
{
548+
if (!isSupportedType(param.type))
549+
return false;
550+
}
551+
return true;
552+
}
553+
554+
// _Imaginary is C only.
555+
case AST.Timaginary32:
556+
case AST.Timaginary64:
557+
case AST.Timaginary80:
558+
return false;
559+
default:
560+
return true;
561+
}
562+
}
563+
521564
override void visit(AST.Dsymbol s)
522565
{
523566
debug (Debug_DtoH)
@@ -680,20 +723,7 @@ public:
680723
if ((tf && tf.linkage != LINK.c && tf.linkage != LINK.cpp) || (!tf && fd.isPostBlitDeclaration()))
681724
{
682725
ignored("function %s because of linkage", fd.toPrettyChars());
683-
684-
// Virtual extern(D) functions require a dummy declaration to ensure proper
685-
// vtable layout - but omit redundant declarations - the slot was already
686-
// reserved in the base class
687-
if (fd.isVirtual() && fd.introducing)
688-
{
689-
// Hide placeholders because they are not ABI compatible
690-
writeProtection(AST.Visibility.Kind.private_);
691-
692-
__gshared int counter; // Ensure unique names in all cases
693-
buf.printf("virtual void __vtable_slot_%u();", counter++);
694-
buf.writenl();
695-
}
696-
return;
726+
return checkVirtualFunction(fd);
697727
}
698728
if (!adparent && !fd.fbody)
699729
{
@@ -705,6 +735,20 @@ public:
705735
ignored("function %s because it is private", fd.toPrettyChars());
706736
return;
707737
}
738+
if (tf && !isSupportedType(tf.next))
739+
{
740+
ignored("function %s because its return type cannot be mapped to C++", fd.toPrettyChars());
741+
return checkVirtualFunction(fd);
742+
}
743+
if (tf) foreach (i, fparam; tf.parameterList)
744+
{
745+
if (!isSupportedType(fparam.type))
746+
{
747+
ignored("function %s because one of its parameters has type `%s` which cannot be mapped to C++",
748+
fd.toPrettyChars(), fparam.type.toChars());
749+
return checkVirtualFunction(fd);
750+
}
751+
}
708752

709753
writeProtection(fd.visibility.kind);
710754

@@ -773,6 +817,23 @@ public:
773817

774818
}
775819

820+
/// Checks whether `fd` is a virtual function and emits a dummy declaration
821+
/// if required to ensure proper vtable layout
822+
private void checkVirtualFunction(AST.FuncDeclaration fd)
823+
{
824+
// Omit redundant declarations - the slot was already
825+
// reserved in the base class
826+
if (fd.isVirtual() && fd.introducing)
827+
{
828+
// Hide placeholders because they are not ABI compatible
829+
writeProtection(AST.Visibility.Kind.private_);
830+
831+
__gshared int counter; // Ensure unique names in all cases
832+
buf.printf("virtual void __vtable_slot_%u();", counter++);
833+
buf.writenl();
834+
}
835+
}
836+
776837
override void visit(AST.UnitTestDeclaration utd)
777838
{
778839
debug (Debug_DtoH)
@@ -870,6 +931,11 @@ public:
870931
ignored("variable %s because of linkage", vd.toPrettyChars());
871932
return;
872933
}
934+
if (!isSupportedType(vd.type))
935+
{
936+
ignored("variable %s because its type cannot be mapped to C++", vd.toPrettyChars());
937+
return;
938+
}
873939
writeProtection(vd.visibility.kind);
874940
typeToBuffer(vd.type, vd, adparent && !(vd.storage_class & (AST.STC.static_ | AST.STC.gshared)));
875941
buf.writestringln(";");
@@ -889,6 +955,11 @@ public:
889955
ignored("variable %s because of thread-local storage", vd.toPrettyChars());
890956
return;
891957
}
958+
if (!isSupportedType(vd.type))
959+
{
960+
ignored("variable %s because its type cannot be mapped to C++", vd.toPrettyChars());
961+
return;
962+
}
892963
writeProtection(vd.visibility.kind);
893964
if (vd.linkage == LINK.c)
894965
buf.writestring("extern \"C\" ");
@@ -1761,6 +1832,20 @@ public:
17611832
typeName = "_d_real";
17621833
hasReal = true;
17631834
break;
1835+
case AST.Tcomplex32: typeName = "_Complex float"; break;
1836+
case AST.Tcomplex64: typeName = "_Complex double"; break;
1837+
case AST.Tcomplex80:
1838+
typeName = "_Complex _d_real";
1839+
hasReal = true;
1840+
break;
1841+
// ???: This is not strictly correct, but it should be ignored
1842+
// in all places where it matters most (variables, functions, ...).
1843+
case AST.Timaginary32: typeName = "float"; break;
1844+
case AST.Timaginary64: typeName = "double"; break;
1845+
case AST.Timaginary80:
1846+
typeName = "_d_real";
1847+
hasReal = true;
1848+
break;
17641849
default:
17651850
//t.print();
17661851
assert(0);

test/compilable/dtoh_ignored.d

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/++
2+
REQUIRED_ARGS: -HC=verbose -c -o- -d
3+
PERMUTE_ARGS:
4+
TEST_OUTPUT:
5+
---
6+
// Automatically generated by Digital Mars D Compiler v2097
7+
8+
#pragma once
9+
10+
#include <assert.h>
11+
#include <stddef.h>
12+
#include <stdint.h>
13+
#include <math.h>
14+
15+
#ifdef CUSTOM_D_ARRAY_TYPE
16+
#define _d_dynamicArray CUSTOM_D_ARRAY_TYPE
17+
#else
18+
/// Represents a D [] array
19+
template<typename T>
20+
struct _d_dynamicArray
21+
{
22+
size_t length;
23+
T *ptr;
24+
25+
_d_dynamicArray() : length(0), ptr(NULL) { }
26+
27+
_d_dynamicArray(size_t length_in, T *ptr_in)
28+
: length(length_in), ptr(ptr_in) { }
29+
30+
T& operator[](const size_t idx) {
31+
assert(idx < length);
32+
return ptr[idx];
33+
}
34+
35+
const T& operator[](const size_t idx) const {
36+
assert(idx < length);
37+
return ptr[idx];
38+
}
39+
};
40+
#endif
41+
#if !defined(_d_real)
42+
# define _d_real long double
43+
#endif
44+
45+
class WithImaginary
46+
{
47+
public:
48+
float memberIf;
49+
double memberId;
50+
_d_real memberIr;
51+
_Complex float memberCf;
52+
_Complex double memberCd;
53+
_Complex _d_real memberCr;
54+
_d_dynamicArray< float > nested;
55+
// Ignored function dtoh_ignored.WithImaginary.onReturn because its return type cannot be mapped to C++
56+
private:
57+
virtual void __vtable_slot_0();
58+
// Ignored function dtoh_ignored.WithImaginary.onParam because one of its parameters has type `ifloat` which cannot be mapped to C++
59+
virtual void __vtable_slot_1();
60+
};
61+
62+
template <typename T>
63+
struct WithImaginaryTemplate
64+
{
65+
// Ignoring var member alignment 0
66+
float member;
67+
// Ignored function onReturn because its return type cannot be mapped to C++
68+
// Ignored function onParam because one of its parameters has type `ifloat` which cannot be mapped to C++
69+
// Ignoring var onVariable alignment 0
70+
// Ignored variable onVariable because of linkage
71+
WithImaginaryTemplate()
72+
{
73+
}
74+
};
75+
76+
extern WithImaginaryTemplate<int32_t > instance;
77+
78+
// Ignored variable dtoh_ignored.onVariable because its type cannot be mapped to C++
79+
// Ignored variable dtoh_ignored.onVariablePointer because its type cannot be mapped to C++
80+
// Ignored variable dtoh_ignored.onVariableSlice because its type cannot be mapped to C++
81+
// Ignored variable dtoh_ignored.onVariableArray because its type cannot be mapped to C++
82+
extern void* onVariableAssocArray;
83+
84+
// Ignored variable dtoh_ignored.onVariableFunction because its type cannot be mapped to C++
85+
// Ignored variable dtoh_ignored.onVariableFunctionParam because its type cannot be mapped to C++
86+
// Ignored variable dtoh_ignored.onVariableDelegate because its type cannot be mapped to C++
87+
88+
---
89+
+/
90+
91+
extern (C++):
92+
93+
class WithImaginary
94+
{
95+
ifloat memberIf;
96+
idouble memberId;
97+
ireal memberIr;
98+
99+
cfloat memberCf;
100+
cdouble memberCd;
101+
creal memberCr;
102+
103+
ifloat[] nested;
104+
105+
ifloat onReturn()
106+
{
107+
return 0i;
108+
}
109+
110+
void onParam(ifloat) {}
111+
}
112+
113+
struct WithImaginaryTemplate(T)
114+
{
115+
ifloat member;
116+
117+
ifloat onReturn()
118+
{
119+
return 0i;
120+
}
121+
122+
void onParam(ifloat)
123+
{
124+
}
125+
126+
__gshared ifloat onVariable;
127+
}
128+
129+
__gshared WithImaginaryTemplate!int instance;
130+
131+
__gshared ifloat onVariable;
132+
133+
__gshared ifloat** onVariablePointer;
134+
135+
__gshared ifloat[] onVariableSlice;
136+
137+
__gshared ifloat[2] onVariableArray;
138+
139+
__gshared ifloat[int] onVariableAssocArray;
140+
141+
__gshared ifloat function() onVariableFunction;
142+
143+
__gshared void function(ifloat) onVariableFunctionParam;
144+
145+
__gshared ifloat delegate() onVariableDelegate;

test/compilable/dtoh_invalid_identifiers.d

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,19 @@ class Alias : public typename_
102102
};
103103
104104
extern void user(Alias* i);
105+
106+
template <typename typename_>
107+
struct InvalidNames
108+
{
109+
// Ignoring var register alignment 0
110+
typename_ register_;
111+
void foo(typename_ and_);
112+
InvalidNames()
113+
{
114+
}
115+
};
116+
117+
extern void useInvalid(InvalidNames<int32_t > _param_0);
105118
---
106119
+/
107120
#line 100
@@ -136,3 +149,12 @@ class Base {
136149
class Alias(typename) : typename {}
137150

138151
void user(Alias!Base i) {}
152+
153+
struct InvalidNames(typename)
154+
{
155+
typename register;
156+
157+
void foo(typename and) {}
158+
}
159+
160+
void useInvalid(InvalidNames!int) {}

0 commit comments

Comments
 (0)