================
@@ -13010,10 +13010,13 @@ static GVALinkage basicGVALinkageForFunction(const 
ASTContext &Context,
 
   if (Context.getTargetInfo().getCXXABI().isMicrosoft() &&
       isa<CXXConstructorDecl>(FD) &&
-      cast<CXXConstructorDecl>(FD)->isInheritingConstructor())
+      cast<CXXConstructorDecl>(FD)->isInheritingConstructor() &&
+      !FD->hasAttr<DLLExportAttr>())
     // Our approach to inheriting constructors is fundamentally different from
     // that used by the MS ABI, so keep our inheriting constructor thunks
     // internal rather than trying to pick an unambiguous mangling for them.
+    // However, dllexport inherited constructors must be externally visible
+    // to match MSVC's behavior.
----------------
chinmaydd wrote:

I believe they are. The MS ABI mangles inherited constructors identically to 
regular constructors -- in the sense that it takes into account class name and 
parameter types. There is no "inherited from" encoding as far as I can see.

Built a small example (w/ assistance of Claude):

```
// base.h

#pragma once
#ifdef BUILDING_DLL
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif

struct DLL_API Base {
  int value;
  Base(int v);
  Base(double v);
};

struct DLL_API Child : public Base {
  using Base::Base;
};
```

```
// lib.cpp

#define BUILDING_DLL
#include "base.h"
Base::Base(int v) : value(v) {}
Base::Base(double v) : value(static_cast<int>(v)) {}
```

```
// client.cpp

#include "base.h"
int main() {
  Child c1(42);
  Child c2(3.14);
  return c1.value + c2.value;
}
```

---

MSVC generated thunk:
```
mov  dword ptr [rsp+10h], edx    ; save int param
mov  qword ptr [rsp+8], rcx     ; save this
sub  rsp, 28h
mov  edx, dword ptr [rsp+38h]   ; reload int
mov  rcx, qword ptr [rsp+30h]   ; reload this
call Base::Base(int)             ; forward to base
mov  rax, qword ptr [rsp+30h]   ; return this
add  rsp, 28h
ret
```

Clang generated thunk:
```
sub  rsp, 38h
mov  dword ptr [rsp+34h], edx   ; save int param
mov  qword ptr [rsp+28h], rcx   ; save this
mov  rcx, qword ptr [rsp+28h]   ; reload this
mov  qword ptr [rsp+20h], rcx   ; save for return
mov  edx, dword ptr [rsp+34h]   ; reload int
call Base::Base(int)             ; forward to base
mov  rax, qword ptr [rsp+20h]   ; return this
add  rsp, 38h
ret
```

Both are forwarding thunks with the same calling convention (this in rcx, int 
in edx), same semantics (forward to base constructor, return this), and same 
mangled symbol name. The only differences are minor register scheduling and 
frame size, which don't affect ABI compatibility.

https://github.com/llvm/llvm-project/pull/182706
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to