Index: lib/CodeGen/CGCXX.cpp =================================================================== --- lib/CodeGen/CGCXX.cpp +++ lib/CodeGen/CGCXX.cpp @@ -242,6 +242,11 @@ if (auto *CD = dyn_cast(MD)) { GD = GlobalDecl(CD, toCXXCtorType(Type)); } else { + // Always alias equivalent complete destructors to base destructors in the + // MS ABI. + if (getTarget().getCXXABI().isMicrosoft() && + Type == StructorType::Complete && MD->getParent()->getNumVBases() == 0) + Type = StructorType::Base; GD = GlobalDecl(cast(MD), toCXXDtorType(Type)); } Index: lib/CodeGen/CGCXXABI.h =================================================================== --- lib/CodeGen/CGCXXABI.h +++ lib/CodeGen/CGCXXABI.h @@ -319,6 +319,14 @@ virtual bool useThunkForDtorVariant(const CXXDestructorDecl *Dtor, CXXDtorType DT) const = 0; + virtual void setCXXDestructorDLLStorage(llvm::GlobalValue *GV, + const CXXDestructorDecl *Dtor, + CXXDtorType DT) const; + + virtual llvm::GlobalValue::LinkageTypes + getCXXDestructorLinkage(GVALinkage Linkage, const CXXDestructorDecl *Dtor, + CXXDtorType DT) const; + /// Emit destructor variants required by this ABI. virtual void EmitCXXDestructors(const CXXDestructorDecl *D) = 0; Index: lib/CodeGen/CGCXXABI.cpp =================================================================== --- lib/CodeGen/CGCXXABI.cpp +++ lib/CodeGen/CGCXXABI.cpp @@ -287,6 +287,20 @@ return nullptr; } +void CGCXXABI::setCXXDestructorDLLStorage(llvm::GlobalValue *GV, + const CXXDestructorDecl *Dtor, + CXXDtorType DT) const { + // Assume the base C++ ABI has no special rules for destructor variants. + CGM.setDLLImportDLLExport(GV, Dtor); +} + +llvm::GlobalValue::LinkageTypes CGCXXABI::getCXXDestructorLinkage( + GVALinkage Linkage, const CXXDestructorDecl *Dtor, CXXDtorType DT) const { + // Delegate back to CGM by default. + return CGM.getLLVMLinkageForDeclarator(Dtor, Linkage, + /*isConstantVariable=*/false); +} + bool CGCXXABI::NeedsVTTParameter(GlobalDecl GD) { return false; } Index: lib/CodeGen/CodeGenModule.cpp =================================================================== --- lib/CodeGen/CodeGenModule.cpp +++ lib/CodeGen/CodeGenModule.cpp @@ -786,12 +786,10 @@ void CodeGenModule::setDLLImportDLLExport(llvm::GlobalValue *GV, GlobalDecl GD) const { const auto *D = dyn_cast(GD.getDecl()); + // C++ destructors have a few C++ ABI specific special cases. if (const auto *Dtor = dyn_cast_or_null(D)) { - if (getCXXABI().useThunkForDtorVariant(Dtor, GD.getDtorType())) { - // Don't dllexport/import destructor thunks. - GV->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass); - return; - } + getCXXABI().setCXXDestructorDLLStorage(GV, Dtor, GD.getDtorType()); + return; } setDLLImportDLLExport(GV, D); } @@ -1074,14 +1072,8 @@ GVALinkage Linkage = getContext().GetGVALinkageForFunction(D); - if (isa(D) && - getCXXABI().useThunkForDtorVariant(cast(D), - GD.getDtorType())) { - // Destructor variants in the Microsoft C++ ABI are always internal or - // linkonce_odr thunks emitted on an as-needed basis. - return Linkage == GVA_Internal ? llvm::GlobalValue::InternalLinkage - : llvm::GlobalValue::LinkOnceODRLinkage; - } + if (const auto *Dtor = dyn_cast(D)) + return getCXXABI().getCXXDestructorLinkage(Linkage, Dtor, GD.getDtorType()); if (isa(D) && cast(D)->isInheritingConstructor() && Index: lib/CodeGen/MicrosoftCXXABI.cpp =================================================================== --- lib/CodeGen/MicrosoftCXXABI.cpp +++ lib/CodeGen/MicrosoftCXXABI.cpp @@ -216,6 +216,14 @@ return DT != Dtor_Base; } + void setCXXDestructorDLLStorage(llvm::GlobalValue *GV, + const CXXDestructorDecl *Dtor, + CXXDtorType DT) const override; + + llvm::GlobalValue::LinkageTypes + getCXXDestructorLinkage(GVALinkage Linkage, const CXXDestructorDecl *Dtor, + CXXDtorType DT) const override; + void EmitCXXDestructors(const CXXDestructorDecl *D) override; const CXXRecordDecl * @@ -1310,6 +1318,52 @@ return Added; } +void MicrosoftCXXABI::setCXXDestructorDLLStorage(llvm::GlobalValue *GV, + const CXXDestructorDecl *Dtor, + CXXDtorType DT) const { + // Deleting destructor variants are never imported or exported. Give them the + // default storage class. + if (DT == Dtor_Deleting) { + GV->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass); + } else { + const NamedDecl *ND = Dtor; + CGM.setDLLImportDLLExport(GV, ND); + } +} + +llvm::GlobalValue::LinkageTypes MicrosoftCXXABI::getCXXDestructorLinkage( + GVALinkage Linkage, const CXXDestructorDecl *Dtor, CXXDtorType DT) const { + // Internal things are always internal, regardless of attributes. After this, + // we know the thunk is externally visible. + if (Linkage == GVA_Internal) + return llvm::GlobalValue::InternalLinkage; + + switch (DT) { + case Dtor_Base: + // The base destructor most closely tracks the user-declared constructor, so + // we delegate back to the normal declarator case. + return CGM.getLLVMLinkageForDeclarator(Dtor, Linkage, + /*isConstantVariable=*/false); + case Dtor_Complete: + // The complete destructor is like an inline function, but it may be + // imported and therefore must be exported as well. This requires changing + // the linkage if a DLL attribute is present. + if (Dtor->hasAttr()) + return llvm::GlobalValue::WeakODRLinkage; + if (Dtor->hasAttr()) + return llvm::GlobalValue::AvailableExternallyLinkage; + return llvm::GlobalValue::LinkOnceODRLinkage; + case Dtor_Deleting: + // Deleting destructors are like inline functions. They have vague linkage + // and are emitted everywhere they are used. They are internal if the class + // is internal. + return llvm::GlobalValue::LinkOnceODRLinkage; + case Dtor_Comdat: + llvm_unreachable("MS C++ ABI does not support comdat dtors"); + } + llvm_unreachable("invalid dtor type"); +} + void MicrosoftCXXABI::EmitCXXDestructors(const CXXDestructorDecl *D) { // The TU defining a dtor is only guaranteed to emit a base destructor. All // other destructor variants are delegating thunks. @@ -1549,6 +1603,12 @@ const CXXDestructorDecl *DD, CXXDtorType Type, bool ForVirtualBase, bool Delegating, Address This) { + // Use the base destructor variant in place of the complete destructor variant + // if the class has no virtual bases. This effectively implements some of the + // -mconstructor-aliases optimization, but as part of the MS C++ ABI. + if (Type == Dtor_Complete && DD->getParent()->getNumVBases() == 0) + Type = Dtor_Base; + CGCallee Callee = CGCallee::forDirect( CGM.getAddrOfCXXStructor(DD, getFromDtorType(Type)), DD); @@ -3821,19 +3881,12 @@ static void emitCXXDestructor(CodeGenModule &CGM, const CXXDestructorDecl *dtor, StructorType dtorType) { - // The complete destructor is equivalent to the base destructor for - // classes with no virtual bases, so try to emit it as an alias. - if (!dtor->getParent()->getNumVBases() && - (dtorType == StructorType::Complete || dtorType == StructorType::Base)) { - bool ProducedAlias = !CGM.TryEmitDefinitionAsAlias( - GlobalDecl(dtor, Dtor_Complete), GlobalDecl(dtor, Dtor_Base)); - if (ProducedAlias) { - if (dtorType == StructorType::Complete) - return; - if (dtor->isVirtual()) - CGM.getVTables().EmitThunks(GlobalDecl(dtor, Dtor_Complete)); - } - } + // Emit the base destructor if the base and complete (vbase) destructors are + // equivalent. This effectively implements -mconstructor-aliases as part of + // the ABI. + if (dtorType == StructorType::Complete && + dtor->getParent()->getNumVBases() == 0) + dtorType = StructorType::Base; // The base destructor is equivalent to the base destructor of its // base class if there is exactly one non-virtual base class with a Index: test/CodeGenCXX/cxx2a-destroying-delete.cpp =================================================================== --- test/CodeGenCXX/cxx2a-destroying-delete.cpp +++ test/CodeGenCXX/cxx2a-destroying-delete.cpp @@ -128,7 +128,7 @@ // CHECK-MSABI: call void @"\01??3F@@SAXPEAU0@Udestroying_delete_t@std@@_KW4align_val_t@2@@Z"({{.*}}, i64 48, i64 16) // CHECK-MSABI: br label %[[RETURN:.*]] // -// CHECK-MSABI: call void @"\01??_DH@@QEAAXXZ"( +// CHECK-MSABI: call void @"\01??1H@@UEAA@XZ"( // CHECK-MSABI: br label %[[RETURN]] // // CHECK-MSABI: } @@ -155,7 +155,7 @@ // CHECK-MSABI: call void @"\01??3F@@SAXPEAU0@Udestroying_delete_t@std@@_KW4align_val_t@2@@Z"({{.*}}, i64 96, i64 32) // CHECK-MSABI: br label %[[RETURN:.*]] // -// CHECK-MSABI: call void @"\01??_DI@@QEAAXXZ"( +// CHECK-MSABI: call void @"\01??1I@@UEAA@XZ"( // CHECK-MSABI: br label %[[RETURN]] // // CHECK-MSABI: } Index: test/CodeGenCXX/debug-info-ms-dtor-thunks.cpp =================================================================== --- test/CodeGenCXX/debug-info-ms-dtor-thunks.cpp +++ test/CodeGenCXX/debug-info-ms-dtor-thunks.cpp @@ -5,10 +5,10 @@ struct __declspec(dllexport) U : S, T { virtual ~U(); }; // CHECK-LABEL: define {{.*}} @"\01??_GS@@UAEPAXI@Z" -// CHECK: call x86_thiscallcc void @"\01??_DS@@QAEXXZ"(%struct.S* %this1){{.*}}!dbg !{{[0-9]+}} +// CHECK: call x86_thiscallcc void @"\01??1S@@UAE@XZ"(%struct.S* %this1){{.*}}!dbg !{{[0-9]+}} // CHECK-LABEL: define {{.*}} @"\01??_GT@@UAEPAXI@Z" -// CHECK: call x86_thiscallcc void @"\01??_DT@@QAEXXZ"(%struct.T* %this1){{.*}}!dbg !{{[0-9]+}} +// CHECK: call x86_thiscallcc void @"\01??1T@@UAE@XZ"(%struct.T* %this1){{.*}}!dbg !{{[0-9]+}} // CHECK-LABEL: define {{.*}} @"\01??_GU@@UAEPAXI@Z" -// CHECK: call x86_thiscallcc void @"\01??_DU@@QAEXXZ"(%struct.U* %this1){{.*}}!dbg !{{[0-9]+}} +// CHECK: call x86_thiscallcc void @"\01??1U@@UAE@XZ"(%struct.U* %this1){{.*}}!dbg !{{[0-9]+}} Index: test/CodeGenCXX/dllexport-dtor-thunks.cpp =================================================================== --- test/CodeGenCXX/dllexport-dtor-thunks.cpp +++ test/CodeGenCXX/dllexport-dtor-thunks.cpp @@ -5,6 +5,6 @@ struct __declspec(dllexport) C : A, B { virtual ~C(); }; C::~C() {} +// CHECK: define dso_local dllexport void @"\01??1C@@UEAA@XZ" // This thunk should *not* be dllexport. // CHECK: define linkonce_odr dso_local i8* @"\01??_EC@@W7EAAPEAXI@Z" -// CHECK: define dso_local dllexport void @"\01??1C@@UEAA@XZ" Index: test/CodeGenCXX/dllimport-dtor-thunks.cpp =================================================================== --- test/CodeGenCXX/dllimport-dtor-thunks.cpp +++ test/CodeGenCXX/dllimport-dtor-thunks.cpp @@ -1,9 +1,5 @@ // RUN: %clang_cc1 -mconstructor-aliases %s -triple x86_64-windows-msvc -fms-extensions -emit-llvm -o - | FileCheck %s -// FIXME: We should really consider removing -mconstructor-aliases for MS C++ -// ABI. The risk of bugs introducing ABI incompatibility under -// -mno-constructor-aliases is too high. - // PR32990 // Introduces the virtual destructor. We should use the base destructor @@ -44,6 +40,6 @@ // CHECK: call void @"\01??1ImportOverrideVDtor@@UEAA@XZ"(%struct.ImportOverrideVDtor* %{{.*}}) // CHECK: call void @"\01??1ImportIntroVDtor@@UEAA@XZ"(%struct.ImportIntroVDtor* %{{.*}}) -// CHECK-LABEL: define linkonce_odr dso_local void @"\01??_DImportVBaseOverrideVDtor@@QEAAXXZ" +// CHECK-LABEL: declare dllimport void @"\01??_DImportVBaseOverrideVDtor@@QEAAXXZ" // CHECK-LABEL: declare dllimport void @"\01??1ImportOverrideVDtor@@UEAA@XZ" // CHECK-LABEL: declare dllimport void @"\01??1ImportIntroVDtor@@UEAA@XZ" Index: test/CodeGenCXX/exceptions-cxx-new.cpp =================================================================== --- test/CodeGenCXX/exceptions-cxx-new.cpp +++ test/CodeGenCXX/exceptions-cxx-new.cpp @@ -55,12 +55,12 @@ // CHECK: to label %[[LEAVE_FUNC:.*]] unwind label %[[CLEANUP:.*]] // CHECK: [[LEAVE_FUNC]] -// CHECK: call x86_thiscallcc void @"\01??_DCleanup@@QAEXXZ"( +// CHECK: call x86_thiscallcc void @"\01??1Cleanup@@QAE@XZ"( // CHECK: ret void // CHECK: [[CLEANUP]] // CHECK: %[[CLEANUPPAD:.*]] = cleanuppad within none [] -// CHECK: call x86_thiscallcc void @"\01??_DCleanup@@QAEXXZ"( +// CHECK: call x86_thiscallcc void @"\01??1Cleanup@@QAE@XZ"( // CHECK: cleanupret from %[[CLEANUPPAD]] unwind to caller Index: test/CodeGenCXX/inheriting-constructor.cpp =================================================================== --- test/CodeGenCXX/inheriting-constructor.cpp +++ test/CodeGenCXX/inheriting-constructor.cpp @@ -137,7 +137,7 @@ // WIN32: call {{.*}} @"\01??0A@inalloca_nonvirt@@QAE@UQ@@H0$$QAU2@@Z"(%{{[^,]*}}, <{{.*}}>* inalloca %[[ARGMEM]]) // WIN32: call void @llvm.stackrestore( // WIN32: call {{.*}} @"\01??0Z@@QAE@XZ"( - // WIN32: call {{.*}} @"\01??_DQ@@QAEXXZ"( + // WIN32: call {{.*}} @"\01??1Q@@QAE@XZ"( // On Win64, the Q arguments would be destroyed in the callee. We don't yet // support that in the non-inlined case, so we force inlining. @@ -150,7 +150,7 @@ // WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"( // WIN64: call {{.*}} @"\01??0A@inalloca_nonvirt@@QEAA@UQ@@H0$$QEAU2@@Z"(%{{.*}}, %{{.*}}* %[[ARG1]], i32 2, %{{.*}}* %[[ARG3]], %{{.*}} %[[TMP]]) // WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"( - // WIN64: call void @"\01??_DQ@@QEAAXXZ"({{.*}}* %[[TMP]]) + // WIN64: call void @"\01??1Q@@QEAA@XZ"({{.*}}* %[[TMP]]) struct C : B { using B::B; }; C c(1, 2, 3, 4); @@ -173,7 +173,7 @@ // WIN32: call {{.*}} @"\01??0A@inalloca_nonvirt@@QAE@UQ@@H0$$QAU2@@Z"(%{{[^,]*}}, <{{.*}}>* inalloca %[[ARGMEM]]) // WIN32: call void @llvm.stackrestore( // WIN32: call {{.*}} @"\01??0Z@@QAE@XZ"( - // WIN32: call {{.*}} @"\01??_DQ@@QAEXXZ"( + // WIN32: call {{.*}} @"\01??1Q@@QAE@XZ"( // On Win64, the Q arguments would be destroyed in the callee. We don't yet // support that in the non-inlined case, so we force inlining. @@ -186,7 +186,7 @@ // WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"( // WIN64: call {{.*}} @"\01??0A@inalloca_nonvirt@@QEAA@UQ@@H0$$QEAU2@@Z"(%{{.*}}, %{{.*}}* %[[ARG1]], i32 2, %{{.*}}* %[[ARG3]], %{{.*}} %[[TMP]]) // WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"( - // WIN64: call void @"\01??_DQ@@QEAAXXZ"({{.*}}* %[[TMP]]) + // WIN64: call void @"\01??1Q@@QEAA@XZ"({{.*}}* %[[TMP]]) } namespace inalloca_virt { @@ -224,7 +224,7 @@ // destroy the parameters, but that's not actually possible. // WIN32: call {{.*}} @"\01??0Z@@QAE@XZ"( // WIN32: call {{.*}} @"\01??0Z@@QAE@XZ"( - // WIN32: call {{.*}} @"\01??_DQ@@QAEXXZ"( + // WIN32: call {{.*}} @"\01??1Q@@QAE@XZ"( // On Win64, the Q arguments would be destroyed in the callee. We don't yet // support that in the non-inlined case, so we force inlining. @@ -239,7 +239,7 @@ // WIN64: br // WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"( // WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"( - // WIN64: call void @"\01??_DQ@@QEAAXXZ"({{.*}}* %[[TMP]]) + // WIN64: call void @"\01??1Q@@QEAA@XZ"({{.*}}* %[[TMP]]) struct C : B { using B::B; }; C c(1, 2, 3, 4); @@ -281,7 +281,7 @@ // // WIN32: call {{.*}} @"\01??0Z@@QAE@XZ"( // WIN32: call {{.*}} @"\01??0Z@@QAE@XZ"( - // WIN32: call {{.*}} @"\01??_DQ@@QAEXXZ"( + // WIN32: call {{.*}} @"\01??1Q@@QAE@XZ"( // On Win64, the Q arguments would be destroyed in the callee. We don't yet // support that in the non-inlined case, so we force inlining. @@ -301,7 +301,7 @@ // WIN64: br // WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"( // WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"( - // WIN64: call void @"\01??_DQ@@QEAAXXZ"({{.*}}* %[[TMP]]) + // WIN64: call void @"\01??1Q@@QEAA@XZ"({{.*}}* %[[TMP]]) } namespace inline_nonvirt { Index: test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp =================================================================== --- test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp +++ test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp @@ -138,6 +138,6 @@ // CHECK: [[CALL:%.*]] = invoke i8* @__RTDynamicCast // CHECK: [[BC:%.*]] = bitcast i8* [[CALL]] to %"struct.PR25606::S3"* -// CHECK: call x86_thiscallcc void @"\01??_DCleanup@PR25606@@QAEXXZ"( +// CHECK: call x86_thiscallcc void @"\01??1Cleanup@PR25606@@QAE@XZ"( // CHECK: ret %"struct.PR25606::S3"* [[BC]] } Index: test/CodeGenCXX/microsoft-abi-methods.cpp =================================================================== --- test/CodeGenCXX/microsoft-abi-methods.cpp +++ test/CodeGenCXX/microsoft-abi-methods.cpp @@ -75,15 +75,15 @@ // CHECK: %{{[.0-9A-Z_a-z]+}} = call x86_thiscallcc %class.Base* @"\01??0Base@@QAE@XZ" // CHECK: ret -// Make sure that the Base constructor definition uses the right CC: -// CHECK: define linkonce_odr dso_local x86_thiscallcc %class.Base* @"\01??0Base@@QAE@XZ" - // Make sure that the Base destructor call in the Child denstructor uses // the right calling convention: // CHECK: define linkonce_odr dso_local x86_thiscallcc void @"\01??1Child@@QAE@XZ" // CHECK: call x86_thiscallcc void @"\01??1Base@@QAE@XZ" // CHECK: ret +// Make sure that the Base constructor definition uses the right CC: +// CHECK: define linkonce_odr dso_local x86_thiscallcc %class.Base* @"\01??0Base@@QAE@XZ" + // Make sure that the Base destructor definition uses the right CC: // CHECK: define linkonce_odr dso_local x86_thiscallcc void @"\01??1Base@@QAE@XZ" } Index: test/CodeGenCXX/regcall.cpp =================================================================== --- test/CodeGenCXX/regcall.cpp +++ test/CodeGenCXX/regcall.cpp @@ -47,8 +47,8 @@ // CHECK-LIN-DAG: define linkonce_odr x86_regcallcc void @_ZN10test_classD2Ev // CHECK-LIN-DAG: define linkonce_odr x86_regcallcc void @_ZN10test_classD1Ev // Windows ignores calling convention on constructor/destructors. - // CHECK-WIN64-DAG: define linkonce_odr dso_local void @"\01??_Dtest_class@@QEAAXXZ" - // CHECK-WIN32-DAG: define linkonce_odr dso_local x86_thiscallcc void @"\01??_Dtest_class@@QAEXXZ" + // CHECK-WIN64-DAG: define linkonce_odr dso_local void @"\01??1test_class@@QEAA@XZ" + // CHECK-WIN32-DAG: define linkonce_odr dso_local x86_thiscallcc void @"\01??1test_class@@QAE@XZ" test_class& __regcall operator+=(const test_class&){ return *this; Index: test/CodeGenCoroutines/coro-eh-cleanup.cpp =================================================================== --- test/CodeGenCoroutines/coro-eh-cleanup.cpp +++ test/CodeGenCoroutines/coro-eh-cleanup.cpp @@ -50,7 +50,7 @@ // CHECK: to label %[[CONT:.+]] unwind label %[[EHCLEANUP:.+]] // CHECK: [[EHCLEANUP]]: // CHECK: %[[INNERPAD:.+]] = cleanuppad within none [] -// CHECK: call void @"\01??_DCleanup@@QEAAXXZ"( +// CHECK: call void @"\01??1Cleanup@@QEAA@XZ"( // CHECK: cleanupret from %{{.+}} unwind label %[[CATCHDISPATCH:.+]] // CHECK: [[CATCHDISPATCH]]: Index: test/CodeGenCoroutines/coro-promise-dtor.cpp =================================================================== --- test/CodeGenCoroutines/coro-promise-dtor.cpp +++ test/CodeGenCoroutines/coro-promise-dtor.cpp @@ -44,4 +44,4 @@ // CHECK: br i1 %[[NRVO]], label %{{.+}}, label %[[DTOR:.+]] // CHECK: [[DTOR]]: -// CHECK: call void @"\01??_Dcoro_t@@QEAAXXZ"( +// CHECK: call void @"\01??1coro_t@@QEAA@XZ"( Index: test/CodeGenCoroutines/coro-unhandled-exception.cpp =================================================================== --- test/CodeGenCoroutines/coro-unhandled-exception.cpp +++ test/CodeGenCoroutines/coro-unhandled-exception.cpp @@ -37,7 +37,7 @@ // CHECK: to label %{{.+}} unwind label %[[EHCLEANUP:.+]] // CHECK: [[EHCLEANUP]]: // CHECK: %[[INNERPAD:.+]] = cleanuppad within none [] -// CHECK: call void @"\01??_DCleanup@@QEAAXXZ"( +// CHECK: call void @"\01??1Cleanup@@QEAA@XZ"( // CHECK: cleanupret from %[[INNERPAD]] unwind label %[[CATCHSW:.+]] // CHECK: [[CATCHSW]]: // CHECK: %[[CATCHSWTOK:.+]] = catchswitch within none [label %[[CATCH:.+]]] unwind label