Skip to content

Commit a010245

Browse files
authored
adjust return scope detection (dlang#21369)
1 parent b8f1ef8 commit a010245

21 files changed

Lines changed: 120 additions & 46 deletions

File tree

compiler/src/dmd/astenums.d

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,10 @@ enum STC : ulong // transfer changes to declaration.h
7777
ref_ = 0x4_0000, /// `ref`
7878
scope_ = 0x8_0000, /// `scope`
7979

80-
scopeinferred = 0x20_0000, /// `scope` has been inferred and should not be part of mangling, `scope_` must also be set
81-
return_ = 0x40_0000, /// 'return ref' or 'return scope' for function parameters
82-
returnScope = 0x80_0000, /// if `ref return scope` then resolve to `ref` and `return scope`
80+
scopeinferred = 0x10_0000, /// `scope` has been inferred and should not be part of mangling, `scope_` must also be set
81+
return_ = 0x20_0000, /// 'return ref' or 'return scope' for function parameters
82+
returnScope = 0x40_0000, /// if `ref return scope` then resolve to `ref` and `return scope`
83+
returnRef = 0x80_0000, /// if `return ref`
8384

8485
returninferred = 0x100_0000, /// `return` has been inferred and should not be part of mangling, `return_` must also be set
8586
immutable_ = 0x200_0000, /// `immutable`

compiler/src/dmd/declaration.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,10 @@ namespace dmd
7171
#define STCref 0x40000ULL /// `ref`
7272
#define STCscope 0x80000ULL /// `scope`
7373

74-
#define STCscopeinferred 0x200000ULL /// `scope` has been inferred and should not be part of mangling, `scope` must also be set
75-
#define STCreturn 0x400000ULL /// 'return ref' or 'return scope' for function parameters
76-
#define STCreturnScope 0x800000ULL /// if `ref return scope` then resolve to `ref` and `return scope`
74+
#define STCscopeinferred 0x100000ULL /// `scope` has been inferred and should not be part of mangling, `scope` must also be set
75+
#define STCreturn 0x200000ULL /// 'return ref' or 'return scope' for function parameters
76+
#define STCreturnScope 0x400000ULL /// if `ref return scope` then resolve to `ref` and `return scope`
77+
#define STCreturnRef 0x800000ULL, /// if `return ref`
7778

7879
#define STCreturninferred 0x1000000ULL /// `return` has been inferred and should not be part of mangling, `return` must also be set
7980
#define STCimmutable 0x2000000ULL /// `immutable`

compiler/src/dmd/expressionsem.d

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2373,7 +2373,7 @@ private bool checkNogc(FuncDeclaration f, ref Loc loc, Scope* sc)
23732373
* t = struct type, or static array of struct type to check
23742374
* loc = error message location
23752375
* sc = scope in which attributes are checked
2376-
* Returns: true if there's an error
2376+
* Returns: true if there is an error
23772377
*/
23782378
private bool checkPostblit(Type t, ref Loc loc, Scope* sc)
23792379
{
@@ -15531,7 +15531,7 @@ Expression addDtorHook(Expression e, Scope* sc)
1553115531
/*******************************
1553215532
* Try to convert an expression to be an lvalue.
1553315533
*
15534-
* Give error if we're not an lvalue.
15534+
* Give error if we are not an lvalue.
1553515535
* Params:
1553615536
* _this = expression to convert
1553715537
* sc = scope
@@ -15546,6 +15546,7 @@ Expression toLvalue(Expression _this, Scope* sc, const(char)* action)
1554615546
// e = original un-lowered expression for error messages, in case of recursive calls
1554715547
private Expression toLvalueImpl(Expression _this, Scope* sc, const(char)* action, Expression e)
1554815548
{
15549+
//printf("toLvalueImpl() %s\n", _this.toChars());
1554915550
if (!action)
1555015551
action = "create lvalue of";
1555115552

@@ -15643,7 +15644,7 @@ private Expression toLvalueImpl(Expression _this, Scope* sc, const(char)* action
1564315644
{
1564415645
auto e1 = _this.e1;
1564515646
auto var = _this.var;
15646-
//printf("DotVarExp::toLvalue(%s)\n", toChars());
15647+
//printf("DotVarExp::toLvalue(%s)\n", _this.toChars());
1564715648
if (sc && sc.inCfile)
1564815649
{
1564915650
/* C11 6.5.2.3-3: A postfix expression followed by the '.' or '->' operator

compiler/src/dmd/frontend.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -772,9 +772,10 @@ enum class STC : uint64_t
772772
templateparameter = 131072LLU,
773773
ref_ = 262144LLU,
774774
scope_ = 524288LLU,
775-
scopeinferred = 2097152LLU,
776-
return_ = 4194304LLU,
777-
returnScope = 8388608LLU,
775+
scopeinferred = 1048576LLU,
776+
return_ = 2097152LLU,
777+
returnScope = 4194304LLU,
778+
returnRef = 8388608LLU,
778779
returninferred = 16777216LLU,
779780
immutable_ = 33554432LLU,
780781
manifest = 134217728LLU,
@@ -809,9 +810,9 @@ enum class STC : uint64_t
809810
IOR = 333824LLU,
810811
TYPECTOR = 42983227396LLU,
811812
FUNCATTR = 4575000774574080LLU,
812-
visibleStorageClasses = 7954966262857631LLU,
813+
visibleStorageClasses = 7954966260760479LLU,
813814
flowThruAggregate = 962072674304LLU,
814-
flowThruFunction = 18446742978991225440LLU,
815+
flowThruFunction = 18446742978993322592LLU,
815816
};
816817

817818
template <typename T>

compiler/src/dmd/hdrgen.d

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1814,7 +1814,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs)
18141814

18151815
// https://issues.dlang.org/show_bug.cgi?id=24891
18161816
// return/scope storage classes are printed as part of function type
1817-
if (stcToBuffer(buf, f.storage_class & ~(STC.scope_ | STC.return_ | STC.returnScope)))
1817+
if (stcToBuffer(buf, f.storage_class & ~(STC.scope_ | STC.return_ | STC.returnScope | STC.returnRef)))
18181818
buf.writeByte(' ');
18191819
typeToBuffer(f.type, f.ident, buf, hgs);
18201820
auto tf = f.type.isTypeFunction();

compiler/src/dmd/objc_glue.d

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1617,7 +1617,7 @@ void xoffOrNull(ref DtBuilder dtb, Symbol* symbol) @safe
16171617
* given buffer `buffer`
16181618
*/
16191619
const(char)* toStringz(size_t maxLength = 4095)(in const(char)[] str,
1620-
scope return void[] buffer = alloca(maxLength + 1)[0 .. maxLength + 1]) pure
1620+
return scope void[] buffer = alloca(maxLength + 1)[0 .. maxLength + 1]) pure
16211621
in
16221622
{
16231623
assert(maxLength >= str.length);

compiler/src/dmd/parse.d

Lines changed: 75 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1286,6 +1286,38 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
12861286
return orig;
12871287
}
12881288

1289+
if (0) // replace this with -preview=return in next PR
1290+
switch (orig & (STC.out_ | STC.ref_ | STC.scope_ | STC.return_))
1291+
{
1292+
case STC.return_ | STC.ref_:
1293+
if (!(orig & STC.returnRef))
1294+
error("`return` `ref` attribute pair must be written as '`return ref`'");
1295+
break;
1296+
1297+
case STC.return_ | STC.out_:
1298+
if (!(orig & STC.returnRef))
1299+
error("`return` `out` attribute pair must be written as '`return out`'");
1300+
break;
1301+
1302+
case STC.return_ | STC.scope_:
1303+
if (!(orig & STC.returnScope))
1304+
error("`return` `scope` attribute pair must be written as '`return scope`'");
1305+
break;
1306+
1307+
case STC.return_ | STC.ref_ | STC.scope_:
1308+
if (!(orig & (STC.returnRef | STC.returnScope)))
1309+
error("`return` `ref` `scope` attribute triple must be written as '`return ref`' and '`scope`' or '`return scope`' and '`ref`'");
1310+
break;
1311+
1312+
case STC.return_ | STC.out_ | STC.scope_:
1313+
if (!(orig & (STC.returnRef | STC.returnScope)))
1314+
error("`return` `out` `scope` attribute triple must be written as '`return out`' and '`scope`' or '`return scope`' and '`out`'");
1315+
break;
1316+
1317+
default:
1318+
break;
1319+
}
1320+
12891321
checkConflictSTCGroup(STC.const_ | STC.immutable_ | STC.manifest);
12901322
checkConflictSTCGroup(STC.gshared | STC.shared_);
12911323
checkConflictSTCGroup!true(STC.safeGroup);
@@ -1397,6 +1429,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
13971429
*/
13981430
private STC parsePostfix(STC storageClass, AST.Expressions** pudas)
13991431
{
1432+
const STC prefix = storageClass;
14001433
while (1)
14011434
{
14021435
STC stc;
@@ -1427,10 +1460,23 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
14271460
break;
14281461

14291462
case TOK.return_:
1463+
{
14301464
stc = STC.return_;
1431-
if (peekNext() == TOK.scope_)
1432-
stc |= STC.returnScope; // recognize `return scope`
1465+
TOK next = peekNext();
1466+
if (next == TOK.scope_) // recognize the `return scope` pair
1467+
{
1468+
stc |= STC.scope_ | STC.returnScope;
1469+
nextToken(); // consume it
1470+
}
1471+
else if (next == TOK.ref_) // recognize the `return ref` pair
1472+
{
1473+
stc |= STC.ref_ | STC.returnRef;
1474+
nextToken(); // consume it
1475+
}
1476+
else if (prefix & STC.ref_) // https://dlang.org/spec/function.html#struct-return-methods
1477+
stc |= STC.returnRef; // treat member function `ref int fp() return;` as `int fp() return ref;`
14331478
break;
1479+
}
14341480

14351481
case TOK.scope_:
14361482
stc = STC.scope_;
@@ -1469,6 +1515,14 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
14691515
nextToken();
14701516
continue;
14711517
}
1518+
1519+
/* This is so we can enforce `return ref`, but not foul things up with an extra `ref`
1520+
* which is not accounted for in the semantic routines. The problem comes about because
1521+
* there's no way to attach `return ref` to the implicit `this` parameter but not the return value.
1522+
*/
1523+
if (!(prefix & STC.ref_) && storageClass & STC.ref_ && storageClass & STC.returnRef)
1524+
storageClass &= ~STC.ref_;
1525+
14721526
return storageClass;
14731527
}
14741528
storageClass = appendStorageClass(storageClass, stc);
@@ -2813,7 +2867,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
28132867
STC varargsStc;
28142868

28152869
// Attributes allowed for ...
2816-
enum VarArgsStc = STC.const_ | STC.immutable_ | STC.shared_ | STC.scope_ | STC.return_ | STC.returnScope;
2870+
enum VarArgsStc = STC.const_ | STC.immutable_ | STC.shared_ | STC.scope_ | STC.return_ | STC.returnScope | STC.returnRef;
28172871

28182872
check(TOK.leftParenthesis);
28192873
while (1)
@@ -2924,10 +2978,26 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
29242978
goto L2;
29252979

29262980
case TOK.return_:
2981+
{
29272982
stc = STC.return_;
2928-
if (peekNext() == TOK.scope_)
2929-
stc |= STC.returnScope;
2983+
TOK next = peekNext();
2984+
if (next == TOK.scope_) // recognize the `return scope` pair
2985+
{
2986+
stc |= STC.scope_ | STC.returnScope;
2987+
nextToken(); // consume it
2988+
}
2989+
else if (next == TOK.ref_) // recognize the `return ref` pair
2990+
{
2991+
stc |= STC.ref_ | STC.returnRef;
2992+
nextToken(); // consume it
2993+
}
2994+
else if (next == TOK.out_) // recognize the `return out` pair
2995+
{
2996+
stc |= STC.out_ | STC.returnRef;
2997+
nextToken(); // consume it
2998+
}
29302999
goto L2;
3000+
}
29313001
L2:
29323002
storageClass = appendStorageClass(storageClass, stc);
29333003
continue;

compiler/test/compilable/extra-files/header1.d

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,7 @@ struct SafeS
566566
{
567567
this(int[1] x) scope {}
568568
this(int[2] x) return scope {}
569-
this(int[3] x) scope return {}
569+
this(int[3] x) return ref scope {}
570570
this(int[4] x) return {}
571571

572572
@safe:

compiler/test/compilable/shared.d

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ pure nothrow @nogc ref @safe shared(C1)(return ref shared(C1) c)
55
pure nothrow @nogc ref @safe shared(int)(return ref shared(C3) c)
66
---
77
*/
8-
ref shared(int) f(return shared ref int y)
8+
ref shared(int) f(return ref shared int y)
99
{
1010
return y;
1111
}
@@ -97,7 +97,7 @@ shared(C2)* test_dotvarexp_4(return ref shared C3 c)
9797
return &c.c2;
9898
}
9999

100-
ref shared(int) test_dotvarexp_5(return shared ref C3 c)
100+
ref shared(int) test_dotvarexp_5(return ref shared C3 c)
101101
{
102102
return c.c1.c1.value;
103103
}

compiler/test/compilable/test23169.d

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ struct Ptr
55
{
66
int* impl;
77
void* fun0() return scope {return impl;}
8-
void* fun1() scope return {return impl;}
8+
void* fun1() scope return ref {return impl;}
99
void* fun2() return {return &this;}
1010
}
1111

0 commit comments

Comments
 (0)