Skip to content

Commit

Permalink
Fix issue 22865 - __traits(compiles) affects inferrence of attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
dkorpel committed May 19, 2022
1 parent 4e7c492 commit 46a99e3
Show file tree
Hide file tree
Showing 11 changed files with 118 additions and 68 deletions.
16 changes: 7 additions & 9 deletions src/dmd/dcast.d
Original file line number Diff line number Diff line change
Expand Up @@ -2768,16 +2768,14 @@ Expression scaleFactor(BinExp be, Scope* sc)
else
assert(0);

if (sc.func && !sc.intypeof)

eoff = eoff.optimize(WANTvalue);
if (eoff.op == EXP.int64 && eoff.toInteger() == 0)
{
eoff = eoff.optimize(WANTvalue);
if (eoff.op == EXP.int64 && eoff.toInteger() == 0)
{
}
else if (sc.func.setUnsafe(false, be.loc, "pointer arithmetic not allowed in @safe functions"))
{
return ErrorExp.get();
}
}
else if (sc.setUnsafe(false, be.loc, "pointer arithmetic not allowed in @safe functions"))
{
return ErrorExp.get();
}

return be;
Expand Down
15 changes: 6 additions & 9 deletions src/dmd/dsymbolsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -468,12 +468,9 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
dsym.type.checkComplexTransition(dsym.loc, sc);

// Calculate type size + safety checks
if (sc.func && !sc.intypeof)
if (dsym.storage_class & STC.gshared && !dsym.isMember())
{
if (dsym.storage_class & STC.gshared && !dsym.isMember())
{
sc.func.setUnsafe(false, dsym.loc, "__gshared not allowed in safe functions; use shared");
}
sc.setUnsafe(false, dsym.loc, "__gshared not allowed in safe functions; use shared");
}

Dsymbol parent = dsym.toParent();
Expand Down Expand Up @@ -857,23 +854,23 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
}

// Calculate type size + safety checks
if (sc.func && !sc.intypeof)
if (1)
{
if (dsym._init && dsym._init.isVoidInitializer() &&
(dsym.type.hasPointers() || dsym.type.hasInvariant())) // also computes type size
{
if (dsym.type.hasPointers())
sc.func.setUnsafe(false, dsym.loc,
sc.setUnsafe(false, dsym.loc,
"`void` initializers for pointers not allowed in safe functions");
else
sc.func.setUnsafe(false, dsym.loc,
sc.setUnsafe(false, dsym.loc,
"`void` initializers for structs with invariants are not allowed in safe functions");
}
else if (!dsym._init &&
!(dsym.storage_class & (STC.static_ | STC.extern_ | STC.gshared | STC.manifest | STC.field | STC.parameter)) &&
dsym.type.hasVoidInitPointers())
{
sc.func.setUnsafe(false, dsym.loc, "`void` initializers for pointers not allowed in safe functions");
sc.setUnsafe(false, dsym.loc, "`void` initializers for pointers not allowed in safe functions");
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/dmd/escape.d
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ bool checkMutableArguments(Scope* sc, FuncDeclaration fd, TypeFunction tf,
if (!(eb.isMutable || eb2.isMutable))
return;

if (!(global.params.useDIP1000 == FeatureState.enabled && sc.func.setUnsafe()))
if (!(global.params.useDIP1000 == FeatureState.enabled && sc.setUnsafe()))
return;

if (!gag)
Expand Down Expand Up @@ -2502,7 +2502,7 @@ private bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, con
}
else if (fs == FeatureState.enabled)
{
return sc.func.setUnsafe(gag, loc, msg, arg0, arg1);
return sc.setUnsafe(gag, loc, msg, arg0, arg1);
}
else
{
Expand Down
6 changes: 3 additions & 3 deletions src/dmd/expression.d
Original file line number Diff line number Diff line change
Expand Up @@ -1370,7 +1370,7 @@ extern (C++) abstract class Expression : ASTNode
*/
if (v.storage_class & STC.gshared)
{
if (sc.func.setUnsafe(false, this.loc,
if (sc.setUnsafe(false, this.loc,
"`@safe` function `%s` cannot access `__gshared` data `%s`", sc.func, v))
{
err = true;
Expand Down Expand Up @@ -5761,7 +5761,7 @@ extern (C++) final class DelegatePtrExp : UnaExp

override Expression modifiableLvalue(Scope* sc, Expression e)
{
if (sc.func.setUnsafe(false, this.loc, "cannot modify delegate pointer in `@safe` code `%s`", this))
if (sc.setUnsafe(false, this.loc, "cannot modify delegate pointer in `@safe` code `%s`", this))
{
return ErrorExp.get();
}
Expand Down Expand Up @@ -5799,7 +5799,7 @@ extern (C++) final class DelegateFuncptrExp : UnaExp

override Expression modifiableLvalue(Scope* sc, Expression e)
{
if (sc.func.setUnsafe(false, this.loc, "cannot modify delegate function pointer in `@safe` code `%s`", this))
if (sc.setUnsafe(false, this.loc, "cannot modify delegate function pointer in `@safe` code `%s`", this))
{
return ErrorExp.get();
}
Expand Down
39 changes: 14 additions & 25 deletions src/dmd/expressionsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -4989,7 +4989,7 @@ 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 && sc.setUnsafe())
{
exp.error("`@safe` %s `%s` cannot call `@system` %s `%s`",
sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
Expand Down Expand Up @@ -6894,9 +6894,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
* because it might end up being a pointer to undefined
* memory.
*/
if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_))
if (1)
{
if (sc.func.setUnsafe(false, exp.loc,
if (sc.setUnsafe(false, exp.loc,
"cannot take address of lazy parameter `%s` in `@safe` function `%s`", ve, sc.func))
{
setError();
Expand Down Expand Up @@ -7045,7 +7045,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_))
{
sc.func.setUnsafe(false, exp.loc,
sc.setUnsafe(false, exp.loc,
"`this` reference necessary to take address of member `%s` in `@safe` function `%s`",
f, sc.func);
}
Expand Down Expand Up @@ -7552,10 +7552,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}

// Check for unsafe casts
if (!sc.intypeof &&
!(sc.flags & SCOPE.debug_) &&
!isSafeCast(ex, t1b, tob) &&
(!sc.func && sc.stc & STC.safe || sc.func && sc.func.setUnsafe()))
if (!isSafeCast(ex, t1b, tob) &&
(!sc.func && sc.stc & STC.safe || sc.setUnsafe()))
{
exp.error("cast from `%s` to `%s` not allowed in safe code", exp.e1.type.toChars(), exp.to.toChars());
return setError();
Expand Down Expand Up @@ -7816,11 +7814,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor

return setError();
}
if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_))
{
if (sc.func.setUnsafe(false, exp.loc, "pointer slicing not allowed in safe functions"))
return setError();
}
if (sc.setUnsafe(false, exp.loc, "pointer slicing not allowed in safe functions"))
return setError();
}
else if (t1b.ty == Tarray)
{
Expand Down Expand Up @@ -8328,11 +8323,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (exp.e2.op == EXP.int64 && exp.e2.toInteger() == 0)
{
}
else if (sc.func && !(sc.flags & SCOPE.debug_))
else if (sc.setUnsafe(false, exp.loc, "`@safe` function `%s` cannot index pointer `%s`", sc.func, exp.e1))
{
if (sc.func.setUnsafe(false, exp.loc,
"`@safe` function `%s` cannot index pointer `%s`", sc.func, exp.e1))
return setError();
return setError();
}
exp.type = (cast(TypeNext)t1b).next;
break;
Expand Down Expand Up @@ -9729,11 +9722,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
if (t1n.toBasetype.ty == Tvoid && t2n.toBasetype.ty == Tvoid)
{
if (!sc.intypeof && sc.func && !(sc.flags & SCOPE.debug_))
{
if (sc.func.setUnsafe(false, exp.loc, "cannot copy `void[]` to `void[]` in `@safe` code"))
return setError();
}
if (sc.setUnsafe(false, exp.loc, "cannot copy `void[]` to `void[]` in `@safe` code"))
return setError();
}
}
else
Expand Down Expand Up @@ -13089,9 +13079,8 @@ bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v)
v.storage_class &= ~STC.maybescope;
v.doNotInferScope = true;
if (global.params.useDIP1000 != FeatureState.enabled &&
!(sc.flags & SCOPE.debug_) &&
!(v.storage_class & STC.temp) &&
sc.func.setUnsafe())
sc.setUnsafe())
{
exp.error("cannot take address of %s `%s` in `@safe` function `%s`", p, v.toChars(), sc.func.toChars());
return false;
Expand Down Expand Up @@ -13304,7 +13293,7 @@ private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions
{
if ((!stype.alignment.isDefault() && stype.alignment.get() < target.ptrsize ||
(v.offset & (target.ptrsize - 1))) &&
(sc.func && sc.func.setUnsafe(false, loc,
(sc.setUnsafe(false, loc,
"field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd, v)))
{
return false;
Expand Down
35 changes: 35 additions & 0 deletions src/dmd/func.d
Original file line number Diff line number Diff line change
Expand Up @@ -4321,6 +4321,41 @@ extern (C++) final class NewDeclaration : FuncDeclaration
}
}

/**************************************
* A statement / expression in this scope is not `@safe`, so mark the function as `@system`
*
* 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
* 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)
{
// TODO:
// For @system variables, unsafe initializers at global scope should mark
// the variable @system, see https://dlang.org/dips/1035

if (!sc.func)
return false;

if (sc.intypeof)
return false; // typeof(cast(int*)0) is safe

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

if (sc.flags & SCOPE.compile) // __traits(compiles, x)
{
return sc.func.isSafeBypassingInference();
}

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

/// Stores a reason why a function failed to infer a function attribute like `@safe` or `pure`
///
/// Has two modes:
Expand Down
5 changes: 2 additions & 3 deletions src/dmd/initsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -197,10 +197,9 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
if (vd.type.hasPointers)
{
if ((!t.alignment.isDefault() && t.alignment.get() < target.ptrsize ||
(vd.offset & (target.ptrsize - 1))) &&
sc.func)
(vd.offset & (target.ptrsize - 1))))
{
if (sc.func.setUnsafe(false, i.value[j].loc,
if (sc.setUnsafe(false, i.value[j].loc,
"field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd, vd))
{
errors = true;
Expand Down
2 changes: 1 addition & 1 deletion src/dmd/mtype.d
Original file line number Diff line number Diff line change
Expand Up @@ -4760,7 +4760,7 @@ extern (C++) final class TypeFunction : TypeNext
char[] s;
if (!f.isPure && sc.func.setImpure())
s ~= "pure ";
if (!f.isSafe() && !f.isTrusted() && sc.func.setUnsafe())
if (!f.isSafe() && !f.isTrusted() && sc.setUnsafe())
s ~= "@safe ";
if (!f.isNogc && sc.func.setGC())
s ~= "nogc ";
Expand Down
19 changes: 8 additions & 11 deletions src/dmd/safe.d
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import dmd.identifier;
import dmd.mtype;
import dmd.target;
import dmd.tokens;

import dmd.func : setUnsafe;

/*************************************************************
* Check for unsafe access in @safe code:
Expand Down Expand Up @@ -66,7 +66,7 @@ bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg)
{
if (v.overlapped)
{
if (sc.func.setUnsafe(!printmsg, e.loc,
if (sc.setUnsafe(!printmsg, e.loc,
"field `%s.%s` cannot access pointers in `@safe` code that overlap other fields", ad, v))
return true;
}
Expand All @@ -76,7 +76,7 @@ bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg)
{
if (v.overlapped)
{
if (sc.func.setUnsafe(!printmsg, e.loc,
if (sc.setUnsafe(!printmsg, e.loc,
"field `%s.%s` cannot access structs with invariants in `@safe` code that overlap other fields",
ad, v))
return true;
Expand All @@ -91,15 +91,15 @@ bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg)
if ((!ad.type.alignment.isDefault() && ad.type.alignment.get() < target.ptrsize ||
(v.offset & (target.ptrsize - 1))))
{
if (sc.func.setUnsafe(!printmsg, e.loc,
if (sc.setUnsafe(!printmsg, e.loc,
"field `%s.%s` cannot modify misaligned pointers in `@safe` code", ad, v))
return true;
}
}

if (v.overlapUnsafe)
{
if (sc.func.setUnsafe(!printmsg, e.loc,
if (sc.setUnsafe(!printmsg, e.loc,
"field `%s.%s` cannot modify fields in `@safe` code that overlap fields with other storage classes",
ad, v))
{
Expand Down Expand Up @@ -211,15 +211,12 @@ bool isSafeCast(Expression e, Type tfrom, Type tto)
*/
bool checkUnsafeDotExp(Scope* sc, Expression e, Identifier id, int flag)
{
if (!(flag & DotExpFlag.noDeref) && // this use is attempting a dereference
sc.func && // inside a function
!sc.intypeof && // allow unsafe code in typeof expressions
!(sc.flags & SCOPE.debug_)) // allow unsafe code in debug statements
if (!(flag & DotExpFlag.noDeref)) // this use is attempting a dereference
{
if (id == Id.ptr)
return sc.func.setUnsafe(false, e.loc, "`%s.ptr` cannot be used in `@safe` code, use `&%s[0]` instead", e, e);
return sc.setUnsafe(false, e.loc, "`%s.ptr` cannot be used in `@safe` code, use `&%s[0]` instead", e, e);
else
return sc.func.setUnsafe(false, e.loc, "`%s.%s` cannot be used in `@safe` code", e, id);
return sc.setUnsafe(false, e.loc, "`%s.%s` cannot be used in `@safe` code", e, id);
}
return false;
}
10 changes: 5 additions & 5 deletions src/dmd/statementsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -3928,7 +3928,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
cas.error("`asm` statement is assumed to use the GC - mark it with `@nogc` if it does not");
if (!(cas.stc & (STC.trusted | STC.safe)))
{
sc.func.setUnsafe(false, cas.loc, "`asm` statement is assumed to be `@system` - mark it with `@trusted` if it is not");
sc.setUnsafe(false, cas.loc, "`asm` statement is assumed to be `@system` - mark it with `@trusted` if it is not");
}

sc.pop();
Expand Down Expand Up @@ -4033,9 +4033,9 @@ void catchSemantic(Catch c, Scope* sc)
error(c.loc, "catching C++ class objects not supported for this target");
c.errors = true;
}
if (sc.func && !sc.intypeof && !c.internalCatch)
if (!c.internalCatch)
{
if (sc.func.setUnsafe(false, c.loc, "cannot catch C++ class objects in `@safe` code"))
if (sc.setUnsafe(false, c.loc, "cannot catch C++ class objects in `@safe` code"))
c.errors = true;
}
}
Expand All @@ -4044,9 +4044,9 @@ void catchSemantic(Catch c, Scope* sc)
error(c.loc, "can only catch class objects derived from `Throwable`, not `%s`", c.type.toChars());
c.errors = true;
}
else if (sc.func && !sc.intypeof && !c.internalCatch && ClassDeclaration.exception &&
else if (!c.internalCatch && ClassDeclaration.exception &&
cd != ClassDeclaration.exception && !ClassDeclaration.exception.isBaseOf(cd, null) &&
sc.func.setUnsafe(false, c.loc,
sc.setUnsafe(false, c.loc,
"can only catch class objects derived from `Exception` in `@safe` code, not `%s`", c.type))
{
c.errors = true;
Expand Down

0 comments on commit 46a99e3

Please sign in to comment.