diff --git a/compiler/src/dmd/backend/cc.d b/compiler/src/dmd/backend/cc.d index 6bb6aa8c8f13..ae216655969f 100644 --- a/compiler/src/dmd/backend/cc.d +++ b/compiler/src/dmd/backend/cc.d @@ -749,6 +749,7 @@ enum Fnothrow = 0x10000, // function does not throw (even if not marked 'nothrow') Feh_none = 0x20000, // ehmethod==EH_NONE for this function only F3hiddenPtr = 0x40000, // function has hidden pointer to return value + F3safe = 0x80000, // function is @safe } struct func_t diff --git a/compiler/src/dmd/backend/gdag.d b/compiler/src/dmd/backend/gdag.d index 030ab4e7e62c..f8c9e8b77dc0 100644 --- a/compiler/src/dmd/backend/gdag.d +++ b/compiler/src/dmd/backend/gdag.d @@ -332,7 +332,7 @@ private void aewalk(elem **pn,vec_t ae) { assert(t.Eoper == OPvar); Symbol* s = t.EV.Vsym; - if (!(s.Sflags & SFLunambig)) + if (Symbol_isAffected(*s)) vec_subass(ae,go.starkill); for (uint i = 0; (i = cast(uint) vec_index(i, ae)) < go.exptop; ++i) // for each ae elem { @@ -821,7 +821,7 @@ private void abewalk(elem *n,vec_t ae,vec_t aeval) assert(t.Eoper == OPvar); s = t.EV.Vsym; - if (!(s.Sflags & SFLunambig)) + if (Symbol_isAffected(*s)) vec_subass(ae,go.starkill); for (uint i = 0; (i = cast(uint) vec_index(i, ae)) < go.exptop; ++i) // for each ae elem { diff --git a/compiler/src/dmd/backend/gother.d b/compiler/src/dmd/backend/gother.d index 7ff7fd83806a..9755b8ab1fd6 100644 --- a/compiler/src/dmd/backend/gother.d +++ b/compiler/src/dmd/backend/gother.d @@ -1255,7 +1255,7 @@ private bool copyPropWalk(elem *n,vec_t IN) v = go.expnod[i].EV.E1.EV.Vsym; if (ambig) { - if (!(v.Sflags & SFLunambig)) + if (Symbol_isAffected(*v)) goto clr; } else @@ -1263,10 +1263,11 @@ private bool copyPropWalk(elem *n,vec_t IN) if (v == t.EV.Vsym) goto clr; } + v = go.expnod[i].EV.E2.EV.Vsym; if (ambig) { - if (!(v.Sflags & SFLunambig)) + if (Symbol_isAffected(*v)) goto clr; } else diff --git a/compiler/src/dmd/backend/symbol.d b/compiler/src/dmd/backend/symbol.d index d1429ec8f199..1f5c35077bc4 100644 --- a/compiler/src/dmd/backend/symbol.d +++ b/compiler/src/dmd/backend/symbol.d @@ -279,10 +279,17 @@ bool Symbol_isAffected(const ref Symbol s) * 4. Const can be mutated by a separate view. * Address this in a separate PR. */ - if (0 && - s.ty() & (mTYconst | mTYimmutable)) + static if (0) + if (s.ty() & (mTYconst | mTYimmutable)) { - return false; + /* Disabled for the moment because even @safe functions + * may have inlined unsafe code from other functions + */ + if (funcsym_p.Sfunc.Fflags3 & F3safe && + s.ty() & mTYimmutable) + { + return false; + } } return true; } diff --git a/compiler/src/dmd/tocsym.d b/compiler/src/dmd/tocsym.d index d5d59833ecec..87ae5b0e039c 100644 --- a/compiler/src/dmd/tocsym.d +++ b/compiler/src/dmd/tocsym.d @@ -356,6 +356,9 @@ Symbol *toSymbol(Dsymbol s) else if (fd.isMember2() && fd.isStatic()) f.Fflags |= Fstatic; + if (fd.isSafe()) + f.Fflags3 |= F3safe; + if (fd.inlining == PINLINE.default_ && global.params.useInline || fd.inlining == PINLINE.always) { diff --git a/test/runnable/test21821.d b/test/runnable/test21821.d new file mode 100644 index 000000000000..d16331d1897a --- /dev/null +++ b/test/runnable/test21821.d @@ -0,0 +1,32 @@ +// REQUIRED_ARGS: -preview=fieldwise -O +// https://issues.dlang.org/show_bug.cgi?id=21821 + +// test case comes from unittests in core.lifetime + +void test() +{ + alias T = immutable(S); + T source; + T target; + copyEmplacex(source, target); + T expectedCopy = source; + assert(target == expectedCopy); +} + +struct S +{ + int x = 42; + this(this) { x += 10; } +} + +void copyEmplacex(ref immutable(S) source, ref immutable(S) target) @system +{ + import core.stdc.string : memcpy; + memcpy(cast(S*) &target, cast(S*) &source, S.sizeof); + (cast() target).__xpostblit(); // casting away immutable +} + +void main() +{ + test(); +}