mirror of
https://github.com/dlang/dmd.git
synced 2025-04-26 13:10:12 +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)
|
||||
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
|
||||
*/
|
||||
int inferred = 0;
|
||||
|
@ -732,7 +735,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
|||
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);
|
||||
|
||||
if (auto tt = tb.isTypeTuple())
|
||||
|
@ -1069,7 +1072,19 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
|||
if (dsymIsRef)
|
||||
{
|
||||
if (!dsym._init && dsym.ident != Id.This)
|
||||
.error(dsym.loc, "%s `%s` - initializer is required for `ref` variable", dsym.kind, dsym.toPrettyChars);
|
||||
{
|
||||
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);
|
||||
}
|
||||
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();
|
||||
|
@ -1303,31 +1318,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
|||
|
||||
Expression exp = ei.exp;
|
||||
Expression e1 = new VarExp(dsym.loc, dsym);
|
||||
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())
|
||||
{
|
||||
.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
|
||||
|
||||
void constructInit(bool isBlit)
|
||||
{
|
||||
if (isBlit)
|
||||
exp = new BlitExp(dsym.loc, e1, exp);
|
||||
|
@ -1338,6 +1330,48 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
|||
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)
|
||||
{
|
||||
dsym._init = new ErrorInitializer();
|
||||
|
|
|
@ -48,13 +48,19 @@ void test4()
|
|||
|
||||
/* TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/diag9679.d(60): 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(65): 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(71): Error: type `immutable(int)` cannot be assigned to `ref int x`
|
||||
fail_compilation/diag9679.d(66): Error: variable `diag9679.test5.r5` - initializer is required for `ref` variable
|
||||
fail_compilation/diag9679.d(66): Error: rvalue `0` cannot be assigned to `ref r5`
|
||||
fail_compilation/diag9679.d(71): Error: rvalue `4` cannot be assigned to `ref x`
|
||||
fail_compilation/diag9679.d(72): Error: returning `x` escapes a reference to local variable `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()
|
||||
{
|
||||
ref int r5;
|
||||
|
@ -71,3 +77,15 @@ void test7(immutable int y)
|
|||
ref int x = y;
|
||||
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()
|
||||
{
|
||||
test6475();
|
||||
|
@ -448,6 +480,7 @@ int main()
|
|||
test13950();
|
||||
testlocalref();
|
||||
testglobalref();
|
||||
testAutoRef();
|
||||
|
||||
printf("Success\n");
|
||||
return 0;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue