46

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"?

rphv
  • 5,409
  • 3
  • 29
  • 47
  • 14
    I was going to be snarky with "you looked in the source code for gcc but couldn't be bothered to google it?" But then I googled it and found nothing. So instead of snark, I give you props. +1 – John Dibling Jul 17 '13 at 20:15
  • 1
    I was able to find [this](http://gcc.gnu.org/ml/gcc-patches/2011-08/msg02397.html), but I still can't say I know what a transparent class is. – John Dibling Jul 17 '13 at 20:25
  • 1
    A «type transparent class» is a class-wrapper on some basic type (ie, int), with operator overloads so it can be used «transparently», in regard with the wrapped type. – Macmade Jul 17 '13 at 20:26
  • See: http://stackoverflow.com/questions/16410878/what-is-the-use-of-c-transparent-class-wrapper – Macmade Jul 17 '13 at 20:27
  • 7
    @Macmade: Are you sure that's the same transparent class GCC is referring to? Why would GCC care if some class happens to be what some programmers call a transparent wrapper? Not less confused. – John Dibling Jul 17 '13 at 20:32
  • @JohnDibling Simply because of GNU's libstdc++, which is used by GCC. Apparently they use such classes in their implementation. – Macmade Jul 17 '13 at 20:35
  • @Macmade: If you can explain why it is an error for such a class to have a base class, then I think you've got yourself a winning answer there. – John Dibling Jul 17 '13 at 20:37
  • Ok, let's make some guesses... See the answer : ) – Macmade Jul 17 '13 at 20:48
  • I have a feeling 'type transparancy' might have to do with [`mode(XX)` attibutes: (What does GCC __attribute__((mode(XX)) actually do?)](http://stackoverflow.com/q/4559025/85371). This tell the compiler that a type is actually a strictly known size and layout. /cc @Nemo – sehe Jul 17 '13 at 21:21
  • I guess the g++ compiler does some automagic things to certain names in `std::decimal`? Can't imagine why, as it looks implementable with ordinary class definitions and inline functions. – aschepler Jul 17 '13 at 21:25
  • 4
    Reproduced: http://ideone.com/nxDE55 . And yes, it has to be the specific namespace and identifier. – aschepler Jul 17 '13 at 21:36
  • @aschelper: Nice. Make that an answer? – Nemo Jul 17 '13 at 21:47

2 Answers2

21

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...

rodrigo
  • 94,151
  • 12
  • 143
  • 190
  • And that looks like a bug/nonconformance/whatever. It violates the rule in 17.6.5.11 that "Unless explicitly stated otherwise, types with distinct names shall be distinct types." And the Standard gives no such permission for `std::decimal::decimal32` (it doesn't have any mention of this namespace that I could find) – Ben Voigt Jul 17 '13 at 23:39
  • @BenVoigt: The comments say it is in "ISO/IEC TR 24733", [free draft here](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2849.pdf). About the permission of treating these two types the same, the `__decfloat32` and the `__attribute__((mode(SD))` things are compiler extensions and/or implementation details, so the possible interactions with any other type should be of no consequence for the conformance of the compiler. – rodrigo Jul 17 '13 at 23:46
  • Don't you think if it's going into the `std` namespace that it has to conform to the `std` requirements? A namespace `std::decimal` is definitely not an implementation-reserved name. – Ben Voigt Jul 18 '13 at 00:01
  • @BenVoigt: `std::decimal` is specified in the `ISO/IEC TR` as an _Extension for the programming language C++ to support decimal floating-point arithmetic_, and I belive that the ISO/IEC has the authority to specify extensions to C++. OTH, `__decfloat32` _is_ an implementation-reserved name, so is `__attribute__(...)`. – rodrigo Jul 18 '13 at 00:09
  • 1
    Authority to specify extensions, yes, but an extension that doesn't follow the rules of the ratified Standard is a non-conformant extension. You'll note that I didn't say "Adding stuff to namespace `std` = undefined behavior". It's the fact that the things being added are breaking the contract set out in the Standard that's the issue. – Ben Voigt Jul 18 '13 at 00:18
  • @BenVoigt: What do you mean? That the TR 24733 is non conformant? That the GCC implementation of that is non conformant? Or that my guess about how the transparent class works is non conformant? – rodrigo Jul 18 '13 at 20:56
  • Since I don't see anything about transparent types in the TR, I'm led to believe that gcc's implementation is non-conformant. It wouldn't be unheard of for a draft TR to be non-conformant, however -- that's why these things go through a comment phase, so that TRs don't get approved which severely contrast with the normal language rules and usage. – Ben Voigt Jul 18 '13 at 21:04
  • 1
    GCC is non-conformant only if there is at least one conformant program which shows the problem. The code as written is non-conformant because of `__attribute__((mode(SD)));`. IOW, an extension may appear to break the rules of the standard, as long as it only does so in programs which had already broken those rules. – MSalters Jul 18 '13 at 22:42
12

As mentioned in one of my comment, a type-transparent class is a wrapper class to some primitive type, like integers, etc.

They are called transparent because of their use of operator overloading, which makes them act just like the primitive type they wrap.

IE, to wrap an int transparently in a class, you'll need to overload the = operator, the ++operator, etc...

Apparently, GNU's libstdc++ uses such classes for some types. Not sure why...

About the base class issue, while I'm not 100% sure, here's a guess.

When dealing with inheritance in C++, you'll often need to declare virtual methods, to resolve issues with upcasting.

Declaring a method as virtual will tell the compiler to create a virtual table for the methods, so they can be looked at runtime.
This will of course increase the instance size of the class.

For a type-transparent class, this is not acceptable, as the compiler won't be able to place an instance of such a class in a register (i.e when passing arguments, etc), unlike the wrapped type, and so the class won't be transparent anymore.

Edit

I've no idea how to declare such a transparent-class in GCC. The closest thing I can think of is transparent unions:

http://gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html

Something like:

class IntWrapper
{
    int _x;

    /* Constructor, operator overloads... */
};

typedef union
{
    int        integerValue;
    IntWrapper integerWrapper;
}
IntUnion __attribute__( ( __transparent_union__ ) );

My GCC version does not seem to support it, but according to the documentation (see above link), this would allow int or IntWrapper to be passed to functions transparently using the same calling convention as int.

Macmade
  • 52,708
  • 13
  • 106
  • 123
  • 1
    Where would the type be _marked_ as 'type transparent'? Is there some kind of GCC specific attribute for this? I mean, you're saying the compiler thinks something is not acceptable, but there is no way it can know whether it should be acceptable? – sehe Jul 17 '13 at 21:16
  • @sehe: Exactly. Can anybody provide a short compilable example, without any `#include` lines, that causes GCC to emit this diagnostic? If not, I do not think we can say this question has been answered. – Nemo Jul 17 '13 at 21:21
  • @Nemo I just commented on my hunch. It's fairly likely the thing. But I'm too tired to look up the relationship in the gcc code. – sehe Jul 17 '13 at 21:22
  • @sehe: If you follow the link in John Dibling's comment (http://gcc.gnu.org/ml/gcc-patches/2011-08/msg02397.html), it looks like there is no attribute for `decimal32`... And I am pretty sure there is no documented GCC attribute for this. So it is a bit of a mystery what is going on here, I think. Maybe a GCC internals expert will show up and clarify. – Nemo Jul 17 '13 at 21:25
  • Can't test it with my GCC version, but see the edit for a possible solution. – Macmade Jul 17 '13 at 22:20