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();
+ 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())
Result = APValue(APValue::UninitStruct(), RD->getNumBases(),
std::distance(RD->field_begin(), RD->field_end()));
if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition))
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 (const MaterializeTemporaryExpr *ME
= dyn_cast<MaterializeTemporaryExpr>(E->getArg(0)))
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, "");
+// 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 {