diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-01-25 22:15:11 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-01-25 22:15:11 +0000 |
commit | d9b02e726262e4009dda830998bb934172ac0020 (patch) | |
tree | f6e7db1e062ff51a19157e5546dddb6b1c452572 /lib/AST/ExprConstant.cpp | |
parent | 51cb75a62511905ffa6dc9712493c50a8f3ebcd2 (diff) |
constexpr: add support for anonymous struct and union members in literal types.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@148987 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/AST/ExprConstant.cpp')
-rw-r--r-- | lib/AST/ExprConstant.cpp | 79 |
1 files changed, 61 insertions, 18 deletions
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index bdedb1608e..1c0d9eae69 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -1188,6 +1188,15 @@ static void HandleLValueMember(EvalInfo &Info, const Expr *E, LValue &LVal, LVal.addDecl(Info, E, FD); } +/// Update LVal to refer to the given indirect field. +static void HandleLValueIndirectMember(EvalInfo &Info, const Expr *E, + LValue &LVal, + const IndirectFieldDecl *IFD) { + for (IndirectFieldDecl::chain_iterator C = IFD->chain_begin(), + CE = IFD->chain_end(); C != CE; ++C) + HandleLValueMember(Info, E, LVal, cast<FieldDecl>(*C)); +} + /// Get the size of the given type in char units. static bool HandleSizeof(EvalInfo &Info, QualType Type, CharUnits &Size) { // sizeof(void), __alignof__(void), sizeof(function) = 1 as a gcc @@ -1654,10 +1663,13 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info, // Add the member. Note that we cannot build bound member functions here. if (IncludeMember) { - // FIXME: Deal with IndirectFieldDecls. - const FieldDecl *FD = dyn_cast<FieldDecl>(MemPtr.getDecl()); - if (!FD) return 0; - HandleLValueMember(Info, BO, LV, FD); + if (const FieldDecl *FD = dyn_cast<FieldDecl>(MemPtr.getDecl())) + HandleLValueMember(Info, BO, LV, FD); + else if (const IndirectFieldDecl *IFD = + dyn_cast<IndirectFieldDecl>(MemPtr.getDecl())) + HandleLValueIndirectMember(Info, BO, LV, IFD); + else + llvm_unreachable("can't construct reference to bound member function"); } return MemPtr.getDecl(); @@ -1904,11 +1916,40 @@ static bool HandleConstructorCall(const Expr *CallExpr, const LValue &This, Result.getStructField(FD->getFieldIndex()), Info, Subobject, (*I)->getInit(), CCEK_MemberInit)) return false; + } else if (IndirectFieldDecl *IFD = (*I)->getIndirectMember()) { + LValue Subobject = This; + APValue *Value = &Result; + // Walk the indirect field decl's chain to find the object to initialize, + // and make sure we've initialized every step along it. + for (IndirectFieldDecl::chain_iterator C = IFD->chain_begin(), + CE = IFD->chain_end(); + C != CE; ++C) { + FieldDecl *FD = cast<FieldDecl>(*C); + CXXRecordDecl *CD = cast<CXXRecordDecl>(FD->getParent()); + // Switch the union field if it differs. This happens if we had + // preceding zero-initialization, and we're now initializing a union + // subobject other than the first. + // FIXME: In this case, the values of the other subobjects are + // specified, since zero-initialization sets all padding bits to zero. + if (Value->isUninit() || + (Value->isUnion() && Value->getUnionField() != FD)) { + if (CD->isUnion()) + *Value = APValue(FD); + else + *Value = APValue(APValue::UninitStruct(), CD->getNumBases(), + std::distance(CD->field_begin(), CD->field_end())); + } + if (CD->isUnion()) + Value = &Value->getUnionValue(); + else + Value = &Value->getStructField(FD->getFieldIndex()); + HandleLValueMember(Info, (*I)->getInit(), Subobject, FD); + } + if (!EvaluateConstantExpression(*Value, Info, Subobject, (*I)->getInit(), + CCEK_MemberInit)) + return false; } else { - // FIXME: handle indirect field initializers - Info.Diag((*I)->getInit()->getExprLoc(), - diag::note_invalid_subexpr_in_const_expr); - return false; + llvm_unreachable("unknown base initializer kind"); } } @@ -2349,18 +2390,20 @@ public: BaseTy = E->getBase()->getType(); } - const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl()); - // FIXME: Handle IndirectFieldDecls - if (!FD) return this->Error(E); - assert(BaseTy->getAs<RecordType>()->getDecl()->getCanonicalDecl() == - FD->getParent()->getCanonicalDecl() && "record / field mismatch"); - (void)BaseTy; - - HandleLValueMember(this->Info, E, Result, FD); + const ValueDecl *MD = E->getMemberDecl(); + if (const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl())) { + assert(BaseTy->getAs<RecordType>()->getDecl()->getCanonicalDecl() == + FD->getParent()->getCanonicalDecl() && "record / field mismatch"); + (void)BaseTy; + HandleLValueMember(this->Info, E, Result, FD); + } else if (const IndirectFieldDecl *IFD = dyn_cast<IndirectFieldDecl>(MD)) { + HandleLValueIndirectMember(this->Info, E, Result, IFD); + } else + return this->Error(E); - if (FD->getType()->isReferenceType()) { + if (MD->getType()->isReferenceType()) { CCValue RefValue; - if (!HandleLValueToRValueConversion(this->Info, E, FD->getType(), Result, + if (!HandleLValueToRValueConversion(this->Info, E, MD->getType(), Result, RefValue)) return false; return Success(RefValue, E); |