Skip to content

Commit

Permalink
move isSafe/setUnsafe to safe.d (#16871)
Browse files Browse the repository at this point in the history
  • Loading branch information
thewilsonator authored Oct 5, 2024
1 parent 2d128bd commit cbc0183
Show file tree
Hide file tree
Showing 10 changed files with 193 additions and 179 deletions.
1 change: 1 addition & 0 deletions compiler/src/dmd/dcast.d
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import dmd.root.ctfloat;
import dmd.common.outbuffer;
import dmd.root.rmem;
import dmd.root.utf;
import dmd.safe : setUnsafe;
import dmd.tokens;
import dmd.typesem;

Expand Down
1 change: 1 addition & 0 deletions compiler/src/dmd/dsymbolsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ import dmd.root.filename;
import dmd.common.outbuffer;
import dmd.root.rmem;
import dmd.rootobject;
import dmd.safe;
import dmd.semantic2;
import dmd.semantic3;
import dmd.sideeffect;
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dmd/escape.d
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import dmd.location;
import dmd.mtype;
import dmd.printast;
import dmd.rootobject;
import dmd.safe;
import dmd.tokens;
import dmd.typesem : hasPointers, parameterStorageClass;
import dmd.visitor;
Expand Down
2 changes: 0 additions & 2 deletions compiler/src/dmd/frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -3773,8 +3773,6 @@ class FuncDeclaration : public Declaration
bool isCodeseg() const final override;
bool isOverloadable() const final override;
bool isAbstract() final override;
bool isSafe();
bool isTrusted();
virtual bool isNested() const;
AggregateDeclaration* isThis() override;
bool needThis() final override;
Expand Down
66 changes: 0 additions & 66 deletions compiler/src/dmd/func.d
Original file line number Diff line number Diff line change
Expand Up @@ -685,72 +685,6 @@ extern (C++) class FuncDeclaration : Declaration
return bitFields;
}

final bool isSafe()
{
if (safetyInprocess)
setUnsafe();
return type.toTypeFunction().trust == TRUST.safe;
}

extern (D) final bool isSafeBypassingInference()
{
return !(safetyInprocess) && isSafe();
}

final bool isTrusted()
{
if (safetyInprocess)
setUnsafe();
return type.toTypeFunction().trust == TRUST.trusted;
}

/**************************************
* The function is doing something unsafe, so mark it as unsafe.
*
* Params:
* gag = surpress error message (used in escape.d)
* loc = location of error
* fmt = printf-style format string
* arg0 = (optional) argument for first %s format specifier
* arg1 = (optional) argument for second %s format specifier
* arg2 = (optional) argument for third %s format specifier
* Returns: whether there's a safe error
*/
extern (D) final bool setUnsafe(
bool gag = false, Loc loc = Loc.init, const(char)* fmt = null,
RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
{
if (safetyInprocess)
{
safetyInprocess = false;
type.toTypeFunction().trust = TRUST.system;
if (fmt || arg0)
safetyViolation = new AttributeViolation(loc, fmt, arg0, arg1, arg2);

if (fes)
fes.func.setUnsafe();
}
else if (isSafe())
{
if (!gag && fmt)
.error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");

return true;
}
return false;
}

/**************************************
* The function is calling `@system` function `f`, so mark it as unsafe.
*
* Params:
* f = function being called (needed for diagnostic of inferred functions)
* Returns: whether there's a safe error
*/
extern (D) final bool setUnsafeCall(FuncDeclaration f)
{
return setUnsafe(false, f.loc, null, f, null);
}

/**************************************
* The function is doing something that may throw an exception, register that in case nothrow is being inferred
Expand Down
111 changes: 1 addition & 110 deletions compiler/src/dmd/funcsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import dmd.rootobject;
import dmd.root.filename;
import dmd.root.string;
import dmd.root.stringtable;
import dmd.safe;
import dmd.semantic2;
import dmd.semantic3;
import dmd.statement;
Expand Down Expand Up @@ -2807,116 +2808,6 @@ bool isRootTraitsCompilesScope(Scope* sc) @safe
return (sc.traitsCompiles) && !sc.func.skipCodegen;
}

/**************************************
* A statement / expression in this scope is not `@safe`,
* so mark the enclosing function as `@system`
*
* Params:
* sc = scope that the unsafe statement / expression is in
* gag = surpress error message (used in escape.d)
* loc = location of error
* fmt = printf-style format string
* arg0 = (optional) argument for first %s format specifier
* arg1 = (optional) argument for second %s format specifier
* arg2 = (optional) argument for third %s format specifier
* Returns: whether there's a safe error
*/
bool setUnsafe(Scope* sc,
bool gag = false, Loc loc = Loc.init, const(char)* fmt = null,
RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
{
if (sc.intypeof)
return false; // typeof(cast(int*)0) is safe

if (sc.debug_) // debug {} scopes are permissive
return false;

if (!sc.func)
{
if (sc.varDecl)
{
if (sc.varDecl.storage_class & STC.safe)
{
.error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
return true;
}
else if (!(sc.varDecl.storage_class & STC.trusted))
{
sc.varDecl.storage_class |= STC.system;
sc.varDecl.systemInferred = true;
}
}
return false;
}


if (isRootTraitsCompilesScope(sc)) // __traits(compiles, x)
{
if (sc.func.isSafeBypassingInference())
{
// Message wil be gagged, but still call error() to update global.errors and for
// -verrors=spec
.error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
return true;
}
return false;
}

return sc.func.setUnsafe(gag, loc, fmt, arg0, arg1, arg2);
}

/***************************************
* Like `setUnsafe`, but for safety errors still behind preview switches
*
* Given a `FeatureState fs`, for example dip1000 / dip25 / systemVariables,
* the behavior changes based on the setting:
*
* - In case of `-revert=fs`, it does nothing.
* - In case of `-preview=fs`, it's the same as `setUnsafe`
* - By default, print a deprecation in `@safe` functions, or store an attribute violation in inferred functions.
*
* Params:
* sc = used to find affected function/variable, and for checking whether we are in a deprecated / speculative scope
* fs = feature state from the preview flag
* gag = surpress error message
* loc = location of error
* msg = printf-style format string
* arg0 = (optional) argument for first %s format specifier
* arg1 = (optional) argument for second %s format specifier
* arg2 = (optional) argument for third %s format specifier
* Returns: whether an actual safe error (not deprecation) occured
*/
bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, const(char)* msg,
RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
{
//printf("setUnsafePreview() fs:%d %s\n", fs, msg);
with (FeatureState) final switch (fs)
{
case disabled:
return false;

case enabled:
return sc.setUnsafe(gag, loc, msg, arg0, arg1, arg2);

case default_:
if (!sc.func)
return false;
if (sc.func.isSafeBypassingInference())
{
if (!gag && !sc.isDeprecated())
{
deprecation(loc, msg, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
}
}
else if (!sc.func.safetyViolation)
{
import dmd.func : AttributeViolation;
sc.func.safetyViolation = new AttributeViolation(loc, msg, arg0, arg1, arg2);
}
return false;
}
}

/+
+ Checks the parameter and return types iff this is a `main` function.
+
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dmd/initsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import dmd.location;
import dmd.mtype;
import dmd.opover;
import dmd.optimize;
import dmd.safe : setUnsafe;
import dmd.statement;
import dmd.target;
import dmd.tokens;
Expand Down
Loading

0 comments on commit cbc0183

Please sign in to comment.