Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/dmd/expressionsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -5122,6 +5122,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor

override void visit(DeleteExp exp)
{
// @@@DEPRECATED_2019-02@@@
// 1. Deprecation for 1 year
// 2. Error for 1 year
// 3. Removal of keyword, "delete" can be used for other identities
if (!exp.isRAII)
deprecation(exp.loc, "The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.");

if (Expression ex = unaSemantic(exp, sc))
{
result = ex;
Expand Down
5 changes: 0 additions & 5 deletions src/dmd/parse.d
Original file line number Diff line number Diff line change
Expand Up @@ -7747,11 +7747,6 @@ final class Parser(AST) : Lexer
case TOK.delete_:
nextToken();
e = parseUnaryExp();
// @@@DEPRECATED_2019-02@@@
// 1. Deprecation for 1 year
// 2. Error for 1 year
// 3. Removal, "delete" can be used for other identities
deprecation("The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.");
e = new AST.DeleteExp(loc, e, false);
break;

Expand Down
13 changes: 11 additions & 2 deletions src/dmd/statementsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -3094,16 +3094,25 @@ else
{
/* Determine "refness" of function return:
* if it's an lvalue, return by ref, else return by value
* https://dlang.org/spec/function.html#auto-ref-functions
*/

void turnOffRef()
{
tf.isref = false; // return by value
tf.isreturn = false; // ignore 'return' attribute, whether explicit or inferred
fd.storage_class &= ~STC.return_;
}

if (rs.exp.isLvalue())
{
/* May return by ref
*/
if (checkReturnEscapeRef(sc, rs.exp, true))
tf.isref = false; // return by value
turnOffRef();
}
else
tf.isref = false; // return by value
turnOffRef();

/* The "refness" is determined by all of return statements.
* This means:
Expand Down
15 changes: 15 additions & 0 deletions test/compilable/test17512.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// https://issues.dlang.org/show_bug.cgi?id=17512

struct A
{
int _value;

bool _hasValue;

auto ref getOr(int alternativeValue)
{
return _hasValue ? _value : alternativeValue;
}
}

A a;
42 changes: 18 additions & 24 deletions test/compilable/vgc1.d
Original file line number Diff line number Diff line change
@@ -1,15 +1,6 @@
// REQUIRED_ARGS: -vgc -o-
// PERMUTE_ARGS:

/*
TEST_OUTPUT:
---
compilable/vgc1.d(93): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
compilable/vgc1.d(94): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
compilable/vgc1.d(95): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
---
*/

/***************** NewExp *******************/

struct S1 { }
Expand All @@ -21,13 +12,13 @@ struct S5 { @nogc new(size_t); }
/*
TEST_OUTPUT:
---
compilable/vgc1.d(36): vgc: `new` causes a GC allocation
compilable/vgc1.d(27): vgc: `new` causes a GC allocation
compilable/vgc1.d(29): vgc: `new` causes a GC allocation
compilable/vgc1.d(30): vgc: `new` causes a GC allocation
compilable/vgc1.d(32): vgc: `new` causes a GC allocation
compilable/vgc1.d(33): vgc: `new` causes a GC allocation
compilable/vgc1.d(34): vgc: `new` causes a GC allocation
compilable/vgc1.d(38): vgc: `new` causes a GC allocation
compilable/vgc1.d(39): vgc: `new` causes a GC allocation
compilable/vgc1.d(41): vgc: `new` causes a GC allocation
compilable/vgc1.d(42): vgc: `new` causes a GC allocation
compilable/vgc1.d(43): vgc: `new` causes a GC allocation
compilable/vgc1.d(47): vgc: `new` causes a GC allocation
---
*/

Expand All @@ -50,12 +41,12 @@ void testNew()
/*
TEST_OUTPUT:
---
compilable/vgc1.d(64): vgc: `new` causes a GC allocation
compilable/vgc1.d(66): vgc: `new` causes a GC allocation
compilable/vgc1.d(67): vgc: `new` causes a GC allocation
compilable/vgc1.d(69): vgc: `new` causes a GC allocation
compilable/vgc1.d(70): vgc: `new` causes a GC allocation
compilable/vgc1.d(71): vgc: `new` causes a GC allocation
compilable/vgc1.d(55): vgc: `new` causes a GC allocation
compilable/vgc1.d(57): vgc: `new` causes a GC allocation
compilable/vgc1.d(58): vgc: `new` causes a GC allocation
compilable/vgc1.d(60): vgc: `new` causes a GC allocation
compilable/vgc1.d(61): vgc: `new` causes a GC allocation
compilable/vgc1.d(62): vgc: `new` causes a GC allocation
---
*/

Expand Down Expand Up @@ -83,9 +74,12 @@ void testNewScope()
/*
TEST_OUTPUT:
---
compilable/vgc1.d(93): vgc: `delete` requires the GC
compilable/vgc1.d(94): vgc: `delete` requires the GC
compilable/vgc1.d(95): vgc: `delete` requires the GC
compilable/vgc1.d(87): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
compilable/vgc1.d(87): vgc: `delete` requires the GC
compilable/vgc1.d(88): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
compilable/vgc1.d(88): vgc: `delete` requires the GC
compilable/vgc1.d(89): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
compilable/vgc1.d(89): vgc: `delete` requires the GC
---
*/
void testDelete(int* p, Object o, S1* s)
Expand Down
Loading