Issue 19496 - Wrong D and C++ ABI caused by scope qualifier in other method
Summary: Wrong D and C++ ABI caused by scope qualifier in other method
Status: RESOLVED FIXED
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: All Linux
: P1 major
Assignee: No Owner
URL:
Keywords: C++, industry, wrong-code
Depends on:
Blocks:
 
Reported: 2018-12-16 17:15 UTC by Илья Ярошенко
Modified: 2020-02-19 05:16 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Илья Ярошенко 2018-12-16 17:15:24 UTC
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
}
Comment 1 Илья Ярошенко 2018-12-16 17:17:15 UTC
Both 32 and 64 bit code affected
Comment 2 kinke 2018-12-16 17:40:50 UTC
Wow, that's a curious major issue indeed. Somehow that little `scope` seems to affect `StructDeclaration.isPOD()`.
Comment 3 Илья Ярошенко 2019-03-01 12:14:04 UTC
Fixed since DMD 2.084 / LDC 1.14
Comment 4 Mathias LANG 2020-02-19 05:16:58 UTC
Since it has been fixed, closing the issue.