Index: clang/lib/AST/ExprConstant.cpp =================================================================== --- clang/lib/AST/ExprConstant.cpp +++ clang/lib/AST/ExprConstant.cpp @@ -449,6 +449,9 @@ /// Index - The call index of this call. unsigned Index; + /// IndirectField - The indirect field being evaluated. + const IndirectFieldDecl *IndirectField = nullptr; + // FIXME: Adding this to every 'CallStackFrame' may have a nontrivial impact // on the overall stack usage of deeply-recursing constexpr evaluataions. // (We should cache this map rather than recomputing it repeatedly.) @@ -4370,6 +4373,7 @@ for (const auto *I : Definition->inits()) { LValue Subobject = This; APValue *Value = &Result; + Frame.IndirectField = nullptr; // Determine the subobject to initialize. FieldDecl *FD = nullptr; @@ -4399,6 +4403,7 @@ } 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. + Frame.IndirectField = IFD; for (auto *C : IFD->chain()) { FD = cast(C); CXXRecordDecl *CD = cast(FD->getParent()); @@ -4437,6 +4442,7 @@ Success = false; } } + Frame.IndirectField = nullptr; return Success && EvaluateStmt(Ret, Info, Definition->getBody()) != ESR_Failed; @@ -5612,6 +5618,20 @@ Result.setFrom(Info.Ctx, RVal); } + } else if (Info.CurrentCall->IndirectField) { + // Fields of anonymous structs/unions can refer to other fields. In this + // case the 'this' expression corresponds to anonymous struct/union but + // Info.CurrentCall->This corresponds to the field's non-anonymous parent. + for (auto *C : Info.CurrentCall->IndirectField->chain()) { + const FieldDecl *FD = cast(C); + if (!FD->isImplicit()) { + assert(E->getType()->getPointeeCXXRecordDecl() == FD->getParent() && + "Should adjust LValue to refer to the same 'this'"); + break; + } + if (!HandleLValueMember(Info, E, Result, FD)) + return false; + } } return true; } Index: clang/test/SemaCXX/constant-expression-cxx1y.cpp =================================================================== --- clang/test/SemaCXX/constant-expression-cxx1y.cpp +++ clang/test/SemaCXX/constant-expression-cxx1y.cpp @@ -1021,3 +1021,44 @@ } static_assert(evalNested(), ""); } // namespace PR19741 + +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, ""); + +} // namespace IndirectFields