// 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 auto AutoT() { return T(); } template const auto AutoConstT() { return T(); } template volatile auto AutoVolatileT() { return T(); } template 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(); // CHECK: call {{.*}} @"??$AutoT@X@@YA?A_PXZ" AutoT(); // CHECK: call {{.*}} @"??$AutoT@$$CBX@@YA?A_PXZ" AutoT(); // CHECK: call {{.*}} @"??$AutoT@$$CCX@@YA?A_PXZ" AutoT(); // CHECK: call {{.*}} @"??$AutoT@$$CDX@@YA?A_PXZ" AutoConstT(); // CHECK: call {{.*}} @"??$AutoConstT@X@@YA?B_PXZ" AutoVolatileT(); // CHECK: call {{.*}} @"??$AutoVolatileT@X@@YA?C_PXZ" AutoConstVolatileT(); // CHECK: call {{.*}} @"??$AutoConstVolatileT@X@@YA?D_PXZ" } void test_template_auto_int() { AutoT(); // CHECK: call {{.*}} @"??$AutoT@H@@YA?A_PXZ" AutoT(); // CHECK: call {{.*}} @"??$AutoT@$$CBH@@YA?A_PXZ" AutoT(); // CHECK: call {{.*}} @"??$AutoT@$$CCH@@YA?A_PXZ" AutoT(); // CHECK: call {{.*}} @"??$AutoT@$$CDH@@YA?A_PXZ" AutoConstT(); // CHECK: call {{.*}} @"??$AutoConstT@H@@YA?B_PXZ" AutoVolatileT(); // CHECK: call {{.*}} @"??$AutoVolatileT@H@@YA?C_PXZ" AutoConstVolatileT(); // CHECK: call {{.*}} @"??$AutoConstVolatileT@H@@YA?D_PXZ" } void test_template_auto_struct() { AutoT(); // CHECK: call {{.*}} @"??$AutoT@UStructA@@@@YA?A_PXZ" AutoT(); // CHECK: call {{.*}} @"??$AutoT@$$CBUStructA@@@@YA?A_PXZ" AutoConstT(); // CHECK: call {{.*}} @"??$AutoConstT@UStructA@@@@YA?B_PXZ" AutoVolatileT(); // CHECK: call {{.*}} @"??$AutoVolatileT@UStructA@@@@YA?C_PXZ" AutoConstVolatileT(); // CHECK: call {{.*}} @"??$AutoConstVolatileT@UStructA@@@@YA?D_PXZ" } void test_template_auto_ptr() { AutoT(); // CHECK: call {{.*}} @"??$AutoT@PEAH@@YA?A_PXZ" AutoT(); // CHECK: call {{.*}} @"??$AutoT@PEBH@@YA?A_PXZ" AutoT(); // CHECK: call {{.*}} @"??$AutoT@QEBH@@YA?A_PXZ" AutoConstT(); // CHECK: call {{.*}} @"??$AutoConstT@PEAH@@YA?B_PXZ" AutoVolatileT(); // CHECK: call {{.*}} @"??$AutoVolatileT@PEAH@@YA?C_PXZ" AutoConstVolatileT(); // CHECK: call {{.*}} @"??$AutoConstVolatileT@PEAH@@YA?D_PXZ" } template auto* PtrAutoT() { return T(); } template const auto* PtrAutoConstT() { return T(); } template volatile auto* PtrAutoVolatileT() { return T(); } template const volatile auto* PtrAutoConstVolatileT() { return T(); } void test_template_ptr_auto() { PtrAutoT(); // CHECK: call {{.*}} @"??$PtrAutoT@PEAH@@YAPEA_PXZ" PtrAutoT(); // CHECK: call {{.*}} @"??$PtrAutoT@PEBH@@YAPEA_PXZ" PtrAutoT(); // CHECK: call {{.*}} @"??$PtrAutoT@QEBH@@YAPEA_PXZ" PtrAutoConstT(); // CHECK: call {{.*}} @"??$PtrAutoConstT@PEAH@@YAPEB_PXZ" PtrAutoVolatileT(); // CHECK: call {{.*}} @"??$PtrAutoVolatileT@PEAH@@YAPEC_PXZ" PtrAutoConstVolatileT(); // CHECK: call {{.*}} @"??$PtrAutoConstVolatileT@PEAH@@YAPED_PXZ" } int func_int(); const int func_constint(); void func_void(); int* func_intptr(); template auto (*FuncPtrAutoT())() { return v; } void test_template_func_ptr_auto() { FuncPtrAutoT(); // CHECK: call {{.*}} @"??$FuncPtrAutoT@P6AHXZ$1?func_int@@YAHXZ@@YAP6A?A_PXZXZ" FuncPtrAutoT(); // CHECK: call {{.*}} @"??$FuncPtrAutoT@P6A?BHXZ$1?func_constint@@YA?BHXZ@@YAP6A?A_PXZXZ" FuncPtrAutoT(); // CHECK: call {{.*}} @"??$FuncPtrAutoT@P6AXXZ$1?func_void@@YAXXZ@@YAP6A?A_PXZXZ" FuncPtrAutoT(); // CHECK: call {{.*}} @"??$FuncPtrAutoT@P6APEAHXZ$1?func_intptr@@YAPEAHXZ@@YAP6A?A_PXZXZ" } template auto& RefAutoT(T& x) { return x; } template const auto& ConstRefAutoT(T& x) { return x; } template auto&& RRefAutoT(T& x) { return static_cast(x); } void test_template_ref_auto() { int x; RefAutoT(x); // CHECK: call {{.*}} @"??$RefAutoT@H@@YAAEA_PAEAH@Z" ConstRefAutoT(x); // CHECK: call {{.*}} @"??$ConstRefAutoT@H@@YAAEB_PAEAH@Z" RRefAutoT(x); // CHECK: call {{.*}} @"??$RRefAutoT@H@@YA$$QEA_PAEAH@Z" } template decltype(auto) DecltypeAutoT() { return T(); } template decltype(auto) DecltypeAutoT2(T& x) { return static_cast(x); } void test_template_decltypeauto() { DecltypeAutoT(); // CHECK: call {{.*}} @"??$DecltypeAutoT@X@@YA?A_TXZ" DecltypeAutoT(); // CHECK: call {{.*}} @"??$DecltypeAutoT@$$CBX@@YA?A_TXZ" DecltypeAutoT(); // CHECK: call {{.*}} @"??$DecltypeAutoT@$$CCX@@YA?A_TXZ" DecltypeAutoT(); // CHECK: call {{.*}} @"??$DecltypeAutoT@$$CDX@@YA?A_TXZ" DecltypeAutoT(); // CHECK: call {{.*}} @"??$DecltypeAutoT@H@@YA?A_TXZ" DecltypeAutoT(); // CHECK: call {{.*}} @"??$DecltypeAutoT@$$CBH@@YA?A_TXZ" DecltypeAutoT(); // CHECK: call {{.*}} @"??$DecltypeAutoT@$$CCH@@YA?A_TXZ" DecltypeAutoT(); // CHECK: call {{.*}} @"??$DecltypeAutoT@$$CDH@@YA?A_TXZ" int x; DecltypeAutoT2(x); // CHECK: call {{.*}} @"??$DecltypeAutoT2@H@@YA?A_TAEAH@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() { int i = 0; auto lambdaIntRetAuto = []() { return 0; }; lambdaIntRetAuto(); // CHECK: call {{.*}} @"??R@?0??test_lambda@@YAXXZ@QEBA?A?@@XZ" auto lambdaIntRet = []() -> int { return 0; }; lambdaIntRet(); // CHECK: call {{.*}} @"??R@?0??test_lambda@@YAXXZ@QEBA@XZ" auto lambdaGenericIntIntRetAuto = [](auto a) { return a; }; lambdaGenericIntIntRetAuto(0); // CHECK: call {{.*}} @"??$?RH@@?0??test_lambda@@YAXXZ@QEBA?A?@@H@Z" auto lambdaRetTrailingAuto = []() -> auto { return 0; }; lambdaRetTrailingAuto(); // CHECK: call {{.*}} @"??R@?0??test_lambda@@YAXXZ@QEBA?A?@@XZ" auto lambdaRetTrailingDecltypeAuto = []() -> decltype(auto) { return 0; }; lambdaRetTrailingDecltypeAuto(); // CHECK: call {{.*}} @"??R@?0??test_lambda@@YAXXZ@QEBA?A?@@XZ" auto lambdaRetTrailingRefCollapse = [](int x) -> auto&& { return x; }; lambdaRetTrailingRefCollapse(i); // CHECK: call {{.*}} @"??R@?0??test_lambda@@YAXXZ@QEBA?A?@@H@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@XZ" TestNonTemplateAutoVoid(); // CHECK: call {{.*}} @"?TestNonTemplateAutoVoid@@YA@XZ" TestNonTemplateAutoStructA(); // CHECK: call {{.*}} @"?TestNonTemplateAutoStructA@@YA@XZ" TestNonTemplateConstAutoInt(); // CHECK: call {{.*}} @"?TestNonTemplateConstAutoInt@@YA@XZ" TestNonTemplateConstAutoVoid(); // CHECK: call {{.*}} @"?TestNonTemplateConstAutoVoid@@YA@XZ" TestNonTemplateConstAutoStructA(); // CHECK: call {{.*}} @"?TestNonTemplateConstAutoStructA@@YA@XZ" } decltype(auto) TestNonTemplateDecltypeAutoInt() { return 0; } decltype(auto) TestNonTemplateDecltypeAutoVoid() { return; } decltype(auto) TestNonTemplateDecltypeAutoStructA() { return StructA{}; } void test_nontemplate_decltypeauto() { TestNonTemplateDecltypeAutoInt(); // CHECK: call {{.*}} @"?TestNonTemplateDecltypeAutoInt@@YA@XZ" TestNonTemplateDecltypeAutoVoid(); // CHECK: call {{.*}} @"?TestNonTemplateDecltypeAutoVoid@@YA@XZ" TestNonTemplateDecltypeAutoStructA(); // CHECK: call {{.*}} @"?TestNonTemplateDecltypeAutoStructA@@YA@XZ" } struct StructB { int x; }; template auto StructB::* AutoMemberDataPtrT(T x) { return x; } template const auto StructB::* AutoConstMemberDataPtrT(T x) { return x; } void test_template_auto_member_data_ptr() { AutoMemberDataPtrT(&StructB::x); // CHECK: call {{.*}} @"??$AutoMemberDataPtrT@PEQStructB@@H@@YAPEQStructB@@_PPEQ0@H@Z" AutoConstMemberDataPtrT(&StructB::x); // CHECK: call {{.*}} @"??$AutoConstMemberDataPtrT@PEQStructB@@H@@YAPERStructB@@_PPEQ0@H@Z" } struct StructC { void test() {} }; struct StructD { const int test() { return 0; } }; template auto (StructC::*AutoMemberFuncPtrT(T x))() { return x; } template const auto (StructD::*AutoConstMemberFuncPtrT(T x))() { return x; } void test_template_auto_member_func_ptr() { AutoMemberFuncPtrT(&StructC::test); // CHECK: call {{.*}} @"??$AutoMemberFuncPtrT@P8StructC@@EAAXXZ@@YAP8StructC@@EAA?A_PXZP80@EAAXXZ@Z" AutoConstMemberFuncPtrT(&StructD::test); // CHECK: call {{.*}} @"??$AutoConstMemberFuncPtrT@P8StructD@@EAA?BHXZ@@YAP8StructD@@EAA?B_PXZP80@EAA?BHXZ@Z" } template auto * __attribute__((address_space(1))) * AutoPtrAddressSpaceT() { T * __attribute__((address_space(1))) * p = nullptr; return p; } void test_template_auto_address_space_ptr() { AutoPtrAddressSpaceT(); // CHECK: call {{.*}} @"??$AutoPtrAddressSpaceT@H@@YA?A?@@XZ" } template auto&& AutoReferenceCollapseT(T& x) { return static_cast(x); } auto&& AutoReferenceCollapse(int& x) { return static_cast(x); } void test2() { int x = 1; auto&& rref0 = AutoReferenceCollapseT(x); // CHECK: call {{.*}} @"??$AutoReferenceCollapseT@H@@YA$$QEA_PAEAH@Z" auto&& rref1 = AutoReferenceCollapse(x); // CHECK: call {{.*}} @"?AutoReferenceCollapse@@YA@AEAH@Z" }