Skip to content

Add C++ Const Mangling DIP#143

Closed
ghost wants to merge 3 commits intomasterfrom
unknown repository
Closed

Add C++ Const Mangling DIP#143
ghost wants to merge 3 commits intomasterfrom
unknown repository

Conversation

@ghost
Copy link

@ghost ghost commented Feb 4, 2019

No description provided.

@Bolpat
Copy link
Contributor

Bolpat commented Feb 4, 2019

I really like the syntax const(*).

On the other hand, I find it very confusing to write T const** to mean T const(**). I'd only allow the version with parentheses. It is much easier to understand and I don't think syntactical sugar is needed for the case where the parentheses span until the end. Compare this

C++ D
T const* const(T)*
T *const T const(*) (propsed)

Using the terminology of D's grammar, in D, const without parentheses is a storage class, not a type constructor. As such, it cannot be part of a type (e.g. in D, there is no ref(T)[] because ref is not a type constructor).

You propose a new postfix type constructor const(*) (the other postfix type constructors are [] and * for slices and pointers), where T const(**) is a shorthand for T const(*)const(*).

Implementing the type wouldn't be that difficult at all. Basically, T const(*) would only be a specially mangled type implemented as

struct FinalPtr(T)
{
    private T* ptr;
    alias ptr this;
@disable:
    this();
    void opAssign(T...)(T);
    void opOpAssign(string op, T...)(T);
    T* opUnary(string op)() if (op == '+' || op == '-');
}

An alternative to proposing a new type constructor might be the possibility to mangle struct/class templates in some generic manner. Unfortunately, I don't know much about mangling, so I have no idea how viable this alternative actually is.

@ghost
Copy link
Author

ghost commented Feb 5, 2019

Yah I wasn't sure about changing the behavior of const compared to C++ but also didn't want to break that const T** means all the pointers and types are const. Restricting it to require parentheses would be fine.

It would also need to allow for const at the end. Or at least some way of handling this case:

void foo(T)(T const p);
foo!(void*)( null ); // mangled as `void const(*)` as it does in C++

For mangling this would only be for C++, so it would have to go about the way C++ does it. C++ has different mangling for every possible variation, even though it only allows one overload to exist with that specific number of indirections.

// C++
void foo(void*);
void foo(void* const); // error redefinition of foo

@Bolpat
Copy link
Contributor

Bolpat commented Feb 5, 2019

I'm not sure I understand what you mean.

First, you're right that suggesting const T** not meaning const(T**) anymore would never ever get approved. Note still that in the former, const is a storage class that has the effect of applying a type constructor while the latter is applying a type constructor. The difference comes to effect on member functions: const T fun() is not the same as const(T) fun(). You don't want to introduce a storage class together with the type constuctor; it would be possible, but not very useful, the same way * and [] aren't storage classes either.

As stated, if const(*) is a type constructor, it is an atom like * itself. This function template

void foo(T)(T const p);

is still ill-formed (I'm not 100% sure that void foo(T)(T const p); is currently invalid and doesn't mean the same as void foo(T)(const(T) p);, but I think so).
For T = void*, the definition becomes foo(void* const p) which is ill-formed; you want foo(void const(*) p), which is conforming with your proposal.

There is no way to make a template simply replace void* by void const(*), the same way you cannot make void[] to void*; you can do so using an alias template though:

foo(T)(HeadConstPtr!T p);
alias HeadConstPtr(T : T*) = T const(*);.

Then foo!(void*) is a function having a head-const pointer to void as the parameter type.

Introducing a non-assignable pointer type constructor is the only sane way I see.

// C++
int *const *pp;
// D
extern(C++) const(int*)* pp;

Looks fine, but isn't. While changes made by the C++ program won't interfere with the D part, the other way around is well possible.

// D
static immutable int* ip = new immutable int(1);
void fun()
{
    pp = &ip; // fine in D: immutable(int*) casts to const(int*).
}
// C++
void gun()
{
    **pp = 2; // overwrites D's immutable value.
}

Without the ability to express that, the type system cannot guarantee correctness. And currently, there is nothing that expresses C++'s const.

There is also a bit of asymmetry as there is T* and T const(*), but for T[] there is no T const([]) (which looks weird by the way).

@ghost
Copy link
Author

ghost commented Feb 5, 2019

I don't really follow what you are saying,

Introducing a non-assignable pointer type constructor is the only sane way I see.

This is not the purpose of the DIP and I think it is perfectly doable without that. This only changes the mangling for C++ only.

// C++
int *const *pp;
// D
extern(C++) const(int*)* pp; // undefined reference, should not link with C++ variable, different types

There is no way to make a template simply replace void* by void const(*)

You aren't replacing anything. It will work the same as:

void foo(T)(const T v) {
    writeln( typeof(v).stringof ); 
}
foo!(void*)( null ); // prints const void*

It is really just being expanded to the equivalent:

extern(C++) void foo( void * const ); // synonymous with void const(*)

There is also a bit of asymmetry as there is T* and T const(*), but for T[] there is no T const([]) (which looks weird by the way).

You can't use T[] for extern(C++) so that doesn't really make a difference.

@mdparker
Copy link
Member

Please edit the status field to "Draft". Thanks!

@thewilsonator
Copy link
Contributor

You can't use T[] for extern(C++) so that doesn't really make a difference.

You can under dlang/dmd#8120 but I think is still doesn't make a difference since you're dealing with structs on the C++ side which we don't have problems with.

@ghost ghost closed this Feb 24, 2019
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants