diff --git a/gcc/d/dfrontend/clone.c b/gcc/d/dfrontend/clone.c index 7f439af79..3751df528 100644 --- a/gcc/d/dfrontend/clone.c +++ b/gcc/d/dfrontend/clone.c @@ -537,7 +537,7 @@ FuncDeclaration *buildXopEquals(StructDeclaration *sd, Scope *sc) Parameters *parameters = new Parameters; parameters->push(new Parameter(STCref | STCconst, sd->type, Id::p, NULL)); parameters->push(new Parameter(STCref | STCconst, sd->type, Id::q, NULL)); - TypeFunction *tf = new TypeFunction(parameters, Type::tbool, 0, LINKd); + TypeFunction *tf = new TypeFunction(parameters, Type::tbool, 0, LINKc); Identifier *id = Id::xopEquals; FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), id, STCstatic, tf); @@ -551,7 +551,7 @@ FuncDeclaration *buildXopEquals(StructDeclaration *sd, Scope *sc) unsigned errors = global.startGagging(); // Do not report errors Scope *sc2 = sc->push(); sc2->stc = 0; - sc2->linkage = LINKd; + sc2->linkage = LINKc; fop->semantic(sc2); fop->semantic2(sc2); @@ -657,25 +657,21 @@ FuncDeclaration *buildXopCmp(StructDeclaration *sd, Scope *sc) Parameters *parameters = new Parameters; parameters->push(new Parameter(STCref | STCconst, sd->type, Id::p, NULL)); parameters->push(new Parameter(STCref | STCconst, sd->type, Id::q, NULL)); - TypeFunction *tf = new TypeFunction(parameters, Type::tint32, 0, LINKd); + TypeFunction *tf = new TypeFunction(parameters, Type::tint32, 0, LINKc); Identifier *id = Id::xopCmp; FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), id, STCstatic, tf); fop->generated = true; Expression *e1 = new IdentifierExp(loc, Id::p); Expression *e2 = new IdentifierExp(loc, Id::q); -#ifdef IN_GCC Expression *e = new CallExp(loc, new DotIdExp(loc, e1, Id::cmp), e2); -#else - Expression *e = new CallExp(loc, new DotIdExp(loc, e2, Id::cmp), e1); -#endif fop->fbody = new ReturnStatement(loc, e); unsigned errors = global.startGagging(); // Do not report errors Scope *sc2 = sc->push(); sc2->stc = 0; - sc2->linkage = LINKd; + sc2->linkage = LINKc; fop->semantic(sc2); fop->semantic2(sc2); diff --git a/gcc/testsuite/gdc.test/runnable/test5854.d b/gcc/testsuite/gdc.test/runnable/test5854.d new file mode 100644 index 000000000..bb98cf5b0 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/test5854.d @@ -0,0 +1,53 @@ +struct S1 +{ + long x1, x2; + + int opCmp(ref const S1 s) const + { + if (x2 - s.x2 != 0) + return x2 < s.x2 ? -1 : 1; + + return x1 < s.x1 ? -1 : x1 == s.x1 ? 0 : 1; + } +} + +struct S2 +{ + long x1, x2; + + int opCmp(in S2 s) const + { + if (x2 - s.x2 != 0) + return x2 < s.x2 ? -1 : 1; + + return x1 < s.x1 ? -1 : x1 == s.x1 ? 0 : 1; + } +} + +extern (C) int structcmp(T)(scope T a, scope T b) +{ + extern (C) int cmp(scope const void* p1, scope const void* p2, scope void* ti) + { + return (cast(TypeInfo)ti).compare(p1, p2); + } + return cmp(&a, &b, cast(void*)typeid(T)); +} + +void test5854() +{ + alias Tuple(T...) = T; + + foreach (T; Tuple!(S1, S2)) + { + assert(T(1, 3).structcmp(T(4, 4)) == -1); + assert(T(1, 3).structcmp(T(4, 3)) == -1); + assert(T(4, 3).structcmp(T(4, 3)) == 0); + assert(T(5, 3).structcmp(T(4, 3)) == 1); + assert(T(5, 4).structcmp(T(4, 3)) == 1); + } +} + +void main() +{ + test5854(); +} diff --git a/libphobos/libdruntime/object.d b/libphobos/libdruntime/object.d index 3156a373c..5bff9fcda 100644 --- a/libphobos/libdruntime/object.d +++ b/libphobos/libdruntime/object.d @@ -1145,12 +1145,7 @@ class TypeInfo_Struct : TypeInfo return false; else if (xopEquals) { - version(GNU) - { // BUG: GDC and DMD use different calling conventions - return (*xopEquals)(p2, p1); - } - else - return (*xopEquals)(p1, p2); + return (*xopEquals)(p1, p2); } else if (p1 == p2) return true; @@ -1171,14 +1166,7 @@ class TypeInfo_Struct : TypeInfo if (!p2) return true; else if (xopCmp) - { - version(GNU) - { // BUG: GDC and DMD use different calling conventions - return (*xopCmp)(p1, p2); - } - else - return (*xopCmp)(p2, p1); - } + return (*xopCmp)(p1, p2); else // BUG: relies on the GC not moving objects return memcmp(p1, p2, initializer().length); @@ -1225,10 +1213,21 @@ class TypeInfo_Struct : TypeInfo @safe pure nothrow { - size_t function(in void*) xtoHash; - bool function(in void*, in void*) xopEquals; - int function(in void*, in void*) xopCmp; - string function(in void*) xtoString; + size_t function(in void*) xtoHash; + /* The xopEquals and xopCmp function pointers usually point to the struct's + * opEquals and opCmp methods. If the method doesn't take its single + * argument by reference, the front-end injects a static __xopEquals/ + * __xopCmp function (taking 2 arguments, lhs `p` and rhs `q`). + * + * In the method case, lhs `p` is the `this` argument and must be passed + * as first argument before rhs `q`. + * Enforce this arguments order by marking the pointed-to functions as + * using the C calling convention, for which the arguments are never + * reversed (contrary to `extern (D)`). + */ + extern (C) bool function(in void*, in void*) xopEquals; + extern (C) int function(in void*, in void*) xopCmp; + string function(in void*) xtoString; enum StructFlags : uint {