Bug 4539 – Refuse assignment to string literal

Status
RESOLVED
Resolution
FIXED
Severity
major
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2010-07-31T04:26:00Z
Last change time
2012-01-31T17:24:32Z
Keywords
accepts-invalid, patch
Assigned to
nobody
Creator
bearophile_hugs

Comments

Comment #0 by bearophile_hugs — 2010-07-31T04:26:35Z
dmd 2.047 compiles this code, but string literals can't be lvalues: void main() { "hello" = "red"; }
Comment #1 by andrej.mitrovich — 2010-07-31T07:27:57Z
I just found this by accident on the compiler docs page: http://www.digitalmars.com/d/2.0/dmd-windows.html " Differences between Windows and Linux versions * String literals are read-only under Linux. Attempting to write to them will cause a segment violation. " Maybe this is relevant?
Comment #2 by bearophile_hugs — 2010-07-31T08:48:12Z
I think that's not relevant, I think that refers to changing the content of a variable initialized with a string literal (plus cast to mutable). But the code I have shown is meaningless, because a string can't be a lvalue. It's like doing: void main() { 5 = 7; }
Comment #3 by andrej.mitrovich — 2010-07-31T09:18:53Z
Yeah, it does not make sense at all. But it gets worse: import std.stdio; void main() { "hello" = "red"; string x = "hello"; writeln(x); } Writes "red" That's not good. :)
Comment #4 by clugdbug — 2010-07-31T17:30:23Z
(In reply to comment #3) > Yeah, it does not make sense at all. But it gets worse: > > import std.stdio; > > void main() { > "hello" = "red"; > string x = "hello"; > writeln(x); > } > > Writes "red" > > That's not good. :) Ouch!
Comment #5 by nfxjfg — 2010-07-31T18:43:05Z
This segfaults on the far superior Linux (dmd v2.046), so yes, it's probably because OPTLINK can't do read-only sections.
Comment #6 by bearophile_hugs — 2010-10-29T09:55:19Z
A related bug found by denis spir: auto p = &"hello"; String literals aren't lvalues, so you can't take their address. Just as you can't tale the address of a decimal literal: auto q = &(1);
Comment #7 by k.hara.pg — 2011-04-27T04:16:32Z
Comment #8 by kennytm — 2011-04-29T07:04:05Z
*** Issue 4309 has been marked as a duplicate of this issue. ***
Comment #9 by bugzilla — 2011-06-04T22:55:03Z
(In reply to comment #7) > Patch posted: > https://github.com/D-Programming-Language/dmd/pull/46 See github for problems with the patch.
Comment #10 by k.hara.pg — 2011-06-04T23:19:38Z
I think the main problem is that dmd treats string literal as lvalue. Lvalue can appear on left hand side of assignment, so string literal now asignable. Patch comment #7 fixes this behavior, and this change also refuse string literal on ref parameter as a side effect. It seems to me that it is correct refusing string literal on ref parameter. So this change breaks existing code. (If D specification treats string literal specially, my think is mistaken. But it might be not.)
Comment #11 by yebblies — 2011-07-01T06:36:13Z
A new patch that reapplies the old one and fixes the failing tests: https://github.com/D-Programming-Language/dmd/pull/188
Comment #12 by yebblies — 2011-09-04T23:30:28Z
Comment #13 by yebblies — 2011-12-12T21:35:53Z
*** Issue 6882 has been marked as a duplicate of this issue. ***
Comment #14 by verylonglogin.reg — 2011-12-25T02:49:33Z
*** Issue 7161 has been marked as a duplicate of this issue. ***
Comment #15 by k.hara.pg — 2011-12-25T07:29:50Z
Updated patch. https://github.com/D-Programming-Language/dmd/pull/164 A string literal should be able to bind a reference to static array type. In the context of ref binding, string literal should work as like static array value. Example: void main() { void foo1(ref string s){} // ref slice void foo2(ref const char[10] s){} // difference of length void foo3(ref char[5] s){} // mutable element void foo4(ref const char[5] s) { assert(s[0] == 'h'); assert(s[4] == 'o'); } void foo5(ref const ubyte[5] s) { assert(s[0] == 0xc3); assert(s[4] == 0x61); } static assert(!__traits(compiles, foo1("hello"))); static assert(!__traits(compiles, foo2("hello"))); static assert(!__traits(compiles, foo3("hello"))); foo4("hello"); foo5(cast(ubyte[5])x"c3fcd3d761"); import std.conv; static assert(!__traits(compiles, parse!int("10") == 10)); }
Comment #16 by github-bugzilla — 2012-01-29T12:21:34Z
Commit pushed to master at https://github.com/D-Programming-Language/dmd https://github.com/D-Programming-Language/dmd/commit/7f33ed71d8897ec0d03828c41063213af0283d02 Merge pull request #164 from 9rnsr/fix4539 Retry to fix issue 4539 - Refuse assignment to string literal
Comment #17 by bearophile_hugs — 2012-01-29T14:36:02Z
With the latest DMD2.058head this code: void foo(immutable ref string) {} void main() { foo("hello"); } Gives: test.d(3): Error: function test.foo (ref immutable(char[]) _param_0) is not callable using argument types (string) Is this expected? (Also note the function signature is (ref immutable(char[]) _param_0) while I have specified an immutable ref).
Comment #18 by k.hara.pg — 2012-01-29T15:20:53Z
(In reply to comment #17) > With the latest DMD2.058head this code: > > > void foo(immutable ref string) {} > void main() { > foo("hello"); > } > > > Gives: > > test.d(3): Error: function test.foo (ref immutable(char[]) _param_0) is not > callable using argument types (string) > > Is this expected? > > (Also note the function signature is (ref immutable(char[]) _param_0) while I > have specified an immutable ref). Yes, it is expected behavior. 'ref' storage class requires lvalue slice in this case, but string literal DOESN'T have slice, because it has only content. Instead, you can get a reference to string literal by `ref immutable(char[5])` or `ref const(char[5])` (5 == "hello".length), they bind just only content.
Comment #19 by andrej.mitrovich — 2012-01-29T20:51:39Z
(In reply to comment #17) > void foo(immutable ref string) {} I'm curious, what does `immutable ref string` buy you compared to just immutable string? Can't the compiler pass by ref automatically if it's an immutable type?
Comment #20 by bearophile_hugs — 2012-01-31T17:09:46Z
(In reply to comment #18) > Yes, it is expected behavior. I have just seen that some of my code that used to compile now gives a problem. This is a reduced version: void foo(ref string t) {} void main() { immutable string s; foo(s); } DMD 2.058head gives: test.d(4): Error: function test.foo (ref string t) is not callable using argument types (immutable(char[])) Is this correct?
Comment #21 by bearophile_hugs — 2012-01-31T17:24:32Z
(In reply to comment #20) > Is this correct? Yes, it's correct, sorry.