[clang] [clang-cl] [AST] Reapply #102848 Fix placeholder return type name mangling for MSVC 1920+ / VS2019+ (PR #104722)

Max Winkler via cfe-commits cfe-commits at lists.llvm.org
Sun Aug 18 14:15:09 PDT 2024


https://github.com/MaxEW707 created https://github.com/llvm/llvm-project/pull/104722

Reapply https://github.com/llvm/llvm-project/pull/102848.

The description in this PR will detail the changes from the reverted original PR above.

For `auto&&` return types that can partake in reference collapsing we weren't properly handling that mangling that can arise.
When collapsing occurs an inner reference is created with the collapsed reference type. If we return `int&` from such a function then an inner reference of `int&` is created within the `auto&&` return type. `getPointeeType` on a reference type goes through all inner references before returning the pointee type which ends up being a builtin type, `int`, which is unexpected.

We can use `getPointeeTypeAsWritten` to get the `AutoType` as expected however for the instantiated template declaration reference collapsing already occurred on the return type. This means `auto&&` is turned into `auto&` in our example above.
We end up mangling an lvalue reference type.
This is unintended as MSVC mangles on the declaration of the return type, `auto&&` in this case, which is treated as an rvalue reference.
```
template<class T>
auto&& AutoReferenceCollapseT(int& x) { return static_cast<int&>(x); }

void test() 
{
    int x = 1;
    auto&& rref = AutoReferenceCollapseT<void>(x); // "??$AutoReferenceCollapseT at X@@YA$$QEA_PAEAH at Z"
    // Mangled as an rvalue reference to auto
}
```

If we are mangling a template with a placeholder return type we want to get the first template declaration and use its return type to do the mangling of any instantiations.

This fixes the bug reported in the original PR that caused the revert with libcxx `std::variant`.
I also tested locally with libcxx and the following test code which fails in the original PR but now works in this PR.
```
#include <variant>

void test()
{
    std::variant<int> v{ 1 };
    int& r = std::get<0>(v);
    (void)r;
}
```

>From e5071bd3be7607730654e5aa815a535db130fdee Mon Sep 17 00:00:00 2001
From: MaxEW707 <max.enrico.winkler at gmail.com>
Date: Sun, 11 Aug 2024 16:50:58 -0700
Subject: [PATCH 1/6] Fix placeholder return type name mangling for MSVC 1920+

---
 clang/lib/AST/MicrosoftMangle.cpp             | 172 ++++++++-
 .../test/CodeGenCXX/mangle-ms-auto-return.cpp | 358 ++++++++++++++++++
 .../mangle-ms-auto-templates-memptrs.cpp      |  12 +-
 .../mangle-ms-auto-templates-nullptr.cpp      |   2 +-
 .../CodeGenCXX/mangle-ms-auto-templates.cpp   |   6 +-
 5 files changed, 531 insertions(+), 19 deletions(-)
 create mode 100644 clang/test/CodeGenCXX/mangle-ms-auto-return.cpp

diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp
index 28f66e71c2f2de..ecbddc1aacc073 100644
--- a/clang/lib/AST/MicrosoftMangle.cpp
+++ b/clang/lib/AST/MicrosoftMangle.cpp
@@ -408,6 +408,9 @@ class MicrosoftCXXNameMangler {
   void mangleSourceName(StringRef Name);
   void mangleNestedName(GlobalDecl GD);
 
+  void mangleAutoReturnType(QualType T, SourceRange Range,
+                            QualifierMangleMode QMM);
+
 private:
   bool isStructorDecl(const NamedDecl *ND) const {
     return ND == Structor || getStructor(ND) == Structor;
@@ -477,6 +480,15 @@ class MicrosoftCXXNameMangler {
                           SourceRange Range);
   void mangleObjCKindOfType(const ObjCObjectType *T, Qualifiers Quals,
                             SourceRange Range);
+
+  void mangleAutoReturnType(const MemberPointerType *T, Qualifiers Quals,
+                            SourceRange Range);
+  void mangleAutoReturnType(const PointerType *T, Qualifiers Quals,
+                            SourceRange Range);
+  void mangleAutoReturnType(const LValueReferenceType *T, Qualifiers Quals,
+                            SourceRange Range);
+  void mangleAutoReturnType(const RValueReferenceType *T, Qualifiers Quals,
+                            SourceRange Range);
 };
 }
 
@@ -2494,8 +2506,61 @@ void MicrosoftCXXNameMangler::mangleAddressSpaceType(QualType T,
   mangleArtificialTagType(TagTypeKind::Struct, ASMangling, {"__clang"});
 }
 
+void MicrosoftCXXNameMangler::mangleAutoReturnType(QualType T,
+                                                   SourceRange Range,
+                                                   QualifierMangleMode QMM) {
+  assert(getASTContext().getLangOpts().isCompatibleWithMSVC(
+             LangOptions::MSVC2019) &&
+         "Cannot mangle MSVC 2017 auto return types!");
+
+  if (isa<AutoType>(T)) {
+    const auto *AT = T->getContainedAutoType();
+    Qualifiers Quals = T.getLocalQualifiers();
+
+    if (QMM == QMM_Result)
+      Out << '?';
+    if (QMM != QMM_Drop)
+      mangleQualifiers(Quals, false);
+    Out << (AT->isDecltypeAuto() ? "_T" : "_P");
+    return;
+  }
+
+  T = T.getDesugaredType(getASTContext());
+  Qualifiers Quals = T.getLocalQualifiers();
+
+  switch (QMM) {
+  case QMM_Drop:
+  case QMM_Result:
+    break;
+  case QMM_Mangle:
+    mangleQualifiers(Quals, false);
+    break;
+  default:
+    llvm_unreachable("QMM_Escape unexpected");
+  }
+
+  const Type *ty = T.getTypePtr();
+  switch (ty->getTypeClass()) {
+  case Type::MemberPointer:
+    mangleAutoReturnType(cast<MemberPointerType>(ty), Quals, Range);
+    break;
+  case Type::Pointer:
+    mangleAutoReturnType(cast<PointerType>(ty), Quals, Range);
+    break;
+  case Type::LValueReference:
+    mangleAutoReturnType(cast<LValueReferenceType>(ty), Quals, Range);
+    break;
+  case Type::RValueReference:
+    mangleAutoReturnType(cast<RValueReferenceType>(ty), Quals, Range);
+    break;
+  default:
+    llvm_unreachable("Invalid type expected");
+  }
+}
+
 void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range,
                                          QualifierMangleMode QMM) {
+
   // Don't use the canonical types.  MSVC includes things like 'const' on
   // pointer arguments to function pointers that canonicalization strips away.
   T = T.getDesugaredType(getASTContext());
@@ -2900,17 +2965,51 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
       // can differ by their calling convention and are typically deduced.  So
       // we make sure that this type gets mangled properly.
       mangleType(ResultType, Range, QMM_Result);
-    } else if (const auto *AT = dyn_cast_or_null<AutoType>(
-                   ResultType->getContainedAutoType())) {
-      Out << '?';
-      mangleQualifiers(ResultType.getLocalQualifiers(), /*IsMember=*/false);
-      Out << '?';
+    } else if (IsInLambda) {
+      if (const auto *AT = ResultType->getContainedAutoType()) {
+        assert(AT->getKeyword() == AutoTypeKeyword::Auto &&
+               "should only need to mangle auto!");
+        Out << '?';
+        mangleQualifiers(ResultType.getLocalQualifiers(), /*IsMember=*/false);
+        Out << '?';
+        mangleSourceName("<auto>");
+        Out << '@';
+      } else {
+        Out << '@';
+      }
+    } else if (const auto *AT = ResultType->getContainedAutoType()) {
       assert(AT->getKeyword() != AutoTypeKeyword::GNUAutoType &&
              "shouldn't need to mangle __auto_type!");
-      mangleSourceName(AT->isDecltypeAuto() ? "<decltype-auto>" : "<auto>");
-      Out << '@';
-    } else if (IsInLambda) {
-      Out << '@';
+
+      // If we have any pointer types with the clang address space extension
+      // then defer to the custom clang mangling to keep backwards
+      // compatibility. See `mangleType(const PointerType *T, Qualifiers Quals,
+      // SourceRange Range)` for details.
+      auto UseClangMangling = [](QualType ResultType) {
+        QualType T = ResultType;
+        while (const auto *PT = dyn_cast<PointerType>(T.getTypePtr())) {
+          T = T->getPointeeType();
+          if (T.getQualifiers().hasAddressSpace())
+            return true;
+        }
+        return false;
+      };
+
+      if (getASTContext().getLangOpts().isCompatibleWithMSVC(
+              LangOptions::MSVC2019) &&
+          !UseClangMangling(ResultType)) {
+        if (D && !D->getPrimaryTemplate()) {
+          Out << '@';
+        } else {
+          mangleAutoReturnType(ResultType, Range, QMM_Result);
+        }
+      } else {
+        Out << '?';
+        mangleQualifiers(ResultType.getLocalQualifiers(), /*IsMember=*/false);
+        Out << '?';
+        mangleSourceName(AT->isDecltypeAuto() ? "<decltype-auto>" : "<auto>");
+        Out << '@';
+      }
     } else {
       if (ResultType->isVoidType())
         ResultType = ResultType.getUnqualifiedType();
@@ -4213,6 +4312,61 @@ void MicrosoftMangleContextImpl::mangleStringLiteral(const StringLiteral *SL,
   Mangler.getStream() << '@';
 }
 
+void MicrosoftCXXNameMangler::mangleAutoReturnType(const MemberPointerType *T,
+                                                   Qualifiers Quals,
+                                                   SourceRange Range) {
+  QualType PointeeType = T->getPointeeType();
+  manglePointerCVQualifiers(Quals);
+  manglePointerExtQualifiers(Quals, PointeeType);
+  if (const FunctionProtoType *FPT = PointeeType->getAs<FunctionProtoType>()) {
+    Out << '8';
+    mangleName(T->getClass()->castAs<RecordType>()->getDecl());
+    mangleFunctionType(FPT, nullptr, true);
+  } else {
+    mangleQualifiers(PointeeType.getQualifiers(), true);
+    mangleName(T->getClass()->castAs<RecordType>()->getDecl());
+    mangleAutoReturnType(PointeeType, Range, QMM_Drop);
+  }
+}
+
+void MicrosoftCXXNameMangler::mangleAutoReturnType(const PointerType *T,
+                                                   Qualifiers Quals,
+                                                   SourceRange Range) {
+  QualType PointeeType = T->getPointeeType();
+  assert(!PointeeType.getQualifiers().hasAddressSpace() &&
+         "Unexpected address space mangling required");
+
+  manglePointerCVQualifiers(Quals);
+  manglePointerExtQualifiers(Quals, PointeeType);
+
+  if (const FunctionProtoType *FPT = PointeeType->getAs<FunctionProtoType>()) {
+    Out << '6';
+    mangleFunctionType(FPT);
+  } else {
+    mangleAutoReturnType(PointeeType, Range, QMM_Mangle);
+  }
+}
+
+void MicrosoftCXXNameMangler::mangleAutoReturnType(const LValueReferenceType *T,
+                                                   Qualifiers Quals,
+                                                   SourceRange Range) {
+  QualType PointeeType = T->getPointeeType();
+  assert(!Quals.hasConst() && !Quals.hasVolatile() && "unexpected qualifier!");
+  Out << 'A';
+  manglePointerExtQualifiers(Quals, PointeeType);
+  mangleAutoReturnType(PointeeType, Range, QMM_Mangle);
+}
+
+void MicrosoftCXXNameMangler::mangleAutoReturnType(const RValueReferenceType *T,
+                                                   Qualifiers Quals,
+                                                   SourceRange Range) {
+  QualType PointeeType = T->getPointeeType();
+  assert(!Quals.hasConst() && !Quals.hasVolatile() && "unexpected qualifier!");
+  Out << "$$Q";
+  manglePointerExtQualifiers(Quals, PointeeType);
+  mangleAutoReturnType(PointeeType, Range, QMM_Mangle);
+}
+
 MicrosoftMangleContext *MicrosoftMangleContext::create(ASTContext &Context,
                                                        DiagnosticsEngine &Diags,
                                                        bool IsAux) {
diff --git a/clang/test/CodeGenCXX/mangle-ms-auto-return.cpp b/clang/test/CodeGenCXX/mangle-ms-auto-return.cpp
new file mode 100644
index 00000000000000..9b34a9abfd75d8
--- /dev/null
+++ b/clang/test/CodeGenCXX/mangle-ms-auto-return.cpp
@@ -0,0 +1,358 @@
+// RUN: %clang_cc1 -std=c++17 -fms-compatibility-version=19.20 -emit-llvm %s -o - -fms-extensions -fdelayed-template-parsing -triple=x86_64-pc-windows-msvc | FileCheck %s
+
+struct StructA {};
+
+template<class T>
+auto AutoT() { return T(); }
+
+template<class T>
+const auto AutoConstT() { return T(); }
+
+template<class T>
+volatile auto AutoVolatileT() { return T(); }
+
+template<class T>
+const volatile auto AutoConstVolatileT() { return T(); }
+
+// The qualifiers of the return type should always be emitted even for void types.
+// Void types usually have their qualifers stripped in the mangled name for MSVC ABI.
+void test_template_auto_void() {
+  AutoT<void>();
+  // CHECK: call {{.*}} @"??$AutoT at X@@YA?A_PXZ"
+
+  AutoT<const void>();
+  // CHECK: call {{.*}} @"??$AutoT@$$CBX@@YA?A_PXZ"
+
+  AutoT<volatile void>();
+  // CHECK: call {{.*}} @"??$AutoT@$$CCX@@YA?A_PXZ"
+
+  AutoT<const volatile void>();
+  // CHECK: call {{.*}} @"??$AutoT@$$CDX@@YA?A_PXZ"
+
+  AutoConstT<void>();
+  // CHECK: call {{.*}} @"??$AutoConstT at X@@YA?B_PXZ"
+
+  AutoVolatileT<void>();
+  // CHECK: call {{.*}} @"??$AutoVolatileT at X@@YA?C_PXZ"
+
+  AutoConstVolatileT<void>();
+  // CHECK: call {{.*}} @"??$AutoConstVolatileT at X@@YA?D_PXZ"
+}
+
+void test_template_auto_int() {
+  AutoT<int>();
+  // CHECK: call {{.*}} @"??$AutoT at H@@YA?A_PXZ"
+
+  AutoT<const int>();
+  // CHECK: call {{.*}} @"??$AutoT@$$CBH@@YA?A_PXZ"
+
+  AutoT<volatile int>();
+  // CHECK: call {{.*}} @"??$AutoT@$$CCH@@YA?A_PXZ"
+
+  AutoT<const volatile int>();
+  // CHECK: call {{.*}} @"??$AutoT@$$CDH@@YA?A_PXZ"
+
+  AutoConstT<int>();
+  // CHECK: call {{.*}} @"??$AutoConstT at H@@YA?B_PXZ"
+
+  AutoVolatileT<int>();
+  // CHECK: call {{.*}} @"??$AutoVolatileT at H@@YA?C_PXZ"
+
+  AutoConstVolatileT<int>();
+  // CHECK: call {{.*}} @"??$AutoConstVolatileT at H@@YA?D_PXZ"
+}
+
+void test_template_auto_struct() {
+  AutoT<StructA>();
+  // CHECK: call {{.*}} @"??$AutoT at UStructA@@@@YA?A_PXZ"
+
+  AutoT<const StructA>();
+  // CHECK: call {{.*}} @"??$AutoT@$$CBUStructA@@@@YA?A_PXZ"
+
+  AutoConstT<StructA>();
+  // CHECK: call {{.*}} @"??$AutoConstT at UStructA@@@@YA?B_PXZ"
+
+  AutoVolatileT<StructA>();
+  // CHECK: call {{.*}} @"??$AutoVolatileT at UStructA@@@@YA?C_PXZ"
+
+  AutoConstVolatileT<StructA>();
+  // CHECK: call {{.*}} @"??$AutoConstVolatileT at UStructA@@@@YA?D_PXZ"
+}
+
+void test_template_auto_ptr() {
+  AutoT<int*>();
+  // CHECK: call {{.*}} @"??$AutoT at PEAH@@YA?A_PXZ"
+
+  AutoT<const int*>();
+  // CHECK: call {{.*}} @"??$AutoT at PEBH@@YA?A_PXZ"
+
+  AutoT<const int* const>();
+  // CHECK: call {{.*}} @"??$AutoT at QEBH@@YA?A_PXZ"
+
+  AutoConstT<int*>();
+  // CHECK: call {{.*}} @"??$AutoConstT at PEAH@@YA?B_PXZ"
+
+  AutoVolatileT<int*>();
+  // CHECK: call {{.*}} @"??$AutoVolatileT at PEAH@@YA?C_PXZ"
+
+  AutoConstVolatileT<int*>();
+  // CHECK: call {{.*}} @"??$AutoConstVolatileT at PEAH@@YA?D_PXZ"
+}
+
+template<class T>
+auto* PtrAutoT() { return T(); }
+
+template<class T>
+const auto* PtrAutoConstT() { return T(); }
+
+template<class T>
+volatile auto* PtrAutoVolatileT() { return T(); }
+
+template<class T>
+const volatile auto* PtrAutoConstVolatileT() { return T(); }
+
+void test_template_ptr_auto() {
+  PtrAutoT<int*>();
+  // CHECK: call {{.*}} @"??$PtrAutoT at PEAH@@YAPEA_PXZ"
+
+  PtrAutoT<const int*>();
+  // CHECK: call {{.*}} @"??$PtrAutoT at PEBH@@YAPEA_PXZ"
+
+  PtrAutoT<const int* const>();
+  // CHECK: call {{.*}} @"??$PtrAutoT at QEBH@@YAPEA_PXZ"
+
+  PtrAutoConstT<int*>();
+  // CHECK: call {{.*}} @"??$PtrAutoConstT at PEAH@@YAPEB_PXZ"
+
+  PtrAutoVolatileT<int*>();
+  // CHECK: call {{.*}} @"??$PtrAutoVolatileT at PEAH@@YAPEC_PXZ"
+
+  PtrAutoConstVolatileT<int*>();
+  // CHECK: call {{.*}} @"??$PtrAutoConstVolatileT at PEAH@@YAPED_PXZ"
+}
+
+int func_int();
+const int func_constint();
+void func_void();
+int* func_intptr();
+
+template<class T, T v>
+auto (*FuncPtrAutoT())() { return v; }
+
+void test_template_func_ptr_auto() {
+  FuncPtrAutoT<int (*)(), &func_int>();
+  // CHECK: call {{.*}} @"??$FuncPtrAutoT at P6AHXZ$1?func_int@@YAHXZ@@YAP6A?A_PXZXZ"
+
+  FuncPtrAutoT<const int (*)(), &func_constint>();
+  // CHECK: call {{.*}} @"??$FuncPtrAutoT at P6A?BHXZ$1?func_constint@@YA?BHXZ@@YAP6A?A_PXZXZ"
+
+  FuncPtrAutoT<void (*)(), &func_void>();
+  // CHECK: call {{.*}} @"??$FuncPtrAutoT at P6AXXZ$1?func_void@@YAXXZ@@YAP6A?A_PXZXZ"
+
+  FuncPtrAutoT<int * (*)(), &func_intptr>();
+  // CHECK: call {{.*}} @"??$FuncPtrAutoT at P6APEAHXZ$1?func_intptr@@YAPEAHXZ@@YAP6A?A_PXZXZ"
+}
+
+template<class T>
+auto& RefAutoT(T& x) { return x; }
+
+template<class T>
+const auto& ConstRefAutoT(T& x) { return x; }
+
+template<class T>
+auto&& RRefAutoT(T& x) { return static_cast<int&&>(x); }
+
+void test_template_ref_auto() {
+  int x;
+
+  RefAutoT(x);
+  // CHECK: call {{.*}} @"??$RefAutoT at H@@YAAEA_PAEAH at Z"
+
+  ConstRefAutoT(x);
+  // CHECK: call {{.*}} @"??$ConstRefAutoT at H@@YAAEB_PAEAH at Z"
+
+  RRefAutoT(x);
+  // CHECK: call {{.*}} @"??$RRefAutoT at H@@YA$$QEA_PAEAH at Z"
+}
+
+template<class T>
+decltype(auto) DecltypeAutoT() { return T(); }
+
+template<class T>
+decltype(auto) DecltypeAutoT2(T& x) { return static_cast<T&&>(x); }
+
+void test_template_decltypeauto() {
+  DecltypeAutoT<void>();
+  // CHECK: call {{.*}} @"??$DecltypeAutoT at X@@YA?A_TXZ"
+
+  DecltypeAutoT<const void>();
+  // CHECK: call {{.*}} @"??$DecltypeAutoT@$$CBX@@YA?A_TXZ"
+
+  DecltypeAutoT<volatile void>();
+  // CHECK: call {{.*}} @"??$DecltypeAutoT@$$CCX@@YA?A_TXZ"
+
+  DecltypeAutoT<const volatile void>();
+  // CHECK: call {{.*}} @"??$DecltypeAutoT@$$CDX@@YA?A_TXZ"
+
+  DecltypeAutoT<int>();
+  // CHECK: call {{.*}} @"??$DecltypeAutoT at H@@YA?A_TXZ"
+
+  DecltypeAutoT<const int>();
+  // CHECK: call {{.*}} @"??$DecltypeAutoT@$$CBH@@YA?A_TXZ"
+
+  DecltypeAutoT<volatile int>();
+  // CHECK: call {{.*}} @"??$DecltypeAutoT@$$CCH@@YA?A_TXZ"
+
+  DecltypeAutoT<const volatile int>();
+  // CHECK: call {{.*}} @"??$DecltypeAutoT@$$CDH@@YA?A_TXZ"
+
+  int x;
+
+  DecltypeAutoT2(x);
+  // CHECK: call {{.*}} @"??$DecltypeAutoT2 at H@@YA?A_TAEAH at Z"
+}
+
+// Still want to use clang's custom mangling for lambdas to keep backwards compatibility until
+// MSVC lambda name mangling has been deciphered.
+void test_lambda() {
+  auto lambdaIntRetAuto = []() { return 0; };
+  lambdaIntRetAuto();
+  // CHECK: call {{.*}} @"??R<lambda_1>@?0??test_lambda@@YAXXZ at QEBA?A?<auto>@@XZ"
+
+  auto lambdaIntRet = []() -> int { return 0; };
+  lambdaIntRet();
+  // CHECK: call {{.*}} @"??R<lambda_2>@?0??test_lambda@@YAXXZ at QEBA@XZ"
+
+  auto lambdaGenericIntIntRetAuto = [](auto a) { return a; };
+  lambdaGenericIntIntRetAuto(0);
+  // CHECK: call {{.*}} @"??$?RH@<lambda_0>@?0??test_lambda@@YAXXZ at QEBA?A?<auto>@@H at Z"
+}
+
+auto TestTrailingInt() -> int {
+  return 0;
+}
+
+auto TestTrailingConstVolatileVoid() -> const volatile void {
+}
+
+auto TestTrailingStructA() -> StructA {
+  return StructA{};
+}
+
+void test_trailing_return() {
+  TestTrailingInt();
+  // CHECK: call {{.*}} @"?TestTrailingInt@@YAHXZ"
+
+  TestTrailingConstVolatileVoid();
+  // CHECK: call {{.*}} @"?TestTrailingConstVolatileVoid@@YAXXZ"
+
+  TestTrailingStructA();
+  // CHECK: call {{.*}} @"?TestTrailingStructA@@YA?AUStructA@@XZ"
+}
+
+auto TestNonTemplateAutoInt() {
+  return 0;
+}
+
+auto TestNonTemplateAutoVoid() {
+  return;
+}
+
+auto TestNonTemplateAutoStructA() {
+  return StructA{};
+}
+
+const auto TestNonTemplateConstAutoInt() {
+  return 0;
+}
+
+const auto TestNonTemplateConstAutoVoid() {
+  return;
+}
+
+const auto TestNonTemplateConstAutoStructA() {
+  return StructA{};
+}
+
+void test_nontemplate_auto() {
+  TestNonTemplateAutoInt();
+  // CHECK: call {{.*}} @"?TestNonTemplateAutoInt@@YA at XZ"
+
+  TestNonTemplateAutoVoid();
+  // CHECK: call {{.*}} @"?TestNonTemplateAutoVoid@@YA at XZ"
+
+  TestNonTemplateAutoStructA();
+  // CHECK: call {{.*}} @"?TestNonTemplateAutoStructA@@YA at XZ"
+
+  TestNonTemplateConstAutoInt();
+  // CHECK: call {{.*}} @"?TestNonTemplateConstAutoInt@@YA at XZ"
+
+  TestNonTemplateConstAutoVoid();
+  // CHECK: call {{.*}} @"?TestNonTemplateConstAutoVoid@@YA at XZ"
+
+  TestNonTemplateConstAutoStructA();
+  // CHECK: call {{.*}} @"?TestNonTemplateConstAutoStructA@@YA at XZ"
+}
+
+decltype(auto) TestNonTemplateDecltypeAutoInt() {
+    return 0;
+}
+
+decltype(auto) TestNonTemplateDecltypeAutoVoid() {
+    return;
+}
+
+decltype(auto) TestNonTemplateDecltypeAutoStructA() {
+    return StructA{};
+}
+
+void test_nontemplate_decltypeauto() {
+  TestNonTemplateDecltypeAutoInt();
+  // CHECK: call {{.*}} @"?TestNonTemplateDecltypeAutoInt@@YA at XZ"
+
+  TestNonTemplateDecltypeAutoVoid();
+  // CHECK: call {{.*}} @"?TestNonTemplateDecltypeAutoVoid@@YA at XZ"
+
+  TestNonTemplateDecltypeAutoStructA();
+  // CHECK: call {{.*}} @"?TestNonTemplateDecltypeAutoStructA@@YA at XZ"
+}
+
+struct StructB {
+  int x;
+};
+
+template<class T>
+auto StructB::* AutoMemberDataPtrT(T x) { return x; }
+
+template<class T>
+const auto StructB::* AutoConstMemberDataPtrT(T x) { return x; }
+
+void test_template_auto_member_data_ptr() {
+  AutoMemberDataPtrT(&StructB::x);
+  // CHECK: call {{.*}} @"??$AutoMemberDataPtrT at PEQStructB@@H@@YAPEQStructB@@_PPEQ0 at H@Z"
+
+  AutoConstMemberDataPtrT(&StructB::x);
+  // CHECK: call {{.*}} @"??$AutoConstMemberDataPtrT at PEQStructB@@H@@YAPERStructB@@_PPEQ0 at H@Z"
+}
+
+struct StructC {
+  void test() {}
+};
+
+struct StructD {
+  const int test() { return 0; }
+};
+
+template<class T>
+auto (StructC::*AutoMemberFuncPtrT(T x))() { return x; }
+
+template<class T>
+const auto (StructD::*AutoConstMemberFuncPtrT(T x))() { return x; }
+
+void test_template_auto_member_func_ptr() {
+  AutoMemberFuncPtrT(&StructC::test);
+  // CHECK: call {{.*}} @"??$AutoMemberFuncPtrT at P8StructC@@EAAXXZ@@YAP8StructC@@EAA?A_PXZP80 at EAAXXZ@Z"
+
+  AutoConstMemberFuncPtrT(&StructD::test);
+  // CHECK: call {{.*}} @"??$AutoConstMemberFuncPtrT at P8StructD@@EAA?BHXZ@@YAP8StructD@@EAA?B_PXZP80 at EAA?BHXZ at Z"
+}
diff --git a/clang/test/CodeGenCXX/mangle-ms-auto-templates-memptrs.cpp b/clang/test/CodeGenCXX/mangle-ms-auto-templates-memptrs.cpp
index 360ebdecc5562b..b7bc3953f0b438 100644
--- a/clang/test/CodeGenCXX/mangle-ms-auto-templates-memptrs.cpp
+++ b/clang/test/CodeGenCXX/mangle-ms-auto-templates-memptrs.cpp
@@ -34,15 +34,15 @@ void template_mangling() {
   // BEFORE: call {{.*}} @"??0?$AutoParmTemplate@$I?f at V@@QEAAXXZA at A@@@QEAA at XZ"
 
   AutoFunc<&S::f>();
-  // AFTER: call {{.*}} @"??$AutoFunc@$MP8S@@EAAXXZ1?f at 1@QEAAXXZ@@YA?A?<auto>@@XZ"
+  // AFTER: call {{.*}} @"??$AutoFunc@$MP8S@@EAAXXZ1?f at 1@QEAAXXZ@@YA?A_PXZ"
   // BEFORE: call {{.*}} @"??$AutoFunc@$1?f at S@@QEAAXXZ@@YA?A?<auto>@@XZ"
 
   AutoFunc<&M::f>();
-  // AFTER: call {{.*}} @"??$AutoFunc@$MP8M@@EAAXXZH?f at 1@QEAAXXZA@@@YA?A?<auto>@@XZ"
+  // AFTER: call {{.*}} @"??$AutoFunc@$MP8M@@EAAXXZH?f at 1@QEAAXXZA@@@YA?A_PXZ"
   // BEFORE: call {{.*}} @"??$AutoFunc@$H?f at M@@QEAAXXZA@@@YA?A?<auto>@@XZ"
 
   AutoFunc<&V::f>();
-  // AFTER: call {{.*}} @"??$AutoFunc@$MP8V@@EAAXXZI?f at 1@QEAAXXZA at A@@@YA?A?<auto>@@XZ"
+  // AFTER: call {{.*}} @"??$AutoFunc@$MP8V@@EAAXXZI?f at 1@QEAAXXZA at A@@@YA?A_PXZ"
   // BEFORE: call {{.*}} @"??$AutoFunc@$I?f at V@@QEAAXXZA at A@@@YA?A?<auto>@@XZ"
 
   AutoParmTemplate<&S::a> auto_data_single_inheritance;
@@ -58,14 +58,14 @@ void template_mangling() {
   // BEFORE: call {{.*}} @"??0?$AutoParmTemplate@$FBA at A@@@QEAA at XZ"
 
   AutoFunc<&S::a>();
-  // AFTER: call {{.*}} @"??$AutoFunc@$MPEQS@@H07@@YA?A?<auto>@@XZ"
+  // AFTER: call {{.*}} @"??$AutoFunc@$MPEQS@@H07@@YA?A_PXZ"
   // BEFORE: call {{.*}} @"??$AutoFunc@$07@@YA?A?<auto>@@XZ"
 
   AutoFunc<&M::a>();
-  // AFTER: call {{.*}} @"??$AutoFunc@$MPEQM@@H0M@@@YA?A?<auto>@@XZ"
+  // AFTER: call {{.*}} @"??$AutoFunc@$MPEQM@@H0M@@@YA?A_PXZ"
   // BEFORE: call {{.*}} @"??$AutoFunc@$0M@@@YA?A?<auto>@@XZ"
 
   AutoFunc<&V::a>();
-  // AFTER: call {{.*}} @"??$AutoFunc@$MPEQV@@HFBA at A@@@YA?A?<auto>@@XZ"
+  // AFTER: call {{.*}} @"??$AutoFunc@$MPEQV@@HFBA at A@@@YA?A_PXZ"
   // BEFORE: call {{.*}} @"??$AutoFunc@$FBA at A@@@YA?A?<auto>@@XZ"
 }
diff --git a/clang/test/CodeGenCXX/mangle-ms-auto-templates-nullptr.cpp b/clang/test/CodeGenCXX/mangle-ms-auto-templates-nullptr.cpp
index 8f98c1e59f73d7..251d9219c01ce2 100644
--- a/clang/test/CodeGenCXX/mangle-ms-auto-templates-nullptr.cpp
+++ b/clang/test/CodeGenCXX/mangle-ms-auto-templates-nullptr.cpp
@@ -19,6 +19,6 @@ void template_mangling() {
   // BEFORE: call {{.*}} @"??0?$AutoParmTemplate@$0A@@@QEAA at XZ"
 
   AutoFunc<nullptr>();
-  // AFTER: call {{.*}} @"??$AutoFunc@$M$$T0A@@@YA?A?<auto>@@XZ"
+  // AFTER: call {{.*}} @"??$AutoFunc@$M$$T0A@@@YA?A_PXZ"
   // BEFORE: call {{.*}} @"??$AutoFunc@$0A@@@YA?A?<auto>@@XZ"
 }
diff --git a/clang/test/CodeGenCXX/mangle-ms-auto-templates.cpp b/clang/test/CodeGenCXX/mangle-ms-auto-templates.cpp
index ff5395cea75eb7..effcc31ee31103 100644
--- a/clang/test/CodeGenCXX/mangle-ms-auto-templates.cpp
+++ b/clang/test/CodeGenCXX/mangle-ms-auto-templates.cpp
@@ -26,7 +26,7 @@ int j;
 
 void template_mangling() {
   AutoFunc<1>();
-  // AFTER: call {{.*}} @"??$AutoFunc@$MH00@@YA?A?<auto>@@XZ"
+  // AFTER: call {{.*}} @"??$AutoFunc@$MH00@@YA?A_PXZ"
   // BEFORE: call {{.*}} @"??$AutoFunc@$00@@YA?A?<auto>@@XZ"
   AutoParmTemplate<0> auto_int;
   // AFTER: call {{.*}} @"??0?$AutoParmTemplate@$MH0A@@@QEAA at XZ"
@@ -52,7 +52,7 @@ void template_mangling() {
   // BEFORE: call {{.*}} @"??0?$AutoParmsTemplate@$00$0HPPPPPPPPPPPPPPP@@@QEAA at XZ"
 
   AutoFunc<&i>();
-  // AFTER: call {{.*}} @"??$AutoFunc@$MPEAH1?i@@3HA@@YA?A?<auto>@@XZ"
+  // AFTER: call {{.*}} @"??$AutoFunc@$MPEAH1?i@@3HA@@YA?A_PXZ"
   // BEFORE: call {{.*}} @"??$AutoFunc@$1?i@@3HA@@YA?A?<auto>@@XZ"
 
   AutoParmTemplate<&i> auto_int_ptr;
@@ -64,7 +64,7 @@ void template_mangling() {
   // BEFORE: call {{.*}} @"??0?$AutoParmsTemplate@$1?i@@3HA$1?j@@3HA@@QEAA at XZ"
 
   AutoFunc<&Func>();
-  // AFTER: call {{.*}} @"??$AutoFunc@$MP6AHXZ1?Func@@YAHXZ@@YA?A?<auto>@@XZ"
+  // AFTER: call {{.*}} @"??$AutoFunc@$MP6AHXZ1?Func@@YAHXZ@@YA?A_PXZ"
   // BEFORE: call {{.*}} @"??$AutoFunc@$1?Func@@YAHXZ@@YA?A?<auto>@@XZ"
 
   AutoParmTemplate<&Func> auto_func_ptr;

>From c316645d62c2a78e84ddf9bd52b7e3067286b08b Mon Sep 17 00:00:00 2001
From: MaxEW707 <max.enrico.winkler at gmail.com>
Date: Sun, 11 Aug 2024 21:50:20 -0700
Subject: [PATCH 2/6] formatting

---
 clang/lib/AST/MicrosoftMangle.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp
index ecbddc1aacc073..5da12b55d1a281 100644
--- a/clang/lib/AST/MicrosoftMangle.cpp
+++ b/clang/lib/AST/MicrosoftMangle.cpp
@@ -2560,7 +2560,6 @@ void MicrosoftCXXNameMangler::mangleAutoReturnType(QualType T,
 
 void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range,
                                          QualifierMangleMode QMM) {
-
   // Don't use the canonical types.  MSVC includes things like 'const' on
   // pointer arguments to function pointers that canonicalization strips away.
   T = T.getDesugaredType(getASTContext());

>From 13f1086e046eacc8c82a1fff2c357444ecc22174 Mon Sep 17 00:00:00 2001
From: MaxEW707 <max.enrico.winkler at gmail.com>
Date: Sun, 11 Aug 2024 22:02:52 -0700
Subject: [PATCH 3/6] add missing address space test

---
 clang/test/CodeGenCXX/mangle-ms-auto-return.cpp | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/clang/test/CodeGenCXX/mangle-ms-auto-return.cpp b/clang/test/CodeGenCXX/mangle-ms-auto-return.cpp
index 9b34a9abfd75d8..737c9c407f4703 100644
--- a/clang/test/CodeGenCXX/mangle-ms-auto-return.cpp
+++ b/clang/test/CodeGenCXX/mangle-ms-auto-return.cpp
@@ -356,3 +356,14 @@ void test_template_auto_member_func_ptr() {
   AutoConstMemberFuncPtrT(&StructD::test);
   // CHECK: call {{.*}} @"??$AutoConstMemberFuncPtrT at P8StructD@@EAA?BHXZ@@YAP8StructD@@EAA?B_PXZP80 at EAA?BHXZ at Z"
 }
+
+template<class T>
+auto * __attribute__((address_space(1))) * AutoPtrAddressSpaceT() {
+  T * __attribute__((address_space(1))) * p = nullptr;
+  return p;
+}
+
+void test_template_auto_address_space_ptr() {
+  AutoPtrAddressSpaceT<int>();
+  // CHECK: call {{.*}} @"??$AutoPtrAddressSpaceT at H@@YA?A?<auto>@@XZ"
+}

>From 9ce68b9ab3cf2201e978a6128622dfaf43caf039 Mon Sep 17 00:00:00 2001
From: MaxEW707 <max.enrico.winkler at gmail.com>
Date: Mon, 12 Aug 2024 20:09:40 -0700
Subject: [PATCH 4/6] Remove unused SourceRange argument

---
 clang/lib/AST/MicrosoftMangle.cpp | 46 ++++++++++++-------------------
 1 file changed, 18 insertions(+), 28 deletions(-)

diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp
index 5da12b55d1a281..bd88bd5fd8f0e8 100644
--- a/clang/lib/AST/MicrosoftMangle.cpp
+++ b/clang/lib/AST/MicrosoftMangle.cpp
@@ -408,8 +408,7 @@ class MicrosoftCXXNameMangler {
   void mangleSourceName(StringRef Name);
   void mangleNestedName(GlobalDecl GD);
 
-  void mangleAutoReturnType(QualType T, SourceRange Range,
-                            QualifierMangleMode QMM);
+  void mangleAutoReturnType(QualType T, QualifierMangleMode QMM);
 
 private:
   bool isStructorDecl(const NamedDecl *ND) const {
@@ -481,14 +480,10 @@ class MicrosoftCXXNameMangler {
   void mangleObjCKindOfType(const ObjCObjectType *T, Qualifiers Quals,
                             SourceRange Range);
 
-  void mangleAutoReturnType(const MemberPointerType *T, Qualifiers Quals,
-                            SourceRange Range);
-  void mangleAutoReturnType(const PointerType *T, Qualifiers Quals,
-                            SourceRange Range);
-  void mangleAutoReturnType(const LValueReferenceType *T, Qualifiers Quals,
-                            SourceRange Range);
-  void mangleAutoReturnType(const RValueReferenceType *T, Qualifiers Quals,
-                            SourceRange Range);
+  void mangleAutoReturnType(const MemberPointerType *T, Qualifiers Quals);
+  void mangleAutoReturnType(const PointerType *T, Qualifiers Quals);
+  void mangleAutoReturnType(const LValueReferenceType *T, Qualifiers Quals);
+  void mangleAutoReturnType(const RValueReferenceType *T, Qualifiers Quals);
 };
 }
 
@@ -2507,7 +2502,6 @@ void MicrosoftCXXNameMangler::mangleAddressSpaceType(QualType T,
 }
 
 void MicrosoftCXXNameMangler::mangleAutoReturnType(QualType T,
-                                                   SourceRange Range,
                                                    QualifierMangleMode QMM) {
   assert(getASTContext().getLangOpts().isCompatibleWithMSVC(
              LangOptions::MSVC2019) &&
@@ -2542,16 +2536,16 @@ void MicrosoftCXXNameMangler::mangleAutoReturnType(QualType T,
   const Type *ty = T.getTypePtr();
   switch (ty->getTypeClass()) {
   case Type::MemberPointer:
-    mangleAutoReturnType(cast<MemberPointerType>(ty), Quals, Range);
+    mangleAutoReturnType(cast<MemberPointerType>(ty), Quals);
     break;
   case Type::Pointer:
-    mangleAutoReturnType(cast<PointerType>(ty), Quals, Range);
+    mangleAutoReturnType(cast<PointerType>(ty), Quals);
     break;
   case Type::LValueReference:
-    mangleAutoReturnType(cast<LValueReferenceType>(ty), Quals, Range);
+    mangleAutoReturnType(cast<LValueReferenceType>(ty), Quals);
     break;
   case Type::RValueReference:
-    mangleAutoReturnType(cast<RValueReferenceType>(ty), Quals, Range);
+    mangleAutoReturnType(cast<RValueReferenceType>(ty), Quals);
     break;
   default:
     llvm_unreachable("Invalid type expected");
@@ -3000,7 +2994,7 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
         if (D && !D->getPrimaryTemplate()) {
           Out << '@';
         } else {
-          mangleAutoReturnType(ResultType, Range, QMM_Result);
+          mangleAutoReturnType(ResultType, QMM_Result);
         }
       } else {
         Out << '?';
@@ -4312,8 +4306,7 @@ void MicrosoftMangleContextImpl::mangleStringLiteral(const StringLiteral *SL,
 }
 
 void MicrosoftCXXNameMangler::mangleAutoReturnType(const MemberPointerType *T,
-                                                   Qualifiers Quals,
-                                                   SourceRange Range) {
+                                                   Qualifiers Quals) {
   QualType PointeeType = T->getPointeeType();
   manglePointerCVQualifiers(Quals);
   manglePointerExtQualifiers(Quals, PointeeType);
@@ -4324,13 +4317,12 @@ void MicrosoftCXXNameMangler::mangleAutoReturnType(const MemberPointerType *T,
   } else {
     mangleQualifiers(PointeeType.getQualifiers(), true);
     mangleName(T->getClass()->castAs<RecordType>()->getDecl());
-    mangleAutoReturnType(PointeeType, Range, QMM_Drop);
+    mangleAutoReturnType(PointeeType, QMM_Drop);
   }
 }
 
 void MicrosoftCXXNameMangler::mangleAutoReturnType(const PointerType *T,
-                                                   Qualifiers Quals,
-                                                   SourceRange Range) {
+                                                   Qualifiers Quals) {
   QualType PointeeType = T->getPointeeType();
   assert(!PointeeType.getQualifiers().hasAddressSpace() &&
          "Unexpected address space mangling required");
@@ -4342,28 +4334,26 @@ void MicrosoftCXXNameMangler::mangleAutoReturnType(const PointerType *T,
     Out << '6';
     mangleFunctionType(FPT);
   } else {
-    mangleAutoReturnType(PointeeType, Range, QMM_Mangle);
+    mangleAutoReturnType(PointeeType, QMM_Mangle);
   }
 }
 
 void MicrosoftCXXNameMangler::mangleAutoReturnType(const LValueReferenceType *T,
-                                                   Qualifiers Quals,
-                                                   SourceRange Range) {
+                                                   Qualifiers Quals) {
   QualType PointeeType = T->getPointeeType();
   assert(!Quals.hasConst() && !Quals.hasVolatile() && "unexpected qualifier!");
   Out << 'A';
   manglePointerExtQualifiers(Quals, PointeeType);
-  mangleAutoReturnType(PointeeType, Range, QMM_Mangle);
+  mangleAutoReturnType(PointeeType, QMM_Mangle);
 }
 
 void MicrosoftCXXNameMangler::mangleAutoReturnType(const RValueReferenceType *T,
-                                                   Qualifiers Quals,
-                                                   SourceRange Range) {
+                                                   Qualifiers Quals) {
   QualType PointeeType = T->getPointeeType();
   assert(!Quals.hasConst() && !Quals.hasVolatile() && "unexpected qualifier!");
   Out << "$$Q";
   manglePointerExtQualifiers(Quals, PointeeType);
-  mangleAutoReturnType(PointeeType, Range, QMM_Mangle);
+  mangleAutoReturnType(PointeeType, QMM_Mangle);
 }
 
 MicrosoftMangleContext *MicrosoftMangleContext::create(ASTContext &Context,

>From 55b8eb32a334304bb775b17ea40dd9b0c2cfca64 Mon Sep 17 00:00:00 2001
From: MaxEW707 <max.enrico.winkler at gmail.com>
Date: Tue, 13 Aug 2024 18:42:10 -0700
Subject: [PATCH 5/6] Update release notes

---
 clang/docs/ReleaseNotes.rst | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 3c2e0282d1c72d..4b6ddd1dd8d0f3 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -46,6 +46,8 @@ C++ Specific Potentially Breaking Changes
 ABI Changes in This Version
 ---------------------------
 
+- Fixed Microsoft name mangling of placeholder, auto and decltype(auto), return types for MSVC 1920+. This change resolves incompatibilities with code compiled by MSVC 1920+ but will introduce incompatibilities with code compiled by earlier versions of Clang unless such code is built with the compiler option -fms-compatibility-version=19.14 to imitate the MSVC 1914 mangling behavior.
+
 AST Dumping Potentially Breaking Changes
 ----------------------------------------
 

>From 342b8b76302b3d796018ed13018ce9b7838053b2 Mon Sep 17 00:00:00 2001
From: MaxEW707 <max.enrico.winkler at gmail.com>
Date: Sat, 17 Aug 2024 21:55:10 -0700
Subject: [PATCH 6/6] Fix reference collapsing auto&& return types

---
 clang/lib/AST/MicrosoftMangle.cpp               | 11 ++++++++++-
 clang/test/CodeGenCXX/mangle-ms-auto-return.cpp | 14 ++++++++++++++
 2 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp
index bd88bd5fd8f0e8..7b3731db019ffa 100644
--- a/clang/lib/AST/MicrosoftMangle.cpp
+++ b/clang/lib/AST/MicrosoftMangle.cpp
@@ -2962,6 +2962,7 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
       if (const auto *AT = ResultType->getContainedAutoType()) {
         assert(AT->getKeyword() == AutoTypeKeyword::Auto &&
                "should only need to mangle auto!");
+        (void)AT;
         Out << '?';
         mangleQualifiers(ResultType.getLocalQualifiers(), /*IsMember=*/false);
         Out << '?';
@@ -2980,7 +2981,7 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
       // SourceRange Range)` for details.
       auto UseClangMangling = [](QualType ResultType) {
         QualType T = ResultType;
-        while (const auto *PT = dyn_cast<PointerType>(T.getTypePtr())) {
+        while (isa<PointerType>(T.getTypePtr())) {
           T = T->getPointeeType();
           if (T.getQualifiers().hasAddressSpace())
             return true;
@@ -2994,6 +2995,14 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
         if (D && !D->getPrimaryTemplate()) {
           Out << '@';
         } else {
+          if (D && D->getPrimaryTemplate()) {
+            const FunctionProtoType *FPT = D->getPrimaryTemplate()
+                                               ->getTemplatedDecl()
+                                               ->getFirstDecl()
+                                               ->getType()
+                                               ->castAs<FunctionProtoType>();
+            ResultType = FPT->getReturnType();
+          }
           mangleAutoReturnType(ResultType, QMM_Result);
         }
       } else {
diff --git a/clang/test/CodeGenCXX/mangle-ms-auto-return.cpp b/clang/test/CodeGenCXX/mangle-ms-auto-return.cpp
index 737c9c407f4703..5b18dcc0820ee6 100644
--- a/clang/test/CodeGenCXX/mangle-ms-auto-return.cpp
+++ b/clang/test/CodeGenCXX/mangle-ms-auto-return.cpp
@@ -367,3 +367,17 @@ void test_template_auto_address_space_ptr() {
   AutoPtrAddressSpaceT<int>();
   // CHECK: call {{.*}} @"??$AutoPtrAddressSpaceT at H@@YA?A?<auto>@@XZ"
 }
+
+template<class T>
+auto&& AutoReferenceCollapseT(T& x) { return static_cast<T&>(x); }
+
+auto&& AutoReferenceCollapse(int& x) { return static_cast<int&>(x); }
+
+void test2() {
+  int x = 1;
+  auto&& rref0 = AutoReferenceCollapseT(x);
+  // CHECK: call {{.*}} @"??$AutoReferenceCollapseT at H@@YA$$QEA_PAEAH at Z"
+
+  auto&& rref1 = AutoReferenceCollapse(x);
+  // CHECK: call {{.*}} @"?AutoReferenceCollapse@@YA at AEAH@Z"
+}



More information about the cfe-commits mailing list