diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 83c7e98c2dda0b..1df8d65c804454 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -1844,6 +1844,15 @@ bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset, else Result = WideIndex - WideOffset; + // When the pointer is one-past-end, going back to index 0 is the only + // useful thing we can do. Any other index has been diagnosed before and + // we don't get here. + if (Result == 0 && Ptr.isOnePastEnd()) { + S.Stk.push(Ptr.asBlockPointer().Pointee, + Ptr.asBlockPointer().Base); + return true; + } + S.Stk.push(Ptr.atIndex(static_cast(Result))); return true; } diff --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp index adc3799a20ce4e..4b06fc7522d45c 100644 --- a/clang/test/AST/Interp/records.cpp +++ b/clang/test/AST/Interp/records.cpp @@ -1500,3 +1500,15 @@ namespace LocalWithThisPtrInit { } static_assert(foo() == 2, ""); } + +namespace OnePastEndAndBack { + struct Base { + constexpr Base() {} + int n = 0; + }; + + constexpr Base a; + constexpr const Base *c = &a + 1; + constexpr const Base *d = c - 1; + static_assert(d == &a, ""); +}