fix #21203 Placement new does not count as initialization (#21243)

This commit is contained in:
Walter Bright 2025-04-16 00:14:46 -07:00 committed by GitHub
parent 1244ef260b
commit d6602a6b0f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 46 additions and 11 deletions

View file

@ -4906,6 +4906,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
error(p.loc, "PlacementExpression `%s` of type `%s` be unshared and mutable", p.toChars(), toChars(p.type)); error(p.loc, "PlacementExpression `%s` of type `%s` be unshared and mutable", p.toChars(), toChars(p.type));
return setError(); return setError();
} }
checkModifiable(exp.placement, sc);
} }
//for error messages if the argument in [] is not convertible to size_t //for error messages if the argument in [] is not convertible to size_t
@ -15806,10 +15807,11 @@ private Expression toLvalueImpl(Expression _this, Scope* sc, const(char)* action
} }
/*************************************** /***************************************
* Parameters: * Params:
* sc: scope * exp = expression to check if modifiable
* flag: 1: do not issue error message for invalid modification * sc = scope
2: the exp is a DotVarExp and a subfield of the leftmost * flag = noError - do not issue error message for invalid modification
fieldAssign - exp is a DotVarExp and a subfield of the leftmost
variable is modified variable is modified
* Returns: * Returns:
* Whether the type is modifiable * Whether the type is modifiable
@ -16763,11 +16765,12 @@ enum ModifyFlags
} }
/************************************* /*************************************
* Check to see if declaration can be modified in this context (sc). * Check to see if `d` can be modified in this context `sc`.
* Issue error if not. * Issue error if not.
* Params: * Params:
* d = declaration to check
* loc = location for error messages * loc = location for error messages
* e1 = `null` or `this` expression when this declaration is a field * e1 = `null` or `this` expression when `d` is a field
* sc = context * sc = context
* flag = if the first bit is set it means do not issue error message for * flag = if the first bit is set it means do not issue error message for
* invalid modification; if the second bit is set, it means that * invalid modification; if the second bit is set, it means that
@ -16777,6 +16780,7 @@ enum ModifyFlags
*/ */
private Modifiable checkModify(Declaration d, Loc loc, Scope* sc, Expression e1, ModifyFlags flag) private Modifiable checkModify(Declaration d, Loc loc, Scope* sc, Expression e1, ModifyFlags flag)
{ {
//printf("checkModify() d: %s, e1: %s\n", d.toChars(), e1.toChars());
VarDeclaration v = d.isVarDeclaration(); VarDeclaration v = d.isVarDeclaration();
if (v && v.canassign) if (v && v.canassign)
return Modifiable.initialization; return Modifiable.initialization;
@ -16822,15 +16826,19 @@ private Modifiable checkModify(Declaration d, Loc loc, Scope* sc, Expression e1,
} }
/*********************************************** /***********************************************
* Mark variable v as modified if it is inside a constructor that var * Mark variable `var` as modified if it is inside a constructor that `var`
* is a field in. * is a field in.
* Also used to allow immutable globals to be initialized inside a static constructor. * Also used to allow immutable globals to be initialized inside a static constructor.
* Params:
* loc = location for error messages
* sc = scope
* var = field
* Returns: * Returns:
* true if it's an initialization of v * true if it's an initialization of `var`
*/ */
private bool modifyFieldVar(Loc loc, Scope* sc, VarDeclaration var, Expression e1) private bool modifyFieldVar(Loc loc, Scope* sc, VarDeclaration var, Expression e1)
{ {
//printf("modifyFieldVar(var = %s)\n", var.toChars()); //printf("modifyFieldVar(var: %s, e1: %s)\n", var.toChars(), e1.toChars());
Dsymbol s = sc.func; Dsymbol s = sc.func;
while (1) while (1)
{ {
@ -16846,7 +16854,7 @@ private bool modifyFieldVar(Loc loc, Scope* sc, VarDeclaration var, Expression e
bool result = true; bool result = true;
var.ctorinit = true; var.ctorinit = true;
//printf("setting ctorinit\n"); //printf("setting ctorinit for %s\n", var.toChars());
if (var.isField() && sc.ctorflow.fieldinit.length && !sc.intypeof) if (var.isField() && sc.ctorflow.fieldinit.length && !sc.intypeof)
{ {

View file

@ -106,6 +106,32 @@ void test7()
assert(t.x == 10 && t.y == 20); assert(t.x == 10 && t.y == 20);
} }
/*************************************************/
// https://github.com/dlang/dmd/issues/21203
struct Y8
{
int a;
this() @disable; // default disabled
this(int i) { a = i; }
}
struct S8
{
Y8 m;
this(int x)
{
new(m) Y8(x); // initialise `m`
}
}
void test8()
{
S8 s = S8(3);
assert(s.m.a == 3);
}
/*************************************************/ /*************************************************/
int main() int main()
@ -117,6 +143,7 @@ int main()
test5(); test5();
test6(); test6();
test7(); test7();
test8();
return 0; return 0;
} }