Fix 20148 - void initializated bool can be both true and false

This commit is contained in:
Dennis Korpel 2023-06-28 12:12:25 +02:00 committed by The Dlang Bot
parent 8272384b3e
commit 0b677d90ee
6 changed files with 86 additions and 26 deletions

View file

@ -223,7 +223,7 @@ extern (C++) class StructDeclaration : AggregateDeclaration
bool hasCopyCtor; // copy constructor
bool hasPointerField; // members with indirections
bool hasVoidInitPointers; // void-initialized unsafe fields
bool hasSystemFields; // @system members
bool hasUnsafeBitpatterns; // @system members, pointers, bool
bool hasFieldWithInvariant; // invariants
bool computedTypeProperties;// the above 3 fields are computed
// Even if struct is defined as non-root symbol, some built-in operations
@ -396,13 +396,16 @@ extern (C++) class StructDeclaration : AggregateDeclaration
foreach (vd; fields)
{
if (vd.storage_class & STC.ref_ || vd.hasPointers())
{
hasPointerField = true;
hasUnsafeBitpatterns = true;
}
if (vd._init && vd._init.isVoidInitializer() && vd.type.hasPointers())
hasVoidInitPointers = true;
if (vd.storage_class & STC.system || vd.type.hasSystemFields())
hasSystemFields = true;
if (vd.storage_class & STC.system || vd.type.hasUnsafeBitpatterns())
hasUnsafeBitpatterns = true;
if (!vd._init && vd.type.hasVoidInitPointers())
hasVoidInitPointers = true;

View file

@ -1072,8 +1072,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
// Calculate type size + safety checks
if (sc && sc.func)
{
if (dsym._init && dsym._init.isVoidInitializer())
if (dsym._init && dsym._init.isVoidInitializer() && !(dsym.storage_class & STC.temp))
{
// Don't do these checks for STC.temp vars because the generated `opAssign`
// for a struct with postblit and destructor void initializes a temporary
// __swap variable, which can be trusted
if (dsym.type.hasPointers()) // also computes type size
sc.setUnsafe(false, dsym.loc,
@ -1081,9 +1084,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
else if (dsym.type.hasInvariant())
sc.setUnsafe(false, dsym.loc,
"`void` initializers for structs with invariants are not allowed in safe functions");
else if (dsym.type.hasSystemFields())
else if (dsym.type.toBasetype().ty == Tbool)
sc.setUnsafePreview(global.params.systemVariables, false, dsym.loc,
"`void` initializers for `@system` variables not allowed in safe functions");
"a `bool` must be 0 or 1, so void intializing it is not allowed in safe functions");
else if (dsym.type.hasUnsafeBitpatterns())
sc.setUnsafePreview(global.params.systemVariables, false, dsym.loc,
"`void` initializers for types with unsafe bit patterns 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)) &&

View file

@ -1863,7 +1863,7 @@ public:
virtual bool isZeroInit(const Loc& loc);
virtual int32_t hasWild() const;
virtual bool hasVoidInitPointers();
virtual bool hasSystemFields();
virtual bool hasUnsafeBitpatterns();
virtual bool hasInvariant();
virtual Type* nextOf();
Type* baseElemOf();
@ -4242,6 +4242,7 @@ public:
bool isunsigned() override;
MATCH implicitConvTo(Type* to) override;
bool isZeroInit(const Loc& loc) override;
bool hasUnsafeBitpatterns() override;
TypeBasic* isTypeBasic() override;
void accept(Visitor* v) override;
};
@ -4329,7 +4330,7 @@ public:
MATCH constConv(Type* to) override;
bool isZeroInit(const Loc& loc) override;
bool hasVoidInitPointers() override;
bool hasSystemFields() override;
bool hasUnsafeBitpatterns() override;
bool hasInvariant() override;
Type* nextOf() override;
void accept(Visitor* v) override;
@ -4568,7 +4569,7 @@ public:
MATCH constConv(Type* to) override;
MATCH implicitConvTo(Type* to) override;
Expression* defaultInitLiteral(const Loc& loc) override;
bool hasSystemFields() override;
bool hasUnsafeBitpatterns() override;
bool hasVoidInitPointers() override;
bool hasInvariant() override;
bool needsDestruction() override;
@ -4607,7 +4608,7 @@ public:
bool needsCopyOrPostblit() override;
bool needsNested() override;
bool hasVoidInitPointers() override;
bool hasSystemFields() override;
bool hasUnsafeBitpatterns() override;
bool hasInvariant() override;
MATCH implicitConvTo(Type* to) override;
MATCH constConv(Type* to) override;
@ -7311,8 +7312,8 @@ public:
bool hasPointerField(bool v);
bool hasVoidInitPointers() const;
bool hasVoidInitPointers(bool v);
bool hasSystemFields() const;
bool hasSystemFields(bool v);
bool hasUnsafeBitpatterns() const;
bool hasUnsafeBitpatterns(bool v);
bool hasFieldWithInvariant() const;
bool hasFieldWithInvariant(bool v);
bool computedTypeProperties() const;

View file

@ -1412,7 +1412,7 @@ extern (C++) abstract class Type : ASTNode
* Returns:
* true if so
*/
bool hasSystemFields()
bool hasUnsafeBitpatterns()
{
return false;
}
@ -2340,6 +2340,11 @@ extern (C++) final class TypeBasic : Type
}
}
override bool hasUnsafeBitpatterns()
{
return ty == Tbool;
}
// For eliminating dynamic_cast
override TypeBasic isTypeBasic()
{
@ -2657,9 +2662,9 @@ extern (C++) final class TypeSArray : TypeArray
return ae;
}
override bool hasSystemFields()
override bool hasUnsafeBitpatterns()
{
return next.hasSystemFields();
return next.hasUnsafeBitpatterns();
}
override bool hasVoidInitPointers()
@ -3976,11 +3981,11 @@ extern (C++) final class TypeStruct : Type
return sym.hasVoidInitPointers;
}
override bool hasSystemFields()
override bool hasUnsafeBitpatterns()
{
sym.size(Loc.initial); // give error for forward references
sym.determineTypeProperties();
return sym.hasSystemFields;
return sym.hasUnsafeBitpatterns;
}
override bool hasInvariant()
@ -4239,9 +4244,9 @@ extern (C++) final class TypeEnum : Type
return memType().hasVoidInitPointers();
}
override bool hasSystemFields()
override bool hasUnsafeBitpatterns()
{
return memType().hasSystemFields();
return memType().hasUnsafeBitpatterns();
}
override bool hasInvariant()

View file

@ -276,7 +276,7 @@ public:
virtual bool isZeroInit(const Loc &loc = Loc()); // if initializer is 0
virtual int hasWild() const;
virtual bool hasVoidInitPointers();
virtual bool hasSystemFields();
virtual bool hasUnsafeBitpatterns();
virtual bool hasInvariant();
virtual Type *nextOf();
Type *baseElemOf();
@ -421,7 +421,7 @@ public:
MATCH constConv(Type *to) override;
MATCH implicitConvTo(Type *to) override;
Expression *defaultInitLiteral(const Loc &loc) override;
bool hasSystemFields() override;
bool hasUnsafeBitpatterns() override;
bool hasVoidInitPointers() override;
bool hasInvariant() override;
bool needsDestruction() override;
@ -739,7 +739,7 @@ public:
bool needsCopyOrPostblit() override;
bool needsNested() override;
bool hasVoidInitPointers() override;
bool hasSystemFields() override;
bool hasUnsafeBitpatterns() override;
bool hasInvariant() override;
MATCH implicitConvTo(Type *to) override;
MATCH constConv(Type *to) override;
@ -775,7 +775,7 @@ public:
MATCH constConv(Type *to) override;
bool isZeroInit(const Loc &loc) override;
bool hasVoidInitPointers() override;
bool hasSystemFields() override;
bool hasUnsafeBitpatterns() override;
bool hasInvariant() override;
Type *nextOf() override;

View file

@ -2,9 +2,13 @@
REQUIRED_ARGS: -preview=systemVariables
TEST_OUTPUT:
---
fail_compilation/systemvariables_void_init.d(29): Error: `void` initializers for `@system` variables not allowed in safe functions
fail_compilation/systemvariables_void_init.d(30): Error: `void` initializers for `@system` variables not allowed in safe functions
fail_compilation/systemvariables_void_init.d(31): Error: `void` initializers for `@system` variables not allowed in safe functions
fail_compilation/systemvariables_void_init.d(48): Error: `void` initializers for types with unsafe bit patterns are not allowed in safe functions
fail_compilation/systemvariables_void_init.d(49): Error: `void` initializers for types with unsafe bit patterns are not allowed in safe functions
fail_compilation/systemvariables_void_init.d(50): Error: `void` initializers for types with unsafe bit patterns are not allowed in safe functions
fail_compilation/systemvariables_void_init.d(51): Error: a `bool` must be 0 or 1, so void intializing it is not allowed in safe functions
fail_compilation/systemvariables_void_init.d(52): Error: a `bool` must be 0 or 1, so void intializing it is not allowed in safe functions
fail_compilation/systemvariables_void_init.d(53): Error: `void` initializers for types with unsafe bit patterns are not allowed in safe functions
fail_compilation/systemvariables_void_init.d(54): Error: `void` initializers for types with unsafe bit patterns are not allowed in safe functions
---
*/
@ -24,9 +28,50 @@ enum E : C
x = C.init,
}
enum B : bool
{
x,
}
struct SB
{
bool x;
}
struct SSB
{
SB sb;
}
void main() @safe
{
S s = void;
C c = void;
E e = void;
const bool b = void;
B bb = void;
SB sb = void;
SSB ssb = void;
}
// The following test is reduced from Phobos. The compiler generates this `opAssign`:
// (CopyPreventer __swap2 = void;) , __swap2 = this , (this = p , __swap2.~this());
// The compiler would give an error about void initialization a struct with a bool,
// but it can be trusted in this case because it's a compiler generated temporary.
auto staticArray(T)(T a) @safe
{
T c;
c = a;
}
void assignmentTest() @safe
{
static struct CopyPreventer
{
bool on;
this(this) @safe {}
~this() { }
}
staticArray(CopyPreventer());
}