mirror of
https://github.com/dlang/dmd.git
synced 2025-04-26 05:00:16 +03:00
Implement Safer D (#17044)
This commit is contained in:
parent
519d388498
commit
347c883586
9 changed files with 48 additions and 6 deletions
3
changelog/dmd.safer.dd
Normal file
3
changelog/dmd.safer.dd
Normal file
|
@ -0,0 +1,3 @@
|
|||
This adds `-preview=safer` which enables safety checking on un-attributed functions.
|
||||
|
||||
For more information, see: [safer.md](https://github.com/WalterBright/documents/blob/38f0a846726b571f8108f6e63e5e217b91421c86/safer.md)
|
|
@ -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"),
|
||||
|
|
|
@ -8252,6 +8252,7 @@ struct Param final
|
|||
FeatureState fieldwise;
|
||||
bool fixAliasThis;
|
||||
FeatureState rvalueRefParam;
|
||||
FeatureState safer;
|
||||
FeatureState noSharedAccess;
|
||||
bool previewIn;
|
||||
bool inclusiveInContracts;
|
||||
|
@ -8386,7 +8387,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),
|
||||
|
@ -8420,6 +8421,7 @@ struct Param final
|
|||
fieldwise(fieldwise),
|
||||
fixAliasThis(fixAliasThis),
|
||||
rvalueRefParam(rvalueRefParam),
|
||||
safer(safer),
|
||||
noSharedAccess(noSharedAccess),
|
||||
previewIn(previewIn),
|
||||
inclusiveInContracts(inclusiveInContracts),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -27,7 +27,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;
|
||||
|
@ -317,6 +317,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)
|
||||
|
@ -365,7 +375,7 @@ extern (D) void reportSafeError(FuncDeclaration fd, bool gag, Loc loc,
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (fd.isSafe())
|
||||
else if (fd.isSafe() || fd.isSaferD())
|
||||
{
|
||||
if (!gag && format)
|
||||
.error(loc, format, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
|
||||
|
@ -393,7 +403,7 @@ extern (D) bool setFunctionToUnsafe(FuncDeclaration fd)
|
|||
setFunctionToUnsafe(fd.fes.func);
|
||||
return true;
|
||||
}
|
||||
else if (fd.isSafe())
|
||||
else if (fd.isSafe() || fd.isSaferD())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ import dmd.opover;
|
|||
import dmd.parse;
|
||||
import dmd.common.outbuffer;
|
||||
import dmd.root.string;
|
||||
import dmd.safe : isSafe, setUnsafe;
|
||||
import dmd.safe : isSafe, isSaferD, setUnsafe;
|
||||
import dmd.semantic2;
|
||||
import dmd.sideeffect;
|
||||
import dmd.statement;
|
||||
|
@ -1987,7 +1987,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
|
|||
}
|
||||
|
||||
ss.hasDefault = sc.sw.sdefault ||
|
||||
!(!ss.isFinal || needswitcherror || global.params.useAssert == CHECKENABLE.on || sc.func.isSafe);
|
||||
!(!ss.isFinal || needswitcherror || global.params.useAssert == CHECKENABLE.on || sc.func.isSafe || sc.func.isSaferD);
|
||||
if (!ss.hasDefault)
|
||||
{
|
||||
if (!ss.isFinal && (!ss._body || !ss._body.isErrorStatement()) && !sc.inCfile)
|
||||
|
|
|
@ -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)
|
||||
|
|
18
compiler/test/fail_compilation/safer.d
Normal file
18
compiler/test/fail_compilation/safer.d
Normal file
|
@ -0,0 +1,18 @@
|
|||
/* REQUIRED_ARGS: -preview=safer
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/safer.d(10): Error: `void` initializers for pointers not allowed in safe functions
|
||||
---
|
||||
*/
|
||||
|
||||
void test1()
|
||||
{
|
||||
int* p = void;
|
||||
}
|
||||
|
||||
void foo3() { }
|
||||
|
||||
void test2()
|
||||
{
|
||||
foo3(); // should not be an error
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue