Index: lib/CodeGen/CGBlocks.cpp =================================================================== --- lib/CodeGen/CGBlocks.cpp +++ lib/CodeGen/CGBlocks.cpp @@ -160,7 +160,7 @@ } std::string TypeAtEncoding = - CGM.getContext().getObjCEncodingForBlock(BlockInfo.getBlockExpr()); + CGM.getObjCRuntime().getObjCEncodingForBlock(BlockInfo.getBlockExpr()); Name += "e" + llvm::to_string(TypeAtEncoding.size()) + "_" + TypeAtEncoding; Name += "l" + CGM.getObjCRuntime().getRCBlockLayoutStr(CGM, BlockInfo); return Name; Index: lib/CodeGen/CGObjCGNU.cpp =================================================================== --- lib/CodeGen/CGObjCGNU.cpp +++ lib/CodeGen/CGObjCGNU.cpp @@ -662,6 +662,14 @@ llvm::Constant *BuildByrefLayout(CodeGenModule &CGM, QualType T) override { return NULLPtr; } + + /// Replace occurrences of '@' with '\1'. '@' is reserved on ELF platforms as + /// a separator between symbol name and symbol version. + std::string getObjCEncodingForBlock(const BlockExpr *BE) const override { + std::string Str = CGM.getContext().getObjCEncodingForBlock(BE); + std::replace(Str.begin(), Str.end(), '@', '\1'); + return Str; + } }; /// Class representing the legacy GCC Objective-C ABI. This is the default when Index: lib/CodeGen/CGObjCRuntime.h =================================================================== --- lib/CodeGen/CGObjCRuntime.h +++ lib/CodeGen/CGObjCRuntime.h @@ -283,6 +283,10 @@ return {}; } + /// Return the block's type encoding string that is used in the block + /// descriptor's symbol name. + virtual std::string getObjCEncodingForBlock(const BlockExpr *BE) const; + /// Returns an i8* which points to the byref layout information. virtual llvm::Constant *BuildByrefLayout(CodeGen::CodeGenModule &CGM, QualType T) = 0; Index: lib/CodeGen/CGObjCRuntime.cpp =================================================================== --- lib/CodeGen/CGObjCRuntime.cpp +++ lib/CodeGen/CGObjCRuntime.cpp @@ -352,6 +352,10 @@ CGF.EmitStmt(S.getSynchBody()); } +std::string CGObjCRuntime::getObjCEncodingForBlock(const BlockExpr *BE) const { + return CGM.getContext().getObjCEncodingForBlock(BE); +} + /// Compute the pointer-to-function type to which a message send /// should be casted in order to correctly call the given method /// with the given arguments. Index: test/CodeGenObjC/gnu-block-desc-str.m =================================================================== --- /dev/null +++ test/CodeGenObjC/gnu-block-desc-str.m @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-freebsd -emit-llvm -fobjc-runtime=gnustep-1.7 -fblocks -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -fobjc-runtime=gcc -fblocks -o - %s | FileCheck %s + +// Test that descriptor symbol names don't include '@', which is reserved on ELF +// platforms as a separator between symbol name and symbol version. + +// CHECK: @[[STR:.*]] = private unnamed_addr constant [6 x i8] c"v8@?0\00" +// CHECK: @"__block_descriptor_40_8_32o_e5_v8\01?0l" = linkonce_odr hidden unnamed_addr constant { i64, i64, i8*, i8*, i8*, i8* } { i64 0, i64 40, i8* bitcast ({{.*}} to i8*), i8* bitcast ({{.*}} to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @[[STR]], i32 0, i32 0), i8* null }, align 8 + +typedef void (^BlockTy)(void); + +void test(id a) { + BlockTy b = ^{ (void)a; }; +}