Skip to content

Commit 47954e1

Browse files
Michael137yuxuanchen1997
authored andcommitted
[clang][CGRecordLayout] Remove dependency on isZeroSize (#96422)
Summary: This is a follow-up from the conversation starting at #93809 (comment) The root problem that motivated the change are external AST sources that compute `ASTRecordLayout`s themselves instead of letting Clang compute them from the AST. One such example is LLDB using DWARF to get the definitive offsets and sizes of C++ structures. Such layouts should be considered correct (modulo buggy DWARF), but various assertions and lowering logic around the `CGRecordLayoutBuilder` relies on the AST having `[[no_unique_address]]` attached to them. This is a layout-altering attribute which is not encoded in DWARF. This causes us LLDB to trip over the various LLVM<->Clang layout consistency checks. There has been precedent for avoiding such layout-altering attributes from affecting lowering with externally-provided layouts (e.g., packed structs). This patch proposes to replace the `isZeroSize` checks in `CGRecordLayoutBuilder` (which roughly means "empty field with [[no_unique_address]]") with checks for `CodeGen::isEmptyField`/`CodeGen::isEmptyRecord`. **Details** The main strategy here was to change the `isZeroSize` check in `CGRecordLowering::accumulateFields` and `CGRecordLowering::accumulateBases` to use the `isEmptyXXX` APIs instead, preventing empty fields from being added to the `Members` and `Bases` structures. The rest of the changes fall out from here, to prevent lookups into these structures (for field numbers or base indices) from failing. Added `isEmptyRecordForLayout` and `isEmptyFieldForLayout` (open to better naming suggestions). The main difference to the existing `isEmptyRecord`/`isEmptyField` APIs, is that the `isEmptyXXXForLayout` counterparts don't have special treatment for `unnamed bitfields`/arrays and also treat fields of empty types as if they had `[[no_unique_address]]` (i.e., just like the `AsIfNoUniqueAddr` in `isEmptyField` does). Test Plan: Reviewers: Subscribers: Tasks: Tags: Differential Revision: https://phabricator.intern.facebook.com/D60251747
1 parent b3862c3 commit 47954e1

28 files changed

+242
-109
lines changed

clang/lib/CodeGen/ABIInfoImpl.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,41 @@ bool CodeGen::isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays,
310310
return true;
311311
}
312312

313+
bool CodeGen::isEmptyFieldForLayout(const ASTContext &Context,
314+
const FieldDecl *FD) {
315+
if (FD->isZeroLengthBitField(Context))
316+
return true;
317+
318+
if (FD->isUnnamedBitField())
319+
return false;
320+
321+
return isEmptyRecordForLayout(Context, FD->getType());
322+
}
323+
324+
bool CodeGen::isEmptyRecordForLayout(const ASTContext &Context, QualType T) {
325+
const RecordType *RT = T->getAs<RecordType>();
326+
if (!RT)
327+
return false;
328+
329+
const RecordDecl *RD = RT->getDecl();
330+
331+
// If this is a C++ record, check the bases first.
332+
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
333+
if (CXXRD->isDynamicClass())
334+
return false;
335+
336+
for (const auto &I : CXXRD->bases())
337+
if (!isEmptyRecordForLayout(Context, I.getType()))
338+
return false;
339+
}
340+
341+
for (const auto *I : RD->fields())
342+
if (!isEmptyFieldForLayout(Context, I))
343+
return false;
344+
345+
return true;
346+
}
347+
313348
const Type *CodeGen::isSingleElementStruct(QualType T, ASTContext &Context) {
314349
const RecordType *RT = T->getAs<RecordType>();
315350
if (!RT)

clang/lib/CodeGen/ABIInfoImpl.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,16 @@ bool isEmptyField(ASTContext &Context, const FieldDecl *FD, bool AllowArrays,
137137
bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays,
138138
bool AsIfNoUniqueAddr = false);
139139

140+
/// isEmptyFieldForLayout - Return true iff the field is "empty", that is,
141+
/// either a zero-width bit-field or an \ref isEmptyRecordForLayout.
142+
bool isEmptyFieldForLayout(const ASTContext &Context, const FieldDecl *FD);
143+
144+
/// isEmptyRecordForLayout - Return true iff a structure contains only empty
145+
/// base classes (per \ref isEmptyRecordForLayout) and fields (per
146+
/// \ref isEmptyFieldForLayout). Note, C++ record fields are considered empty
147+
/// if the [[no_unique_address]] attribute would have made them empty.
148+
bool isEmptyRecordForLayout(const ASTContext &Context, QualType T);
149+
140150
/// isSingleElementStruct - Determine if a structure is a "single
141151
/// element struct", i.e. it has exactly one non-empty field or
142152
/// exactly one field which is itself a single element

clang/lib/CodeGen/CGClass.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
#include "ABIInfoImpl.h"
1314
#include "CGBlocks.h"
1415
#include "CGCXXABI.h"
1516
#include "CGDebugInfo.h"
@@ -933,7 +934,7 @@ namespace {
933934
}
934935

935936
void addMemcpyableField(FieldDecl *F) {
936-
if (F->isZeroSize(CGF.getContext()))
937+
if (isEmptyFieldForLayout(CGF.getContext(), F))
937938
return;
938939
if (!FirstField)
939940
addInitialField(F);
@@ -1815,7 +1816,7 @@ namespace {
18151816
const CXXDestructorDecl *DD)
18161817
: Context(Context), EHStack(EHStack), DD(DD), StartIndex(std::nullopt) {}
18171818
void PushCleanupForField(const FieldDecl *Field) {
1818-
if (Field->isZeroSize(Context))
1819+
if (isEmptyFieldForLayout(Context, Field))
18191820
return;
18201821
unsigned FieldIndex = Field->getFieldIndex();
18211822
if (FieldHasTrivialDestructorBody(Context, Field)) {

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
#include "ABIInfoImpl.h"
1314
#include "CGCUDARuntime.h"
1415
#include "CGCXXABI.h"
1516
#include "CGCall.h"
@@ -4757,7 +4758,7 @@ static Address emitAddrOfZeroSizeField(CodeGenFunction &CGF, Address Base,
47574758
/// The resulting address doesn't necessarily have the right type.
47584759
static Address emitAddrOfFieldStorage(CodeGenFunction &CGF, Address base,
47594760
const FieldDecl *field) {
4760-
if (field->isZeroSize(CGF.getContext()))
4761+
if (isEmptyFieldForLayout(CGF.getContext(), field))
47614762
return emitAddrOfZeroSizeField(CGF, base, field);
47624763

47634764
const RecordDecl *rec = field->getParent();

clang/lib/CodeGen/CGExprConstant.cpp

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
#include "ABIInfoImpl.h"
1314
#include "CGCXXABI.h"
1415
#include "CGObjCRuntime.h"
1516
#include "CGRecordLayout.h"
@@ -736,7 +737,7 @@ bool ConstStructBuilder::Build(const InitListExpr *ILE, bool AllowOverwrite) {
736737

737738
// Zero-sized fields are not emitted, but their initializers may still
738739
// prevent emission of this struct as a constant.
739-
if (Field->isZeroSize(CGM.getContext())) {
740+
if (isEmptyFieldForLayout(CGM.getContext(), Field)) {
740741
if (Init->HasSideEffects(CGM.getContext()))
741742
return false;
742743
continue;
@@ -858,7 +859,8 @@ bool ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD,
858859
continue;
859860

860861
// Don't emit anonymous bitfields or zero-sized fields.
861-
if (Field->isUnnamedBitField() || Field->isZeroSize(CGM.getContext()))
862+
if (Field->isUnnamedBitField() ||
863+
isEmptyFieldForLayout(CGM.getContext(), *Field))
862864
continue;
863865

864866
// Emit the value of the initializer.
@@ -2526,8 +2528,10 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM,
25262528
cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
25272529

25282530
// Ignore empty bases.
2529-
if (base->isEmpty() ||
2530-
CGM.getContext().getASTRecordLayout(base).getNonVirtualSize()
2531+
if (isEmptyRecordForLayout(CGM.getContext(), I.getType()) ||
2532+
CGM.getContext()
2533+
.getASTRecordLayout(base)
2534+
.getNonVirtualSize()
25312535
.isZero())
25322536
continue;
25332537

@@ -2541,7 +2545,8 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM,
25412545
for (const auto *Field : record->fields()) {
25422546
// Fill in non-bitfields. (Bitfields always use a zero pattern, which we
25432547
// will fill in later.)
2544-
if (!Field->isBitField() && !Field->isZeroSize(CGM.getContext())) {
2548+
if (!Field->isBitField() &&
2549+
!isEmptyFieldForLayout(CGM.getContext(), Field)) {
25452550
unsigned fieldIndex = layout.getLLVMFieldNo(Field);
25462551
elements[fieldIndex] = CGM.EmitNullConstant(Field->getType());
25472552
}
@@ -2563,7 +2568,7 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM,
25632568
cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
25642569

25652570
// Ignore empty bases.
2566-
if (base->isEmpty())
2571+
if (isEmptyRecordForLayout(CGM.getContext(), I.getType()))
25672572
continue;
25682573

25692574
unsigned fieldIndex = layout.getVirtualBaseIndex(base);

clang/lib/CodeGen/CGOpenMPRuntime.cpp

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "CGOpenMPRuntime.h"
14+
#include "ABIInfoImpl.h"
1415
#include "CGCXXABI.h"
1516
#include "CGCleanup.h"
1617
#include "CGRecordLayout.h"
@@ -7729,23 +7730,28 @@ class MappableExprsHandler {
77297730
for (const auto &I : RD->bases()) {
77307731
if (I.isVirtual())
77317732
continue;
7732-
const auto *Base = I.getType()->getAsCXXRecordDecl();
7733+
7734+
QualType BaseTy = I.getType();
7735+
const auto *Base = BaseTy->getAsCXXRecordDecl();
77337736
// Ignore empty bases.
7734-
if (Base->isEmpty() || CGF.getContext()
7735-
.getASTRecordLayout(Base)
7736-
.getNonVirtualSize()
7737-
.isZero())
7737+
if (isEmptyRecordForLayout(CGF.getContext(), BaseTy) ||
7738+
CGF.getContext()
7739+
.getASTRecordLayout(Base)
7740+
.getNonVirtualSize()
7741+
.isZero())
77387742
continue;
77397743

77407744
unsigned FieldIndex = RL.getNonVirtualBaseLLVMFieldNo(Base);
77417745
RecordLayout[FieldIndex] = Base;
77427746
}
77437747
// Fill in virtual bases.
77447748
for (const auto &I : RD->vbases()) {
7745-
const auto *Base = I.getType()->getAsCXXRecordDecl();
7749+
QualType BaseTy = I.getType();
77467750
// Ignore empty bases.
7747-
if (Base->isEmpty())
7751+
if (isEmptyRecordForLayout(CGF.getContext(), BaseTy))
77487752
continue;
7753+
7754+
const auto *Base = BaseTy->getAsCXXRecordDecl();
77497755
unsigned FieldIndex = RL.getVirtualBaseIndex(Base);
77507756
if (RecordLayout[FieldIndex])
77517757
continue;
@@ -7756,7 +7762,8 @@ class MappableExprsHandler {
77567762
for (const auto *Field : RD->fields()) {
77577763
// Fill in non-bitfields. (Bitfields always use a zero pattern, which we
77587764
// will fill in later.)
7759-
if (!Field->isBitField() && !Field->isZeroSize(CGF.getContext())) {
7765+
if (!Field->isBitField() &&
7766+
!isEmptyFieldForLayout(CGF.getContext(), Field)) {
77607767
unsigned FieldIndex = RL.getLLVMFieldNo(Field);
77617768
RecordLayout[FieldIndex] = Field;
77627769
}

clang/lib/CodeGen/CGRecordLayoutBuilder.cpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
#include "CGRecordLayout.h"
13+
#include "ABIInfoImpl.h"
1414
#include "CGCXXABI.h"
15+
#include "CGRecordLayout.h"
1516
#include "CodeGenTypes.h"
1617
#include "clang/AST/ASTContext.h"
1718
#include "clang/AST/Attr.h"
@@ -384,7 +385,7 @@ void CGRecordLowering::accumulateFields(bool isNonVirtualBaseType) {
384385
Field = accumulateBitFields(isNonVirtualBaseType, Field, FieldEnd);
385386
assert((Field == FieldEnd || !Field->isBitField()) &&
386387
"Failed to accumulate all the bitfields");
387-
} else if (Field->isZeroSize(Context)) {
388+
} else if (isEmptyFieldForLayout(Context, *Field)) {
388389
// Empty fields have no storage.
389390
++Field;
390391
} else {
@@ -633,7 +634,7 @@ CGRecordLowering::accumulateBitFields(bool isNonVirtualBaseType,
633634
// non-reusable tail padding.
634635
CharUnits LimitOffset;
635636
for (auto Probe = Field; Probe != FieldEnd; ++Probe)
636-
if (!Probe->isZeroSize(Context)) {
637+
if (!isEmptyFieldForLayout(Context, *Probe)) {
637638
// A member with storage sets the limit.
638639
assert((getFieldBitOffset(*Probe) % CharBits) == 0 &&
639640
"Next storage is not byte-aligned");
@@ -731,7 +732,7 @@ void CGRecordLowering::accumulateBases() {
731732
// Bases can be zero-sized even if not technically empty if they
732733
// contain only a trailing array member.
733734
const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
734-
if (!BaseDecl->isEmpty() &&
735+
if (!isEmptyRecordForLayout(Context, Base.getType()) &&
735736
!Context.getASTRecordLayout(BaseDecl).getNonVirtualSize().isZero())
736737
Members.push_back(MemberInfo(Layout.getBaseClassOffset(BaseDecl),
737738
MemberInfo::Base, getStorageType(BaseDecl), BaseDecl));
@@ -879,7 +880,7 @@ CGRecordLowering::calculateTailClippingOffset(bool isNonVirtualBaseType) const {
879880
if (!isNonVirtualBaseType && isOverlappingVBaseABI())
880881
for (const auto &Base : RD->vbases()) {
881882
const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
882-
if (BaseDecl->isEmpty())
883+
if (isEmptyRecordForLayout(Context, Base.getType()))
883884
continue;
884885
// If the vbase is a primary virtual base of some base, then it doesn't
885886
// get its own storage location but instead lives inside of that base.
@@ -895,7 +896,7 @@ CGRecordLowering::calculateTailClippingOffset(bool isNonVirtualBaseType) const {
895896
void CGRecordLowering::accumulateVBases() {
896897
for (const auto &Base : RD->vbases()) {
897898
const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
898-
if (BaseDecl->isEmpty())
899+
if (isEmptyRecordForLayout(Context, Base.getType()))
899900
continue;
900901
CharUnits Offset = Layout.getVBaseClassOffset(BaseDecl);
901902
// If the vbase is a primary virtual base of some base, then it doesn't
@@ -1161,7 +1162,7 @@ CodeGenTypes::ComputeRecordLayout(const RecordDecl *D, llvm::StructType *Ty) {
11611162
const FieldDecl *FD = *it;
11621163

11631164
// Ignore zero-sized fields.
1164-
if (FD->isZeroSize(getContext()))
1165+
if (isEmptyFieldForLayout(getContext(), FD))
11651166
continue;
11661167

11671168
// For non-bit-fields, just check that the LLVM struct offset matches the

clang/lib/CodeGen/CodeGenTBAA.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
//===----------------------------------------------------------------------===//
1616

1717
#include "CodeGenTBAA.h"
18+
#include "ABIInfoImpl.h"
1819
#include "CGRecordLayout.h"
1920
#include "CodeGenTypes.h"
2021
#include "clang/AST/ASTContext.h"
@@ -309,7 +310,7 @@ CodeGenTBAA::CollectFields(uint64_t BaseOffset,
309310
unsigned idx = 0;
310311
for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
311312
i != e; ++i, ++idx) {
312-
if ((*i)->isZeroSize(Context))
313+
if (isEmptyFieldForLayout(Context, *i))
313314
continue;
314315

315316
uint64_t Offset =
Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,19 @@
1-
// RUN: %clang_cc1 -emit-llvm < %s | grep "zeroinitializer, i16 16877"
1+
// RUN: %clang_cc1 %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s --check-prefixes=CHECK,EMPTY
2+
// RUN: %clang_cc1 %s -emit-llvm -triple x86_64-windows-msvc -o - | FileCheck %s --check-prefixes=CHECK,EMPTY-MSVC
23
// PR4390
34
struct sysfs_dirent {
4-
union { struct sysfs_elem_dir {} s_dir; };
5+
union { struct sysfs_elem_dir { int x; } s_dir; };
56
unsigned short s_mode;
67
};
78
struct sysfs_dirent sysfs_root = { {}, 16877 };
9+
10+
// CHECK: @sysfs_root = {{.*}}global %struct.sysfs_dirent { %union.anon zeroinitializer, i16 16877 }
11+
12+
struct Foo {
13+
union { struct empty {} x; };
14+
unsigned short s_mode;
15+
};
16+
struct Foo foo = { {}, 16877 };
17+
18+
// EMPTY: @foo = {{.*}}global %struct.Foo { i16 16877 }
19+
// EMPTY-MSVC: @foo = {{.*}}global %struct.Foo { [4 x i8] undef, i16 16877 }

clang/test/CodeGen/X86/x86_64-vaarg.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ typedef struct {
5656
// CHECK: vaarg.end:
5757
// CHECK-NEXT: [[VAARG_ADDR:%.*]] = phi ptr [ [[TMP1]], [[VAARG_IN_REG]] ], [ [[OVERFLOW_ARG_AREA]], [[VAARG_IN_MEM]] ]
5858
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[RETVAL]], ptr align 8 [[VAARG_ADDR]], i64 8, i1 false)
59-
// CHECK-NEXT: [[TMP3:%.*]] = load double, ptr [[RETVAL]], align 8
59+
// CHECK-NEXT: [[COERCE:%.*]] = getelementptr inbounds [[STRUCT_S1]], ptr [[RETVAL]], i32 0, i32 0
60+
// CHECK-NEXT: [[TMP3:%.*]] = load double, ptr [[COERCE]], align 8
6061
// CHECK-NEXT: ret double [[TMP3]]
6162
//
6263
s1 f(int z, ...) {

clang/test/CodeGen/paren-list-agg-init.cpp

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,13 @@ struct E {
4848
~E() {};
4949
};
5050

51-
// CHECK-DAG: [[STRUCT_F:%.*]] = type { i8 }
5251
struct F {
5352
F (int i = 1);
5453
F (const F &f) = delete;
5554
F (F &&f) = default;
5655
};
5756

58-
// CHECK-DAG: [[STRUCT_G:%.*]] = type <{ i32, [[STRUCT_F]], [3 x i8] }>
57+
// CHECK-DAG: [[STRUCT_G:%.*]] = type <{ i32, [4 x i8] }>
5958
struct G {
6059
int a;
6160
F f;
@@ -78,12 +77,12 @@ namespace gh61145 {
7877
~Vec();
7978
};
8079

81-
// CHECK-DAG: [[STRUCT_S1:%.*]] = type { [[STRUCT_VEC]] }
80+
// CHECK-DAG: [[STRUCT_S1:%.*]] = type { i8 }
8281
struct S1 {
8382
Vec v;
8483
};
8584

86-
// CHECK-DAG: [[STRUCT_S2:%.*]] = type { [[STRUCT_VEC]], i8 }
85+
// CHECK-DAG: [[STRUCT_S2:%.*]] = type { i8, i8 }
8786
struct S2 {
8887
Vec v;
8988
char c;
@@ -377,7 +376,7 @@ void foo18() {
377376
// CHECK-NEXT: [[G:%.*g.*]] = alloca [[STRUCT_G]], align 4
378377
// CHECK-NEXT: [[A:%.*a.*]] = getelementptr inbounds [[STRUCT_G]], ptr [[G]], i32 0, i32 0
379378
// CHECK-NEXT: store i32 2, ptr [[A]], align 4
380-
// CHECK-NEXT: [[F:%.*f.*]] = getelementptr inbounds [[STRUCT_G]], ptr [[G]], i32 0, i32 1
379+
// CHECK-NEXT: [[F:%.*]] = getelementptr inbounds i8, ptr [[G]], i64 4
381380
// CHECk-NEXT: call void @{{.*F.*}}(ptr noundef nonnull align 1 dereferenceable(1)) [[F]], ie32 noundef 1)
382381
// CHECK: ret void
383382
void foo19() {
@@ -392,9 +391,8 @@ namespace gh61145 {
392391
// CHECK-NEXT: [[AGG_TMP_ENSURED:%.*agg.tmp.ensured.*]] = alloca [[STRUCT_S1]], align 1
393392
// a.k.a. Vec::Vec()
394393
// CHECK-NEXT: call void @_ZN7gh611453VecC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[V]])
395-
// CHECK-NEXT: [[V1:%.*v1.*]] = getelementptr inbounds [[STRUCT_S1]], ptr [[AGG_TMP_ENSURED]], i32 0, i32 0
396394
// a.k.a. Vec::Vec(Vec&&)
397-
// CHECK-NEXT: call void @_ZN7gh611453VecC1EOS0_(ptr noundef nonnull align 1 dereferenceable(1) [[V1]], ptr noundef nonnull align 1 dereferenceable(1) [[V]])
395+
// CHECK-NEXT: call void @_ZN7gh611453VecC1EOS0_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_TMP_ENSURED]], ptr noundef nonnull align 1 dereferenceable(1) [[V]])
398396
// a.k.a. S1::~S1()
399397
// CHECK-NEXT: call void @_ZN7gh611452S1D1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_TMP_ENSURED]])
400398
// a.k.a.Vec::~Vec()
@@ -413,9 +411,8 @@ namespace gh61145 {
413411
// CHECK-NEXT: [[AGG_TMP_ENSURED:%.*agg.tmp.ensured.*]] = alloca [[STRUCT_S2]], align 1
414412
// a.k.a. Vec::Vec()
415413
// CHECK-NEXT: call void @_ZN7gh611453VecC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[V]])
416-
// CHECK-NEXT: [[V1:%.*v1.*]] = getelementptr inbounds [[STRUCT_S2]], ptr [[AGG_TMP_ENSURED]], i32 0, i32 0
417414
// a.k.a. Vec::Vec(Vec&&)
418-
// CHECK-NEXT: call void @_ZN7gh611453VecC1EOS0_(ptr noundef nonnull align 1 dereferenceable(1) [[V1]], ptr noundef nonnull align 1 dereferenceable(1) [[V]])
415+
// CHECK-NEXT: call void @_ZN7gh611453VecC1EOS0_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_TMP_ENSURED]], ptr noundef nonnull align 1 dereferenceable(1) [[V]])
419416
// CHECK-NEXT: [[C:%.*c.*]] = getelementptr inbounds [[STRUCT_S2]], ptr [[AGG_TMP_ENSURED]], i32 0, i32
420417
// CHECK-NEXT: store i8 0, ptr [[C]], align 1
421418
// a.k.a. S2::~S2()

0 commit comments

Comments
 (0)