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