mirror of
https://github.com/dlang/dmd.git
synced 2025-04-28 06:00:13 +03:00
Fix 20148 - void initializated bool can be both true and false
This commit is contained in:
parent
8272384b3e
commit
0b677d90ee
6 changed files with 86 additions and 26 deletions
|
@ -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;
|
||||
|
|
|
@ -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)) &&
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue