[PATCH] D143480: [clang][Interp] Fix derived-to-base casts for >1 levels
This revision was landed with ongoing or failed builds. This revision was automatically updated to reflect the committed changes. Closed by commit rG968b4172f6a9: [clang][Interp] Fix derived-to-base casts for 1 levels (authored by tbaeder). Changed prior to commit: https://reviews.llvm.org/D143480?vs=504022=510435#toc Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D143480/new/ https://reviews.llvm.org/D143480 Files: clang/lib/AST/Interp/ByteCodeExprGen.cpp clang/lib/AST/Interp/ByteCodeExprGen.h clang/test/AST/Interp/records.cpp Index: clang/test/AST/Interp/records.cpp === --- clang/test/AST/Interp/records.cpp +++ clang/test/AST/Interp/records.cpp @@ -250,6 +250,21 @@ constexpr S s; static_assert(s.m() == 1, ""); +#if __cplusplus >= 201703L +namespace BaseInit { + class A {public: int a;}; + class B : public A {}; + class C : public A {}; + class D : public B, public C {}; + + // FIXME: Enable this once we support the initialization. + // This initializes D::B::A::a and not D::C::A::a. + //constexpr D d{12}; + //static_assert(d.B::a == 12); + //static_assert(d.C::a == 0); +}; +#endif + namespace MI { class A { public: Index: clang/lib/AST/Interp/ByteCodeExprGen.h === --- clang/lib/AST/Interp/ByteCodeExprGen.h +++ clang/lib/AST/Interp/ByteCodeExprGen.h @@ -260,6 +260,8 @@ } bool emitRecordDestruction(const Descriptor *Desc); + bool emitDerivedToBaseCasts(const RecordType *DerivedType, + const RecordType *BaseType, const Expr *E); protected: /// Variable to storage mapping. Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp === --- clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -85,15 +85,8 @@ if (!this->visit(SubExpr)) return false; -const CXXRecordDecl *FromDecl = getRecordDecl(SubExpr); -assert(FromDecl); -const CXXRecordDecl *ToDecl = getRecordDecl(CE); -assert(ToDecl); -const Record *R = getRecord(FromDecl); -const Record::Base *ToBase = R->getBase(ToDecl); -assert(ToBase); - -return this->emitGetPtrBasePop(ToBase->Offset, CE); +return this->emitDerivedToBaseCasts(getRecordTy(SubExpr->getType()), +getRecordTy(CE->getType()), CE); } case CK_FloatingCast: { @@ -1873,6 +1866,38 @@ C->emitDestruction(); } +template +bool ByteCodeExprGen::emitDerivedToBaseCasts( +const RecordType *DerivedType, const RecordType *BaseType, const Expr *E) { + // Pointer of derived type is already on the stack. + const auto *FinalDecl = cast(BaseType->getDecl()); + const RecordDecl *CurDecl = DerivedType->getDecl(); + const Record *CurRecord = getRecord(CurDecl); + assert(CurDecl && FinalDecl); + for (;;) { +assert(CurRecord->getNumBases() > 0); +// One level up +for (const Record::Base : CurRecord->bases()) { + const auto *BaseDecl = cast(B.Decl); + + if (BaseDecl == FinalDecl || BaseDecl->isDerivedFrom(FinalDecl)) { +// This decl will lead us to the final decl, so emit a base cast. +if (!this->emitGetPtrBasePop(B.Offset, E)) + return false; + +CurRecord = B.R; +CurDecl = BaseDecl; +break; + } +} +if (CurDecl == FinalDecl) + return true; + } + + llvm_unreachable("Couldn't find the base class?"); + return false; +} + /// When calling this, we have a pointer of the local-to-destroy /// on the stack. /// Emit destruction of record types (or arrays of record types). Index: clang/test/AST/Interp/records.cpp === --- clang/test/AST/Interp/records.cpp +++ clang/test/AST/Interp/records.cpp @@ -250,6 +250,21 @@ constexpr S s; static_assert(s.m() == 1, ""); +#if __cplusplus >= 201703L +namespace BaseInit { + class A {public: int a;}; + class B : public A {}; + class C : public A {}; + class D : public B, public C {}; + + // FIXME: Enable this once we support the initialization. + // This initializes D::B::A::a and not D::C::A::a. + //constexpr D d{12}; + //static_assert(d.B::a == 12); + //static_assert(d.C::a == 0); +}; +#endif + namespace MI { class A { public: Index: clang/lib/AST/Interp/ByteCodeExprGen.h === --- clang/lib/AST/Interp/ByteCodeExprGen.h +++ clang/lib/AST/Interp/ByteCodeExprGen.h @@ -260,6 +260,8 @@ } bool emitRecordDestruction(const Descriptor *Desc); + bool emitDerivedToBaseCasts(const RecordType *DerivedType, + const RecordType *BaseType, const Expr *E); protected: /// Variable to storage mapping. Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
[PATCH] D143480: [clang][Interp] Fix derived-to-base casts for >1 levels
aaron.ballman accepted this revision. aaron.ballman added a comment. This revision is now accepted and ready to land. LGTM! CHANGES SINCE LAST ACTION https://reviews.llvm.org/D143480/new/ https://reviews.llvm.org/D143480 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D143480: [clang][Interp] Fix derived-to-base casts for >1 levels
tbaeder added inline comments. Comment at: clang/test/AST/Interp/records.cpp:266 }; #endif aaron.ballman wrote: > I think it'd be good to add test coverage for cases like: > https://godbolt.org/z/GnPnP4z76 That even worked :) CHANGES SINCE LAST ACTION https://reviews.llvm.org/D143480/new/ https://reviews.llvm.org/D143480 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D143480: [clang][Interp] Fix derived-to-base casts for >1 levels
tbaeder updated this revision to Diff 504022. tbaeder marked 2 inline comments as done. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D143480/new/ https://reviews.llvm.org/D143480 Files: clang/lib/AST/Interp/ByteCodeExprGen.cpp clang/lib/AST/Interp/ByteCodeExprGen.h clang/test/AST/Interp/records.cpp Index: clang/test/AST/Interp/records.cpp === --- clang/test/AST/Interp/records.cpp +++ clang/test/AST/Interp/records.cpp @@ -260,6 +260,20 @@ constexpr _C c{12}; constexpr const _B = c; static_assert(b.a == 12); + + // Cast from A to C. + constexpr _A a = c; + static_assert(a.a == 12); + + class A {public: int a;}; + class B : public A {}; + class C : public A {}; + class D : public B, public C {}; + + // This initializes D::B::A::a and not D::C::A::a. + constexpr D d{12}; + static_assert(d.B::a == 12); + static_assert(d.C::a == 0); }; #endif Index: clang/lib/AST/Interp/ByteCodeExprGen.h === --- clang/lib/AST/Interp/ByteCodeExprGen.h +++ clang/lib/AST/Interp/ByteCodeExprGen.h @@ -263,6 +263,8 @@ } bool emitRecordDestruction(const Descriptor *Desc); + bool emitDerivedToBaseCasts(const RecordType *DerivedType, + const RecordType *BaseType, const Expr *E); protected: /// Variable to storage mapping. Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp === --- clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -88,15 +88,8 @@ if (!this->visit(SubExpr)) return false; -const CXXRecordDecl *FromDecl = getRecordDecl(SubExpr); -assert(FromDecl); -const CXXRecordDecl *ToDecl = getRecordDecl(CE); -assert(ToDecl); -const Record *R = getRecord(FromDecl); -const Record::Base *ToBase = R->getBase(ToDecl); -assert(ToBase); - -return this->emitGetPtrBasePop(ToBase->Offset, CE); +return this->emitDerivedToBaseCasts(getRecordTy(SubExpr->getType()), +getRecordTy(CE->getType()), CE); } case CK_FloatingCast: { @@ -1956,6 +1949,38 @@ C->emitDestruction(); } +template +bool ByteCodeExprGen::emitDerivedToBaseCasts( +const RecordType *DerivedType, const RecordType *BaseType, const Expr *E) { + // Pointer of derived type is already on the stack. + const auto *FinalDecl = cast(BaseType->getDecl()); + const RecordDecl *CurDecl = DerivedType->getDecl(); + const Record *CurRecord = getRecord(CurDecl); + assert(CurDecl && FinalDecl); + for (;;) { +assert(CurRecord->getNumBases() > 0); +// One level up +for (const Record::Base : CurRecord->bases()) { + const auto *BaseDecl = cast(B.Decl); + + if (BaseDecl == FinalDecl || BaseDecl->isDerivedFrom(FinalDecl)) { +// This decl will lead us to the final decl, so emit a base cast. +if (!this->emitGetPtrBasePop(B.Offset, E)) + return false; + +CurRecord = B.R; +CurDecl = BaseDecl; +break; + } +} +if (CurDecl == FinalDecl) + return true; + } + + llvm_unreachable("Couldn't find the base class?"); + return false; +} + /// When calling this, we have a pointer of the local-to-destroy /// on the stack. /// Emit destruction of record types (or arrays of record types). Index: clang/test/AST/Interp/records.cpp === --- clang/test/AST/Interp/records.cpp +++ clang/test/AST/Interp/records.cpp @@ -260,6 +260,20 @@ constexpr _C c{12}; constexpr const _B = c; static_assert(b.a == 12); + + // Cast from A to C. + constexpr _A a = c; + static_assert(a.a == 12); + + class A {public: int a;}; + class B : public A {}; + class C : public A {}; + class D : public B, public C {}; + + // This initializes D::B::A::a and not D::C::A::a. + constexpr D d{12}; + static_assert(d.B::a == 12); + static_assert(d.C::a == 0); }; #endif Index: clang/lib/AST/Interp/ByteCodeExprGen.h === --- clang/lib/AST/Interp/ByteCodeExprGen.h +++ clang/lib/AST/Interp/ByteCodeExprGen.h @@ -263,6 +263,8 @@ } bool emitRecordDestruction(const Descriptor *Desc); + bool emitDerivedToBaseCasts(const RecordType *DerivedType, + const RecordType *BaseType, const Expr *E); protected: /// Variable to storage mapping. Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp === --- clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -88,15 +88,8 @@ if (!this->visit(SubExpr)) return false; -const CXXRecordDecl *FromDecl = getRecordDecl(SubExpr); -assert(FromDecl); -const CXXRecordDecl *ToDecl = getRecordDecl(CE); -assert(ToDecl); -
[PATCH] D143480: [clang][Interp] Fix derived-to-base casts for >1 levels
aaron.ballman added inline comments. Comment at: clang/lib/AST/Interp/ByteCodeExprGen.cpp:1949 + // Pointer of derived type is already on the stack. + const CXXRecordDecl *FinalDecl = cast(BaseType->getDecl()); + const RecordDecl *CurDecl = DerivedType->getDecl(); Comment at: clang/test/AST/Interp/records.cpp:266 }; #endif I think it'd be good to add test coverage for cases like: https://godbolt.org/z/GnPnP4z76 Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D143480/new/ https://reviews.llvm.org/D143480 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D143480: [clang][Interp] Fix derived-to-base casts for >1 levels
tbaeder added a comment. Ping Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D143480/new/ https://reviews.llvm.org/D143480 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D143480: [clang][Interp] Fix derived-to-base casts for >1 levels
tbaeder created this revision. tbaeder added reviewers: aaron.ballman, erichkeane, tahonermann, shafik. Herald added a project: All. tbaeder requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits. The GetPtrBasePop op we were using only works for direct base classes. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D143480 Files: clang/lib/AST/Interp/ByteCodeExprGen.cpp clang/lib/AST/Interp/ByteCodeExprGen.h clang/test/AST/Interp/records.cpp Index: clang/test/AST/Interp/records.cpp === --- clang/test/AST/Interp/records.cpp +++ clang/test/AST/Interp/records.cpp @@ -258,6 +258,10 @@ class _B : public _A {}; class _C : public _B {}; constexpr _C c{12}; + + // Cast from A to C. + constexpr _A a = c; + static_assert(a.a == 12); }; #endif Index: clang/lib/AST/Interp/ByteCodeExprGen.h === --- clang/lib/AST/Interp/ByteCodeExprGen.h +++ clang/lib/AST/Interp/ByteCodeExprGen.h @@ -263,6 +263,8 @@ } bool emitRecordDestruction(const Descriptor *Desc); + bool emitDerivedToBaseCasts(const RecordType *DerivedType, + const RecordType *BaseType, const Expr *E); protected: /// Variable to storage mapping. Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp === --- clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -88,15 +88,8 @@ if (!this->visit(SubExpr)) return false; -const CXXRecordDecl *FromDecl = getRecordDecl(SubExpr); -assert(FromDecl); -const CXXRecordDecl *ToDecl = getRecordDecl(CE); -assert(ToDecl); -const Record *R = getRecord(FromDecl); -const Record::Base *ToBase = R->getBase(ToDecl); -assert(ToBase); - -return this->emitGetPtrBasePop(ToBase->Offset, CE); +return this->emitDerivedToBaseCasts(getRecordTy(SubExpr->getType()), +getRecordTy(CE->getType()), CE); } case CK_FloatingCast: { @@ -1949,6 +1942,38 @@ C->emitDestruction(); } +template +bool ByteCodeExprGen::emitDerivedToBaseCasts( +const RecordType *DerivedType, const RecordType *BaseType, const Expr *E) { + // Pointer of derived type is already on the stack. + const CXXRecordDecl *FinalDecl = cast(BaseType->getDecl()); + const RecordDecl *CurDecl = DerivedType->getDecl(); + const Record *CurRecord = getRecord(CurDecl); + assert(CurDecl && FinalDecl); + for (;;) { +assert(CurRecord->getNumBases() > 0); +// One level up +for (const Record::Base : CurRecord->bases()) { + const CXXRecordDecl *BaseDecl = cast(B.Decl); + + if (BaseDecl == FinalDecl || BaseDecl->isDerivedFrom(FinalDecl)) { +// This decl will lead us to the final decl, so emit a base cast. +if (!this->emitGetPtrBasePop(B.Offset, E)) + return false; + +CurRecord = B.R; +CurDecl = BaseDecl; +break; + } +} +if (CurDecl == FinalDecl) + return true; + } + + llvm_unreachable("Couldn't find the base class?"); + return false; +} + /// When calling this, we have a pointer of the local-to-destroy /// on the stack. /// Emit destruction of record types (or arrays of record types). Index: clang/test/AST/Interp/records.cpp === --- clang/test/AST/Interp/records.cpp +++ clang/test/AST/Interp/records.cpp @@ -258,6 +258,10 @@ class _B : public _A {}; class _C : public _B {}; constexpr _C c{12}; + + // Cast from A to C. + constexpr _A a = c; + static_assert(a.a == 12); }; #endif Index: clang/lib/AST/Interp/ByteCodeExprGen.h === --- clang/lib/AST/Interp/ByteCodeExprGen.h +++ clang/lib/AST/Interp/ByteCodeExprGen.h @@ -263,6 +263,8 @@ } bool emitRecordDestruction(const Descriptor *Desc); + bool emitDerivedToBaseCasts(const RecordType *DerivedType, + const RecordType *BaseType, const Expr *E); protected: /// Variable to storage mapping. Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp === --- clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -88,15 +88,8 @@ if (!this->visit(SubExpr)) return false; -const CXXRecordDecl *FromDecl = getRecordDecl(SubExpr); -assert(FromDecl); -const CXXRecordDecl *ToDecl = getRecordDecl(CE); -assert(ToDecl); -const Record *R = getRecord(FromDecl); -const Record::Base *ToBase = R->getBase(ToDecl); -assert(ToBase); - -return this->emitGetPtrBasePop(ToBase->Offset, CE); +return this->emitDerivedToBaseCasts(getRecordTy(SubExpr->getType()), +