December 16, 2018
https://issues.dlang.org/show_bug.cgi?id=19496

          Issue ID: 19496
           Summary: Wrong D and C++ ABI caused by scope qualifier in other
                    method
           Product: D
           Version: D2
          Hardware: x86_64
                OS: Linux
            Status: NEW
          Severity: major
          Priority: P1
         Component: dmd
          Assignee: nobody@puremagic.com
          Reporter: ilyayaroshenko@gmail.com

t1.d:

struct S
{
    void* _payload;
    ~this();
    typeof(this) merge() { return this; }
    bool foo(ref typeof(this) rhs);
}


t2.d:

struct S
{
    void* _payload;
    ~this();
    typeof(this) merge() { return this; }
    bool foo(scope ref typeof(this) rhs);
}


As you can see the difference between this two tests is that t2.S.foo's argument has scope qualifier.

The issue is that t1.S.merge and t2.S.merge have different ABI. Fantastic issue, ha!

The correct ABI is in t1. The same ABI is in C++ for objects with destructors. Note, that ABI depends on if destructor presents, both in D and C++.

The issue is represented both in DMD and LDC, both for extern(D) and
extern(C++).

LLVM output (DMD's assembler is less informative):



t.ll.S.merge:
// ABI signature returns void (as for objects with destructors)

define void @_D22t11S5mergeMFZSQBkQp(%t1.S* noalias nocapture sret align 8 %.sret_arg, %t1.S* nocapture nonnull readonly %.this_arg) local_unnamed_addr #1 comdat {

  %1 = bitcast %t1.S* %.this_arg to i64* ; [#uses = 1]
  %2 = bitcast %t1.S* %.sret_arg to i64* ; [#uses = 1]
  %3 = load i64, i64* %1, align 1                 ; [#uses = 1]
  store i64 %3, i64* %2, align 8
  ret void
}

t2.ll.S.merge:

// ABI signature returns S (as for objects without destructors)

define %t2.S @_D22t21S5mergeMFZSQBkQp(%t2.S* nocapture nonnull readonly %.this_arg) local_unnamed_addr #1 comdat {

  %1 = getelementptr inbounds %t2.S, %t2.S* %.this_arg, i64 0, i32 0 ; [#uses =
1, type = i8**]
  %.unpack = load i8*, i8** %1, align 8           ; [#uses = 1]
  %2 = insertvalue %t2.S undef, i8* %.unpack, 0 ; [#uses = 1]
  ret %t2.S %2
}

--