From 155e26f0f43c92131d624fe5e0db4b3cb010cf96 Mon Sep 17 00:00:00 2001 From: Shoaib Meenai Date: Thu, 28 Mar 2019 17:01:20 +0000 Subject: [PATCH] [CodeGen] Add additional mangling for struct members of non trivial structs In https://bugs.llvm.org/show_bug.cgi?id=41206 we observe bad codegen when embedding a non-trivial C struct within a C struct. This is due to the fact that name mangling for non-trivial structs marks the two structs as identical. This diff contains a fix for this issue. Patch by Dan Zimmerman . Differential Revision: https://reviews.llvm.org/D59873 llvm-svn: 357184 --- clang/lib/CodeGen/CGNonTrivialStruct.cpp | 5 ++- .../nontrivial-c-struct-within-struct-name.m | 44 ++++++++++++++++++++++ clang/test/CodeGenObjC/strong-in-c-struct.m | 32 ++++++++-------- 3 files changed, 63 insertions(+), 18 deletions(-) create mode 100644 clang/test/CodeGenObjC/nontrivial-c-struct-within-struct-name.m diff --git a/clang/lib/CodeGen/CGNonTrivialStruct.cpp b/clang/lib/CodeGen/CGNonTrivialStruct.cpp index a1649e4..f2b59f8 100644 --- a/clang/lib/CodeGen/CGNonTrivialStruct.cpp +++ b/clang/lib/CodeGen/CGNonTrivialStruct.cpp @@ -139,8 +139,8 @@ struct CopyStructVisitor : StructVisitor, // ::= ["_" ] // ::= + // ::= | -// ::= | | -// +// ::= "_S" | +// | // ::= "_AB" "s" "n" // "_AE" // ::= @@ -175,6 +175,7 @@ template struct GenFuncNameBase { void visitStruct(QualType QT, const FieldDecl *FD, CharUnits CurStructOffset) { CharUnits FieldOffset = CurStructOffset + asDerived().getFieldOffset(FD); + appendStr("_S"); asDerived().visitStructFields(QT, FieldOffset); } diff --git a/clang/test/CodeGenObjC/nontrivial-c-struct-within-struct-name.m b/clang/test/CodeGenObjC/nontrivial-c-struct-within-struct-name.m new file mode 100644 index 0000000..854c097 --- /dev/null +++ b/clang/test/CodeGenObjC/nontrivial-c-struct-within-struct-name.m @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -triple arm64-apple-ios11 -fobjc-arc -emit-llvm -o - %s | FileCheck %s + +@class I; + +typedef struct { + I *name; +} Foo; + +typedef struct { + Foo foo; +} Bar; + +typedef struct { + Bar bar; +} Baz; + +I *getI(); + +void f() { + Foo foo = {getI()}; + Bar bar = {foo}; + Baz baz = {bar}; +} + +// CHECK: define linkonce_odr hidden void @__destructor_8_S_S_s0(i8** %[[DST:.*]]) +// CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8 +// CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8 +// CHECK: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8 +// CHECK: call void @__destructor_8_S_s0(i8** %[[V0]]) +// CHECK: ret void + +// CHECK: define linkonce_odr hidden void @__destructor_8_S_s0(i8** %[[DST:.*]]) +// CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8 +// CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8 +// CHECK: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8 +// CHECK: call void @__destructor_8_s0(i8** %[[V0]]) +// CHECK: ret void + +// CHECK: define linkonce_odr hidden void @__destructor_8_s0(i8** %dst) +// CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8 +// CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8 +// CHECK: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8 +// CHECK: call void @llvm.objc.storeStrong(i8** %[[V0]], i8* null) +// CHECK: ret void diff --git a/clang/test/CodeGenObjC/strong-in-c-struct.m b/clang/test/CodeGenObjC/strong-in-c-struct.m index 999b89d..17587f7 100644 --- a/clang/test/CodeGenObjC/strong-in-c-struct.m +++ b/clang/test/CodeGenObjC/strong-in-c-struct.m @@ -89,12 +89,12 @@ void func(Strong *); // CHECK: define void @test_constructor_destructor_StrongOuter() // CHECK: %[[T:.*]] = alloca %[[STRUCT_STRONGOUTER:.*]], align 8 // CHECK: %[[V0:.*]] = bitcast %[[STRUCT_STRONGOUTER]]* %[[T]] to i8** -// CHECK: call void @__default_constructor_8_s16_s24(i8** %[[V0]]) +// CHECK: call void @__default_constructor_8_S_s16_s24(i8** %[[V0]]) // CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGOUTER]]* %[[T]] to i8** -// CHECK: call void @__destructor_8_s16_s24(i8** %[[V1]]) +// CHECK: call void @__destructor_8_S_s16_s24(i8** %[[V1]]) // CHECK: ret void -// CHECK: define linkonce_odr hidden void @__default_constructor_8_s16_s24(i8** %[[DST:.*]]) +// CHECK: define linkonce_odr hidden void @__default_constructor_8_S_s16_s24(i8** %[[DST:.*]]) // CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8 // CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8 // CHECK: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8 @@ -117,7 +117,7 @@ void func(Strong *); // CHECK: call void @llvm.memset.p0i8.i64(i8* align 8 %[[V4]], i8 0, i64 8, i1 false) // CHECK: ret void -// CHECK: define linkonce_odr hidden void @__destructor_8_s16_s24(i8** %[[DST:.*]]) +// CHECK: define linkonce_odr hidden void @__destructor_8_S_s16_s24(i8** %[[DST:.*]]) // CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8 // CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8 // CHECK: %[[V0:.*]] = load i8**, i8*** %[[DST_ADDR]], align 8 @@ -149,12 +149,12 @@ void test_constructor_destructor_StrongOuter(void) { // CHECK: %[[V0:.*]] = load %[[STRUCT_STRONGOUTER]]*, %[[STRUCT_STRONGOUTER]]** %[[S_ADDR]], align 8 // CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGOUTER]]* %[[T]] to i8** // CHECK: %[[V2:.*]] = bitcast %[[STRUCT_STRONGOUTER]]* %[[V0]] to i8** -// CHECK: call void @__copy_constructor_8_8_t0w16_s16_s24_t32w8(i8** %[[V1]], i8** %[[V2]]) +// CHECK: call void @__copy_constructor_8_8_S_t0w16_s16_s24_t32w8(i8** %[[V1]], i8** %[[V2]]) // CHECK: %[[V3:.*]] = bitcast %[[STRUCT_STRONGOUTER]]* %[[T]] to i8** -// CHECK: call void @__destructor_8_s16_s24(i8** %[[V3]]) +// CHECK: call void @__destructor_8_S_s16_s24(i8** %[[V3]]) // CHECK: ret void -// CHECK: define linkonce_odr hidden void @__copy_constructor_8_8_t0w16_s16_s24_t32w8(i8** %[[DST:.*]], i8** %[[SRC:.*]]) +// CHECK: define linkonce_odr hidden void @__copy_constructor_8_8_S_t0w16_s16_s24_t32w8(i8** %[[DST:.*]], i8** %[[SRC:.*]]) // CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8 // CHECK: %[[SRC_ADDR:.*]] = alloca i8**, align 8 // CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8 @@ -208,7 +208,7 @@ void test_copy_constructor_StrongOuter(StrongOuter *s) { StrongOuter t = *s; } -/// CHECK: define linkonce_odr hidden void @__copy_assignment_8_8_t0w16_s16_s24_t32w8(i8** %[[DST:.*]], i8** %[[SRC:.*]]) +/// CHECK: define linkonce_odr hidden void @__copy_assignment_8_8_S_t0w16_s16_s24_t32w8(i8** %[[DST:.*]], i8** %[[SRC:.*]]) // CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8 // CHECK: %[[SRC_ADDR:.*]] = alloca i8**, align 8 // CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8 @@ -231,15 +231,15 @@ void test_copy_assignment_StrongOuter(StrongOuter *d, StrongOuter *s) { // CHECK: define void @test_move_constructor_StrongOuter() // CHECK: %[[T1:.*]] = getelementptr inbounds %[[STRUCT_BLOCK_BYREF_T:.*]], %[[STRUCT_BLOCK_BYREF_T]]* %{{.*}}, i32 0, i32 7 // CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGOUTER]]* %[[T1]] to i8** -// CHECK: call void @__default_constructor_8_s16_s24(i8** %[[V1]]) +// CHECK: call void @__default_constructor_8_S_s16_s24(i8** %[[V1]]) // CHECK: %[[T2:.*]] = getelementptr inbounds %[[STRUCT_BLOCK_BYREF_T]], %[[STRUCT_BLOCK_BYREF_T]]* %{{.*}}, i32 0, i32 7 // CHECK: %[[V9:.*]] = bitcast %[[STRUCT_STRONGOUTER]]* %[[T2]] to i8** -// CHECK: call void @__destructor_8_s16_s24(i8** %[[V9]]) +// CHECK: call void @__destructor_8_S_s16_s24(i8** %[[V9]]) // CHECK: define internal void @__Block_byref_object_copy_(i8*, i8*) -// CHECK: call void @__move_constructor_8_8_t0w16_s16_s24_t32w8( +// CHECK: call void @__move_constructor_8_8_S_t0w16_s16_s24_t32w8( -// CHECK: define linkonce_odr hidden void @__move_constructor_8_8_t0w16_s16_s24_t32w8(i8** %[[DST:.*]], i8** %[[SRC:.*]]) +// CHECK: define linkonce_odr hidden void @__move_constructor_8_8_S_t0w16_s16_s24_t32w8(i8** %[[DST:.*]], i8** %[[SRC:.*]]) // CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8 // CHECK: %[[SRC_ADDR:.*]] = alloca i8**, align 8 // CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8 @@ -258,14 +258,14 @@ void test_copy_assignment_StrongOuter(StrongOuter *d, StrongOuter *s) { // CHECK: store i8* %[[V8]], i8** %[[V4]], align 8 // CHECK: define internal void @__Block_byref_object_dispose_(i8*) -// CHECK: call void @__destructor_8_s16_s24( +// CHECK: call void @__destructor_8_S_s16_s24( void test_move_constructor_StrongOuter(void) { __block StrongOuter t; BlockTy b = ^{ (void)t; }; } -// CHECK: define linkonce_odr hidden void @__move_assignment_8_8_t0w16_s16_s24_t32w8(i8** %[[DST:.*]], i8** %[[SRC:.*]]) +// CHECK: define linkonce_odr hidden void @__move_assignment_8_8_S_t0w16_s16_s24_t32w8(i8** %[[DST:.*]], i8** %[[SRC:.*]]) // CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8 // CHECK: %[[SRC_ADDR:.*]] = alloca i8**, align 8 // CHECK: store i8** %[[DST]], i8*** %[[DST_ADDR]], align 8 @@ -480,14 +480,14 @@ void test_constructor_destructor_IDArray(void) { IDArray t; } -// CHECK: define linkonce_odr hidden void @__default_constructor_8_AB8s24n4_s24_AE( +// CHECK: define linkonce_odr hidden void @__default_constructor_8_AB8s24n4_S_s24_AE( void test_constructor_destructor_StructArray(void) { StructArray t; } // Test that StructArray's field 'd' is copied before entering the loop. -// CHECK: define linkonce_odr hidden void @__copy_constructor_8_8_t0w8_AB8s24n4_t8w16_s24_AE(i8** %[[DST:.*]], i8** %[[SRC:.*]]) +// CHECK: define linkonce_odr hidden void @__copy_constructor_8_8_t0w8_AB8s24n4_S_t8w16_s24_AE(i8** %[[DST:.*]], i8** %[[SRC:.*]]) // CHECK: entry: // CHECK: %[[DST_ADDR:.*]] = alloca i8**, align 8 // CHECK: %[[SRC_ADDR:.*]] = alloca i8**, align 8 -- 2.7.4