@@ -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 ;
0 commit comments