Author: Timm Bäder Date: 2024-05-24T15:15:40+02:00 New Revision: f35aac699167ef1046e2f177d2ba899c6975374e
URL: https://github.com/llvm/llvm-project/commit/f35aac699167ef1046e2f177d2ba899c6975374e DIFF: https://github.com/llvm/llvm-project/commit/f35aac699167ef1046e2f177d2ba899c6975374e.diff LOG: [clang][Interp] Fix zero-initializing unions Only with primitive fields for now. Added: Modified: clang/lib/AST/Interp/ByteCodeExprGen.cpp clang/test/AST/Interp/unions.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index b885cbe2c4b0e..f73eaeebf9fe8 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -1053,9 +1053,6 @@ bool ByteCodeExprGen<Emitter>::visitInitList(ArrayRef<const Expr *> Inits, if (Inits.size() == 1 && E->getType() == Inits[0]->getType()) return this->visitInitializer(Inits[0]); - if (Inits.size() == 0) - return this->emitFinishInit(E); - auto initPrimitiveField = [=](const Record::Field *FieldToInit, const Expr *Init, PrimType T) -> bool { if (!this->visit(Init)) @@ -1083,24 +1080,38 @@ bool ByteCodeExprGen<Emitter>::visitInitList(ArrayRef<const Expr *> Inits, }; if (R->isUnion()) { - assert(Inits.size() == 1); - const Expr *Init = Inits[0]; - const FieldDecl *FToInit = nullptr; - if (const auto *ILE = dyn_cast<InitListExpr>(E)) - FToInit = ILE->getInitializedFieldInUnion(); - else - FToInit = cast<CXXParenListInitExpr>(E)->getInitializedFieldInUnion(); - - if (!this->emitDupPtr(E)) - return false; - - const Record::Field *FieldToInit = R->getField(FToInit); - if (std::optional<PrimType> T = classify(Init)) { - if (!initPrimitiveField(FieldToInit, Init, *T)) - return false; + if (Inits.size() == 0) { + // Zero-initialize the first union field. + if (R->getNumFields() == 0) + return this->emitFinishInit(E); + const Record::Field *FieldToInit = R->getField(0u); + QualType FieldType = FieldToInit->Desc->getType(); + if (std::optional<PrimType> T = classify(FieldType)) { + if (!this->visitZeroInitializer(*T, FieldType, E)) + return false; + if (!this->emitInitField(*T, FieldToInit->Offset, E)) + return false; + } + // FIXME: Non-primitive case? } else { - if (!initCompositeField(FieldToInit, Init)) + const Expr *Init = Inits[0]; + const FieldDecl *FToInit = nullptr; + if (const auto *ILE = dyn_cast<InitListExpr>(E)) + FToInit = ILE->getInitializedFieldInUnion(); + else + FToInit = cast<CXXParenListInitExpr>(E)->getInitializedFieldInUnion(); + + if (!this->emitDupPtr(E)) return false; + + const Record::Field *FieldToInit = R->getField(FToInit); + if (std::optional<PrimType> T = classify(Init)) { + if (!initPrimitiveField(FieldToInit, Init, *T)) + return false; + } else { + if (!initCompositeField(FieldToInit, Init)) + return false; + } } return this->emitFinishInit(E); } diff --git a/clang/test/AST/Interp/unions.cpp b/clang/test/AST/Interp/unions.cpp index b0b1b19617408..293a1981a52f0 100644 --- a/clang/test/AST/Interp/unions.cpp +++ b/clang/test/AST/Interp/unions.cpp @@ -31,6 +31,12 @@ static_assert(ab.d == 1.0, ""); static_assert(ab.a == 1, ""); // both-error {{not an integral constant expression}} \ // both-note {{read of member 'a' of union with active member 'd'}} + +namespace Empty { + union E {}; + constexpr E e{}; +} + namespace SimpleStore { union A { int a; @@ -49,3 +55,13 @@ namespace SimpleStore { } static_assert(empty() == 10, ""); } + +namespace ZeroInit { + struct S { int m; }; + union Z { + float f; + }; + + constexpr Z z{}; + static_assert(z.f == 0.0, ""); +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits