fix Issue 23145 - Stack allocation of scope new variables defeats @safe (#14175)

This commit is contained in:
Walter Bright 2023-02-08 23:29:07 -08:00 committed by GitHub
parent f1b70f41f7
commit 74e40179b5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 103 additions and 42 deletions

View file

@ -1065,7 +1065,7 @@ private DtorDeclaration buildWindowsCppDtor(AggregateDeclaration ad, DtorDeclara
{ {
auto cldec = ad.isClassDeclaration(); auto cldec = ad.isClassDeclaration();
if (!cldec || cldec.cppDtorVtblIndex == -1) // scalar deleting dtor not built for non-virtual dtors if (!cldec || cldec.cppDtorVtblIndex == -1) // scalar deleting dtor not built for non-virtual dtors
return dtor; return dtor; // perhaps also do this if STC.scope_ is set
// generate deleting C++ destructor corresponding to: // generate deleting C++ destructor corresponding to:
// void* C::~C(int del) // void* C::~C(int del)
@ -1077,8 +1077,9 @@ private DtorDeclaration buildWindowsCppDtor(AggregateDeclaration ad, DtorDeclara
Parameter delparam = new Parameter(STC.undefined_, Type.tuns32, Identifier.idPool("del"), new IntegerExp(dtor.loc, 0, Type.tuns32), null); Parameter delparam = new Parameter(STC.undefined_, Type.tuns32, Identifier.idPool("del"), new IntegerExp(dtor.loc, 0, Type.tuns32), null);
Parameters* params = new Parameters; Parameters* params = new Parameters;
params.push(delparam); params.push(delparam);
auto ftype = new TypeFunction(ParameterList(params), Type.tvoidptr, LINK.cpp, dtor.storage_class); const stc = dtor.storage_class & ~STC.scope_; // because we add the `return this;` later
auto func = new DtorDeclaration(dtor.loc, dtor.loc, dtor.storage_class, Id.cppdtor); auto ftype = new TypeFunction(ParameterList(params), Type.tvoidptr, LINK.cpp, stc);
auto func = new DtorDeclaration(dtor.loc, dtor.loc, stc, Id.cppdtor);
func.type = ftype; func.type = ftype;
// Always generate the function with body, because it is not exported from DLLs. // Always generate the function with body, because it is not exported from DLLs.

View file

@ -1090,9 +1090,26 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
ex = (cast(AssignExp)ex).e2; ex = (cast(AssignExp)ex).e2;
if (auto ne = ex.isNewExp()) if (auto ne = ex.isNewExp())
{ {
// See if initializer is a NewExp that can be allocated on the stack /* See if initializer is a NewExp that can be allocated on the stack.
*/
if (dsym.type.toBasetype().ty == Tclass) if (dsym.type.toBasetype().ty == Tclass)
{ {
/* Unsafe to allocate on stack if constructor is not `scope` because the `this` can leak.
* https://issues.dlang.org/show_bug.cgi?id=23145
*/
if (ne.member && !(ne.member.storage_class & STC.scope_))
{
if (sc.func.isSafe())
{
// @@@DEPRECATED_2.112@@@
deprecation(dsym.loc,
"`scope` allocation of `%s` requires that constructor be annotated with `scope`",
dsym.toChars());
deprecationSupplemental(ne.member.loc, "is the location of the constructor");
}
else
sc.func.setUnsafe();
}
ne.onstack = 1; ne.onstack = 1;
dsym.onstack = true; dsym.onstack = true;
} }
@ -4199,8 +4216,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
override void visit(DtorDeclaration dd) override void visit(DtorDeclaration dd)
{ {
//printf("DtorDeclaration::semantic() %s\n", toChars()); //printf("DtorDeclaration::semantic() %s\n", dd.toChars());
//printf("ident: %s, %s, %p, %p\n", ident.toChars(), Id.dtor.toChars(), ident, Id.dtor); //printf("ident: %s, %s, %p, %p\n", dd.ident.toChars(), Id.dtor.toChars(), dd.ident, Id.dtor);
if (dd.semanticRun >= PASS.semanticdone) if (dd.semanticRun >= PASS.semanticdone)
return; return;
if (dd._scope) if (dd._scope)
@ -5342,7 +5359,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
// is less strict (e.g. `preview=dtorfields` might introduce a call to a less qualified dtor) // is less strict (e.g. `preview=dtorfields` might introduce a call to a less qualified dtor)
auto ctor = new CtorDeclaration(cldec.loc, Loc.initial, 0, tf); auto ctor = new CtorDeclaration(cldec.loc, Loc.initial, 0, tf);
ctor.storage_class |= STC.inference; ctor.storage_class |= STC.inference | (fd.storage_class & STC.scope_);
ctor.isGenerated = true; ctor.isGenerated = true;
ctor.fbody = new CompoundStatement(Loc.initial, new Statements()); ctor.fbody = new CompoundStatement(Loc.initial, new Statements());

View file

@ -2320,6 +2320,7 @@ extern (C++) class FuncDeclaration : Declaration
* base.in(); * base.in();
* assert(false, "Logic error: " ~ thr.msg); * assert(false, "Logic error: " ~ thr.msg);
* } * }
* }
*/ */
foreach (fdv; foverrides) foreach (fdv; foverrides)
@ -3861,7 +3862,7 @@ extern (C++) final class CtorDeclaration : FuncDeclaration
{ {
super(loc, endloc, Id.ctor, stc, type); super(loc, endloc, Id.ctor, stc, type);
this.isCpCtor = isCpCtor; this.isCpCtor = isCpCtor;
//printf("CtorDeclaration(loc = %s) %s\n", loc.toChars(), toChars()); //printf("CtorDeclaration(loc = %s) %s %p\n", loc.toChars(), toChars(), this);
} }
override CtorDeclaration syntaxCopy(Dsymbol s) override CtorDeclaration syntaxCopy(Dsymbol s)

View file

@ -13,11 +13,14 @@
module dmd.nogc; module dmd.nogc;
import core.stdc.stdio;
import dmd.aggregate; import dmd.aggregate;
import dmd.apply; import dmd.apply;
import dmd.astenums; import dmd.astenums;
import dmd.declaration; import dmd.declaration;
import dmd.dscope; import dmd.dscope;
import dmd.errors;
import dmd.expression; import dmd.expression;
import dmd.func; import dmd.func;
import dmd.globals; import dmd.globals;

View file

@ -0,0 +1,39 @@
/* TEST_OUTPUT:
---
compilable/test23145.d(117): Deprecation: `scope` allocation of `c` requires that constructor be annotated with `scope`
compilable/test23145.d(111): is the location of the constructor
compilable/test23145.d(124): Deprecation: `scope` allocation of `c` requires that constructor be annotated with `scope`
compilable/test23145.d(111): is the location of the constructor
---
*/
// https://issues.dlang.org/show_bug.cgi?id=23145
#line 100
class D
{
C c;
}
class C
{
D d;
int x=3;
this(int i) scope @safe @nogc;
this(D d) @safe @nogc;
}
C foo(D d)@nogc @safe
{
scope e = new C(1); // ok
scope c = new C(d); // deprecation
return c.d.c;
}
C bax(D d) @safe
{
scope e = new C(1); // ok
scope c = new C(d); // deprecation
return c.d.c;
}

View file

@ -67,13 +67,13 @@ int ax;
class A2 class A2
{ {
this() this() scope
{ {
printf("A2.this()\n"); printf("A2.this()\n");
ax += 1; ax += 1;
} }
~this() ~this() scope
{ {
printf("A2.~this()\n"); printf("A2.~this()\n");
ax += 1000; ax += 1000;
@ -102,12 +102,12 @@ class Parent3
class Child3 : Parent3 class Child3 : Parent3
{ {
this(){ this() scope {
assert(status3==0); assert(status3==0);
status3=1; status3=1;
} }
~this(){ ~this() scope {
assert(status3==1); assert(status3==1);
status3=2; status3=2;
} }

View file

@ -38,12 +38,12 @@ extern (C) int printf(scope const char*, ...);
extern (C++) class CppA extern (C++) class CppA
{ {
int num; int num;
this(int num) this(int num) scope
{ {
this.num = num; this.num = num;
} }
~this() ~this() scope
{ {
printf("%d: CppA.~this\n", num); printf("%d: CppA.~this\n", num);
} }
@ -51,12 +51,12 @@ extern (C++) class CppA
extern (C++) class CppB : CppA extern (C++) class CppB : CppA
{ {
this(int num) this(int num) scope
{ {
super(num); super(num);
} }
~this() ~this() scope
{ {
printf("%d: CppB.~this\n", num); printf("%d: CppB.~this\n", num);
} }
@ -64,12 +64,12 @@ extern (C++) class CppB : CppA
extern (C++) class CppC : CppB extern (C++) class CppC : CppB
{ {
this(int num) this(int num) scope
{ {
super(num); super(num);
} }
~this() ~this() scope
{ {
printf("%d: CppC.~this\n", num); printf("%d: CppC.~this\n", num);
} }
@ -78,12 +78,12 @@ extern (C++) class CppC : CppB
extern (D) class DA extern (D) class DA
{ {
int num; int num;
this(int num) this(int num) scope
{ {
this.num = num; this.num = num;
} }
~this() ~this() scope
{ {
printf("%d: DA.~this\n", num); printf("%d: DA.~this\n", num);
} }
@ -91,12 +91,12 @@ extern (D) class DA
extern (D) class DB : DA extern (D) class DB : DA
{ {
this(int num) this(int num) scope
{ {
super(num); super(num);
} }
~this() ~this() scope
{ {
printf("%d: DB.~this\n", num); printf("%d: DB.~this\n", num);
} }
@ -104,12 +104,12 @@ extern (D) class DB : DA
extern (D) class DC : DB extern (D) class DC : DB
{ {
this(int num) this(int num) scope
{ {
super(num); super(num);
} }
~this() ~this() scope
{ {
printf("%d: DC.~this\n", num); printf("%d: DC.~this\n", num);
} }
@ -118,7 +118,7 @@ extern (D) class DC : DB
extern (C++) class CppNoDestruct extern (C++) class CppNoDestruct
{ {
int num; int num;
this(int num) this(int num) scope
{ {
this.num = num; this.num = num;
} }

View file

@ -82,13 +82,13 @@ int x5;
class Foo5 class Foo5
{ {
this () this () scope
{ {
printf ("Constructor\n"); printf ("Constructor\n");
assert(x5 == 0); assert(x5 == 0);
x5++; x5++;
} }
~this () ~this () scope
{ {
printf ("Destructor\n"); printf ("Destructor\n");
assert(x5 == 2); assert(x5 == 2);

View file

@ -4,7 +4,7 @@
string exp() string exp()
{ {
string s = "a = b + c * d + a;"; string s = "a = b + c * d + a;";
foreach (i; 0 .. 9) foreach (i; 0 .. 8)
s = s ~ s; s = s ~ s;
return s; return s;
} }
@ -22,6 +22,6 @@ int main()
{ {
int a = test(); int a = test();
printf("a = %d\n", a); printf("a = %d\n", a);
assert(test() == 7169); assert(test() == 3585);
return 0; return 0;
} }

View file

@ -1322,22 +1322,22 @@ void test70()
class C71 class C71
{ {
static int cnt; static int cnt;
this() { printf("C()\n"); cnt++; } this() scope { printf("C()\n"); cnt++; }
~this() { printf("~C()\n"); cnt--; } ~this() scope { printf("~C()\n"); cnt--; }
} }
class D71 class D71
{ {
static int cnt; static int cnt;
this() { printf("D()\n"); cnt++; } this() scope { printf("D()\n"); cnt++; }
~this() { printf("~D()\n"); cnt--; } ~this() scope { printf("~D()\n"); cnt--; }
} }
class E71 class E71
{ {
static int cnt; static int cnt;
this() { printf("E()\n"); cnt++; } this() scope { printf("E()\n"); cnt++; }
~this() { printf("~E()\n"); cnt--; } ~this() scope { printf("~E()\n"); cnt--; }
} }
void test71() void test71()

View file

@ -786,8 +786,8 @@ void test42()
int x44; int x44;
class A44 { class A44 {
this() { printf("A44 ctor\n"); x44 += 1; } this() scope { printf("A44 ctor\n"); x44 += 1; }
~this() { printf("A44 dtor\n"); x44 += 0x100; } ~this() scope { printf("A44 dtor\n"); x44 += 0x100; }
} }
class B44 : A44 { } class B44 : A44 { }

View file

@ -494,7 +494,7 @@ void test23()
int status24; int status24;
class C24{ class C24{
this(){ this() scope {
assert(status24==0); assert(status24==0);
status24+=2; status24+=2;
} }

View file

@ -1324,7 +1324,7 @@ extern(C++)
class Cpp15589Derived : Cpp15589Base class Cpp15589Derived : Cpp15589Base
{ {
public: public:
this(); this() scope;
final ~this(); final ~this();
int b; int b;
} }
@ -1334,7 +1334,7 @@ extern(C++)
public: public:
void beforeDtor(); void beforeDtor();
this(); this() scope;
~this(); ~this();
void afterDtor(); void afterDtor();
@ -1344,7 +1344,7 @@ extern(C++)
class Cpp15589DerivedVirtual : Cpp15589BaseVirtual class Cpp15589DerivedVirtual : Cpp15589BaseVirtual
{ {
public: public:
this(); this() scope;
~this(); ~this();
override void afterDtor(); override void afterDtor();
@ -1355,7 +1355,7 @@ extern(C++)
class Cpp15589IntroducingVirtual : Cpp15589Base class Cpp15589IntroducingVirtual : Cpp15589Base
{ {
public: public:
this(); this() scope;
void beforeIntroducedVirtual(); void beforeIntroducedVirtual();
~this(); ~this();
void afterIntroducedVirtual(int); void afterIntroducedVirtual(int);