@@ -3163,7 +3163,18 @@ inout(V) get(K, V)(inout(V[K])* aa, K key, lazy inout(V) defaultValue)
31633163ref V require (K, V)(ref V[K] aa, K key, lazy V value = V.init)
31643164{
31653165 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+ }
31673178 return found ? * p : (* p = value);
31683179}
31693180
@@ -3192,6 +3203,9 @@ private
31923203 }
31933204}
31943205
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+
31953209/* **********************************
31963210 * Looks up key; if it exists applies the update delegate else evaluates the
31973211 * 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)
32053219if (isCreateOperation! (C, V) && isUpdateOperation! (U, V))
32063220{
32073221 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+ }
32093234 if (! found)
32103235 * p = create();
32113236 else
32123237 * p = update(* p);
32133238}
32143239
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+
32153270private void _destructRecurse (E, size_t n)(ref E[n] arr)
32163271{
32173272 import core.internal.traits : hasElaborateDestructor;
0 commit comments