On Fri, Mar 8, 2013 at 11:45 AM, John McCall <span dir="ltr"><<a href="mailto:rjmccall@apple.com" target="_blank">rjmccall@apple.com</a>></span> wrote:<br><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div style="word-wrap:break-word"><div><div class="h5"><div><div>On Mar 8, 2013, at 11:42 AM, Jordan Rose <<a href="mailto:jordan_rose@apple.com" target="_blank">jordan_rose@apple.com</a>> wrote:</div><blockquote type="cite">
<div style="word-wrap:break-word"><div><div>On Mar 8, 2013, at 11:41 , John McCall <<a href="mailto:rjmccall@apple.com" target="_blank">rjmccall@apple.com</a>> wrote:</div><blockquote type="cite"><div style="word-wrap:break-word">
<div><div>On Mar 8, 2013, at 11:38 AM, Jordan Rose <<a href="mailto:jordan_rose@apple.com" target="_blank">jordan_rose@apple.com</a>> wrote:</div><blockquote type="cite"><div style="word-wrap:break-word"><div><div>On Mar 8, 2013, at 11:36 , John McCall <<a href="mailto:rjmccall@apple.com" target="_blank">rjmccall@apple.com</a>> wrote:</div>
<blockquote type="cite"><div style="word-wrap:break-word"><div><div>On Mar 8, 2013, at 9:08 AM, Jordan Rose <<a href="mailto:jordan_rose@apple.com" target="_blank">jordan_rose@apple.com</a>> wrote:</div><blockquote type="cite">
<div style="word-wrap:break-word"><div><div>On Mar 8, 2013, at 3:41 , Nicola Gigante <<a href="mailto:nicola.gigante@gmail.com" target="_blank">nicola.gigante@gmail.com</a>> wrote:</div><blockquote type="cite">Hello.<br>
<br>I'm not sure why this piece of code doesn't compile, but I suspect a bug.<br>This happens with the clang trunk (r176686) (C++11 mode)<br><br>The compilation succeeds if value is made const static OR if I put parenthesis around test<1, N>::value.<br>
<br>template<int I, int N><br>struct test<br>{<br>    bool value = test<1, N>::value;<br>};<br><br>template<int N><br>struct test<1, N><br>{<br>    static const bool value = true;<br>};<br><br>$ ./llvm/build/bin/clang++ -std=c++11 -fsyntax-only test.cpp<br>
test.cpp:4:26: error: declaration of 'N' shadows template parameter<br>    bool value = test<1, N>::value;<br>                         ^<br>test.cpp:1:21: note: template parameter is declared here<br>template<int I, int N><br>
                    ^<br>test.cpp:4:27: error: expected ';' at end of declaration list<br>    bool value = test<1, N>::value;<br>                          ^<br>                          ;<br>test.cpp:4:24: error: expected '>'<br>
    bool value = test<1, N>::value;<br>                       ^<br>3 errors generated.<br><br>Am I missing something (or is it already known)?<br></blockquote></div><br><div>Clang is parsing this as:</div><div><br></div>
<div>bool value = (test < 1), N > ::value;</div><div><br></div><div>The first error is because it thinks you're declaring "bool N", the second because "> ::value" isn't a valid initializer for "bool N", and the third because "test < 1" isn't a complete template reference.</div>
<div><br></div><div>I can't be sure whether this is correct, and clearly we could have better recovery, but it explains what's going on here. I think it's due to the fact that we don't know if "test" is a template until <i>after</i> it's been parsed—it could be an integer that we're trying to compare against 1.</div>
</div></blockquote><div><br></div>Ugh.  I *think* this just a bug and doesn't rise to the level of a standards defect.  I did a cursory check and couldn't find an existing defect.</div><div><br></div><div>The lookup rules for non-static data member initializers are equivalent to the rules for being in a member function, i.e. lookup is delayed until the class is complete.  However, collecting tokens and delaying their parsing is an unambiguous process for member functions, because a member function body can be assumed to have balanced delimiters.  That is at least not obviously true for non-static data member initializers, because < and > may or may not be delimiters depending on whether what came before them was a template-id, and we can't decide whether something was a template-id without parsing.</div>
<div><br></div><div>So what's apparently currently happening is that we're just collecting tokens until we get to a semicolon or comma (but skipping over balanced parens, brackets, and braces) and then treating that all as a delayed initializer.</div>
<div><br></div><div>Now, I don't know that there's a formal ambiguity here, because a template-argument has to be a constant-expression, and a constant-expression is just a semantically-constrained conditional-expression, which does not include the assignment operator.  So, for example, this:</div>
<div>  bool a = test<1, b=2>::value;</div><div>cannot be parsed as this:</div><div><div>  bool a = test<1, (b=2)>::value;</div><div>because that's not a grammatically valid template argument.  (It is with parens, but then it's almost certainly a *semantically* invalid template argument, unless somebody's got a constexpr assignment operator...)</div>
<div><br></div><div>So I think we might be able to tweak our current rule so that we only cut off after a comma if what follows looks like a declarator followed by '='.</div></div></div></blockquote><br></div><div>
Just for the record, we'd still have a problem with this case, yes?</div><div><br></div><div>bool comparison = test<1, *ptr;</div></div></blockquote><div><br></div><div>Ah, right, we'd need to cut off after a comma if what follows looks like a declarator followed by '=', or a semicolon, or a comma that we can cut off after.</div>
<br><blockquote type="cite"><div style="word-wrap:break-word">bool templated = test<1, *ptr>::value;</div></blockquote><br></div><div>This can't possibly be a declaration of 'ptr'; it should be parsed as a single initializer.</div>
</div></blockquote><br></div><div>Right, I just included it to demonstrate the common prefix.</div></div></blockquote></div><br></div></div><div>Right.  Key to my proposed rule is that the prefix is irrelevant;  we really don't want to have to do a pseudo-parse of the initializer.</div>
</div></blockquote><div><br></div><div>This is core issue 325 / PR13657. It is possible to fully disambiguate both this case and default argument commas, but it's not yet clear whether we will be required to disambiguate or not. Disambiguation is not trivial in either case. For default initializers it's possible because we can't have a '<' in a declarator in a class, and we can't have an unparenthesized '=' in a template-argument (except in both cases after the token 'operator'). For default arguments it's possible because any parameter in a class-scope function declaration *must* have a default argument if the previous parameter did, and default arguments must start with an '=' (so we can distinguish a parameter-declaration from a template-argument based on whether it's followed by an '='). Needless to say, both of these are *extremely* fragile to tiny changes in the C++ grammar.</div>
<div><br></div><div>I have a patch for disambiguation of these cases, but it's not quite right in the default argument case -- and it may not match the eventual decision on CWG 325.</div></div>