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 | |
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
-rw-r--r-- | lib/AST/ExprConstant.cpp | 79 | ||||
-rw-r--r-- | test/SemaCXX/constant-expression-cxx11.cpp | 40 |
2 files changed, 101 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); diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp index 21c2cb2b41..af66acda0a 100644 --- a/test/SemaCXX/constant-expression-cxx11.cpp +++ b/test/SemaCXX/constant-expression-cxx11.cpp @@ -1046,3 +1046,43 @@ namespace ConvertedConstantExpr { eq = reinterpret_cast<int>((int*)0) // expected-error {{not a constant expression}} expected-note {{reinterpret_cast}} }; } + +namespace IndirectField { + struct S { + struct { // expected-warning {{GNU extension}} + union { + struct { // expected-warning {{GNU extension}} + int a; + int b; + }; + int c; + }; + int d; + }; + union { + int e; + int f; + }; + constexpr S(int a, int b, int d, int e) : a(a), b(b), d(d), e(e) {} + constexpr S(int c, int d, int f) : c(c), d(d), f(f) {} + }; + + constexpr S s1(1, 2, 3, 4); + constexpr S s2(5, 6, 7); + + // FIXME: The diagnostics here do a very poor job of explaining which unnamed + // member is active and which is requested. + static_assert(s1.a == 1, ""); + static_assert(s1.b == 2, ""); + static_assert(s1.c == 0, ""); // expected-error {{constant expression}} expected-note {{union with active member}} + static_assert(s1.d == 3, ""); + static_assert(s1.e == 4, ""); + static_assert(s1.f == 0, ""); // expected-error {{constant expression}} expected-note {{union with active member}} + + static_assert(s2.a == 0, ""); // expected-error {{constant expression}} expected-note {{union with active member}} + static_assert(s2.b == 0, ""); // expected-error {{constant expression}} expected-note {{union with active member}} + static_assert(s2.c == 5, ""); + static_assert(s2.d == 6, ""); + static_assert(s2.e == 0, ""); // expected-error {{constant expression}} expected-note {{union with active member}} + static_assert(s2.f == 7, ""); +} |