<html><head><meta http-equiv="Content-Type" content="text/html charset=windows-1252"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;">Hi all!<div><br></div><div>I was just looking at:</div><div><br></div><div><div></div><blockquote type="cite"><div>r184968 | rnk | 2013-06-26 13:16:08 -0400 (Wed, 26 Jun 2013) | 9 lines</div><div><br></div><div>Match MSVC's handling of commas during macro argument expansion</div><div><br></div><div>This allows clang to parse the type_traits header in Visual Studio 2012,</div><div>which is included widely in practice.</div><div><br></div><div>This is a rework of r163022 by João Matos. The original patch broke</div><div>preprocessing of gtest headers, which this patch addresses.</div><div><br></div><div>Patch by Will Wilson!</div></blockquote><div><br class="webkit-block-placeholder"></div><div>... which makes a mistake very similar to the one I made in my first attempt at implementing this in PC-lint.</div><div><br></div><div>Initially, I was focussing on the coma token, and implemented a rule where in certain contexts it should not be regarded as an argument delimiter.</div><div><br></div><div>But that’s shown to be wrong e.g. with:</div><div><br></div><div><div>#define Comma ,</div><div>#define E1(a) E2(a)</div><div>#define E2(a,b) a * b</div><div><br></div><div>E1(1 Comma 2)</div></div><div><br></div><div><br></div><div>... for which Clang, GCC, and EDG produce "1 * 2”, and for which MSVC reports: </div><div><br></div><div><div>x.cpp(8) : warning C4003: not enough actual parameters for macro 'E2'</div><div>1 , 2 *</div></div><div><br></div><div>With -fms-compatibility, Clang ToT does not currently reproduce this.</div><div><br></div><div>To make sense of it all, it may help to start by digesting Dave Prosser’s original expand() algorithm from 1986 (which was used as the basis for the English text that eventually wound up in ISO C90---see also [c++std-core-9035]); the original version and a more recent version with corrections can be found here:</div><div><br></div><div><a href="http://www.spinellis.gr/blog/20060626/">http://www.spinellis.gr/blog/20060626/</a></div><div><br></div><div><br></div><div>(Hint: In Dave Prosser’s formulation, if you think in terms of “expanding a macro”, you’re doing it wrong. Instead, a *token sequence* is expanded, and this may involve the expansion of the token sequence that results from replacing an *invocation* by the subst()’d expansion-list of the invoked macro.)</div><div><br></div><div>With that in mind, it might be easier to talk about how MSVC’s rule differs. In particular, James McNellis provided a very helpful response to:</div><div><br></div><div><a href="http://stackoverflow.com/questions/12945911/gcc-vs-visual-studio-macro-expansion">http://stackoverflow.com/questions/12945911/gcc-vs-visual-studio-macro-expansion</a></div><div><br></div><div>... which was: "<span style="color: rgb(119, 119, 119); font-family: arial, sans-serif; font-size: 12.727272033691406px; background-color: rgb(255, 255, 255);">This is a known bug in the Visual C++ preprocessor: </span><strong style="color: rgb(119, 119, 119); font-family: arial, sans-serif; font-size: 12.727272033691406px; background-color: rgb(255, 255, 255);">it does not expand macros prior to rescanning</strong><span style="color: rgb(119, 119, 119); font-family: arial, sans-serif; font-size: 12.727272033691406px; background-color: rgb(255, 255, 255);">. gcc’s behavior is correct.</span><span style="font-family: arial, sans-serif; font-size: 12.727272033691406px; background-color: rgb(255, 255, 255);"><font color="#222222">"</font></span></div><div><br></div><div>I take this to mean that, where DaveProsser::subst() has:</div><div><br></div><div><div style="margin: 0px; font-family: Times; font-size: 14px;"><span style="font-family: Courier;">return </span><i>subst</i><span style="font-family: Courier;">(</span><i>IS’,FP,AP,HS,OS • expand</i><span style="font-family: Courier;">(</span><i>select</i><span style="font-family: Courier;">(</span><i>i,AP</i><span style="font-family: Courier;">)));</span></div></div><div style="margin: 0px; font-family: Times; font-size: 14px;"><span style="font-family: Helvetica; font-size: 12px;"><br></span></div><div style="margin: 0px; font-family: Times; font-size: 14px;"><span style="font-family: Helvetica; font-size: 12px;">...MSVC::subst() instead has the effect of:</span></div><div style="margin: 0px; font-family: Times; font-size: 14px;"><span style="font-family: Helvetica; font-size: 12px;"><br></span></div><div style="margin: 0px; font-family: Times; font-size: 14px;"><span style="font-family: Courier;">return </span><i>subst</i><span style="font-family: Courier;">(</span><i>IS’,FP,AP,HS,OS • </i><i>select</i><span style="font-family: Courier;">(</span><i>i,AP</i><span style="font-family: Courier;">));</span></div><div style="margin: 0px; font-family: Times; font-size: 14px;"><span style="font-family: Courier;"><br></span></div><div style="margin: 0px;">This seems consistent with the test results that I’ve seen so far, except that we need some adjustment to the implementation of the stringize operator. (For #define S(t) #t, if an identifier is mentioned directly in the argument to t, then it needs to be added to the hide set for the evaluation of #t; and anything that is not in the hide set needs to be expanded. At least, that’s what *seems* to happen.)</div><div style="margin: 0px;"><br></div><div style="margin: 0px;">That doesn’t cover everything, though: I still need to review MSVC's ## behavior, and then there’s something odd going on with: </div><div style="margin: 0px;"><br></div><div style="margin: 0px;"><div style="margin: 0px;"><div style="margin: 0px;">#define Comma ,</div><div style="margin: 0px;">#define L (</div><div style="margin: 0px;">#define E1(a) E2 L a )</div><div style="margin: 0px;">#define E2(a, b) ( a + b )</div><div style="margin: 0px;"><br></div><div style="margin: 0px;">E1( 1 Comma 2 )</div><div><br></div><div><br></div><div>... for which ISO behavior appears to produce:</div><div><br></div><div> E2 ( 1 , 2 )</div><div><br></div><div>... but MSVC produces: </div><div><br></div><div><div>( 1 + 2 )</div></div><div><br></div><div>... which might be explained by a version of expand() where the substitution of an *invocation* and the substitution of *parameters* both happen in the same frame. (So, first replace “L" by (, then replace “a" by “1 Comma2”; then consume ), then do the rescan.</div><div><br></div><div>But, I’m not sure if that’s a priority. (I don’t know of any library header that actually depends on that.)</div></div></div><div style="margin: 0px;"><br></div><div apple-content-edited="true"><br></div><div apple-content-edited="true">James Widman <br>-- <br>Gimpel Software <br><a href="http://gimpel.com">http://gimpel.com</a><br>http://twitter.com/GimpelSoftware
</div>
<br></div></body></html>