diff options
-rw-r--r-- | lib/Parse/ParseTentative.cpp | 27 | ||||
-rw-r--r-- | test/SemaCXX/PR11358.cpp | 51 |
2 files changed, 76 insertions, 2 deletions
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 4f80da2dc9..987ae65d06 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -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 index 0000000000..9c49227695 --- /dev/null +++ b/test/SemaCXX/PR11358.cpp @@ -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; + }; +} |