PR11724: Implement evaluation for constexpr defaulted trivial union copy/move

constructors. These are a special case whose behavior cannot be modeled as a
user-written constructor.

llvm-svn: 147839
This commit is contained in:
Richard Smith 2012-01-10 04:32:03 +00:00
parent f714d3d7f2
commit 1bc5c2c7ef
2 changed files with 22 additions and 2 deletions

View File

@ -1854,8 +1854,22 @@ static bool HandleConstructorCall(const Expr *CallExpr, const LValue &This,
return EvaluateConstantExpression(Result, Info, This, (*I)->getInit()); return EvaluateConstantExpression(Result, Info, This, (*I)->getInit());
} }
// Reserve space for the struct members. // For a trivial copy or move constructor, perform an APValue copy. This is
// essential for unions, where the operations performed by the constructor
// cannot be represented by ctor-initializers.
const CXXRecordDecl *RD = Definition->getParent(); const CXXRecordDecl *RD = Definition->getParent();
if (Definition->isDefaulted() &&
((Definition->isCopyConstructor() && RD->hasTrivialCopyConstructor()) ||
(Definition->isMoveConstructor() && RD->hasTrivialMoveConstructor()))) {
LValue RHS;
RHS.setFrom(ArgValues[0]);
CCValue Value;
return HandleLValueToRValueConversion(Info, Args[0], Args[0]->getType(),
RHS, Value) &&
CheckConstantExpression(Info, CallExpr, Value, Result);
}
// Reserve space for the struct members.
if (!RD->isUnion() && Result.isUninit()) if (!RD->isUnion() && Result.isUninit())
Result = APValue(APValue::UninitStruct(), RD->getNumBases(), Result = APValue(APValue::UninitStruct(), RD->getNumBases(),
std::distance(RD->field_begin(), RD->field_end())); std::distance(RD->field_begin(), RD->field_end()));
@ -3073,7 +3087,7 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition)) if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition))
return false; return false;
// FIXME: Elide the copy/move construction wherever we can. // Avoid materializing a temporary for an elidable copy/move constructor.
if (E->isElidable() && !ZeroInit) if (E->isElidable() && !ZeroInit)
if (const MaterializeTemporaryExpr *ME if (const MaterializeTemporaryExpr *ME
= dyn_cast<MaterializeTemporaryExpr>(E->getArg(0))) = dyn_cast<MaterializeTemporaryExpr>(E->getArg(0)))

View File

@ -726,6 +726,12 @@ static_assert((&u[1].b)[1] == 2, ""); // expected-error {{constant expression}}
static_assert(*(&(u[1].b) + 1 + 1) == 3, ""); // expected-error {{constant expression}} expected-note {{cannot refer to element 2 of non-array object}} static_assert(*(&(u[1].b) + 1 + 1) == 3, ""); // expected-error {{constant expression}} expected-note {{cannot refer to element 2 of non-array object}}
static_assert((&(u[1]) + 1 + 1)->b == 3, ""); static_assert((&(u[1]) + 1 + 1)->b == 3, "");
// Make sure we handle trivial copy constructors for unions.
constexpr U x = {42};
constexpr U y = x;
static_assert(y.a == 42, "");
static_assert(y.b == 42, ""); // expected-error {{constant expression}} expected-note {{'b' of union with active member 'a'}}
} }
namespace MemberPointer { namespace MemberPointer {