Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DIP 1028 Make @safe the default #10709

Closed
wants to merge 1 commit into from
Closed
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
2 changes: 2 additions & 0 deletions src/dmd/cli.d
Original file line number Diff line number Diff line change
Expand Up @@ -757,6 +757,8 @@ dmd -cov -unittest myprog.d
"disable access to shared memory objects"),
Feature("in", "inMeansScopeConst",
"in means scope const"),
Feature("safedefault", "safeDefault",
"make @safe the default"),
];
}

Expand Down
18 changes: 15 additions & 3 deletions src/dmd/dcast.d
Original file line number Diff line number Diff line change
Expand Up @@ -2915,10 +2915,22 @@ Lagain:

if (tf1.trust == tf2.trust)
d.trust = tf1.trust;
else if (tf1.trust <= TRUST.system || tf2.trust <= TRUST.system)
d.trust = TRUST.system;
else if (global.params.safeDefault)
{
if (tf1.trust == TRUST.system || tf2.trust == TRUST.system)
d.trust = TRUST.system;
else if (tf1.trust == TRUST.trusted || tf2.trust == TRUST.trusted)
d.trust = TRUST.trusted;
else
d.trust = TRUST.default_;
}
else
d.trust = TRUST.trusted;
{
if (tf1.trust <= TRUST.system || tf2.trust <= TRUST.system)
d.trust = TRUST.system;
else
d.trust = TRUST.trusted;
}

Type tx = null;
if (t1.ty == Tdelegate)
Expand Down
8 changes: 6 additions & 2 deletions src/dmd/dmangle.d
Original file line number Diff line number Diff line change
Expand Up @@ -401,15 +401,19 @@ public:
if (ta.islive)
buf.writestring("Nm");

switch (ta.trust)
final switch (ta.trust)
{
case TRUST.default_:
if (global.params.safeDefault)
goto case TRUST.safe;
break;
case TRUST.trusted:
buf.writestring("Ne");
break;
case TRUST.safe:
buf.writestring("Nf");
break;
default:
case TRUST.system:
break;
}

Expand Down
7 changes: 4 additions & 3 deletions src/dmd/expressionsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -2346,10 +2346,10 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
}
//if (eprefix) printf("eprefix: %s\n", eprefix.toChars());

/* Test compliance with DIP1021
/* Test compliance with DIP1021 Argument Ownership and Function Calls
*/
if (global.params.useDIP1021 &&
tf.trust != TRUST.system && tf.trust != TRUST.trusted)
(tf.trust == TRUST.safe || tf.trust == TRUST.default_))
err |= checkMutableArguments(sc, fd, tf, ethis, arguments, false);

// If D linkage and variadic, add _arguments[] as first argument
Expand Down Expand Up @@ -4897,7 +4897,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
err = true;
}
if (tf.trust <= TRUST.system && sc.func.setUnsafe())
if ((tf.trust == TRUST.system || tf.trust == TRUST.default_ && !global.params.safeDefault) &&
sc.func.setUnsafe())
{
exp.error("`@safe` %s `%s` cannot call `@system` %s `%s`",
sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
Expand Down
4 changes: 3 additions & 1 deletion src/dmd/func.d
Original file line number Diff line number Diff line change
Expand Up @@ -1379,7 +1379,9 @@ extern (C++) class FuncDeclaration : Declaration
{
if (flags & FUNCFLAG.safetyInprocess)
setUnsafe();
return type.toTypeFunction().trust == TRUST.safe;
const trust = type.toTypeFunction().trust;
return trust == TRUST.safe ||
trust == TRUST.default_ && global.params.safeDefault;
}

final bool isSafeBypassingInference()
Expand Down
1 change: 1 addition & 0 deletions src/dmd/globals.d
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ extern (C++) struct Param
bool useExceptions = true; // support exception handling
bool noSharedAccess; // read/write access to shared memory objects
bool inMeansScopeConst; // `in` means `scope const`
bool safeDefault; // @safe is the default
bool betterC; // be a "better C" compiler; no dependency on D runtime
bool addMain; // add a default main() function
bool allInst; // generate code for all template instantiations
Expand Down
1 change: 1 addition & 0 deletions src/dmd/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ struct Param
bool useExceptions; // support exception handling
bool noSharedAccess; // read/write access to shared memory objects
bool inMeansScopeConst; // `in` means `scope const`
bool safeDefault; // @safe is the default
bool betterC; // be a "better C" compiler; no dependency on D runtime
bool addMain; // add a default main() function
bool allInst; // generate code for all template instantiations
Expand Down
15 changes: 12 additions & 3 deletions src/dmd/mtype.d
Original file line number Diff line number Diff line change
Expand Up @@ -759,7 +759,16 @@ extern (C++) abstract class Type : ASTNode

/* Can convert safe/trusted to system
*/
if (t1.trust <= TRUST.system && t2.trust >= TRUST.trusted)
if (global.params.safeDefault)
{
if (t1.trust == TRUST.system &&
(t2.trust == TRUST.default_ || t2.trust == TRUST.trusted || t2.trust == TRUST.safe))
{
// Should we infer trusted or safe? Go with safe.
stc |= STC.safe;
}
}
else if (t1.trust <= TRUST.system && t2.trust >= TRUST.trusted)
{
// Should we infer trusted or safe? Go with safe.
stc |= STC.safe;
Expand Down Expand Up @@ -4492,7 +4501,7 @@ extern (C++) final class TypeFunction : TypeNext
(stc & STC.nothrow_ && !t.isnothrow) ||
(stc & STC.nogc && !t.isnogc) ||
(stc & STC.scope_ && !t.isscope) ||
(stc & STC.safe && t.trust < TRUST.trusted))
(stc & STC.safe && (t.trust == TRUST.system || (!global.params.safeDefault && t.trust == TRUST.default_))))
{
// Klunky to change these
auto tf = new TypeFunction(t.parameterList, t.next, t.linkage, 0);
Expand Down Expand Up @@ -6787,7 +6796,7 @@ void attributesApply(const TypeFunction tf, void delegate(string) dg, TRUSTforma
if (trustAttrib == TRUST.default_)
{
if (trustFormat == TRUSTformatSystem)
trustAttrib = TRUST.system;
trustAttrib = global.params.safeDefault ? TRUST.safe : TRUST.system;
else
return; // avoid calling with an empty string
}
Expand Down
11 changes: 6 additions & 5 deletions src/dmd/toir.d
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,13 @@ struct IRState
case CHECKENABLE.safeonly:
{
result = false;
FuncDeclaration fd = getFunc();
if (fd)
if (auto fd = getFunc())
{
Type t = fd.type;
if (t.ty == Tfunction && (cast(TypeFunction)t).trust == TRUST.safe)
result = true;
if (auto tf = fd.type.isTypeFunction())
{
result = tf.trust == TRUST.safe ||
tf.trust == TRUST.default_ && global.params.safeDefault;
}
}
break;
}
Expand Down
1 change: 1 addition & 0 deletions test/compilable/previewhelp.d
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ Upcoming language changes listed by -preview=name:
=rvaluerefparam enable rvalue arguments to ref parameters
=nosharedaccess disable access to shared memory objects
=in in means scope const
=safedefault make @safe the default
----
*/
103 changes: 103 additions & 0 deletions test/fail_compilation/safedefault.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/* REQUIRED_ARGS: -preview=safedefault
*/

#line 50
void default_();
@system void system();
@trusted void trusted();
@safe void safe();

/*********************
* TEST_OUTPUT:
---
fail_compilation/safedefault.d(103): Error: `@safe` function `safedefault.test1` cannot call `@system` function `safedefault.system`
fail_compilation/safedefault.d(51): `safedefault.system` is declared here
---
*/

#line 100

void test1()
{
system();
}

/**********************/

void func2()()
{
system();
}

/**********************/

void func3()()
{
func3();
}

/**********************/

void func4()()
{
func5();
}

void func5()()
{
func4();
}

/**********************/

#line 600

void test6(bool b)
{
@safe void function() fp1 = b ? &default_ : &default_;
@system void function() fp2 = b ? &default_ : &system;
@trusted void function() fp3 = b ? &default_ : &trusted;
@safe void function() fp4 = b ? &default_ : &safe;

@system void function() fp5 = b ? &system : &system;
@system void function() fp6 = b ? &system : &trusted;
@system void function() fp7 = b ? &system : &safe;

@trusted void function() fp8 = b ? &trusted : &trusted;
@trusted void function() fp9 = b ? &trusted : &safe;

@safe void function() fp10 = b ? &safe : &safe;
}

/**********************/
/* TEST_OUTPUT:
---
fail_compilation/safedefault.d(703): Error: cannot implicitly convert expression `b ? & default_ : & system` of type `void function() @system` to `void function() @safe`
fail_compilation/safedefault.d(706): Error: cannot implicitly convert expression `b ? & system : & system` of type `void function() @system` to `void function() @safe`
fail_compilation/safedefault.d(707): Error: cannot implicitly convert expression `b ? & system : & trusted` of type `void function() @system` to `void function() @safe`
fail_compilation/safedefault.d(708): Error: cannot implicitly convert expression `b ? & system : & safe` of type `void function() @system` to `void function() @safe`
---
*/

#line 700

void test7(bool b)
{
@safe void function() fp2 = b ? &default_ : &system;
@safe void function() fp3 = b ? &default_ : &trusted;

@safe void function() fp5 = b ? &system : &system;
@safe void function() fp6 = b ? &system : &trusted;
@safe void function() fp7 = b ? &system : &safe;

@safe void function() fp8 = b ? &trusted : &trusted;
@safe void function() fp9 = b ? &trusted : &safe;
}

/******************************/

void test8(void delegate() dg)
{
dg();
}