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

add nascent implementation of Safer D #17044

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
3 changes: 3 additions & 0 deletions compiler/src/dmd/cli.d
Original file line number Diff line number Diff line change
Expand Up @@ -972,6 +972,9 @@ dmd -cov -unittest myprog.d
Feature("rvaluerefparam", "rvalueRefParam",
"enable rvalue arguments to ref parameters",
"https://gist.github.com/andralex/e5405a5d773f07f73196c05f8339435a"),
Feature("safer", "safer",
"more safety checks by default",
"https://github.com/WalterBright/documents/blob/38f0a846726b571f8108f6e63e5e217b91421c86/safer.md", true, false),
Feature("nosharedaccess", "noSharedAccess",
"disable access to shared memory objects",
"https://dlang.org/spec/const3.html#shared"),
Expand Down
9 changes: 7 additions & 2 deletions compiler/src/dmd/dsymbolsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -1137,8 +1137,13 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
// __swap variable, which can be trusted

if (dsym.type.hasPointers()) // also computes type size
sc.setUnsafe(false, dsym.loc,
"`void` initializers for pointers not allowed in safe functions");
{
if (isSaferD(sc.func))
error(dsym.loc, "`void` initializers for pointers not allowed by default, remove `= void` for default initialization or annotate with `@trusted` or `@system`");
else
sc.setUnsafe(false, dsym.loc,
"`void` initializers for pointers not allowed in safe functions");
}
else if (dsym.type.hasInvariant())
sc.setUnsafe(false, dsym.loc,
"`void` initializers for structs with invariants are not allowed in safe functions");
Expand Down
4 changes: 3 additions & 1 deletion compiler/src/dmd/frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -8257,6 +8257,7 @@ struct Param final
FeatureState fieldwise;
bool fixAliasThis;
FeatureState rvalueRefParam;
FeatureState safer;
FeatureState noSharedAccess;
bool previewIn;
bool inclusiveInContracts;
Expand Down Expand Up @@ -8391,7 +8392,7 @@ struct Param final
timeTraceFile()
{
}
Param(bool obj, bool multiobj = false, bool trace = false, bool tracegc = false, bool vcg_ast = false, DiagnosticReporting useDeprecated = (DiagnosticReporting)1u, bool useUnitTests = false, bool useInline = false, bool release = false, bool preservePaths = false, DiagnosticReporting useWarnings = (DiagnosticReporting)2u, bool cov = false, uint8_t covPercent = 0u, bool ctfe_cov = false, bool ignoreUnsupportedPragmas = true, bool useModuleInfo = true, bool useTypeInfo = true, bool useExceptions = true, bool useGC = true, bool betterC = false, bool addMain = false, bool allInst = false, bool bitfields = false, CppStdRevision cplusplus = (CppStdRevision)201103u, Help help = Help(), Verbose v = Verbose(), FeatureState useDIP25 = (FeatureState)2u, FeatureState useDIP1000 = (FeatureState)0u, bool ehnogc = false, bool useDIP1021 = false, FeatureState fieldwise = (FeatureState)0u, bool fixAliasThis = false, FeatureState rvalueRefParam = (FeatureState)0u, FeatureState noSharedAccess = (FeatureState)0u, bool previewIn = false, bool inclusiveInContracts = false, bool shortenedMethods = true, bool fixImmutableConv = false, bool fix16997 = true, FeatureState dtorFields = (FeatureState)0u, FeatureState systemVariables = (FeatureState)0u, CHECKENABLE useInvariants = (CHECKENABLE)0u, CHECKENABLE useIn = (CHECKENABLE)0u, CHECKENABLE useOut = (CHECKENABLE)0u, CHECKENABLE useArrayBounds = (CHECKENABLE)0u, CHECKENABLE useAssert = (CHECKENABLE)0u, CHECKENABLE useSwitchError = (CHECKENABLE)0u, CHECKENABLE boundscheck = (CHECKENABLE)0u, CHECKACTION checkAction = (CHECKACTION)0u, CLIIdentifierTable dIdentifierTable = (CLIIdentifierTable)0u, CLIIdentifierTable cIdentifierTable = (CLIIdentifierTable)0u, _d_dynamicArray< const char > argv0 = {}, Array<const char* > modFileAliasStrings = Array<const char* >(), Array<const char* > imppath = Array<const char* >(), Array<const char* > fileImppath = Array<const char* >(), _d_dynamicArray< const char > objdir = {}, _d_dynamicArray< const char > objname = {}, _d_dynamicArray< const char > libname = {}, Output ddoc = Output(), Output dihdr = Output(), Output cxxhdr = Output(), Output json = Output(), JsonFieldFlags jsonFieldFlags = (JsonFieldFlags)0u, Output makeDeps = Output(), Output mixinOut = Output(), Output moduleDeps = Output(), uint32_t debuglevel = 0u, uint32_t versionlevel = 0u, bool run = false, Array<const char* > runargs = Array<const char* >(), Array<const char* > cppswitches = Array<const char* >(), const char* cpp = nullptr, Array<const char* > objfiles = Array<const char* >(), Array<const char* > linkswitches = Array<const char* >(), Array<bool > linkswitchIsForCC = Array<bool >(), Array<const char* > libfiles = Array<const char* >(), Array<const char* > dllfiles = Array<const char* >(), _d_dynamicArray< const char > deffile = {}, _d_dynamicArray< const char > resfile = {}, _d_dynamicArray< const char > exefile = {}, _d_dynamicArray< const char > mapfile = {}, bool fullyQualifiedObjectFiles = false, bool timeTrace = false, uint32_t timeTraceGranularityUs = 500u, const char* timeTraceFile = nullptr) :
Param(bool obj, bool multiobj = false, bool trace = false, bool tracegc = false, bool vcg_ast = false, DiagnosticReporting useDeprecated = (DiagnosticReporting)1u, bool useUnitTests = false, bool useInline = false, bool release = false, bool preservePaths = false, DiagnosticReporting useWarnings = (DiagnosticReporting)2u, bool cov = false, uint8_t covPercent = 0u, bool ctfe_cov = false, bool ignoreUnsupportedPragmas = true, bool useModuleInfo = true, bool useTypeInfo = true, bool useExceptions = true, bool useGC = true, bool betterC = false, bool addMain = false, bool allInst = false, bool bitfields = false, CppStdRevision cplusplus = (CppStdRevision)201103u, Help help = Help(), Verbose v = Verbose(), FeatureState useDIP25 = (FeatureState)2u, FeatureState useDIP1000 = (FeatureState)0u, bool ehnogc = false, bool useDIP1021 = false, FeatureState fieldwise = (FeatureState)0u, bool fixAliasThis = false, FeatureState rvalueRefParam = (FeatureState)0u, FeatureState safer = (FeatureState)0u, FeatureState noSharedAccess = (FeatureState)0u, bool previewIn = false, bool inclusiveInContracts = false, bool shortenedMethods = true, bool fixImmutableConv = false, bool fix16997 = true, FeatureState dtorFields = (FeatureState)0u, FeatureState systemVariables = (FeatureState)0u, CHECKENABLE useInvariants = (CHECKENABLE)0u, CHECKENABLE useIn = (CHECKENABLE)0u, CHECKENABLE useOut = (CHECKENABLE)0u, CHECKENABLE useArrayBounds = (CHECKENABLE)0u, CHECKENABLE useAssert = (CHECKENABLE)0u, CHECKENABLE useSwitchError = (CHECKENABLE)0u, CHECKENABLE boundscheck = (CHECKENABLE)0u, CHECKACTION checkAction = (CHECKACTION)0u, CLIIdentifierTable dIdentifierTable = (CLIIdentifierTable)0u, CLIIdentifierTable cIdentifierTable = (CLIIdentifierTable)0u, _d_dynamicArray< const char > argv0 = {}, Array<const char* > modFileAliasStrings = Array<const char* >(), Array<const char* > imppath = Array<const char* >(), Array<const char* > fileImppath = Array<const char* >(), _d_dynamicArray< const char > objdir = {}, _d_dynamicArray< const char > objname = {}, _d_dynamicArray< const char > libname = {}, Output ddoc = Output(), Output dihdr = Output(), Output cxxhdr = Output(), Output json = Output(), JsonFieldFlags jsonFieldFlags = (JsonFieldFlags)0u, Output makeDeps = Output(), Output mixinOut = Output(), Output moduleDeps = Output(), uint32_t debuglevel = 0u, uint32_t versionlevel = 0u, bool run = false, Array<const char* > runargs = Array<const char* >(), Array<const char* > cppswitches = Array<const char* >(), const char* cpp = nullptr, Array<const char* > objfiles = Array<const char* >(), Array<const char* > linkswitches = Array<const char* >(), Array<bool > linkswitchIsForCC = Array<bool >(), Array<const char* > libfiles = Array<const char* >(), Array<const char* > dllfiles = Array<const char* >(), _d_dynamicArray< const char > deffile = {}, _d_dynamicArray< const char > resfile = {}, _d_dynamicArray< const char > exefile = {}, _d_dynamicArray< const char > mapfile = {}, bool fullyQualifiedObjectFiles = false, bool timeTrace = false, uint32_t timeTraceGranularityUs = 500u, const char* timeTraceFile = nullptr) :
obj(obj),
multiobj(multiobj),
trace(trace),
Expand Down Expand Up @@ -8425,6 +8426,7 @@ struct Param final
fieldwise(fieldwise),
fixAliasThis(fixAliasThis),
rvalueRefParam(rvalueRefParam),
safer(safer),
noSharedAccess(noSharedAccess),
previewIn(previewIn),
inclusiveInContracts(inclusiveInContracts),
Expand Down
2 changes: 2 additions & 0 deletions compiler/src/dmd/globals.d
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,8 @@ extern (C++) struct Param
// https://gist.github.com/andralex/e5405a5d773f07f73196c05f8339435a
// https://digitalmars.com/d/archives/digitalmars/D/Binding_rvalues_to_ref_parameters_redux_325087.html
// Implementation: https://github.com/dlang/dmd/pull/9817
FeatureState safer; // safer by default (more @safe checks in unattributed code)
// https://github.com/WalterBright/documents/blob/38f0a846726b571f8108f6e63e5e217b91421c86/safer.md
FeatureState noSharedAccess; // read/write access to shared memory objects
bool previewIn; // `in` means `[ref] scope const`, accepts rvalues
bool inclusiveInContracts; // 'in' contracts of overridden methods must be a superset of parent contract
Expand Down
3 changes: 3 additions & 0 deletions compiler/src/dmd/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,9 @@ struct Param
// https://gist.github.com/andralex/e5405a5d773f07f73196c05f8339435a
// https://digitalmars.com/d/archives/digitalmars/D/Binding_rvalues_to_ref_parameters_redux_325087.html
// Implementation: https://github.com/dlang/dmd/pull/9817
FeatureState safer; // safer by default (more @safe checks in unattributed code)
// https://github.com/WalterBright/documents/blob/38f0a846726b571f8108f6e63e5e217b91421c86/safer.md

FeatureState noSharedAccess; // read/write access to shared memory objects
d_bool previewIn; // `in` means `[ref] scope const`, accepts rvalues
d_bool inclusiveInContracts; // 'in' contracts of overridden methods must be a superset of parent contract
Expand Down
12 changes: 11 additions & 1 deletion compiler/src/dmd/safe.d
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import dmd.errors;
import dmd.expression;
import dmd.func;
import dmd.funcsem : isRootTraitsCompilesScope;
import dmd.globals : FeatureState;
import dmd.globals : FeatureState, global;
import dmd.id;
import dmd.identifier;
import dmd.location;
Expand Down Expand Up @@ -316,6 +316,16 @@ bool checkUnsafeDotExp(Scope* sc, Expression e, Identifier id, int flag)
return false;
}

/**************************************
* Safer D adds safety checks to functions with the default
* trust setting.
*/
bool isSaferD(FuncDeclaration fd)
{
return fd.type.toTypeFunction().trust == TRUST.default_ &&
global.params.safer == FeatureState.enabled;
}

bool isSafe(FuncDeclaration fd)
{
if (fd.safetyInprocess)
Expand Down
1 change: 1 addition & 0 deletions compiler/test/compilable/previewhelp.d
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Upcoming language changes listed by -preview=name:
=fieldwise use fieldwise comparisons for struct equality (https://dlang.org/changelog/2.085.0.html#no-cmpsb)
=fixAliasThis when a symbol is resolved, check alias this scope before going to upper scopes (https://github.com/dlang/dmd/pull/8885)
=rvaluerefparam enable rvalue arguments to ref parameters (https://gist.github.com/andralex/e5405a5d773f07f73196c05f8339435a)
=safer more safety checks by default (https://github.com/WalterBright/documents/blob/38f0a846726b571f8108f6e63e5e217b91421c86/safer.md)
=nosharedaccess disable access to shared memory objects (https://dlang.org/spec/const3.html#shared)
=in `in` on parameters means `scope const [ref]` and accepts rvalues (https://dlang.org/spec/function.html#in-params)
=inclusiveincontracts 'in' contracts of overridden methods must be a superset of parent contract (https://dlang.org/changelog/2.095.0.html#inclusive-incontracts)
Expand Down
11 changes: 11 additions & 0 deletions compiler/test/fail_compilation/safer.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/* REQUIRED_ARGS: -preview=safer
TEST_OUTPUT:
---
fail_compilation/safer.d(10): Error: `void` initializers for pointers not allowed by default, remove `= void` for default initialization or annotate with `@trusted` or `@system`
---
*/

void test1()
{
int* p = void;
}
Loading