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