forked from OSchip/llvm-project
PR45087: Fix check for emptiness when determining whether a trivial copy
operation needs to read from its operand.
This commit is contained in:
parent
de2c586a12
commit
ad18665e37
|
|
@ -3047,15 +3047,22 @@ static void expandArray(APValue &Array, unsigned Index) {
|
||||||
/// is trivial. Note that this is never true for a union type with fields
|
/// is trivial. Note that this is never true for a union type with fields
|
||||||
/// (because the copy always "reads" the active member) and always true for
|
/// (because the copy always "reads" the active member) and always true for
|
||||||
/// a non-class type.
|
/// a non-class type.
|
||||||
|
static bool isReadByLvalueToRvalueConversion(const CXXRecordDecl *RD);
|
||||||
static bool isReadByLvalueToRvalueConversion(QualType T) {
|
static bool isReadByLvalueToRvalueConversion(QualType T) {
|
||||||
CXXRecordDecl *RD = T->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
|
CXXRecordDecl *RD = T->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
|
||||||
if (!RD || (RD->isUnion() && !RD->field_empty()))
|
return !RD || isReadByLvalueToRvalueConversion(RD);
|
||||||
return true;
|
}
|
||||||
|
static bool isReadByLvalueToRvalueConversion(const CXXRecordDecl *RD) {
|
||||||
|
// FIXME: A trivial copy of a union copies the object representation, even if
|
||||||
|
// the union is empty.
|
||||||
|
if (RD->isUnion())
|
||||||
|
return !RD->field_empty();
|
||||||
if (RD->isEmpty())
|
if (RD->isEmpty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (auto *Field : RD->fields())
|
for (auto *Field : RD->fields())
|
||||||
if (isReadByLvalueToRvalueConversion(Field->getType()))
|
if (!Field->isUnnamedBitfield() &&
|
||||||
|
isReadByLvalueToRvalueConversion(Field->getType()))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
for (auto &BaseSpec : RD->bases())
|
for (auto &BaseSpec : RD->bases())
|
||||||
|
|
@ -5460,22 +5467,6 @@ static bool HandleUnionActiveMemberChange(EvalInfo &Info, const Expr *LHSExpr,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determine if a class has any fields that might need to be copied by a
|
|
||||||
/// trivial copy or move operation.
|
|
||||||
static bool hasFields(const CXXRecordDecl *RD) {
|
|
||||||
if (!RD || RD->isEmpty())
|
|
||||||
return false;
|
|
||||||
for (auto *FD : RD->fields()) {
|
|
||||||
if (FD->isUnnamedBitfield())
|
|
||||||
continue;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
for (auto &Base : RD->bases())
|
|
||||||
if (hasFields(Base.getType()->getAsCXXRecordDecl()))
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
typedef SmallVector<APValue, 8> ArgVector;
|
typedef SmallVector<APValue, 8> ArgVector;
|
||||||
}
|
}
|
||||||
|
|
@ -5546,7 +5537,8 @@ static bool HandleFunctionCall(SourceLocation CallLoc,
|
||||||
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee);
|
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee);
|
||||||
if (MD && MD->isDefaulted() &&
|
if (MD && MD->isDefaulted() &&
|
||||||
(MD->getParent()->isUnion() ||
|
(MD->getParent()->isUnion() ||
|
||||||
(MD->isTrivial() && hasFields(MD->getParent())))) {
|
(MD->isTrivial() &&
|
||||||
|
isReadByLvalueToRvalueConversion(MD->getParent())))) {
|
||||||
assert(This &&
|
assert(This &&
|
||||||
(MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()));
|
(MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()));
|
||||||
LValue RHS;
|
LValue RHS;
|
||||||
|
|
@ -5633,7 +5625,8 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
|
||||||
// actually read them.
|
// actually read them.
|
||||||
if (Definition->isDefaulted() && Definition->isCopyOrMoveConstructor() &&
|
if (Definition->isDefaulted() && Definition->isCopyOrMoveConstructor() &&
|
||||||
(Definition->getParent()->isUnion() ||
|
(Definition->getParent()->isUnion() ||
|
||||||
(Definition->isTrivial() && hasFields(Definition->getParent())))) {
|
(Definition->isTrivial() &&
|
||||||
|
isReadByLvalueToRvalueConversion(Definition->getParent())))) {
|
||||||
LValue RHS;
|
LValue RHS;
|
||||||
RHS.setFrom(Info.Ctx, ArgValues[0]);
|
RHS.setFrom(Info.Ctx, ArgValues[0]);
|
||||||
return handleLValueToRValueConversion(
|
return handleLValueToRValueConversion(
|
||||||
|
|
|
||||||
|
|
@ -600,6 +600,10 @@ namespace CopyCtor {
|
||||||
constexpr B c = b;
|
constexpr B c = b;
|
||||||
static_assert(c.arr[2] == 3, "");
|
static_assert(c.arr[2] == 3, "");
|
||||||
static_assert(c.arr[7] == 0, "");
|
static_assert(c.arr[7] == 0, "");
|
||||||
|
|
||||||
|
// OK: the copy ctor for X doesn't read any members.
|
||||||
|
struct X { struct Y {} y; } x1;
|
||||||
|
constexpr X x2 = x1;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr int selfref[2][2][2] = {
|
constexpr int selfref[2][2][2] = {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue