From: John McCall Date: Tue, 7 May 2013 05:20:46 +0000 (+0000) Subject: Weaken an assertion in memcpyization to account for X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=402cd22c598b39a272f2b31b52b19d4830954e1a;p=clang Weaken an assertion in memcpyization to account for unnamed bitfields. Unnamed bitfields won't have an explicit copy operation in the AST, which breaks the strong form of the invariant. rdar://13816940 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181289 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 3fd075701d..e4180a0d72 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -859,8 +859,12 @@ namespace { } void addNextField(FieldDecl *F) { - assert(F->getFieldIndex() == LastAddedFieldIndex + 1 && - "Cannot aggregate non-contiguous fields."); + // For the most part, the following invariant will hold: + // F->getFieldIndex() == LastAddedFieldIndex + 1 + // The one exception is that Sema won't add a copy-initializer for an + // unnamed bitfield, which will show up here as a gap in the sequence. + assert(F->getFieldIndex() >= LastAddedFieldIndex + 1 && + "Cannot aggregate fields out of order."); LastAddedFieldIndex = F->getFieldIndex(); // The 'first' and 'last' fields are chosen by offset, rather than field diff --git a/test/CodeGenCXX/copy-constructor-synthesis.cpp b/test/CodeGenCXX/copy-constructor-synthesis.cpp index 68f680574b..f6c3821951 100644 --- a/test/CodeGenCXX/copy-constructor-synthesis.cpp +++ b/test/CodeGenCXX/copy-constructor-synthesis.cpp @@ -136,6 +136,32 @@ void f(B b1) { B b2 = b1; } +// CHECK: define linkonce_odr [[A:%.*]]* @_ZN12rdar138169401AaSERKS0_( +// CHECK: [[THIS:%.*]] = load [[A]]** +// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[A]]* [[THIS]], i32 0, i32 1 +// CHECK-NEXT: [[T1:%.*]] = bitcast [2 x i8]* [[T0]] to i16* +// CHECK-NEXT: [[OTHER:%.*]] = load [[A]]** +// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[A]]* [[OTHER]], i32 0, i32 1 +// CHECK-NEXT: [[T3:%.*]] = bitcast [2 x i8]* [[T2]] to i16* +// CHECK-NEXT: [[T4:%.*]] = bitcast i16* [[T1]] to i8* +// CHECK-NEXT: [[T5:%.*]] = bitcast i16* [[T3]] to i8* +// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[T4]], i8* [[T5]], i64 8, i32 8, i1 false) +// CHECK-NEXT: ret [[A]]* [[THIS]] + +// CHECK: define linkonce_odr void @_ZN12rdar138169401AC2ERKS0_( +// CHECK: [[THIS:%.*]] = load [[A]]** +// CHECK-NEXT: [[T0:%.*]] = bitcast [[A]]* [[THIS]] to i8*** +// CHECK-NEXT: store i8** getelementptr inbounds ([4 x i8*]* @_ZTVN12rdar138169401AE, i64 0, i64 2), i8*** [[T0]] +// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[A]]* [[THIS]], i32 0, i32 1 +// CHECK-NEXT: [[T1:%.*]] = bitcast [2 x i8]* [[T0]] to i16* +// CHECK-NEXT: [[OTHER:%.*]] = load [[A]]** +// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[A]]* [[OTHER]], i32 0, i32 1 +// CHECK-NEXT: [[T3:%.*]] = bitcast [2 x i8]* [[T2]] to i16* +// CHECK-NEXT: [[T4:%.*]] = bitcast i16* [[T1]] to i8* +// CHECK-NEXT: [[T5:%.*]] = bitcast i16* [[T3]] to i8* +// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[T4]], i8* [[T5]], i64 8, i32 8, i1 false) +// CHECK-NEXT: ret void + // CHECK: define linkonce_odr void @_ZN6PR66281BC2ERKS0_(%"struct.PR6628::B"* %this, %"struct.PR6628::B"*) unnamed_addr // CHECK: call void @_ZN6PR66281TC1Ev // CHECK: call void @_ZN6PR66281TC1Ev @@ -154,3 +180,18 @@ void f(B b1) { // CHECK: call void @_ZN6PR66281TD1Ev } +// rdar://13816940 +// Test above because things get weirdly re-ordered. +namespace rdar13816940 { + struct A { + virtual ~A(); + unsigned short a : 1; + unsigned short : 15; + unsigned other; + }; + + void test(A &a) { + A x = a; // force copy constructor into existence + x = a; // also force the copy assignment operator + } +}