Index: cfe/trunk/lib/AST/ExprConstant.cpp =================================================================== --- cfe/trunk/lib/AST/ExprConstant.cpp +++ cfe/trunk/lib/AST/ExprConstant.cpp @@ -4383,6 +4383,7 @@ #endif for (const auto *I : Definition->inits()) { LValue Subobject = This; + LValue SubobjectParent = This; APValue *Value = &Result; // Determine the subobject to initialize. @@ -4413,7 +4414,8 @@ } else if (IndirectFieldDecl *IFD = I->getIndirectMember()) { // Walk the indirect field decl's chain to find the object to initialize, // and make sure we've initialized every step along it. - for (auto *C : IFD->chain()) { + auto IndirectFieldChain = IFD->chain(); + for (auto *C : IndirectFieldChain) { FD = cast(C); CXXRecordDecl *CD = cast(FD->getParent()); // Switch the union field if it differs. This happens if we had @@ -4429,6 +4431,10 @@ *Value = APValue(APValue::UninitStruct(), CD->getNumBases(), std::distance(CD->field_begin(), CD->field_end())); } + // Store Subobject as its parent before updating it for the last element + // in the chain. + if (C == IndirectFieldChain.back()) + SubobjectParent = Subobject; if (!HandleLValueMember(Info, I->getInit(), Subobject, FD)) return false; if (CD->isUnion()) @@ -4440,10 +4446,16 @@ llvm_unreachable("unknown base initializer kind"); } + // Need to override This for implicit field initializers as in this case + // This refers to innermost anonymous struct/union containing initializer, + // not to currently constructed class. + const Expr *Init = I->getInit(); + ThisOverrideRAII ThisOverride(*Info.CurrentCall, &SubobjectParent, + isa(Init)); FullExpressionRAII InitScope(Info); - if (!EvaluateInPlace(*Value, Info, Subobject, I->getInit()) || - (FD && FD->isBitField() && !truncateBitfieldValue(Info, I->getInit(), - *Value, FD))) { + if (!EvaluateInPlace(*Value, Info, Subobject, Init) || + (FD && FD->isBitField() && + !truncateBitfieldValue(Info, Init, *Value, FD))) { // If we're checking for a potential constant expression, evaluate all // initializers even if some of them fail. if (!Info.noteFailure()) Index: cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp =================================================================== --- cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp +++ cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp @@ -1045,3 +1045,57 @@ constexpr B b; constexpr int p = b.n; // expected-error {{constant expression}} expected-note {{mutable}} } + +namespace IndirectFields { + +// Reference indirect field. +struct A { + struct { + union { + int x = x = 3; // expected-note {{outside its lifetime}} + }; + }; + constexpr A() {} +}; +static_assert(A().x == 3, ""); // expected-error{{not an integral constant expression}} expected-note{{in call to 'A()'}} + +// Reference another indirect field, with different 'this'. +struct B { + struct { + union { + int x = 3; + }; + int y = x; + }; + constexpr B() {} +}; +static_assert(B().y == 3, ""); + +// Nested evaluation of indirect field initializers. +struct C { + union { + int x = 1; + }; +}; +struct D { + struct { + C c; + int y = c.x + 1; + }; +}; +static_assert(D().y == 2, ""); + +// Explicit 'this'. +struct E { + int n = 0; + struct { + void *x = this; + }; + void *y = this; +}; +constexpr E e1 = E(); +static_assert(e1.x != e1.y, ""); +constexpr E e2 = E{0}; +static_assert(e2.x != e2.y, ""); + +} // namespace IndirectFields