Ping! Sorry for the <1 week ping, but I just got another bug report about
this issue. Testcase:

#include <hash_map>
using namespace std;
using namespace __gnu_cxx;
template <typename KeyType, typename ValueType>
void MapTest(hash_map<KeyType, ValueType> map) {
  for (hash_map<KeyType, ValueType>::const_iterator it = map.begin(); it !=
map.end(); it++) {
  }
}

without this patch produces:

z.cc:6:53: error: expected ';' in 'for' statement specifier
  for (hash_map<KeyType, ValueType>::const_iterator it = map.begin(); ...
                                                    ^
z.cc:6:53: error: use of undeclared identifier 'it'
z.cc:6:71: error: use of undeclared identifier 'it'
  for (hash_map<KeyType, ValueType>::const_iterator it = map.begin(); it ...
                                                                      ^
z.cc:6:86: error: expected ')'
  ...ValueType>::const_iterator it = map.begin(); it != map.end(); it++) {
                                                                 ^
z.cc:6:7: note: to match this '('
  for (hash_map<KeyType, ValueType>::const_iterator it = map.begin(); ...
      ^
z.cc:6:88: error: use of undeclared identifier 'it'
  ...ValueType>::const_iterator it = map.begin(); it != map.end(); it++) {
                                                                   ^

but with this patch produces:

z.cc:6:8: error: missing 'typename' prior to dependent type name
      'hash_map<KeyType, ValueType>::const_iterator'
  for (hash_map<KeyType, ValueType>::const_iterator it = map.begin(); ...
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       typename

Same patch attached again. Please review!

Nick


On 20 January 2012 17:54, Nick Lewycky <[email protected]> wrote:

> The attached patch fixes PR11358:
>
> pr11358.cc:11:5: error: missing 'typename' prior to dependent type name
>       'Container::iterator'
>     Container::iterator i = c.begin();
>     ^~~~~~~~~~~~~~~~~~~
>     typename
>
> It works by teaching Parser::isCXXDeclarationSpecifier() to, in the event
> of a cxxscope annotation followed by an identifier, ("Container::" and
> "iterator" in the above example), look at the next token. Yes, this means
> doing two-tokens of look-ahead. If that next token is an identifier or
> cvr-qualifier, we conclude that this can't possibly be an expression and
> return a parse error.
>
> This is pretty important because some developers don't seem to understand
> the rule for where they need to put typename, and Clang has exacerbated
> this by teaching them that they only need to put typename where the
> compiler tells them to put typename. Consequently, when we don't tell them
> to put typename there, that isn't one of the things they'll try any more.
>
> The condition under which we'll do an extra token of look-ahead is when we
> see a dependent nested-name-specifier followed by an identifier while doing
> the tentative parse to determine whether the statement is a declaration or
> an expression. This is reasonably rare. Here's some build times of boost:
>
> run of "bootstrap"
> with patch: 0m26.460s 0m26.530s
> without patch: 0m25.510s 0m26.110s
> run of "b2"
> with patch: 13m12.050s 12m58.670s
> without patch: 12m26.260s 13m9.030s
>
> So we conclude that my testing machine is crazy noisy, but at least the
> patch doesn't cause a horrible performance regression. To give you another
> statistic, the number of times we need to look ahead by one more token is
> slightly less than 250,000 times across all translation units in an
> llvm+clang build. I haven't checked how many of those are unique.
>
> Please review!
>
> Nick
>
>
Index: test/SemaCXX/PR11358.cpp
===================================================================
--- test/SemaCXX/PR11358.cpp	(revision 0)
+++ test/SemaCXX/PR11358.cpp	(revision 0)
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 %s -verify
+// PR11358
+
+template<typename T>
+struct container {
+  class iterator {};
+  iterator begin() { return iterator(); }
+};
+
+template<typename T>
+struct Test {
+  typedef container<T> Container;
+  void test() {
+    Container::iterator i = c.begin(); // expected-error{{missing 'typename'}}
+  }
+  Container c;
+};
+
Index: lib/Parse/ParseTentative.cpp
===================================================================
--- lib/Parse/ParseTentative.cpp	(revision 148493)
+++ lib/Parse/ParseTentative.cpp	(working copy)
@@ -864,7 +864,7 @@
     if (TryAnnotateTypeOrScopeToken())
       return TPResult::Error();
     return isCXXDeclarationSpecifier();
-      
+
     // decl-specifier:
     //   storage-class-specifier
     //   type-specifier
@@ -950,8 +950,23 @@
     // We've already annotated a scope; try to annotate a type.
     if (TryAnnotateTypeOrScopeToken())
       return TPResult::Error();
-    if (!Tok.is(tok::annot_typename))
+    if (!Tok.is(tok::annot_typename)) {
+      // If the next token is an identifier or a type qualifier, then this
+      // can't possibly be a valid expression either.
+      if (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier)) {
+        CXXScopeSpec SS;
+        Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(),
+                                                     Tok.getAnnotationRange(),
+                                                     SS);
+        if (SS.getScopeRep() && SS.getScopeRep()->isDependent()) {
+          tok::TokenKind After = PP.LookAhead(1).getKind();
+          if (After == tok::identifier || After == tok::kw_const ||
+              After == tok::kw_volatile || After == tok::kw_restrict)
+            return TPResult::Error();
+        }
+      }
       return TPResult::False();
+    }
     // If that succeeded, fallthrough into the generic simple-type-id case.
 
     // The ambiguity resides in a simple-type-specifier/typename-specifier
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to