@@ -3164,7 +3164,18 @@ inout(V) get(K, V)(inout(V[K])* aa, K key, lazy inout(V) defaultValue)
3164
3164
ref V require (K, V)(ref V[K] aa, K key, lazy V value = V.init)
3165
3165
{
3166
3166
bool found;
3167
- auto p = cast (V* ) _aaGetX(cast (void ** )&aa, typeid (V[K]), V.sizeof, &key, found);
3167
+ // if key is @safe-ly copyable, `require` can infer @safe
3168
+ static if (isSafeCopyable! K)
3169
+ {
3170
+ auto p = () @trusted
3171
+ {
3172
+ return cast (V* ) _aaGetX(cast (void ** ) &aa, typeid (V[K]), V.sizeof, &key, found);
3173
+ } ();
3174
+ }
3175
+ else
3176
+ {
3177
+ auto p = cast (V* ) _aaGetX(cast (void ** ) &aa, typeid (V[K]), V.sizeof, &key, found);
3178
+ }
3168
3179
return found ? * p : (* p = value);
3169
3180
}
3170
3181
@@ -3193,6 +3204,9 @@ private
3193
3204
}
3194
3205
}
3195
3206
3207
+ // Tests whether T can be @safe-ly copied. Use a union to exclude destructor from the test.
3208
+ private enum bool isSafeCopyable(T) = is (typeof (() @safe { union U { T x; } T * x; auto u = U(* x); }));
3209
+
3196
3210
/* **********************************
3197
3211
* Looks up key; if it exists applies the update delegate else evaluates the
3198
3212
* create delegate and adds it to the associative array
@@ -3206,13 +3220,54 @@ void update(K, V, C, U)(ref V[K] aa, K key, scope C create, scope U update)
3206
3220
if (isCreateOperation! (C, V) && isUpdateOperation! (U, V))
3207
3221
{
3208
3222
bool found;
3209
- auto p = cast (V* ) _aaGetX(cast (void ** )&aa, typeid (V[K]), V.sizeof, &key, found);
3223
+ // if key is @safe-ly copyable, `update` may infer @safe
3224
+ static if (isSafeCopyable! K)
3225
+ {
3226
+ auto p = () @trusted
3227
+ {
3228
+ return cast (V* ) _aaGetX(cast (void ** ) &aa, typeid (V[K]), V.sizeof, &key, found);
3229
+ } ();
3230
+ }
3231
+ else
3232
+ {
3233
+ auto p = cast (V* ) _aaGetX(cast (void ** ) &aa, typeid (V[K]), V.sizeof, &key, found);
3234
+ }
3210
3235
if (! found)
3211
3236
* p = create();
3212
3237
else
3213
3238
* p = update(* p);
3214
3239
}
3215
3240
3241
+ unittest
3242
+ {
3243
+ static struct S
3244
+ {
3245
+ int x;
3246
+ @nogc nothrow pure :
3247
+ this (this ) @system {}
3248
+
3249
+ @safe const :
3250
+ // stubs
3251
+ bool opEquals (S rhs) { assert (0 ); }
3252
+ size_t toHash () { assert (0 ); }
3253
+ }
3254
+
3255
+ int [string ] aai;
3256
+ static assert (is (typeof (() @safe { aai.require(" a" , 1234 ); })));
3257
+ static assert (is (typeof (() @safe { aai.update(" a" , { return 1234 ; }, (ref int x) { x++ ; return x; }); })));
3258
+
3259
+ S[string ] aas;
3260
+ static assert (is (typeof (() { aas.require(" a" , S(1234 )); })));
3261
+ static assert (is (typeof (() { aas.update(" a" , { return S(1234 ); }, (ref S s) { s.x++ ; return s; }); })));
3262
+ static assert (! is (typeof (() @safe { aas.update(" a" , { return S(1234 ); }, (ref S s) { s.x++ ; return s; }); })));
3263
+
3264
+ int [S] aais;
3265
+ static assert (is (typeof (() { aais.require(S(1234 ), 1234 ); })));
3266
+ static assert (is (typeof (() { aais.update(S(1234 ), { return 1234 ; }, (ref int x) { x++ ; return x; }); })));
3267
+ static assert (! is (typeof (() @safe { aais.require(S(1234 ), 1234 ); })));
3268
+ static assert (! is (typeof (() @safe { aais.update(S(1234 ), { return 1234 ; }, (ref int x) { x++ ; return x; }); })));
3269
+ }
3270
+
3216
3271
private void _destructRecurse (E, size_t n)(ref E[n] arr)
3217
3272
{
3218
3273
import core.internal.traits : hasElaborateDestructor;
0 commit comments