From: Nick Lewycky Date: Wed, 25 Jan 2012 01:19:14 +0000 (+0000) Subject: With a little more work in the tentative parse determining whether a statement X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=443aac9bd22624c6abb1fe7e581ac30c4e654eea;p=clang 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 --- 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 + struct container { + class iterator {}; + iterator begin() { return iterator(); } + }; + + template + struct Test { + typedef container Container; + void test() { + Container::iterator i = c.begin(); // expected-error{{missing 'typename'}} + } + Container c; + }; +} + +namespace test2 { + template + class hash_map { + class const_iterator { void operator++(); }; + const_iterator begin() const; + const_iterator end() const; + }; + + template + void MapTest(hash_map map) { + for (hash_map::const_iterator it = map.begin(); // expected-error{{missing 'typename'}} + it != map.end(); it++) { + } + } +} + +namespace test3 { + template + struct container { + class iterator {}; + }; + + template + struct Test { + typedef container Container; + void test() { + Container::iterator const i; // expected-error{{missing 'typename'}} + } + Container c; + }; +}