September 05, 2019
On Friday, 2 August 2019 at 13:17:46 UTC, Gregor Mückl wrote:
> On Tuesday, 30 July 2019 at 14:50:15 UTC, Eduard Staniloiu wrote:
>> Another question is how should `align(n)` be generated. See the following two:
>>
>> 1) __attribute__((packed, aligned(n)))
>>
>> or
>>
>> 2) __attribute__((aligned(n)))
>>
>> Note the missing `packed` between 1) and 2)
>>
>> Currently (on GH) the entire generated output looks like this
>>
>> struct
>> #if defined(__GNUC__) || defined(__clang__)
>>     __attribute__((packed, aligned(8)))
>> #elif defined(_MSC_VER)
>>     __declspec(align(8))
>> #elif defined(__DMC__)
>>     #pragma pack(push, 8)
>> #endif
>> MyStruct
>> {
>>   /* fields */
>> }
>> #if defined(__DMC__)
>>     #pragma pack(pop)
>> #endif
>
> This only covers structure packing rules, right? So alignment of the aggregate as a whole (equivalent to C++ alignas(n) statement) is out of scope?
>
> If so,
>
> #pragma pack(push,n)
>
> and
>
> #pragma pack(pop,n)
>
> work on MSVC, GCC and clang in my experience. DMC is documented to have the same behavior. So you should be able to dispense with the #ifdef's completely.

I missed your reply. Sorry about that.

`#pragma pack(push/pop, n)` was initially used, but when testing it didn't have the same behaviour as `__attribute__((packed, aligned(n)))` so I ended up with the entire `#ifdef` tree above.

I could generate `alignas(n)` when the user compiles with `-extern-std=c++11` and above, but I'm currently working on correctly generating the ctors and dtors declarations.
September 05, 2019
> On Thursday, 5 September 2019 at 11:25:47 UTC, Eduard Staniloiu wrote:
> [...]
> I'm currently working on correctly generating the ctors and dtors declarations.

More details about the above.

When I began working on the project, the code was generating two ctors for each `struct`
  1. a default ctor that was initializing all the struct fields with their default value
  2. a ctor that took all the struct field types as arguments and assigned the supplied arguments to each struct field (Ex. `this->x = x`).

The above two replicate (almost) the D behavior of constructing a struct that has no ctor defined. I say almost because you can either use the default ctor, or you **must** pass all the field arguments to the ctor (in D you can pass as many as you want, not all).

When I first saw this and ran it with Razvan and Andrei and we said "Thats odd. The tool should only generate declarations, not definitions". I asked Iain about it and he said he couldn't remember why it was there, but probably he needed it at some point. So, in the light of this, we took the decision of dropping the ctor definition generation until further notice.

Well, this week I had an epiphany: for any struct, we have to generate the default ctor definition because on the D side, fields are default initialized to their `.init` value. If one would construct a struct (Ex. on the stack) on the C++ side, then the code could break.

Let's see the following simple struct example
```
// D module

extern (C++) struct S
{
  int* ptr;
  void apiFun() {
    if (ptr) {
      /* do stuff */
    }
  }
}

void bar()
{
  S s;
  s.apiFun();
}

// C++ code

// Generated struct header
struct S
{
  int* ptr;
  void apiFun();
};

void gun()
{
  S s;
  s.apiFun();
}
```

The `bar` function, being on the D side, is fine.
The `gun` function on the other hand, will be UB.

This is bad.

Starting from this, I came to the following conclusions:
  - For any `extern (C++)` struct, a default ctor must be generated
  - If a struct defines a dtor, a declaration must be generated: `virtual ~A();`
  - For any defined ctors, a declaration must be generated

I think that if a struct defines a copy ctor, an opAssign, then an equivalent C++ declaration must be generated.

What do you think, folks?

Cheers,
Edi

September 05, 2019
On Thu, Sep 5, 2019 at 5:01 AM Eduard Staniloiu via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> > On Thursday, 5 September 2019 at 11:25:47 UTC, Eduard Staniloiu
> > wrote:
> > [...]
> > I'm currently working on correctly generating the ctors and
> > dtors declarations.
>
> More details about the above.
>
> When I began working on the project, the code was generating two
> ctors for each `struct`
>    1. a default ctor that was initializing all the struct fields
> with their default value
>    2. a ctor that took all the struct field types as arguments and
> assigned the supplied arguments to each struct field (Ex.
> `this->x = x`).
>
> The above two replicate (almost) the D behavior of constructing a struct that has no ctor defined. I say almost because you can either use the default ctor, or you **must** pass all the field arguments to the ctor (in D you can pass as many as you want, not all).
>
> When I first saw this and ran it with Razvan and Andrei and we said "Thats odd. The tool should only generate declarations, not definitions". I asked Iain about it and he said he couldn't remember why it was there, but probably he needed it at some point. So, in the light of this, we took the decision of dropping the ctor definition generation until further notice.
>
> Well, this week I had an epiphany: for any struct, we have to generate the default ctor definition because on the D side, fields are default initialized to their `.init` value. If one would construct a struct (Ex. on the stack) on the C++ side, then the code could break.
>
> Let's see the following simple struct example
> ```
> // D module
>
> extern (C++) struct S
> {
>    int* ptr;
>    void apiFun() {
>      if (ptr) {
>        /* do stuff */
>      }
>    }
> }
>
> void bar()
> {
>    S s;
>    s.apiFun();
> }
>
> // C++ code
>
> // Generated struct header
> struct S
> {
>    int* ptr;
>    void apiFun();
> };
>
> void gun()
> {
>    S s;
>    s.apiFun();
> }
> ```
>
> The `bar` function, being on the D side, is fine.
> The `gun` function on the other hand, will be UB.
>
> This is bad.
>
> Starting from this, I came to the following conclusions:
>    - For any `extern (C++)` struct, a default ctor must be
> generated

We have discussed responding to the C++ language version before, and for >= C++11 it would be nice to use member initialisers rather than a default ctor.

>    - If a struct defines a dtor, a declaration must be generated:
> `virtual ~A();`

Not virtual though right?

>    - For any defined ctors, a declaration must be generated

A constructor is no different than any other method. I expect you're emiting all the methods right?

> I think that if a struct defines a copy ctor, an opAssign, then an equivalent C++ declaration must be generated.

These are just normal methods too... if a method has a C++
counterpart, then emit a declaration for it. This includes all
constructors (except postblit, that guy's a problem).
You could translate operators (perhaps as a stretch goal), ie;
opAssign -> operator=

> What do you think, folks?

I think declarations for all methods that have a valid C++ counterpart should be emit... no?


On a tangent, can you confirm where you landed with respect to the enum discussion? I want to be sure we landed in a satisfying place. Did you go with the fully-loaded macro solution, so the client can define the macro's to taste?
September 06, 2019
On Thursday, 5 September 2019 at 11:25:47 UTC, Eduard Staniloiu wrote:
>
> `#pragma pack(push/pop, n)` was initially used, but when testing it didn't have the same behaviour as `__attribute__((packed, aligned(n)))` so I ended up with the entire `#ifdef` tree above.

Can you give a quick summary of the differences that you encountered? I believe you, but I'm curious because this goes completely against my expectations.
1 2 3 4 5 6 7
Next ›   Last »