@@ -2066,34 +2066,32 @@ inline bool CastMemberPtrPtr(InterpState &S, CodePtr OpPC) {
2066
2066
// ===----------------------------------------------------------------------===//
2067
2067
2068
2068
template <class T , ArithOp Op>
2069
- bool OffsetHelper (InterpState &S, CodePtr OpPC, const T &Offset,
2070
- const Pointer &Ptr, bool IsPointerArith = false ) {
2069
+ std::optional<Pointer> OffsetHelper (InterpState &S, CodePtr OpPC,
2070
+ const T &Offset, const Pointer &Ptr,
2071
+ bool IsPointerArith = false ) {
2071
2072
// A zero offset does not change the pointer.
2072
- if (Offset.isZero ()) {
2073
- S.Stk .push <Pointer>(Ptr);
2074
- return true ;
2075
- }
2073
+ if (Offset.isZero ())
2074
+ return Ptr;
2076
2075
2077
2076
if (IsPointerArith && !CheckNull (S, OpPC, Ptr, CSK_ArrayIndex)) {
2078
2077
// The CheckNull will have emitted a note already, but we only
2079
2078
// abort in C++, since this is fine in C.
2080
2079
if (S.getLangOpts ().CPlusPlus )
2081
- return false ;
2080
+ return std::nullopt ;
2082
2081
}
2083
2082
2084
2083
// Arrays of unknown bounds cannot have pointers into them.
2085
2084
if (!CheckArray (S, OpPC, Ptr))
2086
- return false ;
2085
+ return std::nullopt ;
2087
2086
2088
2087
// This is much simpler for integral pointers, so handle them first.
2089
2088
if (Ptr.isIntegralPointer ()) {
2090
2089
uint64_t V = Ptr.getIntegerRepresentation ();
2091
2090
uint64_t O = static_cast <uint64_t >(Offset) * Ptr.elemSize ();
2092
2091
if constexpr (Op == ArithOp::Add)
2093
- S. Stk . push < Pointer> (V + O, Ptr.asIntPointer ().Desc );
2092
+ return Pointer (V + O, Ptr.asIntPointer ().Desc );
2094
2093
else
2095
- S.Stk .push <Pointer>(V - O, Ptr.asIntPointer ().Desc );
2096
- return true ;
2094
+ return Pointer (V - O, Ptr.asIntPointer ().Desc );
2097
2095
} else if (Ptr.isFunctionPointer ()) {
2098
2096
uint64_t O = static_cast <uint64_t >(Offset);
2099
2097
uint64_t N;
@@ -2105,8 +2103,7 @@ bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
2105
2103
if (N > 1 )
2106
2104
S.CCEDiag (S.Current ->getSource (OpPC), diag::note_constexpr_array_index)
2107
2105
<< N << /* non-array*/ true << 0 ;
2108
- S.Stk .push <Pointer>(Ptr.asFunctionPointer ().getFunction (), N);
2109
- return true ;
2106
+ return Pointer (Ptr.asFunctionPointer ().getFunction (), N);
2110
2107
}
2111
2108
2112
2109
assert (Ptr.isBlockPointer ());
@@ -2156,7 +2153,7 @@ bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
2156
2153
}
2157
2154
2158
2155
if (Invalid && S.getLangOpts ().CPlusPlus )
2159
- return false ;
2156
+ return std::nullopt ;
2160
2157
2161
2158
// Offset is valid - compute it on unsigned.
2162
2159
int64_t WideIndex = static_cast <int64_t >(Index);
@@ -2172,15 +2169,11 @@ bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
2172
2169
// we don't get here.
2173
2170
if (Result == 0 && Ptr.isOnePastEnd ()) {
2174
2171
if (Ptr.getFieldDesc ()->isArray ())
2175
- S.Stk .push <Pointer>(Ptr.atIndex (0 ));
2176
- else
2177
- S.Stk .push <Pointer>(Ptr.asBlockPointer ().Pointee ,
2178
- Ptr.asBlockPointer ().Base );
2179
- return true ;
2172
+ return Ptr.atIndex (0 );
2173
+ return Pointer (Ptr.asBlockPointer ().Pointee , Ptr.asBlockPointer ().Base );
2180
2174
}
2181
2175
2182
- S.Stk .push <Pointer>(Ptr.atIndex (static_cast <uint64_t >(Result)));
2183
- return true ;
2176
+ return Ptr.atIndex (static_cast <uint64_t >(Result));
2184
2177
}
2185
2178
2186
2179
template <PrimType Name, class T = typename PrimConv<Name>::T>
@@ -2189,16 +2182,26 @@ bool AddOffset(InterpState &S, CodePtr OpPC) {
2189
2182
Pointer Ptr = S.Stk .pop <Pointer>();
2190
2183
if (Ptr.isBlockPointer ())
2191
2184
Ptr = Ptr.expand ();
2192
- return OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr,
2193
- /* IsPointerArith=*/ true );
2185
+
2186
+ if (std::optional<Pointer> Result = OffsetHelper<T, ArithOp::Add>(
2187
+ S, OpPC, Offset, Ptr, /* IsPointerArith=*/ true )) {
2188
+ S.Stk .push <Pointer>(*Result);
2189
+ return true ;
2190
+ }
2191
+ return false ;
2194
2192
}
2195
2193
2196
2194
template <PrimType Name, class T = typename PrimConv<Name>::T>
2197
2195
bool SubOffset (InterpState &S, CodePtr OpPC) {
2198
2196
const T &Offset = S.Stk .pop <T>();
2199
2197
const Pointer &Ptr = S.Stk .pop <Pointer>();
2200
- return OffsetHelper<T, ArithOp::Sub>(S, OpPC, Offset, Ptr,
2201
- /* IsPointerArith=*/ true );
2198
+
2199
+ if (std::optional<Pointer> Result = OffsetHelper<T, ArithOp::Sub>(
2200
+ S, OpPC, Offset, Ptr, /* IsPointerArith=*/ true )) {
2201
+ S.Stk .push <Pointer>(*Result);
2202
+ return true ;
2203
+ }
2204
+ return false ;
2202
2205
}
2203
2206
2204
2207
template <ArithOp Op>
@@ -2218,12 +2221,13 @@ static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC,
2218
2221
2219
2222
// Now the current Ptr again and a constant 1.
2220
2223
OneT One = OneT::from (1 );
2221
- if (!OffsetHelper<OneT, Op>(S, OpPC, One, P, /* IsPointerArith=*/ true ))
2222
- return false ;
2223
-
2224
- // Store the new value.
2225
- Ptr.deref <Pointer>() = S.Stk .pop <Pointer>();
2226
- return true ;
2224
+ if (std::optional<Pointer> Result =
2225
+ OffsetHelper<OneT, Op>(S, OpPC, One, P, /* IsPointerArith=*/ true )) {
2226
+ // Store the new value.
2227
+ Ptr.deref <Pointer>() = *Result;
2228
+ return true ;
2229
+ }
2230
+ return false ;
2227
2231
}
2228
2232
2229
2233
static inline bool IncPtr (InterpState &S, CodePtr OpPC) {
@@ -2925,16 +2929,22 @@ inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
2925
2929
2926
2930
if (Offset.isZero ()) {
2927
2931
if (Ptr.getFieldDesc ()->isArray () && Ptr.getIndex () == 0 ) {
2928
- S.Stk .push <Pointer>(Ptr.atIndex (0 ));
2929
- } else {
2930
- S.Stk .push <Pointer>(Ptr);
2932
+ S.Stk .push <Pointer>(Ptr.atIndex (0 ).narrow ());
2933
+ return true ;
2931
2934
}
2932
- } else {
2933
- if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
2934
- return false ;
2935
+ S.Stk .push <Pointer>(Ptr);
2936
+ return true ;
2937
+ }
2938
+
2939
+ assert (!Offset.isZero ());
2940
+
2941
+ if (std::optional<Pointer> Result =
2942
+ OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr)) {
2943
+ S.Stk .push <Pointer>(Result->narrow ());
2944
+ return true ;
2935
2945
}
2936
2946
2937
- return NarrowPtr (S, OpPC) ;
2947
+ return false ;
2938
2948
}
2939
2949
2940
2950
template <PrimType Name, class T = typename PrimConv<Name>::T>
@@ -2949,16 +2959,21 @@ inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
2949
2959
2950
2960
if (Offset.isZero ()) {
2951
2961
if (Ptr.getFieldDesc ()->isArray () && Ptr.getIndex () == 0 ) {
2952
- S.Stk .push <Pointer>(Ptr.atIndex (0 ));
2953
- } else {
2954
- S.Stk .push <Pointer>(Ptr);
2962
+ S.Stk .push <Pointer>(Ptr.atIndex (0 ).narrow ());
2963
+ return true ;
2955
2964
}
2956
- } else {
2957
- if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
2958
- return false ;
2965
+ S.Stk .push <Pointer>(Ptr);
2966
+ return true ;
2959
2967
}
2960
2968
2961
- return NarrowPtr (S, OpPC);
2969
+ assert (!Offset.isZero ());
2970
+
2971
+ if (std::optional<Pointer> Result =
2972
+ OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr)) {
2973
+ S.Stk .push <Pointer>(Result->narrow ());
2974
+ return true ;
2975
+ }
2976
+ return false ;
2962
2977
}
2963
2978
2964
2979
template <PrimType Name, class T = typename PrimConv<Name>::T>
0 commit comments