<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; "><br><div><div>On Mar 8, 2013, at 11:41 , John McCall <<a href="mailto:rjmccall@apple.com">rjmccall@apple.com</a>> wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite"><meta http-equiv="Content-Type" content="text/html charset=windows-1252"><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><div><div>On Mar 8, 2013, at 11:38 AM, Jordan Rose <<a href="mailto:jordan_rose@apple.com">jordan_rose@apple.com</a>> wrote:</div><blockquote type="cite"><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><div><div>On Mar 8, 2013, at 11:36 , John McCall <<a href="mailto:rjmccall@apple.com">rjmccall@apple.com</a>> wrote:</div><blockquote type="cite"><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><div><div>On Mar 8, 2013, at 9:08 AM, Jordan Rose <<a href="mailto:jordan_rose@apple.com">jordan_rose@apple.com</a>> wrote:</div><blockquote type="cite"><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><div><div>On Mar 8, 2013, at 3:41 , Nicola Gigante <<a href="mailto:nicola.gigante@gmail.com">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; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; ">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><br></body></html>