summaryrefslogtreecommitdiffstats
path: root/clang/lib/AST/ExprConstant.cpp
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2014-11-19 21:27:17 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2014-11-19 21:27:17 +0000
commitbe6dd818fbf1305c895038904396d20761d3f98c (patch)
tree942524d82ae6505ce58f494d10b0bb2fe87f69e2 /clang/lib/AST/ExprConstant.cpp
parent06839a536f39170f2ff6793ccbfa6ebb3468efe5 (diff)
downloadbcm5719-llvm-be6dd818fbf1305c895038904396d20761d3f98c.tar.gz
bcm5719-llvm-be6dd818fbf1305c895038904396d20761d3f98c.zip
Fix bug where a trivial constexpr copy/move operation couldn't copy from an
empty non-constexpr object. Such a copy doesn't break any of the constexpr rules. llvm-svn: 222387
Diffstat (limited to 'clang/lib/AST/ExprConstant.cpp')
-rw-r--r--clang/lib/AST/ExprConstant.cpp35
1 files changed, 31 insertions, 4 deletions
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index ea28d74ddc7..9a2c5527955 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -3657,6 +3657,22 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
return false;
}
+/// 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 {
typedef SmallVector<APValue, 8> ArgVector;
}
@@ -3695,8 +3711,12 @@ static bool HandleFunctionCall(SourceLocation CallLoc,
// For a trivial copy or move assignment, perform an APValue copy. This is
// essential for unions, where the operations performed by the assignment
// operator cannot be represented as statements.
+ //
+ // Skip this for non-union classes with no fields; in that case, the defaulted
+ // copy/move does not actually read the object.
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee);
- if (MD && MD->isDefaulted() && MD->isTrivial()) {
+ if (MD && MD->isDefaulted() && MD->isTrivial() &&
+ (MD->getParent()->isUnion() || hasFields(MD->getParent()))) {
assert(This &&
(MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()));
LValue RHS;
@@ -3753,11 +3773,18 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
}
// 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.
+ // essential for unions (or classes with anonymous union members), where the
+ // operations performed by the constructor cannot be represented by
+ // ctor-initializers.
+ //
+ // Skip this for empty non-union classes; we should not perform an
+ // lvalue-to-rvalue conversion on them because their copy constructor does not
+ // actually read them.
if (Definition->isDefaulted() &&
((Definition->isCopyConstructor() && Definition->isTrivial()) ||
- (Definition->isMoveConstructor() && Definition->isTrivial()))) {
+ (Definition->isMoveConstructor() && Definition->isTrivial())) &&
+ (Definition->getParent()->isUnion() ||
+ hasFields(Definition->getParent()))) {
LValue RHS;
RHS.setFrom(Info.Ctx, ArgValues[0]);
return handleLValueToRValueConversion(Info, Args[0], Args[0]->getType(),
OpenPOWER on IntegriCloud