]> granicus.if.org Git - clang/commitdiff
With a little more work in the tentative parse determining whether a statement
authorNick Lewycky <nicholas@mxc.ca>
Wed, 25 Jan 2012 01:19:14 +0000 (01:19 +0000)
committerNick Lewycky <nicholas@mxc.ca>
Wed, 25 Jan 2012 01:19:14 +0000 (01:19 +0000)
is a declaration-stmt or an expression, we can discern a subset of cases where
the user erred in omitting the typename keyword before a dependent type name.
Fixes PR11358!

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@148896 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Parse/ParseTentative.cpp
test/SemaCXX/PR11358.cpp [new file with mode: 0644]

index 4f80da2dc998cfcfb5657ce829ea4a38190aed5d..987ae65d066b45c5f7ceceb591fd5c2b42d3f6cf 100644 (file)
@@ -864,7 +864,7 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
     if (TryAnnotateTypeOrScopeToken())
       return TPResult::Error();
     return isCXXDeclarationSpecifier();
-      
+
     // decl-specifier:
     //   storage-class-specifier
     //   type-specifier
@@ -950,8 +950,31 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
     // 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()) {
+          TentativeParsingAction PA(*this);
+          ConsumeToken();
+          ConsumeToken();
+          bool isIdentifier = Tok.is(tok::identifier);
+          TPResult TPR = TPResult::False();
+          if (!isIdentifier)
+            TPR = isCXXDeclarationSpecifier();
+          PA.Revert();
+
+          if (isIdentifier ||
+              TPR == TPResult::True() || TPR == TPResult::Error())
+            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
diff --git a/test/SemaCXX/PR11358.cpp b/test/SemaCXX/PR11358.cpp
new file mode 100644 (file)
index 0000000..9c49227
--- /dev/null
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 %s -verify
+// PR11358
+
+namespace test1 {
+  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;
+  };
+}
+
+namespace test2 {
+  template <typename Key, typename Value>
+  class hash_map {
+    class const_iterator { void operator++(); };
+    const_iterator begin() const;
+    const_iterator end() const;
+  };
+
+  template <typename KeyType, typename ValueType>
+  void MapTest(hash_map<KeyType, ValueType> map) {
+    for (hash_map<KeyType, ValueType>::const_iterator it = map.begin(); // expected-error{{missing 'typename'}}
+         it != map.end(); it++) {
+    }
+  }
+}
+
+namespace test3 {
+  template<typename T>
+  struct container {
+    class iterator {};
+  };
+
+  template<typename T>
+  struct Test {
+    typedef container<T> Container;
+    void test() {
+      Container::iterator const i; // expected-error{{missing 'typename'}}
+    }
+    Container c;
+  };
+}