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