Index: lib/AST/MicrosoftMangle.cpp =================================================================== --- lib/AST/MicrosoftMangle.cpp +++ lib/AST/MicrosoftMangle.cpp @@ -966,16 +966,71 @@ } if (const BlockDecl *BD = dyn_cast(DC)) { - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = - Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle a local inside this block yet"); - Diags.Report(BD->getLocation(), DiagID); - - // FIXME: This is completely, utterly, wrong; see ItaniumMangle - // for how this should be done. - Out << "__block_invoke" << Context.getBlockId(BD, false); - Out << '@'; + auto Discriminate = + [](StringRef Name, const unsigned Discriminator, + const unsigned ParameterDiscriminator) -> std::string { + std::string Buffer; + llvm::raw_string_ostream Stream(Buffer); + Stream << Name; + if (Discriminator) + Stream << '_' << Discriminator; + if (ParameterDiscriminator) + Stream << '_' << ParameterDiscriminator; + return Stream.str(); + }; + + unsigned Discriminator = BD->getBlockManglingNumber(); + if (!Discriminator) + Discriminator = Context.getBlockId(BD, /*Local=*/false); + + // Mangle the parameter position as a discriminator to deal with unnamed + // parameters. Rather than mangling the unqualified parameter name, + // always use the position to give a uniform mangling. + unsigned ParameterDiscriminator = 0; + if (const auto *MC = BD->getBlockManglingContextDecl()) + if (const auto *P = dyn_cast(MC)) + if (const auto *F = dyn_cast(P->getDeclContext())) + ParameterDiscriminator = + F->getNumParams() - P->getFunctionScopeIndex(); + + DC = getEffectiveDeclContext(BD); + + Out << '?'; + mangleSourceName(Discriminate("_block_invoke", Discriminator, + ParameterDiscriminator)); + // If we have a block mangling context, encode that now. This allows us + // to discriminate between named static data initializers in the same + // scope. This is handled differently from parameters, which use + // positions to discriminate between multiple instances. + if (const auto *MC = BD->getBlockManglingContextDecl()) + if (!isa(MC)) + if (const auto *ND = dyn_cast(MC)) + mangleUnqualifiedName(ND); + // MS ABI and Itanium manglings are in inverted scopes. In the case of a + // RecordDecl, mangle the entire scope hierachy at this point rather than + // just the unqualified name to get the ordering correct. + if (const auto *RD = dyn_cast(DC)) + mangleName(RD); + else + Out << '@'; + // void __cdecl + Out << "YAX"; + // struct __block_literal * + Out << 'P'; + // __ptr64 + if (PointersAre64Bit) + Out << 'E'; + Out << 'A'; + mangleArtificalTagType(TTK_Struct, + Discriminate("__block_literal", Discriminator, + ParameterDiscriminator)); + Out << "@Z"; + + // If the effective context was a Record, we have fully mangled the + // qualified name and do not need to continue. + if (isa(DC)) + break; + continue; } else if (const ObjCMethodDecl *Method = dyn_cast(DC)) { mangleObjCMethodName(Method); } else if (isa(DC)) { Index: test/CodeGenCXX/msabi-blocks.cpp =================================================================== --- /dev/null +++ test/CodeGenCXX/msabi-blocks.cpp @@ -0,0 +1,113 @@ +// RUN: %clang_cc1 -triple i686-unknown-windows-msvc -std=c++11 -fblocks -S -o - -emit-llvm %s | FileCheck %s -check-prefix CHECK-X86 +// RUN: %clang_cc1 -triple x86_64-unknown-windows-msvc -std=c++11 -fblocks -S -o - -emit-llvm %s | FileCheck %s -check-prefix CHECK-X64 + +extern int e(void); + +void (^b)() = ^{ + static int i = 0; +}; + +// CHECK-X86-DAG: @"\01?i@?1??_block_invoke@@YAXPAU__block_literal@@@Z@4HA" ={{.*}} global i32 0 +// CHECK-X64-DAG: @"\01?i@?1??_block_invoke@@YAXPEAU__block_literal@@@Z@4HA" ={{.*}} global i32 0 + +void f(void) { + static int i = 0; + ^{ static int i = e(); }(); + +// CHECK-X86-DAG: @"\01?i@?1??_block_invoke_1@@YAXPAU__block_literal_1@@@Z?1??f@@YAXXZ@4HA" ={{.*}} global i32 0 +// CHECK-X64-DAG: @"\01?i@?1??_block_invoke_1@@YAXPEAU__block_literal_1@@@Z?1??f@@YAXXZ@4HA" ={{.*}} global i32 0 + + ^{ static int i = e(); }(); + +// CHECK-X86-DAG: @"\01?i@?1??_block_invoke_2@@YAXPAU__block_literal_2@@@Z?1??f@@YAXXZ@4HA" ={{.*}} global i32 0 +// CHECK-X64-DAG: @"\01?i@?1??_block_invoke_2@@YAXPEAU__block_literal_2@@@Z?1??f@@YAXXZ@4HA" ={{.*}} global i32 0 + + ^{ ^{ static int i = e(); }(); }(); + +// CHECK-X86-DAG: @"\01?i@?1??_block_invoke_3@@YAXPAU__block_literal_3@@@Z?1??_block_invoke_4@@YAXPAU__block_literal_4@@@Z?1??f@@YAXXZ@4HA" ={{.*}} global i32 0 +// CHECK-X64-DAG: @"\01?i@?1??_block_invoke_3@@YAXPEAU__block_literal_3@@@Z?1??_block_invoke_4@@YAXPEAU__block_literal_4@@@Z?1??f@@YAXXZ@4HA" ={{.*}} global i32 0 +} + + +template +void g(void) { + ^{ static int i = e(); }(); +} + +template void g(void); + +// CHECK-X86-DAG: @"\01?i@?2??_block_invoke_1@@YAXPAU__block_literal_1@@@Z?2???$g@D@@YAXXZ@4HA" ={{.*}} global i32 0 +// CHECK-X64-DAG: @"\01?i@?2??_block_invoke_1@@YAXPEAU__block_literal_1@@@Z?2???$g@D@@YAXXZ@4HA" ={{.*}} global i32 0 + +template void g(void); + +// CHECK-X86-DAG: @"\01?i@?2??_block_invoke_1@@YAXPAU__block_literal_1@@@Z?2???$g@H@@YAXXZ@4HA" ={{.*}} global i32 0 +// CHECK-X64-DAG: @"\01?i@?2??_block_invoke_1@@YAXPEAU__block_literal_1@@@Z?2???$g@H@@YAXXZ@4HA" ={{.*}} global i32 0 + +inline void h(void) { + ^{ static int i = e(); }(); +} + +// CHECK-X86-DAG: @"\01?i@?2??_block_invoke_1@@YAXPAU__block_literal_1@@@Z?2??h@@YAXXZ@4HA" ={{.*}} global i32 0 +// CHECK-X64-DAG: @"\01?i@?2??_block_invoke_1@@YAXPEAU__block_literal_1@@@Z?2??h@@YAXXZ@4HA" ={{.*}} global i32 0 + +struct s { + int i = ^{ static int i = e(); return ++i; }(); + +// CHECK-X86-DAG: @"\01?i@?0??_block_invoke_1@0s@@YAXPAU__block_literal_1@@@Z@4HA" ={{.*}} global i32 0 +// CHECK-X64-DAG: @"\01?i@?0??_block_invoke_1@0s@@YAXPEAU__block_literal_1@@@Z@4HA" ={{.*}} global i32 0 + + int j = ^{ static int i = e(); return ++i; }(); + +// CHECK-X86-DAG: @"\01?i@?0??_block_invoke_1@j@s@@YAXPAU__block_literal_1@@@Z@4HA" ={{.*}} global i32 0 +// CHECK-X64-DAG: @"\01?i@?0??_block_invoke_1@j@s@@YAXPEAU__block_literal_1@@@Z@4HA" ={{.*}} global i32 0 + + void m(int i = ^{ static int i = e(); return ++i; }(), + int j = ^{ static int i = e(); return ++i; }()) {} + +// CHECK-X86-DAG: @"\01?i@?0??_block_invoke_1_1@@YAXPAU__block_literal_1_1@@@Z?0??m@s@@QAEXHH@Z@4HA" ={{.*}} global i32 0 +// CHECK-X86-DAG: @"\01?i@?0??_block_invoke_1_2@@YAXPAU__block_literal_1_2@@@Z?0??m@s@@QAEXHH@Z@4HA" ={{.*}} global i32 0 +// CHECK-X64-DAG: @"\01?i@?0??_block_invoke_1_1@@YAXPEAU__block_literal_1_1@@@Z?0??m@s@@QEAAXHH@Z@4HA" ={{.*}} global i32 0 +// CHECK-X64-DAG: @"\01?i@?0??_block_invoke_1_2@@YAXPEAU__block_literal_1_2@@@Z?0??m@s@@QEAAXHH@Z@4HA" ={{.*}} global i32 0 + + void n(int = ^{ static int i = e(); return ++i; }(), + int = ^{ static int i = e(); return ++i; }()) {} + +// CHECK-X86-DAG: @"\01?i@?0??_block_invoke_1_1@@YAXPAU__block_literal_1_1@@@Z?0??n@s@@QAEXHH@Z@4HA" ={{.*}} global i32 0 +// CHECK-X86-DAG: @"\01?i@?0??_block_invoke_1_2@@YAXPAU__block_literal_1_2@@@Z?0??n@s@@QAEXHH@Z@4HA" ={{.*}} global i32 0 +// CHECK-X64-DAG: @"\01?i@?0??_block_invoke_1_1@@YAXPEAU__block_literal_1_1@@@Z?0??n@s@@QEAAXHH@Z@4HA" ={{.*}} global i32 0 +// CHECK-X64-DAG: @"\01?i@?0??_block_invoke_1_2@@YAXPEAU__block_literal_1_2@@@Z?0??n@s@@QEAAXHH@Z@4HA" ={{.*}} global i32 0 + +}; + +struct t { + struct u { + int i = ^{ static int i = e(); return ++i; }(); + +// CHECK-X86-DAG: @"\01?i@?0??_block_invoke_1@0u@t@@YAXPAU__block_literal_1@@@Z@4HA" ={{.*}} global i32 0 +// CHECK-X64-DAG: @"\01?i@?0??_block_invoke_1@0u@t@@YAXPEAU__block_literal_1@@@Z@4HA" ={{.*}} global i32 0 + + }; +}; + +void j(void) { + h(); + struct s s; + s.m(); + s.n(); + struct t::u t; +} + +#if 0 +template +struct v { + static T i; +}; + +template +T v::i = ^{ static T i = T(); return i; }(); + +template class v; +template class v; +#endif +