GabrielDosReis/ipr

How to represent: enum class X : int;? Possibly add opt<Type> underlying_type

Opened this issue · 4 comments

Need to be able to represent:

enum class X : int;

Currently not representable by IPR

Enum should have opt underlying_type

Enums are an odd case compared to class types. An enum declaration with an underlying type is really a complete type, where as there a forward declaration of a class references an incomplete type. So, the issue here is whether a Typedecl as currently defined is sufficient to represent both a forward declaration of num and a forward declaration of a class. The answer is "no" post C++11. It is a design point as to which of the various choices should be picked.

One of the ideas we had during recent discussion about this issue was to introduce a meta type, tentative name, [Complete type: enum, alignment: x, size: sizeof(int)] that will be used in this case instead of lexicon::enum_type() both in a Typedecl when there is no initializer (i.e. enum body) and as a type of ipr::Enum itself.

enum class X : int;

enum class X : int { a, b };

Will be represented as:

type#1 Complete[type: enum, size: sizeof(int), alignment: alignas(int)]
decl#1 Typedecl[name:X, type:type#1, init: <absent>]
type#2 Enum[type:type#1 enumerators... ]
decl#2 Typedecl[name:X, type:type#1, init: type#2]

We talked a bit more about this representation. Latest thinking:

  1. Change complete to be just a pair [Complete type: enum, layout: int], as opposed carrying size/align fields. If we want to represent an exported opaque structure (for which only size and alignment is visible), we can introduce a new type [OpaqueLayout align: <expr> size: <expr> to be used for the layout field of Complete metatype.

This addresses a use case:

enum class X;
using undy = std::underlying_type_t<X>; 

Now std::underlying_type_t can grab the type from the layout field.

  1. Currently ipr uses a Kind field in the enum type to represent a distinction between scoped and unscoped enumerations. Since under the model we are discussing in this thread, we would like to retain a property that only one declaration is a definition (adds initializer), we need to represent scoped/unscoped without relying on an initializer.
enum class X;
enum X; // error: scoped enum cannot be redeclared as an unscoped one

The suggestion is to introduce a new metatype scoped_enum_type to the lexicon that will be the type of scoped enumerations and the enum_type will be used for unscoped ones.

There are two issues in this report:

  1. How to represent the underlying type of an enumeration in a declaration that explicitly specifies it?
  2. How to represent the enumerators of an enumeration that are defined in a declaration separate from a prior declaration that specified the base type?

All of these issues stem from timeline: when IPR was originally designed, the notion of separately specifying the underlying type of an enumeration was not yet a thing. This points to the perilous task of predicting the future.

Aspect (1) bears some similarity with base class types of a class declaration.
Aspect (2) bears some similarity with the notion of prolongation, i.e. definition of members (providing initializer for a member) of a scope outside the definition of that scope.