aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2012-01-25 22:15:11 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2012-01-25 22:15:11 +0000
commitd9b02e726262e4009dda830998bb934172ac0020 (patch)
treef6e7db1e062ff51a19157e5546dddb6b1c452572
parent51cb75a62511905ffa6dc9712493c50a8f3ebcd2 (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.cpp79
-rw-r--r--test/SemaCXX/constant-expression-cxx11.cpp40
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, "");
+}