diff --git a/src/dmd/astbase.d b/src/dmd/astbase.d index 226cd9ecce22..3a49b2a258e1 100644 --- a/src/dmd/astbase.d +++ b/src/dmd/astbase.d @@ -128,6 +128,7 @@ struct ASTBase scopeinferred = (1L << 49), // 'scope' has been inferred and should not be part of mangling future = (1L << 50), // introducing new base class function local = (1L << 51), // do not forward (see dmd.dsymbol.ForwardingScopeDsymbol). + returninferred = (1L << 52), // 'return' has been inferred and should not be part of mangling TYPECTOR = (STC.const_ | STC.immutable_ | STC.shared_ | STC.wild), FUNCATTR = (STC.ref_ | STC.nothrow_ | STC.nogc | STC.pure_ | STC.property | STC.safe | STC.trusted | STC.system), diff --git a/src/dmd/declaration.d b/src/dmd/declaration.d index 4101d011555a..0536cbf4bed7 100644 --- a/src/dmd/declaration.d +++ b/src/dmd/declaration.d @@ -258,6 +258,7 @@ enum STC : long scopeinferred = (1L << 49), // 'scope' has been inferred and should not be part of mangling future = (1L << 50), // introducing new base class function local = (1L << 51), // do not forward (see dmd.dsymbol.ForwardingScopeDsymbol). + returninferred = (1L << 52), // 'return' has been inferred and should not be part of mangling TYPECTOR = (STC.const_ | STC.immutable_ | STC.shared_ | STC.wild), FUNCATTR = (STC.ref_ | STC.nothrow_ | STC.nogc | STC.pure_ | STC.property | STC.safe | STC.trusted | STC.system), diff --git a/src/dmd/declaration.h b/src/dmd/declaration.h index b86987911ab2..9edd1c73d080 100644 --- a/src/dmd/declaration.h +++ b/src/dmd/declaration.h @@ -87,6 +87,7 @@ struct IntRange; #define STCscopeinferred 0x2000000000000LL // 'scope' has been inferred and should not be part of mangling #define STCfuture 0x4000000000000LL // introducing new base class function #define STClocal 0x8000000000000LL // do not forward (see dmd.dsymbol.ForwardingScopeDsymbol). +#define STCreturninferred 0x10000000000000LL // 'return' has been inferred and should not be part of mangling void ObjectNotFound(Identifier *id); diff --git a/src/dmd/dmangle.d b/src/dmd/dmangle.d index 6d05f17b0aac..01c23a4267ca 100644 --- a/src/dmd/dmangle.d +++ b/src/dmd/dmangle.d @@ -1066,7 +1066,8 @@ public: if (p.storageClass & STC.scope_ && !(p.storageClass & STC.scopeinferred)) buf.writeByte('M'); // 'return inout ref' is the same as 'inout ref' - if ((p.storageClass & (STC.return_ | STC.wild)) == STC.return_) + if ((p.storageClass & (STC.return_ | STC.wild)) == STC.return_ && + !(p.storageClass & STC.returninferred)) buf.writestring("Nk"); switch (p.storageClass & (STC.in_ | STC.out_ | STC.ref_ | STC.lazy_)) { diff --git a/src/dmd/escape.d b/src/dmd/escape.d index 944f51a4dcfd..a2874e793167 100644 --- a/src/dmd/escape.d +++ b/src/dmd/escape.d @@ -500,7 +500,8 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag) if (!va.isScope() && inferScope) { //printf("inferring scope for %s\n", va.toChars()); va.storage_class |= STC.scope_ | STC.scopeinferred; - va.storage_class |= v.storage_class & STC.return_; + if (v.storage_class & STC.return_) + va.storage_class |= STC.return_ | STC.returninferred; } continue; } @@ -1071,7 +1072,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) * Because dg.ptr points to x, this is returning dt.ptr+offset */ if (global.params.vsafe) - sc.func.storage_class |= STC.return_; + sc.func.storage_class |= STC.return_ | STC.returninferred; } } @@ -1141,14 +1142,14 @@ private void inferReturn(FuncDeclaration fd, VarDeclaration v) // v is a local in the current function //printf("for function '%s' inferring 'return' for variable '%s'\n", fd.toChars(), v.toChars()); - v.storage_class |= STC.return_; + v.storage_class |= STC.return_ | STC.returninferred; TypeFunction tf = cast(TypeFunction)fd.type; if (v == fd.vthis) { /* v is the 'this' reference, so mark the function */ - fd.storage_class |= STC.return_; + fd.storage_class |= STC.return_ | STC.returninferred; if (tf.ty == Tfunction) { //printf("'this' too %p %s\n", tf, sc.func.toChars()); @@ -1166,7 +1167,7 @@ private void inferReturn(FuncDeclaration fd, VarDeclaration v) Parameter p = tf.parameterList[i]; if (p.ident == v.ident) { - p.storageClass |= STC.return_; + p.storageClass |= STC.return_ | STC.returninferred; break; // there can be only one } } @@ -1807,7 +1808,7 @@ void eliminateMaybeScopes(VarDeclaration[] array) // v cannot be scope since it is assigned to a non-scope va notMaybeScope(v); if (!(v.storage_class & (STC.ref_ | STC.out_))) - v.storage_class &= ~STC.return_; + v.storage_class &= ~(STC.return_ | STC.returninferred); changes = true; } } diff --git a/test/compilable/scopeinfer.d b/test/compilable/scopeinfer.d new file mode 100644 index 000000000000..4c89bd45f963 --- /dev/null +++ b/test/compilable/scopeinfer.d @@ -0,0 +1,12 @@ +// PERMUTE_ARGS: -dip1000 + +// Mangling should be the same with or without inference of `return scope` + +@safe: + +auto foo(void* p) { return 0; } +static assert(typeof(foo).mangleof == "FNaNbNiNfPvZi"); + +auto bar(void* p) { return p; } +static assert(typeof(bar).mangleof == "FNaNbNiNfPvZQd"); +