5799 – Address-of operator fails on nested conditional operator expression

D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 5799 - Address-of operator fails on nested conditional operator expression
Summary: Address-of operator fails on nested conditional operator expression
Status: RESOLVED FIXED
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: All All
: P2 normal
Assignee: No Owner
URL:
Keywords: patch, rejects-valid
Depends on:
Blocks:
Reported: 2011年03月30日 13:43 UTC by timon.gehr
Modified: 2011年08月13日 14:58 UTC (History)
2 users (show)

See Also:


Attachments
Add an attachment (proposed patch, testcase, etc.)

Note You need to log in before you can comment on or make changes to this issue.
Description timon.gehr 2011年03月30日 13:43:22 UTC
The following (perfectly valid) D code is rejected by dmd:
int main(){
 int a;
 int *u=&(a ? a : (a ? a : a));
 return 0;
}
Error Message:
minimal.d(3): Error: incompatible types for ((&a) ? (&*(a ? &a : &a))): 'int*' and 'int**'
minimal.d(3): Error: cannot implicitly convert expression (a ? __error : (__error)) of type int* to int*
This is nonsense, clearly, the expression
(a ? a : (a ? a : a)) evaluates to a valid int lvalue, therefore it can have the Address-of operator applied to it.
(For comparison: the following code compiles:
int main(){
 int a;
 (a ? a : (a ? a : a))=a;
 return 0;
})
Comment 1 timon.gehr 2011年04月18日 16:00:30 UTC
I had a look at the DMD source code and I identified the problem:
expression.c (1326):
Expression *Expression::addressOf(Scope *sc){
 Expression *e;
 //printf("Expression::addressOf()\n");
 e = toLvalue(sc, NULL);
 e = new AddrExp(loc, e);
 e->type = type->pointerTo();
 return e;
}
Note how the instruction e->type = type->pointerTo(); is dependent on the fact that method toLvalue does not change the type of the expression. However, the current Implementation of CondExp::toLvalue changes the object while creating an Lvalue. Disaster strikes because CondExp::toLvalue calls addressOf on it's two subexpressions. If one or both of them are CondExp, e->type may be incorrect. The reported bug is an instance of this one.
This can be easily resolved by operating on a copy of the CondExp object in CondExp::toLvalue instead of on the original object.
Suggested fix:
Replace the current implementation of CondExp::toLvalue in expression.c (11140)
- Expression *CondExp::toLvalue(Scope *sc, Expression *ex)
- {
- PtrExp *e;
- 
- // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2)
- e = new PtrExp(loc, this, type);
- 
- e1 = e1->addressOf(sc);
- //e1 = e1->toLvalue(sc, NULL);
- 
- e2 = e2->addressOf(sc);
- //e2 = e2->toLvalue(sc, NULL);
- 
- typeCombine(sc);
- 
- type = e2->type;
- return e;
- }
With this one:
+ Expression *CondExp::toLvalue(Scope *sc, Expression *ex)
+ {
+ CondExp *e = (CondExp*)copy();
+ 
+ // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2)
+ e->e1 = e->e1->addressOf(sc);
+ e->e2 = e->e2->addressOf(sc);
+ 
+ e->typeCombine(sc);
+ 
+ e->type = e->e2->type;
+ return new PtrExp(loc, e, type);
+ }
Comment 2 Kenji Hara 2011年07月07日 23:38:21 UTC
https://github.com/D-Programming-Language/dmd/pull/215 


AltStyle によって変換されたページ (->オリジナル) /