[RFC] Fixing address spaces in C++ cast operators


I am trying to fix address spaces in C++ cast operators and I would like to get some help on several thoughts. I am primarily working on OpenCL but I would quite like this to be applied generically to C++ wherever possible.

For pointer/reference type qualifiers the following rules apply in C++:

  • Converting to more qualified type from less qualified type is permitted in all cast operators

  • Converting to less qualified type (casting away qualifiers) is only permitted in const_cast

Address spaces have slightly different semantic:

  • There are some safe implicit conversions for pointers if the pointee types are declared in compatible address spaces. In OpenCL there is a generic address space that can be used to declare pointee types, and represents an alias for any valid address space (except for __constant). Converting to generic pointee types is always safe because it is designed to be a placeholder.

Example: __local SomeType * → __generic SomeType * // always safe

  • There are some safe explicit address space conversions. In OpenCL converting from a generic address space pointee type to a specific address space is valid if the generic address space pointer points to an object in that specific address space; the programmer has to ensure this is true, therefore, the cast has to be explicit.

Example: __generic SomeType * → __local SomeType * // only safe when explicitly done

  • There are unsafe address space conversion that can not be permitted. In OpenCL this would be conversions to/from __constant address space pointer (read-only memory) or any conversion between pointers to different specific address spaces.

Example: __constant SomeType * → __local SomeType * // unsafe

__global SomeType * → __local SomeType * // unsafe

Considering this semantic and C++ cast logic, it seems to make sense to:

  1. Allow safe implicit conversions in all pointer/reference cast operations apart from const_cast.

  2. Add special operator for safe explicit address space conversion, for example addrspace_cast.

template __as1 T* addrspace_cast(__as2 T*)

template __as1 T& addrspace_cast(__as2 T&)

where __as1 and __as2 are possibly different address spaces.

  1. Disallow unsafe address space conversions in all pointer/reference cast operators (incl addrspace_cast).

The main motivation for adding a special cast operator is to be explicit about address space conversions and to allow separation of type or cv-qualifier conversions from the address space conversion to prevent accidental errors.

Note that address space conversions between non-pointer types doesn’t create any problem because it implies copy of the original object.

Converting from pointer types to integers (or opposite) is fine even when the pointee types are qualified with an address space (similar to regular qualifier rules).

Below is the summary of the behavior for various conversions in Clang master at r348932:

  • Implicit conversions [OK]: disallowed for all address spaces in C++ and allowed for safe implicit conversions in OpenCL.

  • C style cast [OK]: allowed for all address spaces in C++ and all safe address space casts in OpenCL.

  • static_cast: like implicit conversions but the wrong error message is given.

error: static_cast from ‘attribute((address_space(2))) B *’ to ‘attribute((address_space(1))) D *’ casts away qualifiers

error: static_cast from ‘__generic B *’ to ‘__local D *’ casts away qualifiers

  • dynamic_cast: like implicit conversions but the wrong error message is given.

error: dynamic_cast from ‘attribute((address_space(2))) B *’ to ‘attribute((address_space(1))) D *’ casts away qualifiers

Note that polymorphism is currently not supported in OpenCL

  • reinterpret_cast: any address space conversion is allowed even unsafe ones.

  • const_cast [OK]: all address space conversions are disallowed

If we adopt the logic explained above for the address spaces in cast operators, I would like to fix the error message in static_cast & dynamic_cast, as well as change the behavior of reinterpret_cast to align with static_cast & dynamic_cast, and then also add addrspace_cast operator for conversion of pointers/references with different address spaces.

Looking forward to any feedback,