@@ -3047,15 +3047,22 @@ static void expandArray(APValue &Array, unsigned Index) {
3047
3047
/// is trivial. Note that this is never true for a union type with fields
3048
3048
/// (because the copy always "reads" the active member) and always true for
3049
3049
/// a non-class type.
3050
+ static bool isReadByLvalueToRvalueConversion(const CXXRecordDecl *RD);
3050
3051
static bool isReadByLvalueToRvalueConversion(QualType T) {
3051
3052
CXXRecordDecl *RD = T->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
3052
- if (!RD || (RD->isUnion() && !RD->field_empty()))
3053
- return true;
3053
+ return !RD || isReadByLvalueToRvalueConversion(RD);
3054
+ }
3055
+ static bool isReadByLvalueToRvalueConversion(const CXXRecordDecl *RD) {
3056
+ // FIXME: A trivial copy of a union copies the object representation, even if
3057
+ // the union is empty.
3058
+ if (RD->isUnion())
3059
+ return !RD->field_empty();
3054
3060
if (RD->isEmpty())
3055
3061
return false;
3056
3062
3057
3063
for (auto *Field : RD->fields())
3058
- if (isReadByLvalueToRvalueConversion(Field->getType()))
3064
+ if (!Field->isUnnamedBitfield() &&
3065
+ isReadByLvalueToRvalueConversion(Field->getType()))
3059
3066
return true;
3060
3067
3061
3068
for (auto &BaseSpec : RD->bases())
@@ -5460,22 +5467,6 @@ static bool HandleUnionActiveMemberChange(EvalInfo &Info, const Expr *LHSExpr,
5460
5467
return true;
5461
5468
}
5462
5469
5463
- /// Determine if a class has any fields that might need to be copied by a
5464
- /// trivial copy or move operation.
5465
- static bool hasFields(const CXXRecordDecl *RD) {
5466
- if (!RD || RD->isEmpty())
5467
- return false;
5468
- for (auto *FD : RD->fields()) {
5469
- if (FD->isUnnamedBitfield())
5470
- continue;
5471
- return true;
5472
- }
5473
- for (auto &Base : RD->bases())
5474
- if (hasFields(Base.getType()->getAsCXXRecordDecl()))
5475
- return true;
5476
- return false;
5477
- }
5478
-
5479
5470
namespace {
5480
5471
typedef SmallVector<APValue, 8> ArgVector;
5481
5472
}
@@ -5546,7 +5537,8 @@ static bool HandleFunctionCall(SourceLocation CallLoc,
5546
5537
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee);
5547
5538
if (MD && MD->isDefaulted() &&
5548
5539
(MD->getParent()->isUnion() ||
5549
- (MD->isTrivial() && hasFields(MD->getParent())))) {
5540
+ (MD->isTrivial() &&
5541
+ isReadByLvalueToRvalueConversion(MD->getParent())))) {
5550
5542
assert(This &&
5551
5543
(MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()));
5552
5544
LValue RHS;
@@ -5633,7 +5625,8 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
5633
5625
// actually read them.
5634
5626
if (Definition->isDefaulted() && Definition->isCopyOrMoveConstructor() &&
5635
5627
(Definition->getParent()->isUnion() ||
5636
- (Definition->isTrivial() && hasFields(Definition->getParent())))) {
5628
+ (Definition->isTrivial() &&
5629
+ isReadByLvalueToRvalueConversion(Definition->getParent())))) {
5637
5630
LValue RHS;
5638
5631
RHS.setFrom(Info.Ctx, ArgValues[0]);
5639
5632
return handleLValueToRValueConversion(
0 commit comments