diff --git a/compiler/src/dmd/astbase.d b/compiler/src/dmd/astbase.d index a2ebd19d40f..f6b34d14af8 100644 --- a/compiler/src/dmd/astbase.d +++ b/compiler/src/dmd/astbase.d @@ -3989,6 +3989,8 @@ struct ASTBase this.trust = TRUST.default_; if (stc & STC.safe) this.trust = TRUST.safe; + else if (stc & STC.saferSystem) + this.trust = TRUST.saferSystem; else if (stc & STC.system) this.trust = TRUST.system; else if (stc & STC.trusted) @@ -6920,6 +6922,7 @@ struct ASTBase SCstring(STC.property, "@property"), SCstring(STC.safe, "@safe"), SCstring(STC.trusted, "@trusted"), + SCstring(STC.saferSystem, "@saferSystem"), SCstring(STC.system, "@system"), SCstring(STC.disable, "@disable"), SCstring(STC.future, "@__future"), diff --git a/compiler/src/dmd/astenums.d b/compiler/src/dmd/astenums.d index 1e30b9f8fc2..426a1f73fc9 100644 --- a/compiler/src/dmd/astenums.d +++ b/compiler/src/dmd/astenums.d @@ -96,31 +96,32 @@ enum STC : ulong // transfer changes to declaration.h gshared = 0x4_0000_0000, /// accessible from multiple threads, but not typed as `shared` wild = 0x8_0000_0000, /// for wild type constructor - property = 0x10_0000_0000, /// `@property` - safe = 0x20_0000_0000, /// `@safe` - trusted = 0x40_0000_0000, /// `@trusted` - system = 0x80_0000_0000, /// `@system` - - ctfe = 0x100_0000_0000, /// can be used in CTFE, even if it is static - disable = 0x200_0000_0000, /// for functions that are not callable - result = 0x400_0000_0000, /// for result variables passed to out contracts - nodefaultctor = 0x800_0000_0000, /// must be set inside constructor - - temp = 0x1000_0000_0000, /// temporary variable - rvalue = 0x2000_0000_0000, /// force rvalue for variables - nogc = 0x4000_0000_0000, /// `@nogc` - autoref = 0x8000_0000_0000, /// Mark for the already deduced `auto ref` parameter - - inference = 0x1_0000_0000_0000, /// do attribute inference - exptemp = 0x2_0000_0000_0000, /// temporary variable that has lifetime restricted to an expression - future = 0x4_0000_0000_0000, /// introducing new base class function - local = 0x8_0000_0000_0000, /// do not forward (see dmd.dsymbol.ForwardingScopeDsymbol). - - live = 0x10_0000_0000_0000, /// function `@live` attribute - register = 0x20_0000_0000_0000, /// `register` storage class (ImportC) - volatile_ = 0x40_0000_0000_0000, /// destined for volatile in the back end - - safeGroup = STC.safe | STC.trusted | STC.system, + property = 0x010_0000_0000, /// `@property` + safe = 0x020_0000_0000, /// `@safe` + trusted = 0x040_0000_0000, /// `@trusted` + saferSystem = 0x080_0000_0000, /// `@saferSystem` + system = 0x100_0000_0000, /// `@system` + + ctfe = 0x1000_0000_0000, /// can be used in CTFE, even if it is static + disable = 0x2000_0000_0000, /// for functions that are not callable + result = 0x4000_0000_0000, /// for result variables passed to out contracts + nodefaultctor = 0x8000_0000_0000, /// must be set inside constructor + + temp = 0x1_0000_0000_0000, /// temporary variable + rvalue = 0x2_0000_0000_0000, /// force rvalue for variables + nogc = 0x4_0000_0000_0000, /// `@nogc` + autoref = 0x8_0000_0000_0000, /// Mark for the already deduced `auto ref` parameter + + inference = 0x10_0000_0000_0000, /// do attribute inference + exptemp = 0x20_0000_0000_0000, /// temporary variable that has lifetime restricted to an expression + future = 0x40_0000_0000_0000, /// introducing new base class function + local = 0x80_0000_0000_0000, /// do not forward (see dmd.dsymbol.ForwardingScopeDsymbol). + + live = 0x100_0000_0000_0000, /// function `@live` attribute + register = 0x200_0000_0000_0000, /// `register` storage class (ImportC) + volatile_ = 0x400_0000_0000_0000, /// destined for volatile in the back end + + safeGroup = STC.safe | STC.trusted | STC.saferSystem | STC.system, IOR = STC.constscoperef | STC.in_ | STC.ref_ | STC.out_, TYPECTOR = (STC.const_ | STC.immutable_ | STC.shared_ | STC.wild), FUNCATTR = (STC.ref_ | STC.nothrow_ | STC.nogc | STC.pure_ | STC.property | STC.live | @@ -139,7 +140,7 @@ enum STC : ulong // transfer changes to declaration.h flowThruAggregate = STC.safeGroup, /// for an AggregateDeclaration flowThruFunction = ~(STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.abstract_ | STC.deprecated_ | STC.override_ | STC.TYPECTOR | STC.final_ | STC.tls | STC.gshared | STC.ref_ | STC.return_ | STC.property | - STC.nothrow_ | STC.pure_ | STC.safe | STC.trusted | STC.system), /// for a FuncDeclaration + STC.nothrow_ | STC.pure_ | STC.safe | STC.trusted | STC.saferSystem | STC.system), /// for a FuncDeclaration } @@ -301,10 +302,11 @@ enum ThreeState : ubyte enum TRUST : ubyte { - default_ = 0, - system = 1, // @system (same as TRUST.default) - trusted = 2, // @trusted - safe = 3, // @safe + default_ = 0, + system = 1, // @system (same as TRUST.default_ unless feature "safer" is enabled) + saferSystem = 2, // @saferSystem (same as TRUST.default_ if feature "safer" is enabled) + trusted = 3, // @trusted + safe = 4, // @safe } enum PURE : ubyte diff --git a/compiler/src/dmd/clone.d b/compiler/src/dmd/clone.d index 1b838603c7e..0f9ccd7a92a 100644 --- a/compiler/src/dmd/clone.d +++ b/compiler/src/dmd/clone.d @@ -60,6 +60,8 @@ StorageClass mergeFuncAttrs(StorageClass s1, const FuncDeclaration f) pure @safe auto tf = f.type.isTypeFunction(); if (tf.trust == TRUST.safe) s2 |= STC.safe; + else if (tf.trust == TRUST.saferSystem) + s2 |= STC.system; else if (tf.trust == TRUST.system) s2 |= STC.system; else if (tf.trust == TRUST.trusted) diff --git a/compiler/src/dmd/expressionsem.d b/compiler/src/dmd/expressionsem.d index c42dedf85d9..bb681bed666 100644 --- a/compiler/src/dmd/expressionsem.d +++ b/compiler/src/dmd/expressionsem.d @@ -2301,8 +2301,11 @@ private bool checkSafety(FuncDeclaration f, ref Loc loc, Scope* sc) if (!loc.isValid()) // e.g. implicitly generated dtor loc = sc.func.loc; + immutable msg = (f.isSaferD()) + ? "`@safe` %s `%s` cannot call `@saferSystem` %s `%s`" + : "`@safe` %s `%s` cannot call `@system` %s `%s`"; const prettyChars = f.toPrettyChars(); - error(loc, "`@safe` %s `%s` cannot call `@system` %s `%s`", + error(loc, msg.ptr, sc.func.kind(), sc.func.toPrettyChars(), f.kind(), prettyChars); if (!f.isDtorDeclaration) diff --git a/compiler/src/dmd/frontend.h b/compiler/src/dmd/frontend.h index 614a29ec558..b16a1e2ffbd 100644 --- a/compiler/src/dmd/frontend.h +++ b/compiler/src/dmd/frontend.h @@ -5306,67 +5306,68 @@ enum class MODFlags enum class STC : uint64_t { - undefined_ = 0LLU, - static_ = 1LLU, - extern_ = 2LLU, - const_ = 4LLU, - final_ = 8LLU, - abstract_ = 16LLU, - parameter = 32LLU, - field = 64LLU, - override_ = 128LLU, - auto_ = 256LLU, - synchronized_ = 512LLU, - deprecated_ = 1024LLU, - in_ = 2048LLU, - out_ = 4096LLU, - lazy_ = 8192LLU, - foreach_ = 16384LLU, - variadic = 32768LLU, - constscoperef = 65536LLU, - templateparameter = 131072LLU, - ref_ = 262144LLU, - scope_ = 524288LLU, - scopeinferred = 2097152LLU, - return_ = 4194304LLU, - returnScope = 8388608LLU, - returninferred = 16777216LLU, - immutable_ = 33554432LLU, - manifest = 134217728LLU, - nodtor = 268435456LLU, - nothrow_ = 536870912LLU, - pure_ = 1073741824LLU, - tls = 2147483648LLU, - alias_ = 4294967296LLU, - shared_ = 8589934592LLU, - gshared = 17179869184LLU, - wild = 34359738368LLU, - property = 68719476736LLU, - safe = 137438953472LLU, - trusted = 274877906944LLU, - system = 549755813888LLU, - ctfe = 1099511627776LLU, - disable = 2199023255552LLU, - result = 4398046511104LLU, - nodefaultctor = 8796093022208LLU, - temp = 17592186044416LLU, - rvalue = 35184372088832LLU, - nogc = 70368744177664LLU, - autoref = 140737488355328LLU, - inference = 281474976710656LLU, - exptemp = 562949953421312LLU, - future = 1125899906842624LLU, - local = 2251799813685248LLU, - live = 4503599627370496LLU, - register_ = 9007199254740992LLU, - volatile_ = 18014398509481984LLU, - safeGroup = 962072674304LLU, - IOR = 333824LLU, - TYPECTOR = 42983227396LLU, - FUNCATTR = 4575000774574080LLU, - visibleStorageClasses = 7954966262857631LLU, - flowThruAggregate = 962072674304LLU, - flowThruFunction = 18446742978991225440LLU, + undefined_ = 0LLU + static_ = 1LLU + extern_ = 2LLU + const_ = 4LLU + final_ = 8LLU + abstract_ = 16LLU + parameter = 32LLU + field = 64LLU + override_ = 128LLU + auto_ = 256LLU + synchronized_ = 512LLU + deprecated_ = 1024LLU + in_ = 2048LLU + out_ = 4096LLU + lazy_ = 8192LLU + foreach_ = 16384LLU + variadic = 32768LLU + constscoperef = 65536LLU + templateparameter = 131072LLU + ref_ = 262144LLU + scope_ = 524288LLU + scopeinferred = 2097152LLU + return_ = 4194304LLU + returnScope = 8388608LLU + returninferred = 16777216LLU + immutable_ = 33554432LLU + manifest = 134217728LLU + nodtor = 268435456LLU + nothrow_ = 536870912LLU + pure_ = 1073741824LLU + tls = 2147483648LLU + alias_ = 4294967296LLU + shared_ = 8589934592LLU + gshared = 17179869184LLU + wild = 34359738368LLU + property = 68719476736LLU + safe = 137438953472LLU + trusted = 274877906944LLU + saferSystem = 549755813888LLU + system = 1099511627776LLU + ctfe = 17592186044416LLU + disable = 35184372088832LLU + result = 70368744177664LLU + nodefaultctor = 140737488355328LLU + temp = 281474976710656LLU + rvalue = 562949953421312LLU + nogc = 1125899906842624LLU + autoref = 2251799813685248LLU + inference = 4503599627370496LLU + exptemp = 9007199254740992LLU + future = 18014398509481984LLU + local = 36028797018963968LLU + live = 72057594037927936LLU + register_ = 144115188075855872LLU + volatile_ = 288230376151711744LLU + safeGroup = 2061584302080LLU + IOR = 333824LLU + TYPECTOR = 42983227396LLU + FUNCATTR = 73185625859424256LLU + visibleStorageClasses = 127264072504459167LLU + flowThruAggregate = 2061584302080LLU + flowThruFunction = 18446741879479597664LLU }; struct ASTCodegen final diff --git a/compiler/src/dmd/funcsem.d b/compiler/src/dmd/funcsem.d index eba93973a48..f33a040125f 100644 --- a/compiler/src/dmd/funcsem.d +++ b/compiler/src/dmd/funcsem.d @@ -373,6 +373,8 @@ void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl) sc.stc &= ~STC.safeGroup; if (tf.trust == TRUST.safe) sc.stc |= STC.safe; + else if (tf.trust == TRUST.saferSystem) + sc.stc |= STC.saferSystem; else if (tf.trust == TRUST.system) sc.stc |= STC.system; else if (tf.trust == TRUST.trusted) diff --git a/compiler/src/dmd/hdrgen.d b/compiler/src/dmd/hdrgen.d index cfe4262ce44..038c6b7b21c 100644 --- a/compiler/src/dmd/hdrgen.d +++ b/compiler/src/dmd/hdrgen.d @@ -3268,6 +3268,7 @@ string stcToString(ref StorageClass stc) @safe SCstring(STC.property, "@property"), SCstring(STC.safe, "@safe"), SCstring(STC.trusted, "@trusted"), + SCstring(STC.saferSystem, "@saferSystem"), SCstring(STC.system, "@system"), SCstring(STC.disable, "@disable"), SCstring(STC.future, "@__future"), diff --git a/compiler/src/dmd/id.d b/compiler/src/dmd/id.d index aae07bc1537..15fe5492665 100644 --- a/compiler/src/dmd/id.d +++ b/compiler/src/dmd/id.d @@ -211,6 +211,7 @@ immutable Msgtable[] msgtable = { "nogc" }, { "live" }, { "safe" }, + { "saferSystem" }, { "trusted" }, { "system" }, { "disable" }, diff --git a/compiler/src/dmd/json.d b/compiler/src/dmd/json.d index 174a2d95cd2..7c8998c1ab3 100644 --- a/compiler/src/dmd/json.d +++ b/compiler/src/dmd/json.d @@ -290,9 +290,10 @@ public: // Should not be printed //property(name, "default"); break; - case TRUST.system: return property(name, "system"); - case TRUST.trusted: return property(name, "trusted"); - case TRUST.safe: return property(name, "safe"); + case TRUST.system: return property(name, "system"); + case TRUST.saferSystem: return property(name, "saferSystem"); + case TRUST.trusted: return property(name, "trusted"); + case TRUST.safe: return property(name, "safe"); } } diff --git a/compiler/src/dmd/mtype.d b/compiler/src/dmd/mtype.d index 9ebdbd424a3..9fafc8f6ddd 100644 --- a/compiler/src/dmd/mtype.d +++ b/compiler/src/dmd/mtype.d @@ -214,6 +214,8 @@ string trustToString(TRUST trust) pure nothrow @nogc @safe return null; case TRUST.system: return "@system"; + case TRUST.saferSystem: + return "@saferSystem"; case TRUST.trusted: return "@trusted"; case TRUST.safe: @@ -225,6 +227,7 @@ unittest { assert(trustToString(TRUST.default_) == ""); assert(trustToString(TRUST.system) == "@system"); + assert(trustToString(TRUST.saferSystem) == "@saferSystem"); assert(trustToString(TRUST.trusted) == "@trusted"); assert(trustToString(TRUST.safe) == "@safe"); } @@ -2538,6 +2541,8 @@ extern (C++) final class TypeFunction : TypeNext this.trust = TRUST.default_; if (stc & STC.safe) this.trust = TRUST.safe; + else if (stc & STC.saferSystem) + this.trust = TRUST.saferSystem; else if (stc & STC.system) this.trust = TRUST.system; else if (stc & STC.trusted) diff --git a/compiler/src/dmd/mtype.h b/compiler/src/dmd/mtype.h index eced43eeacf..663228af5df 100644 --- a/compiler/src/dmd/mtype.h +++ b/compiler/src/dmd/mtype.h @@ -469,9 +469,10 @@ enum RET enum class TRUST : unsigned char { default_ = 0, - system = 1, // @system (same as TRUSTdefault) - trusted = 2, // @trusted - safe = 3 // @safe + system = 1, // @system (same as TRUST.default_ unless feature "safer" is enabled) + saferSystem = 2, // @saferSystem (same as TRUST.default_ if feature "safer" is enabled) + trusted = 3, // @trusted + safe = 4 // @safe }; enum TRUSTformat diff --git a/compiler/src/dmd/parse.d b/compiler/src/dmd/parse.d index b4cc866acb2..6006a1f9a94 100644 --- a/compiler/src/dmd/parse.d +++ b/compiler/src/dmd/parse.d @@ -9636,14 +9636,15 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer */ static StorageClass isBuiltinAtAttribute(Identifier ident) { - return (ident == Id.property) ? STC.property : - (ident == Id.nogc) ? STC.nogc : - (ident == Id.safe) ? STC.safe : - (ident == Id.trusted) ? STC.trusted : - (ident == Id.system) ? STC.system : - (ident == Id.live) ? STC.live : - (ident == Id.future) ? STC.future : - (ident == Id.disable) ? STC.disable : + return (ident == Id.property) ? STC.property : + (ident == Id.nogc) ? STC.nogc : + (ident == Id.safe) ? STC.safe : + (ident == Id.saferSystem) ? STC.saferSystem : + (ident == Id.trusted) ? STC.trusted : + (ident == Id.system) ? STC.system : + (ident == Id.live) ? STC.live : + (ident == Id.future) ? STC.future : + (ident == Id.disable) ? STC.disable : 0; } diff --git a/compiler/src/dmd/safe.d b/compiler/src/dmd/safe.d index 86dff7b5bcf..50ce9c7deb5 100644 --- a/compiler/src/dmd/safe.d +++ b/compiler/src/dmd/safe.d @@ -323,8 +323,9 @@ bool checkUnsafeDotExp(Scope* sc, Expression e, Identifier id, int flag) */ bool isSaferD(FuncDeclaration fd) { - return fd.type.toTypeFunction().trust == TRUST.default_ && - global.params.safer == FeatureState.enabled; + return fd.type.toTypeFunction().trust == TRUST.saferSystem || + (fd.type.toTypeFunction().trust == TRUST.default_ && + global.params.safer == FeatureState.enabled); } bool isSafe(FuncDeclaration fd) diff --git a/compiler/src/dmd/typesem.d b/compiler/src/dmd/typesem.d index 6d2d9212e9e..b1ea5a11323 100644 --- a/compiler/src/dmd/typesem.d +++ b/compiler/src/dmd/typesem.d @@ -2234,6 +2234,8 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc) { if (sc.stc & STC.safe) tf.trust = TRUST.safe; + else if (sc.stc & STC.saferSystem) + tf.trust = TRUST.saferSystem; else if (sc.stc & STC.system) tf.trust = TRUST.system; else if (sc.stc & STC.trusted) diff --git a/compiler/test/fail_compilation/safer_attrib.d b/compiler/test/fail_compilation/safer_attrib.d new file mode 100644 index 00000000000..932cee5a6ce --- /dev/null +++ b/compiler/test/fail_compilation/safer_attrib.d @@ -0,0 +1,18 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/safer_attrib.d(10): Error: `void` initializers for pointers not allowed in safe functions +--- +*/ + +void test1() @saferSystem +{ + int* p = void; +} + +void foo3() { } + +void test2() +{ + foo3(); // should not be an error +} diff --git a/compiler/test/fail_compilation/safer_attrib2.d b/compiler/test/fail_compilation/safer_attrib2.d new file mode 100644 index 00000000000..2452c6c16d9 --- /dev/null +++ b/compiler/test/fail_compilation/safer_attrib2.d @@ -0,0 +1,21 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/safer_attrib2.d(15): Error: `@safe` function `safer_attrib2.saf` cannot call `@saferSystem` function `safer_attrib2.safSys` +fail_compilation/safer_attrib2.d(9): `safer_attrib2.safSys` is declared here +--- +*/ + +void safSys() @saferSystem +{ +} + +void saf() @safe +{ + safSys(); +} + +void sys() @system +{ + safSys(); // fine +}