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.
Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D149013 Files: clang/lib/AST/Interp/Interp.cpp clang/lib/AST/Interp/Interp.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 @@ -497,6 +497,21 @@ //static_assert(b.a.f == 100, ""); } +namespace PointerArith { + struct A {}; + struct B : A { int n; }; + + B b = {}; + constexpr A *a1 = &b; + constexpr B *b1 = &b + 1; + constexpr B *b2 = &b + 0; + + constexpr A *a2 = &b + 1; // expected-error {{must be initialized by a constant expression}} \ + // expected-note {{cannot access base class of pointer past the end of object}} \ + // ref-error {{must be initialized by a constant expression}} \ + // ref-note {{cannot access base class of pointer past the end of object}} +} + #if __cplusplus >= 202002L namespace VirtualCalls { namespace Obvious { Index: clang/lib/AST/Interp/Interp.h =================================================================== --- clang/lib/AST/Interp/Interp.h +++ clang/lib/AST/Interp/Interp.h @@ -67,6 +67,9 @@ bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK); +/// Checks if accessing a base of the given pointer is valid. +bool CheckBase(InterpState &S, CodePtr OpPC, const Pointer &Ptr); + /// Checks if a pointer points to const storage. bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr); @@ -1079,6 +1082,8 @@ const Pointer &Ptr = S.Stk.peek<Pointer>(); if (!CheckNull(S, OpPC, Ptr, CSK_Base)) return false; + if (!CheckBase(S, OpPC, Ptr)) + return false; S.Stk.push<Pointer>(Ptr.atField(Off)); return true; } @@ -1087,6 +1092,8 @@ const Pointer &Ptr = S.Stk.pop<Pointer>(); if (!CheckNull(S, OpPC, Ptr, CSK_Base)) return false; + if (!CheckBase(S, OpPC, Ptr)) + return false; S.Stk.push<Pointer>(Ptr.atField(Off)); return true; } Index: clang/lib/AST/Interp/Interp.cpp =================================================================== --- clang/lib/AST/Interp/Interp.cpp +++ clang/lib/AST/Interp/Interp.cpp @@ -211,6 +211,15 @@ return false; } +bool CheckBase(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { + if (!Ptr.isOnePastEnd()) + return true; + + const SourceInfo &Loc = S.Current->getSource(OpPC); + S.FFDiag(Loc, diag::note_constexpr_past_end_subobject) << CSK_Base; + return false; +} + bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { assert(Ptr.isLive() && "Pointer is not live"); if (!Ptr.isConst())
Index: clang/test/AST/Interp/records.cpp =================================================================== --- clang/test/AST/Interp/records.cpp +++ clang/test/AST/Interp/records.cpp @@ -497,6 +497,21 @@ //static_assert(b.a.f == 100, ""); } +namespace PointerArith { + struct A {}; + struct B : A { int n; }; + + B b = {}; + constexpr A *a1 = &b; + constexpr B *b1 = &b + 1; + constexpr B *b2 = &b + 0; + + constexpr A *a2 = &b + 1; // expected-error {{must be initialized by a constant expression}} \ + // expected-note {{cannot access base class of pointer past the end of object}} \ + // ref-error {{must be initialized by a constant expression}} \ + // ref-note {{cannot access base class of pointer past the end of object}} +} + #if __cplusplus >= 202002L namespace VirtualCalls { namespace Obvious { Index: clang/lib/AST/Interp/Interp.h =================================================================== --- clang/lib/AST/Interp/Interp.h +++ clang/lib/AST/Interp/Interp.h @@ -67,6 +67,9 @@ bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK); +/// Checks if accessing a base of the given pointer is valid. +bool CheckBase(InterpState &S, CodePtr OpPC, const Pointer &Ptr); + /// Checks if a pointer points to const storage. bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr); @@ -1079,6 +1082,8 @@ const Pointer &Ptr = S.Stk.peek<Pointer>(); if (!CheckNull(S, OpPC, Ptr, CSK_Base)) return false; + if (!CheckBase(S, OpPC, Ptr)) + return false; S.Stk.push<Pointer>(Ptr.atField(Off)); return true; } @@ -1087,6 +1092,8 @@ const Pointer &Ptr = S.Stk.pop<Pointer>(); if (!CheckNull(S, OpPC, Ptr, CSK_Base)) return false; + if (!CheckBase(S, OpPC, Ptr)) + return false; S.Stk.push<Pointer>(Ptr.atField(Off)); return true; } Index: clang/lib/AST/Interp/Interp.cpp =================================================================== --- clang/lib/AST/Interp/Interp.cpp +++ clang/lib/AST/Interp/Interp.cpp @@ -211,6 +211,15 @@ return false; } +bool CheckBase(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { + if (!Ptr.isOnePastEnd()) + return true; + + const SourceInfo &Loc = S.Current->getSource(OpPC); + S.FFDiag(Loc, diag::note_constexpr_past_end_subobject) << CSK_Base; + return false; +} + bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { assert(Ptr.isLive() && "Pointer is not live"); if (!Ptr.isConst())
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits