C++ - What is a "type transparent class"?

c++, gcc

Solution

Reading the source code of GCC a bit more, in `semantics.c`:

  if (TREE_CODE (t) == RECORD_TYPE
      && !processing_template_decl)
    {
      tree ns = TYPE_CONTEXT (t);
      if (ns && TREE_CODE (ns) == NAMESPACE_DECL
          && DECL_CONTEXT (ns) == std_node
          && DECL_NAME (ns)
          && !strcmp (IDENTIFIER_POINTER (DECL_NAME (ns)), "decimal"))
        {
          const char *n = TYPE_NAME_STRING (t);
          if ((strcmp (n, "decimal32") == 0)
              || (strcmp (n, "decimal64") == 0)
              || (strcmp (n, "decimal128") == 0))
            TYPE_TRANSPARENT_AGGR (t) = 1;
        }
    }

This code means that a type is marked transparent if:

- It is a struct, but not a template;

- And it is at namespace level, and that namespace is `std::decimal`.

- And it is named `decimal32`, `decimal64` or `decimal128`.

In `class.c` there is the error check you encountered, and a few more.

And in `mangle.c`:

      /* According to the C++ ABI, some library classes are passed the
         same as the scalar type of their single member and use the same
         mangling.  */
      if (TREE_CODE (type) == RECORD_TYPE && TYPE_TRANSPARENT_AGGR (type))
        type = TREE_TYPE (first_field (type));

The comment is key here. I think it means that a transparent type is replaced for the type of its fist (and only) member, so it can be used anywhere it first member can. For example, in my `include/decimal` the class `std::decimal::decimal32` has a single field of type `__decfloat32` (from a previous `typedef float __decfloat32 __attribute__((mode(SD)));`), so any function that takes a `__decfloat32` can take a `std::decimal::decimal32` and vice-versa. Even the function decoration is done the same. The idea is probably to make this classes ABI compatible with the C types `_Decimal32`, `_Decimal64` and `_Decimal128`.

Now, how are you getting a `class decimal32` with base classes? My only guess is that you are including incompatible (maybe older) header files, with a totally different implementation.

UPDATE

After some investigation, it looks like my guess about the ABI and function decoration is right. The following code:

#include <decimal/decimal>
using namespace std::decimal;

 //This is a synonym of C99 _Decimal32, but that is not directly available in C++
typedef float Decimal32 __attribute__((mode(SD)));

void foo(decimal32 a) {}
void foo(Decimal32 a) {}

gives the curious error:

/tmp/ccr61gna.s: Assembler messages:
/tmp/ccr61gna.s:1291: Error: symbol `_Z3fooDf' is already defined

That is, the compiler front-end sees no problem in the overload and emits the asm code, but since both functions are decorated the same the assembler fails.

Now, is this a non-conformance of GCC, as Ben Voigt suggests in the comments? I don't know... you should be able to write overloaded functions with any two different types you want. But OTOH, it is impossible to get the `Decimal32` type without using some compiler extension, so the meaning of this type is implementation defined...

Problem

Using gcc to compile a program that includes support for decimal data types, I recently encountered the following error: `error: type transparent class 'std::decimal::decimal32' has base classes` A quick look at GCC's source tree shows that this error message is found in `gcc/cp/class.c`. What is a "type transparent class"? Why is it an error for such a class to have "base classes"?

Original source

Related problems