<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Tue, Mar 25, 2014 at 8:30 AM, Tom Honermann <span dir="ltr"><<a href="mailto:thonermann@coverity.com" target="_blank">thonermann@coverity.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">Using clang trunk:<br>
<br>
$ cat t.cpp<br>
char ca[] = "text";<br>
<br>
$ clang --version<br>
clang version 3.5.0 (trunk 204467)<br>
...<br>
<br>
$ clang -c -Xclang -ast-dump t.cpp<br>
...<br>
`-VarDecl 0x7b0cb90 <t.cpp:1:1, col:13> ca 'char [5]'<br>
`-StringLiteral 0x7b0cc68 <col:13> 'char [5]' lvalue "text"<br>
<br>
Note that the type of the string literal is 'char [5]'. I would expect 'const char[5]'.<br>
<br>
I debugged a bit and the StringLiteral instance is initially created with a const qualified element type, but the const qualification is later removed by CheckStringInit() in lib/Sema/SemaInit.cpp. I suspect CheckStringInit() intends only to adjust the size of the string literal and not to change qualifiers on the element type.<br>
<br>
Actually, while debugging this, I realized the issue goes beyond qualifiers. The element type of the string literal itself is changed:<br>
<br>
$ cat t.cpp<br>
typedef char my_char;<br>
my_char ca[] = "text";<br>
<br>
$ clang -c -Xclang -ast-dump t.cpp<br>
...<br>
`-VarDecl 0x4e61730 <line:2:1, col:16> ca 'my_char [5]'<br>
`-StringLiteral 0x4e61808 <col:16> 'my_char [5]' lvalue "text"<br>
<br>
Note that the StringLiteral now has an array element type of 'my_char'.</blockquote><div><br></div><div>This is intentional, though surprising. A string literal expression that's used to initialize an array is quite a different beast from a string literal expression that's used to create a string literal object. In the initialization case, we're effectively initializing each element of the array from the corresponding character in the string literal, so it makes some degree of sense to model the string literal as having the same type as the initialized entity. (If we didn't do that, then to maintain the AST invariants we'd need to invent a new kind of implicit cast that switches out the type.)</div>
<div><br></div><div>This is similar to how we handle the semantic form of an InitListExpr. Consider:</div><div><br></div><div><div>typedef unsigned char my_char;</div><div>my_char arr[10] = { 't', 'e', 'x', 't', 0 };</div>
<div>my_char arr2[10] = "text";</div></div><div><br></div><div>This produces:</div><div><br></div><div><div>|-VarDecl 0x6c4f0b0 <line:2:1, col:43> arr 'my_char [10]'</div><div>| `-InitListExpr 0x6c4f1f0 <col:19, col:43> 'my_char [10]'</div>
<div>| |-ImplicitCastExpr 0x6c4f230 <col:21> 'my_char':'unsigned char' <IntegralCast></div><div>| | `-CharacterLiteral 0x6c4f108 <col:21> 'char' 116</div><div>| |-ImplicitCastExpr 0x6c4f250 <col:26> 'my_char':'unsigned char' <IntegralCast></div>
<div>| | `-CharacterLiteral 0x6c4f120 <col:26> 'char' 101</div><div>| |-ImplicitCastExpr 0x6c4f278 <col:31> 'my_char':'unsigned char' <IntegralCast></div><div>| | `-CharacterLiteral 0x6c4f138 <col:31> 'char' 120</div>
<div>| |-ImplicitCastExpr 0x6c4f2b0 <col:36> 'my_char':'unsigned char' <IntegralCast></div><div>| | `-CharacterLiteral 0x6c4f150 <col:36> 'char' 116</div><div>| `-ImplicitCastExpr 0x6c4f2c8 <col:41> 'my_char':'unsigned char' <IntegralCast></div>
<div>| `-IntegerLiteral 0x6c4f168 <col:41> 'int' 0</div><div>`-VarDecl 0x6c96540 <line:3:1, col:20> arr2 'my_char [10]'</div><div> `-StringLiteral 0x6c96618 <col:20> 'my_char [10]' lvalue "text"</div>
</div><div><br></div></div></div></div>