[clang codegen] Fix MS ABI detection of user-provided constructors. (#90151)
authorEli Friedman <efriedma@quicinc.com>
Mon, 29 Apr 2024 19:00:12 +0000 (12:00 -0700)
committerTom Stellard <tstellar@redhat.com>
Wed, 1 May 2024 22:56:33 +0000 (15:56 -0700)
In the context of determining whether a class counts as an "aggregate",
a constructor template counts as a user-provided constructor.

Fixes #86384

(cherry picked from commit 3ab4ae9e58c09dfd8203547ba8916f3458a0a481)

clang/docs/ReleaseNotes.rst
clang/lib/CodeGen/MicrosoftCXXABI.cpp
clang/test/CodeGen/arm64-microsoft-arguments.cpp

index 1e88b58725bd953ebe6d078431bf37b630f89ad5..e533ecfd5aeba5109e356e88f80236c358b0cf12 100644 (file)
@@ -149,6 +149,12 @@ ABI Changes in This Version
 - Following the SystemV ABI for x86-64, ``__int128`` arguments will no longer
   be split between a register and a stack slot.
 
+- Fixed Microsoft calling convention for returning certain classes with a
+  templated constructor. If a class has a templated constructor, it should
+  be returned indirectly even if it meets all the other requirements for
+  returning a class in a register. This affects some uses of std::pair.
+  (#GH86384).
+
 AST Dumping Potentially Breaking Changes
 ----------------------------------------
 - When dumping a sugared type, Clang will no longer print the desugared type if
index 172c4c937b97280d30ca5689ec58b600a852a809..4d0f4c63f843b8f896af40c84c614af540ee59c6 100644 (file)
@@ -1135,9 +1135,15 @@ static bool isTrivialForMSVC(const CXXRecordDecl *RD, QualType Ty,
     return false;
   if (RD->hasNonTrivialCopyAssignment())
     return false;
-  for (const CXXConstructorDecl *Ctor : RD->ctors())
-    if (Ctor->isUserProvided())
-      return false;
+  for (const Decl *D : RD->decls()) {
+    if (auto *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
+      if (Ctor->isUserProvided())
+        return false;
+    } else if (auto *Template = dyn_cast<FunctionTemplateDecl>(D)) {
+      if (isa<CXXConstructorDecl>(Template->getTemplatedDecl()))
+        return false;
+    }
+  }
   if (RD->hasNonTrivialDestructor())
     return false;
   return true;
index e8309888dcfe21bb8563db2d57ac8ee70578446d..85472645acb3b36112a8ad64161ceada485c0879 100644 (file)
@@ -201,3 +201,18 @@ S11 f11() {
   S11 x;
   return func11(x);
 }
+
+// GH86384
+// Pass and return object with template constructor (pass directly,
+// return indirectly).
+// CHECK: define dso_local void @"?f12@@YA?AUS12@@XZ"(ptr dead_on_unwind inreg noalias writable sret(%struct.S12) align 4 {{.*}})
+// CHECK: call void @"?func12@@YA?AUS12@@U1@@Z"(ptr dead_on_unwind inreg writable sret(%struct.S12) align 4 {{.*}}, i64 {{.*}})
+struct S12 {
+  template<typename T> S12(T*) {}
+  int x;
+};
+S12 func12(S12 x);
+S12 f12() {
+  S12 x((int*)0);
+  return func12(x);
+}