mirror of
https://github.com/dlang/dmd.git
synced 2025-04-26 21:21:48 +03:00
Implement auto ref for local variables
This commit is contained in:
parent
b02f718380
commit
f7f320a8e4
3 changed files with 117 additions and 32 deletions
|
@ -615,6 +615,9 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||||
if (ad)
|
if (ad)
|
||||||
dsym.storage_class |= ad.storage_class & STC.TYPECTOR;
|
dsym.storage_class |= ad.storage_class & STC.TYPECTOR;
|
||||||
|
|
||||||
|
if ((dsym.storage_class & STC.auto_) && (dsym.storage_class & STC.ref_))
|
||||||
|
dsym.storage_class |= STC.autoref;
|
||||||
|
|
||||||
/* If auto type inference, do the inference
|
/* If auto type inference, do the inference
|
||||||
*/
|
*/
|
||||||
int inferred = 0;
|
int inferred = 0;
|
||||||
|
@ -732,7 +735,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||||
dsym.type = Type.terror;
|
dsym.type = Type.terror;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((dsym.storage_class & STC.auto_) && !inferred)
|
if ((dsym.storage_class & STC.auto_) && !inferred && !(dsym.storage_class & STC.autoref))
|
||||||
.error(dsym.loc, "%s `%s` - storage class `auto` has no effect if type is not inferred, did you mean `scope`?", dsym.kind, dsym.toPrettyChars);
|
.error(dsym.loc, "%s `%s` - storage class `auto` has no effect if type is not inferred, did you mean `scope`?", dsym.kind, dsym.toPrettyChars);
|
||||||
|
|
||||||
if (auto tt = tb.isTypeTuple())
|
if (auto tt = tb.isTypeTuple())
|
||||||
|
@ -1069,8 +1072,20 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||||
if (dsymIsRef)
|
if (dsymIsRef)
|
||||||
{
|
{
|
||||||
if (!dsym._init && dsym.ident != Id.This)
|
if (!dsym._init && dsym.ident != Id.This)
|
||||||
|
{
|
||||||
|
if (dsym.storage_class & STC.autoref)
|
||||||
|
{
|
||||||
|
dsymIsRef = false;
|
||||||
|
dsym.storage_class &= ~STC.ref_;
|
||||||
|
}
|
||||||
|
else
|
||||||
.error(dsym.loc, "%s `%s` - initializer is required for `ref` variable", dsym.kind, dsym.toPrettyChars);
|
.error(dsym.loc, "%s `%s` - initializer is required for `ref` variable", dsym.kind, dsym.toPrettyChars);
|
||||||
}
|
}
|
||||||
|
else if (dsym._init.isVoidInitializer())
|
||||||
|
{
|
||||||
|
.error(dsym.loc, "%s `%s` - void initializer not allowed for `ref` variable", dsym.kind, dsym.toPrettyChars);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FuncDeclaration fd = parent.isFuncDeclaration();
|
FuncDeclaration fd = parent.isFuncDeclaration();
|
||||||
if (dsym.type.isScopeClass() && !(dsym.storage_class & STC.nodtor))
|
if (dsym.type.isScopeClass() && !(dsym.storage_class & STC.nodtor))
|
||||||
|
@ -1303,31 +1318,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||||
|
|
||||||
Expression exp = ei.exp;
|
Expression exp = ei.exp;
|
||||||
Expression e1 = new VarExp(dsym.loc, dsym);
|
Expression e1 = new VarExp(dsym.loc, dsym);
|
||||||
if (dsymIsRef) // follow logic similar to typesem.argumentMatchParameter() and statementsem.visitForeach()
|
|
||||||
{
|
void constructInit(bool isBlit)
|
||||||
dsym.storage_class |= STC.nodtor;
|
|
||||||
exp = exp.expressionSemantic(sc);
|
|
||||||
Type tp = dsym.type;
|
|
||||||
Type ta = exp.type;
|
|
||||||
if (!exp.isLvalue())
|
|
||||||
{
|
|
||||||
.error(dsym.loc, "rvalue `%s` cannot be assigned to `ref %s`", exp.toChars(), dsym.toChars());
|
|
||||||
exp = ErrorExp.get();
|
|
||||||
}
|
|
||||||
else if (!ta.constConv(tp))
|
|
||||||
{
|
|
||||||
.error(dsym.loc, "type `%s` cannot be assigned to `ref %s %s`", ta.toChars(), tp.toChars(), dsym.toChars());
|
|
||||||
exp = ErrorExp.get();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
exp = new ConstructExp(dsym.loc, e1, exp);
|
|
||||||
dsym.canassign++;
|
|
||||||
exp = exp.expressionSemantic(sc);
|
|
||||||
dsym.canassign--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
if (isBlit)
|
if (isBlit)
|
||||||
exp = new BlitExp(dsym.loc, e1, exp);
|
exp = new BlitExp(dsym.loc, e1, exp);
|
||||||
|
@ -1338,6 +1330,48 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
||||||
dsym.canassign--;
|
dsym.canassign--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dsymIsRef) // follow logic similar to typesem.argumentMatchParameter() and statementsem.visitForeach()
|
||||||
|
{
|
||||||
|
dsym.storage_class |= STC.nodtor;
|
||||||
|
exp = exp.expressionSemantic(sc);
|
||||||
|
Type tp = dsym.type;
|
||||||
|
Type ta = exp.type;
|
||||||
|
if (!exp.isLvalue())
|
||||||
|
{
|
||||||
|
if (dsym.storage_class & STC.autoref)
|
||||||
|
{
|
||||||
|
dsym.storage_class &= ~STC.ref_;
|
||||||
|
constructInit(isBlit);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
.error(dsym.loc, "rvalue `%s` cannot be assigned to `ref %s`", exp.toChars(), dsym.toChars());
|
||||||
|
exp = ErrorExp.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!ta.constConv(tp))
|
||||||
|
{
|
||||||
|
if (dsym.storage_class & STC.autoref)
|
||||||
|
{
|
||||||
|
dsym.storage_class &= ~STC.ref_;
|
||||||
|
constructInit(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
.error(dsym.loc, "type `%s` cannot be assigned to `ref %s %s`", ta.toChars(), tp.toChars(), dsym.toChars());
|
||||||
|
exp = ErrorExp.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
constructInit(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
constructInit(isBlit);
|
||||||
|
}
|
||||||
|
|
||||||
if (exp.op == EXP.error)
|
if (exp.op == EXP.error)
|
||||||
{
|
{
|
||||||
dsym._init = new ErrorInitializer();
|
dsym._init = new ErrorInitializer();
|
||||||
|
|
|
@ -48,13 +48,19 @@ void test4()
|
||||||
|
|
||||||
/* TEST_OUTPUT:
|
/* TEST_OUTPUT:
|
||||||
---
|
---
|
||||||
fail_compilation/diag9679.d(60): Error: variable `diag9679.test5.r5` - initializer is required for `ref` variable
|
fail_compilation/diag9679.d(66): Error: variable `diag9679.test5.r5` - initializer is required for `ref` variable
|
||||||
fail_compilation/diag9679.d(60): Error: rvalue `0` cannot be assigned to `ref r5`
|
fail_compilation/diag9679.d(66): Error: rvalue `0` cannot be assigned to `ref r5`
|
||||||
fail_compilation/diag9679.d(65): Error: rvalue `4` cannot be assigned to `ref x`
|
fail_compilation/diag9679.d(71): Error: rvalue `4` cannot be assigned to `ref x`
|
||||||
fail_compilation/diag9679.d(66): Error: returning `x` escapes a reference to local variable `x`
|
fail_compilation/diag9679.d(72): Error: returning `x` escapes a reference to local variable `x`
|
||||||
fail_compilation/diag9679.d(71): Error: type `immutable(int)` cannot be assigned to `ref int x`
|
fail_compilation/diag9679.d(77): Error: type `immutable(int)` cannot be assigned to `ref int x`
|
||||||
|
fail_compilation/diag9679.d(84): Error: returning `x` escapes a reference to local variable `x`
|
||||||
|
fail_compilation/diag9679.d(89): Error: variable `diag9679.test9.x` - void initializer not allowed for `ref` variable
|
||||||
|
fail_compilation/diag9679.d(90): Error: variable `diag9679.test9.y` - void initializer not allowed for `ref` variable
|
||||||
---
|
---
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void test5()
|
void test5()
|
||||||
{
|
{
|
||||||
ref int r5;
|
ref int r5;
|
||||||
|
@ -71,3 +77,15 @@ void test7(immutable int y)
|
||||||
ref int x = y;
|
ref int x = y;
|
||||||
x = 5;
|
x = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ref int test8()
|
||||||
|
{
|
||||||
|
auto ref int x = 3;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test9()
|
||||||
|
{
|
||||||
|
ref int x = void;
|
||||||
|
auto ref int y = void;
|
||||||
|
}
|
||||||
|
|
|
@ -433,6 +433,38 @@ void testglobalref()
|
||||||
|
|
||||||
/***************************************************/
|
/***************************************************/
|
||||||
|
|
||||||
|
void testAutoRef()
|
||||||
|
{
|
||||||
|
auto ref int x = 4;
|
||||||
|
auto ref int y = x;
|
||||||
|
auto ref z = x + 0;
|
||||||
|
auto ref char w;
|
||||||
|
auto ref float v = x; // type conversion
|
||||||
|
|
||||||
|
static assert(!__traits(isRef, x));
|
||||||
|
static assert( __traits(isRef, y));
|
||||||
|
static assert(!__traits(isRef, z));
|
||||||
|
static assert(!__traits(isRef, w));
|
||||||
|
static assert(!__traits(isRef, v));
|
||||||
|
|
||||||
|
assert(&y == &x);
|
||||||
|
assert(&z != &x);
|
||||||
|
assert(w == char.init);
|
||||||
|
assert(v == 4.0);
|
||||||
|
|
||||||
|
if (auto ref int a = 3)
|
||||||
|
static assert(!__traits(isRef, a));
|
||||||
|
|
||||||
|
while (auto ref a = x)
|
||||||
|
{
|
||||||
|
static assert(is(typeof(a) == int));
|
||||||
|
static assert(__traits(isRef, a));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
test6475();
|
test6475();
|
||||||
|
@ -448,6 +480,7 @@ int main()
|
||||||
test13950();
|
test13950();
|
||||||
testlocalref();
|
testlocalref();
|
||||||
testglobalref();
|
testglobalref();
|
||||||
|
testAutoRef();
|
||||||
|
|
||||||
printf("Success\n");
|
printf("Success\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue