diff options
author | Nick Lewycky <nicholas@mxc.ca> | 2012-01-25 01:19:14 +0000 |
---|---|---|
committer | Nick Lewycky <nicholas@mxc.ca> | 2012-01-25 01:19:14 +0000 |
commit | 443aac9bd22624c6abb1fe7e581ac30c4e654eea (patch) | |
tree | 48190e9139228c03617d30a99f0e4a927f46d6d1 | |
parent | 8efca6bb688d32fd7c0d91b504ef3307f97ee66a (diff) |
With a little more work in the tentative parse determining whether a statement
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
-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; + }; +} |