diff options
-rw-r--r-- | lib/AST/ExprConstant.cpp | 18 | ||||
-rw-r--r-- | test/SemaCXX/constant-expression-cxx11.cpp | 6 |
2 files changed, 22 insertions, 2 deletions
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 1ad17ea376..5fd710d90e 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -1854,8 +1854,22 @@ static bool HandleConstructorCall(const Expr *CallExpr, const LValue &This, 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())); @@ -3073,7 +3087,7 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { 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))) diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp index d865010920..ff9889276d 100644 --- a/test/SemaCXX/constant-expression-cxx11.cpp +++ b/test/SemaCXX/constant-expression-cxx11.cpp @@ -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]) + 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 { |